diff --git a/base/sources/ts/base.ts b/base/sources/ts/base.ts index 0549c57a..e24e63b7 100644 --- a/base/sources/ts/base.ts +++ b/base/sources/ts/base.ts @@ -824,7 +824,7 @@ function base_init_config() { raw.dilate_radius = 2; raw.gpu_inference = true; raw.blender = ""; - raw.scene_atlas_res = 0; + raw.scene_atlas_res = texture_res_t.RES8192; raw.pathtrace_mode = pathtrace_mode_t.FAST; raw.grid_snap = false; diff --git a/base/sources/ts/enums.ts b/base/sources/ts/enums.ts index 40b356bc..0b025d20 100644 --- a/base/sources/ts/enums.ts +++ b/base/sources/ts/enums.ts @@ -167,7 +167,7 @@ enum mesh_format_t { ARM = 1, } -enum menu_category_t { +enum menubar_category_t { FILE = 0, EDIT = 1, VIEWPORT = 2, diff --git a/base/sources/ts/ui_toolbar.ts b/base/sources/ts/ui_toolbar.ts index df96f3b9..f6fc107b 100644 --- a/base/sources/ts/ui_toolbar.ts +++ b/base/sources/ts/ui_toolbar.ts @@ -98,7 +98,7 @@ function ui_toolbar_render_ui() { if (context_is_floating_toolbar()) { x += ui_toolbar_x(); y += ui_toolbar_x(); - h = ui_toolbar_tool_names.length * (ui_toolbar_w() + 2); + h = (ui_toolbar_tool_names.length + 1) * (ui_toolbar_w() + 2); ui.ops.theme.WINDOW_BG_COL = ui.ops.theme.SEPARATOR_COL; } diff --git a/paint/project.js b/paint/project.js index dd89200f..c3c3ca0c 100644 --- a/paint/project.js +++ b/paint/project.js @@ -2,6 +2,7 @@ let flags = globalThis.flags; flags.name = "ArmorPaint"; flags.package = "org.armorpaint"; +flags.with_video_write = true; let project = new Project(flags.name); project.add_define("is_paint"); diff --git a/paint/sources/base_ext.ts b/paint/sources/base_ext.ts index 1cabd543..4b75909c 100644 --- a/paint/sources/base_ext.ts +++ b/paint/sources/base_ext.ts @@ -9,6 +9,11 @@ function base_ext_render() { base_init_undo_layers(); } + + if (context_raw.tool == tool_type_t.GIZMO) { + sim_init(); + sim_update(); + } } function base_ext_init_config(raw: config_t) { @@ -16,5 +21,13 @@ function base_ext_init_config(raw: config_t) { } function base_ext_update() { + if (context_raw.tool == tool_type_t.GIZMO) { + if (keyboard_down("control") && keyboard_started("d")) { + sim_duplicate(); + } + if (keyboard_started("delete")) { + sim_delete(); + } + } } diff --git a/paint/sources/context_ext.ts b/paint/sources/context_ext.ts index 532b8859..2b72ce84 100644 --- a/paint/sources/context_ext.ts +++ b/paint/sources/context_ext.ts @@ -13,6 +13,11 @@ function context_ext_select_paint_object(o: mesh_object_t) { let p: mesh_object_t = project_paint_objects[i]; p.skip_context = "paint"; } + + ///if_forge + context_raw.paint_object.skip_context = ""; + ///end + context_raw.paint_object = o; let mask: i32 = slot_layer_get_object_mask(context_raw.layer); diff --git a/paint/sources/sim.ts b/paint/sources/sim.ts new file mode 100644 index 00000000..62f545bb --- /dev/null +++ b/paint/sources/sim.ts @@ -0,0 +1,136 @@ + +let sim_running: bool = false; +let sim_transforms: mat4_box_t[]; +let sim_object_script_map: map_t = map_create(); +let sim_record: bool = false; +let sim_initialized: bool = false; + +function sim_init() { + if (sim_initialized) { + return; + } + physics_world_create(); + sim_initialized = true; +} + +function sim_update() { + + render_path_raytrace_ready = false; + + if (sim_running) { + // if (render_path_raytrace_frame != 1) { + // return; + // } + + let objects: object_t[] = map_keys(sim_object_script_map); + for (let i: i32 = 0; i < objects.length; ++i) { + let o: object_t = objects[i]; + let s: string = map_get(sim_object_script_map, o); + let addr: string = i64_to_string((i64)(o.transform)); + s = "{let transform=" + addr + ";" + s + "}"; + js_eval(s); + } + + let world: physics_world_t = physics_world_active; + physics_world_update(world); + + iron_delay_idle_sleep(); + + if (sim_record) { + let rt: render_target_t = map_get(render_path_render_targets, "last"); + let pixels: buffer_t = gpu_get_texture_pixels(rt._image); + ///if (arm_metal || arm_vulkan) + export_arm_bgra_swap(pixels); + ///end + iron_mp4_encode(pixels); + } + } +} + +function sim_play() { + sim_running = true; + + if (sim_record) { + if (project_filepath == "") { + console_error(tr("Save project first")); + sim_record = false; + return; + } + let path: string = path_base_dir(project_filepath) + "/output.mp4"; + let rt: render_target_t = map_get(render_path_render_targets, "last"); + iron_mp4_begin(path, rt._image.width, rt._image.height); + } + + // Save transforms + sim_transforms = []; + let pos: mesh_object_t[] = project_paint_objects; + for (let i: i32 = 0; i < pos.length; ++i) { + let m: mat4_box_t = { v: pos[i].base.transform.local }; + array_push(sim_transforms, m); + } +} + +function sim_stop() { + sim_running = false; + + if (sim_record) { + iron_mp4_end(); + } + + // Restore transforms + let pos: mesh_object_t[] = project_paint_objects; + for (let i: i32 = 0; i < pos.length; ++i) { + transform_set_matrix(pos[i].base.transform, sim_transforms[i].v); + + let pb: physics_body_t = map_get(physics_body_object_map, pos[i].base.uid); + if (pb != null) { + physics_body_sync_transform(pb); + } + } +} + +function sim_add_body(o: object_t, shape: physics_shape_t, mass: f32) { + let body: physics_body_t = physics_body_create(); + body.shape = shape; + body.mass = mass; + physics_body_init(body, o); +} + +function sim_remove_body(uid: i32) { + physics_body_remove(uid); +} + +function sim_duplicate() { + // Mesh + let so: mesh_object_t = context_raw.selected_object.ext; + let dup: mesh_object_t = scene_add_mesh_object(so.data, so.materials, so.base.parent); + transform_set_matrix(dup.base.transform, so.base.transform.local); + array_push(project_paint_objects, dup); + dup.base.name = so.base.name; + + // Physics + let pb: physics_body_t = map_get(physics_body_object_map, so.base.uid); + if (pb != null) { + let pbdup: physics_body_t = physics_body_create(); + pbdup.shape = pb.shape; + pbdup.mass = pb.mass; + physics_body_init(pbdup, dup.base); + } + + ///if is_forge + _tab_scene_paint_object_length++; + tab_scene_sort(); + ///end +} + +function sim_delete() { + let so: mesh_object_t = context_raw.selected_object.ext; + array_remove(project_paint_objects, so); + mesh_object_remove(so); + sim_remove_body(so.base.uid); + + ///if is_forge + _tab_scene_paint_object_length--; + tab_scene_sort(); + ///end +} diff --git a/paint/sources/ui_header_ext.ts b/paint/sources/ui_header_ext.ts index b43973b1..7b8a8ec6 100644 --- a/paint/sources/ui_header_ext.ts +++ b/paint/sources/ui_header_ext.ts @@ -516,4 +516,16 @@ function ui_header_draw_tool_properties(ui: ui_t) { } } } + + if (context_raw.tool == tool_type_t.GIZMO) { + if (!sim_running && ui_button("Play")) { + sim_play(); + context_raw.selected_object = scene_camera.base; + } + if (sim_running && ui_button("Stop")) { + sim_stop(); + } + let h_record: ui_handle_t = ui_handle(__ID__); + sim_record = ui_check(h_record, tr("Record")); + } } diff --git a/paint/sources/ui_toolbar_ext.ts b/paint/sources/ui_toolbar_ext.ts index f19ef593..0396492f 100644 --- a/paint/sources/ui_toolbar_ext.ts +++ b/paint/sources/ui_toolbar_ext.ts @@ -1,17 +1,17 @@ function ui_toolbar_ext_draw_tools(ui: ui_t, img: gpu_texture_t, icon_accent: i32, keys: string[]) { - - ui_toolbar_draw_tool(tool_type_t.BRUSH, ui, img, icon_accent, keys); - ui_toolbar_draw_tool(tool_type_t.ERASER, ui, img, icon_accent, keys); - ui_toolbar_draw_tool(tool_type_t.FILL, ui, img, icon_accent, keys); - ui_toolbar_draw_tool(tool_type_t.DECAL, ui, img, icon_accent, keys); - ui_toolbar_draw_tool(tool_type_t.TEXT, ui, img, icon_accent, keys); - ui_toolbar_draw_tool(tool_type_t.CLONE, ui, img, icon_accent, keys); - ui_toolbar_draw_tool(tool_type_t.BLUR, ui, img, icon_accent, keys); - ui_toolbar_draw_tool(tool_type_t.SMUDGE, ui, img, icon_accent, keys); - ui_toolbar_draw_tool(tool_type_t.PARTICLE, ui, img, icon_accent, keys); - ui_toolbar_draw_tool(tool_type_t.COLORID, ui, img, icon_accent, keys); - ui_toolbar_draw_tool(tool_type_t.PICKER, ui, img, icon_accent, keys); - ui_toolbar_draw_tool(tool_type_t.BAKE, ui, img, icon_accent, keys); - ui_toolbar_draw_tool(tool_type_t.MATERIAL, ui, img, icon_accent, keys); + ui_toolbar_draw_tool(tool_type_t.BRUSH, ui, img, icon_accent, keys); + ui_toolbar_draw_tool(tool_type_t.ERASER, ui, img, icon_accent, keys); + ui_toolbar_draw_tool(tool_type_t.FILL, ui, img, icon_accent, keys); + ui_toolbar_draw_tool(tool_type_t.DECAL, ui, img, icon_accent, keys); + ui_toolbar_draw_tool(tool_type_t.TEXT, ui, img, icon_accent, keys); + ui_toolbar_draw_tool(tool_type_t.CLONE, ui, img, icon_accent, keys); + ui_toolbar_draw_tool(tool_type_t.BLUR, ui, img, icon_accent, keys); + ui_toolbar_draw_tool(tool_type_t.SMUDGE, ui, img, icon_accent, keys); + ui_toolbar_draw_tool(tool_type_t.PARTICLE, ui, img, icon_accent, keys); + ui_toolbar_draw_tool(tool_type_t.COLORID, ui, img, icon_accent, keys); + ui_toolbar_draw_tool(tool_type_t.PICKER, ui, img, icon_accent, keys); + ui_toolbar_draw_tool(tool_type_t.BAKE, ui, img, icon_accent, keys); + ui_toolbar_draw_tool(tool_type_t.MATERIAL, ui, img, icon_accent, keys); + ui_toolbar_draw_tool(tool_type_t.GIZMO, ui, img, icon_accent, keys); } diff --git a/paint/sources/util_mesh_ext.ts b/paint/sources/util_mesh_ext.ts new file mode 100644 index 00000000..f92ca61a --- /dev/null +++ b/paint/sources/util_mesh_ext.ts @@ -0,0 +1,41 @@ + +function _util_mesh_unique_data_count(): i32 { + return util_mesh_ext_get_unique().length; +} + +function util_mesh_ext_pack_uvs(texa: i16_array_t) { + // Scale tex coords into global atlas + let atlas_w: i32 = config_get_scene_atlas_res(); + let item_i: i32 = _util_mesh_unique_data_count() - 1; // Add the one being imported + let item_w: i32 = config_get_layer_res(); + let atlas_stride: i32 = atlas_w / item_w; + let atlas_step: i32 = 32767 / atlas_stride; + let item_x: i32 = (item_i % atlas_stride) * atlas_step; + let item_y: i32 = math_floor(item_i / atlas_stride) * atlas_step; + for (let i: i32 = 0; i < texa.length / 2; ++i) { + texa[i * 2] = texa[i * 2] / atlas_stride + item_x; + texa[i * 2 + 1] = texa[i * 2 + 1] / atlas_stride + item_y; + } +} + +function util_mesh_ext_get_unique(): mesh_object_t[] { + let ar: mesh_object_t[] = []; + + for (let i: i32 = 0; i < project_paint_objects.length; ++i) { + if (!project_paint_objects[i].base.visible) { + continue; + } + let found: bool = false; + for (let j: i32 = 0; j < i; ++j) { + if (project_paint_objects[i].data == project_paint_objects[j].data) { + found = true; + break; + } + } + if (!found) { + array_push(ar, project_paint_objects[i]); + } + } + + return ar; +}