diff --git a/base/sources/iron_obj.h b/base/sources/iron_obj.h index 63718079..30842673 100644 --- a/base/sources/iron_obj.h +++ b/base/sources/iron_obj.h @@ -9,6 +9,7 @@ typedef struct raw_mesh { struct i16_array *posa; struct i16_array *nora; struct i16_array *texa; + struct i16_array *texa1; struct i16_array *cola; struct u32_array *inda; int vertex_count; diff --git a/paint/plugins/io_fbx/io_fbx.c b/paint/plugins/io_fbx/io_fbx.c index a55bbd3f..2cb30621 100644 --- a/paint/plugins/io_fbx/io_fbx.c +++ b/paint/plugins/io_fbx/io_fbx.c @@ -1,42 +1,45 @@ -#include "ufbx/ufbx.h" -#include -#include #include "iron_array.h" #include "iron_obj.h" +#include "ufbx/ufbx.h" +#include +#include -static bool has_next = false; -static int current_node = 0; -static float scale_pos = 1.0; +static bool has_next = false; +static int current_node = 0; +static float scale_pos = 1.0; void io_fbx_parse_mesh(raw_mesh_t *raw, ufbx_mesh *mesh, ufbx_matrix *to_world, ufbx_matrix *to_world_unscaled) { - uint32_t indices_size = mesh->max_face_triangles * 3; - uint32_t *indices = (uint32_t *)malloc(sizeof(uint32_t) * indices_size); + uint32_t indices_size = mesh->max_face_triangles * 3; + uint32_t *indices = (uint32_t *)malloc(sizeof(uint32_t) * indices_size); - bool has_tex = mesh->vertex_uv.exists; - bool has_col = mesh->vertex_color.exists; + bool has_tex = mesh->vertex_uv.exists; + bool has_tex1 = mesh->uv_sets.count > 1; + bool has_col = mesh->vertex_color.exists; - int numtri = mesh->num_triangles; - float *posa32 = (float *)malloc(sizeof(float) * numtri * 3 * 3); - float *nora32 = (float *)malloc(sizeof(float) * numtri * 3 * 3); - float *texa32 = has_tex ? (float *)malloc(sizeof(float) * numtri * 3 * 2) : NULL; - float *cola32 = has_col ? (float *)malloc(sizeof(float) * numtri * 3 * 4) : NULL; - int pi = 0; - int ni = 0; - int ti = 0; - int ci = 0; + int numtri = mesh->num_triangles; + float *posa32 = (float *)malloc(sizeof(float) * numtri * 3 * 3); + float *nora32 = (float *)malloc(sizeof(float) * numtri * 3 * 3); + float *texa32 = has_tex ? (float *)malloc(sizeof(float) * numtri * 3 * 2) : NULL; + float *texa132 = has_tex1 ? (float *)malloc(sizeof(float) * numtri * 3 * 2) : NULL; + float *cola32 = has_col ? (float *)malloc(sizeof(float) * numtri * 3 * 4) : NULL; + int pi = 0; + int ni = 0; + int ti = 0; + int ti1 = 0; + int ci = 0; for (int j = 0; j < mesh->faces.count; ++j) { - ufbx_face face = mesh->faces.data[j]; - uint32_t num_triangles = ufbx_triangulate_face(indices, indices_size, mesh, face); + ufbx_face face = mesh->faces.data[j]; + uint32_t num_triangles = ufbx_triangulate_face(indices, indices_size, mesh, face); for (uint32_t v_ix = 0; v_ix < num_triangles * 3; v_ix++) { uint32_t a = indices[v_ix]; - ufbx_vec3 v = ufbx_transform_position(to_world, ufbx_get_vertex_vec3(&mesh->vertex_position, a)); + ufbx_vec3 v = ufbx_transform_position(to_world, ufbx_get_vertex_vec3(&mesh->vertex_position, a)); posa32[pi++] = v.x; posa32[pi++] = v.y; posa32[pi++] = v.z; - v = ufbx_transform_direction(to_world_unscaled, ufbx_get_vertex_vec3(&mesh->vertex_normal, a)); + v = ufbx_transform_direction(to_world_unscaled, ufbx_get_vertex_vec3(&mesh->vertex_normal, a)); nora32[ni++] = v.x; nora32[ni++] = v.y; nora32[ni++] = v.z; @@ -46,6 +49,11 @@ void io_fbx_parse_mesh(raw_mesh_t *raw, ufbx_mesh *mesh, ufbx_matrix *to_world, texa32[ti++] = ufbx_get_vertex_vec2(&mesh->vertex_uv, a).y; } + if (has_tex1) { + texa132[ti1++] = ufbx_get_vertex_vec2(&mesh->uv_sets.data[1].vertex_uv, a).x; + texa132[ti1++] = ufbx_get_vertex_vec2(&mesh->uv_sets.data[1].vertex_uv, a).y; + } + if (has_col) { cola32[ci++] = ufbx_get_vertex_vec4(&mesh->vertex_color, a).x; cola32[ci++] = ufbx_get_vertex_vec4(&mesh->vertex_color, a).y; @@ -58,7 +66,7 @@ void io_fbx_parse_mesh(raw_mesh_t *raw, ufbx_mesh *mesh, ufbx_matrix *to_world, free(indices); int vertex_count = pi / 3; - int index_count = vertex_count; + int index_count = vertex_count; uint32_t *inda = malloc(sizeof(uint32_t) * index_count); for (int i = 0; i < index_count; ++i) { @@ -71,20 +79,24 @@ void io_fbx_parse_mesh(raw_mesh_t *raw, ufbx_mesh *mesh, ufbx_matrix *to_world, float hz = 0.0; for (int i = 0; i < vertex_count; ++i) { float f = fabsf(posa32[i * 3]); - if (hx < f) hx = f; + if (hx < f) + hx = f; f = fabsf(posa32[i * 3 + 1]); - if (hy < f) hy = f; + if (hy < f) + hy = f; f = fabsf(posa32[i * 3 + 2]); - if (hz < f) hz = f; + if (hz < f) + hz = f; } float _scale_pos = fmax(hx, fmax(hy, hz)); - if (_scale_pos > scale_pos) scale_pos = _scale_pos; + if (_scale_pos > scale_pos) + scale_pos = _scale_pos; float inv = 1 / scale_pos; - // Pack into 16bit + // Pack into 16bit short *posa = malloc(sizeof(short) * vertex_count * 4); for (int i = 0; i < vertex_count; ++i) { - posa[i * 4 ] = posa32[i * 3 ] * 32767 * inv; + posa[i * 4] = posa32[i * 3] * 32767 * inv; posa[i * 4 + 1] = posa32[i * 3 + 1] * 32767 * inv; posa[i * 4 + 2] = posa32[i * 3 + 2] * 32767 * inv; } @@ -92,7 +104,7 @@ void io_fbx_parse_mesh(raw_mesh_t *raw, ufbx_mesh *mesh, ufbx_matrix *to_world, short *nora = malloc(sizeof(short) * vertex_count * 2); if (nora32 != NULL) { for (int i = 0; i < vertex_count; ++i) { - nora[i * 2 ] = nora32[i * 3 ] * 32767; + nora[i * 2] = nora32[i * 3] * 32767; nora[i * 2 + 1] = nora32[i * 3 + 1] * 32767; posa[i * 4 + 3] = nora32[i * 3 + 2] * 32767; } @@ -105,17 +117,27 @@ void io_fbx_parse_mesh(raw_mesh_t *raw, ufbx_mesh *mesh, ufbx_matrix *to_world, if (texa32 != NULL) { texa = malloc(sizeof(short) * vertex_count * 2); for (int i = 0; i < vertex_count; ++i) { - texa[i * 2 ] = texa32[i * 2 ] * 32767; + texa[i * 2] = texa32[i * 2] * 32767; texa[i * 2 + 1] = (1.0 - texa32[i * 2 + 1]) * 32767; } free(texa32); } + short *texa1 = NULL; + if (texa132 != NULL) { + texa1 = malloc(sizeof(short) * vertex_count * 2); + for (int i = 0; i < vertex_count; ++i) { + texa1[i * 2] = texa132[i * 2] * 32767; + texa1[i * 2 + 1] = (1.0 - texa132[i * 2 + 1]) * 32767; + } + free(texa132); + } + short *cola = NULL; if (cola32 != NULL) { cola = malloc(sizeof(short) * vertex_count * 4); for (int i = 0; i < vertex_count; ++i) { - cola[i * 4 ] = cola32[i * 4 ] * 32767; + cola[i * 4] = cola32[i * 4] * 32767; cola[i * 4 + 1] = cola32[i * 4 + 1] * 32767; cola[i * 4 + 2] = cola32[i * 4 + 2] * 32767; cola[i * 4 + 3] = cola32[i * 4 + 3] * 32767; @@ -123,27 +145,33 @@ void io_fbx_parse_mesh(raw_mesh_t *raw, ufbx_mesh *mesh, ufbx_matrix *to_world, free(cola32); } - raw->posa = (i16_array_t *)malloc(sizeof(i16_array_t)); + raw->posa = (i16_array_t *)malloc(sizeof(i16_array_t)); raw->posa->buffer = posa; raw->posa->length = raw->posa->capacity = vertex_count * 4; - raw->nora = (i16_array_t *)malloc(sizeof(i16_array_t)); + raw->nora = (i16_array_t *)malloc(sizeof(i16_array_t)); raw->nora->buffer = nora; raw->nora->length = raw->nora->capacity = vertex_count * 2; if (texa != NULL) { - raw->texa = (i16_array_t *)malloc(sizeof(i16_array_t)); + raw->texa = (i16_array_t *)malloc(sizeof(i16_array_t)); raw->texa->buffer = texa; raw->texa->length = raw->texa->capacity = vertex_count * 2; } + if (texa1 != NULL) { + raw->texa1 = (i16_array_t *)malloc(sizeof(i16_array_t)); + raw->texa1->buffer = texa1; + raw->texa1->length = raw->texa1->capacity = vertex_count * 2; + } + if (cola != NULL) { - raw->cola = (i16_array_t *)malloc(sizeof(i16_array_t)); + raw->cola = (i16_array_t *)malloc(sizeof(i16_array_t)); raw->cola->buffer = cola; raw->cola->length = raw->cola->capacity = vertex_count * 4; } - raw->inda = (u32_array_t *)malloc(sizeof(u32_array_t)); + raw->inda = (u32_array_t *)malloc(sizeof(u32_array_t)); raw->inda->buffer = inda; raw->inda->length = raw->inda->capacity = index_count; @@ -152,9 +180,9 @@ void io_fbx_parse_mesh(raw_mesh_t *raw, ufbx_mesh *mesh, ufbx_matrix *to_world, } void *io_fbx_parse(char *buf, size_t size) { - ufbx_load_opts opts = { .generate_missing_normals = true }; - ufbx_scene *scene = ufbx_load_memory(buf, size, &opts, NULL); - raw_mesh_t *raw = (raw_mesh_t *)calloc(sizeof(raw_mesh_t), 1); + ufbx_load_opts opts = {.generate_missing_normals = true}; + ufbx_scene *scene = ufbx_load_memory(buf, size, &opts, NULL); + raw_mesh_t *raw = (raw_mesh_t *)calloc(sizeof(raw_mesh_t), 1); for (; current_node < scene->nodes.count; ++current_node) { ufbx_node *n = scene->nodes.data[current_node]; diff --git a/paint/sources/export_arm.ts b/paint/sources/export_arm.ts index b9766cff..a7a5e890 100644 --- a/paint/sources/export_arm.ts +++ b/paint/sources/export_arm.ts @@ -77,6 +77,7 @@ function export_arm_run_project() { uv_scale : l.scale, uv_rot : l.angle, uv_type : l.uv_type, + uv_map : l.uv_map, decal_mat : l.uv_type == uv_type_t.PROJECT ? mat4_to_f32_array(l.decal_mat) : null, opacity_mask : l.mask_opacity, fill_layer : l.fill_layer != null ? array_index_of(project_materials, l.fill_layer) : -1, diff --git a/paint/sources/geom.ts b/paint/sources/geom.ts index 4ed2148a..e5df70ba 100644 --- a/paint/sources/geom.ts +++ b/paint/sources/geom.ts @@ -133,6 +133,7 @@ declare type raw_mesh_t = { posa?: i16_array_t; nora?: i16_array_t; texa?: i16_array_t; + texa1?: i16_array_t; cola?: i16_array_t; inda?: u32_array_t; vertex_count?: i32; diff --git a/paint/sources/import_arm.ts b/paint/sources/import_arm.ts index b565dced..6aeff3a5 100644 --- a/paint/sources/import_arm.ts +++ b/paint/sources/import_arm.ts @@ -252,6 +252,7 @@ function import_arm_run_project(path: string) { l.scale = ld.uv_scale; l.angle = ld.uv_rot; l.uv_type = ld.uv_type; + l.uv_map = ld.uv_map; if (ld.decal_mat != null) { l.decal_mat = mat4_from_f32_array(ld.decal_mat); } diff --git a/paint/sources/import_mesh.ts b/paint/sources/import_mesh.ts index 878c17a6..19ba3157 100644 --- a/paint/sources/import_mesh.ts +++ b/paint/sources/import_mesh.ts @@ -3,7 +3,6 @@ let import_mesh_clear_layers: bool = true; let import_mesh_meshes_to_unwrap: any[] = null; function import_mesh_run(path: string, _clear_layers: bool = true, replace_existing: bool = true) { - if (!path_is_mesh(path)) { if (!context_enable_import_plugin(path)) { console_error(strings_unknown_asset_format()); @@ -260,6 +259,11 @@ function import_mesh_raw_mesh(mesh: raw_mesh_t): mesh_data_t { scale_tex : mesh.scale_tex }; + if (mesh.texa1 != null) { + let va: vertex_array_t = {values : mesh.texa1, attrib : "tex1", data : "short2norm"}; + array_push(raw.vertex_arrays, va); + } + if (mesh.cola != null) { let va: vertex_array_t = {values : mesh.cola, attrib : "col", data : "short4norm"}; array_push(raw.vertex_arrays, va); diff --git a/paint/sources/make_mesh.ts b/paint/sources/make_mesh.ts index 313901a6..14d64770 100644 --- a/paint/sources/make_mesh.ts +++ b/paint/sources/make_mesh.ts @@ -14,6 +14,10 @@ function make_mesh_run(data: material_t, layer_pass: i32 = 0): node_shader_conte }; let con_mesh: node_shader_context_t = node_shader_context_create(data, props); + if (mesh_data_get_vertex_array(context_raw.paint_object.data, "tex1") != null) { + node_shader_context_add_elem(con_mesh, "tex1", "short2norm"); + } + let kong: node_shader_t = node_shader_context_make_kong(con_mesh); node_shader_add_out(kong, "tex_coord: float2"); @@ -60,6 +64,12 @@ function make_mesh_run(data: material_t, layer_pass: i32 = 0): node_shader_conte node_shader_write_vert(kong, "output.tex_coord = input.tex;"); node_shader_write_attrib_frag(kong, "var tex_coord: float2 = input.tex_coord;"); + if (mesh_data_get_vertex_array(context_raw.paint_object.data, "tex1") != null) { + node_shader_add_out(kong, "tex_coord1: float2"); + node_shader_write_vert(kong, "output.tex_coord1 = input.tex1;"); + node_shader_write_attrib_frag(kong, "var tex_coord1: float2 = input.tex_coord1;"); + } + kong.frag_out = "float4[3]"; kong.frag_n = true; node_shader_add_function(kong, str_pack_float_int16); @@ -202,8 +212,9 @@ function make_mesh_run(data: material_t, layer_pass: i32 = 0): node_shader_conte } } + let tex_coord: string = l.uv_map == 1 ? "tex_coord1" : "tex_coord"; node_shader_add_texture(kong, "texpaint" + l.id); - node_shader_write_frag(kong, "texpaint_sample = sample_lod(texpaint" + l.id + ", sampler_linear, tex_coord, 0.0);"); + node_shader_write_frag(kong, "texpaint_sample = sample_lod(texpaint" + l.id + ", sampler_linear, " + tex_coord + ", 0.0);"); node_shader_write_frag(kong, "texpaint_opac = texpaint_sample.a;"); // ///if (arm_direct3d12 || arm_vulkan) // if (raw.viewport_mode == viewport_mode_t.LIT) { @@ -231,8 +242,8 @@ function make_mesh_run(data: material_t, layer_pass: i32 = 0): node_shader_conte } node_shader_add_texture(kong, "texpaint" + m.id); node_shader_write_frag(kong, "{"); // Group mask is sampled across multiple layers - node_shader_write_frag(kong, "var texpaint_mask_sample" + m.id + ": float = sample_lod(texpaint" + m.id + - ", sampler_linear, tex_coord, 0.0).r;"); + node_shader_write_frag(kong, "var texpaint_mask_sample" + m.id + ": float = sample_lod(texpaint" + m.id + ", sampler_linear, " + + tex_coord + ", 0.0).r;"); let opac: f32 = slot_layer_get_opacity(m); let mask: string = make_material_blend_mode_mask(kong, m.blending, texpaint_mask, "texpaint_mask_sample" + m.id, "float(" + opac + ")"); node_shader_write_frag(kong, texpaint_mask + " = " + mask + ";"); @@ -259,13 +270,13 @@ function make_mesh_run(data: material_t, layer_pass: i32 = 0): node_shader_conte if (l.paint_nor || make_material_emis_used) { node_shader_add_texture(kong, "texpaint_nor" + l.id); - node_shader_write_frag(kong, "texpaint_nor_sample = sample_lod(texpaint_nor" + l.id + ", sampler_linear, tex_coord, 0.0);"); + node_shader_write_frag(kong, "texpaint_nor_sample = sample_lod(texpaint_nor" + l.id + ", sampler_linear, " + tex_coord + ", 0.0);"); if (make_material_emis_used) { node_shader_write_frag(kong, "if (texpaint_opac > 0.0) {"); node_shader_add_constant(kong, "texpaint_size: float2", "_texpaint_size"); - node_shader_write_frag(kong, " var texpaint_nor_raw: float4 = texpaint_nor" + l.id + - "[uint2(uint(tex_coord.x * constants.texpaint_size.x), uint(tex_coord.y * constants.texpaint_size.y))];"); + node_shader_write_frag(kong, " var texpaint_nor_raw: float4 = texpaint_nor" + l.id + "[uint2(uint(" + tex_coord + + ".x * constants.texpaint_size.x), uint(" + tex_coord + ".y * constants.texpaint_size.y))];"); node_shader_write_frag(kong, " matid = texpaint_nor_raw.a;"); node_shader_write_frag(kong, "}"); } @@ -289,7 +300,7 @@ function make_mesh_run(data: material_t, layer_pass: i32 = 0): node_shader_conte if (l.paint_occ || l.paint_rough || l.paint_met || (l.paint_height && make_material_height_used)) { node_shader_add_texture(kong, "texpaint_pack" + l.id); - node_shader_write_frag(kong, "texpaint_pack_sample = sample_lod(texpaint_pack" + l.id + ", sampler_linear, tex_coord, 0.0);"); + node_shader_write_frag(kong, "texpaint_pack_sample = sample_lod(texpaint_pack" + l.id + ", sampler_linear, " + tex_coord + ", 0.0);"); if (l.paint_occ) { node_shader_write_frag(kong, "occlusion = lerp(occlusion, texpaint_pack_sample.r, texpaint_opac);"); @@ -306,14 +317,14 @@ function make_mesh_run(data: material_t, layer_pass: i32 = 0): node_shader_conte node_shader_write_frag(kong, "{"); node_shader_add_constant(kong, "texpaint_size: float2", "_texpaint_size"); node_shader_write_frag(kong, "var tex_step: float = 1.0 / constants.texpaint_size.x;"); - node_shader_write_frag(kong, "height0 " + assign + " sample_lod(texpaint_pack" + l.id + - ", sampler_linear, float2(tex_coord.x - tex_step, tex_coord.y), 0.0).a * texpaint_opac;"); - node_shader_write_frag(kong, "height1 " + assign + " sample_lod(texpaint_pack" + l.id + - ", sampler_linear, float2(tex_coord.x + tex_step, tex_coord.y), 0.0).a * texpaint_opac;"); - node_shader_write_frag(kong, "height2 " + assign + " sample_lod(texpaint_pack" + l.id + - ", sampler_linear, float2(tex_coord.x, tex_coord.y - tex_step), 0.0).a * texpaint_opac;"); - node_shader_write_frag(kong, "height3 " + assign + " sample_lod(texpaint_pack" + l.id + - ", sampler_linear, float2(tex_coord.x, tex_coord.y + tex_step), 0.0).a * texpaint_opac;"); + node_shader_write_frag(kong, "height0 " + assign + " sample_lod(texpaint_pack" + l.id + ", sampler_linear, float2(" + tex_coord + + ".x - tex_step, " + tex_coord + ".y), 0.0).a * texpaint_opac;"); + node_shader_write_frag(kong, "height1 " + assign + " sample_lod(texpaint_pack" + l.id + ", sampler_linear, float2(" + tex_coord + + ".x + tex_step, " + tex_coord + ".y), 0.0).a * texpaint_opac;"); + node_shader_write_frag(kong, "height2 " + assign + " sample_lod(texpaint_pack" + l.id + ", sampler_linear, float2(" + tex_coord + ".x, " + + tex_coord + ".y - tex_step), 0.0).a * texpaint_opac;"); + node_shader_write_frag(kong, "height3 " + assign + " sample_lod(texpaint_pack" + l.id + ", sampler_linear, float2(" + tex_coord + ".x, " + + tex_coord + ".y + tex_step), 0.0).a * texpaint_opac;"); node_shader_write_frag(kong, "}"); } } diff --git a/paint/sources/make_paint.ts b/paint/sources/make_paint.ts index b8ac2c70..49e0a978 100644 --- a/paint/sources/make_paint.ts +++ b/paint/sources/make_paint.ts @@ -54,6 +54,10 @@ function make_paint_run(data: material_t, matcon: material_context_t): node_shad }; let con_paint: node_shader_context_t = node_shader_context_create(data, props); + if (mesh_data_get_vertex_array(context_raw.paint_object.data, "tex1") != null) { + node_shader_context_add_elem(con_paint, "tex1", "short2norm"); + } + con_paint.data.color_writes_red = [ true, true, true, true ]; con_paint.data.color_writes_green = [ true, true, true, true ]; con_paint.data.color_writes_blue = [ true, true, true, true ]; @@ -87,7 +91,12 @@ function make_paint_run(data: material_t, matcon: material_context_t): node_shad let uv_island_fill: bool = context_raw.tool == tool_type_t.FILL && context_raw.fill_type_handle.i == fill_type_t.UV_ISLAND; let decal: bool = context_is_decal(); - node_shader_write_vert(kong, "var tpos: float2 = float2(input.tex.x * 2.0 - 1.0, (1.0 - input.tex.y) * 2.0 - 1.0);"); + if (context_raw.layer.uv_map == 1) { + node_shader_write_vert(kong, "var tpos: float2 = float2(input.tex1.x * 2.0 - 1.0, (1.0 - input.tex1.y) * 2.0 - 1.0);"); + } + else { + node_shader_write_vert(kong, "var tpos: float2 = float2(input.tex.x * 2.0 - 1.0, (1.0 - input.tex.y) * 2.0 - 1.0);"); + } node_shader_write_vert(kong, "output.pos = float4(tpos, 0.0, 1.0);"); diff --git a/paint/sources/make_texcoord.ts b/paint/sources/make_texcoord.ts index d123632a..c51e09ec 100644 --- a/paint/sources/make_texcoord.ts +++ b/paint/sources/make_texcoord.ts @@ -73,7 +73,14 @@ function make_texcoord_run(kong: node_shader_t) { else if (uv_type == uv_type_t.UVMAP) { // TexCoords - uvmap node_shader_add_constant(kong, "brush_scale: float", "_brush_scale"); node_shader_add_out(kong, "tex_coord: float2"); - node_shader_write_vert(kong, "output.tex_coord = input.tex * constants.brush_scale;"); + + if (context_raw.layer.uv_map == 1) { + node_shader_write_vert(kong, "output.tex_coord = input.tex1 * constants.brush_scale;"); + } + else { + node_shader_write_vert(kong, "output.tex_coord = input.tex * constants.brush_scale;"); + } + if (uv_angle > 0.0) { node_shader_add_constant(kong, "brush_angle: float2", "_brush_angle"); node_shader_write_vert( diff --git a/paint/sources/node_shader.ts b/paint/sources/node_shader.ts index d9039ce0..61623f69 100644 --- a/paint/sources/node_shader.ts +++ b/paint/sources/node_shader.ts @@ -164,7 +164,6 @@ function node_shader_vstruct_to_vsin(raw: node_shader_t) { } function node_shader_get(raw: node_shader_t): string { - node_shader_vstruct_to_vsin(raw); let s: string = ""; diff --git a/paint/sources/project.ts b/paint/sources/project.ts index 037f85c5..bdbee58f 100644 --- a/paint/sources/project.ts +++ b/paint/sources/project.ts @@ -783,6 +783,7 @@ type layer_data_t = { uv_scale?: f32; uv_rot?: f32; uv_type?: i32; + uv_map?: i32; decal_mat?: f32_array_t; opacity_mask?: f32; fill_layer?: i32; diff --git a/paint/sources/slot_layer.ts b/paint/sources/slot_layer.ts index eea86b04..5d711e54 100644 --- a/paint/sources/slot_layer.ts +++ b/paint/sources/slot_layer.ts @@ -17,6 +17,7 @@ type slot_layer_t = { scale?: f32; angle?: f32; uv_type?: uv_type_t; + uv_map?: i32; paint_base?: bool; paint_opac?: bool; paint_occ?: bool; diff --git a/paint/sources/tab_layers.ts b/paint/sources/tab_layers.ts index 987ca9d5..2b189edc 100644 --- a/paint/sources/tab_layers.ts +++ b/paint/sources/tab_layers.ts @@ -543,7 +543,7 @@ function tab_layers_draw_layer_highlight(l: slot_layer_t, mini: bool) { function tab_layers_handle_layer_icon_state(l: slot_layer_t, i: i32, state: ui_state_t, uix: f32, uiy: f32) { let texpaint_preview: gpu_texture_t = l.texpaint_preview; - tab_layers_show_context_menu = false; + tab_layers_show_context_menu = false; // Layer preview tooltip if (ui.is_hovered && texpaint_preview != null) { @@ -848,10 +848,20 @@ function tab_layers_draw_layer_context_menu(l: slot_layer_t, mini: bool) { layers_on_resized(); } - // ui_menu_align(); - // let hh: ui_handle_t = ui_handle(__ID__); - // let aruv: string[] = [ "main" ]; - // ui_combo(hh, aruv, tr("UV Map"), true); + ui_menu_align(); + let huv: ui_handle_t = ui_handle(__ID__); + huv.i = l.uv_map; + let aruv: string[] = [ "uv0" ]; + if (mesh_data_get_vertex_array(context_raw.paint_object.data, "tex1") != null) { + array_push(aruv, "uv1"); + } + ui_combo(huv, aruv, tr("UV Map"), true); + l.uv_map = huv.i; + if (huv.changed) { + make_material_parse_paint_material(); + make_material_parse_mesh_material(); + ui_menu_keep_open = true; + } /// if (arm_android || arm_ios) // let bits_items: string[] = ["8"]; @@ -916,7 +926,6 @@ function tab_layers_draw_layer_context_menu(l: slot_layer_t, mini: bool) { } if (!slot_layer_is_group(l)) { - let base_handle: ui_handle_t = ui_nest(ui_handle(__ID__), l.id); let opac_handle: ui_handle_t = ui_nest(ui_handle(__ID__), l.id); let nor_handle: ui_handle_t = ui_nest(ui_handle(__ID__), l.id); diff --git a/paint/sources/util_mesh.ts b/paint/sources/util_mesh.ts index f058d1a2..f21a388e 100644 --- a/paint/sources/util_mesh.ts +++ b/paint/sources/util_mesh.ts @@ -24,12 +24,15 @@ function util_mesh_merge(paint_objects: mesh_object_t[] = null) { max_scale = paint_objects[i].data.scale_pos; } } - vlen = math_floor(vlen / 4); - let va0: i16_array_t = i16_array_create(vlen * 4); - let va1: i16_array_t = i16_array_create(vlen * 2); - let va2: i16_array_t = i16_array_create(vlen * 2); - let va3: i16_array_t = paint_objects[0].data.vertex_arrays.length > 3 ? i16_array_create(vlen * 4) : null; - let ia: u32_array_t = u32_array_create(ilen); + vlen = math_floor(vlen / 4); + let va0: i16_array_t = i16_array_create(vlen * 4); + let va1: i16_array_t = i16_array_create(vlen * 2); + let va2: i16_array_t = i16_array_create(vlen * 2); + let vatex1: i16_array_t = mesh_data_get_vertex_array(paint_objects[0].data, "tex1") != null ? i16_array_create(vlen * 2) : null; + let vacol: i16_array_t = mesh_data_get_vertex_array(paint_objects[0].data, "col") != null ? i16_array_create(vlen * 4) : null; + let tex1i: i32 = 3; + let coli: i32 = vatex1 != null ? 4 : 3; + let ia: u32_array_t = u32_array_create(ilen); let voff: i32 = 0; let ioff: i32 = 0; @@ -65,10 +68,16 @@ function util_mesh_merge(paint_objects: mesh_object_t[] = null) { for (let j: i32 = 0; j < vas[2].values.length; ++j) { va2[j + voff * 2] = vas[2].values[j]; } + // Tex1 + if (vatex1 != null) { + for (let j: i32 = 0; j < vas[tex1i].values.length; ++j) { + vatex1[j + voff * 2] = vas[tex1i].values[j]; + } + } // Col - if (va3 != null) { - for (let j: i32 = 0; j < vas[3].values.length; ++j) { - va3[j + voff * 4] = vas[3].values[j]; + if (vacol != null) { + for (let j: i32 = 0; j < vas[coli].values.length; ++j) { + vacol[j + voff * 4] = vas[coli].values[j]; } } // Indices @@ -90,9 +99,13 @@ function util_mesh_merge(paint_objects: mesh_object_t[] = null) { scale_pos : max_scale, scale_tex : 1.0 }; - if (va3 != null) { - let col: vertex_array_t = {values : va3, attrib : "col", data : "short4norm"}; - array_push(raw.vertex_arrays, col); + if (vatex1 != null) { + let va: vertex_array_t = {values : vatex1, attrib : "tex1", data : "short2norm"}; + array_push(raw.vertex_arrays, va); + } + if (vacol != null) { + let va: vertex_array_t = {values : vacol, attrib : "col", data : "short4norm"}; + array_push(raw.vertex_arrays, va); } util_mesh_remove_merged();