From 831df62631792a32c40df474762bab0b89dbe627 Mon Sep 17 00:00:00 2001 From: jesus-g20 Date: Thu, 3 Oct 2024 21:00:27 -0400 Subject: [PATCH 1/4] =?UTF-8?q?=EF=BB=BFAdded=20alternate=20key=20binding?= =?UTF-8?q?=20setting=20and=20updated=20documentation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/docs/user_interface.md | 5 +++-- project/addons/terrain_3d/editor.gd | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/docs/user_interface.md b/doc/docs/user_interface.md index 58b90d01e..bce9481df 100644 --- a/doc/docs/user_interface.md +++ b/doc/docs/user_interface.md @@ -21,14 +21,15 @@ The tools provide options for sculpting, texturing, and other features. Each but First, select the Region Tool (first one: square with a cross), and click the ground. This allocates space for you to sculpt and paint. ---- - ## Keyboard Shortcuts The following mouse and keyboard shortcuts are available. *Note*: Touchscreen users will see an `Invert` checkbox on the settings bar which acts like Ctrl to inverse operations. +*Note*: If the "Alternate Key Bindings" option is enabled in the editor settings, RMB (Right Mouse Button) replaces the default Alt + LMB behavior. This allows sculpting operations to be performed with RMB. + + ### General Keys * LMB - Click the terrain to positively apply the current tool. * Ctrl + LMB - **Inverse** the tool. Removes regions, height, color, wetness, autoshader, holes, navigation, foliage. diff --git a/project/addons/terrain_3d/editor.gd b/project/addons/terrain_3d/editor.gd index b01ac3460..557d111be 100644 --- a/project/addons/terrain_3d/editor.gd +++ b/project/addons/terrain_3d/editor.gd @@ -31,6 +31,9 @@ func _enter_tree() -> void: editor = Terrain3DEditor.new() editor_settings = EditorInterface.get_editor_settings() _cleanup_editor_settings() + # Initialize the new key binding option + if not editor_settings.has_setting("config/alternate_key_binding"): + editor_settings.set_setting("config/alternate_key_binding", false) ui = UI.new() ui.plugin = self add_child(ui) From 09544e3a8d0ee9281daa4d39f75bd9c1ac810c8c Mon Sep 17 00:00:00 2001 From: Cory Petkovsek <632766+TokisanGames@users.noreply.github.com> Date: Mon, 21 Oct 2024 15:37:02 +0700 Subject: [PATCH 2/4] Reorganize modifier & settings code --- project/addons/terrain_3d/editor.gd | 63 ++++++++++++++-- project/addons/terrain_3d/src/ui.gd | 109 ++++++++++------------------ 2 files changed, 94 insertions(+), 78 deletions(-) diff --git a/project/addons/terrain_3d/editor.gd b/project/addons/terrain_3d/editor.gd index 557d111be..aaa6d9266 100644 --- a/project/addons/terrain_3d/editor.gd +++ b/project/addons/terrain_3d/editor.gd @@ -8,6 +8,16 @@ const UI: Script = preload("res://addons/terrain_3d/src/ui.gd") const RegionGizmo: Script = preload("res://addons/terrain_3d/src/region_gizmo.gd") const ASSET_DOCK: String = "res://addons/terrain_3d/src/asset_dock.tscn" +const MODIFIER_KEYS := [KEY_SHIFT, KEY_CTRL, KEY_ALT] +const M_SHIFT: int = 0x1 +const M_CTRL: int = 0x2 +const M_ALT: int = 0x4 + +var modifier_ctrl: bool +var modifier_alt: bool +var modifier_shift: bool +var _last_modifiers: int = 0 + var terrain: Terrain3D var _last_terrain: Terrain3D var nav_region: NavigationRegion3D @@ -25,15 +35,12 @@ var godot_editor_window: Window # The Godot Editor window func _init() -> void: # Get the Godot Editor window. Structure is root:Window/EditorNode/Base Control godot_editor_window = EditorInterface.get_base_control().get_parent().get_parent() + godot_editor_window.focus_entered.connect(_on_godot_focus_entered) func _enter_tree() -> void: editor = Terrain3DEditor.new() - editor_settings = EditorInterface.get_editor_settings() - _cleanup_editor_settings() - # Initialize the new key binding option - if not editor_settings.has_setting("config/alternate_key_binding"): - editor_settings.set_setting("config/alternate_key_binding", false) + setup_editor_settings() ui = UI.new() ui.plugin = self add_child(ui) @@ -53,6 +60,12 @@ func _exit_tree() -> void: editor.free() scene_changed.disconnect(_on_scene_changed) + godot_editor_window.focus_entered.disconnect(_on_godot_focus_entered) + + +func _on_godot_focus_entered() -> void: + update_modifiers() + ui.update_decal() ## EditorPlugin selection function call chain isn't consistent. Here's the map of calls: @@ -144,7 +157,7 @@ func _forward_3d_gui_input(p_viewport_camera: Camera3D, p_event: InputEvent) -> if not is_terrain_valid(): return AFTER_GUI_INPUT_PASS - ui.update_modifiers() + update_modifiers() ## Handle mouse movement if p_event is InputEventMouseMotion: @@ -242,6 +255,30 @@ func _forward_3d_gui_input(p_viewport_camera: Camera3D, p_event: InputEvent) -> return AFTER_GUI_INPUT_PASS +func update_modifiers() -> void: + var current_mods: int = 0 + for i in MODIFIER_KEYS.size(): + if Input.is_key_pressed(MODIFIER_KEYS[i]): + current_mods |= 1 << i + + # Return if modifiers haven't changed AND brush_data has them; + # modifiers disappear from brush_data when clicking asset_dock (Why?) + if _last_modifiers == current_mods and ui.brush_data.has("modifier_shift"): + return + + modifier_shift = bool(current_mods & M_SHIFT) + ui.brush_data["modifier_shift"] = modifier_shift + + modifier_ctrl = bool(current_mods & M_CTRL) + ui.brush_data["modifier_ctrl"] = modifier_ctrl + + modifier_alt = bool(current_mods & M_ALT) + ui.brush_data["modifier_alt"] = modifier_alt + + _last_modifiers = current_mods + ui.update_modifiers() + + func update_region_grid() -> void: if not region_gizmo: return @@ -301,8 +338,20 @@ func select_terrain() -> void: es.add_node(_last_terrain) +## Editor Settings + + +func setup_editor_settings() -> void: + editor_settings = EditorInterface.get_editor_settings() + # Initialize the new key binding option + if not editor_settings.has_setting("terrain3d/config/alternate_key_binding"): + editor_settings.set_setting("terrain3d/config/alternate_key_binding", false) + + _cleanup_old_settings() + + # Remove or rename old settings -func _cleanup_editor_settings() -> void: +func _cleanup_old_settings() -> void: # Rename deprecated settings - Remove in 1.0 var value: Variant var rename_arr := [ "terrain3d/config/dock_slot", "terrain3d/config/dock_tile_size", diff --git a/project/addons/terrain_3d/src/ui.gd b/project/addons/terrain_3d/src/ui.gd index 643ea144d..696a148f0 100644 --- a/project/addons/terrain_3d/src/ui.gd +++ b/project/addons/terrain_3d/src/ui.gd @@ -26,10 +26,6 @@ const COLOR_PICK_COLOR := Color.WHITE const COLOR_PICK_HEIGHT := Color.DARK_RED const COLOR_PICK_ROUGH := Color.ROYAL_BLUE -const MODIFIER_KEYS := [KEY_SHIFT, KEY_CTRL, KEY_ALT] -const M_SHIFT: int = 0x1 -const M_CTRL: int = 0x2 -const M_ALT: int = 0x4 const OP_NONE: int = 0x0 const OP_POSITIVE_ONLY: int = 0x01 const OP_NEGATIVE_ONLY: int = 0x02 @@ -50,13 +46,9 @@ var decal_timer: Timer var gradient_decals: Array[Decal] var brush_data: Dictionary var operation_builder: OperationBuilder -var modifiers: int = 0 -var modifier_ctrl: bool -var modifier_alt: bool -var modifier_shift: bool var last_tool: Terrain3DEditor.Tool var last_operation: Terrain3DEditor.Operation -var last_rmb_time: int = 0 +var last_rmb_time: int = 0 # Set in editor.gd # Compatibility decals, indices; 0 = main brush, 1 = slope point A, 2 = slope point B var editor_decal_position: Array[Vector2] @@ -96,7 +88,6 @@ func _enter_tree() -> void: if node: get_tree().create_tween().tween_property(node, "albedo_mix", 0.0, 0.15)).bind(decal)) add_child(decal_timer) - plugin.godot_editor_window.focus_entered.connect(_on_godot_focus_entered) func _exit_tree() -> void: @@ -110,12 +101,6 @@ func _exit_tree() -> void: for gradient_decal in gradient_decals: gradient_decal.queue_free() gradient_decals.clear() - plugin.godot_editor_window.focus_entered.disconnect(_on_godot_focus_entered) - - -func _on_godot_focus_entered() -> void: - update_modifiers() - update_decal() func set_visible(p_visible: bool, p_menu_only: bool = false) -> void: @@ -278,6 +263,41 @@ func _on_setting_changed() -> void: plugin.editor.set_operation(_modify_operation(plugin.editor.get_operation())) +func update_modifiers() -> void: + toolbar.show_add_buttons(not plugin.modifier_ctrl) + + if plugin.modifier_shift and not plugin.modifier_ctrl: + plugin.editor.set_tool(Terrain3DEditor.SCULPT) + plugin.editor.set_operation(Terrain3DEditor.AVERAGE) + else: + plugin.editor.set_tool(last_tool) + if plugin.modifier_ctrl: + plugin.editor.set_operation(_modify_operation(last_operation)) + else: + plugin.editor.set_operation(last_operation) + + +func _modify_operation(p_operation: Terrain3DEditor.Operation) -> Terrain3DEditor.Operation: + var remove_checked: bool = false + if DisplayServer.is_touchscreen_available(): + var removable_tools := [Terrain3DEditor.REGION, Terrain3DEditor.SCULPT, Terrain3DEditor.HEIGHT, Terrain3DEditor.AUTOSHADER, + Terrain3DEditor.HOLES, Terrain3DEditor.INSTANCER, Terrain3DEditor.NAVIGATION, + Terrain3DEditor.COLOR, Terrain3DEditor.ROUGHNESS] + remove_checked = brush_data.get("remove", false) && plugin.editor.get_tool() in removable_tools + + if plugin.modifier_ctrl or remove_checked: + return _invert_operation(p_operation, OP_NEGATIVE_ONLY) + return _invert_operation(p_operation, OP_POSITIVE_ONLY) + + +func _invert_operation(p_operation: Terrain3DEditor.Operation, flags: int = OP_NONE) -> Terrain3DEditor.Operation: + if p_operation == Terrain3DEditor.ADD and ! (flags & OP_POSITIVE_ONLY): + return Terrain3DEditor.SUBTRACT + elif p_operation == Terrain3DEditor.SUBTRACT and ! (flags & OP_NEGATIVE_ONLY): + return Terrain3DEditor.ADD + return p_operation + + func update_decal() -> void: var mouse_buttons: int = Input.get_mouse_button_mask() @@ -323,14 +343,14 @@ func update_decal() -> void: Terrain3DEditor.SCULPT: match plugin.editor.get_operation(): Terrain3DEditor.ADD: - if modifier_alt: + if plugin.modifier_alt: decal.modulate = COLOR_LIFT decal.modulate.a = clamp(brush_data["strength"], .2, .5) else: decal.modulate = COLOR_RAISE decal.modulate.a = clamp(brush_data["strength"], .2, .5) Terrain3DEditor.SUBTRACT: - if modifier_alt: + if plugin.modifier_alt: decal.modulate = COLOR_FLATTEN decal.modulate.a = clamp(brush_data["strength"], .2, .5) else: @@ -512,58 +532,5 @@ func pick(p_global_position: Vector3) -> void: operation_builder.pick(p_global_position, plugin.terrain) -func update_modifiers() -> void: - # Return if modifiers haven't changed; modifiers disappear when clicking asset_dock - var current_mods: int = 0 - for i in MODIFIER_KEYS.size(): - if Input.is_key_pressed(MODIFIER_KEYS[i]): - current_mods |= 1 << i - if modifiers == current_mods and brush_data.has("modifier_shift"): - return - - modifier_shift = bool(current_mods & M_SHIFT) - brush_data["modifier_shift"] = modifier_shift - - modifier_ctrl = bool(current_mods & M_CTRL) - brush_data["modifier_ctrl"] = modifier_ctrl - toolbar.show_add_buttons(!modifier_ctrl) - - modifier_alt = bool(current_mods & M_ALT) - brush_data["modifier_alt"] = modifier_alt - - if modifier_shift and not modifier_ctrl: - plugin.editor.set_tool(Terrain3DEditor.SCULPT) - plugin.editor.set_operation(Terrain3DEditor.AVERAGE) - else: - plugin.editor.set_tool(last_tool) - if modifier_ctrl: - plugin.editor.set_operation(_modify_operation(last_operation)) - else: - plugin.editor.set_operation(last_operation) - - modifiers = current_mods - - -func _modify_operation(p_operation: Terrain3DEditor.Operation) -> Terrain3DEditor.Operation: - var remove_checked: bool = false - if DisplayServer.is_touchscreen_available(): - var removable_tools := [Terrain3DEditor.REGION, Terrain3DEditor.SCULPT, Terrain3DEditor.HEIGHT, Terrain3DEditor.AUTOSHADER, - Terrain3DEditor.HOLES, Terrain3DEditor.INSTANCER, Terrain3DEditor.NAVIGATION, - Terrain3DEditor.COLOR, Terrain3DEditor.ROUGHNESS] - remove_checked = brush_data.get("remove", false) && plugin.editor.get_tool() in removable_tools - - if modifier_ctrl or remove_checked: - return _invert_operation(p_operation, OP_NEGATIVE_ONLY) - return _invert_operation(p_operation, OP_POSITIVE_ONLY) - - -func _invert_operation(p_operation: Terrain3DEditor.Operation, flags: int = OP_NONE) -> Terrain3DEditor.Operation: - if p_operation == Terrain3DEditor.ADD and ! (flags & OP_POSITIVE_ONLY): - return Terrain3DEditor.SUBTRACT - elif p_operation == Terrain3DEditor.SUBTRACT and ! (flags & OP_NEGATIVE_ONLY): - return Terrain3DEditor.ADD - return p_operation - - func set_button_editor_icon(p_button: Button, p_icon_name: String) -> void: p_button.icon = EditorInterface.get_base_control().get_theme_icon(p_icon_name, "EditorIcons") From 07d6c8648e8c99fa8b4db02a7774b98a56c39ee2 Mon Sep 17 00:00:00 2001 From: Cory Petkovsek <632766+TokisanGames@users.noreply.github.com> Date: Mon, 21 Oct 2024 22:24:26 +0700 Subject: [PATCH 3/4] Add alternate ALT keybinds --- project/addons/terrain_3d/editor.gd | 169 +++++++++++++++------------- project/addons/terrain_3d/src/ui.gd | 29 +++-- 2 files changed, 107 insertions(+), 91 deletions(-) diff --git a/project/addons/terrain_3d/editor.gd b/project/addons/terrain_3d/editor.gd index aaa6d9266..0a81a1ed3 100644 --- a/project/addons/terrain_3d/editor.gd +++ b/project/addons/terrain_3d/editor.gd @@ -8,15 +8,11 @@ const UI: Script = preload("res://addons/terrain_3d/src/ui.gd") const RegionGizmo: Script = preload("res://addons/terrain_3d/src/region_gizmo.gd") const ASSET_DOCK: String = "res://addons/terrain_3d/src/asset_dock.tscn" -const MODIFIER_KEYS := [KEY_SHIFT, KEY_CTRL, KEY_ALT] -const M_SHIFT: int = 0x1 -const M_CTRL: int = 0x2 -const M_ALT: int = 0x4 - var modifier_ctrl: bool var modifier_alt: bool var modifier_shift: bool var _last_modifiers: int = 0 +var _input_mode: int = 0 # -1: camera move, 0: none, 1: operating var terrain: Terrain3D var _last_terrain: Terrain3D @@ -64,7 +60,7 @@ func _exit_tree() -> void: func _on_godot_focus_entered() -> void: - update_modifiers() + _read_input() ui.update_decal() @@ -157,15 +153,12 @@ func _forward_3d_gui_input(p_viewport_camera: Camera3D, p_event: InputEvent) -> if not is_terrain_valid(): return AFTER_GUI_INPUT_PASS - update_modifiers() + _read_input(p_event) ## Handle mouse movement if p_event is InputEventMouseMotion: - if Input.is_mouse_button_pressed(MOUSE_BUTTON_RIGHT): - return AFTER_GUI_INPUT_PASS + ## Setup active camera & viewport - ## Setup for active camera & viewport - # Snap terrain to current camera terrain.set_camera(p_viewport_camera) @@ -192,90 +185,108 @@ func _forward_3d_gui_input(p_viewport_camera: Camera3D, p_event: InputEvent) -> return AFTER_GUI_INPUT_STOP mouse_global_position = intersection_point - ## Update decal - ui.decal.global_position = mouse_global_position ui.update_decal() - ## Update region highlight - var region_position: Vector2 = ( Vector2(mouse_global_position.x, mouse_global_position.z) \ - / (terrain.get_region_size() * terrain.get_vertex_spacing()) ).floor() - if current_region_position != region_position: - current_region_position = region_position - update_region_grid() + if _input_mode != -1: # Not cam rotation + ## Update region highlight + var region_position: Vector2 = ( Vector2(mouse_global_position.x, mouse_global_position.z) \ + / (terrain.get_region_size() * terrain.get_vertex_spacing()) ).floor() + if current_region_position != region_position: + current_region_position = region_position + update_region_grid() - # Inject pressure - Relies on C++ set_brush_data() using same dictionary instance - ui.brush_data["mouse_pressure"] = p_event.pressure - - if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT) and editor.is_operating(): - editor.operate(mouse_global_position, p_viewport_camera.rotation.y) - return AFTER_GUI_INPUT_STOP + if _input_mode > 0 and editor.is_operating(): + # Inject pressure - Relies on C++ set_brush_data() using same dictionary instance + ui.brush_data["mouse_pressure"] = p_event.pressure - elif p_event is InputEventMouseButton: - if p_event.get_button_index() == MOUSE_BUTTON_RIGHT and p_event.is_released(): - ui.last_rmb_time = Time.get_ticks_msec() - ui.update_decal() + editor.operate(mouse_global_position, p_viewport_camera.rotation.y) + return AFTER_GUI_INPUT_STOP - if p_event.get_button_index() == MOUSE_BUTTON_LEFT: - if p_event.is_pressed(): - if Input.is_mouse_button_pressed(MOUSE_BUTTON_RIGHT): + return AFTER_GUI_INPUT_PASS + + ui.update_decal() + + if p_event is InputEventMouseButton and _input_mode > 0: + if p_event.is_pressed(): + # If picking + if ui.is_picking(): + ui.pick(mouse_global_position) + if not ui.operation_builder or not ui.operation_builder.is_ready(): return AFTER_GUI_INPUT_STOP - - # If picking - if ui.is_picking(): - ui.pick(mouse_global_position) - if not ui.operation_builder or not ui.operation_builder.is_ready(): - return AFTER_GUI_INPUT_STOP - - # If adjusting regions - if editor.get_tool() == Terrain3DEditor.REGION: - # Skip regions that already exist or don't - var has_region: bool = terrain.data.has_regionp(mouse_global_position) - var op: int = editor.get_operation() - if ( has_region and op == Terrain3DEditor.ADD) or \ - ( not has_region and op == Terrain3DEditor.SUBTRACT ): - return AFTER_GUI_INPUT_STOP - - # If an automatic operation is ready to go (e.g. gradient) - if ui.operation_builder and ui.operation_builder.is_ready(): - ui.operation_builder.apply_operation(editor, mouse_global_position, p_viewport_camera.rotation.y) + + # If adjusting regions + if editor.get_tool() == Terrain3DEditor.REGION: + # Skip regions that already exist or don't + var has_region: bool = terrain.data.has_regionp(mouse_global_position) + var op: int = editor.get_operation() + if ( has_region and op == Terrain3DEditor.ADD) or \ + ( not has_region and op == Terrain3DEditor.SUBTRACT ): return AFTER_GUI_INPUT_STOP - - # Mouse clicked, start editing - editor.start_operation(mouse_global_position) - editor.operate(mouse_global_position, p_viewport_camera.rotation.y) - return AFTER_GUI_INPUT_STOP - elif editor.is_operating(): - # Mouse released, save undo data - editor.stop_operation() + # If an automatic operation is ready to go (e.g. gradient) + if ui.operation_builder and ui.operation_builder.is_ready(): + ui.operation_builder.apply_operation(editor, mouse_global_position, p_viewport_camera.rotation.y) return AFTER_GUI_INPUT_STOP + + # Mouse clicked, start editing + editor.start_operation(mouse_global_position) + editor.operate(mouse_global_position, p_viewport_camera.rotation.y) + return AFTER_GUI_INPUT_STOP + + # _input_apply released, save undo data + elif editor.is_operating(): + editor.stop_operation() + return AFTER_GUI_INPUT_STOP - # Key presses - ui.update_decal() return AFTER_GUI_INPUT_PASS -func update_modifiers() -> void: - var current_mods: int = 0 - for i in MODIFIER_KEYS.size(): - if Input.is_key_pressed(MODIFIER_KEYS[i]): - current_mods |= 1 << i +func _read_input(p_event: InputEvent = null) -> void: + ## Determine if user is moving camera or applying + _input_mode = 1 if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT) else 0 + + match get_setting("editors/3d/navigation/navigation_scheme", 0): + 2, 1: # Modo, Maya + if Input.is_mouse_button_pressed(MOUSE_BUTTON_RIGHT) or \ + ( Input.is_key_pressed(KEY_ALT) and Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT) ): + _input_mode = -1 + if p_event is InputEventMouseButton and p_event.is_released() and \ + ( p_event.get_button_index() == MOUSE_BUTTON_RIGHT or \ + ( Input.is_key_pressed(KEY_ALT) and p_event.get_button_index() == MOUSE_BUTTON_LEFT )): + ui.last_rmb_time = Time.get_ticks_msec() + 0, _: # Godot + if Input.is_mouse_button_pressed(MOUSE_BUTTON_RIGHT) or \ + Input.is_mouse_button_pressed(MOUSE_BUTTON_MIDDLE): + _input_mode = -1 + if p_event is InputEventMouseButton and p_event.is_released() and \ + ( p_event.get_button_index() == MOUSE_BUTTON_RIGHT or \ + p_event.get_button_index() == MOUSE_BUTTON_MIDDLE ): + ui.last_rmb_time = Time.get_ticks_msec() + if _input_mode < 0: + return + + ## Determine modifiers pressed + modifier_shift = Input.is_key_pressed(KEY_SHIFT) + modifier_ctrl = Input.is_key_pressed(KEY_CTRL) + # Keybind enum: Alt,Space,Meta,Capslock + var alt_key: int + match get_setting("terrain3d/config/alt_key_bind", 0): + 3: alt_key = KEY_CAPSLOCK + 2: alt_key = KEY_META + 1: alt_key = KEY_SPACE + 0, _: alt_key = KEY_ALT + modifier_alt = Input.is_key_pressed(alt_key) # Return if modifiers haven't changed AND brush_data has them; # modifiers disappear from brush_data when clicking asset_dock (Why?) + var current_mods: int = int(modifier_shift) | int(modifier_ctrl) << 1 | int(modifier_alt) << 2 if _last_modifiers == current_mods and ui.brush_data.has("modifier_shift"): return - modifier_shift = bool(current_mods & M_SHIFT) + _last_modifiers = current_mods ui.brush_data["modifier_shift"] = modifier_shift - - modifier_ctrl = bool(current_mods & M_CTRL) ui.brush_data["modifier_ctrl"] = modifier_ctrl - - modifier_alt = bool(current_mods & M_ALT) ui.brush_data["modifier_alt"] = modifier_alt - - _last_modifiers = current_mods ui.update_modifiers() @@ -343,9 +354,15 @@ func select_terrain() -> void: func setup_editor_settings() -> void: editor_settings = EditorInterface.get_editor_settings() - # Initialize the new key binding option - if not editor_settings.has_setting("terrain3d/config/alternate_key_binding"): - editor_settings.set_setting("terrain3d/config/alternate_key_binding", false) + if not editor_settings.has_setting("terrain3d/config/alt_key_bind"): + editor_settings.set("terrain3d/config/alt_key_bind", 0) + var property_info = { + "name": "terrain3d/config/alt_key_bind", + "type": TYPE_INT, + "hint": PROPERTY_HINT_ENUM, + "hint_string": "Alt,Space,Meta,Capslock" + } + editor_settings.add_property_info(property_info) _cleanup_old_settings() diff --git a/project/addons/terrain_3d/src/ui.gd b/project/addons/terrain_3d/src/ui.gd index 696a148f0..c5772edb6 100644 --- a/project/addons/terrain_3d/src/ui.gd +++ b/project/addons/terrain_3d/src/ui.gd @@ -299,23 +299,22 @@ func _invert_operation(p_operation: Terrain3DEditor.Operation, flags: int = OP_N func update_decal() -> void: - var mouse_buttons: int = Input.get_mouse_button_mask() - # If not a state that should show the decal, hide everything and return if not visible or \ - not plugin.terrain or \ - # Wait for cursor to recenter after right-click before revealing - # See https://github.com/godotengine/godot/issues/70098 - Time.get_ticks_msec() - last_rmb_time <= 10 or \ - brush_data.is_empty() or \ - mouse_buttons & MOUSE_BUTTON_RIGHT or \ - (mouse_buttons & MOUSE_BUTTON_LEFT and not brush_data["show_cursor_while_painting"]) or \ - plugin.editor.get_tool() == Terrain3DEditor.REGION: - decal.visible = false - for gradient_decal in gradient_decals: - gradient_decal.visible = false - return - + not plugin.terrain or \ + plugin._input_mode < 0 or \ + # Wait for cursor to recenter after moving camera before revealing + # See https://github.com/godotengine/godot/issues/70098 + Time.get_ticks_msec() - last_rmb_time <= 30 or \ + brush_data.is_empty() or \ + plugin.editor.get_tool() == Terrain3DEditor.REGION or \ + (plugin._input_mode > 0 and not brush_data["show_cursor_while_painting"]): + decal.visible = false + for gradient_decal in gradient_decals: + gradient_decal.visible = false + return + + decal.position = plugin.mouse_global_position decal.visible = true decal.size = Vector3.ONE * brush_data["size"] if brush_data["align_to_view"]: From 79e2e79754adf8991f8a0009f388737a57a22d71 Mon Sep 17 00:00:00 2001 From: Cory Petkovsek <632766+TokisanGames@users.noreply.github.com> Date: Mon, 21 Oct 2024 22:51:14 +0700 Subject: [PATCH 4/4] Update docs --- AUTHORS.md | 4 +++- doc/api/class_terrain3dassets.rst | 4 ++-- doc/api/class_terrain3dinstancer.rst | 2 +- doc/api/class_terrain3dmaterial.rst | 28 ++++++++++++------------- doc/classes/Terrain3DAssets.xml | 3 ++- doc/classes/Terrain3DMaterial.xml | 3 ++- doc/docs/games.md | 1 + doc/docs/user_interface.md | 31 ++++++++++++++++------------ 8 files changed, 43 insertions(+), 33 deletions(-) diff --git a/AUTHORS.md b/AUTHORS.md index e4dcb426e..e7f20c544 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -23,4 +23,6 @@ Contributors * Raven [@az-raven](https://github.com/az-raven) * Ryan [@Ryan-000](https://github.com/Ryan-000) * Malido [@Malidos](https://github.com/Malidos) -* Sven Cannivy [@svencan](https://github.com/svencan) \ No newline at end of file +* Sven Cannivy [@svencan](https://github.com/svencan) +* Scott Davis [@scottdavis](https://github.com/scottdavis) +* [@jesus-g20](https://github.com/jesus-g20) \ No newline at end of file diff --git a/doc/api/class_terrain3dassets.rst b/doc/api/class_terrain3dassets.rst index 777e7ff9f..b5462298c 100644 --- a/doc/api/class_terrain3dassets.rst +++ b/doc/api/class_terrain3dassets.rst @@ -62,7 +62,7 @@ Methods +-----------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | :ref:`PackedFloat32Array` | :ref:`get_texture_uv_scales`\ (\ ) |const| | +-----------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | |void| | :ref:`save`\ (\ ) | + | :ref:`Error` | :ref:`save`\ (\ path\: :ref:`String` = ""\ ) | +-----------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | |void| | :ref:`set_mesh_asset`\ (\ id\: :ref:`int`, mesh\: :ref:`Terrain3DMeshAsset`\ ) | +-----------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ @@ -330,7 +330,7 @@ Returns the array of all uv scale values used in the texture assets, indexed by .. rst-class:: classref-method -|void| **save**\ (\ ) :ref:`🔗` +:ref:`Error` **save**\ (\ path\: :ref:`String` = ""\ ) :ref:`🔗` Saves this texture list resource to disk, if saved as an external ``.tres`` or ``.res`` resource file. diff --git a/doc/api/class_terrain3dinstancer.rst b/doc/api/class_terrain3dinstancer.rst index 4b8326bd8..ecae8ca84 100644 --- a/doc/api/class_terrain3dinstancer.rst +++ b/doc/api/class_terrain3dinstancer.rst @@ -90,7 +90,7 @@ Method Descriptions |void| **add_instances**\ (\ global_position\: :ref:`Vector3`, params\: :ref:`Dictionary`\ ) :ref:`🔗` -Used by Terrain3DEditor to place instances given many brush parameters. In addition to the brush position, it also uses the following parameters: asset_id, size, strength, fixed_scale, random_scale, fixed_spin, random_spin, fixed_angle, random_angle, align_to_normal, height_offset, random_height, vertex_color, random_hue, random_darken. All of these settings are set in the editor through tool_settings.gd. +Used by Terrain3DEditor to place instances given many brush parameters. In addition to the brush position, it also uses the following parameters: asset_id, size, strength, fixed_scale, random_scale, fixed_spin, random_spin, fixed_tilt, random_tilt, align_to_normal, height_offset, random_height, vertex_color, random_hue, random_darken. All of these settings are set in the editor through tool_settings.gd. .. rst-class:: classref-item-separator diff --git a/doc/api/class_terrain3dmaterial.rst b/doc/api/class_terrain3dmaterial.rst index 1c2768eae..d2b14c60b 100644 --- a/doc/api/class_terrain3dmaterial.rst +++ b/doc/api/class_terrain3dmaterial.rst @@ -89,19 +89,19 @@ Methods .. table:: :widths: auto - +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | :ref:`RID` | :ref:`get_material_rid`\ (\ ) |const| | - +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | :ref:`Variant` | :ref:`get_shader_param`\ (\ name\: :ref:`StringName`\ ) |const| | - +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | :ref:`RID` | :ref:`get_shader_rid`\ (\ ) |const| | - +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | |void| | :ref:`save`\ (\ ) | - +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | |void| | :ref:`set_shader_param`\ (\ name\: :ref:`StringName`, value\: :ref:`Variant`\ ) | - +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | |void| | :ref:`update`\ (\ ) | - +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +---------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | :ref:`RID` | :ref:`get_material_rid`\ (\ ) |const| | + +---------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | :ref:`Variant` | :ref:`get_shader_param`\ (\ name\: :ref:`StringName`\ ) |const| | + +---------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | :ref:`RID` | :ref:`get_shader_rid`\ (\ ) |const| | + +---------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | :ref:`Error` | :ref:`save`\ (\ path\: :ref:`String` = ""\ ) | + +---------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | |void| | :ref:`set_shader_param`\ (\ name\: :ref:`StringName`, value\: :ref:`Variant`\ ) | + +---------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | |void| | :ref:`update`\ (\ ) | + +---------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ .. rst-class:: classref-section-separator @@ -610,7 +610,7 @@ Returns the RID of the built in shader used with the Rendering Server. This is d .. rst-class:: classref-method -|void| **save**\ (\ ) :ref:`🔗` +:ref:`Error` **save**\ (\ path\: :ref:`String` = ""\ ) :ref:`🔗` Saves this material resource to disk, if saved as an external ``.tres`` or ``.res`` resource file. diff --git a/doc/classes/Terrain3DAssets.xml b/doc/classes/Terrain3DAssets.xml index 6c7c6604c..650556454 100644 --- a/doc/classes/Terrain3DAssets.xml +++ b/doc/classes/Terrain3DAssets.xml @@ -73,7 +73,8 @@ - + + Saves this texture list resource to disk, if saved as an external [code skip-lint].tres[/code] or [code skip-lint].res[/code] resource file. diff --git a/doc/classes/Terrain3DMaterial.xml b/doc/classes/Terrain3DMaterial.xml index 6bb43763e..17286baaa 100644 --- a/doc/classes/Terrain3DMaterial.xml +++ b/doc/classes/Terrain3DMaterial.xml @@ -31,7 +31,8 @@ - + + Saves this material resource to disk, if saved as an external [code skip-lint].tres[/code] or [code skip-lint].res[/code] resource file. diff --git a/doc/docs/games.md b/doc/docs/games.md index 53f4d45f5..6a4ae2603 100644 --- a/doc/docs/games.md +++ b/doc/docs/games.md @@ -11,6 +11,7 @@ Terrain3D is being used in the following games. To add yours, submit it to the # | [RotorSim](https://immaculate-lift-studio.itch.io/godot-flight-simulator-alpha) | [Immaculate Lift](https://www.youtube.com/channel/UC-9JixNs1FFE6T5DGwZ6O5Q) | Retro helicopter simulation | [B&E Ski](https://www.youtube.com/watch?v=pD8Ea3utz9o) | [Penguin Milk](https://bande.ski/) | Skiing game | [Sacred Forest](https://store.steampowered.com/app/2864350/Sacred_Forest/) | [Blekoh](https://www.youtube.com/@sacredforestgame) | Open world 3D pixel art RPG +| [Pest Apocalypse](https://store.steampowered.com/app/2506810/Pest_Apocalypse/) | [Kikimora Games](https://x.com/KikimoraGames) | Post-apocalyptic pizza delivery ## Tech Demos diff --git a/doc/docs/user_interface.md b/doc/docs/user_interface.md index bce9481df..bc316554d 100644 --- a/doc/docs/user_interface.md +++ b/doc/docs/user_interface.md @@ -21,39 +21,44 @@ The tools provide options for sculpting, texturing, and other features. Each but First, select the Region Tool (first one: square with a cross), and click the ground. This allocates space for you to sculpt and paint. +--- + ## Keyboard Shortcuts The following mouse and keyboard shortcuts are available. -*Note*: Touchscreen users will see an `Invert` checkbox on the settings bar which acts like Ctrl to inverse operations. +**Maya Users:** The Alt key can be changed to Space, Meta (Windows), or Capslock in `Editor Settings / Terrain3D / Config / Alt Key Bind` so it does not conflict with Maya input settings `Editor Settings / 3D / Navigation / Navigation Scheme`. -*Note*: If the "Alternate Key Bindings" option is enabled in the editor settings, RMB (Right Mouse Button) replaces the default Alt + LMB behavior. This allows sculpting operations to be performed with RMB. +**Touchscreen Users:** will see an `Invert` checkbox on the settings bar which acts like Ctrl to inverse operations. ### General Keys * LMB - Click the terrain to positively apply the current tool. * Ctrl + LMB - **Inverse** the tool. Removes regions, height, color, wetness, autoshader, holes, navigation, foliage. -* Shift + LMB - Change to the **Smooth** sculpting tool if shift is the _only_ modifier pressed. -* Ctrl + Z - Undo. You can also view the operations in Godot's `History` panel. -* Ctrl + Shift + Z - Redo. -* Ctrl + S - Save the scene and all data. +* Shift + LMB - Change to the **Smooth** sculpting tool. +* Ctrl + Z - **Undo**. You can view the entries in the Godot `History` panel. +* Ctrl + Shift + Z - **Redo**. +* Ctrl + S - **Save** the scene and all data. ### Sculpting Specific -* Alt + LMB - **Lift floors**. This lifts up lower portions of the terrain without affecting higher terrain around it. Use it along the bottom of cliff faces. See [videos demonstrating before and after](https://github.com/TokisanGames/Terrain3D/pull/409). +* Alt + LMB - **Lift floors**. This lifts up lower portions of the terrain without affecting higher terrain. Use it along the bottom of cliff faces. See [videos demonstrating before and after](https://github.com/TokisanGames/Terrain3D/pull/409). * Ctrl + Alt + LMB - **Flatten peaks**. The inverse of the above. This reduces peaks and ridges without affecting lower terrain around it. -### Slope Operations Specific +### Slope Filter + +The slope filter on the bottom settings bar limits operations based on terrain slope. Don't confuse this with the slope sculpting tool on the left toolbar. -These operations support slope: **Paint**, **Spray**, **Color**, **Wetness**, **Instancer**. +These operations support filtering by slope: **Paint**, **Spray**, **Color**, **Wetness**, **Instancer**. -* LMB - Operate within the set slope. -* Alt + LMB - Operate outside the set slope. -* Ctrl + Alt + LMB - Inversely operate outside the set slope. eg. Remove color or foliage outside the defined slope setting. +* LMB - Add within the defined slope. +* Ctrl + LMB - Remove within the defined slope. +* Alt + LMB - Add outside the defined slope. +* Ctrl + Alt + LMB - Remove operate outside the defined slope. ### Instancer Specific * LMB - Add the selected mesh instance to the terrain. * Ctrl + LMB - Remove instances of the selected type. -* Ctrl + Shift + LMB - Remove instances of any type. +* Ctrl + Shift + LMB - Remove instances of **any** type. ---