From ebded1126ea1b2ece08a09bbbc4048822fdbf918 Mon Sep 17 00:00:00 2001 From: luboslenco Date: Mon, 20 Jan 2025 17:23:03 +0100 Subject: [PATCH] Add merge shared vertices option for obj export --- base/sources/box_export.ts | 12 ++++- base/sources/export_mesh.ts | 6 ++- base/sources/export_obj.ts | 99 +++++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 4 deletions(-) diff --git a/base/sources/box_export.ts b/base/sources/box_export.ts index d103ab77..235983af 100644 --- a/base/sources/box_export.ts +++ b/base/sources/box_export.ts @@ -32,6 +32,7 @@ let box_export_color_spaces: string[] = [ let _box_export_bake_material: bool; let _box_export_t: export_preset_texture_t; let _box_export_apply_displacement: bool; +let _box_export_merge_vertices: bool; function box_export_show_textures() { ui_box_show_custom(function (ui: ui_t) { @@ -356,7 +357,7 @@ function box_export_show_mesh() { ui_box_show_custom(function (ui: ui_t) { let htab: ui_handle_t = ui_handle(__ID__); box_export_tab_export_mesh(ui, htab); - }); + }, 400, 240); } function box_export_tab_export_mesh(ui: ui_t, htab: ui_handle_t) { @@ -381,6 +382,12 @@ function box_export_tab_export_mesh(ui: ui_t, htab: ui_handle_t) { let apply_displacement: bool = ui_check(ui_handle(__ID__), tr("Apply Displacement")); + let hmerge: ui_handle_t = ui_handle(__ID__); + if (hmerge.init) { + hmerge.selected = true; + } + let merge_vertices: bool = ui_check(hmerge, tr("Merge Shared Vertices")); + let tris: i32 = 0; let pos: i32 = box_export_mesh_handle.position; let paint_objects: mesh_object_t[]; @@ -407,6 +414,7 @@ function box_export_tab_export_mesh(ui: ui_t, htab: ui_handle_t) { if (ui_button(tr("Export"))) { ui_box_hide(); _box_export_apply_displacement = apply_displacement; + _box_export_merge_vertices = merge_vertices; ui_files_show(context_raw.export_mesh_format == mesh_format_t.OBJ ? "obj" : "arm", true, false, function (path: string) { ///if (arm_android || arm_ios) let f: string = sys_title(); @@ -429,7 +437,7 @@ function box_export_tab_export_mesh(ui: ui_t, htab: ui_handle_t) { paint_objects = [po]; } - export_mesh_run(path + path_sep + f, paint_objects, _box_export_apply_displacement); + export_mesh_run(path + path_sep + f, paint_objects, _box_export_apply_displacement, _box_export_merge_vertices); }); } } diff --git a/base/sources/export_mesh.ts b/base/sources/export_mesh.ts index b82098d2..f0052bf0 100644 --- a/base/sources/export_mesh.ts +++ b/base/sources/export_mesh.ts @@ -1,10 +1,12 @@ -function export_mesh_run(path: string, paint_objects: mesh_object_t[] = null, apply_disp: bool = false) { +function export_mesh_run(path: string, paint_objects: mesh_object_t[] = null, apply_disp: bool = false, merge_vertices: bool = true) { if (paint_objects == null) { paint_objects = project_paint_objects; } if (context_raw.export_mesh_format == mesh_format_t.OBJ) { - export_obj_run(path, paint_objects, apply_disp); + merge_vertices ? + export_obj_run(path, paint_objects, apply_disp) : + export_obj_run_fast(path, paint_objects); } else { export_arm_run_mesh(path, paint_objects); diff --git a/base/sources/export_obj.ts b/base/sources/export_obj.ts index e0ce614f..59d39e56 100644 --- a/base/sources/export_obj.ts +++ b/base/sources/export_obj.ts @@ -177,3 +177,102 @@ function export_obj_run(path: string, paint_objects: mesh_object_t[], apply_disp } iron_file_save_bytes(path, o, 0); } + +function export_obj_run_fast(path: string, paint_objects: mesh_object_t[]) { + // Skips merging shared vertices + + let o: u8[] = []; + export_obj_write_string(o, "# armorpaint.org\n"); + + let poff: i32 = 0; + let noff: i32 = 0; + let toff: i32 = 0; + for (let i: i32 = 0; i < paint_objects.length; ++i) { + let p: mesh_object_t = paint_objects[i]; + let mesh: mesh_data_t = p.data; + let inv: f32 = 1 / 32767; + let sc: f32 = p.data.scale_pos * inv; + let posa: i16_array_t = mesh.vertex_arrays[0].values; + let nora: i16_array_t = mesh.vertex_arrays[1].values; + let texa: i16_array_t = mesh.vertex_arrays[2].values; + + let pi: i32 = posa.length / 4; + let ni: i32 = pi; + let ti: i32 = pi; + + export_obj_write_string(o, "o " + p.base.name + "\n"); + for (let i: i32 = 0; i < pi; ++i) { + export_obj_write_string(o, "v "); + let f: f32 = posa[i * 4] * sc; + export_obj_write_string(o, f + ""); + export_obj_write_string(o, " "); + f = posa[i * 4 + 2] * sc; + export_obj_write_string(o, f + ""); + export_obj_write_string(o, " "); + f = -posa[i * 4 + 1] * sc; + export_obj_write_string(o, f + ""); + export_obj_write_string(o, "\n"); + } + for (let i: i32 = 0; i < ni; ++i) { + export_obj_write_string(o, "vn "); + let f: f32 = nora[i * 2] * inv; + export_obj_write_string(o, f + ""); + export_obj_write_string(o, " "); + f = posa[i * 4 + 3] * inv; + export_obj_write_string(o, f + ""); + export_obj_write_string(o, " "); + f = -nora[i * 2 + 1] * inv; + export_obj_write_string(o, f + ""); + export_obj_write_string(o, "\n"); + } + for (let i: i32 = 0; i < ti; ++i) { + export_obj_write_string(o, "vt "); + let f: f32 = texa[i * 2] * inv; + export_obj_write_string(o, f + ""); + export_obj_write_string(o, " "); + f = 1.0 - texa[i * 2 + 1] * inv; + export_obj_write_string(o, f + ""); + export_obj_write_string(o, "\n"); + } + + let inda: u32_array_t = mesh.index_arrays[0].values; + for (let i: i32 = 0; i < math_floor(inda.length / 3); ++i) { + let pi1: i32 = inda[i * 3 ] + 1 + poff; + let pi2: i32 = inda[i * 3 + 1] + 1 + poff; + let pi3: i32 = inda[i * 3 + 2] + 1 + poff; + let ni1: i32 = inda[i * 3 ] + 1 + noff; + let ni2: i32 = inda[i * 3 + 1] + 1 + noff; + let ni3: i32 = inda[i * 3 + 2] + 1 + noff; + let ti1: i32 = inda[i * 3 ] + 1 + toff; + let ti2: i32 = inda[i * 3 + 1] + 1 + toff; + let ti3: i32 = inda[i * 3 + 2] + 1 + toff; + export_obj_write_string(o, "f "); + export_obj_write_string(o, pi1 + ""); + export_obj_write_string(o, "/"); + export_obj_write_string(o, ti1 + ""); + export_obj_write_string(o, "/"); + export_obj_write_string(o, ni1 + ""); + export_obj_write_string(o, " "); + export_obj_write_string(o, pi2 + ""); + export_obj_write_string(o, "/"); + export_obj_write_string(o, ti2 + ""); + export_obj_write_string(o, "/"); + export_obj_write_string(o, ni2 + ""); + export_obj_write_string(o, " "); + export_obj_write_string(o, pi3 + ""); + export_obj_write_string(o, "/"); + export_obj_write_string(o, ti3 + ""); + export_obj_write_string(o, "/"); + export_obj_write_string(o, ni3 + ""); + export_obj_write_string(o, "\n"); + } + poff += pi; + noff += ni; + toff += ti; + } + + if (!ends_with(path, ".obj")) { + path += ".obj"; + } + iron_file_save_bytes(path, o, 0); +}