From d4eead86cabf96130b403fedd1d33b21b030d4e3 Mon Sep 17 00:00:00 2001 From: luboslenco Date: Fri, 8 Aug 2025 14:08:39 +0200 Subject: [PATCH 1/8] Menubar cleanup --- base/sources/ts/ui_menu.ts | 534 +-------------------------------- base/sources/ts/ui_menubar.ts | 550 +++++++++++++++++++++++++++++++++- 2 files changed, 548 insertions(+), 536 deletions(-) diff --git a/base/sources/ts/ui_menu.ts b/base/sources/ts/ui_menu.ts index e283e04a..d274db01 100644 --- a/base/sources/ts/ui_menu.ts +++ b/base/sources/ts/ui_menu.ts @@ -1,10 +1,9 @@ let ui_menu_show: bool = false; -let ui_menu_category: i32 = 0; +let ui_menu_nested: bool = false; let ui_menu_x: i32 = 0; let ui_menu_y: i32 = 0; let ui_menu_h: i32 = 0; -let ui_menu_elements: i32 = 0; //// let ui_menu_keep_open: bool = false; let ui_menu_commands: (ui: ui_t)=>void = null; let ui_menu_show_first: bool = true; @@ -12,11 +11,6 @@ let ui_menu_hide_flag: bool = false; let _ui_menu_render_msg: string; -type update_info_t = { - version: i32; - version_name: string; -}; - function ui_menu_render() { let ui: ui_t = base_ui_menu; let menu_w: i32 = ui_menu_commands != null ? @@ -30,6 +24,11 @@ function ui_menu_render() { let _ELEMENT_H: i32 = ui.ops.theme.ELEMENT_H; ui.ops.theme.ELEMENT_H = config_raw.touch_ui ? (28 + 2) : 28; + if (ui_menu_nested) { + ui_menu_show_first = true; + ui_menu_nested = false; + } + // First draw out of screen, then align the menu based on menu height if (ui_menu_show_first) { ui_menu_x -= iron_window_width() * 2; @@ -43,523 +42,6 @@ function ui_menu_render() { if (ui_menu_commands != null) { ui_menu_commands(ui); } - else { - if (ui_menu_category == menu_category_t.FILE) { - if (ui_menu_button(tr("New Project..."), map_get(config_keymap, "file_new"))) { - project_new_box(); - } - if (ui_menu_button(tr("Open..."), map_get(config_keymap, "file_open"))) { - project_open(); - } - if (ui_menu_button(tr("Open Recent..."), map_get(config_keymap, "file_open_recent"))) { - box_projects_show(); - } - if (ui_menu_button(tr("Save"), map_get(config_keymap, "file_save"))) { - project_save(); - } - if (ui_menu_button(tr("Save As..."), map_get(config_keymap, "file_save_as"))) { - project_save_as(); - } - ui_menu_separator(ui); - if (ui_menu_button(tr("Import Texture..."), map_get(config_keymap, "file_import_assets"))) { - project_import_asset(string_array_join(path_texture_formats, ","), false); - } - if (ui_menu_button(tr("Import Envmap..."))) { - ui_files_show("hdr", false, false, function (path: string) { - if (!ends_with(path, ".hdr")) { - console_error(tr("Error: .hdr file expected")); - return; - } - import_asset_run(path); - }); - } - - ///if is_paint - if (ui_menu_button(tr("Import Font..."))) { - project_import_asset("ttf,ttc,otf"); - } - if (ui_menu_button(tr("Import Material..."))) { - project_import_material(); - } - if (ui_menu_button(tr("Import Brush..."))) { - project_import_brush(); - } - ///end - - ///if (is_paint || is_lab) - if (ui_menu_button(tr("Import Swatches..."))) { - project_import_swatches(); - } - ///end - if (ui_menu_button(tr("Import Mesh..."))) { - project_import_mesh(); - } - if (ui_menu_button(tr("Reimport Mesh"), map_get(config_keymap, "file_reimport_mesh"))) { - project_reimport_mesh(); - } - if (ui_menu_button(tr("Reimport Textures"), map_get(config_keymap, "file_reimport_textures"))) { - project_reimport_textures(); - } - ui_menu_separator(ui); - ///if (is_paint || is_lab) - if (ui_menu_button(tr("Export Textures..."), map_get(config_keymap, "file_export_textures_as"))) { - context_raw.layers_export = export_mode_t.VISIBLE; - box_export_show_textures(); - } - if (ui_menu_button(tr("Export Swatches..."))) { - project_export_swatches(); - } - ///end - if (ui_menu_button(tr("Export Mesh..."))) { - context_raw.export_mesh_index = 0; // All - box_export_show_mesh(); - } - - ///if is_paint - if (ui_menu_button(tr("Bake Material..."))) { - box_export_show_bake_material(); - } - ///end - - ui_menu_separator(ui); - if (ui_menu_button(tr("Exit"))) { - iron_stop(); - } - } - else if (ui_menu_category == menu_category_t.EDIT) { - let step_undo: string = ""; - let step_redo: string = ""; - if (history_undos > 0) { - step_undo = history_steps[history_steps.length - 1 - history_redos].name; - } - if (history_redos > 0) { - step_redo = history_steps[history_steps.length - history_redos].name; - } - - ui.enabled = history_undos > 0; - let vars_undo: map_t = map_create(); - map_set(vars_undo, "step", step_undo); - if (ui_menu_button(tr("Undo {step}", vars_undo), map_get(config_keymap, "edit_undo"))) { - history_undo(); - } - - ui.enabled = history_redos > 0; - let vars_redo: map_t = map_create(); - map_set(vars_redo, "step", step_redo); - if (ui_menu_button(tr("Redo {step}", vars_redo), map_get(config_keymap, "edit_redo"))) { - history_redo(); - } - ui.enabled = true; - ui_menu_separator(ui); - if (ui_menu_button(tr("Preferences..."), map_get(config_keymap, "edit_prefs"))) { - box_preferences_show(); - } - } - else if (ui_menu_category == menu_category_t.VIEWPORT) { - if (ui_menu_button(tr("Distract Free"), map_get(config_keymap, "view_distract_free"))) { - ui_base_toggle_distract_free(); - ui_base_ui.is_hovered = false; - } - - ///if !(arm_android || arm_ios) - if (ui_menu_button(tr("Toggle Fullscreen"), "alt+enter")) { - base_toggle_fullscreen(); - } - ///end - - ui.changed = false; - - let p: world_data_t = scene_world; - let env_handle: ui_handle_t = ui_handle(__ID__); - env_handle.value = p.strength; - ui_menu_align(ui); - p.strength = ui_slider(env_handle, tr("Environment"), 0.0, 8.0, true); - if (env_handle.changed) { - context_raw.ddirty = 2; - } - - let enva_handle: ui_handle_t = ui_handle(__ID__); - enva_handle.value = context_raw.envmap_angle / math_pi() * 180.0; - if (enva_handle.value < 0) { - enva_handle.value += (math_floor(-enva_handle.value / 360) + 1) * 360; - } - else if (enva_handle.value > 360) { - enva_handle.value -= math_floor(enva_handle.value / 360) * 360; - } - ui_menu_align(ui); - context_raw.envmap_angle = ui_slider(enva_handle, tr("Environment Angle"), 0.0, 360.0, true, 1) / 180.0 * math_pi(); - if (ui.is_hovered) { - let vars: map_t = map_create(); - map_set(vars, "shortcut", map_get(config_keymap, "rotate_envmap")); - ui_tooltip(tr("{shortcut} and move mouse", vars)); - } - if (enva_handle.changed) { - context_raw.ddirty = 2; - } - - ///if is_paint - let split_view_handle: ui_handle_t = ui_handle(__ID__); - if (split_view_handle.init) { - split_view_handle.selected = context_raw.split_view; - } - context_raw.split_view = ui_check(split_view_handle, " " + tr("Split View")); - if (split_view_handle.changed) { - base_resize(); - } - ///end - - ///if is_lab - let brush_scale_handle: ui_handle_t = ui_handle(__ID__); - if (brush_scale_handle.init) { - brush_scale_handle.value = context_raw.brush_scale; - } - ui_menu_align(ui); - context_raw.brush_scale = ui_slider(brush_scale_handle, tr("UV Scale"), 0.01, 5.0, true); - if (brush_scale_handle.changed) { - make_material_parse_mesh_material(); - render_path_raytrace_uv_scale = context_raw.brush_scale; - render_path_raytrace_ready = false; - } - ///end - - let cull_handle: ui_handle_t = ui_handle(__ID__); - if (cull_handle.init) { - cull_handle.selected = context_raw.cull_backfaces; - } - context_raw.cull_backfaces = ui_check(cull_handle, " " + tr("Cull Backfaces")); - if (cull_handle.changed) { - make_material_parse_mesh_material(); - } - - let filter_handle: ui_handle_t = ui_handle(__ID__); - if (filter_handle.init) { - filter_handle.selected = context_raw.texture_filter; - } - context_raw.texture_filter = ui_check(filter_handle, " " + tr("Filter Textures")); - if (filter_handle.changed) { - make_material_parse_paint_material(); - make_material_parse_mesh_material(); - } - - ///if is_paint - context_raw.draw_wireframe = ui_check(context_raw.wireframe_handle, " " + tr("Wireframe")); - if (context_raw.wireframe_handle.changed) { - let current: gpu_texture_t = _draw_current; - draw_end(); - util_uv_cache_uv_map(); - draw_begin(current); - make_material_parse_mesh_material(); - } - ///end - - ///if is_paint - context_raw.draw_texels = ui_check(context_raw.texels_handle, " " + tr("Texels")); - if (context_raw.texels_handle.changed) { - make_material_parse_mesh_material(); - } - ///end - - let compass_handle: ui_handle_t = ui_handle(__ID__); - if (compass_handle.init) { - compass_handle.selected = context_raw.show_compass; - } - context_raw.show_compass = ui_check(compass_handle, " " + tr("Compass")); - if (compass_handle.changed) { - context_raw.ddirty = 2; - } - - context_raw.show_envmap = ui_check(context_raw.show_envmap_handle, " " + tr("Envmap")); - if (context_raw.show_envmap_handle.changed) { - context_load_envmap(); - context_raw.ddirty = 2; - } - - context_raw.show_envmap_blur = ui_check(context_raw.show_envmap_blur_handle, " " + tr("Blur Envmap")); - if (context_raw.show_envmap_blur_handle.changed) { - context_raw.ddirty = 2; - } - - context_update_envmap(); - - if (ui.changed) { - ui_menu_keep_open = true; - } - } - else if (ui_menu_category == menu_category_t.MODE) { - let mode_handle: ui_handle_t = ui_handle(__ID__); - mode_handle.position = context_raw.viewport_mode; - let modes: string[] = [ - tr("Lit"), - tr("Base Color"), - ///if (is_paint || is_lab) - tr("Normal"), - tr("Occlusion"), - tr("Roughness"), - tr("Metallic"), - tr("Opacity"), - tr("Height"), - ///end - ///if (is_paint) - tr("Emission"), - tr("Subsurface"), - ///end - ///if is_paint - tr("TexCoord"), - tr("Object Normal"), - tr("Material ID"), - tr("Object ID"), - tr("Mask") - ///end - ]; - let shortcuts: string[] = ["l", "b", "n", "o", "r", "m", "a", "h", "e", "s", "t", "1", "2", "3", "4"]; - - if (gpu_raytrace_supported()) { - array_push(modes, tr("Path Traced")); - array_push(shortcuts, "p"); - } - - for (let i: i32 = 0; i < modes.length; ++i) { - let shortcut: string = config_raw.touch_ui ? "" : map_get(config_keymap, "viewport_mode") + ", " + shortcuts[i]; - ui_radio(mode_handle, i, modes[i], shortcut); - } - - if (mode_handle.changed) { - context_set_viewport_mode(mode_handle.position); - // TODO: rotate mode is not supported for path tracing yet - if (mode_handle.position == viewport_mode_t.PATH_TRACE && context_raw.camera_controls == camera_controls_t.ROTATE) { - context_raw.camera_controls = camera_controls_t.ORBIT; - viewport_reset(); - } - } - } - else if (ui_menu_category == menu_category_t.CAMERA) { - if (ui_menu_button(tr("Reset"), map_get(config_keymap, "view_reset"))) { - viewport_reset(); - viewport_scale_to_bounds(); - } - ui_menu_separator(ui); - if (ui_menu_button(tr("Front"), map_get(config_keymap, "view_front"))) { - viewport_set_view(0, -1, 0, math_pi() / 2, 0, 0); - } - if (ui_menu_button(tr("Back"), map_get(config_keymap, "view_back"))) { - viewport_set_view(0, 1, 0, math_pi() / 2, 0, math_pi()); - } - if (ui_menu_button(tr("Right"), map_get(config_keymap, "view_right"))) { - viewport_set_view(1, 0, 0, math_pi() / 2, 0, math_pi() / 2); - } - if (ui_menu_button(tr("Left"), map_get(config_keymap, "view_left"))) { - viewport_set_view(-1, 0, 0, math_pi() / 2, 0, -math_pi() / 2); - } - if (ui_menu_button(tr("Top"), map_get(config_keymap, "view_top"))) { - viewport_set_view(0, 0, 1, 0, 0, 0); - } - if (ui_menu_button(tr("Bottom"), map_get(config_keymap, "view_bottom"))) { - viewport_set_view(0, 0, -1, math_pi(), 0, math_pi()); - } - ui_menu_separator(ui); - - ui.changed = false; - - if (ui_menu_button(tr("Orbit Left"), map_get(config_keymap, "view_orbit_left"))) { - viewport_orbit(-math_pi() / 12, 0); - } - if (ui_menu_button(tr("Orbit Right"), map_get(config_keymap, "view_orbit_right"))) { - viewport_orbit(math_pi() / 12, 0); - } - if (ui_menu_button(tr("Orbit Up"), map_get(config_keymap, "view_orbit_up"))) { - viewport_orbit(0, -math_pi() / 12); - } - if (ui_menu_button(tr("Orbit Down"), map_get(config_keymap, "view_orbit_down"))) { - viewport_orbit(0, math_pi() / 12); - } - if (ui_menu_button(tr("Orbit Opposite"), map_get(config_keymap, "view_orbit_opposite"))) { - viewport_orbit_opposite(); - } - if (ui_menu_button(tr("Zoom In"), map_get(config_keymap, "view_zoom_in"))) { - viewport_zoom(0.2); - } - if (ui_menu_button(tr("Zoom Out"), map_get(config_keymap, "view_zoom_out"))) { - viewport_zoom(-0.2); - } - - let cam: camera_object_t = scene_camera; - context_raw.fov_handle = ui_handle(__ID__); - if (context_raw.fov_handle.init) { - context_raw.fov_handle.value = math_floor(cam.data.fov * 100) / 100; - } - ui_menu_align(ui); - cam.data.fov = ui_slider(context_raw.fov_handle, tr("FoV"), 0.3, 1.4, true); - if (context_raw.fov_handle.changed) { - viewport_update_camera_type(context_raw.camera_type); - } - - ui_menu_align(ui); - let camera_controls_handle: ui_handle_t = ui_handle(__ID__); - camera_controls_handle.position = context_raw.camera_controls; - let camera_controls_items: string[] = [tr("Orbit"), tr("Rotate"), tr("Fly")]; - context_raw.camera_controls = ui_inline_radio(camera_controls_handle, camera_controls_items, ui_align_t.LEFT); - - let vars: map_t = map_create(); - map_set(vars, "rotate_shortcut", map_get(config_keymap, "action_rotate")); - map_set(vars, "zoom_shortcut", map_get(config_keymap, "action_zoom")); - map_set(vars, "pan_shortcut", map_get(config_keymap, "action_pan")); - let orbit_and_rotate_tooltip: string = tr("Orbit and Rotate mode:\n{rotate_shortcut} or move right mouse button to rotate.\n{zoom_shortcut} or scroll to zoom.\n{pan_shortcut} or move middle mouse to pan.", vars); - let fly_tooltip: string = tr("Fly mode:\nHold the right mouse button and one of the following commands:\nmove mouse to rotate.\nw, up or scroll up to move forward.\ns, down or scroll down to move backward.\na or left to move left.\nd or right to move right.\ne to move up.\nq to move down.\nHold shift to move faster or alt to move slower."); - if (ui.is_hovered) { - ui_tooltip(orbit_and_rotate_tooltip + "\n\n" + fly_tooltip); - } - - ui_menu_align(ui); - let camera_type_items: string[] = [tr("Perspective"), tr("Orthographic")]; - context_raw.camera_type = ui_inline_radio(context_raw.cam_handle, camera_type_items, ui_align_t.LEFT); - if (ui.is_hovered) { - ui_tooltip(tr("Camera Type") + " (" + map_get(config_keymap, "view_camera_type") + ")"); - } - if (context_raw.cam_handle.changed) { - viewport_update_camera_type(context_raw.camera_type); - } - - if (ui.changed) { - ui_menu_keep_open = true; - } - } - else if (ui_menu_category == menu_category_t.HELP) { - if (ui_menu_button(tr("Manual"))) { - file_load_url(manifest_url + "/manual"); - } - if (ui_menu_button(tr("How To"))) { - file_load_url(manifest_url + "/howto"); - } - if (ui_menu_button(tr("What's New"))) { - file_load_url(manifest_url + "/notes"); - } - if (ui_menu_button(tr("Issue Tracker"))) { - file_load_url("https://github.com/armory3d/armortools/issues"); - } - if (ui_menu_button(tr("Report Bug"))) { - ///if (arm_macos || arm_ios) // Limited url length - file_load_url("https://github.com/armory3d/armortools/issues/new?labels=bug&template=bug_report.md&body=*" + manifest_title + "%20" + manifest_version + "-" + config_get_sha() + ",%20" + iron_system_id()); - ///else - file_load_url("https://github.com/armory3d/armortools/issues/new?labels=bug&template=bug_report.md&body=*" + manifest_title + "%20" + manifest_version + "-" + config_get_sha() + ",%20" + iron_system_id() + "*%0A%0A**Issue description:**%0A%0A**Steps to reproduce:**%0A%0A"); - ///end - } - if (ui_menu_button(tr("Request Feature"))) { - ///if (arm_macos || arm_ios) // Limited url length - file_load_url("https://github.com/armory3d/armortools/issues/new?labels=feature%20request&template=feature_request.md&body=*" + manifest_title + "%20" + manifest_version + "-" + config_get_sha() + ",%20" + iron_system_id()); - ///else - file_load_url("https://github.com/armory3d/armortools/issues/new?labels=feature%20request&template=feature_request.md&body=*" + manifest_title + "%20" + manifest_version + "-" + config_get_sha() + ",%20" + iron_system_id() + "*%0A%0A**Feature description:**%0A%0A"); - ///end - } - ui_menu_separator(ui); - - if (ui_menu_button(tr("Check for Updates..."))) { - ///if arm_android - file_load_url(manifest_url_android); - ///elseif arm_ios - file_load_url(manifest_url_ios); - ///else - // Retrieve latest version number - file_download_bytes("https://server.armorpaint.org/" + to_lower_case(manifest_title) + ".html", function (url: string, buffer: buffer_t) { - if (buffer != null) { - // Compare versions - let update: update_info_t = json_parse(sys_buffer_to_string(buffer)); - let update_version: i32 = math_floor(update.version); - if (update_version > 0) { - let date: string = config_get_date(); // 2019 -> 19 - date = substring(date, 2, date.length); - let date_int: i32 = parse_int(string_replace_all(date, "-", "")); - if (update_version > date_int) { - let vars: map_t = map_create(); - map_set(vars, "url", manifest_url); - ui_box_show_message(tr("Update"), tr("Update is available!\nPlease visit {url}.", vars)); - } - else { - ui_box_show_message(tr("Update"), tr("You are up to date!")); - } - } - } - else { - let vars: map_t = map_create(); - map_set(vars, "url", manifest_url); - ui_box_show_message(tr("Update"), tr("Unable to check for updates.\nPlease visit {url}.", vars)); - } - }); - ///end - } - - if (ui_menu_button(tr("About..."))) { - - let msg: string = manifest_title + ".org - v" + manifest_version + " (" + config_get_date() + ") - " + config_get_sha() + "\n"; - msg += iron_system_id() + " - " + strings_graphics_api(); - - ///if arm_windows - let save: string; - if (path_is_protected()) { - save = iron_internal_save_path(); - } - else { - save = path_data(); - } - save += path_sep + "tmp.txt"; - iron_sys_command("wmic path win32_VideoController get name > \"" + save + "\""); - let blob: buffer_t = iron_load_blob(save); - let u8: u8_array_t = blob; - let gpu_raw: string = ""; - for (let i: i32 = 0; i < math_floor(u8.length / 2); ++i) { - let c: string = string_from_char_code(u8[i * 2]); - gpu_raw += c; - } - - let gpus: string[] = string_split(gpu_raw, "\n"); - array_splice(gpus, 1, gpus.length - 2); - let gpu: string = ""; - for (let i: i32 = 0; i < gpus.length; ++i) { - let g: string = gpus[i]; - gpu += trim_end(g) + ", "; - } - gpu = substring(gpu, 0, gpu.length - 2); - msg += "\n" + gpu; - ///else - // { lshw -C display } - ///end - - _ui_menu_render_msg = msg; - - ui_box_show_custom(function (ui: ui_t) { - let tab_vertical: bool = config_raw.touch_ui; - if (ui_tab(ui_handle(__ID__), tr("About"), tab_vertical)) { - - let img: gpu_texture_t = data_get_image("badge.k"); - ui_image(img); - _ui_end_element(); - - let h: ui_handle_t = ui_handle(__ID__); - if (h.init) { - h.text = _ui_menu_render_msg; - } - ui_text_area(h, ui_align_t.LEFT, false); - - ui_row3(); - - ///if (arm_windows || arm_linux || arm_macos) - if (ui_button(tr("Copy"))) { - iron_copy_to_clipboard(_ui_menu_render_msg); - } - ///else - _ui_end_element(); - ///end - - if (ui_button(tr("Contributors"))) { - file_load_url("https://github.com/armory3d/armortools/graphs/contributors"); - } - if (ui_button(tr("OK"))) { - ui_box_hide(); - } - } - }, 400, 320); - } - } - } ui_menu_hide_flag = ui.combo_selected_handle == null && !ui_menu_keep_open && !ui_menu_show_first && (ui.changed || ui.input_released || ui.input_released_r || ui.is_escape_down); ui_menu_keep_open = false; @@ -594,6 +76,10 @@ function ui_menu_hide() { function ui_menu_draw(commands: (ui: ui_t)=>void = null, x: i32 = -1, y: i32 = -1) { ui_end_input(); + if (ui_menu_show) { + ui_menu_nested = true; + ui_menu_keep_open = true; + } ui_menu_show = true; ui_menu_commands = commands; ui_menu_x = x > -1 ? x : math_floor(mouse_x + 1); diff --git a/base/sources/ts/ui_menubar.ts b/base/sources/ts/ui_menubar.ts index 23f6c533..a7b88c9b 100644 --- a/base/sources/ts/ui_menubar.ts +++ b/base/sources/ts/ui_menubar.ts @@ -3,10 +3,16 @@ let ui_menubar_default_w: i32 = 330; let ui_menubar_workspace_handle: ui_handle_t = ui_handle_create(); let ui_menubar_menu_handle: ui_handle_t = ui_handle_create(); let ui_menubar_w: i32 = ui_menubar_default_w; +let ui_menubar_category: i32 = 0; let _ui_menubar_saved_camera: mat4_t = mat4_nan(); let _ui_menubar_plane: mesh_object_t = null; +type update_info_t = { + version: i32; + version_name: string; +}; + function ui_menubar_init() { ui_menubar_workspace_handle.layout = ui_layout_t.HORIZONTAL; ui_menubar_menu_handle.layout = ui_layout_t.HORIZONTAL; @@ -57,29 +63,29 @@ function ui_menubar_render_ui() { } ///end let size: i32 = math_floor(ui._w / ui_SCALE(ui)); - if (ui_menu_show && ui_menu_category == menu_category_t.VIEWPORT) { + if (ui_menu_show && ui_menubar_category == menubar_category_t.VIEWPORT) { ui_fill(0, -6, size, size - 4, ui.ops.theme.HIGHLIGHT_COL); } if (ui_menubar_icon_button(ui, 8, 2)) { - ui_menubar_show_menu(ui, menu_category_t.VIEWPORT); + ui_menubar_show_menu(ui, menubar_category_t.VIEWPORT); } - if (ui_menu_show && ui_menu_category == menu_category_t.MODE) { + if (ui_menu_show && ui_menubar_category == menubar_category_t.MODE) { ui_fill(0, -6, size, size - 4, ui.ops.theme.HIGHLIGHT_COL); } if (ui_menubar_icon_button(ui, 9, 2)) { - ui_menubar_show_menu(ui, menu_category_t.MODE); + ui_menubar_show_menu(ui, menubar_category_t.MODE); } - if (ui_menu_show && ui_menu_category == menu_category_t.CAMERA) { + if (ui_menu_show && ui_menubar_category == menubar_category_t.CAMERA) { ui_fill(0, -6, size, size - 4, ui.ops.theme.HIGHLIGHT_COL); } if (ui_menubar_icon_button(ui, 10, 2)) { - ui_menubar_show_menu(ui, menu_category_t.CAMERA); + ui_menubar_show_menu(ui, menubar_category_t.CAMERA); } - if (ui_menu_show && ui_menu_category == menu_category_t.HELP) { + if (ui_menu_show && ui_menubar_category == menubar_category_t.HELP) { ui_fill(0, -6, size, size - 4, ui.ops.theme.HIGHLIGHT_COL); } if (ui_menubar_icon_button(ui, 11, 2)) { - ui_menubar_show_menu(ui, menu_category_t.HELP); + ui_menubar_show_menu(ui, menubar_category_t.HELP); } ui.enabled = history_undos > 0; if (ui_menubar_icon_button(ui, 6, 2)) { @@ -94,7 +100,7 @@ function ui_menubar_render_ui() { else { let categories: string[] = [tr("File"), tr("Edit"), tr("Viewport"), tr("Mode"), tr("Camera"), tr("Help")]; for (let i: i32 = 0; i < categories.length; ++i) { - if (_ui_menu_button(categories[i]) || (ui_menu_show && ui_menu_commands == null && ui.is_hovered)) { + if (_ui_menu_button(categories[i]) || (ui_menu_show && ui_menu_commands == ui_menubar_draw_category_items && ui.is_hovered)) { ui_menubar_show_menu(ui, i); } } @@ -207,15 +213,535 @@ function ui_menubar_draw_tab_header() { } } +function ui_menubar_draw_category_items(ui: ui_t) { + if (ui_menubar_category == menubar_category_t.FILE) { + if (ui_menu_button(tr("New Project..."), map_get(config_keymap, "file_new"))) { + project_new_box(); + } + if (ui_menu_button(tr("Open..."), map_get(config_keymap, "file_open"))) { + project_open(); + } + if (ui_menu_button(tr("Open Recent..."), map_get(config_keymap, "file_open_recent"))) { + box_projects_show(); + } + if (ui_menu_button(tr("Save"), map_get(config_keymap, "file_save"))) { + project_save(); + } + if (ui_menu_button(tr("Save As..."), map_get(config_keymap, "file_save_as"))) { + project_save_as(); + } + ui_menu_separator(ui); + if (ui_menu_button(tr("Import Texture..."), map_get(config_keymap, "file_import_assets"))) { + project_import_asset(string_array_join(path_texture_formats, ","), false); + } + if (ui_menu_button(tr("Import Envmap..."))) { + ui_files_show("hdr", false, false, function (path: string) { + if (!ends_with(path, ".hdr")) { + console_error(tr("Error: .hdr file expected")); + return; + } + import_asset_run(path); + }); + } + + ///if is_paint + if (ui_menu_button(tr("Import Font..."))) { + project_import_asset("ttf,ttc,otf"); + } + if (ui_menu_button(tr("Import Material..."))) { + project_import_material(); + } + if (ui_menu_button(tr("Import Brush..."))) { + project_import_brush(); + } + ///end + + ///if (is_paint || is_lab) + if (ui_menu_button(tr("Import Swatches..."))) { + project_import_swatches(); + } + ///end + if (ui_menu_button(tr("Import Mesh..."))) { + project_import_mesh(); + } + if (ui_menu_button(tr("Reimport Mesh"), map_get(config_keymap, "file_reimport_mesh"))) { + project_reimport_mesh(); + } + if (ui_menu_button(tr("Reimport Textures"), map_get(config_keymap, "file_reimport_textures"))) { + project_reimport_textures(); + } + ui_menu_separator(ui); + ///if (is_paint || is_lab) + if (ui_menu_button(tr("Export Textures..."), map_get(config_keymap, "file_export_textures_as"))) { + context_raw.layers_export = export_mode_t.VISIBLE; + box_export_show_textures(); + } + if (ui_menu_button(tr("Export Swatches..."))) { + project_export_swatches(); + } + ///end + if (ui_menu_button(tr("Export Mesh..."))) { + context_raw.export_mesh_index = 0; // All + box_export_show_mesh(); + } + + ///if is_paint + if (ui_menu_button(tr("Bake Material..."))) { + box_export_show_bake_material(); + } + ///end + + ui_menu_separator(ui); + if (ui_menu_button(tr("Exit"))) { + iron_stop(); + } + } + else if (ui_menubar_category == menubar_category_t.EDIT) { + let step_undo: string = ""; + let step_redo: string = ""; + if (history_undos > 0) { + step_undo = history_steps[history_steps.length - 1 - history_redos].name; + } + if (history_redos > 0) { + step_redo = history_steps[history_steps.length - history_redos].name; + } + + ui.enabled = history_undos > 0; + let vars_undo: map_t = map_create(); + map_set(vars_undo, "step", step_undo); + if (ui_menu_button(tr("Undo {step}", vars_undo), map_get(config_keymap, "edit_undo"))) { + history_undo(); + } + + ui.enabled = history_redos > 0; + let vars_redo: map_t = map_create(); + map_set(vars_redo, "step", step_redo); + if (ui_menu_button(tr("Redo {step}", vars_redo), map_get(config_keymap, "edit_redo"))) { + history_redo(); + } + ui.enabled = true; + ui_menu_separator(ui); + if (ui_menu_button(tr("Preferences..."), map_get(config_keymap, "edit_prefs"))) { + box_preferences_show(); + } + } + else if (ui_menubar_category == menubar_category_t.VIEWPORT) { + if (ui_menu_button(tr("Distract Free"), map_get(config_keymap, "view_distract_free"))) { + ui_base_toggle_distract_free(); + ui_base_ui.is_hovered = false; + } + + ///if !(arm_android || arm_ios) + if (ui_menu_button(tr("Toggle Fullscreen"), "alt+enter")) { + base_toggle_fullscreen(); + } + ///end + + ui.changed = false; + + let p: world_data_t = scene_world; + let env_handle: ui_handle_t = ui_handle(__ID__); + env_handle.value = p.strength; + ui_menu_align(ui); + p.strength = ui_slider(env_handle, tr("Environment"), 0.0, 8.0, true); + if (env_handle.changed) { + context_raw.ddirty = 2; + } + + let enva_handle: ui_handle_t = ui_handle(__ID__); + enva_handle.value = context_raw.envmap_angle / math_pi() * 180.0; + if (enva_handle.value < 0) { + enva_handle.value += (math_floor(-enva_handle.value / 360) + 1) * 360; + } + else if (enva_handle.value > 360) { + enva_handle.value -= math_floor(enva_handle.value / 360) * 360; + } + ui_menu_align(ui); + context_raw.envmap_angle = ui_slider(enva_handle, tr("Environment Angle"), 0.0, 360.0, true, 1) / 180.0 * math_pi(); + if (ui.is_hovered) { + let vars: map_t = map_create(); + map_set(vars, "shortcut", map_get(config_keymap, "rotate_envmap")); + ui_tooltip(tr("{shortcut} and move mouse", vars)); + } + if (enva_handle.changed) { + context_raw.ddirty = 2; + } + + ///if is_paint + let split_view_handle: ui_handle_t = ui_handle(__ID__); + if (split_view_handle.init) { + split_view_handle.selected = context_raw.split_view; + } + context_raw.split_view = ui_check(split_view_handle, " " + tr("Split View")); + if (split_view_handle.changed) { + base_resize(); + } + ///end + + ///if is_lab + let brush_scale_handle: ui_handle_t = ui_handle(__ID__); + if (brush_scale_handle.init) { + brush_scale_handle.value = context_raw.brush_scale; + } + ui_menu_align(ui); + context_raw.brush_scale = ui_slider(brush_scale_handle, tr("UV Scale"), 0.01, 5.0, true); + if (brush_scale_handle.changed) { + make_material_parse_mesh_material(); + render_path_raytrace_uv_scale = context_raw.brush_scale; + render_path_raytrace_ready = false; + } + ///end + + let cull_handle: ui_handle_t = ui_handle(__ID__); + if (cull_handle.init) { + cull_handle.selected = context_raw.cull_backfaces; + } + context_raw.cull_backfaces = ui_check(cull_handle, " " + tr("Cull Backfaces")); + if (cull_handle.changed) { + make_material_parse_mesh_material(); + } + + let filter_handle: ui_handle_t = ui_handle(__ID__); + if (filter_handle.init) { + filter_handle.selected = context_raw.texture_filter; + } + context_raw.texture_filter = ui_check(filter_handle, " " + tr("Filter Textures")); + if (filter_handle.changed) { + make_material_parse_paint_material(); + make_material_parse_mesh_material(); + } + + ///if is_paint + context_raw.draw_wireframe = ui_check(context_raw.wireframe_handle, " " + tr("Wireframe")); + if (context_raw.wireframe_handle.changed) { + let current: gpu_texture_t = _draw_current; + draw_end(); + util_uv_cache_uv_map(); + draw_begin(current); + make_material_parse_mesh_material(); + } + ///end + + ///if is_paint + context_raw.draw_texels = ui_check(context_raw.texels_handle, " " + tr("Texels")); + if (context_raw.texels_handle.changed) { + make_material_parse_mesh_material(); + } + ///end + + let compass_handle: ui_handle_t = ui_handle(__ID__); + if (compass_handle.init) { + compass_handle.selected = context_raw.show_compass; + } + context_raw.show_compass = ui_check(compass_handle, " " + tr("Compass")); + if (compass_handle.changed) { + context_raw.ddirty = 2; + } + + context_raw.show_envmap = ui_check(context_raw.show_envmap_handle, " " + tr("Envmap")); + if (context_raw.show_envmap_handle.changed) { + context_load_envmap(); + context_raw.ddirty = 2; + } + + context_raw.show_envmap_blur = ui_check(context_raw.show_envmap_blur_handle, " " + tr("Blur Envmap")); + if (context_raw.show_envmap_blur_handle.changed) { + context_raw.ddirty = 2; + } + + context_update_envmap(); + + if (ui.changed) { + ui_menu_keep_open = true; + } + } + else if (ui_menubar_category == menubar_category_t.MODE) { + let mode_handle: ui_handle_t = ui_handle(__ID__); + mode_handle.position = context_raw.viewport_mode; + let modes: string[] = [ + tr("Lit"), + tr("Base Color"), + ///if (is_paint || is_lab) + tr("Normal"), + tr("Occlusion"), + tr("Roughness"), + tr("Metallic"), + tr("Opacity"), + tr("Height"), + ///end + ///if (is_paint) + tr("Emission"), + tr("Subsurface"), + ///end + ///if is_paint + tr("TexCoord"), + tr("Object Normal"), + tr("Material ID"), + tr("Object ID"), + tr("Mask") + ///end + ]; + let shortcuts: string[] = ["l", "b", "n", "o", "r", "m", "a", "h", "e", "s", "t", "1", "2", "3", "4"]; + + if (gpu_raytrace_supported()) { + array_push(modes, tr("Path Traced")); + array_push(shortcuts, "p"); + } + + for (let i: i32 = 0; i < modes.length; ++i) { + let shortcut: string = config_raw.touch_ui ? "" : map_get(config_keymap, "viewport_mode") + ", " + shortcuts[i]; + ui_radio(mode_handle, i, modes[i], shortcut); + } + + if (mode_handle.changed) { + context_set_viewport_mode(mode_handle.position); + // Rotate mode is not supported for path tracing yet + if (mode_handle.position == viewport_mode_t.PATH_TRACE && context_raw.camera_controls == camera_controls_t.ROTATE) { + context_raw.camera_controls = camera_controls_t.ORBIT; + viewport_reset(); + } + ui_menu_keep_open = true; + } + } + else if (ui_menubar_category == menubar_category_t.CAMERA) { + if (ui_menu_button(tr("Reset"), map_get(config_keymap, "view_reset"))) { + viewport_reset(); + viewport_scale_to_bounds(); + } + ui_menu_separator(ui); + if (ui_menu_button(tr("Front"), map_get(config_keymap, "view_front"))) { + viewport_set_view(0, -1, 0, math_pi() / 2, 0, 0); + } + if (ui_menu_button(tr("Back"), map_get(config_keymap, "view_back"))) { + viewport_set_view(0, 1, 0, math_pi() / 2, 0, math_pi()); + } + if (ui_menu_button(tr("Right"), map_get(config_keymap, "view_right"))) { + viewport_set_view(1, 0, 0, math_pi() / 2, 0, math_pi() / 2); + } + if (ui_menu_button(tr("Left"), map_get(config_keymap, "view_left"))) { + viewport_set_view(-1, 0, 0, math_pi() / 2, 0, -math_pi() / 2); + } + if (ui_menu_button(tr("Top"), map_get(config_keymap, "view_top"))) { + viewport_set_view(0, 0, 1, 0, 0, 0); + } + if (ui_menu_button(tr("Bottom"), map_get(config_keymap, "view_bottom"))) { + viewport_set_view(0, 0, -1, math_pi(), 0, math_pi()); + } + ui_menu_separator(ui); + + ui.changed = false; + + if (ui_menu_button(tr("Orbit Left"), map_get(config_keymap, "view_orbit_left"))) { + viewport_orbit(-math_pi() / 12, 0); + } + if (ui_menu_button(tr("Orbit Right"), map_get(config_keymap, "view_orbit_right"))) { + viewport_orbit(math_pi() / 12, 0); + } + if (ui_menu_button(tr("Orbit Up"), map_get(config_keymap, "view_orbit_up"))) { + viewport_orbit(0, -math_pi() / 12); + } + if (ui_menu_button(tr("Orbit Down"), map_get(config_keymap, "view_orbit_down"))) { + viewport_orbit(0, math_pi() / 12); + } + if (ui_menu_button(tr("Orbit Opposite"), map_get(config_keymap, "view_orbit_opposite"))) { + viewport_orbit_opposite(); + } + if (ui_menu_button(tr("Zoom In"), map_get(config_keymap, "view_zoom_in"))) { + viewport_zoom(0.2); + } + if (ui_menu_button(tr("Zoom Out"), map_get(config_keymap, "view_zoom_out"))) { + viewport_zoom(-0.2); + } + + let cam: camera_object_t = scene_camera; + context_raw.fov_handle = ui_handle(__ID__); + if (context_raw.fov_handle.init) { + context_raw.fov_handle.value = math_floor(cam.data.fov * 100) / 100; + } + ui_menu_align(ui); + cam.data.fov = ui_slider(context_raw.fov_handle, tr("FoV"), 0.3, 1.4, true); + if (context_raw.fov_handle.changed) { + viewport_update_camera_type(context_raw.camera_type); + } + + ui_menu_align(ui); + let camera_controls_handle: ui_handle_t = ui_handle(__ID__); + camera_controls_handle.position = context_raw.camera_controls; + let camera_controls_items: string[] = [tr("Orbit"), tr("Rotate"), tr("Fly")]; + context_raw.camera_controls = ui_inline_radio(camera_controls_handle, camera_controls_items, ui_align_t.LEFT); + + let vars: map_t = map_create(); + map_set(vars, "rotate_shortcut", map_get(config_keymap, "action_rotate")); + map_set(vars, "zoom_shortcut", map_get(config_keymap, "action_zoom")); + map_set(vars, "pan_shortcut", map_get(config_keymap, "action_pan")); + let orbit_and_rotate_tooltip: string = tr("Orbit and Rotate mode:\n{rotate_shortcut} or move right mouse button to rotate.\n{zoom_shortcut} or scroll to zoom.\n{pan_shortcut} or move middle mouse to pan.", vars); + let fly_tooltip: string = tr("Fly mode:\nHold the right mouse button and one of the following commands:\nmove mouse to rotate.\nw, up or scroll up to move forward.\ns, down or scroll down to move backward.\na or left to move left.\nd or right to move right.\ne to move up.\nq to move down.\nHold shift to move faster or alt to move slower."); + if (ui.is_hovered) { + ui_tooltip(orbit_and_rotate_tooltip + "\n\n" + fly_tooltip); + } + + ui_menu_align(ui); + let camera_type_items: string[] = [tr("Perspective"), tr("Orthographic")]; + context_raw.camera_type = ui_inline_radio(context_raw.cam_handle, camera_type_items, ui_align_t.LEFT); + if (ui.is_hovered) { + ui_tooltip(tr("Camera Type") + " (" + map_get(config_keymap, "view_camera_type") + ")"); + } + if (context_raw.cam_handle.changed) { + viewport_update_camera_type(context_raw.camera_type); + } + + if (ui.changed) { + ui_menu_keep_open = true; + } + } + else if (ui_menubar_category == menubar_category_t.HELP) { + if (ui_menu_button(tr("Manual"))) { + file_load_url(manifest_url + "/manual"); + } + if (ui_menu_button(tr("How To"))) { + file_load_url(manifest_url + "/howto"); + } + if (ui_menu_button(tr("What's New"))) { + file_load_url(manifest_url + "/notes"); + } + if (ui_menu_button(tr("Issue Tracker"))) { + file_load_url("https://github.com/armory3d/armortools/issues"); + } + if (ui_menu_button(tr("Report Bug"))) { + ///if (arm_macos || arm_ios) // Limited url length + file_load_url("https://github.com/armory3d/armortools/issues/new?labels=bug&template=bug_report.md&body=*" + manifest_title + "%20" + manifest_version + "-" + config_get_sha() + ",%20" + iron_system_id()); + ///else + file_load_url("https://github.com/armory3d/armortools/issues/new?labels=bug&template=bug_report.md&body=*" + manifest_title + "%20" + manifest_version + "-" + config_get_sha() + ",%20" + iron_system_id() + "*%0A%0A**Issue description:**%0A%0A**Steps to reproduce:**%0A%0A"); + ///end + } + if (ui_menu_button(tr("Request Feature"))) { + ///if (arm_macos || arm_ios) // Limited url length + file_load_url("https://github.com/armory3d/armortools/issues/new?labels=feature%20request&template=feature_request.md&body=*" + manifest_title + "%20" + manifest_version + "-" + config_get_sha() + ",%20" + iron_system_id()); + ///else + file_load_url("https://github.com/armory3d/armortools/issues/new?labels=feature%20request&template=feature_request.md&body=*" + manifest_title + "%20" + manifest_version + "-" + config_get_sha() + ",%20" + iron_system_id() + "*%0A%0A**Feature description:**%0A%0A"); + ///end + } + ui_menu_separator(ui); + + if (ui_menu_button(tr("Check for Updates..."))) { + ///if arm_android + file_load_url(manifest_url_android); + ///elseif arm_ios + file_load_url(manifest_url_ios); + ///else + // Retrieve latest version number + file_download_bytes("https://server.armorpaint.org/" + to_lower_case(manifest_title) + ".html", function (url: string, buffer: buffer_t) { + if (buffer != null) { + // Compare versions + let update: update_info_t = json_parse(sys_buffer_to_string(buffer)); + let update_version: i32 = math_floor(update.version); + if (update_version > 0) { + let date: string = config_get_date(); // 2019 -> 19 + date = substring(date, 2, date.length); + let date_int: i32 = parse_int(string_replace_all(date, "-", "")); + if (update_version > date_int) { + let vars: map_t = map_create(); + map_set(vars, "url", manifest_url); + ui_box_show_message(tr("Update"), tr("Update is available!\nPlease visit {url}.", vars)); + } + else { + ui_box_show_message(tr("Update"), tr("You are up to date!")); + } + } + } + else { + let vars: map_t = map_create(); + map_set(vars, "url", manifest_url); + ui_box_show_message(tr("Update"), tr("Unable to check for updates.\nPlease visit {url}.", vars)); + } + }); + ///end + } + + if (ui_menu_button(tr("About..."))) { + + let msg: string = manifest_title + ".org - v" + manifest_version + " (" + config_get_date() + ") - " + config_get_sha() + "\n"; + msg += iron_system_id() + " - " + strings_graphics_api(); + + ///if arm_windows + let save: string; + if (path_is_protected()) { + save = iron_internal_save_path(); + } + else { + save = path_data(); + } + save += path_sep + "tmp.txt"; + iron_sys_command("wmic path win32_VideoController get name > \"" + save + "\""); + let blob: buffer_t = iron_load_blob(save); + let u8: u8_array_t = blob; + let gpu_raw: string = ""; + for (let i: i32 = 0; i < math_floor(u8.length / 2); ++i) { + let c: string = string_from_char_code(u8[i * 2]); + gpu_raw += c; + } + + let gpus: string[] = string_split(gpu_raw, "\n"); + array_splice(gpus, 1, gpus.length - 2); + let gpu: string = ""; + for (let i: i32 = 0; i < gpus.length; ++i) { + let g: string = gpus[i]; + gpu += trim_end(g) + ", "; + } + gpu = substring(gpu, 0, gpu.length - 2); + msg += "\n" + gpu; + ///else + // { lshw -C display } + ///end + + _ui_menu_render_msg = msg; + + ui_box_show_custom(function (ui: ui_t) { + let tab_vertical: bool = config_raw.touch_ui; + if (ui_tab(ui_handle(__ID__), tr("About"), tab_vertical)) { + + let img: gpu_texture_t = data_get_image("badge.k"); + ui_image(img); + _ui_end_element(); + + let h: ui_handle_t = ui_handle(__ID__); + if (h.init) { + h.text = _ui_menu_render_msg; + } + ui_text_area(h, ui_align_t.LEFT, false); + + ui_row3(); + + ///if (arm_windows || arm_linux || arm_macos) + if (ui_button(tr("Copy"))) { + iron_copy_to_clipboard(_ui_menu_render_msg); + } + ///else + _ui_end_element(); + ///end + + if (ui_button(tr("Contributors"))) { + file_load_url("https://github.com/armory3d/armortools/graphs/contributors"); + } + if (ui_button(tr("OK"))) { + ui_box_hide(); + } + } + }, 400, 320); + } + } +} + function ui_menubar_show_menu(ui: ui_t, category: i32) { - if (ui_menu_show && ui_menu_category == category) { + if (ui_menu_show && ui_menubar_category == category) { return; } ui_menu_show = true; ui_menu_show_first = true; - ui_menu_commands = null; - ui_menu_category = category; + ui_menu_commands = ui_menubar_draw_category_items; + ui_menubar_category = category; + ui_menu_x = math_floor(ui._x - ui._w); ui_menu_y = math_floor(ui_MENUBAR_H(ui)); if (config_raw.touch_ui) { From feb49bd118383ce3e5d2770e61d0291aeccc2620 Mon Sep 17 00:00:00 2001 From: luboslenco Date: Fri, 8 Aug 2025 14:09:04 +0200 Subject: [PATCH 2/8] Rework meshes tab --- base/sources/ts/tab_meshes.ts | 151 +++++++++++++++++----------------- 1 file changed, 77 insertions(+), 74 deletions(-) diff --git a/base/sources/ts/tab_meshes.ts b/base/sources/ts/tab_meshes.ts index 1bc24577..6ededbd5 100644 --- a/base/sources/ts/tab_meshes.ts +++ b/base/sources/ts/tab_meshes.ts @@ -8,25 +8,13 @@ function tab_meshes_draw(htab: ui_handle_t) { ui_begin_sticky(); - ///if is_paint if (config_raw.touch_ui) { - ui_row6(); + ui_row2(); } else { - let row: f32[] = [1 / 14, 1 / 9, 1 / 9, 1 / 9, 1 / 9, 1 / 14]; + let row: f32[] = [1 / 14, 1 / 14]; ui_row(row); } - ///end - - ///if is_lab - if (config_raw.touch_ui) { - ui_row7(); - } - else { - let row: f32[] = [1 / 14, 1 / 9, 1 / 9, 1 / 9, 1 / 9, 1 / 9, 1 / 14]; - ui_row(row); - } - ///end if (ui_button(tr("Import"))) { ui_menu_draw(function (ui: ui_t) { @@ -40,78 +28,93 @@ function tab_meshes_draw(htab: ui_handle_t) { } if (ui.is_hovered) ui_tooltip(tr("Import mesh file")); - ///if is_lab - if (ui_button(tr("Set Default"))) { + + if (ui_button(tr("Edit"))) { + ui_menu_draw(function (ui: ui_t) { - if (ui_menu_button(tr("Cube"))) { - tab_meshes_set_default_mesh(".Cube"); - } - if (ui_menu_button(tr("Plane"))) { - tab_meshes_set_default_mesh(".Plane"); - } - if (ui_menu_button(tr("Sphere"))) { - tab_meshes_set_default_mesh(".Sphere"); - } - if (ui_menu_button(tr("Cylinder"))) { - tab_meshes_set_default_mesh(".Cylinder"); - } - }); - } - ///end - if (ui_button(tr("Flip Normals"))) { - util_mesh_flip_normals(); - context_raw.ddirty = 2; - } - - if (ui_button(tr("Calculate Normals"))) { - ui_menu_draw(function (ui: ui_t) { - if (ui_menu_button(tr("Smooth"))) { - util_mesh_calc_normals(true); - context_raw.ddirty = 2; + ///if is_lab + if (ui_menu_button(tr("Set Default"))) { + ui_menu_draw(function (ui: ui_t) { + if (ui_menu_button(tr("Cube"))) { + tab_meshes_set_default_mesh(".Cube"); + } + if (ui_menu_button(tr("Plane"))) { + tab_meshes_set_default_mesh(".Plane"); + } + if (ui_menu_button(tr("Sphere"))) { + tab_meshes_set_default_mesh(".Sphere"); + } + if (ui_menu_button(tr("Cylinder"))) { + tab_meshes_set_default_mesh(".Cylinder"); + } + }); } - if (ui_menu_button(tr("Flat"))) { - util_mesh_calc_normals(false); - context_raw.ddirty = 2; - } - }); - } + ///end - if (ui_button(tr("Geometry to Origin"))) { - util_mesh_to_origin(); - context_raw.ddirty = 2; - } - - if (ui_button(tr("Apply Displacement"))) { - ///if is_paint - util_mesh_apply_displacement(project_layers[0].texpaint_pack); - ///end - ///if is_lab - let displace_strength: f32 = config_raw.displace_strength > 0 ? config_raw.displace_strength : 1.0; - let uv_scale: f32 = scene_meshes[0].data.scale_tex * context_raw.brush_scale; - util_mesh_apply_displacement(context_raw.brush_output_node_inst.texpaint_pack, 0.05 * displace_strength, uv_scale); - ///end - - util_mesh_calc_normals(); - context_raw.ddirty = 2; - } - - if (ui_button(tr("Rotate"))) { - ui_menu_draw(function (ui: ui_t) { - if (ui_menu_button(tr("Rotate X"))) { - util_mesh_swap_axis(1, 2); + if (ui_menu_button(tr("Flip Normals"))) { + util_mesh_flip_normals(); context_raw.ddirty = 2; } - if (ui_menu_button(tr("Rotate Y"))) { - util_mesh_swap_axis(2, 0); + if (ui_menu_button(tr("Calculate Normals"))) { + ui_menu_draw(function (ui: ui_t) { + if (ui_menu_button(tr("Smooth"))) { + util_mesh_calc_normals(true); + context_raw.ddirty = 2; + } + if (ui_menu_button(tr("Flat"))) { + util_mesh_calc_normals(false); + context_raw.ddirty = 2; + } + }); + } + + if (ui_menu_button(tr("Geometry to Origin"))) { + util_mesh_to_origin(); context_raw.ddirty = 2; } - if (ui_menu_button(tr("Rotate Z"))) { - util_mesh_swap_axis(0, 1); + if (ui_menu_button(tr("Apply Displacement"))) { + ///if is_paint + util_mesh_apply_displacement(project_layers[0].texpaint_pack); + ///end + ///if is_lab + let displace_strength: f32 = config_raw.displace_strength > 0 ? config_raw.displace_strength : 1.0; + let uv_scale: f32 = scene_meshes[0].data.scale_tex * context_raw.brush_scale; + util_mesh_apply_displacement(context_raw.brush_output_node_inst.texpaint_pack, 0.05 * displace_strength, uv_scale); + ///end + + util_mesh_calc_normals(); context_raw.ddirty = 2; } + + if (ui_menu_button(tr("Rotate"))) { + ui_menu_draw(function (ui: ui_t) { + if (ui_menu_button(tr("Rotate X"))) { + util_mesh_swap_axis(1, 2); + context_raw.ddirty = 2; + } + + if (ui_menu_button(tr("Rotate Y"))) { + util_mesh_swap_axis(2, 0); + context_raw.ddirty = 2; + } + + if (ui_menu_button(tr("Rotate Z"))) { + util_mesh_swap_axis(0, 1); + context_raw.ddirty = 2; + } + }); + } + + if (ui_menu_button(tr("UV Unwrap"))) { + let f: string = "uv_unwrap.js"; + if (array_index_of(config_raw.plugins, f) == -1) { + config_enable_plugin(f); + } + plugin_uv_unwrap_button(); + } }); } From 625aa681a9447bae45011cb832356b4da78848d3 Mon Sep 17 00:00:00 2001 From: luboslenco Date: Fri, 8 Aug 2025 14:09:48 +0200 Subject: [PATCH 3/8] Merge forge --- base/sources/ts/base.ts | 2 +- base/sources/ts/enums.ts | 2 +- base/sources/ts/ui_toolbar.ts | 2 +- paint/project.js | 1 + paint/sources/base_ext.ts | 13 +++ paint/sources/context_ext.ts | 5 ++ paint/sources/sim.ts | 136 ++++++++++++++++++++++++++++++++ paint/sources/ui_header_ext.ts | 12 +++ paint/sources/ui_toolbar_ext.ts | 28 +++---- paint/sources/util_mesh_ext.ts | 41 ++++++++++ 10 files changed, 225 insertions(+), 17 deletions(-) create mode 100644 paint/sources/sim.ts create mode 100644 paint/sources/util_mesh_ext.ts 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; +} From 2651b0613511bbbb3f5204a51398ac89cd1bee71 Mon Sep 17 00:00:00 2001 From: luboslenco Date: Fri, 8 Aug 2025 14:26:27 +0200 Subject: [PATCH 4/8] Fix viewport resize flicker --- base/sources/ts/base.ts | 1 + base/sources/ts/render_path_base.ts | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/base/sources/ts/base.ts b/base/sources/ts/base.ts index e24e63b7..c1d95c2c 100644 --- a/base/sources/ts/base.ts +++ b/base/sources/ts/base.ts @@ -271,6 +271,7 @@ function base_resize() { cam.data.ortho[3] = 2 * (sys_h() / sys_w()); } camera_object_build_proj(cam); + render_path_base_taa_frame = 0; if (context_raw.camera_type == camera_type_t.ORTHOGRAPHIC) { viewport_update_camera_type(context_raw.camera_type); diff --git a/base/sources/ts/render_path_base.ts b/base/sources/ts/render_path_base.ts index 5230c61f..a2d43e3d 100644 --- a/base/sources/ts/render_path_base.ts +++ b/base/sources/ts/render_path_base.ts @@ -261,7 +261,7 @@ function render_path_base_init_ssao() { function render_path_base_draw_ssao() { let ssao: bool = config_raw.rp_ssao != false && context_raw.camera_type == camera_type_t.PERSPECTIVE; - if (ssao && context_raw.ddirty > 0 && render_path_base_taa_frame > 0) { + if (ssao && context_raw.ddirty > 0 && _render_path_frame > 0) { if (map_get(render_path_render_targets, "singlea") == null) { render_path_base_init_ssao(); } @@ -289,7 +289,7 @@ function render_path_base_draw_deferred_light() { render_path_bind_target("gbuffer0", "gbuffer0"); render_path_bind_target("gbuffer1", "gbuffer1"); let ssao: bool = config_raw.rp_ssao != false && context_raw.camera_type == camera_type_t.PERSPECTIVE; - if (ssao && render_path_base_taa_frame > 0) { + if (ssao && _render_path_frame > 0) { render_path_bind_target("singlea", "ssaotex"); } else { From e3148dc760835d347b1381ec2ac59f6a6a46089c Mon Sep 17 00:00:00 2001 From: luboslenco Date: Fri, 8 Aug 2025 15:35:50 +0200 Subject: [PATCH 5/8] Vulkan fixes --- base/sources/backends/vulkan_gpu.c | 16 +++++++--------- base/sources/iron.h | 3 +-- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/base/sources/backends/vulkan_gpu.c b/base/sources/backends/vulkan_gpu.c index bb2fd16b..7bdd9aa7 100644 --- a/base/sources/backends/vulkan_gpu.c +++ b/base/sources/backends/vulkan_gpu.c @@ -1301,10 +1301,6 @@ void gpu_set_index_buffer(gpu_buffer_t *buffer) { } void gpu_get_render_target_pixels(gpu_texture_t *render_target, uint8_t *data) { - if (gpu_in_use) { - vkCmdEndRendering(command_buffer); - } - int buffer_size = render_target->width * render_target->height * gpu_texture_format_size(render_target->format); int new_readback_buffer_size = buffer_size; if (new_readback_buffer_size < (2048 * 2048 * 4)) { @@ -1336,7 +1332,7 @@ void gpu_get_render_target_pixels(gpu_texture_t *render_target, uint8_t *data) { mem_alloc.allocationSize = 0; mem_alloc.memoryTypeIndex = 0; mem_alloc.allocationSize = mem_reqs.size; - memory_type_from_properties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &mem_alloc.memoryTypeIndex); + memory_type_from_properties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT, &mem_alloc.memoryTypeIndex); vkAllocateMemory(device, &mem_alloc, NULL, &readback_mem); vkBindBufferMemory(device, readback_buffer, readback_mem, 0); } @@ -1357,7 +1353,13 @@ void gpu_get_render_target_pixels(gpu_texture_t *render_target, uint8_t *data) { region.imageExtent.width = (uint32_t)render_target->width; region.imageExtent.height = (uint32_t)render_target->height; region.imageExtent.depth = 1; + if (gpu_in_use) { + vkCmdEndRendering(command_buffer); + } vkCmdCopyImageToBuffer(command_buffer, render_target->impl.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, readback_buffer, 1, ®ion); + if (gpu_in_use) { + vkCmdBeginRendering(command_buffer, ¤t_rendering_info); + } set_image_layout(render_target->impl.image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); @@ -1368,10 +1370,6 @@ void gpu_get_render_target_pixels(gpu_texture_t *render_target, uint8_t *data) { vkMapMemory(device, readback_mem, 0, VK_WHOLE_SIZE, 0, (void **)&p); memcpy(data, p, buffer_size); vkUnmapMemory(device, readback_mem); - - if (gpu_in_use) { - vkCmdBeginRendering(command_buffer, ¤t_rendering_info); - } } static VkDescriptorSet get_descriptor_set(VkBuffer buffer) { diff --git a/base/sources/iron.h b/base/sources/iron.h index 9b7b3cac..ef346fac 100644 --- a/base/sources/iron.h +++ b/base/sources/iron.h @@ -1335,8 +1335,7 @@ buffer_t *gpu_get_texture_pixels(gpu_texture_t *image) { image->buffer->buffer = malloc(image->buffer->length); } - uint8_t *b = (uint8_t *)image->buffer->buffer; - gpu_get_render_target_pixels(image, b); + gpu_get_render_target_pixels(image, image->buffer->buffer); return image->buffer; } From 4f271706c1f0bd7dcbbc779cd2601a859672ac84 Mon Sep 17 00:00:00 2001 From: luboslenco Date: Fri, 8 Aug 2025 17:48:41 +0200 Subject: [PATCH 6/8] Vulkan fixes --- base/sources/backends/vulkan_gpu.c | 188 +++++++++++------------------ 1 file changed, 70 insertions(+), 118 deletions(-) diff --git a/base/sources/backends/vulkan_gpu.c b/base/sources/backends/vulkan_gpu.c index 7bdd9aa7..172fca4a 100644 --- a/base/sources/backends/vulkan_gpu.c +++ b/base/sources/backends/vulkan_gpu.c @@ -38,6 +38,9 @@ static VkRenderingAttachmentInfo current_depth_attachment_info; static VkPhysicalDeviceMemoryProperties memory_properties; static VkSampler immutable_sampler; static VkCommandBuffer command_buffer; +static VkBuffer buffers_to_destroy[256]; +static VkDeviceMemory buffer_memories_to_destroy[256]; +static int buffers_to_destroy_count = 0; static VkInstance instance; static VkPhysicalDevice gpu; @@ -1245,6 +1248,12 @@ void gpu_present_internal() { vkBeginCommandBuffer(command_buffer, &begin_info); framebuffer_acquired = false; + + while (buffers_to_destroy_count > 0) { + buffers_to_destroy_count--; + vkFreeMemory(device, buffer_memories_to_destroy[buffers_to_destroy_count], NULL); + vkDestroyBuffer(device, buffers_to_destroy[buffers_to_destroy_count], NULL); + } } void gpu_draw_internal() { @@ -1791,6 +1800,49 @@ void gpu_render_target_init(gpu_texture_t *target, int width, int height, gpu_te gpu_render_target_init2(target, width, height, format, -1); } +void _gpu_buffer_init(gpu_buffer_impl_t *buffer, int size, int usage, int memory_requirements) { + if (buffer->buf != NULL) { + assert(buffers_to_destroy_count < 256); + buffers_to_destroy[buffers_to_destroy_count] = buffer->buf; + buffer_memories_to_destroy[buffers_to_destroy_count] = buffer->mem; + buffers_to_destroy_count++; + } + + VkBufferCreateInfo buf_info = { + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .pNext = NULL, + .size = size, + .usage = usage, + .flags = 0, + }; + bool raytrace = gpu_raytrace_supported() && (usage == VK_BUFFER_USAGE_VERTEX_BUFFER_BIT || usage == VK_BUFFER_USAGE_INDEX_BUFFER_BIT); + if (raytrace) { + buf_info.usage |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; + buf_info.usage |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; + buf_info.usage |= VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR; + } + vkCreateBuffer(device, &buf_info, NULL, &buffer->buf); + VkMemoryRequirements mem_reqs = {0}; + vkGetBufferMemoryRequirements(device, buffer->buf, &mem_reqs); + + memset(&buffer->mem_alloc, 0, sizeof(VkMemoryAllocateInfo)); + buffer->mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + buffer->mem_alloc.pNext = NULL; + buffer->mem_alloc.allocationSize = mem_reqs.size; + buffer->mem_alloc.memoryTypeIndex = 0; + memory_type_from_properties(mem_reqs.memoryTypeBits, memory_requirements, &buffer->mem_alloc.memoryTypeIndex); + + VkMemoryAllocateFlagsInfo memory_allocate_flags_info = {0}; + if (raytrace) { + memory_allocate_flags_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO; + memory_allocate_flags_info.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR; + buffer->mem_alloc.pNext = &memory_allocate_flags_info; + } + + vkAllocateMemory(device, &buffer->mem_alloc, NULL, &buffer->mem); + vkBindBufferMemory(device, buffer->buf, buffer->mem, 0); +} + void gpu_vertex_buffer_init(gpu_buffer_t *buffer, int count, gpu_vertex_structure_t *structure) { buffer->count = count; buffer->stride = 0; @@ -1798,46 +1850,11 @@ void gpu_vertex_buffer_init(gpu_buffer_t *buffer, int count, gpu_vertex_structur gpu_vertex_element_t element = structure->elements[i]; buffer->stride += gpu_vertex_data_size(element.data); } - - VkBufferCreateInfo buf_info = { - .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, - .pNext = NULL, - .size = count * buffer->stride, - .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, - .flags = 0, - }; - - if (gpu_raytrace_supported()) { - buf_info.usage |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; - buf_info.usage |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; - buf_info.usage |= VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR; - } - - memset(&buffer->impl.mem_alloc, 0, sizeof(VkMemoryAllocateInfo)); - buffer->impl.mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - buffer->impl.mem_alloc.pNext = NULL; - buffer->impl.mem_alloc.allocationSize = 0; - buffer->impl.mem_alloc.memoryTypeIndex = 0; - - vkCreateBuffer(device, &buf_info, NULL, &buffer->impl.buf); - VkMemoryRequirements mem_reqs = {0}; - vkGetBufferMemoryRequirements(device, buffer->impl.buf, &mem_reqs); - - buffer->impl.mem_alloc.allocationSize = mem_reqs.size; - memory_type_from_properties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &buffer->impl.mem_alloc.memoryTypeIndex); - - VkMemoryAllocateFlagsInfo memory_allocate_flags_info = {0}; - if (gpu_raytrace_supported()) { - memory_allocate_flags_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO; - memory_allocate_flags_info.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR; - buffer->impl.mem_alloc.pNext = &memory_allocate_flags_info; - } - - vkAllocateMemory(device, &buffer->impl.mem_alloc, NULL, &buffer->impl.mem); - vkBindBufferMemory(device, buffer->impl.buf, buffer->impl.mem, 0); + buffer->impl.buf = NULL; } void *gpu_vertex_buffer_lock(gpu_buffer_t *buffer) { + _gpu_buffer_init(&buffer->impl, buffer->count * buffer->stride, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); void *p; vkMapMemory(device, buffer->impl.mem, 0, buffer->count * buffer->stride, 0, (void **)&p); return p; @@ -1847,40 +1864,27 @@ void gpu_vertex_buffer_unlock(gpu_buffer_t *buffer) { vkUnmapMemory(device, buffer->impl.mem); } -void gpu_constant_buffer_init(gpu_buffer_t *buffer, int size) { - buffer->count = size; - buffer->data = NULL; +void gpu_index_buffer_init(gpu_buffer_t *buffer, int count) { + buffer->count = count; + buffer->impl.buf = NULL; +} - VkBufferCreateInfo buf_info; - memset(&buf_info, 0, sizeof(buf_info)); - buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - buf_info.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; - buf_info.usage |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; - - buf_info.size = size; - vkCreateBuffer(device, &buf_info, NULL, &buffer->impl.buf); - - VkMemoryRequirements mem_reqs; - vkGetBufferMemoryRequirements(device, buffer->impl.buf, &mem_reqs); - - buffer->impl.mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - buffer->impl.mem_alloc.pNext = NULL; - buffer->impl.mem_alloc.allocationSize = mem_reqs.size; - buffer->impl.mem_alloc.memoryTypeIndex = 0; - - memory_type_from_properties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &buffer->impl.mem_alloc.memoryTypeIndex); - vkAllocateMemory(device, &buffer->impl.mem_alloc, NULL, &buffer->impl.mem); - vkBindBufferMemory(device, buffer->impl.buf, buffer->impl.mem, 0); - - void *p; +void *gpu_index_buffer_lock(gpu_buffer_t *buffer) { + _gpu_buffer_init(&buffer->impl, buffer->count * sizeof(uint32_t), VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + uint8_t *p; vkMapMemory(device, buffer->impl.mem, 0, buffer->impl.mem_alloc.allocationSize, 0, (void **)&p); - memset(p, 0, buffer->impl.mem_alloc.allocationSize); + return p; +} + +void gpu_index_buffer_unlock(gpu_buffer_t *buffer) { vkUnmapMemory(device, buffer->impl.mem); } -void gpu_constant_buffer_destroy(gpu_buffer_t *buffer) { - vkFreeMemory(device, buffer->impl.mem, NULL); - vkDestroyBuffer(device, buffer->impl.buf, NULL); +void gpu_constant_buffer_init(gpu_buffer_t *buffer, int size) { + buffer->count = size; + buffer->data = NULL; + buffer->impl.buf = NULL; + _gpu_buffer_init(&buffer->impl, size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); } void gpu_constant_buffer_lock(gpu_buffer_t *buffer, int start, int count) { @@ -1892,63 +1896,11 @@ void gpu_constant_buffer_unlock(gpu_buffer_t *buffer) { buffer->data = NULL; } -void gpu_index_buffer_init(gpu_buffer_t *buffer, int count) { - buffer->count = count; - - VkBufferCreateInfo buf_info = { - .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, - .pNext = NULL, - .size = count * sizeof(uint32_t), - .usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT, - .flags = 0, - }; - - if (gpu_raytrace_supported()) { - buf_info.usage |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; - buf_info.usage |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; - buf_info.usage |= VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR; - } - - memset(&buffer->impl.mem_alloc, 0, sizeof(VkMemoryAllocateInfo)); - buffer->impl.mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - buffer->impl.mem_alloc.pNext = NULL; - buffer->impl.mem_alloc.allocationSize = 0; - buffer->impl.mem_alloc.memoryTypeIndex = 0; - - vkCreateBuffer(device, &buf_info, NULL, &buffer->impl.buf); - - VkMemoryRequirements mem_reqs = {0}; - vkGetBufferMemoryRequirements(device, buffer->impl.buf, &mem_reqs); - - buffer->impl.mem_alloc.allocationSize = mem_reqs.size; - memory_type_from_properties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &buffer->impl.mem_alloc.memoryTypeIndex); - - VkMemoryAllocateFlagsInfo memory_allocate_flags_info = {0}; - if (gpu_raytrace_supported()) { - memory_allocate_flags_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO; - memory_allocate_flags_info.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR; - buffer->impl.mem_alloc.pNext = &memory_allocate_flags_info; - } - - vkAllocateMemory(device, &buffer->impl.mem_alloc, NULL, &buffer->impl.mem); - vkBindBufferMemory(device, buffer->impl.buf, buffer->impl.mem, 0); -} - void gpu_buffer_destroy(gpu_buffer_t *buffer) { vkFreeMemory(device, buffer->impl.mem, NULL); vkDestroyBuffer(device, buffer->impl.buf, NULL); } -void *gpu_index_buffer_lock(gpu_buffer_t *buffer) { - uint8_t *data; - vkMapMemory(device, buffer->impl.mem, 0, buffer->impl.mem_alloc.allocationSize, 0, (void **)&data); - return data; -} - -void gpu_index_buffer_unlock(gpu_buffer_t *buffer) { - vkUnmapMemory(device, buffer->impl.mem); -} - static const int INDEX_RAYGEN = 0; static const int INDEX_MISS = 1; static const int INDEX_CLOSEST_HIT = 2; From 13a9782de5c5d8d41cbf1e7450b203bfdcce1120 Mon Sep 17 00:00:00 2001 From: luboslenco Date: Fri, 8 Aug 2025 17:48:52 +0200 Subject: [PATCH 7/8] Cleanup --- base/sources/backends/direct3d12_gpu.c | 4 ---- base/sources/backends/metal_gpu.m | 6 ------ base/sources/backends/webgpu_gpu.c | 1 - base/sources/iron.h | 2 +- base/sources/iron_gpu.h | 1 - 5 files changed, 1 insertion(+), 13 deletions(-) diff --git a/base/sources/backends/direct3d12_gpu.c b/base/sources/backends/direct3d12_gpu.c index 52a4d6c2..8e4de687 100644 --- a/base/sources/backends/direct3d12_gpu.c +++ b/base/sources/backends/direct3d12_gpu.c @@ -1059,10 +1059,6 @@ void gpu_constant_buffer_init(gpu_buffer_t *buffer, int size) { _gpu_buffer_init(&buffer->impl.buffer, size, D3D12_HEAP_TYPE_UPLOAD); } -void gpu_constant_buffer_destroy(gpu_buffer_t *buffer) { - buffer->impl.buffer->lpVtbl->Release(buffer->impl.buffer); -} - void gpu_constant_buffer_lock(gpu_buffer_t *buffer, int start, int count) { buffer->impl.last_start = start; buffer->impl.last_count = count; diff --git a/base/sources/backends/metal_gpu.m b/base/sources/backends/metal_gpu.m index d4fc74ad..04047901 100644 --- a/base/sources/backends/metal_gpu.m +++ b/base/sources/backends/metal_gpu.m @@ -596,12 +596,6 @@ void gpu_constant_buffer_init(gpu_buffer_t *buffer, int size) { buffer->impl.metal_buffer = (__bridge_retained void *)[get_metal_device() newBufferWithLength:size options:MTLResourceOptionCPUCacheModeDefault]; } -void gpu_constant_buffer_destroy(gpu_buffer_t *buffer) { - id buf = (__bridge_transfer id)buffer->impl.metal_buffer; - buf = nil; - buffer->impl.metal_buffer = NULL; -} - void gpu_constant_buffer_lock(gpu_buffer_t *buffer, int start, int count) { id buf = (__bridge id)buffer->impl.metal_buffer; uint8_t *data = (uint8_t *)[buf contents]; diff --git a/base/sources/backends/webgpu_gpu.c b/base/sources/backends/webgpu_gpu.c index 50439b19..4def6979 100644 --- a/base/sources/backends/webgpu_gpu.c +++ b/base/sources/backends/webgpu_gpu.c @@ -109,7 +109,6 @@ void gpu_vertex_buffer_unlock(gpu_buffer_t *buffer) { } void gpu_constant_buffer_init(gpu_buffer_t *buffer, int size) {} -void gpu_constant_buffer_destroy(gpu_buffer_t *buffer) {} void gpu_constant_buffer_lock(gpu_buffer_t *buffer, int start, int count) {} void gpu_constant_buffer_unlock(gpu_buffer_t *buffer) {} diff --git a/base/sources/iron.h b/base/sources/iron.h index ef346fac..bb16aaa5 100644 --- a/base/sources/iron.h +++ b/base/sources/iron.h @@ -2043,7 +2043,7 @@ void iron_ml_unload() { void iron_raytrace_init(buffer_t *shader) { if (rt_created) { - gpu_constant_buffer_destroy(&rt_constant_buffer); + gpu_buffer_destroy(&rt_constant_buffer); gpu_raytrace_pipeline_destroy(&rt_pipeline); } rt_created = true; diff --git a/base/sources/iron_gpu.h b/base/sources/iron_gpu.h index 2d8f148c..f931de71 100644 --- a/base/sources/iron_gpu.h +++ b/base/sources/iron_gpu.h @@ -183,7 +183,6 @@ void gpu_vertex_buffer_init(gpu_buffer_t *buffer, int count, gpu_vertex_structur void *gpu_vertex_buffer_lock(gpu_buffer_t *buffer); void gpu_vertex_buffer_unlock(gpu_buffer_t *buffer); void gpu_constant_buffer_init(gpu_buffer_t *buffer, int size); -void gpu_constant_buffer_destroy(gpu_buffer_t *buffer); void gpu_constant_buffer_lock(gpu_buffer_t *buffer, int start, int count); void gpu_constant_buffer_unlock(gpu_buffer_t *buffer); void gpu_index_buffer_init(gpu_buffer_t *buffer, int count); From cb9c454bf4d64c1190b38cb88514da34058b5eb0 Mon Sep 17 00:00:00 2001 From: luboslenco Date: Fri, 8 Aug 2025 19:51:33 +0200 Subject: [PATCH 8/8] Vulkan fixes --- base/sources/backends/vulkan_gpu.c | 49 +++++++++++++++++++++--------- base/sources/backends/vulkan_gpu.h | 1 - 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/base/sources/backends/vulkan_gpu.c b/base/sources/backends/vulkan_gpu.c index 172fca4a..fa17537b 100644 --- a/base/sources/backends/vulkan_gpu.c +++ b/base/sources/backends/vulkan_gpu.c @@ -1815,7 +1815,7 @@ void _gpu_buffer_init(gpu_buffer_impl_t *buffer, int size, int usage, int memory .usage = usage, .flags = 0, }; - bool raytrace = gpu_raytrace_supported() && (usage == VK_BUFFER_USAGE_VERTEX_BUFFER_BIT || usage == VK_BUFFER_USAGE_INDEX_BUFFER_BIT); + bool raytrace = gpu_raytrace_supported() && ((usage & VK_BUFFER_USAGE_VERTEX_BUFFER_BIT) || (usage & VK_BUFFER_USAGE_INDEX_BUFFER_BIT)); if (raytrace) { buf_info.usage |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; buf_info.usage |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; @@ -1825,24 +1825,36 @@ void _gpu_buffer_init(gpu_buffer_impl_t *buffer, int size, int usage, int memory VkMemoryRequirements mem_reqs = {0}; vkGetBufferMemoryRequirements(device, buffer->buf, &mem_reqs); - memset(&buffer->mem_alloc, 0, sizeof(VkMemoryAllocateInfo)); - buffer->mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - buffer->mem_alloc.pNext = NULL; - buffer->mem_alloc.allocationSize = mem_reqs.size; - buffer->mem_alloc.memoryTypeIndex = 0; - memory_type_from_properties(mem_reqs.memoryTypeBits, memory_requirements, &buffer->mem_alloc.memoryTypeIndex); - + VkMemoryAllocateInfo mem_alloc = { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .pNext = NULL, + .allocationSize = mem_reqs.size, + .memoryTypeIndex = 0, + }; + memory_type_from_properties(mem_reqs.memoryTypeBits, memory_requirements, &mem_alloc.memoryTypeIndex); VkMemoryAllocateFlagsInfo memory_allocate_flags_info = {0}; if (raytrace) { memory_allocate_flags_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO; memory_allocate_flags_info.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR; - buffer->mem_alloc.pNext = &memory_allocate_flags_info; + mem_alloc.pNext = &memory_allocate_flags_info; } - - vkAllocateMemory(device, &buffer->mem_alloc, NULL, &buffer->mem); + vkAllocateMemory(device, &mem_alloc, NULL, &buffer->mem); vkBindBufferMemory(device, buffer->buf, buffer->mem, 0); } +void _gpu_buffer_copy(VkBuffer dest, VkBuffer source, uint32_t size) { + if (gpu_in_use) { + vkCmdEndRendering(command_buffer); + } + VkBufferCopy copy_region = { + .size = size, + }; + vkCmdCopyBuffer(command_buffer, source, dest, 1, ©_region); + if (gpu_in_use) { + vkCmdBeginRendering(command_buffer, ¤t_rendering_info); + } +} + void gpu_vertex_buffer_init(gpu_buffer_t *buffer, int count, gpu_vertex_structure_t *structure) { buffer->count = count; buffer->stride = 0; @@ -1854,7 +1866,7 @@ void gpu_vertex_buffer_init(gpu_buffer_t *buffer, int count, gpu_vertex_structur } void *gpu_vertex_buffer_lock(gpu_buffer_t *buffer) { - _gpu_buffer_init(&buffer->impl, buffer->count * buffer->stride, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + _gpu_buffer_init(&buffer->impl, buffer->count * buffer->stride, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); void *p; vkMapMemory(device, buffer->impl.mem, 0, buffer->count * buffer->stride, 0, (void **)&p); return p; @@ -1862,22 +1874,29 @@ void *gpu_vertex_buffer_lock(gpu_buffer_t *buffer) { void gpu_vertex_buffer_unlock(gpu_buffer_t *buffer) { vkUnmapMemory(device, buffer->impl.mem); + VkBuffer upload_buffer = buffer->impl.buf; + _gpu_buffer_init(&buffer->impl, buffer->count * buffer->stride, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + _gpu_buffer_copy(buffer->impl.buf, upload_buffer, buffer->count * buffer->stride); } void gpu_index_buffer_init(gpu_buffer_t *buffer, int count) { buffer->count = count; + buffer->stride = sizeof(uint32_t); buffer->impl.buf = NULL; } void *gpu_index_buffer_lock(gpu_buffer_t *buffer) { - _gpu_buffer_init(&buffer->impl, buffer->count * sizeof(uint32_t), VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - uint8_t *p; - vkMapMemory(device, buffer->impl.mem, 0, buffer->impl.mem_alloc.allocationSize, 0, (void **)&p); + _gpu_buffer_init(&buffer->impl, buffer->count * buffer->stride, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + void *p; + vkMapMemory(device, buffer->impl.mem, 0, buffer->count * buffer->stride, 0, (void **)&p); return p; } void gpu_index_buffer_unlock(gpu_buffer_t *buffer) { vkUnmapMemory(device, buffer->impl.mem); + VkBuffer upload_buffer = buffer->impl.buf; + _gpu_buffer_init(&buffer->impl, buffer->count * buffer->stride, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + _gpu_buffer_copy(buffer->impl.buf, upload_buffer, buffer->count * buffer->stride); } void gpu_constant_buffer_init(gpu_buffer_t *buffer, int size) { diff --git a/base/sources/backends/vulkan_gpu.h b/base/sources/backends/vulkan_gpu.h index 067d0bc5..da0fa186 100644 --- a/base/sources/backends/vulkan_gpu.h +++ b/base/sources/backends/vulkan_gpu.h @@ -25,7 +25,6 @@ typedef struct { typedef struct { VkBuffer buf; VkDeviceMemory mem; - VkMemoryAllocateInfo mem_alloc; } gpu_buffer_impl_t; typedef struct {