diff --git a/paint/assets/plugins/import_exr.js b/paint/assets/plugins/import_exr.js new file mode 100644 index 00000000..e69de29b diff --git a/paint/sources/base.ts b/paint/sources/base.ts index 7319456e..4f37642e 100644 --- a/paint/sources/base.ts +++ b/paint/sources/base.ts @@ -33,6 +33,26 @@ let base_drag_layer: slot_layer_t = null; let base_default_fov: f32 = 0.69; let _base_material_count: i32; +let ui: ui_t; +let ui_base_show: bool = true; +let ui_base_border_started: i32 = 0; +let ui_base_border_handle: ui_handle_t = null; +let ui_base_action_paint_remap: string = ""; +let ui_base_operator_search_offset: i32 = 0; +let ui_base_undo_tap_time: f32 = 0.0; +let ui_base_redo_tap_time: f32 = 0.0; +let ui_base_viewport_col: i32; +let _ui_base_operator_search_first: bool; + +type tab_draw_t = { + f: (h: ui_handle_t)=>void; +}; +type tab_draw_array_t = tab_draw_t[]; + +let ui_base_hwnds: ui_handle_t[] = ui_base_init_hwnds(); +let ui_base_htabs: ui_handle_t[] = ui_base_init_htabs(); +let ui_base_hwnd_tabs: tab_draw_array_t[] = ui_base_init_hwnd_tabs(); + function base_init() { base_last_window_width = iron_window_width(); base_last_window_height = iron_window_height(); @@ -156,7 +176,7 @@ function base_w(): i32 { let res: i32 = 0; if (config_raw.layout == null) { - let sidebarw: i32 = ui_base_default_sidebar_w; + let sidebarw: i32 = ui_sidebar_default_w; res = iron_window_width() - sidebarw - ui_toolbar_default_w; } else if (ui_nodes_show || ui_view2d_show) { @@ -192,7 +212,7 @@ function base_h(): i32 { let res: i32 = iron_window_height(); if (config_raw.layout == null) { - res -= ui_header_default_h * 2 + ui_status_default_status_h; + res -= ui_header_default_h * 2 + ui_statusbar_default_h; ///if (arm_android || arm_ios) res += ui_header_h; ///end @@ -587,7 +607,7 @@ function base_render() { } let using_menu: bool = ui_menu_show && mouse_y > ui_header_h; - base_ui_enabled = !ui_box_show && !using_menu && !base_is_combo_selected(); + base_ui_enabled = !ui_box_show && !using_menu && ui.combo_selected_handle == null; if (ui_box_show) { ui_box_render(); } @@ -670,14 +690,6 @@ function base_toggle_fullscreen() { } } -function base_is_scrolling(): bool { - return ui.is_scrolling; -} - -function base_is_combo_selected(): bool { - return ui.combo_selected_handle != null; -} - function base_is_decal_layer(): bool { let is_painting: bool = context_raw.tool != tool_type_t.MATERIAL && context_raw.tool != tool_type_t.BAKE; return is_painting && context_raw.layer.fill_layer != null && context_raw.layer.uv_type == uv_type_t.PROJECT; @@ -689,7 +701,7 @@ function base_redraw_status() { function base_redraw_console() { let statush: i32 = config_raw.layout[layout_size_t.STATUS_H]; - if (ui != null && statush > ui_status_default_status_h * UI_SCALE()) { + if (ui != null && statush > ui_statusbar_default_h * UI_SCALE()) { ui_base_hwnds[tab_area_t.STATUS].redraws = 2; } } @@ -711,7 +723,7 @@ function base_init_layout() { let show2d: bool = (ui_nodes_show || ui_view2d_show) && raw.layout != null; let new_layout: i32[] = []; - array_push(new_layout, math_floor(ui_base_default_sidebar_w * raw.window_scale)); // LayoutSidebarW + array_push(new_layout, math_floor(ui_sidebar_default_w * raw.window_scale)); // LayoutSidebarW array_push(new_layout, math_floor(iron_window_height() / 2)); // LayoutSidebarH0 array_push(new_layout, math_floor(iron_window_height() / 2)); // LayoutSidebarH1 @@ -724,7 +736,7 @@ function base_init_layout() { ///end array_push(new_layout, math_floor(sys_h() / 2)); // LayoutNodesH - array_push(new_layout, math_floor(ui_status_default_status_h * raw.window_scale)); // LayoutStatusH + array_push(new_layout, math_floor(ui_statusbar_default_h * raw.window_scale)); // LayoutStatusH ///if (arm_android || arm_ios) array_push(new_layout, 0); // LayoutHeader @@ -741,60 +753,1334 @@ function base_init_layout() { raw.layout = new_layout; } -function base_init_config() { - let raw: config_t = config_raw; - raw.recent_projects = []; - raw.bookmarks = []; - raw.plugins = []; - ///if (arm_android || arm_ios) - raw.keymap = "touch.json"; - ///else - raw.keymap = "default.json"; - ///end - raw.theme = "default.json"; - raw.server = "https://armorpaint.fra1.digitaloceanspaces.com"; - raw.undo_steps = 4; - raw.pressure_radius = true; - ///if (arm_ios || arm_linux) - raw.pressure_sensitivity = 1.0; - ///else - raw.pressure_sensitivity = 2.0; - ///end - raw.camera_zoom_speed = 1.0; - raw.camera_pan_speed = 1.0; - raw.camera_rotation_speed = 1.0; - raw.zoom_direction = zoom_direction_t.VERTICAL; - raw.displace_strength = 0.0; - raw.wrap_mouse = false; - raw.workspace = space_type_t.SPACE3D; - raw.camera_controls = camera_controls_t.ORBIT; - raw.layer_res = texture_res_t.RES2048; - ///if (arm_android || arm_ios) - raw.touch_ui = true; - raw.splash_screen = true; - ///else - raw.touch_ui = false; - raw.splash_screen = false; - ///end - raw.node_preview = true; - raw.pressure_hardness = true; - raw.pressure_angle = false; - raw.pressure_opacity = false; - ///if (arm_android || arm_ios) - raw.material_live = false; - ///else - raw.material_live = true; - ///end - raw.brush_3d = true; - raw.brush_depth_reject = true; - raw.brush_angle_reject = true; - raw.brush_live = false; - raw.show_asset_names = false; - raw.dilate = dilate_type_t.INSTANT; - raw.dilate_radius = 2; - raw.gpu_inference = true; - raw.blender = ""; - raw.scene_atlas_res = texture_res_t.RES8192; - raw.pathtrace_mode = pathtrace_mode_t.FAST; - raw.grid_snap = false; +function ui_base_init_hwnds(): ui_handle_t[] { + let hwnds: ui_handle_t[] = [ui_handle_create(), ui_handle_create(), ui_handle_create()]; + return hwnds; +} + +function ui_base_init_htabs(): ui_handle_t[] { + let htabs: ui_handle_t[] = [ui_handle_create(), ui_handle_create(), ui_handle_create()]; + return htabs; +} + +function _draw_callback_create(f: (h: ui_handle_t)=>void): tab_draw_t { + let cb: tab_draw_t = { f: f }; + return cb; +} + +function ui_base_init_hwnd_tabs(): tab_draw_array_t[] { + let a0: tab_draw_array_t = [ + _draw_callback_create(tab_layers_draw), + _draw_callback_create(tab_history_draw), + _draw_callback_create(tab_plugins_draw) + ]; + let a1: tab_draw_array_t = [ + _draw_callback_create(tab_materials_draw), + _draw_callback_create(tab_brushes_draw), + _draw_callback_create(tab_scripts_draw) + + ]; + let a2: tab_draw_array_t = [ + _draw_callback_create(tab_browser_draw), + _draw_callback_create(tab_meshes_draw), + _draw_callback_create(tab_textures_draw), + _draw_callback_create(tab_fonts_draw), + _draw_callback_create(tab_swatches_draw), + _draw_callback_create(tab_console_draw), + _draw_callback_create(ui_statusbar_draw_version_tab) + ]; + + let r: tab_draw_array_t[] = []; + array_push(r, a0); + array_push(r, a1); + array_push(r, a2); + return r; +} + +function ui_base_init() { + ui_toolbar_init(); + context_raw.text_tool_text = tr("Text"); + ui_header_init(); + ui_statusbar_init(); + ui_menubar_init(); + + ui_header_h = math_floor(ui_header_default_h * config_raw.window_scale); + ui_menubar_w = math_floor(ui_menubar_default_w * config_raw.window_scale); + + if (context_raw.empty_envmap == null) { + ui_base_make_empty_envmap(base_theme.VIEWPORT_COL); + } + if (context_raw.preview_envmap == null) { + let b: u8_array_t = u8_array_create(4); + b[0] = 0; + b[1] = 0; + b[2] = 0; + b[3] = 255; + context_raw.preview_envmap = gpu_create_texture_from_bytes(b, 1, 1); + } + + if (context_raw.saved_envmap == null) { + // raw.saved_envmap = scene_world._envmap; + context_raw.default_irradiance = scene_world._.irradiance; + context_raw.default_radiance = scene_world._.radiance; + context_raw.default_radiance_mipmaps = scene_world._.radiance_mipmaps; + } + scene_world._.envmap = context_raw.show_envmap ? context_raw.saved_envmap : context_raw.empty_envmap; + context_raw.ddirty = 1; + + let resources: string[] = ["cursor.k", "icons.k"]; + resource_load(resources); + + let scale: f32 = config_raw.window_scale; + let ops: ui_options_t = { + theme: base_theme, + font: base_font, + scale_factor: scale, + color_wheel: base_color_wheel, + black_white_gradient: base_color_wheel_gradient + }; + ui = ui_create(ops); + ui_on_border_hover = ui_base_on_border_hover; + ui_on_tab_drop = ui_base_on_tab_drop; + if (UI_SCALE() > 1) { + ui_base_set_icon_scale(); + } + + context_raw.gizmo = scene_get_child(".Gizmo"); + context_raw.gizmo_translate_x = object_get_child(context_raw.gizmo, ".TranslateX"); + context_raw.gizmo_translate_y = object_get_child(context_raw.gizmo, ".TranslateY"); + context_raw.gizmo_translate_z = object_get_child(context_raw.gizmo, ".TranslateZ"); + context_raw.gizmo_scale_x = object_get_child(context_raw.gizmo, ".ScaleX"); + context_raw.gizmo_scale_y = object_get_child(context_raw.gizmo, ".ScaleY"); + context_raw.gizmo_scale_z = object_get_child(context_raw.gizmo, ".ScaleZ"); + context_raw.gizmo_rotate_x = object_get_child(context_raw.gizmo, ".RotateX"); + context_raw.gizmo_rotate_y = object_get_child(context_raw.gizmo, ".RotateY"); + context_raw.gizmo_rotate_z = object_get_child(context_raw.gizmo, ".RotateZ"); + + project_new(false); + + if (project_filepath == "") { + sys_notify_on_next_frame(layers_init); + } + + context_raw.project_objects = []; + for (let i: i32 = 0; i < scene_meshes.length; ++i) { + let m: mesh_object_t = scene_meshes[i]; + array_push(context_raw.project_objects, m); + } + + operator_register("view_top", ui_base_view_top); +} + +function ui_base_update() { + ui_base_update_ui(); + operator_update(); + + let keys: string[] = map_keys(plugin_map); + for (let i: i32 = 0; i < keys.length; ++i) { + let p: plugin_t = map_get(plugin_map, keys[i]); + if (p.on_update != null) { + js_call(p.on_update); + } + } + + if (!base_ui_enabled) { + return; + } + + if (!ui.is_typing) { + if (operator_shortcut(map_get(config_keymap, "toggle_node_editor"))) { + ui_nodes_canvas_type == canvas_type_t.MATERIAL ? ui_base_show_material_nodes() : ui_base_show_brush_nodes(); + } + else if (operator_shortcut(map_get(config_keymap, "toggle_browser"))) { + ui_base_toggle_browser(); + } + + else if (operator_shortcut(map_get(config_keymap, "toggle_2d_view"))) { + ui_base_show_2d_view(view_2d_type_t.LAYER); + } + } + + if (operator_shortcut(map_get(config_keymap, "file_save_as"))) { + project_save_as(); + } + else if (operator_shortcut(map_get(config_keymap, "file_save"))) { + project_save(); + } + else if (operator_shortcut(map_get(config_keymap, "file_open"))) { + project_open(); + } + else if (operator_shortcut(map_get(config_keymap, "file_open_recent"))) { + box_projects_show(); + } + else if (operator_shortcut(map_get(config_keymap, "file_reimport_mesh"))) { + project_reimport_mesh(); + } + else if (operator_shortcut(map_get(config_keymap, "file_reimport_textures"))) { + project_reimport_textures(); + } + else if (operator_shortcut(map_get(config_keymap, "file_new"))) { + project_new_box(); + } + else if (operator_shortcut(map_get(config_keymap, "file_export_textures"))) { + if (context_raw.texture_export_path == "") { // First export, ask for path + context_raw.layers_export = export_mode_t.VISIBLE; + box_export_show_textures(); + } + else { + sys_notify_on_next_frame(function () { + export_texture_run(context_raw.texture_export_path); + }); + } + } + else if (operator_shortcut(map_get(config_keymap, "file_export_textures_as"))) { + context_raw.layers_export = export_mode_t.VISIBLE; + box_export_show_textures(); + } + else if (operator_shortcut(map_get(config_keymap, "file_import_assets"))) { + project_import_asset(); + } + else if (operator_shortcut(map_get(config_keymap, "edit_prefs"))) { + box_preferences_show(); + } + + if (keyboard_started(map_get(config_keymap, "view_distract_free")) || (keyboard_started("escape") && !ui_base_show && !ui_box_show)) { + ui_base_toggle_distract_free(); + } + + ///if arm_linux + if (operator_shortcut("alt+enter", shortcut_type_t.STARTED)) { + base_toggle_fullscreen(); + } + ///end + + let decal_mask: bool = context_is_decal_mask(); + + if ((context_raw.brush_can_lock || context_raw.brush_locked) && mouse_moved) { + if (operator_shortcut(map_get(config_keymap, "brush_radius"), shortcut_type_t.DOWN) || + operator_shortcut(map_get(config_keymap, "brush_opacity"), shortcut_type_t.DOWN) || + operator_shortcut(map_get(config_keymap, "brush_angle"), shortcut_type_t.DOWN) || + (decal_mask && operator_shortcut(map_get(config_keymap, "decal_mask") + "+" + map_get(config_keymap, "brush_radius"), shortcut_type_t.DOWN))) { + if (context_raw.brush_locked) { + if (operator_shortcut(map_get(config_keymap, "brush_opacity"), shortcut_type_t.DOWN)) { + context_raw.brush_opacity += mouse_movement_x / 500; + context_raw.brush_opacity = math_max(0.0, math_min(1.0, context_raw.brush_opacity)); + context_raw.brush_opacity = math_round(context_raw.brush_opacity * 100) / 100; + context_raw.brush_opacity_handle.value = context_raw.brush_opacity; + } + else if (operator_shortcut(map_get(config_keymap, "brush_angle"), shortcut_type_t.DOWN)) { + context_raw.brush_angle += mouse_movement_x / 5; + let i: i32 = math_floor(context_raw.brush_angle); + context_raw.brush_angle = i % 360; + if (context_raw.brush_angle < 0) context_raw.brush_angle += 360; + context_raw.brush_angle_handle.value = context_raw.brush_angle; + make_material_parse_paint_material(); + } + else if (decal_mask && operator_shortcut(map_get(config_keymap, "decal_mask") + "+" + map_get(config_keymap, "brush_radius"), shortcut_type_t.DOWN)) { + context_raw.brush_decal_mask_radius += mouse_movement_x / 150; + context_raw.brush_decal_mask_radius = math_max(0.01, math_min(4.0, context_raw.brush_decal_mask_radius)); + context_raw.brush_decal_mask_radius = math_round(context_raw.brush_decal_mask_radius * 100) / 100; + context_raw.brush_decal_mask_radius_handle.value = context_raw.brush_decal_mask_radius; + } + else { + context_raw.brush_radius += mouse_movement_x / 150; + context_raw.brush_radius = math_max(0.01, math_min(4.0, context_raw.brush_radius)); + context_raw.brush_radius = math_round(context_raw.brush_radius * 100) / 100; + context_raw.brush_radius_handle.value = context_raw.brush_radius; + } + ui_header_handle.redraws = 2; + } + else if (context_raw.brush_can_lock) { + context_raw.brush_can_lock = false; + context_raw.brush_locked = true; + } + } + } + + let is_typing: bool = ui.is_typing; + if (!is_typing) { + if (operator_shortcut(map_get(config_keymap, "select_material"), shortcut_type_t.DOWN)) { + ui_base_hwnds[tab_area_t.SIDEBAR1].redraws = 2; + for (let i: i32 = 1; i < 10; ++i) { + if (keyboard_started(i + "")) { + context_select_material(i - 1); + } + } + } + else if (operator_shortcut(map_get(config_keymap, "select_layer"), shortcut_type_t.DOWN)) { + ui_base_hwnds[tab_area_t.SIDEBAR0].redraws = 2; + for (let i: i32 = 1; i < 10; ++i) { + if (keyboard_started(i + "")) { + context_select_layer(i - 1); + } + } + } + } + + // Viewport shortcuts + if (context_in_paint_area() && !is_typing) { + + if (!mouse_down("right")) { // Fly mode off + if (operator_shortcut(map_get(config_keymap, "tool_brush"))) { + context_select_tool(tool_type_t.BRUSH); + } + else if (operator_shortcut(map_get(config_keymap, "tool_eraser"))) { + context_select_tool(tool_type_t.ERASER); + } + else if (operator_shortcut(map_get(config_keymap, "tool_fill"))) { + context_select_tool(tool_type_t.FILL); + } + else if (operator_shortcut(map_get(config_keymap, "tool_colorid"))) { + context_select_tool(tool_type_t.COLORID); + } + else if (operator_shortcut(map_get(config_keymap, "tool_decal"))) { + context_select_tool(tool_type_t.DECAL); + } + else if (operator_shortcut(map_get(config_keymap, "tool_text"))) { + context_select_tool(tool_type_t.TEXT); + } + else if (operator_shortcut(map_get(config_keymap, "tool_clone"))) { + context_select_tool(tool_type_t.CLONE); + } + else if (operator_shortcut(map_get(config_keymap, "tool_blur"))) { + context_select_tool(tool_type_t.BLUR); + } + else if (operator_shortcut(map_get(config_keymap, "tool_smudge"))) { + context_select_tool(tool_type_t.SMUDGE); + } + else if (operator_shortcut(map_get(config_keymap, "tool_particle"))) { + context_select_tool(tool_type_t.PARTICLE); + } + else if (operator_shortcut(map_get(config_keymap, "tool_picker"))) { + context_select_tool(tool_type_t.PICKER); + } + else if (operator_shortcut(map_get(config_keymap, "tool_bake"))) { + context_select_tool(tool_type_t.BAKE); + } + else if (operator_shortcut(map_get(config_keymap, "tool_gizmo"))) { + context_select_tool(tool_type_t.GIZMO); + } + else if (operator_shortcut(map_get(config_keymap, "tool_material"))) { + context_select_tool(tool_type_t.MATERIAL); + } + else if (operator_shortcut(map_get(config_keymap, "swap_brush_eraser"))) { + context_select_tool(context_raw.tool == tool_type_t.BRUSH ? tool_type_t.ERASER : tool_type_t.BRUSH); + } + } + + // Radius + if (context_raw.tool == tool_type_t.BRUSH || + context_raw.tool == tool_type_t.ERASER || + context_raw.tool == tool_type_t.DECAL || + context_raw.tool == tool_type_t.TEXT || + context_raw.tool == tool_type_t.CLONE || + context_raw.tool == tool_type_t.BLUR || + context_raw.tool == tool_type_t.SMUDGE || + context_raw.tool == tool_type_t.PARTICLE) { + if (operator_shortcut(map_get(config_keymap, "brush_radius")) || + operator_shortcut(map_get(config_keymap, "brush_opacity")) || + operator_shortcut(map_get(config_keymap, "brush_angle")) || + (decal_mask && operator_shortcut(map_get(config_keymap, "decal_mask") + "+" + map_get(config_keymap, "brush_radius")))) { + context_raw.brush_can_lock = true; + if (!pen_connected) { + mouse_lock(); + } + context_raw.lock_started_x = mouse_x; + context_raw.lock_started_y = mouse_y; + } + else if (operator_shortcut(map_get(config_keymap, "brush_radius_decrease"), shortcut_type_t.REPEAT)) { + context_raw.brush_radius -= ui_base_get_radius_increment(); + context_raw.brush_radius = math_max(math_round(context_raw.brush_radius * 100) / 100, 0.01); + context_raw.brush_radius_handle.value = context_raw.brush_radius; + ui_header_handle.redraws = 2; + } + else if (operator_shortcut(map_get(config_keymap, "brush_radius_increase"), shortcut_type_t.REPEAT)) { + context_raw.brush_radius += ui_base_get_radius_increment(); + context_raw.brush_radius = math_round(context_raw.brush_radius * 100) / 100; + context_raw.brush_radius_handle.value = context_raw.brush_radius; + ui_header_handle.redraws = 2; + } + else if (decal_mask) { + if (operator_shortcut(map_get(config_keymap, "decal_mask") + "+" + map_get(config_keymap, "brush_radius_decrease"), shortcut_type_t.REPEAT)) { + context_raw.brush_decal_mask_radius -= ui_base_get_radius_increment(); + context_raw.brush_decal_mask_radius = math_max(math_round(context_raw.brush_decal_mask_radius * 100) / 100, 0.01); + context_raw.brush_decal_mask_radius_handle.value = context_raw.brush_decal_mask_radius; + ui_header_handle.redraws = 2; + } + else if (operator_shortcut(map_get(config_keymap, "decal_mask") + "+" + map_get(config_keymap, "brush_radius_increase"), shortcut_type_t.REPEAT)) { + context_raw.brush_decal_mask_radius += ui_base_get_radius_increment(); + context_raw.brush_decal_mask_radius = math_round(context_raw.brush_decal_mask_radius * 100) / 100; + context_raw.brush_decal_mask_radius_handle.value = context_raw.brush_decal_mask_radius; + ui_header_handle.redraws = 2; + } + } + } + + if (decal_mask && (operator_shortcut(map_get(config_keymap, "decal_mask"), shortcut_type_t.STARTED) || operator_shortcut(map_get(config_keymap, "decal_mask"), shortcut_type_t.RELEASED))) { + ui_header_handle.redraws = 2; + } + + // Viewpoint + if (mouse_view_x() < sys_w()) { + if (operator_shortcut(map_get(config_keymap, "view_reset"))) { + viewport_reset(); + viewport_scale_to_bounds(); + } + else if (operator_shortcut(map_get(config_keymap, "view_back"))) { + viewport_set_view(0, 1, 0, math_pi() / 2, 0, math_pi()); + } + else if (operator_shortcut(map_get(config_keymap, "view_front"))) { + viewport_set_view(0, -1, 0, math_pi() / 2, 0, 0); + } + else if (operator_shortcut(map_get(config_keymap, "view_left"))) { + viewport_set_view(-1, 0, 0, math_pi() / 2, 0, -math_pi() / 2); + } + else if (operator_shortcut(map_get(config_keymap, "view_right"))) { + viewport_set_view(1, 0, 0, math_pi() / 2, 0, math_pi() / 2); + } + else if (operator_shortcut(map_get(config_keymap, "view_bottom"))) { + viewport_set_view(0, 0, -1, math_pi(), 0, math_pi()); + } + else if (operator_shortcut(map_get(config_keymap, "view_camera_type"))) { + context_raw.camera_type = context_raw.camera_type == camera_type_t.PERSPECTIVE ? camera_type_t.ORTHOGRAPHIC : camera_type_t.PERSPECTIVE; + context_raw.cam_handle.position = context_raw.camera_type; + viewport_update_camera_type(context_raw.camera_type); + } + else if (operator_shortcut(map_get(config_keymap, "view_orbit_left"), shortcut_type_t.REPEAT)) { + viewport_orbit(-math_pi() / 12, 0); + } + else if (operator_shortcut(map_get(config_keymap, "view_orbit_right"), shortcut_type_t.REPEAT)) { + viewport_orbit(math_pi() / 12, 0); + } + else if (operator_shortcut(map_get(config_keymap, "view_orbit_up"), shortcut_type_t.REPEAT)) { + viewport_orbit(0, -math_pi() / 12); + } + else if (operator_shortcut(map_get(config_keymap, "view_orbit_down"), shortcut_type_t.REPEAT)) { + viewport_orbit(0, math_pi() / 12); + } + else if (operator_shortcut(map_get(config_keymap, "view_orbit_opposite"))) { + viewport_orbit_opposite(); + } + else if (operator_shortcut(map_get(config_keymap, "view_zoom_in"), shortcut_type_t.REPEAT)) { + viewport_zoom(0.2); + } + else if (operator_shortcut(map_get(config_keymap, "view_zoom_out"), shortcut_type_t.REPEAT)) { + viewport_zoom(-0.2); + } + else if (operator_shortcut(map_get(config_keymap, "viewport_mode"))) { + ui.is_key_pressed = false; + ui_menu_draw(function () { + let mode_handle: ui_handle_t = ui_handle(__ID__); + mode_handle.position = context_raw.viewport_mode; + ui_text(tr("Viewport Mode"), ui_align_t.RIGHT); + let modes: string[] = [ + tr("Lit"), + tr("Base Color"), + tr("Normal"), + tr("Occlusion"), + tr("Roughness"), + tr("Metallic"), + tr("Opacity"), + tr("Height"), + tr("Emission"), + tr("Subsurface"), + tr("TexCoord"), + tr("Object Normal"), + tr("Material ID"), + tr("Object ID"), + tr("Mask") + ]; + + 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) { + ui_radio(mode_handle, i, modes[i], shortcuts[i]); + } + + let index: i32 = array_index_of(shortcuts, keyboard_key_code(ui.key_code)); + if (ui.is_key_pressed && index != -1) { + mode_handle.position = index; + ui.changed = true; + context_set_viewport_mode(mode_handle.position); + } + else if (mode_handle.changed) { + context_set_viewport_mode(mode_handle.position); + ui.changed = true; + } + }); + } + } + + if (operator_shortcut(map_get(config_keymap, "operator_search"))) { + ui_base_operator_search(); + } + } + + if (context_raw.brush_can_lock || context_raw.brush_locked) { + if (mouse_moved && context_raw.brush_can_unlock) { + context_raw.brush_locked = false; + context_raw.brush_can_unlock = false; + } + + let b: bool = (context_raw.brush_can_lock || context_raw.brush_locked) && + !operator_shortcut(map_get(config_keymap, "brush_radius"), shortcut_type_t.DOWN) && + !operator_shortcut(map_get(config_keymap, "brush_opacity"), shortcut_type_t.DOWN) && + !operator_shortcut(map_get(config_keymap, "brush_angle"), shortcut_type_t.DOWN) && + !(decal_mask && operator_shortcut(map_get(config_keymap, "decal_mask") + "+" + map_get(config_keymap, "brush_radius"), shortcut_type_t.DOWN)); + + if (b) { + mouse_unlock(); + context_raw.last_paint_x = -1; + context_raw.last_paint_y = -1; + if (context_raw.brush_can_lock) { + context_raw.brush_can_lock = false; + context_raw.brush_can_unlock = false; + context_raw.brush_locked = false; + } + else { + context_raw.brush_can_unlock = true; + } + } + } + + // Resizing + if (ui_base_border_handle != null) { + if (ui_base_border_handle == ui_nodes_hwnd || ui_base_border_handle == ui_view2d_hwnd) { + if (ui_base_border_started == border_side_t.LEFT) { + config_raw.layout[layout_size_t.NODES_W] -= math_floor(mouse_movement_x); + if (config_raw.layout[layout_size_t.NODES_W] < 32) { + config_raw.layout[layout_size_t.NODES_W] = 32; + } + else if (config_raw.layout[layout_size_t.NODES_W] > iron_window_width() * 0.7) { + config_raw.layout[layout_size_t.NODES_W] = math_floor(iron_window_width() * 0.7); + } + } + else { // UINodes / UIView2D ratio + config_raw.layout[layout_size_t.NODES_H] -= math_floor(mouse_movement_y); + if (config_raw.layout[layout_size_t.NODES_H] < 32) { + config_raw.layout[layout_size_t.NODES_H] = 32; + } + else if (config_raw.layout[layout_size_t.NODES_H] > sys_h() * 0.95) { + config_raw.layout[layout_size_t.NODES_H] = math_floor(sys_h() * 0.95); + } + } + } + else if (ui_base_border_handle == ui_base_hwnds[tab_area_t.STATUS]) { + let my: i32 = math_floor(mouse_movement_y); + if (config_raw.layout[layout_size_t.STATUS_H] - my >= ui_statusbar_default_h * config_raw.window_scale && config_raw.layout[layout_size_t.STATUS_H] - my < iron_window_height() * 0.7) { + config_raw.layout[layout_size_t.STATUS_H] -= my; + } + } + else { + if (ui_base_border_started == border_side_t.LEFT) { + config_raw.layout[layout_size_t.SIDEBAR_W] -= math_floor(mouse_movement_x); + if (config_raw.layout[layout_size_t.SIDEBAR_W] < ui_sidebar_w_mini) { + config_raw.layout[layout_size_t.SIDEBAR_W] = ui_sidebar_w_mini; + } + else if (config_raw.layout[layout_size_t.SIDEBAR_W] > iron_window_width() - ui_sidebar_w_mini) { + config_raw.layout[layout_size_t.SIDEBAR_W] = iron_window_width() - ui_sidebar_w_mini; + } + } + else { + let my: i32 = math_floor(mouse_movement_y); + if (ui_base_border_handle == ui_base_hwnds[tab_area_t.SIDEBAR1] && ui_base_border_started == border_side_t.TOP) { + if (config_raw.layout[layout_size_t.SIDEBAR_H0] + my > 32 && config_raw.layout[layout_size_t.SIDEBAR_H1] - my > 32) { + config_raw.layout[layout_size_t.SIDEBAR_H0] += my; + config_raw.layout[layout_size_t.SIDEBAR_H1] -= my; + } + } + } + } + } + + if (!mouse_down()) { + ui_base_border_handle = null; + base_is_resizing = false; + } + + if (context_raw.tool == tool_type_t.PARTICLE && context_in_paint_area() && !context_raw.paint2d) { + util_particle_init_physics(); + let world: physics_world_t = physics_world_active; + physics_world_update(world); + context_raw.ddirty = 2; + context_raw.rdirty = 2; + if (mouse_started()) { + if (context_raw.particle_timer != null) { + tween_stop(context_raw.particle_timer); + let timer: tween_anim_t = context_raw.particle_timer; + timer.done(timer.done_data); + context_raw.particle_timer = null; + } + history_push_undo = true; + context_raw.particle_hit_x = context_raw.particle_hit_y = context_raw.particle_hit_z = 0; + let o: object_t = scene_spawn_object(".Sphere"); + let mo: mesh_object_t = o.ext; + mo.base.name = ".Bullet"; + mo.base.visible = true; + + let camera: camera_object_t = scene_camera; + let ct: transform_t = camera.base.transform; + mo.base.transform.loc = vec4_create(transform_world_x(ct), transform_world_y(ct), transform_world_z(ct)); + mo.base.transform.scale = vec4_create(context_raw.brush_radius * 0.2, context_raw.brush_radius * 0.2, context_raw.brush_radius * 0.2); + transform_build_matrix(mo.base.transform); + + let body: physics_body_t = physics_body_create(); + body.shape = physics_shape_t.SPHERE; + body.mass = 1.0; + physics_body_init(body, mo.base); + + let ray: ray_t = raycast_get_ray(mouse_view_x(), mouse_view_y(), camera); + physics_body_apply_impulse(body, vec4_mult(ray.dir, 0.15)); + + context_raw.particle_timer = tween_timer(5, function (mo: mesh_object_t) { + mesh_object_remove(mo); + }, mo); + } + + let pairs: physics_pair_t[] = physics_world_get_contact_pairs(world, context_raw.paint_body); + if (pairs != null) { + for (let i: i32 = 0; i < pairs.length; ++i) { + let p: physics_pair_t = pairs[i]; + context_raw.last_particle_hit_x = context_raw.particle_hit_x != 0 ? context_raw.particle_hit_x : p.pos_a_x; + context_raw.last_particle_hit_y = context_raw.particle_hit_y != 0 ? context_raw.particle_hit_y : p.pos_a_y; + context_raw.last_particle_hit_z = context_raw.particle_hit_z != 0 ? context_raw.particle_hit_z : p.pos_a_z; + context_raw.particle_hit_x = p.pos_a_x; + context_raw.particle_hit_y = p.pos_a_y; + context_raw.particle_hit_z = p.pos_a_z; + context_raw.pdirty = 1; + break; // 1 pair for now + } + } + } +} + +function ui_base_view_top() { + let is_typing: bool = ui.is_typing; + + if (context_in_paint_area() && !is_typing) { + if (mouse_view_x() < sys_w()) { + viewport_set_view(0, 0, 1, 0, 0, 0); + } + } +} + +function ui_base_operator_search() { + _ui_base_operator_search_first = true; + + ui_menu_draw(function () { + ui_menu_h = UI_ELEMENT_H() * 8; + let search_handle: ui_handle_t = ui_handle(__ID__); + let search: string = ui_text_input(search_handle, "", ui_align_t.LEFT, true, true); + ui.changed = false; + if (_ui_base_operator_search_first) { + _ui_base_operator_search_first = false; + search_handle.text = ""; + ui_start_text_edit(search_handle); // Focus search bar + } + + if (search_handle.changed) { + ui_base_operator_search_offset = 0; + } + + if (ui.is_key_pressed) { // Move selection + if (ui.key_code == key_code_t.DOWN && ui_base_operator_search_offset < 6) { + ui_base_operator_search_offset++; + } + if (ui.key_code == key_code_t.UP && ui_base_operator_search_offset > 0) { + ui_base_operator_search_offset--; + } + } + let enter: bool = keyboard_down("enter"); + let count: i32 = 0; + let BUTTON_COL: i32 = ui.ops.theme.BUTTON_COL; + + let keys: string[] = map_keys(config_keymap); + for (let i: i32 = 0; i < keys.length; ++i) { + let n: string = keys[i]; + if (string_index_of(n, search) >= 0) { + ui.ops.theme.BUTTON_COL = count == ui_base_operator_search_offset ? ui.ops.theme.HIGHLIGHT_COL : ui.ops.theme.SEPARATOR_COL; + if (ui_button(n, ui_align_t.LEFT, map_get(config_keymap, n)) || (enter && count == ui_base_operator_search_offset)) { + if (enter) { + ui.changed = true; + count = 6; // Trigger break + } + operator_run(n); + } + if (++count > 6) { + break; + } + } + } + + if (enter && count == 0) { // Hide popup on enter when command is not found + ui.changed = true; + search_handle.text = ""; + } + ui.ops.theme.BUTTON_COL = BUTTON_COL; + }); +} + +function ui_base_toggle_distract_free() { + ui_base_show = !ui_base_show; + base_resize(); +} + +function ui_base_get_radius_increment(): f32 { + return 0.1; +} + +function ui_base_hit_rect(mx: f32, my: f32, x: i32, y: i32, w: i32, h: i32): bool { + return mx > x && mx < x + w && my > y && my < y + h; +} + +function ui_base_get_brush_stencil_rect(): rect_t { + let w: i32 = math_floor(context_raw.brush_stencil_image.width * (base_h() / context_raw.brush_stencil_image.height) * context_raw.brush_stencil_scale); + let h: i32 = math_floor(base_h() * context_raw.brush_stencil_scale); + let x: i32 = math_floor(base_x() + context_raw.brush_stencil_x * base_w()); + let y: i32 = math_floor(base_y() + context_raw.brush_stencil_y * base_h()); + let r: rect_t = { + w: w, + h: h, + x: x, + y: y + }; + return r; +} + +function ui_base_update_ui() { + if (console_message_timer > 0) { + console_message_timer -= sys_delta(); + if (console_message_timer <= 0) { + ui_base_hwnds[tab_area_t.STATUS].redraws = 2; + } + } + + ui_sidebar_w_mini = math_floor(ui_sidebar_default_w_mini * UI_SCALE()); + + if (!base_ui_enabled) { + return; + } + + // Same mapping for paint and rotate (predefined in touch keymap) + if (context_in_viewport()) { + let paint_key: string = map_get(config_keymap, "action_paint"); + let rotate_key: string = map_get(config_keymap, "action_rotate"); + if (mouse_started() && paint_key == rotate_key) { + ui_base_action_paint_remap = paint_key; + util_render_pick_pos_nor_tex(); + let is_mesh: bool = math_abs(context_raw.posx_picked) < 50 && math_abs(context_raw.posy_picked) < 50 && math_abs(context_raw.posz_picked) < 50; + ///if arm_android + // Allow rotating with both pen and touch, because hovering a pen prevents touch input on android + let pen_only: bool = false; + ///else + let pen_only: bool = context_raw.pen_painting_only; + ///end + let is_pen: bool = pen_only && pen_down(); + // Mesh picked - disable rotate + // Pen painting only - rotate with touch, paint with pen + if ((is_mesh && !pen_only) || is_pen) { + map_set(config_keymap, "action_rotate", ""); + map_set(config_keymap, "action_paint", ui_base_action_paint_remap); + } + // World sphere picked - disable paint + else { + map_set(config_keymap, "action_paint", ""); + map_set(config_keymap, "action_rotate", ui_base_action_paint_remap); + } + } + else if (!mouse_down() && ui_base_action_paint_remap != "") { + map_set(config_keymap, "action_rotate", ui_base_action_paint_remap); + map_set(config_keymap, "action_paint", ui_base_action_paint_remap); + ui_base_action_paint_remap = ""; + } + } + + if (context_raw.brush_stencil_image != null && operator_shortcut(map_get(config_keymap, "stencil_transform"), shortcut_type_t.DOWN)) { + let r: rect_t = ui_base_get_brush_stencil_rect(); + if (mouse_started("left")) { + context_raw.brush_stencil_scaling = + ui_base_hit_rect(mouse_x, mouse_y, r.x - 8, r.y - 8, 16, 16) || + ui_base_hit_rect(mouse_x, mouse_y, r.x - 8, r.h + r.y - 8, 16, 16) || + ui_base_hit_rect(mouse_x, mouse_y, r.w + r.x - 8, r.y - 8, 16, 16) || + ui_base_hit_rect(mouse_x, mouse_y, r.w + r.x - 8, r.h + r.y - 8, 16, 16); + let cosa: f32 = math_cos(-context_raw.brush_stencil_angle); + let sina: f32 = math_sin(-context_raw.brush_stencil_angle); + let ox: f32 = 0; + let oy: f32 = -r.h / 2; + let x: f32 = ox * cosa - oy * sina; + let y: f32 = ox * sina + oy * cosa; + x += r.x + r.w / 2; + y += r.y + r.h / 2; + context_raw.brush_stencil_rotating = + ui_base_hit_rect(mouse_x, mouse_y, math_floor(x - 16), math_floor(y - 16), 32, 32); + } + let _scale: f32 = context_raw.brush_stencil_scale; + if (mouse_down("left")) { + if (context_raw.brush_stencil_scaling) { + let mult: i32 = mouse_x > r.x + r.w / 2 ? 1 : -1; + context_raw.brush_stencil_scale += mouse_movement_x / 400 * mult; + } + else if (context_raw.brush_stencil_rotating) { + let gizmo_x: f32 = r.x + r.w / 2; + let gizmo_y: f32 = r.y + r.h / 2; + context_raw.brush_stencil_angle = -math_atan2(mouse_y - gizmo_y, mouse_x - gizmo_x) - math_pi() / 2; + } + else { + context_raw.brush_stencil_x += mouse_movement_x / base_w(); + context_raw.brush_stencil_y += mouse_movement_y / base_h(); + } + } + else { + context_raw.brush_stencil_scaling = false; + } + if (mouse_wheel_delta != 0) { + context_raw.brush_stencil_scale -= mouse_wheel_delta / 10; + } + // Center after scale + let ratio: f32 = base_h() / context_raw.brush_stencil_image.height; + let old_w: f32 = _scale * context_raw.brush_stencil_image.width * ratio; + let new_w: f32 = context_raw.brush_stencil_scale * context_raw.brush_stencil_image.width * ratio; + let old_h: f32 = _scale * base_h(); + let new_h: f32 = context_raw.brush_stencil_scale * base_h(); + context_raw.brush_stencil_x += (old_w - new_w) / base_w() / 2; + context_raw.brush_stencil_y += (old_h - new_h) / base_h() / 2; + } + + let set_clone_source: bool = context_raw.tool == tool_type_t.CLONE && operator_shortcut(map_get(config_keymap, "set_clone_source") + "+" + map_get(config_keymap, "action_paint"), shortcut_type_t.DOWN); + + let decal: bool = context_is_decal(); + let decal_mask: bool = context_is_decal_mask_paint(); + + let down: bool = operator_shortcut(map_get(config_keymap, "action_paint"), shortcut_type_t.DOWN) || + decal_mask || + set_clone_source || + operator_shortcut(map_get(config_keymap, "brush_ruler") + "+" + map_get(config_keymap, "action_paint"), shortcut_type_t.DOWN) || + (pen_down() && !keyboard_down("alt")); + + if (config_raw.touch_ui) { + if (pen_down()) { + context_raw.pen_painting_only = true; + } + else if (context_raw.pen_painting_only) { + down = false; + } + } + + if (context_raw.tool == tool_type_t.PARTICLE) { + down = false; + } + + if (down) { + let mx: i32 = mouse_view_x(); + let my: i32 = mouse_view_y(); + let ww: i32 = sys_w(); + + if (context_raw.paint2d) { + mx -= sys_w(); + ww = ui_view2d_ww; + } + + if (mx < ww && + mx > sys_x() && + my < sys_h() && + my > sys_y()) { + + if (set_clone_source) { + context_raw.clone_start_x = mx; + context_raw.clone_start_y = my; + } + else { + if (context_raw.brush_time == 0 && + !base_is_dragging && + !base_is_resizing && + ui.combo_selected_handle == null) { // Paint started + + // Draw line + if (operator_shortcut(map_get(config_keymap, "brush_ruler") + "+" + map_get(config_keymap, "action_paint"), shortcut_type_t.DOWN)) { + context_raw.last_paint_vec_x = context_raw.last_paint_x; + context_raw.last_paint_vec_y = context_raw.last_paint_y; + } + + history_push_undo = true; + + if (context_raw.tool == tool_type_t.CLONE && context_raw.clone_start_x >= 0.0) { // Clone delta + context_raw.clone_delta_x = (context_raw.clone_start_x - mx) / ww; + context_raw.clone_delta_y = (context_raw.clone_start_y - my) / sys_h(); + context_raw.clone_start_x = -1; + } + else if (context_raw.tool == tool_type_t.FILL && context_raw.fill_type_handle.position == fill_type_t.UV_ISLAND) { + util_uv_uvislandmap_cached = false; + } + } + + context_raw.brush_time += sys_delta(); + + if (context_raw.run_brush != null) { + context_raw.run_brush(context_raw.brush_output_node_inst, 0); + } + } + } + } + else if (context_raw.brush_time > 0) { // Brush released + context_raw.brush_time = 0; + context_raw.prev_paint_vec_x = -1; + context_raw.prev_paint_vec_y = -1; + ///if (arm_opengl || arm_direct3d11) // Keep accumulated samples for D3D12 + context_raw.ddirty = 3; + ///end + context_raw.brush_blend_dirty = true; // Update brush mask + + context_raw.layer_preview_dirty = true; // Update layer preview + + // New color id picked, update fill layer + if (context_raw.tool == tool_type_t.COLORID && context_raw.layer.fill_layer != null) { + sys_notify_on_next_frame(function () { + layers_update_fill_layer(); + make_material_parse_paint_material(false); + }); + } + } + + if (context_raw.layers_preview_dirty) { + context_raw.layers_preview_dirty = false; + context_raw.layer_preview_dirty = false; + context_raw.mask_preview_last = null; + // Update all layer previews + for (let i: i32 = 0; i < project_layers.length; ++i) { + let l: slot_layer_t = project_layers[i]; + if (slot_layer_is_group(l)) { + continue; + } + + let target: gpu_texture_t = l.texpaint_preview; + if (target == null) { + continue; + } + + let source: gpu_texture_t = l.texpaint; + draw_begin(target, true, 0x00000000); + // draw_set_pipeline(l.is_mask() ? pipes_copy8 : pipes_copy); + draw_set_pipeline(pipes_copy); // texpaint_preview is always RGBA32 for now + draw_scaled_image(source, 0, 0, target.width, target.height); + draw_set_pipeline(null); + draw_end(); + } + ui_base_hwnds[tab_area_t.SIDEBAR0].redraws = 2; + } + if (context_raw.layer != null && context_raw.layer_preview_dirty && !slot_layer_is_group(context_raw.layer)) { + context_raw.layer_preview_dirty = false; + context_raw.mask_preview_last = null; + // Update layer preview + let l: slot_layer_t = context_raw.layer; + + let target: gpu_texture_t = l.texpaint_preview; + if (target != null) { + + let source: gpu_texture_t = l.texpaint; + draw_begin(target, true, 0x00000000); + // draw_set_pipeline(raw.layer.is_mask() ? pipes_copy8 : pipes_copy); + draw_set_pipeline(pipes_copy); // texpaint_preview is always RGBA32 for now + draw_scaled_image(source, 0, 0, target.width, target.height); + draw_set_pipeline(null); + draw_end(); + ui_base_hwnds[tab_area_t.SIDEBAR0].redraws = 2; + } + } + + let undo_pressed: bool = operator_shortcut(map_get(config_keymap, "edit_undo")); + let redo_pressed: bool = operator_shortcut(map_get(config_keymap, "edit_redo")) || + (keyboard_down("control") && keyboard_started("y")); + + // Two-finger tap to undo, three-finger tap to redo + if (context_in_viewport() && config_raw.touch_ui) { + if (mouse_started("middle")) { + ui_base_redo_tap_time = sys_time(); + } + else if (mouse_started("right")) { + ui_base_undo_tap_time = sys_time(); + } + else if (mouse_released("middle") && sys_time() - ui_base_redo_tap_time < 0.1) { + ui_base_redo_tap_time = ui_base_undo_tap_time = 0; + redo_pressed = true; + } + else if (mouse_released("right") && sys_time() - ui_base_undo_tap_time < 0.1) { + ui_base_redo_tap_time = ui_base_undo_tap_time = 0; + undo_pressed = true; + } + } + + if (undo_pressed) { + history_undo(); + } + else if (redo_pressed) { + history_redo(); + } + + gizmo_update(); +} + +function ui_base_render() { + if (!ui_base_show && config_raw.touch_ui) { + ui.input_enabled = true; + ui_begin(ui); + if (ui_window(ui_handle(__ID__), 0, 0, 150, math_floor(UI_ELEMENT_H() + UI_ELEMENT_OFFSET() + 1))) { + if (ui_button(tr("Close"))) { + ui_base_toggle_distract_free(); + } + } + ui_end(); + } + + if (!ui_base_show) { + return; + } + + ui.input_enabled = base_ui_enabled; + + // Remember last tab positions + for (let i: i32 = 0; i < ui_base_htabs.length; ++i) { + if (ui_base_htabs[i].changed) { + config_raw.layout_tabs[i] = ui_base_htabs[i].position; + config_save(); + } + } + + // Set tab positions + for (let i: i32 = 0; i < ui_base_htabs.length; ++i) { + ui_base_htabs[i].position = config_raw.layout_tabs[i]; + } + + ui_begin(ui); + ui_toolbar_render_ui(); + ui_menubar_render_ui(); + ui_header_render_ui(); + ui_statusbar_render_ui(); + ui_sidebar_render_ui(); + ui_end(); + + ui.input_enabled = true; +} + +function ui_base_render_cursor() { + if (!base_ui_enabled) { + return; + } + + if (context_raw.tool == tool_type_t.MATERIAL || context_raw.tool == tool_type_t.BAKE) { + return; + } + + draw_begin(); + draw_set_color(0xffffffff); + + context_raw.view_index = context_raw.view_index_last; + let mx: i32 = base_x() + context_raw.paint_vec.x * base_w(); + let my: i32 = base_y() + context_raw.paint_vec.y * base_h(); + context_raw.view_index = -1; + + // Radius being scaled + if (context_raw.brush_locked) { + mx += context_raw.lock_started_x - iron_window_width() / 2; + my += context_raw.lock_started_y - iron_window_height() / 2; + } + + if (context_raw.brush_stencil_image != null && + context_raw.tool != tool_type_t.BAKE && + context_raw.tool != tool_type_t.PICKER && + context_raw.tool != tool_type_t.MATERIAL && + context_raw.tool != tool_type_t.COLORID) { + let r: rect_t = ui_base_get_brush_stencil_rect(); + if (!operator_shortcut(map_get(config_keymap, "stencil_hide"), shortcut_type_t.DOWN)) { + draw_set_color(0x88ffffff); + let angle: f32 = context_raw.brush_stencil_angle; + draw_set_transform(mat3_multmat(mat3_multmat(mat3_translation(0.5, 0.5), mat3_rotation(-angle)), mat3_translation(-0.5, -0.5))); + draw_scaled_image(context_raw.brush_stencil_image, r.x, r.y, r.w, r.h); + draw_set_transform(mat3_nan()); + draw_set_color(0xffffffff); + } + let transform: bool = operator_shortcut(map_get(config_keymap, "stencil_transform"), shortcut_type_t.DOWN); + if (transform) { + // Outline + draw_rect(r.x, r.y, r.w, r.h); + // Scale + draw_rect(r.x - 8, r.y - 8, 16, 16); + draw_rect(r.x - 8 + r.w, r.y - 8, 16, 16); + draw_rect(r.x - 8, r.y - 8 + r.h, 16, 16); + draw_rect(r.x - 8 + r.w, r.y - 8 + r.h, 16, 16); + // Rotate + let cosa: f32 = math_cos(-context_raw.brush_stencil_angle); + let sina: f32 = math_sin(-context_raw.brush_stencil_angle); + let ox: f32 = 0; + let oy: f32 = -r.h / 2; + let x: f32 = ox * cosa - oy * sina; + let y: f32 = ox * sina + oy * cosa; + x += r.x + r.w / 2; + y += r.y + r.h / 2; + draw_filled_circle(x, y, 8); + } + } + + // Show picked material next to cursor + if (context_raw.tool == tool_type_t.PICKER && context_raw.picker_select_material && context_raw.color_picker_callback == null) { + let img: gpu_texture_t = context_raw.material.image_icon; + draw_image(img, mx + 10, my + 10); + } + if (context_raw.tool == tool_type_t.PICKER && context_raw.color_picker_callback != null) { + let img: gpu_texture_t = resource_get("icons.k"); + let rect: rect_t = resource_tile50(img, tool_type_t.PICKER, 0); + draw_sub_image(img, mx + 10, my + 10, rect.x, rect.y, rect.w, rect.h); + } + + let cursor_img: gpu_texture_t = resource_get("cursor.k"); + let psize: i32 = math_floor(182 * (context_raw.brush_radius * context_raw.brush_nodes_radius) * UI_SCALE()); + + // Clone source cursor + if (context_raw.tool == tool_type_t.CLONE && !keyboard_down("alt") && (mouse_down() || pen_down())) { + draw_set_color(0x66ffffff); + draw_scaled_image(cursor_img, mx + context_raw.clone_delta_x * sys_w() - psize / 2, my + context_raw.clone_delta_y * sys_h() - psize / 2, psize, psize); + draw_set_color(0xffffffff); + } + + let decal: bool = context_is_decal(); + + if (!config_raw.brush_3d || context_in_2d_view() || decal) { + let decal_mask: bool = context_is_decal_mask(); + if (decal && !context_in_nodes()) { + let decal_alpha: f32 = 0.5; + if (!decal_mask) { + context_raw.decal_x = context_raw.paint_vec.x; + context_raw.decal_y = context_raw.paint_vec.y; + decal_alpha = context_raw.brush_opacity; + + // Radius being scaled + if (context_raw.brush_locked) { + context_raw.decal_x += (context_raw.lock_started_x - iron_window_width() / 2) / base_w(); + context_raw.decal_y += (context_raw.lock_started_y - iron_window_height() / 2) / base_h(); + } + } + + if (!config_raw.brush_live) { + let psizex: i32 = math_floor(256 * UI_SCALE() * (context_raw.brush_radius * context_raw.brush_nodes_radius * context_raw.brush_scale_x)); + let psizey: i32 = math_floor(256 * UI_SCALE() * (context_raw.brush_radius * context_raw.brush_nodes_radius)); + + context_raw.view_index = context_raw.view_index_last; + let decalx: f32 = base_x() + context_raw.decal_x * base_w() - psizex / 2; + let decaly: f32 = base_y() + context_raw.decal_y * base_h() - psizey / 2; + context_raw.view_index = -1; + + draw_set_color(color_from_floats(1, 1, 1, decal_alpha)); + let angle: f32 = (context_raw.brush_angle + context_raw.brush_nodes_angle) * (math_pi() / 180); + draw_set_transform(mat3_multmat(mat3_multmat(mat3_translation(0.5, 0.5), mat3_rotation(angle)), mat3_translation(-0.5, -0.5))); + draw_scaled_image(context_raw.decal_image, decalx, decaly, psizex, psizey); + draw_set_transform(mat3_nan()); + draw_set_color(0xffffffff); + } + } + if (context_raw.tool == tool_type_t.BRUSH || + context_raw.tool == tool_type_t.ERASER || + context_raw.tool == tool_type_t.CLONE || + context_raw.tool == tool_type_t.BLUR || + context_raw.tool == tool_type_t.SMUDGE || + context_raw.tool == tool_type_t.PARTICLE || + (decal_mask && !config_raw.brush_3d) || + (decal_mask && context_in_2d_view())) { + if (decal_mask) { + psize = math_floor(cursor_img.width * (context_raw.brush_decal_mask_radius * context_raw.brush_nodes_radius) * UI_SCALE()); + } + if (config_raw.brush_3d && context_in_2d_view()) { + psize = math_floor(psize * ui_view2d_pan_scale); + } + draw_scaled_image(cursor_img, mx - psize / 2, my - psize / 2, psize, psize); + } + } + + if (context_raw.brush_lazy_radius > 0 && !context_raw.brush_locked && + (context_raw.tool == tool_type_t.BRUSH || + context_raw.tool == tool_type_t.ERASER || + context_raw.tool == tool_type_t.DECAL || + context_raw.tool == tool_type_t.TEXT || + context_raw.tool == tool_type_t.CLONE || + context_raw.tool == tool_type_t.BLUR || + context_raw.tool == tool_type_t.SMUDGE || + context_raw.tool == tool_type_t.PARTICLE)) { + draw_filled_rect(mx - 1, my - 1, 2, 2); + mx = context_raw.brush_lazy_x * base_w() + base_x(); + my = context_raw.brush_lazy_y * base_h() + base_y(); + let radius: f32 = context_raw.brush_lazy_radius * 180; + draw_set_color(0xff666666); + draw_scaled_image(cursor_img, mx - radius / 2, my - radius / 2, radius, radius); + draw_set_color(0xffffffff); + } + draw_end(); +} + +function ui_base_show_material_nodes() { + // Clear input state as ui receives input events even when not drawn + ui_end_input(); + + ui_nodes_show = !ui_nodes_show || ui_nodes_canvas_type != canvas_type_t.MATERIAL; + ui_nodes_canvas_type = canvas_type_t.MATERIAL; + + ///if (arm_ios || arm_android) + if (ui_view2d_show) { + ui_view2d_show = false; + } + ///end + + base_resize(); +} + +function ui_base_show_brush_nodes() { + // Clear input state as ui receives input events even when not drawn + ui_end_input(); + ui_nodes_show = !ui_nodes_show || ui_nodes_canvas_type != canvas_type_t.BRUSH; + ui_nodes_canvas_type = canvas_type_t.BRUSH; + + ///if (arm_ios || arm_android) + if (ui_view2d_show) { + ui_view2d_show = false; + } + ///end + + base_resize(); +} + +function ui_base_show_2d_view(type: view_2d_type_t) { + // Clear input state as ui receives input events even when not drawn + ui_end_input(); + if (ui_view2d_type != type) { + ui_view2d_show = true; + } + else { + ui_view2d_show = !ui_view2d_show; + } + ui_view2d_type = type; + ui_view2d_hwnd.redraws = 2; + + ///if (arm_ios || arm_android) + if (ui_nodes_show) { + ui_nodes_show = false; + } + ///end + + base_resize(); +} + +function ui_base_toggle_browser() { + let minimized: bool = config_raw.layout[layout_size_t.STATUS_H] <= (ui_statusbar_default_h * config_raw.window_scale); + config_raw.layout[layout_size_t.STATUS_H] = minimized ? 240 : ui_statusbar_default_h; + config_raw.layout[layout_size_t.STATUS_H] = math_floor(config_raw.layout[layout_size_t.STATUS_H] * config_raw.window_scale); +} + +function ui_base_set_icon_scale() { + if (UI_SCALE() > 1) { + let res: string[] = ["icons2x.k"]; + resource_load(res); + map_set(resource_bundled, "icons.k", resource_get("icons2x.k")); + } + else { + let res: string[] = ["icons.k"]; + resource_load(res); + } +} + +function ui_base_on_border_hover(handle: ui_handle_t, side: i32) { + if (!base_ui_enabled) { + return; + } + + if (handle != ui_base_hwnds[tab_area_t.SIDEBAR0] && + handle != ui_base_hwnds[tab_area_t.SIDEBAR1] && + handle != ui_base_hwnds[tab_area_t.STATUS] && + handle != ui_nodes_hwnd && + handle != ui_view2d_hwnd) { + return; // Scalable handles + } + if (handle == ui_view2d_hwnd && side != border_side_t.LEFT) { + return; + } + if (handle == ui_nodes_hwnd && side == border_side_t.TOP && !ui_view2d_show) { + return; + } + if (handle == ui_base_hwnds[tab_area_t.SIDEBAR0] && side == border_side_t.TOP) { + return; + } + + if (handle == ui_nodes_hwnd && side != border_side_t.LEFT && side != border_side_t.TOP) { + return; + } + if (handle == ui_base_hwnds[tab_area_t.STATUS] && side != border_side_t.TOP) { + return; + } + if (side == border_side_t.RIGHT) { + return; // UI is snapped to the right side + } + + side == border_side_t.LEFT || side == border_side_t.RIGHT ? + iron_mouse_set_cursor(cursor_t.SIZEWE) : + iron_mouse_set_cursor(cursor_t.SIZENS); + + if (ui.input_started) { + ui_base_border_started = side; + ui_base_border_handle = handle; + base_is_resizing = true; + } +} + +function ui_base_on_tab_drop(to: ui_handle_t, to_position: i32, from: ui_handle_t, from_position: i32) { + let i: i32 = -1; + let j: i32 = -1; + for (let k: i32 = 0; k < ui_base_htabs.length; ++k) { + if (ui_base_htabs[k] == to) { + i = k; + } + if (ui_base_htabs[k] == from) { + j = k; + } + } + if (i == j && to_position == from_position) { + return; + } + if (i > -1 && j > -1) { + let tabsi: tab_draw_t[] = ui_base_hwnd_tabs[i]; + let tabsj: tab_draw_t[] = ui_base_hwnd_tabs[j]; + let element: tab_draw_t = tabsj[from_position]; + array_splice(tabsj, from_position, 1); + array_insert(tabsi, to_position, element); + ui_base_hwnds[i].redraws = 2; + ui_base_hwnds[j].redraws = 2; + } +} + +function ui_base_tag_ui_redraw() { + ui_header_handle.redraws = 2; + ui_base_hwnds[tab_area_t.STATUS].redraws = 2; + ui_menubar_workspace_handle.redraws = 2; + ui_menubar_menu_handle.redraws = 2; + ui_base_hwnds[tab_area_t.SIDEBAR0].redraws = 2; + ui_base_hwnds[tab_area_t.SIDEBAR1].redraws = 2; + ui_toolbar_handle.redraws = 2; +} + +function ui_base_make_empty_envmap(col: i32) { + ui_base_viewport_col = col; + let b: u8_array_t = u8_array_create(4); + b[0] = color_get_rb(col); + b[1] = color_get_gb(col); + b[2] = color_get_bb(col); + b[3] = 255; + context_raw.empty_envmap = gpu_create_texture_from_bytes(b, 1, 1); +} + +function ui_base_set_viewport_col(col: i32) { + ui_base_make_empty_envmap(col); + context_raw.ddirty = 2; + if (!context_raw.show_envmap) { + scene_world._.envmap = context_raw.empty_envmap; + } } diff --git a/paint/sources/box_preferences.ts b/paint/sources/box_preferences.ts index 6ccb7aa7..20dff563 100644 --- a/paint/sources/box_preferences.ts +++ b/paint/sources/box_preferences.ts @@ -866,11 +866,11 @@ function box_preferences_set_scale() { let scale: f32 = config_raw.window_scale; ui_set_scale(scale); ui_header_h = math_floor(ui_header_default_h * scale); - config_raw.layout[layout_size_t.STATUS_H] = math_floor(ui_status_default_status_h * scale); + config_raw.layout[layout_size_t.STATUS_H] = math_floor(ui_statusbar_default_h * scale); ui_menubar_w = math_floor(ui_menubar_default_w * scale); ui_base_set_icon_scale(); base_resize(); - config_raw.layout[layout_size_t.SIDEBAR_W] = math_floor(ui_base_default_sidebar_w * scale); + config_raw.layout[layout_size_t.SIDEBAR_W] = math_floor(ui_sidebar_default_w * scale); } function box_preferences_theme_to_json(theme: ui_theme_t): string { diff --git a/paint/sources/brush_nodes/brush_output_node.ts b/paint/sources/brush_nodes/brush_output_node.ts index 7f2e59e9..380a4a02 100644 --- a/paint/sources/brush_nodes/brush_output_node.ts +++ b/paint/sources/brush_nodes/brush_output_node.ts @@ -146,8 +146,8 @@ function brush_output_node_run(self: brush_output_node_t, from: i32) { if (ui.is_hovered || base_is_dragging || base_is_resizing || - base_is_scrolling() || - base_is_combo_selected()) { + ui.is_scrolling || + ui.combo_selected_handle != null) { return; } diff --git a/paint/sources/camera.ts b/paint/sources/camera.ts index ea46de8b..adad8c98 100644 --- a/paint/sources/camera.ts +++ b/paint/sources/camera.ts @@ -64,7 +64,7 @@ function camera_update() { camera_controls_down = false; } - if (_input_occupied || !base_ui_enabled || base_is_dragging || base_is_scrolling() || base_is_combo_selected() || !camera_controls_down) { + if (_input_occupied || !base_ui_enabled || base_is_dragging || ui.is_scrolling || ui.combo_selected_handle != null || !camera_controls_down) { return; } diff --git a/paint/sources/config.ts b/paint/sources/config.ts index 54c874f9..e9865084 100644 --- a/paint/sources/config.ts +++ b/paint/sources/config.ts @@ -155,7 +155,61 @@ function config_init() { ///end config_raw.version = manifest_version; config_raw.sha = config_get_sha(); - base_init_config(); + + config_raw.recent_projects = []; + config_raw.bookmarks = []; + config_raw.plugins = []; + ///if (arm_android || arm_ios) + config_raw.keymap = "touch.json"; + ///else + config_raw.keymap = "default.json"; + ///end + config_raw.theme = "default.json"; + config_raw.server = "https://armorpaint.fra1.digitaloceanspaces.com"; + config_raw.undo_steps = 4; + config_raw.pressure_radius = true; + ///if (arm_ios || arm_linux) + config_raw.pressure_sensitivity = 1.0; + ///else + config_raw.pressure_sensitivity = 2.0; + ///end + config_raw.camera_zoom_speed = 1.0; + config_raw.camera_pan_speed = 1.0; + config_raw.camera_rotation_speed = 1.0; + config_raw.zoom_direction = zoom_direction_t.VERTICAL; + config_raw.displace_strength = 0.0; + config_raw.wrap_mouse = false; + config_raw.workspace = space_type_t.SPACE3D; + config_raw.camera_controls = camera_controls_t.ORBIT; + config_raw.layer_res = texture_res_t.RES2048; + ///if (arm_android || arm_ios) + config_raw.touch_ui = true; + config_raw.splash_screen = true; + ///else + config_raw.touch_ui = false; + config_raw.splash_screen = false; + ///end + config_raw.node_preview = true; + config_raw.pressure_hardness = true; + config_raw.pressure_angle = false; + config_raw.pressure_opacity = false; + ///if (arm_android || arm_ios) + config_raw.material_live = false; + ///else + config_raw.material_live = true; + ///end + config_raw.brush_3d = true; + config_raw.brush_depth_reject = true; + config_raw.brush_angle_reject = true; + config_raw.brush_live = false; + config_raw.show_asset_names = false; + config_raw.dilate = dilate_type_t.INSTANT; + config_raw.dilate_radius = 2; + config_raw.gpu_inference = true; + config_raw.blender = ""; + config_raw.scene_atlas_res = texture_res_t.RES8192; + config_raw.pathtrace_mode = pathtrace_mode_t.FAST; + config_raw.grid_snap = false; } else { // Upgrade config format created by older ArmorPaint build diff --git a/paint/sources/parser_exr.ts b/paint/sources/export_exr.ts similarity index 71% rename from paint/sources/parser_exr.ts rename to paint/sources/export_exr.ts index 869503a8..25746565 100644 --- a/paint/sources/parser_exr.ts +++ b/paint/sources/export_exr.ts @@ -2,49 +2,49 @@ // https://github.com/aras-p/miniexr // https://www.openexr.com/documentation/openexrfilelayout.pdf -let _parser_exr_width: i32; -let _parser_exr_stride: i32; -let _parser_exr_out: u8[]; -let _parser_exr_src_view: buffer_t; -let _parser_exr_write_line: (byte_pos: i32)=> void; +let _export_exr_width: i32; +let _export_exr_stride: i32; +let _export_exr_out: u8[]; +let _export_exr_src_view: buffer_t; +let _export_exr_write_line: (byte_pos: i32)=> void; -function parser_exr_write_string(out: u8[], str: string) { +function export_exr_write_string(out: u8[], str: string) { for (let i: i32 = 0; i < str.length; ++i) { array_push(out, char_code_at(str, i)); } } -function parser_exr_write_line16(byte_pos: i32) { - for (let x: i32 = 0; x < _parser_exr_width; ++x) { - array_push(_parser_exr_out, buffer_get_u8(_parser_exr_src_view, byte_pos )); - array_push(_parser_exr_out, buffer_get_u8(_parser_exr_src_view, byte_pos + 1)); - byte_pos += _parser_exr_stride; +function export_exr_write_line16(byte_pos: i32) { + for (let x: i32 = 0; x < _export_exr_width; ++x) { + array_push(_export_exr_out, buffer_get_u8(_export_exr_src_view, byte_pos )); + array_push(_export_exr_out, buffer_get_u8(_export_exr_src_view, byte_pos + 1)); + byte_pos += _export_exr_stride; } } -function parser_exr_write_line32(byte_pos: i32) { - for (let x: i32 = 0; x < _parser_exr_width; ++x) { - array_push(_parser_exr_out, buffer_get_u8(_parser_exr_src_view, byte_pos )); - array_push(_parser_exr_out, buffer_get_u8(_parser_exr_src_view, byte_pos + 1)); - array_push(_parser_exr_out, buffer_get_u8(_parser_exr_src_view, byte_pos + 2)); - array_push(_parser_exr_out, buffer_get_u8(_parser_exr_src_view, byte_pos + 3)); - byte_pos += _parser_exr_stride; +function export_exr_write_line32(byte_pos: i32) { + for (let x: i32 = 0; x < _export_exr_width; ++x) { + array_push(_export_exr_out, buffer_get_u8(_export_exr_src_view, byte_pos )); + array_push(_export_exr_out, buffer_get_u8(_export_exr_src_view, byte_pos + 1)); + array_push(_export_exr_out, buffer_get_u8(_export_exr_src_view, byte_pos + 2)); + array_push(_export_exr_out, buffer_get_u8(_export_exr_src_view, byte_pos + 3)); + byte_pos += _export_exr_stride; } } -function parser_exr_write_bgr(off: i32, pos: i32, byte_size: i32) { - _parser_exr_write_line(pos + byte_size * 2); - _parser_exr_write_line(pos + byte_size); - _parser_exr_write_line(pos); +function export_exr_write_bgr(off: i32, pos: i32, byte_size: i32) { + _export_exr_write_line(pos + byte_size * 2); + _export_exr_write_line(pos + byte_size); + _export_exr_write_line(pos); } -function parser_exr_write_single(off: i32, pos: i32, byte_size: i32) { - _parser_exr_write_line(pos + off * byte_size); - _parser_exr_write_line(pos + off * byte_size); - _parser_exr_write_line(pos + off * byte_size); +function export_exr_write_single(off: i32, pos: i32, byte_size: i32) { + _export_exr_write_line(pos + off * byte_size); + _export_exr_write_line(pos + off * byte_size); + _export_exr_write_line(pos + off * byte_size); } -function parser_exr_run(width: i32, height: i32, src: buffer_t, bits: i32 = 16, type: i32 = 1, off: i32 = 0): buffer_t { +function export_exr_run(width: i32, height: i32, src: buffer_t, bits: i32 = 16, type: i32 = 1, off: i32 = 0): buffer_t { let out: u8[] = []; array_push(out, 0x76); // magic array_push(out, 0x2f); @@ -54,9 +54,9 @@ function parser_exr_run(width: i32, height: i32, src: buffer_t, bits: i32 = 16, array_push(out, 0); array_push(out, 0); array_push(out, 0); - parser_exr_write_string(out, "channels"); + export_exr_write_string(out, "channels"); array_push(out, 0); - parser_exr_write_string(out, "chlist"); + export_exr_write_string(out, "chlist"); array_push(out, 0); array_push(out, 55); @@ -137,9 +137,9 @@ function parser_exr_run(width: i32, height: i32, src: buffer_t, bits: i32 = 16, array_push(out, 0); - parser_exr_write_string(out, "compression"); + export_exr_write_string(out, "compression"); array_push(out, 0); - parser_exr_write_string(out, "compression"); + export_exr_write_string(out, "compression"); array_push(out, 0); array_push(out, 1); @@ -148,9 +148,9 @@ function parser_exr_run(width: i32, height: i32, src: buffer_t, bits: i32 = 16, array_push(out, 0); array_push(out, 0); // no compression - parser_exr_write_string(out, "dataWindow"); + export_exr_write_string(out, "dataWindow"); array_push(out, 0); - parser_exr_write_string(out, "box2i"); + export_exr_write_string(out, "box2i"); array_push(out, 0); array_push(out, 16); @@ -181,9 +181,9 @@ function parser_exr_run(width: i32, height: i32, src: buffer_t, bits: i32 = 16, array_push(out, (hh >> 16) & 0xff); array_push(out, (hh >> 24) & 0xff); - parser_exr_write_string(out, "displayWindow"); + export_exr_write_string(out, "displayWindow"); array_push(out, 0); - parser_exr_write_string(out, "box2i"); + export_exr_write_string(out, "box2i"); array_push(out, 0); array_push(out, 16); @@ -211,9 +211,9 @@ function parser_exr_run(width: i32, height: i32, src: buffer_t, bits: i32 = 16, array_push(out, (hh >> 16) & 0xff); array_push(out, (hh >> 24) & 0xff); - parser_exr_write_string(out, "lineOrder"); + export_exr_write_string(out, "lineOrder"); array_push(out, 0); - parser_exr_write_string(out, "lineOrder"); + export_exr_write_string(out, "lineOrder"); array_push(out, 0); array_push(out, 1); @@ -222,9 +222,9 @@ function parser_exr_run(width: i32, height: i32, src: buffer_t, bits: i32 = 16, array_push(out, 0); array_push(out, 0); // increasing Y - parser_exr_write_string(out, "pixelAspectRatio"); + export_exr_write_string(out, "pixelAspectRatio"); array_push(out, 0); - parser_exr_write_string(out, "float"); + export_exr_write_string(out, "float"); array_push(out, 0); array_push(out, 4); @@ -237,10 +237,10 @@ function parser_exr_run(width: i32, height: i32, src: buffer_t, bits: i32 = 16, array_push(out, 0x80); array_push(out, 0x3f); - parser_exr_write_string(out, "screenWindowCenter"); + export_exr_write_string(out, "screenWindowCenter"); array_push(out, 0); - parser_exr_write_string(out, "v2f"); + export_exr_write_string(out, "v2f"); array_push(out, 0); array_push(out, 8); @@ -258,10 +258,10 @@ function parser_exr_run(width: i32, height: i32, src: buffer_t, bits: i32 = 16, array_push(out, 0); array_push(out, 0); - parser_exr_write_string(out, "screenWindowWidth"); + export_exr_write_string(out, "screenWindowWidth"); array_push(out, 0); - parser_exr_write_string(out, "float"); + export_exr_write_string(out, "float"); array_push(out, 0); array_push(out, 4); @@ -301,13 +301,13 @@ function parser_exr_run(width: i32, height: i32, src: buffer_t, bits: i32 = 16, let stride: i32 = channels * byte_size; let pos: i32 = 0; - _parser_exr_width = width; - _parser_exr_stride = stride; - _parser_exr_out = out; - _parser_exr_src_view = src; + _export_exr_width = width; + _export_exr_stride = stride; + _export_exr_out = out; + _export_exr_src_view = src; - _parser_exr_write_line = bits == 16 ? parser_exr_write_line16 : parser_exr_write_line32; - let write_data: (off: i32, pos: i32, byte_size: i32)=>void = type == 1 ? parser_exr_write_bgr : parser_exr_write_single; + _export_exr_write_line = bits == 16 ? export_exr_write_line16 : export_exr_write_line32; + let write_data: (off: i32, pos: i32, byte_size: i32)=>void = type == 1 ? export_exr_write_bgr : export_exr_write_single; for (let y: i32 = 0; y < height; ++y) { // coordinate diff --git a/paint/sources/export_texture.ts b/paint/sources/export_texture.ts index ebd4410f..30800031 100644 --- a/paint/sources/export_texture.ts +++ b/paint/sources/export_texture.ts @@ -465,7 +465,7 @@ function export_texture_write_texture(file: string, pixels: buffer_t, type: i32 iron_write_jpg(file, pixels, res_x, res_y, format, math_floor(context_raw.format_quality)); } else { // Exr - let b: buffer_t = parser_exr_run(res_x, res_y, pixels, bits, type, off); + let b: buffer_t = export_exr_run(res_x, res_y, pixels, bits, type, off); iron_file_save_bytes(file, b, b.length); } } diff --git a/paint/sources/import_mesh.ts b/paint/sources/import_mesh.ts index 3cb4c773..c5551135 100644 --- a/paint/sources/import_mesh.ts +++ b/paint/sources/import_mesh.ts @@ -201,7 +201,7 @@ function _import_mesh_add_mesh(mesh: raw_mesh_t) { let raw: mesh_data_t = import_mesh_raw_mesh(mesh); if (context_raw.tool == tool_type_t.GIZMO) { - util_mesh_ext_pack_uvs(mesh.texa); + util_mesh_pack_uvs(mesh.texa); } let md: mesh_data_t = mesh_data_create(raw); diff --git a/paint/sources/neural_nodes/brush_output_node_ext.ts b/paint/sources/neural_nodes/brush_output_node_ext.ts index 0edd9037..5a48564c 100644 --- a/paint/sources/neural_nodes/brush_output_node_ext.ts +++ b/paint/sources/neural_nodes/brush_output_node_ext.ts @@ -103,8 +103,8 @@ function brush_output_node_run(from: i32) { context_raw.paint_vec.y < 1 && !base_is_dragging && !base_is_resizing && - !base_is_scrolling() && - !base_is_combo_selected()) { + !ui.is_scrolling && + ui.combo_selected_handle == null) { let down: bool = mouse_down() || pen_down(); diff --git a/paint/sources/node_shader.ts b/paint/sources/node_shader.ts index 1fa590c5..828c449b 100644 --- a/paint/sources/node_shader.ts +++ b/paint/sources/node_shader.ts @@ -240,3 +240,134 @@ function node_shader_get(raw: node_shader_t): string { return s; } + + +type material_t = { + name?: string; + canvas?: ui_node_canvas_t; +}; + +type node_shader_context_t = { + kong?: node_shader_t; + data?: shader_context_t; + allow_vcols?: bool; + material?: material_t; +}; + +function node_shader_context_create(material: material_t, props: shader_context_t): node_shader_context_t { + let raw: node_shader_context_t = {}; + raw.material = material; + + let vertex_elements_default: vertex_element_t[] = [ + { + name: "pos", + data: "short4norm" + }, + { + name: "nor", + data: "short2norm" + } + ]; + + raw.data = { + name: props.name, + depth_write: props.depth_write, + compare_mode: props.compare_mode, + cull_mode: props.cull_mode, + blend_source: props.blend_source, + blend_destination: props.blend_destination, + alpha_blend_source: props.alpha_blend_source, + alpha_blend_destination: props.alpha_blend_destination, + fragment_shader: "", + vertex_shader: "", + vertex_elements: props.vertex_elements != null ? props.vertex_elements : vertex_elements_default, + color_attachments: props.color_attachments, + depth_attachment: props.depth_attachment + }; + + let rw: shader_context_t = raw.data; + rw._ = {}; + + if (props.color_writes_red != null) { + raw.data.color_writes_red = props.color_writes_red; + } + if (props.color_writes_green != null) { + raw.data.color_writes_green = props.color_writes_green; + } + if (props.color_writes_blue != null) { + raw.data.color_writes_blue = props.color_writes_blue; + } + if (props.color_writes_alpha != null) { + raw.data.color_writes_alpha = props.color_writes_alpha; + } + + raw.data.texture_units = []; + raw.data.constants = []; + return raw; +} + +function node_shader_context_add_elem(raw: node_shader_context_t, name: string, data_type: string) { + for (let i: i32 = 0; i < raw.data.vertex_elements.length; ++i) { + let e: vertex_element_t = raw.data.vertex_elements[i]; + if (e.name == name) { + return; + } + } + let elem: vertex_element_t = { name: name, data: data_type }; + array_push(raw.data.vertex_elements, elem); +} + +function node_shader_context_is_elem(raw: node_shader_context_t, name: string): bool { + for (let i: i32 = 0; i < raw.data.vertex_elements.length; ++i) { + let elem: vertex_element_t = raw.data.vertex_elements[i]; + if (elem.name == name) { + return true; + } + } + return false; +} + +function node_shader_context_get_elem(raw: node_shader_context_t, name: string): vertex_element_t { + for (let i: i32 = 0; i < raw.data.vertex_elements.length; ++i) { + let elem: vertex_element_t = raw.data.vertex_elements[i]; + if (elem.name == name) { + return elem; + } + } + return null; +} + +function node_shader_context_add_constant(raw: node_shader_context_t, ctype: string, name: string, link: string = null) { + for (let i: i32 = 0; i < raw.data.constants.length; ++i) { + let c: shader_const_t = raw.data.constants[i]; + if (c.name == name) { + return; + } + } + + let c: shader_const_t = { name: name, type: ctype }; + if (link != null) { + c.link = link; + } + let consts: shader_const_t[] = raw.data.constants; + array_push(consts, c); +} + +function node_shader_context_add_texture_unit(raw: node_shader_context_t, name: string, link: string = null) { + for (let i: i32 = 0; i < raw.data.texture_units.length; ++i) { + let c: tex_unit_t = raw.data.texture_units[i]; + if (c.name == name) { + return; + } + } + + let c: tex_unit_t = { name: name, link: link }; + array_push(raw.data.texture_units, c); +} + +function node_shader_context_make_kong(raw: node_shader_context_t): node_shader_t { + raw.data.vertex_shader = raw.material.name + "_" + raw.data.name + ".vert"; + raw.data.fragment_shader = raw.material.name + "_" + raw.data.name + ".frag"; + raw.kong = node_shader_create(raw); + return raw.kong; +} diff --git a/paint/sources/node_shader_context.ts b/paint/sources/node_shader_context.ts deleted file mode 100644 index b5fe2fe0..00000000 --- a/paint/sources/node_shader_context.ts +++ /dev/null @@ -1,130 +0,0 @@ - -type material_t = { - name?: string; - canvas?: ui_node_canvas_t; -}; - -type node_shader_context_t = { - kong?: node_shader_t; - data?: shader_context_t; - allow_vcols?: bool; - material?: material_t; -}; - -function node_shader_context_create(material: material_t, props: shader_context_t): node_shader_context_t { - let raw: node_shader_context_t = {}; - raw.material = material; - - let vertex_elements_default: vertex_element_t[] = [ - { - name: "pos", - data: "short4norm" - }, - { - name: "nor", - data: "short2norm" - } - ]; - - raw.data = { - name: props.name, - depth_write: props.depth_write, - compare_mode: props.compare_mode, - cull_mode: props.cull_mode, - blend_source: props.blend_source, - blend_destination: props.blend_destination, - alpha_blend_source: props.alpha_blend_source, - alpha_blend_destination: props.alpha_blend_destination, - fragment_shader: "", - vertex_shader: "", - vertex_elements: props.vertex_elements != null ? props.vertex_elements : vertex_elements_default, - color_attachments: props.color_attachments, - depth_attachment: props.depth_attachment - }; - - let rw: shader_context_t = raw.data; - rw._ = {}; - - if (props.color_writes_red != null) { - raw.data.color_writes_red = props.color_writes_red; - } - if (props.color_writes_green != null) { - raw.data.color_writes_green = props.color_writes_green; - } - if (props.color_writes_blue != null) { - raw.data.color_writes_blue = props.color_writes_blue; - } - if (props.color_writes_alpha != null) { - raw.data.color_writes_alpha = props.color_writes_alpha; - } - - raw.data.texture_units = []; - raw.data.constants = []; - return raw; -} - -function node_shader_context_add_elem(raw: node_shader_context_t, name: string, data_type: string) { - for (let i: i32 = 0; i < raw.data.vertex_elements.length; ++i) { - let e: vertex_element_t = raw.data.vertex_elements[i]; - if (e.name == name) { - return; - } - } - let elem: vertex_element_t = { name: name, data: data_type }; - array_push(raw.data.vertex_elements, elem); -} - -function node_shader_context_is_elem(raw: node_shader_context_t, name: string): bool { - for (let i: i32 = 0; i < raw.data.vertex_elements.length; ++i) { - let elem: vertex_element_t = raw.data.vertex_elements[i]; - if (elem.name == name) { - return true; - } - } - return false; -} - -function node_shader_context_get_elem(raw: node_shader_context_t, name: string): vertex_element_t { - for (let i: i32 = 0; i < raw.data.vertex_elements.length; ++i) { - let elem: vertex_element_t = raw.data.vertex_elements[i]; - if (elem.name == name) { - return elem; - } - } - return null; -} - -function node_shader_context_add_constant(raw: node_shader_context_t, ctype: string, name: string, link: string = null) { - for (let i: i32 = 0; i < raw.data.constants.length; ++i) { - let c: shader_const_t = raw.data.constants[i]; - if (c.name == name) { - return; - } - } - - let c: shader_const_t = { name: name, type: ctype }; - if (link != null) { - c.link = link; - } - let consts: shader_const_t[] = raw.data.constants; - array_push(consts, c); -} - -function node_shader_context_add_texture_unit(raw: node_shader_context_t, name: string, link: string = null) { - for (let i: i32 = 0; i < raw.data.texture_units.length; ++i) { - let c: tex_unit_t = raw.data.texture_units[i]; - if (c.name == name) { - return; - } - } - - let c: tex_unit_t = { name: name, link: link }; - array_push(raw.data.texture_units, c); -} - -function node_shader_context_make_kong(raw: node_shader_context_t): node_shader_t { - raw.data.vertex_shader = raw.material.name + "_" + raw.data.name + ".vert"; - raw.data.fragment_shader = raw.material.name + "_" + raw.data.name + ".frag"; - raw.kong = node_shader_create(raw); - return raw.kong; -} diff --git a/paint/sources/sim.ts b/paint/sources/physics_sim.ts similarity index 100% rename from paint/sources/sim.ts rename to paint/sources/physics_sim.ts diff --git a/paint/sources/tab_browser.ts b/paint/sources/tab_browser.ts index 804a9d15..b79063e9 100644 --- a/paint/sources/tab_browser.ts +++ b/paint/sources/tab_browser.ts @@ -15,7 +15,7 @@ function tab_browser_show_directory(directory: string) { function tab_browser_draw(htab: ui_handle_t) { let statush: i32 = config_raw.layout[layout_size_t.STATUS_H]; - if (ui_tab(htab, tr("Browser")) && statush > ui_status_default_status_h * UI_SCALE()) { + if (ui_tab(htab, tr("Browser")) && statush > ui_statusbar_default_h * UI_SCALE()) { if (config_raw.bookmarks == null) { config_raw.bookmarks = []; diff --git a/paint/sources/tab_console.ts b/paint/sources/tab_console.ts index 6b67d1c3..4858b6f9 100644 --- a/paint/sources/tab_console.ts +++ b/paint/sources/tab_console.ts @@ -4,7 +4,7 @@ function tab_console_draw(htab: ui_handle_t) { let color: i32 = console_message_timer > 0 ? console_message_color : -1; let statush: i32 = config_raw.layout[layout_size_t.STATUS_H]; - if (ui_tab(htab, title, false, color) && statush > ui_status_default_status_h * UI_SCALE()) { + if (ui_tab(htab, title, false, color) && statush > ui_statusbar_default_h * UI_SCALE()) { ui_begin_sticky(); ///if (arm_windows || arm_linux || arm_macos) // Copy diff --git a/paint/sources/tab_fonts.ts b/paint/sources/tab_fonts.ts index 685c79ec..66250e5f 100644 --- a/paint/sources/tab_fonts.ts +++ b/paint/sources/tab_fonts.ts @@ -3,7 +3,7 @@ let _tab_fonts_draw_i: i32; function tab_fonts_draw(htab: ui_handle_t) { let statush: i32 = config_raw.layout[layout_size_t.STATUS_H]; - if (ui_tab(htab, tr("Fonts")) && statush > ui_status_default_status_h * UI_SCALE()) { + if (ui_tab(htab, tr("Fonts")) && statush > ui_statusbar_default_h * UI_SCALE()) { ui_begin_sticky(); if (config_raw.touch_ui) { diff --git a/paint/sources/tab_layers.ts b/paint/sources/tab_layers.ts index f3ea0a8c..5b1c2e89 100644 --- a/paint/sources/tab_layers.ts +++ b/paint/sources/tab_layers.ts @@ -6,7 +6,7 @@ let tab_layers_l: slot_layer_t; let tab_layers_mini: bool; function tab_layers_draw(htab: ui_handle_t) { - let mini: bool = config_raw.layout[layout_size_t.SIDEBAR_W] <= ui_base_sidebar_mini_w; + let mini: bool = config_raw.layout[layout_size_t.SIDEBAR_W] <= ui_sidebar_w_mini; mini ? tab_layers_draw_mini(htab) : tab_layers_draw_full(htab); } @@ -14,7 +14,7 @@ function tab_layers_draw_mini(htab: ui_handle_t) { ui_set_hovered_tab_name(tr("Layers")); let _ELEMENT_H: i32 = ui.ops.theme.ELEMENT_H; - ui.ops.theme.ELEMENT_H = math_floor(ui_base_sidebar_mini_w / 2 / UI_SCALE()); + ui.ops.theme.ELEMENT_H = math_floor(ui_sidebar_w_mini / 2 / UI_SCALE()); ui_begin_sticky(); ui_separator(5); diff --git a/paint/sources/tab_materials.ts b/paint/sources/tab_materials.ts index 53ac7d53..36e35321 100644 --- a/paint/sources/tab_materials.ts +++ b/paint/sources/tab_materials.ts @@ -2,7 +2,7 @@ let _tab_materials_draw_slots: i32; function tab_materials_draw(htab: ui_handle_t) { - let mini: bool = config_raw.layout[layout_size_t.SIDEBAR_W] <= ui_base_sidebar_mini_w; + let mini: bool = config_raw.layout[layout_size_t.SIDEBAR_W] <= ui_sidebar_w_mini; mini ? tab_materials_draw_mini(htab) : tab_materials_draw_full(htab); } @@ -104,7 +104,7 @@ function tab_materials_draw_slots(mini: bool) { let uix: f32 = ui._x; let uiy: f32 = ui._y; let tile: i32 = UI_SCALE() > 1 ? 100 : 50; - let imgh: f32 = mini ? ui_base_default_sidebar_mini_w * 0.85 * UI_SCALE() : -1.0; + let imgh: f32 = mini ? ui_sidebar_default_w_mini * 0.85 * UI_SCALE() : -1.0; let state: ui_state_t = project_materials[i].preview_ready ? ui_image(img, 0xffffffff, imgh) : ui_sub_image(resource_get("icons.k"), 0xffffffff, -1.0, tile, tile, tile, tile); diff --git a/paint/sources/tab_meshes.ts b/paint/sources/tab_meshes.ts index 8e19c81a..7a925bf8 100644 --- a/paint/sources/tab_meshes.ts +++ b/paint/sources/tab_meshes.ts @@ -3,7 +3,7 @@ let _tab_meshes_draw_i: i32; function tab_meshes_draw(htab: ui_handle_t) { let statush: i32 = config_raw.layout[layout_size_t.STATUS_H]; - if (ui_tab(htab, tr("Meshes")) && statush > ui_status_default_status_h * UI_SCALE()) { + if (ui_tab(htab, tr("Meshes")) && statush > ui_statusbar_default_h * UI_SCALE()) { ui_begin_sticky(); @@ -347,7 +347,7 @@ function tab_meshes_draw(htab: ui_handle_t) { function tab_meshes_append_shape(mesh_name: string) { let blob: buffer_t = iron_load_blob(data_path() + "meshes/" + mesh_name + ".arm"); let raw: scene_t = armpack_decode(blob); - util_mesh_ext_pack_uvs(raw.mesh_datas[0].vertex_arrays[2].values); + util_mesh_pack_uvs(raw.mesh_datas[0].vertex_arrays[2].values); let md: mesh_data_t = mesh_data_create(raw.mesh_datas[0]); md._.handle = md.name; let mo: mesh_object_t = scene_add_mesh_object(md, project_paint_objects[0].material); diff --git a/paint/sources/tab_swatches.ts b/paint/sources/tab_swatches.ts index 1b4ca8c9..55925625 100644 --- a/paint/sources/tab_swatches.ts +++ b/paint/sources/tab_swatches.ts @@ -21,7 +21,7 @@ function tab_swatches_empty_get(): gpu_texture_t { function tab_swatches_draw(htab: ui_handle_t) { let statush: i32 = config_raw.layout[layout_size_t.STATUS_H]; - if (ui_tab(htab, tr("Swatches")) && statush > ui_status_default_status_h * UI_SCALE()) { + if (ui_tab(htab, tr("Swatches")) && statush > ui_statusbar_default_h * UI_SCALE()) { ui_begin_sticky(); if (config_raw.touch_ui) { diff --git a/paint/sources/tab_textures.ts b/paint/sources/tab_textures.ts index c131a396..fef1cb12 100644 --- a/paint/sources/tab_textures.ts +++ b/paint/sources/tab_textures.ts @@ -7,7 +7,7 @@ let _tab_textures_draw_is_packed: bool; function tab_textures_draw(htab: ui_handle_t) { let statush: i32 = config_raw.layout[layout_size_t.STATUS_H]; - if (ui_tab(htab, tr("Textures")) && statush > ui_status_default_status_h * UI_SCALE()) { + if (ui_tab(htab, tr("Textures")) && statush > ui_statusbar_default_h * UI_SCALE()) { ui_begin_sticky(); diff --git a/paint/sources/ui_base.ts b/paint/sources/ui_base.ts deleted file mode 100644 index 7620c324..00000000 --- a/paint/sources/ui_base.ts +++ /dev/null @@ -1,1437 +0,0 @@ - -type tab_draw_t = { - f: (h: ui_handle_t)=>void; -}; -type tab_draw_array_t = tab_draw_t[]; - -let ui: ui_t; -let ui_base_show: bool = true; -let ui_base_border_started: i32 = 0; -let ui_base_border_handle: ui_handle_t = null; -let ui_base_action_paint_remap: string = ""; -let ui_base_operator_search_offset: i32 = 0; -let ui_base_undo_tap_time: f32 = 0.0; -let ui_base_redo_tap_time: f32 = 0.0; -let ui_base_hwnds: ui_handle_t[] = ui_base_init_hwnds(); -let ui_base_htabs: ui_handle_t[] = ui_base_init_htabs(); -let ui_base_hwnd_tabs: tab_draw_array_t[] = ui_base_init_hwnd_tabs(); -let ui_base_viewport_col: i32; -let ui_base_default_sidebar_mini_w: i32 = 56; -let ui_base_default_sidebar_full_w: i32 = 280; - -///if (arm_android || arm_ios) -let ui_base_default_sidebar_w: i32 = ui_base_default_sidebar_mini_w; -///else -let ui_base_default_sidebar_w: i32 = ui_base_default_sidebar_full_w; -///end - -let ui_base_tabx: i32 = 0; -let ui_base_hminimized: ui_handle_t = ui_handle_create(); -let ui_base_sidebar_mini_w: i32 = ui_base_default_sidebar_mini_w; -let _ui_base_operator_search_first: bool; - -function ui_base_init_hwnds(): ui_handle_t[] { - let hwnds: ui_handle_t[] = [ui_handle_create(), ui_handle_create(), ui_handle_create()]; - return hwnds; -} - -function ui_base_init_htabs(): ui_handle_t[] { - let htabs: ui_handle_t[] = [ui_handle_create(), ui_handle_create(), ui_handle_create()]; - return htabs; -} - -function _draw_callback_create(f: (h: ui_handle_t)=>void): tab_draw_t { - let cb: tab_draw_t = { f: f }; - return cb; -} - -function ui_base_init_hwnd_tabs(): tab_draw_array_t[] { - let a0: tab_draw_array_t = [ - _draw_callback_create(tab_layers_draw), - _draw_callback_create(tab_history_draw), - _draw_callback_create(tab_plugins_draw) - ]; - let a1: tab_draw_array_t = [ - _draw_callback_create(tab_materials_draw), - _draw_callback_create(tab_brushes_draw), - _draw_callback_create(tab_scripts_draw) - - ]; - let a2: tab_draw_array_t = [ - _draw_callback_create(tab_browser_draw), - _draw_callback_create(tab_meshes_draw), - _draw_callback_create(tab_textures_draw), - _draw_callback_create(tab_fonts_draw), - _draw_callback_create(tab_swatches_draw), - _draw_callback_create(tab_console_draw), - _draw_callback_create(ui_status_draw_version_tab) - ]; - - let r: tab_draw_array_t[] = []; - array_push(r, a0); - array_push(r, a1); - array_push(r, a2); - return r; -} - -function ui_base_init() { - ui_toolbar_init(); - context_raw.text_tool_text = tr("Text"); - ui_header_init(); - ui_status_init(); - ui_menubar_init(); - - ui_header_h = math_floor(ui_header_default_h * config_raw.window_scale); - ui_menubar_w = math_floor(ui_menubar_default_w * config_raw.window_scale); - - if (context_raw.empty_envmap == null) { - ui_base_make_empty_envmap(base_theme.VIEWPORT_COL); - } - if (context_raw.preview_envmap == null) { - let b: u8_array_t = u8_array_create(4); - b[0] = 0; - b[1] = 0; - b[2] = 0; - b[3] = 255; - context_raw.preview_envmap = gpu_create_texture_from_bytes(b, 1, 1); - } - - if (context_raw.saved_envmap == null) { - // raw.saved_envmap = scene_world._envmap; - context_raw.default_irradiance = scene_world._.irradiance; - context_raw.default_radiance = scene_world._.radiance; - context_raw.default_radiance_mipmaps = scene_world._.radiance_mipmaps; - } - scene_world._.envmap = context_raw.show_envmap ? context_raw.saved_envmap : context_raw.empty_envmap; - context_raw.ddirty = 1; - - let resources: string[] = ["cursor.k", "icons.k"]; - resource_load(resources); - - let scale: f32 = config_raw.window_scale; - let ops: ui_options_t = { - theme: base_theme, - font: base_font, - scale_factor: scale, - color_wheel: base_color_wheel, - black_white_gradient: base_color_wheel_gradient - }; - ui = ui_create(ops); - ui_on_border_hover = ui_base_on_border_hover; - ui_on_tab_drop = ui_base_on_tab_drop; - if (UI_SCALE() > 1) { - ui_base_set_icon_scale(); - } - - context_raw.gizmo = scene_get_child(".Gizmo"); - context_raw.gizmo_translate_x = object_get_child(context_raw.gizmo, ".TranslateX"); - context_raw.gizmo_translate_y = object_get_child(context_raw.gizmo, ".TranslateY"); - context_raw.gizmo_translate_z = object_get_child(context_raw.gizmo, ".TranslateZ"); - context_raw.gizmo_scale_x = object_get_child(context_raw.gizmo, ".ScaleX"); - context_raw.gizmo_scale_y = object_get_child(context_raw.gizmo, ".ScaleY"); - context_raw.gizmo_scale_z = object_get_child(context_raw.gizmo, ".ScaleZ"); - context_raw.gizmo_rotate_x = object_get_child(context_raw.gizmo, ".RotateX"); - context_raw.gizmo_rotate_y = object_get_child(context_raw.gizmo, ".RotateY"); - context_raw.gizmo_rotate_z = object_get_child(context_raw.gizmo, ".RotateZ"); - - project_new(false); - - if (project_filepath == "") { - sys_notify_on_next_frame(layers_init); - } - - context_raw.project_objects = []; - for (let i: i32 = 0; i < scene_meshes.length; ++i) { - let m: mesh_object_t = scene_meshes[i]; - array_push(context_raw.project_objects, m); - } - - operator_register("view_top", ui_base_view_top); -} - -function ui_base_update() { - ui_base_update_ui(); - operator_update(); - - let keys: string[] = map_keys(plugin_map); - for (let i: i32 = 0; i < keys.length; ++i) { - let p: plugin_t = map_get(plugin_map, keys[i]); - if (p.on_update != null) { - js_call(p.on_update); - } - } - - if (!base_ui_enabled) { - return; - } - - if (!ui.is_typing) { - if (operator_shortcut(map_get(config_keymap, "toggle_node_editor"))) { - ui_nodes_canvas_type == canvas_type_t.MATERIAL ? ui_base_show_material_nodes() : ui_base_show_brush_nodes(); - } - else if (operator_shortcut(map_get(config_keymap, "toggle_browser"))) { - ui_base_toggle_browser(); - } - - else if (operator_shortcut(map_get(config_keymap, "toggle_2d_view"))) { - ui_base_show_2d_view(view_2d_type_t.LAYER); - } - } - - if (operator_shortcut(map_get(config_keymap, "file_save_as"))) { - project_save_as(); - } - else if (operator_shortcut(map_get(config_keymap, "file_save"))) { - project_save(); - } - else if (operator_shortcut(map_get(config_keymap, "file_open"))) { - project_open(); - } - else if (operator_shortcut(map_get(config_keymap, "file_open_recent"))) { - box_projects_show(); - } - else if (operator_shortcut(map_get(config_keymap, "file_reimport_mesh"))) { - project_reimport_mesh(); - } - else if (operator_shortcut(map_get(config_keymap, "file_reimport_textures"))) { - project_reimport_textures(); - } - else if (operator_shortcut(map_get(config_keymap, "file_new"))) { - project_new_box(); - } - else if (operator_shortcut(map_get(config_keymap, "file_export_textures"))) { - if (context_raw.texture_export_path == "") { // First export, ask for path - context_raw.layers_export = export_mode_t.VISIBLE; - box_export_show_textures(); - } - else { - sys_notify_on_next_frame(function () { - export_texture_run(context_raw.texture_export_path); - }); - } - } - else if (operator_shortcut(map_get(config_keymap, "file_export_textures_as"))) { - context_raw.layers_export = export_mode_t.VISIBLE; - box_export_show_textures(); - } - else if (operator_shortcut(map_get(config_keymap, "file_import_assets"))) { - project_import_asset(); - } - else if (operator_shortcut(map_get(config_keymap, "edit_prefs"))) { - box_preferences_show(); - } - - if (keyboard_started(map_get(config_keymap, "view_distract_free")) || (keyboard_started("escape") && !ui_base_show && !ui_box_show)) { - ui_base_toggle_distract_free(); - } - - ///if arm_linux - if (operator_shortcut("alt+enter", shortcut_type_t.STARTED)) { - base_toggle_fullscreen(); - } - ///end - - let decal: bool = context_is_decal(); - let decal_mask: bool = context_is_decal_mask(); - - if ((context_raw.brush_can_lock || context_raw.brush_locked) && mouse_moved) { - if (operator_shortcut(map_get(config_keymap, "brush_radius"), shortcut_type_t.DOWN) || - operator_shortcut(map_get(config_keymap, "brush_opacity"), shortcut_type_t.DOWN) || - operator_shortcut(map_get(config_keymap, "brush_angle"), shortcut_type_t.DOWN) || - (decal_mask && operator_shortcut(map_get(config_keymap, "decal_mask") + "+" + map_get(config_keymap, "brush_radius"), shortcut_type_t.DOWN))) { - if (context_raw.brush_locked) { - if (operator_shortcut(map_get(config_keymap, "brush_opacity"), shortcut_type_t.DOWN)) { - context_raw.brush_opacity += mouse_movement_x / 500; - context_raw.brush_opacity = math_max(0.0, math_min(1.0, context_raw.brush_opacity)); - context_raw.brush_opacity = math_round(context_raw.brush_opacity * 100) / 100; - context_raw.brush_opacity_handle.value = context_raw.brush_opacity; - } - else if (operator_shortcut(map_get(config_keymap, "brush_angle"), shortcut_type_t.DOWN)) { - context_raw.brush_angle += mouse_movement_x / 5; - let i: i32 = math_floor(context_raw.brush_angle); - context_raw.brush_angle = i % 360; - if (context_raw.brush_angle < 0) context_raw.brush_angle += 360; - context_raw.brush_angle_handle.value = context_raw.brush_angle; - make_material_parse_paint_material(); - } - else if (decal_mask && operator_shortcut(map_get(config_keymap, "decal_mask") + "+" + map_get(config_keymap, "brush_radius"), shortcut_type_t.DOWN)) { - context_raw.brush_decal_mask_radius += mouse_movement_x / 150; - context_raw.brush_decal_mask_radius = math_max(0.01, math_min(4.0, context_raw.brush_decal_mask_radius)); - context_raw.brush_decal_mask_radius = math_round(context_raw.brush_decal_mask_radius * 100) / 100; - context_raw.brush_decal_mask_radius_handle.value = context_raw.brush_decal_mask_radius; - } - else { - context_raw.brush_radius += mouse_movement_x / 150; - context_raw.brush_radius = math_max(0.01, math_min(4.0, context_raw.brush_radius)); - context_raw.brush_radius = math_round(context_raw.brush_radius * 100) / 100; - context_raw.brush_radius_handle.value = context_raw.brush_radius; - } - ui_header_handle.redraws = 2; - } - else if (context_raw.brush_can_lock) { - context_raw.brush_can_lock = false; - context_raw.brush_locked = true; - } - } - } - - let is_typing: bool = ui.is_typing; - - if (!is_typing) { - if (operator_shortcut(map_get(config_keymap, "select_material"), shortcut_type_t.DOWN)) { - ui_base_hwnds[tab_area_t.SIDEBAR1].redraws = 2; - for (let i: i32 = 1; i < 10; ++i) { - if (keyboard_started(i + "")) { - context_select_material(i - 1); - } - } - } - else if (operator_shortcut(map_get(config_keymap, "select_layer"), shortcut_type_t.DOWN)) { - ui_base_hwnds[tab_area_t.SIDEBAR0].redraws = 2; - for (let i: i32 = 1; i < 10; ++i) { - if (keyboard_started(i + "")) { - context_select_layer(i - 1); - } - } - } - } - - // Viewport shortcuts - if (context_in_paint_area() && !is_typing) { - - if (!mouse_down("right")) { // Fly mode off - if (operator_shortcut(map_get(config_keymap, "tool_brush"))) { - context_select_tool(tool_type_t.BRUSH); - } - else if (operator_shortcut(map_get(config_keymap, "tool_eraser"))) { - context_select_tool(tool_type_t.ERASER); - } - else if (operator_shortcut(map_get(config_keymap, "tool_fill"))) { - context_select_tool(tool_type_t.FILL); - } - else if (operator_shortcut(map_get(config_keymap, "tool_colorid"))) { - context_select_tool(tool_type_t.COLORID); - } - else if (operator_shortcut(map_get(config_keymap, "tool_decal"))) { - context_select_tool(tool_type_t.DECAL); - } - else if (operator_shortcut(map_get(config_keymap, "tool_text"))) { - context_select_tool(tool_type_t.TEXT); - } - else if (operator_shortcut(map_get(config_keymap, "tool_clone"))) { - context_select_tool(tool_type_t.CLONE); - } - else if (operator_shortcut(map_get(config_keymap, "tool_blur"))) { - context_select_tool(tool_type_t.BLUR); - } - else if (operator_shortcut(map_get(config_keymap, "tool_smudge"))) { - context_select_tool(tool_type_t.SMUDGE); - } - else if (operator_shortcut(map_get(config_keymap, "tool_particle"))) { - context_select_tool(tool_type_t.PARTICLE); - } - else if (operator_shortcut(map_get(config_keymap, "tool_picker"))) { - context_select_tool(tool_type_t.PICKER); - } - else if (operator_shortcut(map_get(config_keymap, "tool_bake"))) { - context_select_tool(tool_type_t.BAKE); - } - else if (operator_shortcut(map_get(config_keymap, "tool_gizmo"))) { - context_select_tool(tool_type_t.GIZMO); - } - else if (operator_shortcut(map_get(config_keymap, "tool_material"))) { - context_select_tool(tool_type_t.MATERIAL); - } - else if (operator_shortcut(map_get(config_keymap, "swap_brush_eraser"))) { - context_select_tool(context_raw.tool == tool_type_t.BRUSH ? tool_type_t.ERASER : tool_type_t.BRUSH); - } - } - - // Radius - if (context_raw.tool == tool_type_t.BRUSH || - context_raw.tool == tool_type_t.ERASER || - context_raw.tool == tool_type_t.DECAL || - context_raw.tool == tool_type_t.TEXT || - context_raw.tool == tool_type_t.CLONE || - context_raw.tool == tool_type_t.BLUR || - context_raw.tool == tool_type_t.SMUDGE || - context_raw.tool == tool_type_t.PARTICLE) { - if (operator_shortcut(map_get(config_keymap, "brush_radius")) || - operator_shortcut(map_get(config_keymap, "brush_opacity")) || - operator_shortcut(map_get(config_keymap, "brush_angle")) || - (decal_mask && operator_shortcut(map_get(config_keymap, "decal_mask") + "+" + map_get(config_keymap, "brush_radius")))) { - context_raw.brush_can_lock = true; - if (!pen_connected) { - mouse_lock(); - } - context_raw.lock_started_x = mouse_x; - context_raw.lock_started_y = mouse_y; - } - else if (operator_shortcut(map_get(config_keymap, "brush_radius_decrease"), shortcut_type_t.REPEAT)) { - context_raw.brush_radius -= ui_base_get_radius_increment(); - context_raw.brush_radius = math_max(math_round(context_raw.brush_radius * 100) / 100, 0.01); - context_raw.brush_radius_handle.value = context_raw.brush_radius; - ui_header_handle.redraws = 2; - } - else if (operator_shortcut(map_get(config_keymap, "brush_radius_increase"), shortcut_type_t.REPEAT)) { - context_raw.brush_radius += ui_base_get_radius_increment(); - context_raw.brush_radius = math_round(context_raw.brush_radius * 100) / 100; - context_raw.brush_radius_handle.value = context_raw.brush_radius; - ui_header_handle.redraws = 2; - } - else if (decal_mask) { - if (operator_shortcut(map_get(config_keymap, "decal_mask") + "+" + map_get(config_keymap, "brush_radius_decrease"), shortcut_type_t.REPEAT)) { - context_raw.brush_decal_mask_radius -= ui_base_get_radius_increment(); - context_raw.brush_decal_mask_radius = math_max(math_round(context_raw.brush_decal_mask_radius * 100) / 100, 0.01); - context_raw.brush_decal_mask_radius_handle.value = context_raw.brush_decal_mask_radius; - ui_header_handle.redraws = 2; - } - else if (operator_shortcut(map_get(config_keymap, "decal_mask") + "+" + map_get(config_keymap, "brush_radius_increase"), shortcut_type_t.REPEAT)) { - context_raw.brush_decal_mask_radius += ui_base_get_radius_increment(); - context_raw.brush_decal_mask_radius = math_round(context_raw.brush_decal_mask_radius * 100) / 100; - context_raw.brush_decal_mask_radius_handle.value = context_raw.brush_decal_mask_radius; - ui_header_handle.redraws = 2; - } - } - } - - if (decal_mask && (operator_shortcut(map_get(config_keymap, "decal_mask"), shortcut_type_t.STARTED) || operator_shortcut(map_get(config_keymap, "decal_mask"), shortcut_type_t.RELEASED))) { - ui_header_handle.redraws = 2; - } - - // Viewpoint - if (mouse_view_x() < sys_w()) { - if (operator_shortcut(map_get(config_keymap, "view_reset"))) { - viewport_reset(); - viewport_scale_to_bounds(); - } - else if (operator_shortcut(map_get(config_keymap, "view_back"))) { - viewport_set_view(0, 1, 0, math_pi() / 2, 0, math_pi()); - } - else if (operator_shortcut(map_get(config_keymap, "view_front"))) { - viewport_set_view(0, -1, 0, math_pi() / 2, 0, 0); - } - else if (operator_shortcut(map_get(config_keymap, "view_left"))) { - viewport_set_view(-1, 0, 0, math_pi() / 2, 0, -math_pi() / 2); - } - else if (operator_shortcut(map_get(config_keymap, "view_right"))) { - viewport_set_view(1, 0, 0, math_pi() / 2, 0, math_pi() / 2); - } - else if (operator_shortcut(map_get(config_keymap, "view_bottom"))) { - viewport_set_view(0, 0, -1, math_pi(), 0, math_pi()); - } - else if (operator_shortcut(map_get(config_keymap, "view_camera_type"))) { - context_raw.camera_type = context_raw.camera_type == camera_type_t.PERSPECTIVE ? camera_type_t.ORTHOGRAPHIC : camera_type_t.PERSPECTIVE; - context_raw.cam_handle.position = context_raw.camera_type; - viewport_update_camera_type(context_raw.camera_type); - } - else if (operator_shortcut(map_get(config_keymap, "view_orbit_left"), shortcut_type_t.REPEAT)) { - viewport_orbit(-math_pi() / 12, 0); - } - else if (operator_shortcut(map_get(config_keymap, "view_orbit_right"), shortcut_type_t.REPEAT)) { - viewport_orbit(math_pi() / 12, 0); - } - else if (operator_shortcut(map_get(config_keymap, "view_orbit_up"), shortcut_type_t.REPEAT)) { - viewport_orbit(0, -math_pi() / 12); - } - else if (operator_shortcut(map_get(config_keymap, "view_orbit_down"), shortcut_type_t.REPEAT)) { - viewport_orbit(0, math_pi() / 12); - } - else if (operator_shortcut(map_get(config_keymap, "view_orbit_opposite"))) { - viewport_orbit_opposite(); - } - else if (operator_shortcut(map_get(config_keymap, "view_zoom_in"), shortcut_type_t.REPEAT)) { - viewport_zoom(0.2); - } - else if (operator_shortcut(map_get(config_keymap, "view_zoom_out"), shortcut_type_t.REPEAT)) { - viewport_zoom(-0.2); - } - else if (operator_shortcut(map_get(config_keymap, "viewport_mode"))) { - ui.is_key_pressed = false; - ui_menu_draw(function () { - let mode_handle: ui_handle_t = ui_handle(__ID__); - mode_handle.position = context_raw.viewport_mode; - ui_text(tr("Viewport Mode"), ui_align_t.RIGHT); - let modes: string[] = [ - tr("Lit"), - tr("Base Color"), - tr("Normal"), - tr("Occlusion"), - tr("Roughness"), - tr("Metallic"), - tr("Opacity"), - tr("Height"), - tr("Emission"), - tr("Subsurface"), - tr("TexCoord"), - tr("Object Normal"), - tr("Material ID"), - tr("Object ID"), - tr("Mask") - ]; - - 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) { - ui_radio(mode_handle, i, modes[i], shortcuts[i]); - } - - let index: i32 = array_index_of(shortcuts, keyboard_key_code(ui.key_code)); - if (ui.is_key_pressed && index != -1) { - mode_handle.position = index; - ui.changed = true; - context_set_viewport_mode(mode_handle.position); - } - else if (mode_handle.changed) { - context_set_viewport_mode(mode_handle.position); - ui.changed = true; - } - }); - } - } - - if (operator_shortcut(map_get(config_keymap, "operator_search"))) { - ui_base_operator_search(); - } - } - - if (context_raw.brush_can_lock || context_raw.brush_locked) { - if (mouse_moved && context_raw.brush_can_unlock) { - context_raw.brush_locked = false; - context_raw.brush_can_unlock = false; - } - - let b: bool = (context_raw.brush_can_lock || context_raw.brush_locked) && - !operator_shortcut(map_get(config_keymap, "brush_radius"), shortcut_type_t.DOWN) && - !operator_shortcut(map_get(config_keymap, "brush_opacity"), shortcut_type_t.DOWN) && - !operator_shortcut(map_get(config_keymap, "brush_angle"), shortcut_type_t.DOWN) && - !(decal_mask && operator_shortcut(map_get(config_keymap, "decal_mask") + "+" + map_get(config_keymap, "brush_radius"), shortcut_type_t.DOWN)); - - if (b) { - mouse_unlock(); - context_raw.last_paint_x = -1; - context_raw.last_paint_y = -1; - if (context_raw.brush_can_lock) { - context_raw.brush_can_lock = false; - context_raw.brush_can_unlock = false; - context_raw.brush_locked = false; - } - else { - context_raw.brush_can_unlock = true; - } - } - } - - if (ui_base_border_handle != null) { - if (ui_base_border_handle == ui_nodes_hwnd || ui_base_border_handle == ui_view2d_hwnd) { - if (ui_base_border_started == border_side_t.LEFT) { - config_raw.layout[layout_size_t.NODES_W] -= math_floor(mouse_movement_x); - if (config_raw.layout[layout_size_t.NODES_W] < 32) { - config_raw.layout[layout_size_t.NODES_W] = 32; - } - else if (config_raw.layout[layout_size_t.NODES_W] > iron_window_width() * 0.7) { - config_raw.layout[layout_size_t.NODES_W] = math_floor(iron_window_width() * 0.7); - } - } - else { // UINodes / UIView2D ratio - config_raw.layout[layout_size_t.NODES_H] -= math_floor(mouse_movement_y); - if (config_raw.layout[layout_size_t.NODES_H] < 32) { - config_raw.layout[layout_size_t.NODES_H] = 32; - } - else if (config_raw.layout[layout_size_t.NODES_H] > sys_h() * 0.95) { - config_raw.layout[layout_size_t.NODES_H] = math_floor(sys_h() * 0.95); - } - } - } - else if (ui_base_border_handle == ui_base_hwnds[tab_area_t.STATUS]) { - let my: i32 = math_floor(mouse_movement_y); - if (config_raw.layout[layout_size_t.STATUS_H] - my >= ui_status_default_status_h * config_raw.window_scale && config_raw.layout[layout_size_t.STATUS_H] - my < iron_window_height() * 0.7) { - config_raw.layout[layout_size_t.STATUS_H] -= my; - } - } - else { - if (ui_base_border_started == border_side_t.LEFT) { - config_raw.layout[layout_size_t.SIDEBAR_W] -= math_floor(mouse_movement_x); - if (config_raw.layout[layout_size_t.SIDEBAR_W] < ui_base_sidebar_mini_w) { - config_raw.layout[layout_size_t.SIDEBAR_W] = ui_base_sidebar_mini_w; - } - else if (config_raw.layout[layout_size_t.SIDEBAR_W] > iron_window_width() - ui_base_sidebar_mini_w) { - config_raw.layout[layout_size_t.SIDEBAR_W] = iron_window_width() - ui_base_sidebar_mini_w; - } - } - else { - let my: i32 = math_floor(mouse_movement_y); - if (ui_base_border_handle == ui_base_hwnds[tab_area_t.SIDEBAR1] && ui_base_border_started == border_side_t.TOP) { - if (config_raw.layout[layout_size_t.SIDEBAR_H0] + my > 32 && config_raw.layout[layout_size_t.SIDEBAR_H1] - my > 32) { - config_raw.layout[layout_size_t.SIDEBAR_H0] += my; - config_raw.layout[layout_size_t.SIDEBAR_H1] -= my; - } - } - } - } - } - - if (!mouse_down()) { - ui_base_border_handle = null; - base_is_resizing = false; - } - - if (context_raw.tool == tool_type_t.PARTICLE && context_in_paint_area() && !context_raw.paint2d) { - util_particle_init_physics(); - let world: physics_world_t = physics_world_active; - physics_world_update(world); - context_raw.ddirty = 2; - context_raw.rdirty = 2; - if (mouse_started()) { - if (context_raw.particle_timer != null) { - tween_stop(context_raw.particle_timer); - let timer: tween_anim_t = context_raw.particle_timer; - timer.done(timer.done_data); - context_raw.particle_timer = null; - } - history_push_undo = true; - context_raw.particle_hit_x = context_raw.particle_hit_y = context_raw.particle_hit_z = 0; - let o: object_t = scene_spawn_object(".Sphere"); - let mo: mesh_object_t = o.ext; - mo.base.name = ".Bullet"; - mo.base.visible = true; - - let camera: camera_object_t = scene_camera; - let ct: transform_t = camera.base.transform; - mo.base.transform.loc = vec4_create(transform_world_x(ct), transform_world_y(ct), transform_world_z(ct)); - mo.base.transform.scale = vec4_create(context_raw.brush_radius * 0.2, context_raw.brush_radius * 0.2, context_raw.brush_radius * 0.2); - transform_build_matrix(mo.base.transform); - - let body: physics_body_t = physics_body_create(); - body.shape = physics_shape_t.SPHERE; - body.mass = 1.0; - physics_body_init(body, mo.base); - - let ray: ray_t = raycast_get_ray(mouse_view_x(), mouse_view_y(), camera); - physics_body_apply_impulse(body, vec4_mult(ray.dir, 0.15)); - - context_raw.particle_timer = tween_timer(5, function (mo: mesh_object_t) { - mesh_object_remove(mo); - }, mo); - } - - let pairs: physics_pair_t[] = physics_world_get_contact_pairs(world, context_raw.paint_body); - if (pairs != null) { - for (let i: i32 = 0; i < pairs.length; ++i) { - let p: physics_pair_t = pairs[i]; - context_raw.last_particle_hit_x = context_raw.particle_hit_x != 0 ? context_raw.particle_hit_x : p.pos_a_x; - context_raw.last_particle_hit_y = context_raw.particle_hit_y != 0 ? context_raw.particle_hit_y : p.pos_a_y; - context_raw.last_particle_hit_z = context_raw.particle_hit_z != 0 ? context_raw.particle_hit_z : p.pos_a_z; - context_raw.particle_hit_x = p.pos_a_x; - context_raw.particle_hit_y = p.pos_a_y; - context_raw.particle_hit_z = p.pos_a_z; - context_raw.pdirty = 1; - break; // 1 pair for now - } - } - } -} - -function ui_base_view_top() { - let is_typing: bool = ui.is_typing; - - if (context_in_paint_area() && !is_typing) { - if (mouse_view_x() < sys_w()) { - viewport_set_view(0, 0, 1, 0, 0, 0); - } - } -} - -function ui_base_operator_search() { - _ui_base_operator_search_first = true; - - ui_menu_draw(function () { - ui_menu_h = UI_ELEMENT_H() * 8; - let search_handle: ui_handle_t = ui_handle(__ID__); - let search: string = ui_text_input(search_handle, "", ui_align_t.LEFT, true, true); - ui.changed = false; - if (_ui_base_operator_search_first) { - _ui_base_operator_search_first = false; - search_handle.text = ""; - ui_start_text_edit(search_handle); // Focus search bar - } - - if (search_handle.changed) { - ui_base_operator_search_offset = 0; - } - - if (ui.is_key_pressed) { // Move selection - if (ui.key_code == key_code_t.DOWN && ui_base_operator_search_offset < 6) { - ui_base_operator_search_offset++; - } - if (ui.key_code == key_code_t.UP && ui_base_operator_search_offset > 0) { - ui_base_operator_search_offset--; - } - } - let enter: bool = keyboard_down("enter"); - let count: i32 = 0; - let BUTTON_COL: i32 = ui.ops.theme.BUTTON_COL; - - let keys: string[] = map_keys(config_keymap); - for (let i: i32 = 0; i < keys.length; ++i) { - let n: string = keys[i]; - if (string_index_of(n, search) >= 0) { - ui.ops.theme.BUTTON_COL = count == ui_base_operator_search_offset ? ui.ops.theme.HIGHLIGHT_COL : ui.ops.theme.SEPARATOR_COL; - if (ui_button(n, ui_align_t.LEFT, map_get(config_keymap, n)) || (enter && count == ui_base_operator_search_offset)) { - if (enter) { - ui.changed = true; - count = 6; // Trigger break - } - operator_run(n); - } - if (++count > 6) { - break; - } - } - } - - if (enter && count == 0) { // Hide popup on enter when command is not found - ui.changed = true; - search_handle.text = ""; - } - ui.ops.theme.BUTTON_COL = BUTTON_COL; - }); -} - -function ui_base_toggle_distract_free() { - ui_base_show = !ui_base_show; - base_resize(); -} - -function ui_base_get_radius_increment(): f32 { - return 0.1; -} - -function ui_base_hit_rect(mx: f32, my: f32, x: i32, y: i32, w: i32, h: i32): bool { - return mx > x && mx < x + w && my > y && my < y + h; -} - -function ui_base_get_brush_stencil_rect(): rect_t { - let w: i32 = math_floor(context_raw.brush_stencil_image.width * (base_h() / context_raw.brush_stencil_image.height) * context_raw.brush_stencil_scale); - let h: i32 = math_floor(base_h() * context_raw.brush_stencil_scale); - let x: i32 = math_floor(base_x() + context_raw.brush_stencil_x * base_w()); - let y: i32 = math_floor(base_y() + context_raw.brush_stencil_y * base_h()); - let r: rect_t = { - w: w, - h: h, - x: x, - y: y - }; - return r; -} - -function ui_base_update_ui() { - if (console_message_timer > 0) { - console_message_timer -= sys_delta(); - if (console_message_timer <= 0) { - ui_base_hwnds[tab_area_t.STATUS].redraws = 2; - } - } - - ui_base_sidebar_mini_w = math_floor(ui_base_default_sidebar_mini_w * UI_SCALE()); - - if (!base_ui_enabled) { - return; - } - - // Same mapping for paint and rotate (predefined in touch keymap) - if (context_in_viewport()) { - let paint_key: string = map_get(config_keymap, "action_paint"); - let rotate_key: string = map_get(config_keymap, "action_rotate"); - if (mouse_started() && paint_key == rotate_key) { - ui_base_action_paint_remap = paint_key; - util_render_pick_pos_nor_tex(); - let is_mesh: bool = math_abs(context_raw.posx_picked) < 50 && math_abs(context_raw.posy_picked) < 50 && math_abs(context_raw.posz_picked) < 50; - ///if arm_android - // Allow rotating with both pen and touch, because hovering a pen prevents touch input on android - let pen_only: bool = false; - ///else - let pen_only: bool = context_raw.pen_painting_only; - ///end - let is_pen: bool = pen_only && pen_down(); - // Mesh picked - disable rotate - // Pen painting only - rotate with touch, paint with pen - if ((is_mesh && !pen_only) || is_pen) { - map_set(config_keymap, "action_rotate", ""); - map_set(config_keymap, "action_paint", ui_base_action_paint_remap); - } - // World sphere picked - disable paint - else { - map_set(config_keymap, "action_paint", ""); - map_set(config_keymap, "action_rotate", ui_base_action_paint_remap); - } - } - else if (!mouse_down() && ui_base_action_paint_remap != "") { - map_set(config_keymap, "action_rotate", ui_base_action_paint_remap); - map_set(config_keymap, "action_paint", ui_base_action_paint_remap); - ui_base_action_paint_remap = ""; - } - } - - if (context_raw.brush_stencil_image != null && operator_shortcut(map_get(config_keymap, "stencil_transform"), shortcut_type_t.DOWN)) { - let r: rect_t = ui_base_get_brush_stencil_rect(); - if (mouse_started("left")) { - context_raw.brush_stencil_scaling = - ui_base_hit_rect(mouse_x, mouse_y, r.x - 8, r.y - 8, 16, 16) || - ui_base_hit_rect(mouse_x, mouse_y, r.x - 8, r.h + r.y - 8, 16, 16) || - ui_base_hit_rect(mouse_x, mouse_y, r.w + r.x - 8, r.y - 8, 16, 16) || - ui_base_hit_rect(mouse_x, mouse_y, r.w + r.x - 8, r.h + r.y - 8, 16, 16); - let cosa: f32 = math_cos(-context_raw.brush_stencil_angle); - let sina: f32 = math_sin(-context_raw.brush_stencil_angle); - let ox: f32 = 0; - let oy: f32 = -r.h / 2; - let x: f32 = ox * cosa - oy * sina; - let y: f32 = ox * sina + oy * cosa; - x += r.x + r.w / 2; - y += r.y + r.h / 2; - context_raw.brush_stencil_rotating = - ui_base_hit_rect(mouse_x, mouse_y, math_floor(x - 16), math_floor(y - 16), 32, 32); - } - let _scale: f32 = context_raw.brush_stencil_scale; - if (mouse_down("left")) { - if (context_raw.brush_stencil_scaling) { - let mult: i32 = mouse_x > r.x + r.w / 2 ? 1 : -1; - context_raw.brush_stencil_scale += mouse_movement_x / 400 * mult; - } - else if (context_raw.brush_stencil_rotating) { - let gizmo_x: f32 = r.x + r.w / 2; - let gizmo_y: f32 = r.y + r.h / 2; - context_raw.brush_stencil_angle = -math_atan2(mouse_y - gizmo_y, mouse_x - gizmo_x) - math_pi() / 2; - } - else { - context_raw.brush_stencil_x += mouse_movement_x / base_w(); - context_raw.brush_stencil_y += mouse_movement_y / base_h(); - } - } - else { - context_raw.brush_stencil_scaling = false; - } - if (mouse_wheel_delta != 0) { - context_raw.brush_stencil_scale -= mouse_wheel_delta / 10; - } - // Center after scale - let ratio: f32 = base_h() / context_raw.brush_stencil_image.height; - let old_w: f32 = _scale * context_raw.brush_stencil_image.width * ratio; - let new_w: f32 = context_raw.brush_stencil_scale * context_raw.brush_stencil_image.width * ratio; - let old_h: f32 = _scale * base_h(); - let new_h: f32 = context_raw.brush_stencil_scale * base_h(); - context_raw.brush_stencil_x += (old_w - new_w) / base_w() / 2; - context_raw.brush_stencil_y += (old_h - new_h) / base_h() / 2; - } - - let set_clone_source: bool = context_raw.tool == tool_type_t.CLONE && operator_shortcut(map_get(config_keymap, "set_clone_source") + "+" + map_get(config_keymap, "action_paint"), shortcut_type_t.DOWN); - - let decal: bool = context_is_decal(); - let decal_mask: bool = context_is_decal_mask_paint(); - - let down: bool = operator_shortcut(map_get(config_keymap, "action_paint"), shortcut_type_t.DOWN) || - decal_mask || - set_clone_source || - operator_shortcut(map_get(config_keymap, "brush_ruler") + "+" + map_get(config_keymap, "action_paint"), shortcut_type_t.DOWN) || - (pen_down() && !keyboard_down("alt")); - - if (config_raw.touch_ui) { - if (pen_down()) { - context_raw.pen_painting_only = true; - } - else if (context_raw.pen_painting_only) { - down = false; - } - } - - if (context_raw.tool == tool_type_t.PARTICLE) { - down = false; - } - - if (down) { - let mx: i32 = mouse_view_x(); - let my: i32 = mouse_view_y(); - let ww: i32 = sys_w(); - - if (context_raw.paint2d) { - mx -= sys_w(); - ww = ui_view2d_ww; - } - - if (mx < ww && - mx > sys_x() && - my < sys_h() && - my > sys_y()) { - - if (set_clone_source) { - context_raw.clone_start_x = mx; - context_raw.clone_start_y = my; - } - else { - if (context_raw.brush_time == 0 && - !base_is_dragging && - !base_is_resizing && - !base_is_combo_selected()) { // Paint started - - // Draw line - if (operator_shortcut(map_get(config_keymap, "brush_ruler") + "+" + map_get(config_keymap, "action_paint"), shortcut_type_t.DOWN)) { - context_raw.last_paint_vec_x = context_raw.last_paint_x; - context_raw.last_paint_vec_y = context_raw.last_paint_y; - } - - history_push_undo = true; - - if (context_raw.tool == tool_type_t.CLONE && context_raw.clone_start_x >= 0.0) { // Clone delta - context_raw.clone_delta_x = (context_raw.clone_start_x - mx) / ww; - context_raw.clone_delta_y = (context_raw.clone_start_y - my) / sys_h(); - context_raw.clone_start_x = -1; - } - else if (context_raw.tool == tool_type_t.FILL && context_raw.fill_type_handle.position == fill_type_t.UV_ISLAND) { - util_uv_uvislandmap_cached = false; - } - } - - context_raw.brush_time += sys_delta(); - - if (context_raw.run_brush != null) { - context_raw.run_brush(context_raw.brush_output_node_inst, 0); - } - } - } - } - else if (context_raw.brush_time > 0) { // Brush released - context_raw.brush_time = 0; - context_raw.prev_paint_vec_x = -1; - context_raw.prev_paint_vec_y = -1; - ///if (arm_opengl || arm_direct3d11) // Keep accumulated samples for D3D12 - context_raw.ddirty = 3; - ///end - context_raw.brush_blend_dirty = true; // Update brush mask - - context_raw.layer_preview_dirty = true; // Update layer preview - - // New color id picked, update fill layer - if (context_raw.tool == tool_type_t.COLORID && context_raw.layer.fill_layer != null) { - sys_notify_on_next_frame(function () { - layers_update_fill_layer(); - make_material_parse_paint_material(false); - }); - } - } - - if (context_raw.layers_preview_dirty) { - context_raw.layers_preview_dirty = false; - context_raw.layer_preview_dirty = false; - context_raw.mask_preview_last = null; - // Update all layer previews - for (let i: i32 = 0; i < project_layers.length; ++i) { - let l: slot_layer_t = project_layers[i]; - if (slot_layer_is_group(l)) { - continue; - } - - let target: gpu_texture_t = l.texpaint_preview; - if (target == null) { - continue; - } - - let source: gpu_texture_t = l.texpaint; - draw_begin(target, true, 0x00000000); - // draw_set_pipeline(l.is_mask() ? pipes_copy8 : pipes_copy); - draw_set_pipeline(pipes_copy); // texpaint_preview is always RGBA32 for now - draw_scaled_image(source, 0, 0, target.width, target.height); - draw_set_pipeline(null); - draw_end(); - } - ui_base_hwnds[tab_area_t.SIDEBAR0].redraws = 2; - } - if (context_raw.layer != null && context_raw.layer_preview_dirty && !slot_layer_is_group(context_raw.layer)) { - context_raw.layer_preview_dirty = false; - context_raw.mask_preview_last = null; - // Update layer preview - let l: slot_layer_t = context_raw.layer; - - let target: gpu_texture_t = l.texpaint_preview; - if (target != null) { - - let source: gpu_texture_t = l.texpaint; - draw_begin(target, true, 0x00000000); - // draw_set_pipeline(raw.layer.is_mask() ? pipes_copy8 : pipes_copy); - draw_set_pipeline(pipes_copy); // texpaint_preview is always RGBA32 for now - draw_scaled_image(source, 0, 0, target.width, target.height); - draw_set_pipeline(null); - draw_end(); - ui_base_hwnds[tab_area_t.SIDEBAR0].redraws = 2; - } - } - - let undo_pressed: bool = operator_shortcut(map_get(config_keymap, "edit_undo")); - let redo_pressed: bool = operator_shortcut(map_get(config_keymap, "edit_redo")) || - (keyboard_down("control") && keyboard_started("y")); - - // Two-finger tap to undo, three-finger tap to redo - if (context_in_viewport() && config_raw.touch_ui) { - if (mouse_started("middle")) { - ui_base_redo_tap_time = sys_time(); - } - else if (mouse_started("right")) { - ui_base_undo_tap_time = sys_time(); - } - else if (mouse_released("middle") && sys_time() - ui_base_redo_tap_time < 0.1) { - ui_base_redo_tap_time = ui_base_undo_tap_time = 0; - redo_pressed = true; - } - else if (mouse_released("right") && sys_time() - ui_base_undo_tap_time < 0.1) { - ui_base_redo_tap_time = ui_base_undo_tap_time = 0; - undo_pressed = true; - } - } - - if (undo_pressed) { - history_undo(); - } - else if (redo_pressed) { - history_redo(); - } - - gizmo_update(); -} - -function ui_base_render() { - if (!ui_base_show && config_raw.touch_ui) { - ui.input_enabled = true; - ui_begin(ui); - if (ui_window(ui_handle(__ID__), 0, 0, 150, math_floor(UI_ELEMENT_H() + UI_ELEMENT_OFFSET() + 1))) { - if (ui_button(tr("Close"))) { - ui_base_toggle_distract_free(); - } - } - ui_end(); - } - - if (!ui_base_show) { - return; - } - - ui.input_enabled = base_ui_enabled; - - // Remember last tab positions - for (let i: i32 = 0; i < ui_base_htabs.length; ++i) { - if (ui_base_htabs[i].changed) { - config_raw.layout_tabs[i] = ui_base_htabs[i].position; - config_save(); - } - } - - // Set tab positions - for (let i: i32 = 0; i < ui_base_htabs.length; ++i) { - ui_base_htabs[i].position = config_raw.layout_tabs[i]; - } - - ui_begin(ui); - ui_toolbar_render_ui(); - ui_menubar_render_ui(); - ui_header_render_ui(); - ui_status_render_ui(); - ui_base_draw_sidebar(); - ui_end(); - - ui.input_enabled = true; -} - -function ui_base_draw_sidebar() { - // Tabs - let mini: bool = config_raw.layout[layout_size_t.SIDEBAR_W] <= ui_base_sidebar_mini_w; - let expand_button_offset: i32 = config_raw.touch_ui ? math_floor(UI_ELEMENT_H() + UI_ELEMENT_OFFSET()) : 0; - ui_base_tabx = iron_window_width() - config_raw.layout[layout_size_t.SIDEBAR_W]; - - let _SCROLL_W: i32 = ui.ops.theme.SCROLL_W; - if (mini) { - ui.ops.theme.SCROLL_W = ui.ops.theme.SCROLL_MINI_W; - } - - if (ui_window(ui_base_hwnds[tab_area_t.SIDEBAR0], ui_base_tabx, 0, config_raw.layout[layout_size_t.SIDEBAR_W], config_raw.layout[layout_size_t.SIDEBAR_H0])) { - let tabs: tab_draw_t[] = ui_base_hwnd_tabs[tab_area_t.SIDEBAR0]; - for (let i: i32 = 0; i < (mini ? 1 : tabs.length); ++i) { - tabs[i].f(ui_base_htabs[tab_area_t.SIDEBAR0]); - } - } - if (ui_window(ui_base_hwnds[tab_area_t.SIDEBAR1], ui_base_tabx, config_raw.layout[layout_size_t.SIDEBAR_H0], config_raw.layout[layout_size_t.SIDEBAR_W], config_raw.layout[layout_size_t.SIDEBAR_H1] - expand_button_offset)) { - let tabs: tab_draw_t[] = ui_base_hwnd_tabs[tab_area_t.SIDEBAR1]; - for (let i: i32 = 0; i < (mini ? 1 : tabs.length); ++i) { - tabs[i].f(ui_base_htabs[tab_area_t.SIDEBAR1]); - } - } - - ui_end_window(); - ui.ops.theme.SCROLL_W = _SCROLL_W; - - // Collapse / expand button for mini sidebar - if (config_raw.touch_ui) { - let width: i32 = config_raw.layout[layout_size_t.SIDEBAR_W]; - let height: i32 = math_floor(UI_ELEMENT_H() + UI_ELEMENT_OFFSET()); - if (ui_window(ui_handle(__ID__), iron_window_width() - width, iron_window_height() - height, width, height + 1)) { - ui._w = width; - let _BUTTON_H: i32 = ui.ops.theme.BUTTON_H; - let _BUTTON_COL: i32 = ui.ops.theme.BUTTON_COL; - ui.ops.theme.BUTTON_H = ui.ops.theme.ELEMENT_H; - ui.ops.theme.BUTTON_COL = ui.ops.theme.WINDOW_BG_COL; - if (ui_button(mini ? "<<" : ">>")) { - config_raw.layout[layout_size_t.SIDEBAR_W] = mini ? ui_base_default_sidebar_full_w : ui_base_default_sidebar_mini_w; - config_raw.layout[layout_size_t.SIDEBAR_W] = math_floor(config_raw.layout[layout_size_t.SIDEBAR_W] * UI_SCALE()); - } - ui.ops.theme.BUTTON_H = _BUTTON_H; - ui.ops.theme.BUTTON_COL = _BUTTON_COL; - } - } - - // Expand button - if (config_raw.layout[layout_size_t.SIDEBAR_W] == 0) { - let width: i32 = math_floor(draw_string_width(ui.ops.font, ui.font_size, "<<") + 25 * UI_SCALE()); - if (ui_window(ui_base_hminimized, iron_window_width() - width, 0, width, math_floor(UI_ELEMENT_H() + UI_ELEMENT_OFFSET() + 1))) { - ui._w = width; - let _BUTTON_H: i32 = ui.ops.theme.BUTTON_H; - let _BUTTON_COL: i32 = ui.ops.theme.BUTTON_COL; - ui.ops.theme.BUTTON_H = ui.ops.theme.ELEMENT_H; - ui.ops.theme.BUTTON_COL = ui.ops.theme.SEPARATOR_COL; - - if (ui_button("<<")) { - config_raw.layout[layout_size_t.SIDEBAR_W] = context_raw.maximized_sidebar_width != 0 ? context_raw.maximized_sidebar_width : math_floor(ui_base_default_sidebar_w * config_raw.window_scale); - } - ui.ops.theme.BUTTON_H = _BUTTON_H; - ui.ops.theme.BUTTON_COL = _BUTTON_COL; - } - } - else if (ui_base_htabs[tab_area_t.SIDEBAR0].changed && ui_base_htabs[tab_area_t.SIDEBAR0].position == context_raw.last_htab0_pos) { - if (sys_time() - context_raw.select_time < 0.25) { - context_raw.maximized_sidebar_width = config_raw.layout[layout_size_t.SIDEBAR_W]; - config_raw.layout[layout_size_t.SIDEBAR_W] = 0; - } - context_raw.select_time = sys_time(); - } - context_raw.last_htab0_pos = ui_base_htabs[tab_area_t.SIDEBAR0].position; -} - -function ui_base_render_cursor() { - if (!base_ui_enabled) { - return; - } - - if (context_raw.tool == tool_type_t.MATERIAL || context_raw.tool == tool_type_t.BAKE) { - return; - } - - draw_begin(); - draw_set_color(0xffffffff); - - context_raw.view_index = context_raw.view_index_last; - let mx: i32 = base_x() + context_raw.paint_vec.x * base_w(); - let my: i32 = base_y() + context_raw.paint_vec.y * base_h(); - context_raw.view_index = -1; - - // Radius being scaled - if (context_raw.brush_locked) { - mx += context_raw.lock_started_x - iron_window_width() / 2; - my += context_raw.lock_started_y - iron_window_height() / 2; - } - - if (context_raw.brush_stencil_image != null && - context_raw.tool != tool_type_t.BAKE && - context_raw.tool != tool_type_t.PICKER && - context_raw.tool != tool_type_t.MATERIAL && - context_raw.tool != tool_type_t.COLORID) { - let r: rect_t = ui_base_get_brush_stencil_rect(); - if (!operator_shortcut(map_get(config_keymap, "stencil_hide"), shortcut_type_t.DOWN)) { - draw_set_color(0x88ffffff); - let angle: f32 = context_raw.brush_stencil_angle; - draw_set_transform(mat3_multmat(mat3_multmat(mat3_translation(0.5, 0.5), mat3_rotation(-angle)), mat3_translation(-0.5, -0.5))); - draw_scaled_image(context_raw.brush_stencil_image, r.x, r.y, r.w, r.h); - draw_set_transform(mat3_nan()); - draw_set_color(0xffffffff); - } - let transform: bool = operator_shortcut(map_get(config_keymap, "stencil_transform"), shortcut_type_t.DOWN); - if (transform) { - // Outline - draw_rect(r.x, r.y, r.w, r.h); - // Scale - draw_rect(r.x - 8, r.y - 8, 16, 16); - draw_rect(r.x - 8 + r.w, r.y - 8, 16, 16); - draw_rect(r.x - 8, r.y - 8 + r.h, 16, 16); - draw_rect(r.x - 8 + r.w, r.y - 8 + r.h, 16, 16); - // Rotate - let cosa: f32 = math_cos(-context_raw.brush_stencil_angle); - let sina: f32 = math_sin(-context_raw.brush_stencil_angle); - let ox: f32 = 0; - let oy: f32 = -r.h / 2; - let x: f32 = ox * cosa - oy * sina; - let y: f32 = ox * sina + oy * cosa; - x += r.x + r.w / 2; - y += r.y + r.h / 2; - draw_filled_circle(x, y, 8); - } - } - - // Show picked material next to cursor - if (context_raw.tool == tool_type_t.PICKER && context_raw.picker_select_material && context_raw.color_picker_callback == null) { - let img: gpu_texture_t = context_raw.material.image_icon; - draw_image(img, mx + 10, my + 10); - } - if (context_raw.tool == tool_type_t.PICKER && context_raw.color_picker_callback != null) { - let img: gpu_texture_t = resource_get("icons.k"); - let rect: rect_t = resource_tile50(img, tool_type_t.PICKER, 0); - draw_sub_image(img, mx + 10, my + 10, rect.x, rect.y, rect.w, rect.h); - } - - let cursor_img: gpu_texture_t = resource_get("cursor.k"); - let psize: i32 = math_floor(182 * (context_raw.brush_radius * context_raw.brush_nodes_radius) * UI_SCALE()); - - // Clone source cursor - if (context_raw.tool == tool_type_t.CLONE && !keyboard_down("alt") && (mouse_down() || pen_down())) { - draw_set_color(0x66ffffff); - draw_scaled_image(cursor_img, mx + context_raw.clone_delta_x * sys_w() - psize / 2, my + context_raw.clone_delta_y * sys_h() - psize / 2, psize, psize); - draw_set_color(0xffffffff); - } - - let decal: bool = context_is_decal(); - - if (!config_raw.brush_3d || context_in_2d_view() || decal) { - let decal_mask: bool = context_is_decal_mask(); - if (decal && !context_in_nodes()) { - let decal_alpha: f32 = 0.5; - if (!decal_mask) { - context_raw.decal_x = context_raw.paint_vec.x; - context_raw.decal_y = context_raw.paint_vec.y; - decal_alpha = context_raw.brush_opacity; - - // Radius being scaled - if (context_raw.brush_locked) { - context_raw.decal_x += (context_raw.lock_started_x - iron_window_width() / 2) / base_w(); - context_raw.decal_y += (context_raw.lock_started_y - iron_window_height() / 2) / base_h(); - } - } - - if (!config_raw.brush_live) { - let psizex: i32 = math_floor(256 * UI_SCALE() * (context_raw.brush_radius * context_raw.brush_nodes_radius * context_raw.brush_scale_x)); - let psizey: i32 = math_floor(256 * UI_SCALE() * (context_raw.brush_radius * context_raw.brush_nodes_radius)); - - context_raw.view_index = context_raw.view_index_last; - let decalx: f32 = base_x() + context_raw.decal_x * base_w() - psizex / 2; - let decaly: f32 = base_y() + context_raw.decal_y * base_h() - psizey / 2; - context_raw.view_index = -1; - - draw_set_color(color_from_floats(1, 1, 1, decal_alpha)); - let angle: f32 = (context_raw.brush_angle + context_raw.brush_nodes_angle) * (math_pi() / 180); - draw_set_transform(mat3_multmat(mat3_multmat(mat3_translation(0.5, 0.5), mat3_rotation(angle)), mat3_translation(-0.5, -0.5))); - draw_scaled_image(context_raw.decal_image, decalx, decaly, psizex, psizey); - draw_set_transform(mat3_nan()); - draw_set_color(0xffffffff); - } - } - if (context_raw.tool == tool_type_t.BRUSH || - context_raw.tool == tool_type_t.ERASER || - context_raw.tool == tool_type_t.CLONE || - context_raw.tool == tool_type_t.BLUR || - context_raw.tool == tool_type_t.SMUDGE || - context_raw.tool == tool_type_t.PARTICLE || - (decal_mask && !config_raw.brush_3d) || - (decal_mask && context_in_2d_view())) { - if (decal_mask) { - psize = math_floor(cursor_img.width * (context_raw.brush_decal_mask_radius * context_raw.brush_nodes_radius) * UI_SCALE()); - } - if (config_raw.brush_3d && context_in_2d_view()) { - psize = math_floor(psize * ui_view2d_pan_scale); - } - draw_scaled_image(cursor_img, mx - psize / 2, my - psize / 2, psize, psize); - } - } - - if (context_raw.brush_lazy_radius > 0 && !context_raw.brush_locked && - (context_raw.tool == tool_type_t.BRUSH || - context_raw.tool == tool_type_t.ERASER || - context_raw.tool == tool_type_t.DECAL || - context_raw.tool == tool_type_t.TEXT || - context_raw.tool == tool_type_t.CLONE || - context_raw.tool == tool_type_t.BLUR || - context_raw.tool == tool_type_t.SMUDGE || - context_raw.tool == tool_type_t.PARTICLE)) { - draw_filled_rect(mx - 1, my - 1, 2, 2); - mx = context_raw.brush_lazy_x * base_w() + base_x(); - my = context_raw.brush_lazy_y * base_h() + base_y(); - let radius: f32 = context_raw.brush_lazy_radius * 180; - draw_set_color(0xff666666); - draw_scaled_image(cursor_img, mx - radius / 2, my - radius / 2, radius, radius); - draw_set_color(0xffffffff); - } - draw_end(); -} - -function ui_base_show_material_nodes() { - // Clear input state as ui receives input events even when not drawn - ui_end_input(); - - ui_nodes_show = !ui_nodes_show || ui_nodes_canvas_type != canvas_type_t.MATERIAL; - ui_nodes_canvas_type = canvas_type_t.MATERIAL; - - ///if (arm_ios || arm_android) - if (ui_view2d_show) { - ui_view2d_show = false; - } - ///end - - base_resize(); -} - -function ui_base_show_brush_nodes() { - // Clear input state as ui receives input events even when not drawn - ui_end_input(); - ui_nodes_show = !ui_nodes_show || ui_nodes_canvas_type != canvas_type_t.BRUSH; - ui_nodes_canvas_type = canvas_type_t.BRUSH; - - ///if (arm_ios || arm_android) - if (ui_view2d_show) { - ui_view2d_show = false; - } - ///end - - base_resize(); -} - -function ui_base_show_2d_view(type: view_2d_type_t) { - // Clear input state as ui receives input events even when not drawn - ui_end_input(); - if (ui_view2d_type != type) { - ui_view2d_show = true; - } - else { - ui_view2d_show = !ui_view2d_show; - } - ui_view2d_type = type; - ui_view2d_hwnd.redraws = 2; - - ///if (arm_ios || arm_android) - if (ui_nodes_show) { - ui_nodes_show = false; - } - ///end - - base_resize(); -} - -function ui_base_toggle_browser() { - let minimized: bool = config_raw.layout[layout_size_t.STATUS_H] <= (ui_status_default_status_h * config_raw.window_scale); - config_raw.layout[layout_size_t.STATUS_H] = minimized ? 240 : ui_status_default_status_h; - config_raw.layout[layout_size_t.STATUS_H] = math_floor(config_raw.layout[layout_size_t.STATUS_H] * config_raw.window_scale); -} - -function ui_base_set_icon_scale() { - if (UI_SCALE() > 1) { - let res: string[] = ["icons2x.k"]; - resource_load(res); - map_set(resource_bundled, "icons.k", resource_get("icons2x.k")); - } - else { - let res: string[] = ["icons.k"]; - resource_load(res); - } -} - -function ui_base_on_border_hover(handle: ui_handle_t, side: i32) { - if (!base_ui_enabled) { - return; - } - - if (handle != ui_base_hwnds[tab_area_t.SIDEBAR0] && - handle != ui_base_hwnds[tab_area_t.SIDEBAR1] && - handle != ui_base_hwnds[tab_area_t.STATUS] && - handle != ui_nodes_hwnd && - handle != ui_view2d_hwnd) { - return; // Scalable handles - } - if (handle == ui_view2d_hwnd && side != border_side_t.LEFT) { - return; - } - if (handle == ui_nodes_hwnd && side == border_side_t.TOP && !ui_view2d_show) { - return; - } - if (handle == ui_base_hwnds[tab_area_t.SIDEBAR0] && side == border_side_t.TOP) { - return; - } - - if (handle == ui_nodes_hwnd && side != border_side_t.LEFT && side != border_side_t.TOP) { - return; - } - if (handle == ui_base_hwnds[tab_area_t.STATUS] && side != border_side_t.TOP) { - return; - } - if (side == border_side_t.RIGHT) { - return; // UI is snapped to the right side - } - - side == border_side_t.LEFT || side == border_side_t.RIGHT ? - iron_mouse_set_cursor(cursor_t.SIZEWE) : - iron_mouse_set_cursor(cursor_t.SIZENS); - - if (ui.input_started) { - ui_base_border_started = side; - ui_base_border_handle = handle; - base_is_resizing = true; - } -} - -function ui_base_on_tab_drop(to: ui_handle_t, to_position: i32, from: ui_handle_t, from_position: i32) { - let i: i32 = -1; - let j: i32 = -1; - for (let k: i32 = 0; k < ui_base_htabs.length; ++k) { - if (ui_base_htabs[k] == to) { - i = k; - } - if (ui_base_htabs[k] == from) { - j = k; - } - } - if (i == j && to_position == from_position) { - return; - } - if (i > -1 && j > -1) { - let tabsi: tab_draw_t[] = ui_base_hwnd_tabs[i]; - let tabsj: tab_draw_t[] = ui_base_hwnd_tabs[j]; - let element: tab_draw_t = tabsj[from_position]; - array_splice(tabsj, from_position, 1); - array_insert(tabsi, to_position, element); - ui_base_hwnds[i].redraws = 2; - ui_base_hwnds[j].redraws = 2; - } -} - -function ui_base_tag_ui_redraw() { - ui_header_handle.redraws = 2; - ui_base_hwnds[tab_area_t.STATUS].redraws = 2; - ui_menubar_workspace_handle.redraws = 2; - ui_menubar_menu_handle.redraws = 2; - ui_base_hwnds[tab_area_t.SIDEBAR0].redraws = 2; - ui_base_hwnds[tab_area_t.SIDEBAR1].redraws = 2; - ui_toolbar_handle.redraws = 2; -} - -function ui_base_make_empty_envmap(col: i32) { - ui_base_viewport_col = col; - let b: u8_array_t = u8_array_create(4); - b[0] = color_get_rb(col); - b[1] = color_get_gb(col); - b[2] = color_get_bb(col); - b[3] = 255; - context_raw.empty_envmap = gpu_create_texture_from_bytes(b, 1, 1); -} - -function ui_base_set_viewport_col(col: i32) { - ui_base_make_empty_envmap(col); - context_raw.ddirty = 2; - if (!context_raw.show_envmap) { - scene_world._.envmap = context_raw.empty_envmap; - } -} diff --git a/paint/sources/ui_nodes.ts b/paint/sources/ui_nodes.ts index d20cb5de..030f05e5 100644 --- a/paint/sources/ui_nodes.ts +++ b/paint/sources/ui_nodes.ts @@ -428,7 +428,7 @@ function ui_nodes_get_canvas_control(controls_down: bool): ui_canvas_control_t { zoom: ui.input_wheel_delta != 0.0 ? -ui.input_wheel_delta / 10 : zoom_delta, controls_down: controls_down }; - if (base_is_combo_selected()) { + if (ui.combo_selected_handle != null) { control.zoom = 0.0; } if (control.zoom != 0.0) { diff --git a/paint/sources/ui_sidebar.ts b/paint/sources/ui_sidebar.ts new file mode 100644 index 00000000..5fe7a24a --- /dev/null +++ b/paint/sources/ui_sidebar.ts @@ -0,0 +1,86 @@ + +let ui_sidebar_default_w_mini: i32 = 56; +let ui_sidebar_default_w_full: i32 = 280; + +///if (arm_android || arm_ios) +let ui_sidebar_default_w: i32 = ui_sidebar_default_w_mini; +///else +let ui_sidebar_default_w: i32 = ui_sidebar_default_w_full; +///end + +let ui_sidebar_tabx: i32 = 0; +let ui_sidebar_hminimized: ui_handle_t = ui_handle_create(); +let ui_sidebar_w_mini: i32 = ui_sidebar_default_w_mini; + +function ui_sidebar_render_ui() { + // Tabs + let mini: bool = config_raw.layout[layout_size_t.SIDEBAR_W] <= ui_sidebar_w_mini; + let expand_button_offset: i32 = config_raw.touch_ui ? math_floor(UI_ELEMENT_H() + UI_ELEMENT_OFFSET()) : 0; + ui_sidebar_tabx = iron_window_width() - config_raw.layout[layout_size_t.SIDEBAR_W]; + + let _SCROLL_W: i32 = ui.ops.theme.SCROLL_W; + if (mini) { + ui.ops.theme.SCROLL_W = ui.ops.theme.SCROLL_MINI_W; + } + + if (ui_window(ui_base_hwnds[tab_area_t.SIDEBAR0], ui_sidebar_tabx, 0, config_raw.layout[layout_size_t.SIDEBAR_W], config_raw.layout[layout_size_t.SIDEBAR_H0])) { + let tabs: tab_draw_t[] = ui_base_hwnd_tabs[tab_area_t.SIDEBAR0]; + for (let i: i32 = 0; i < (mini ? 1 : tabs.length); ++i) { + tabs[i].f(ui_base_htabs[tab_area_t.SIDEBAR0]); + } + } + if (ui_window(ui_base_hwnds[tab_area_t.SIDEBAR1], ui_sidebar_tabx, config_raw.layout[layout_size_t.SIDEBAR_H0], config_raw.layout[layout_size_t.SIDEBAR_W], config_raw.layout[layout_size_t.SIDEBAR_H1] - expand_button_offset)) { + let tabs: tab_draw_t[] = ui_base_hwnd_tabs[tab_area_t.SIDEBAR1]; + for (let i: i32 = 0; i < (mini ? 1 : tabs.length); ++i) { + tabs[i].f(ui_base_htabs[tab_area_t.SIDEBAR1]); + } + } + + ui_end_window(); + ui.ops.theme.SCROLL_W = _SCROLL_W; + + // Collapse / expand button for mini sidebar + if (config_raw.touch_ui) { + let width: i32 = config_raw.layout[layout_size_t.SIDEBAR_W]; + let height: i32 = math_floor(UI_ELEMENT_H() + UI_ELEMENT_OFFSET()); + if (ui_window(ui_handle(__ID__), iron_window_width() - width, iron_window_height() - height, width, height + 1)) { + ui._w = width; + let _BUTTON_H: i32 = ui.ops.theme.BUTTON_H; + let _BUTTON_COL: i32 = ui.ops.theme.BUTTON_COL; + ui.ops.theme.BUTTON_H = ui.ops.theme.ELEMENT_H; + ui.ops.theme.BUTTON_COL = ui.ops.theme.WINDOW_BG_COL; + if (ui_button(mini ? "<<" : ">>")) { + config_raw.layout[layout_size_t.SIDEBAR_W] = mini ? ui_sidebar_default_w_full : ui_sidebar_default_w_mini; + config_raw.layout[layout_size_t.SIDEBAR_W] = math_floor(config_raw.layout[layout_size_t.SIDEBAR_W] * UI_SCALE()); + } + ui.ops.theme.BUTTON_H = _BUTTON_H; + ui.ops.theme.BUTTON_COL = _BUTTON_COL; + } + } + + // Expand button + if (config_raw.layout[layout_size_t.SIDEBAR_W] == 0) { + let width: i32 = math_floor(draw_string_width(ui.ops.font, ui.font_size, "<<") + 25 * UI_SCALE()); + if (ui_window(ui_sidebar_hminimized, iron_window_width() - width, 0, width, math_floor(UI_ELEMENT_H() + UI_ELEMENT_OFFSET() + 1))) { + ui._w = width; + let _BUTTON_H: i32 = ui.ops.theme.BUTTON_H; + let _BUTTON_COL: i32 = ui.ops.theme.BUTTON_COL; + ui.ops.theme.BUTTON_H = ui.ops.theme.ELEMENT_H; + ui.ops.theme.BUTTON_COL = ui.ops.theme.SEPARATOR_COL; + + if (ui_button("<<")) { + config_raw.layout[layout_size_t.SIDEBAR_W] = context_raw.maximized_sidebar_width != 0 ? context_raw.maximized_sidebar_width : math_floor(ui_sidebar_default_w * config_raw.window_scale); + } + ui.ops.theme.BUTTON_H = _BUTTON_H; + ui.ops.theme.BUTTON_COL = _BUTTON_COL; + } + } + else if (ui_base_htabs[tab_area_t.SIDEBAR0].changed && ui_base_htabs[tab_area_t.SIDEBAR0].position == context_raw.last_htab0_pos) { + if (sys_time() - context_raw.select_time < 0.25) { + context_raw.maximized_sidebar_width = config_raw.layout[layout_size_t.SIDEBAR_W]; + config_raw.layout[layout_size_t.SIDEBAR_W] = 0; + } + context_raw.select_time = sys_time(); + } + context_raw.last_htab0_pos = ui_base_htabs[tab_area_t.SIDEBAR0].position; +} diff --git a/paint/sources/ui_status.ts b/paint/sources/ui_statusbar.ts similarity index 74% rename from paint/sources/ui_status.ts rename to paint/sources/ui_statusbar.ts index 28da1adc..3a41edd3 100644 --- a/paint/sources/ui_status.ts +++ b/paint/sources/ui_statusbar.ts @@ -1,17 +1,17 @@ -let ui_status_default_status_h: i32 = 33; +let ui_statusbar_default_h: i32 = 33; -function ui_status_init() { +function ui_statusbar_init() { } -function ui_status_width(): i32 { +function ui_statusbar_width(): i32 { return iron_window_width() - ui_toolbar_w(true) - config_raw.layout[layout_size_t.SIDEBAR_W]; } -function ui_status_render_ui() { +function ui_statusbar_render_ui() { let statush: i32 = config_raw.layout[layout_size_t.STATUS_H]; - if (ui_window(ui_base_hwnds[tab_area_t.STATUS], sys_x(), iron_window_height() - statush, ui_status_width(), statush)) { + if (ui_window(ui_base_hwnds[tab_area_t.STATUS], sys_x(), iron_window_height() - statush, ui_statusbar_width(), statush)) { ui._y += 2; // Border @@ -27,7 +27,7 @@ function ui_status_render_ui() { draw.f(htab); } - let minimized: bool = statush <= ui_status_default_status_h * config_raw.window_scale; + let minimized: bool = statush <= ui_statusbar_default_h * config_raw.window_scale; if (htab.changed && (htab.position == context_raw.last_status_position || minimized)) { ui_base_toggle_browser(); } @@ -35,7 +35,7 @@ function ui_status_render_ui() { } } -function ui_status_draw_version_tab(htab: ui_handle_t) { +function ui_statusbar_draw_version_tab(htab: ui_handle_t) { // Version label if (!config_raw.touch_ui) { ui.enabled = false; diff --git a/paint/sources/util_mesh.ts b/paint/sources/util_mesh.ts index b595bfd3..ce8f7025 100644 --- a/paint/sources/util_mesh.ts +++ b/paint/sources/util_mesh.ts @@ -4,7 +4,7 @@ let util_mesh_unwrappers: map_t = map_create(); // JSValue * -> ((a function util_mesh_merge(paint_objects: mesh_object_t[] = null) { if (paint_objects == null) { if (context_raw.tool == tool_type_t.GIZMO) { - paint_objects = util_mesh_ext_get_unique(); + paint_objects = util_mesh_get_unique(); } else { paint_objects = project_paint_objects; @@ -433,3 +433,44 @@ function util_mesh_decimate() { // decimate_mesh(mesh); import_mesh_add_mesh(mesh); } + +function _util_mesh_unique_data_count(): i32 { + return util_mesh_get_unique().length; +} + +function util_mesh_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_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; +} diff --git a/paint/sources/util_mesh_ext.ts b/paint/sources/util_mesh_ext.ts deleted file mode 100644 index f92ca61a..00000000 --- a/paint/sources/util_mesh_ext.ts +++ /dev/null @@ -1,41 +0,0 @@ - -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; -}