From 4bfbf641dc2b8aca8de9f86a9908063f39bd6e31 Mon Sep 17 00:00:00 2001 From: jacopograndi Date: Fri, 14 Jan 2022 13:04:34 +0100 Subject: . --- .../addons/voxel-core/engine/importers/meshes.gd | 108 +++ .../voxel-core/engine/importers/voxel_objects.gd | 112 +++ .../voxel-core/engine/importers/voxel_sets.gd | 66 ++ .../engine/voxel_object_editor/config.var | Bin 0 -> 316 bytes .../editor_selection/editor_selection.gd | 17 + .../editor_selection/editor_selections/area.gd | 39 + .../editor_selection/editor_selections/extrude.gd | 69 ++ .../editor_selections/individual.gd | 27 + .../voxel_object_editor/editor_tool/editor_tool.gd | 29 + .../editor_tool/editor_tools/add.gd | 49 + .../editor_tool/editor_tools/fill.gd | 42 + .../editor_tool/editor_tools/pick.gd | 21 + .../editor_tool/editor_tools/sub.gd | 42 + .../editor_tool/editor_tools/swap.gd | 45 + .../voxel_cursor/voxel_cursor.gd | 112 +++ .../voxel_object_editor/voxel_grid/voxel_grid.gd | 113 +++ .../voxel_object_editor/voxel_object_editor.gd | 866 +++++++++++++++++ .../voxel_object_editor/voxel_object_editor.tscn | 1011 ++++++++++++++++++++ .../engine/voxel_set_editor/voxel_set_editor.gd | 210 ++++ .../engine/voxel_set_editor/voxel_set_editor.tscn | 257 +++++ 20 files changed, 3235 insertions(+) create mode 100644 assets/addons/voxel-core/engine/importers/meshes.gd create mode 100644 assets/addons/voxel-core/engine/importers/voxel_objects.gd create mode 100644 assets/addons/voxel-core/engine/importers/voxel_sets.gd create mode 100644 assets/addons/voxel-core/engine/voxel_object_editor/config.var create mode 100644 assets/addons/voxel-core/engine/voxel_object_editor/editor_selection/editor_selection.gd create mode 100644 assets/addons/voxel-core/engine/voxel_object_editor/editor_selection/editor_selections/area.gd create mode 100644 assets/addons/voxel-core/engine/voxel_object_editor/editor_selection/editor_selections/extrude.gd create mode 100644 assets/addons/voxel-core/engine/voxel_object_editor/editor_selection/editor_selections/individual.gd create mode 100644 assets/addons/voxel-core/engine/voxel_object_editor/editor_tool/editor_tool.gd create mode 100644 assets/addons/voxel-core/engine/voxel_object_editor/editor_tool/editor_tools/add.gd create mode 100644 assets/addons/voxel-core/engine/voxel_object_editor/editor_tool/editor_tools/fill.gd create mode 100644 assets/addons/voxel-core/engine/voxel_object_editor/editor_tool/editor_tools/pick.gd create mode 100644 assets/addons/voxel-core/engine/voxel_object_editor/editor_tool/editor_tools/sub.gd create mode 100644 assets/addons/voxel-core/engine/voxel_object_editor/editor_tool/editor_tools/swap.gd create mode 100644 assets/addons/voxel-core/engine/voxel_object_editor/voxel_cursor/voxel_cursor.gd create mode 100644 assets/addons/voxel-core/engine/voxel_object_editor/voxel_grid/voxel_grid.gd create mode 100644 assets/addons/voxel-core/engine/voxel_object_editor/voxel_object_editor.gd create mode 100644 assets/addons/voxel-core/engine/voxel_object_editor/voxel_object_editor.tscn create mode 100644 assets/addons/voxel-core/engine/voxel_set_editor/voxel_set_editor.gd create mode 100644 assets/addons/voxel-core/engine/voxel_set_editor/voxel_set_editor.tscn (limited to 'assets/addons/voxel-core/engine') diff --git a/assets/addons/voxel-core/engine/importers/meshes.gd b/assets/addons/voxel-core/engine/importers/meshes.gd new file mode 100644 index 0000000..8b2dbbd --- /dev/null +++ b/assets/addons/voxel-core/engine/importers/meshes.gd @@ -0,0 +1,108 @@ +tool +extends EditorImportPlugin +# Import files as static Mesh Resource, not to be confused with VoxelObjects + + + +## Enums +enum Presets { DEFAULT } + + + +## Built-In Virtual Methods +func get_visible_name() -> String: + return "MeshOfVoxels" + + +func get_importer_name() -> String: + return "VoxelCore.MeshOfVoxels" + + +func get_recognized_extensions() -> Array: + return [ + "png", "jpg", + "vox", + #"qb", + #"qbt", + #"vxm", + ] + + +func get_resource_type() -> String: + return "Mesh" + + +func get_save_extension() -> String: + return "mesh" + + +func get_preset_count() -> int: + return Presets.size() + + +func get_preset_name(preset : int) -> String: + match preset: + Presets.DEFAULT: + return "Default" + _: + return "Unknown" + + +func get_import_options(preset : int) -> Array: + var preset_options = [ + { + "name": "mesh_mode", + "default_value": VoxelMesh.MeshModes.GREEDY, + "property_hint": PROPERTY_HINT_ENUM, + "hint_string": PoolStringArray(VoxelMesh.MeshModes.keys()).join(","), + "usage": PROPERTY_USAGE_EDITOR, + }, + { + "name": "center", + "default_value": 0, + "property_hint": PROPERTY_HINT_ENUM, + "hint_string": "NONE,CENTER,CENTER_ABOVE_AXIS", + "usage": PROPERTY_USAGE_EDITOR, + }, + ] + + match preset: + Presets.DEFAULT: + pass + + return preset_options + + +func get_option_visibility(option : String, options : Dictionary) -> bool: + return true + + +func import(source_file : String, save_path : String, options : Dictionary, r_platform_variants : Array, r_gen_files : Array) -> int: + var read := Reader.read_file(source_file) + var error = read.get("error", FAILED) + if error == OK: + var voxel_mesh = VoxelMesh.new() + voxel_mesh.voxel_set = VoxelSet.new() + + voxel_mesh.set_mesh_mode(options.get("mesh_mode", VoxelMesh.MeshModes.GREEDY)) + voxel_mesh.voxel_set.set_voxels(read["palette"]) + for voxel_position in read["voxels"]: + voxel_mesh.set_voxel(voxel_position, read["voxels"][voxel_position]) + + var center = options.get("center", 0) + if center > 0: + match center: + 1: + center = Vector3(0.5, 0.5, 0.5) + 2: + center = Vector3(0.5, 1.0, 0.5) + voxel_mesh.center(center) + + voxel_mesh.update_mesh() + + error = ResourceSaver.save( + '%s.%s' % [save_path, get_save_extension()], + voxel_mesh.mesh) + + voxel_mesh.free() + return error diff --git a/assets/addons/voxel-core/engine/importers/voxel_objects.gd b/assets/addons/voxel-core/engine/importers/voxel_objects.gd new file mode 100644 index 0000000..e1f2f48 --- /dev/null +++ b/assets/addons/voxel-core/engine/importers/voxel_objects.gd @@ -0,0 +1,112 @@ +tool +extends EditorImportPlugin +# Import files as VoxelObjects + + +## Enums +enum Presets { DEFAULT } + + + +## Built-In Virtual Methods +func get_visible_name() -> String: + return "VoxelObject" + + +func get_importer_name() -> String: + return "VoxelCore.VoxelObject" + + +func get_recognized_extensions() -> Array: + return [ + "png", "jpg", + "vox", + #"qb", + #"qbt", + #"vxm", + ] + + +func get_resource_type() -> String: + return "PackedScene" + + +func get_save_extension() -> String: + return "tscn" + + +func get_preset_count() -> int: + return Presets.size() + + +func get_preset_name(preset : int) -> String: + match preset: + Presets.DEFAULT: + return "Default" + _: + return "Unknown" + + +func get_import_options(preset : int) -> Array: + var preset_options = [ + { + "name": "name", + "default_value": "", + "usage": PROPERTY_USAGE_EDITOR, + }, + { + "name": "voxel_object", + "default_value": 0, + "property_hint": PROPERTY_HINT_ENUM, + "hint_string": "DETECT,VOXEL_MESH", + "usage": PROPERTY_USAGE_EDITOR, + }, + { + "name": "mesh_mode", + "default_value": VoxelMesh.MeshModes.NAIVE, + "property_hint": PROPERTY_HINT_ENUM, + "hint_string": PoolStringArray(VoxelMesh.MeshModes.keys()).join(","), + "usage": PROPERTY_USAGE_EDITOR, + }, + { + "name": "center", + "default_value": 0, + "property_hint": PROPERTY_HINT_ENUM, + "hint_string": "NONE,CENTER,CENTER_ABOVE_AXIS", + "usage": PROPERTY_USAGE_EDITOR, + }, + ] + + return preset_options + + +func get_option_visibility(option : String, options : Dictionary) -> bool: + return true + + +func import(source_file : String, save_path : String, options : Dictionary, r_platform_variants : Array, r_gen_files : Array) -> int: + var voxel_object + match options.get("voxel_object", 0): + _: voxel_object = VoxelMesh.new() + var error = voxel_object.load_file(source_file) + if error == OK: + voxel_object.set_name(source_file.get_file().replace("." + source_file.get_extension(), "") if options["name"].empty() else options["name"]) + voxel_object.set_mesh_mode(options.get("mesh_mode", VoxelMesh.MeshModes.NAIVE)) + + var center = options.get("center", 0) + if center > 0: + match center: + 1: + center = Vector3(0.5, 0.5, 0.5) + 2: + center = Vector3(0.5, 1.0, 0.5) + voxel_object.center(center) + + voxel_object.update_mesh() + + var scene = PackedScene.new() + error = scene.pack(voxel_object) + if error == OK: + error = ResourceSaver.save("%s.%s" % [save_path, get_save_extension()], scene) + voxel_object.free() + return error diff --git a/assets/addons/voxel-core/engine/importers/voxel_sets.gd b/assets/addons/voxel-core/engine/importers/voxel_sets.gd new file mode 100644 index 0000000..fc560b4 --- /dev/null +++ b/assets/addons/voxel-core/engine/importers/voxel_sets.gd @@ -0,0 +1,66 @@ +tool +extends EditorImportPlugin + + + +## Enums +enum Presets { DEFAULT } + + + +## Built-In Virtual Methods +func get_visible_name() -> String: + return "VoxelSet" + + +func get_importer_name() -> String: + return "VoxelCore.VoxelSet" + + +func get_recognized_extensions() -> Array: + return [ + "png", "jpg", + "vox", + "gpl", + ] + + +func get_resource_type() -> String: + return "Resource" + + +func get_save_extension() -> String: + return "tres" + + +func get_preset_count() -> int: + return Presets.size() + + +func get_preset_name(preset : int) -> String: + match preset: + Presets.DEFAULT: + return "Default" + _: + return "Unknown" + + +func get_import_options(preset : int) -> Array: + var preset_options = [ + + ] + + return preset_options + + +func get_option_visibility(option : String, options : Dictionary) -> bool: + return true + + +func import(source_file : String, save_path : String, options : Dictionary, r_platform_variants : Array, r_gen_files : Array) -> int: + var voxel_set := VoxelSet.new() + var error = voxel_set.load_file(source_file) + if error == OK: + voxel_set.request_refresh() + error = ResourceSaver.save("%s.%s" % [save_path, get_save_extension()], voxel_set) + return error diff --git a/assets/addons/voxel-core/engine/voxel_object_editor/config.var b/assets/addons/voxel-core/engine/voxel_object_editor/config.var new file mode 100644 index 0000000..8c78087 Binary files /dev/null and b/assets/addons/voxel-core/engine/voxel_object_editor/config.var differ diff --git a/assets/addons/voxel-core/engine/voxel_object_editor/editor_selection/editor_selection.gd b/assets/addons/voxel-core/engine/voxel_object_editor/editor_selection/editor_selection.gd new file mode 100644 index 0000000..ec6973d --- /dev/null +++ b/assets/addons/voxel-core/engine/voxel_object_editor/editor_selection/editor_selection.gd @@ -0,0 +1,17 @@ +tool +extends Reference + + + +## Public Variables +var name := "" + + + +## Public Methods +# Handles VoxelObjectEditor selection(s) +# editor : VoxelObjectEditor : refrence to VoxelObjectEditor +# event : InputEventMouse : event to be handled +# prev_hit : Dictionary : previous raycast result +func select(editor, event : InputEventMouse, prev_hit : Dictionary) -> bool: + return false diff --git a/assets/addons/voxel-core/engine/voxel_object_editor/editor_selection/editor_selections/area.gd b/assets/addons/voxel-core/engine/voxel_object_editor/editor_selection/editor_selections/area.gd new file mode 100644 index 0000000..97044ad --- /dev/null +++ b/assets/addons/voxel-core/engine/voxel_object_editor/editor_selection/editor_selections/area.gd @@ -0,0 +1,39 @@ +tool +extends "res://addons/voxel-core/engine/voxel_object_editor/editor_selection/editor_selection.gd" + + + +## Private Variables +var _selection := [] + + + +## Built-In Virtual Methods +func _init(): + name = "area" + + + +## Public Methods +func select(editor, event : InputEventMouse, prev_hit : Dictionary) -> bool: + editor.set_cursors_visibility(true) + + if event is InputEventMouseButton and not editor.last_hit.empty(): + if event.pressed: + _selection.clear() + _selection.append(editor.get_selection()) + _selection.append(editor.get_selection()) + else: + if not _selection.empty(): + editor.work_tool() + _selection.clear() + elif event is InputEventMouseMotion: + if not (editor.last_hit.get("position") == prev_hit.get("position") and editor.last_hit.get("normal") == prev_hit.get("normal")): + if not editor.last_hit.empty(): + if _selection.empty(): + editor.set_cursors_selections([editor.get_selection()]) + else: + _selection[1] = editor.get_selection() + editor.set_cursors_selections([_selection]) + + return true diff --git a/assets/addons/voxel-core/engine/voxel_object_editor/editor_selection/editor_selections/extrude.gd b/assets/addons/voxel-core/engine/voxel_object_editor/editor_selection/editor_selections/extrude.gd new file mode 100644 index 0000000..70cef5f --- /dev/null +++ b/assets/addons/voxel-core/engine/voxel_object_editor/editor_selection/editor_selections/extrude.gd @@ -0,0 +1,69 @@ +tool +extends "res://addons/voxel-core/engine/voxel_object_editor/editor_selection/editor_selection.gd" + + + +## Private Variables +# Face area being selected +var _face := [] + +# Flag indicating if currently extruding +var _extruding := false + +# How much extrusion is being applied currently +var _extrude_amount := 1 + +# Normal of extrusion +var _extrude_normal := Vector3.ZERO + + + +## Built-In Virtual Methods +func _init(): + name = "extrude" + + +## Public Methods +func select(editor, event : InputEventMouse, prev_hit : Dictionary) -> bool: + editor.set_cursors_visibility(true) + + if event is InputEventMouseButton: + if event.is_pressed(): + if not _face.empty(): + _extruding = true + _extrude_normal = editor.last_hit["normal"] + else: + if _extruding: + editor.work_tool() + _face.clear() + _extrude_amount = 1 + _extrude_normal = Vector3.ZERO + _extruding = false + editor.set_cursors_selections(_face) + elif event is InputEventMouseMotion: + if _extruding: + var extrude := [] + _extrude_amount = clamp(_extrude_amount + clamp(event.relative.normalized().x, -1, 1), 1, 100) + var extrude_direction := 1 if editor.get_tool_normal() > 0 else -1 + for e in range(_extrude_amount): + for position in _face: + extrude.append(position + _extrude_normal * extrude_direction * e) + editor.set_cursors_selections(extrude) + else: + if not editor.last_hit.empty(): + if editor.voxel_object.get_voxel_id(editor.last_hit["position"]) > -1: + if editor.last_hit.empty() or not (editor.last_hit.get("position") == prev_hit.get("position") and editor.last_hit.get("normal") == prev_hit.get("normal")): + if Input.is_key_pressed(KEY_SHIFT): + _face = editor.voxel_object.select_face_similar(editor.last_hit["position"], editor.last_hit["normal"]) + else: + _face = editor.voxel_object.select_face(editor.last_hit["position"], editor.last_hit["normal"]) + if editor.get_tool_normal() > 0: + for i in range(_face.size()): + _face[i] += editor.last_hit["normal"] + else: + _face.clear() + else: + _face.clear() + editor.set_cursors_selections(_face) + + return true diff --git a/assets/addons/voxel-core/engine/voxel_object_editor/editor_selection/editor_selections/individual.gd b/assets/addons/voxel-core/engine/voxel_object_editor/editor_selection/editor_selections/individual.gd new file mode 100644 index 0000000..7b45702 --- /dev/null +++ b/assets/addons/voxel-core/engine/voxel_object_editor/editor_selection/editor_selections/individual.gd @@ -0,0 +1,27 @@ +tool +extends "res://addons/voxel-core/engine/voxel_object_editor/editor_selection/editor_selection.gd" + + + +## Built-In Virtual Methods +func _init(): + name = "individual" + + + +## Public Methods +func select(editor, event : InputEventMouse, prev_hit : Dictionary) -> bool: + editor.set_cursors_visibility(true) + + if (event is InputEventMouseButton and not event.pressed) and not editor.last_hit.empty(): + editor.work_tool() + elif Input.is_mouse_button_pressed(BUTTON_LEFT) and Input.is_key_pressed(KEY_SHIFT): + editor.work_tool() + + if not (editor.last_hit.get("position") == prev_hit.get("position") and editor.last_hit.get("normal") == prev_hit.get("normal")): + if editor.last_hit.empty(): + editor.set_cursors_selections([]) + else: + editor.set_cursors_selections([editor.get_selection()]) + + return true diff --git a/assets/addons/voxel-core/engine/voxel_object_editor/editor_tool/editor_tool.gd b/assets/addons/voxel-core/engine/voxel_object_editor/editor_tool/editor_tool.gd new file mode 100644 index 0000000..48b8667 --- /dev/null +++ b/assets/addons/voxel-core/engine/voxel_object_editor/editor_tool/editor_tool.gd @@ -0,0 +1,29 @@ +tool +extends Reference + + + +## Public Variables +# Name of this tool +var name := "" + +# Offset applied to VoxelObjectEditor selection when using this tool +var tool_normal := 0 + +# Types of selection modes +var selection_modes := PoolStringArray([ + "individual", + "area", + "extrude", +]) + +# A 1 in each coordinate means all selection mirrors are applicable using this tool +var mirror_modes := Vector3.ONE + + + +## Public Methods +# Applies tool +# editor : VoxelObjectEditor : refrence to VoxelObjectEditor +func work(editor) -> void: + pass diff --git a/assets/addons/voxel-core/engine/voxel_object_editor/editor_tool/editor_tools/add.gd b/assets/addons/voxel-core/engine/voxel_object_editor/editor_tool/editor_tools/add.gd new file mode 100644 index 0000000..da7e832 --- /dev/null +++ b/assets/addons/voxel-core/engine/voxel_object_editor/editor_tool/editor_tools/add.gd @@ -0,0 +1,49 @@ +tool +extends "res://addons/voxel-core/engine/voxel_object_editor/editor_tool/editor_tool.gd" + + + +## Built-In Virtual Methods +func _init(): + name = "add" + tool_normal = 1 + + + +## Public Methods +# Sets voxel id at given grid position in given VoxelObject and commits it to provided UndoRedo +func add(voxel_object, position : Vector3, voxel : int, undo_redo : UndoRedo) -> void: + undo_redo.add_do_method(voxel_object, "set_voxel", position, voxel) + voxel = voxel_object.get_voxel_id(position) + if voxel == -1: + undo_redo.add_undo_method(voxel_object, "erase_voxel", position) + else: + undo_redo.add_undo_method(voxel_object, "set_voxel", position, voxel) + + +func work(editor) -> void: + var voxel = editor.get_palette() + if voxel == -1: + return + + editor.undo_redo.create_action("VoxelObjectEditor : Add voxel") + for cursor_selection in editor.get_selections(): + for selection in cursor_selection: + match typeof(selection): + TYPE_VECTOR3: + add(editor.voxel_object, selection, voxel, editor.undo_redo) + TYPE_ARRAY: + var origin := Vector3( + selection[0 if selection[0].x < selection[1].x else 1].x, + selection[0 if selection[0].y < selection[1].y else 1].y, + selection[0 if selection[0].z < selection[1].z else 1].z) + var dimensions : Vector3 = (selection[0] - selection[1]).abs() + for x in range(origin.x, origin.x + dimensions.x + 1): + for y in range(origin.y, origin.y + dimensions.y + 1): + for z in range(origin.z, origin.z + dimensions.z + 1): + add( + editor.voxel_object, + Vector3(x, y, z), voxel, editor.undo_redo) + editor.undo_redo.add_do_method(editor.voxel_object, "update_mesh") + editor.undo_redo.add_undo_method(editor.voxel_object, "update_mesh") + editor.undo_redo.commit_action() diff --git a/assets/addons/voxel-core/engine/voxel_object_editor/editor_tool/editor_tools/fill.gd b/assets/addons/voxel-core/engine/voxel_object_editor/editor_tool/editor_tools/fill.gd new file mode 100644 index 0000000..9336e78 --- /dev/null +++ b/assets/addons/voxel-core/engine/voxel_object_editor/editor_tool/editor_tools/fill.gd @@ -0,0 +1,42 @@ +tool +extends "res://addons/voxel-core/engine/voxel_object_editor/editor_tool/editor_tool.gd" + + + +## Built-In Virtual Methods +func _init(): + name = "fill" + selection_modes = PoolStringArray([ + "individual" + ]) + + + +## Public Methods +# Replaces all matching connected voxels in VoxelObject starting at given position and commits it to provided UndoRedo +func fill(voxel_object, position : Vector3, target : int, replacement : int, undo_redo : UndoRedo, filled := []) -> void: + var voxel = voxel_object.get_voxel_id(position) + if voxel > -1 and voxel == target and not filled.has(position): + filled.append(position) + undo_redo.add_do_method(voxel_object, 'set_voxel', position, replacement) + undo_redo.add_undo_method(voxel_object, 'set_voxel', position, target) + for face in Voxel.Faces: + fill( + voxel_object, position + face, target, replacement, + undo_redo, filled) + + +func work(editor) -> void: + editor.undo_redo.create_action("VoxelObjectEditor : Fill voxel(s)") + for selection in editor.get_selections(): + for position in selection: + var target = editor.voxel_object.get_voxel_id(position) + if target == -1: + continue + + fill( + editor.voxel_object, position, target, editor.get_palette(), + editor.undo_redo) + editor.undo_redo.add_do_method(editor.voxel_object, "update_mesh") + editor.undo_redo.add_undo_method(editor.voxel_object, "update_mesh") + editor.undo_redo.commit_action() diff --git a/assets/addons/voxel-core/engine/voxel_object_editor/editor_tool/editor_tools/pick.gd b/assets/addons/voxel-core/engine/voxel_object_editor/editor_tool/editor_tools/pick.gd new file mode 100644 index 0000000..34f8732 --- /dev/null +++ b/assets/addons/voxel-core/engine/voxel_object_editor/editor_tool/editor_tools/pick.gd @@ -0,0 +1,21 @@ +tool +extends "res://addons/voxel-core/engine/voxel_object_editor/editor_tool/editor_tool.gd" + + + +## Built-In Virtual Methods +func _init(): + name = "pick" + selection_modes = PoolStringArray([ + "individual" + ]) + mirror_modes = Vector3.ZERO + + + +## Public Methods +func work(editor) -> void: + var voxel = editor.voxel_object.get_voxel_id(editor.get_selection()) + if voxel > -1: + editor.VoxelSetViewer.unselect_all() + editor.VoxelSetViewer.select(voxel) diff --git a/assets/addons/voxel-core/engine/voxel_object_editor/editor_tool/editor_tools/sub.gd b/assets/addons/voxel-core/engine/voxel_object_editor/editor_tool/editor_tools/sub.gd new file mode 100644 index 0000000..d778583 --- /dev/null +++ b/assets/addons/voxel-core/engine/voxel_object_editor/editor_tool/editor_tools/sub.gd @@ -0,0 +1,42 @@ +tool +extends "res://addons/voxel-core/engine/voxel_object_editor/editor_tool/editor_tool.gd" + + + +## Built-In Virtual Methods +func _init(): + name = "sub" + + + +## Public Methods +# Removes voxel id at given grid position in given VoxelObject and commits it to provided UndoRedo +func sub(voxel_object, position : Vector3, undo_redo : UndoRedo) -> void: + var voxel = voxel_object.get_voxel_id(position) + if voxel > -1: + undo_redo.add_do_method(voxel_object, 'erase_voxel', position) + undo_redo.add_undo_method(voxel_object, 'set_voxel', position, voxel) + + +func work(editor) -> void: + editor.undo_redo.create_action("VoxelObjectEditor : Sub voxel") + for cursor_selection in editor.get_selections(): + for selection in cursor_selection: + match typeof(selection): + TYPE_VECTOR3: + sub(editor.voxel_object, selection, editor.undo_redo) + TYPE_ARRAY: + var origin := Vector3( + selection[0 if selection[0].x < selection[1].x else 1].x, + selection[0 if selection[0].y < selection[1].y else 1].y, + selection[0 if selection[0].z < selection[1].z else 1].z) + var dimensions : Vector3 = (selection[0] - selection[1]).abs() + for x in range(origin.x, origin.x + dimensions.x + 1): + for y in range(origin.y, origin.y + dimensions.y + 1): + for z in range(origin.z, origin.z + dimensions.z + 1): + sub( + editor.voxel_object, Vector3(x, y, z), + editor.undo_redo) + editor.undo_redo.add_do_method(editor.voxel_object, "update_mesh") + editor.undo_redo.add_undo_method(editor.voxel_object, "update_mesh") + editor.undo_redo.commit_action() diff --git a/assets/addons/voxel-core/engine/voxel_object_editor/editor_tool/editor_tools/swap.gd b/assets/addons/voxel-core/engine/voxel_object_editor/editor_tool/editor_tools/swap.gd new file mode 100644 index 0000000..5b7b92f --- /dev/null +++ b/assets/addons/voxel-core/engine/voxel_object_editor/editor_tool/editor_tools/swap.gd @@ -0,0 +1,45 @@ +tool +extends "res://addons/voxel-core/engine/voxel_object_editor/editor_tool/editor_tool.gd" + + + +## Built-In Virtual Methods +func _init(): + name = "swap" + + +## Public Methods +# Swaps voxel at given grid position in given VoxelObject with given id and commits it to provided UndoRedo +func swap(voxel_object, position : Vector3, voxel, undo_redo : UndoRedo) -> void: + var prev_voxel = voxel_object.get_voxel_id(position) + if prev_voxel > -1: + undo_redo.add_do_method(voxel_object, 'set_voxel', position, voxel) + undo_redo.add_undo_method(voxel_object, 'set_voxel', position, prev_voxel) + + +func work(editor) -> void: + var voxel = editor.get_palette() + if voxel == -1: + return + + editor.undo_redo.create_action("VoxelObjectEditor : Swap voxel") + for cursor_selection in editor.get_selections(): + for selection in cursor_selection: + match typeof(selection): + TYPE_VECTOR3: + swap(editor.voxel_object, selection, voxel, editor.undo_redo) + TYPE_ARRAY: + var origin := Vector3( + selection[0 if selection[0].x < selection[1].x else 1].x, + selection[0 if selection[0].y < selection[1].y else 1].y, + selection[0 if selection[0].z < selection[1].z else 1].z) + var dimensions : Vector3 = (selection[0] - selection[1]).abs() + for x in range(origin.x, origin.x + dimensions.x + 1): + for y in range(origin.y, origin.y + dimensions.y + 1): + for z in range(origin.z, origin.z + dimensions.z + 1): + swap( + editor.voxel_object, Vector3(x, y, z), + voxel, editor.undo_redo) + editor.undo_redo.add_do_method(editor.voxel_object, "update_mesh") + editor.undo_redo.add_undo_method(editor.voxel_object, "update_mesh") + editor.undo_redo.commit_action() diff --git a/assets/addons/voxel-core/engine/voxel_object_editor/voxel_cursor/voxel_cursor.gd b/assets/addons/voxel-core/engine/voxel_object_editor/voxel_cursor/voxel_cursor.gd new file mode 100644 index 0000000..178a976 --- /dev/null +++ b/assets/addons/voxel-core/engine/voxel_object_editor/voxel_cursor/voxel_cursor.gd @@ -0,0 +1,112 @@ +tool +extends MeshInstance +# Mesh used to highlight voxel grid selections + + + +## Exported Variables +# Highlight color +export var color := Color(1, 1, 1, 0.75) setget set_color + + + +## Public Variables +# Grid positions and areas to highlight +# A Vector3 highlights a single grid position +# [Vector3, Vector3] highlights the area between two grid positions +# Many type of selections can be mixed and selected at a time +var selections := [] setget set_selections + + + +## Private Variables +# VoxelTool used to construct mesh +var _voxel_tool := VoxelTool.new() + + + +## Built-In Virtual Methods +func _init(): + setup() +func _ready() -> void: + setup() + + + +## Public Methods +func set_color(value : Color) -> void: + color = value + if is_instance_valid(material_override): + material_override.albedo_color = color + + +func set_selections(value : Array, update := true) -> void: + selections = value + + if update: + self.update() + + +# Setup the material if not already done +func setup() -> void: + if not is_instance_valid(material_override): + material_override = SpatialMaterial.new() + material_override.flags_transparent = true + material_override.flags_unshaded = true + material_override.params_grow = true + material_override.params_grow_amount = 0.001 + material_override.albedo_color = color + update() + + +# Update highlighted position(s) / area(s) +func update() -> void: + if not selections.empty(): + _voxel_tool.begin() + var voxel := Voxel.colored(color) + for selection in selections: + match typeof(selection): + TYPE_VECTOR3: + for face in Voxel.Faces: + if not selections.has(selection + face): + _voxel_tool.add_face(voxel, face, selection) + TYPE_ARRAY: + var origin := Vector3( + selection[0 if selection[0].x < selection[1].x else 1].x, + selection[0 if selection[0].y < selection[1].y else 1].y, + selection[0 if selection[0].z < selection[1].z else 1].z) + var dimensions : Vector3 = (selection[0] - selection[1]).abs() + + _voxel_tool.add_face(voxel, Vector3.RIGHT, + Vector3(origin.x + dimensions.x, origin.y, origin.z + dimensions.z), + Vector3(origin.x + dimensions.x, origin.y, origin.z), + Vector3(origin.x + dimensions.x, origin.y + dimensions.y, origin.z + dimensions.z), + Vector3(origin.x + dimensions.x, origin.y + dimensions.y, origin.z)) + _voxel_tool.add_face(voxel, Vector3.LEFT, + Vector3(origin.x, origin.y, origin.z + dimensions.z), + Vector3(origin.x, origin.y, origin.z), + Vector3(origin.x, origin.y + dimensions.y, origin.z + dimensions.z), + Vector3(origin.x, origin.y + dimensions.y, origin.z)) + _voxel_tool.add_face(voxel, Vector3.UP, + Vector3(origin.x + dimensions.x, origin.y + dimensions.y, origin.z), + Vector3(origin.x, origin.y + dimensions.y, origin.z), + Vector3(origin.x + dimensions.x, origin.y + dimensions.y, origin.z + dimensions.z), + Vector3(origin.x, origin.y + dimensions.y, origin.z + dimensions.z)) + _voxel_tool.add_face(voxel, Vector3.DOWN, + Vector3(origin.x + dimensions.x, origin.y, origin.z), + Vector3(origin.x, origin.y, origin.z), + Vector3(origin.x + dimensions.x, origin.y, origin.z + dimensions.z), + Vector3(origin.x, origin.y, origin.z + dimensions.z)) + _voxel_tool.add_face(voxel, Vector3.BACK, + Vector3(origin.x + dimensions.x, origin.y, origin.z + dimensions.z), + Vector3(origin.x, origin.y, origin.z + dimensions.z), + Vector3(origin.x + dimensions.x, origin.y + dimensions.y, origin.z + dimensions.z), + Vector3(origin.x, origin.y + dimensions.y, origin.z + dimensions.z)) + _voxel_tool.add_face(voxel, Vector3.FORWARD, + Vector3(origin.x + dimensions.x, origin.y, origin.z), + Vector3(origin.x, origin.y, origin.z), + Vector3(origin.x + dimensions.x, origin.y + dimensions.y, origin.z), + Vector3(origin.x, origin.y + dimensions.y, origin.z)) + mesh = _voxel_tool.commit() + else: + mesh = null diff --git a/assets/addons/voxel-core/engine/voxel_object_editor/voxel_grid/voxel_grid.gd b/assets/addons/voxel-core/engine/voxel_object_editor/voxel_grid/voxel_grid.gd new file mode 100644 index 0000000..5ed975e --- /dev/null +++ b/assets/addons/voxel-core/engine/voxel_object_editor/voxel_grid/voxel_grid.gd @@ -0,0 +1,113 @@ +tool +extends MeshInstance +# Grid Mesh used by VoxelObjectEditor + + + +## Enums +enum GridModes { SOLID, WIRED } + + + +## Exported Variables +export var disabled := false setget set_disabled + +export(Color, RGB) var color := Color.white setget set_modulate + +export(GridModes) var grid_mode := GridModes.WIRED setget set_grid_mode + +export var grid_size := Vector3(16, 16, 16) setget set_grid_size + + + +## Private Variables +var _surface_tool := SurfaceTool.new() + + + +## Built-In Virtual Methods +func _init(): + setup() + + +func _ready() -> void: + setup() + + + +## Public Methods +func set_disabled(value : bool) -> void: + disabled = value + visible = not disabled + find_node("CollisionShape", true, false).disabled = disabled + + +func set_modulate(value : Color) -> void: + color = value + + material_override.albedo_color = color + + +func set_grid_mode(value : int, update := true) -> void: + grid_mode = value + + if update: + self.update() + + +func set_grid_size(value : Vector3, update := true) -> void: + grid_size = Vector3( + clamp(value.x, 1, 100), + clamp(value.y, 1, 100), + clamp(value.z, 1, 100)) + + if update: + self.update() + + +func setup() -> void: + if not is_instance_valid(material_override): + material_override = SpatialMaterial.new() + material_override.albedo_color = color + material_override.set_cull_mode(2) + update() + + +func update() -> void: + match grid_mode: + GridModes.SOLID: + mesh = PlaneMesh.new() + scale = Vector3( + grid_size.x * Voxel.VoxelWorldSize, + 1, + grid_size.z * Voxel.VoxelWorldSize) + GridModes.WIRED: + scale = Vector3.ONE + _surface_tool.begin(Mesh.PRIMITIVE_LINES) + + var x : int = -grid_size.x + while x <= grid_size.x: + _surface_tool.add_normal(Vector3.UP) + _surface_tool.add_vertex( + Voxel.grid_to_snapped(Vector3(x, 0, -abs(grid_size.z)))) + _surface_tool.add_vertex( + Voxel.grid_to_snapped(Vector3(x, 0, abs(grid_size.z)))) + + x += 1 + + var z : int = -grid_size.z + while z <= grid_size.z: + _surface_tool.add_normal(Vector3.UP) + _surface_tool.add_vertex( + Voxel.grid_to_snapped(Vector3(-abs(grid_size.x), 0, z))) + _surface_tool.add_vertex( + Voxel.grid_to_snapped(Vector3(abs(grid_size.x), 0, z))) + + z += 1 + + mesh = _surface_tool.commit() + for child in get_children(): + remove_child(child) + child.queue_free() + create_convex_collision() + set_disabled(disabled) diff --git a/assets/addons/voxel-core/engine/voxel_object_editor/voxel_object_editor.gd b/assets/addons/voxel-core/engine/voxel_object_editor/voxel_object_editor.gd new file mode 100644 index 0000000..a2a03b4 --- /dev/null +++ b/assets/addons/voxel-core/engine/voxel_object_editor/voxel_object_editor.gd @@ -0,0 +1,866 @@ +tool +extends Control + + + +## Signals +# Emited when editing state changed +signal editing(state) + +# Emited when editor needs to be closed +signal close + + + +## Enums +# The possible palettes +enum Palettes { PRIMARY, SECONDARY } + + + +## Constants +const VoxelGrid := preload("res://addons/voxel-core/engine/voxel_object_editor/voxel_grid/voxel_grid.gd") + +const VoxelCursor := preload("res://addons/voxel-core/engine/voxel_object_editor/voxel_cursor/voxel_cursor.gd") + +const VoxelObject := preload("res://addons/voxel-core/classes/voxel_object.gd") + +# Default editor config +const ConfigDefault := { + "cursor.visible": true, + "cursor.dynamic": true, + "cursor.voxel_raycasting": false, + "cursor.color": Color.white, + "grid.visible": true, + "grid.mode": VoxelGrid.GridModes.WIRED, + "grid.color": Color.white, + "grid.constant": true, + "grid.size": Vector2(16, 16), +} + + + +## Public Variables +# UndoRedo used to commit operations +var undo_redo : UndoRedo + +# Last registered raycast hit +var last_hit := {} + +# Editor's current config +var config := {} + +# Reference to VoxelObject being edited +var voxel_object : VoxelObject setget start_editing + + + +## Private Variables +# Refrence to editor's grid +var _grid := VoxelGrid.new() + +# Colletions of loaded editor selection modes +var _selection_modes := [ + preload("res://addons/voxel-core/engine/voxel_object_editor/editor_selection/editor_selections/individual.gd").new(), + preload("res://addons/voxel-core/engine/voxel_object_editor/editor_selection/editor_selections/area.gd").new(), + preload("res://addons/voxel-core/engine/voxel_object_editor/editor_selection/editor_selections/extrude.gd").new(), +] + +# Refrence to editor's voxel cursors +var _cursors := { + Vector3(0, 0, 0): VoxelCursor.new(), + Vector3(1, 0, 0): VoxelCursor.new(), + Vector3(1, 1, 0): VoxelCursor.new(), + Vector3(1, 1, 1): VoxelCursor.new(), + Vector3(0, 1, 1): VoxelCursor.new(), + Vector3(0, 1, 0): VoxelCursor.new(), + Vector3(0, 0, 1): VoxelCursor.new(), + Vector3(1, 0, 1): VoxelCursor.new(), +} + +# Collection of loaded editor tools +var _tools := [ + preload("res://addons/voxel-core/engine/voxel_object_editor/editor_tool/editor_tools/add.gd").new(), + preload("res://addons/voxel-core/engine/voxel_object_editor/editor_tool/editor_tools/sub.gd").new(), + preload("res://addons/voxel-core/engine/voxel_object_editor/editor_tool/editor_tools/swap.gd").new(), + preload("res://addons/voxel-core/engine/voxel_object_editor/editor_tool/editor_tools/fill.gd").new(), + preload("res://addons/voxel-core/engine/voxel_object_editor/editor_tool/editor_tools/pick.gd").new(), +] + +# Voxel id of each palette +var _palette := [ -1, -1 ] + +# Path to file going to imported +var import_file_path := "" + + + +## OnReady Variables +onready var Editing := get_node("VoxelObjectEditor/HBoxContainer/VBoxContainer/HBoxContainer/Editing") + +onready var Options := get_node("VoxelObjectEditor/HBoxContainer/VBoxContainer/Options") + +onready var Tool := get_node("VoxelObjectEditor/HBoxContainer/VBoxContainer/Options/VBoxContainer/HBoxContainer/Tool") + +onready var Palette := get_node("VoxelObjectEditor/HBoxContainer/VBoxContainer/Options/VBoxContainer/HBoxContainer/Palette") + +onready var SelectionMode := get_node("VoxelObjectEditor/HBoxContainer/VBoxContainer/Options/VBoxContainer/HBoxContainer/SelectionMode") + +onready var MirrorX := get_node("VoxelObjectEditor/HBoxContainer/VBoxContainer/Options/VBoxContainer/HBoxContainer2/MirrorX") + +onready var MirrorY := get_node("VoxelObjectEditor/HBoxContainer/VBoxContainer/Options/VBoxContainer/HBoxContainer2/MirrorY") + +onready var MirrorZ := get_node("VoxelObjectEditor/HBoxContainer/VBoxContainer/Options/VBoxContainer/HBoxContainer2/MirrorZ") + +onready var ColorChooser := get_node("VoxelObjectEditor/HBoxContainer/VBoxContainer/Options/VBoxContainer/ColorChooser") + +onready var ColorPicked := get_node("VoxelObjectEditor/HBoxContainer/VBoxContainer/Options/VBoxContainer/ColorChooser/ColorPicked") + +onready var VoxelSetViewer := get_node("VoxelObjectEditor/HBoxContainer/VBoxContainer/Options/VoxelSetViewer") + +onready var Notice := get_node("VoxelObjectEditor/HBoxContainer/VBoxContainer/Notice") + +onready var MoveX := get_node("VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/Move/X") + +onready var MoveY := get_node("VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/Move/Y") + +onready var MoveZ := get_node("VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/Move/Z") + +onready var CenterX := get_node("VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/Center/X") + +onready var CenterY := get_node("VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/Center/Y") + +onready var CenterZ := get_node("VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/Center/Z") + +onready var ImportMenu := get_node("VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/File/Import/ImportFile") + +onready var ImportHow := get_node("VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/File/Import/ImportHow") + +onready var Settings := get_node("VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings") + +onready var CursorVisible := get_node("VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Cursor/ScrollContainer/VBoxContainer/CursorVisible") + +onready var CursorDynamic := get_node("VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Cursor/ScrollContainer/VBoxContainer/CursorDynamic") + +onready var VoxelRaycasting := get_node("VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Cursor/ScrollContainer/VBoxContainer/VoxelRaycasting") + +onready var CursorColor := get_node("VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Cursor/ScrollContainer/VBoxContainer/HBoxContainer/CursorColor") + +onready var GridVisible := get_node("VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Grid/ScrollContainer/VBoxContainer/GridVisible") + +onready var GridConstant := get_node("VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Grid/ScrollContainer/VBoxContainer/GridConstant") + +onready var GridMode := get_node("VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Grid/ScrollContainer/VBoxContainer/GridMode") + +onready var GridColor := get_node("VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Grid/ScrollContainer/VBoxContainer/HBoxContainer2/GridColor") + +onready var GridSizeX := get_node("VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Grid/ScrollContainer/VBoxContainer/VBoxContainer/Size/X") + +onready var GridSizeZ := get_node("VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Grid/ScrollContainer/VBoxContainer/VBoxContainer/Size/Z") + +onready var ColorMenu := get_node("ColorMenu") + +onready var ColorMenuColor := get_node("ColorMenu/VBoxContainer/Color") + +onready var ColorMenuAdd := get_node("ColorMenu/VBoxContainer/HBoxContainer/Add") + + + +## Built-In Virtual Methods +func _ready(): + if not is_instance_valid(undo_redo): + undo_redo = UndoRedo.new() + + update_tools() + update_palette() + update_selections() + update_mirrors() + update_settings() + update_grid_mode() + + load_config() + + +func _exit_tree(): + if is_instance_valid(_grid): + _grid.queue_free() + for cursor in _cursors: + if is_instance_valid(_cursors[cursor]): + _cursors[cursor].queue_free() + + + +## Public Methods +func is_editing() -> bool: + return Editing.pressed + + +# Updates the drop down ui menu in editor with all loaded tools +func update_tools(tools := _tools) -> void: + Tool.clear() + for tool_index in range(tools.size()): + Tool.add_icon_item( + load("res://addons/voxel-core/assets/controls/" + tools[tool_index].name.to_lower() + ".png"), + tools[tool_index].name.capitalize(), + tool_index) + + +# Updates the drop down ui menu in editor with palettes +func update_palette(palettes := Palettes.keys()) -> void: + Palette.clear() + for palette in palettes: + Palette.add_icon_item( + load("res://addons/voxel-core/assets/controls/" + palette.to_lower() + ".png"), + palette.capitalize(), + Palettes[palette.to_upper()]) + + +# Updates the drop down ui menu in editor with all loaded selection modes +func update_selections(selection_modes := [ + "individual", + "area", + "extrude", + ]) -> void: + var prev = SelectionMode.get_selected_id() + SelectionMode.clear() + for select_mode in range(_selection_modes.size()): + if selection_modes.find(_selection_modes[select_mode].name.to_lower()) > -1: + SelectionMode.add_icon_item( + load("res://addons/voxel-core/assets/controls/" + _selection_modes[select_mode].name.to_lower() + ".png"), + _selection_modes[select_mode].name.capitalize(), select_mode) + if SelectionMode.get_item_index(prev) > -1: + SelectionMode.select(SelectionMode.get_item_index(prev)) + else: + _on_SelectionMode_selected(SelectionMode.get_selected_id()) + + +# Disables and enables possible selection mirror(s) possible with current tool +func update_mirrors(mirror := Vector3.ONE) -> void: + MirrorX.visible = mirror.x == 1 + MirrorX.pressed = MirrorX.pressed if mirror.x == 1 else false + MirrorY.visible = mirror.y == 1 + MirrorY.pressed = MirrorY.pressed if mirror.y == 1 else false + MirrorZ.visible = mirror.z == 1 + MirrorZ.pressed = MirrorZ.pressed if mirror.z == 1 else false + set_cursors_visibility() + + +# Updates the setting tabs +func update_settings() -> void: + for tab in range(Settings.get_tab_count()): + var name : String = Settings.get_tab_title(tab) + Settings.set_tab_icon(tab, + load("res://addons/voxel-core/assets/controls/" + name.to_lower() + ".png")) + + +# Sets the cursor visibility +func set_cursor_visible(visible : bool) -> void: + config["cursor.visible"] = visible + CursorVisible.pressed = visible + if not visible: + set_cursors_visibility(visible) + save_config() + + +# Sets the cursor's dynamic option +# Enabling would change cursor color based on selected palette +func set_cursor_dynamic(dynamic : bool) -> void: + config["cursor.dynamic"] = dynamic + CursorDynamic.pressed = dynamic + CursorColor.disabled = dynamic + if dynamic: + var color = ColorPicked.color + color.a = 0.75 + set_cursor_color(color) + else: + set_cursor_color(config["cursor.color"]) + save_config() + + +# Sets the cursor color +func set_cursor_color(color : Color) -> void: + config["cursor.color"] = color + CursorColor.color = color + for cursor in _cursors.values(): + cursor.color = color + save_config() + + +# Returns true if grid should be visible +func is_grid_disabled() -> bool: + return not Editing.pressed or (Editing.pressed and not GridVisible.pressed or (GridVisible.pressed and (not GridConstant.pressed and (is_instance_valid(voxel_object) and not voxel_object.empty())))) + + +# Sets the grid visibility +func set_grid_visible(visible : bool) -> void: + config["grid.visible"] = visible + GridVisible.pressed = visible + _grid.disabled = is_grid_disabled() + save_config() + + +# Sets the grid constant option +# Disabling would mean grid would not be visible once voxels are present +func set_grid_constant(constant : bool) -> void: + config["grid.constant"] = constant + GridConstant.pressed = constant + _grid.disabled = is_grid_disabled() + save_config() + + +# Updates the grid ui options +func update_grid_mode() -> void: + GridMode.clear() + for mode_index in range(VoxelGrid.GridModes.size()): + GridMode.add_icon_item( + load("res://addons/voxel-core/assets/controls/" + VoxelGrid.GridModes.keys()[mode_index].to_lower() + ".png"), + VoxelGrid.GridModes.keys()[mode_index].capitalize(), mode_index) + + +# Sets the grid mode +func set_grid_mode(mode : int) -> void: + config["grid.mode"] = mode + GridMode.selected = mode + _grid.grid_mode = mode + save_config() + + +# Sets the grid color +func set_grid_color(color : Color) -> void: + config["grid.color"] = color + GridColor.color = color + _grid.color = color + save_config() + + +# Sets the grid size +func set_grid_size(size : Vector2) -> void: + config["grid.size"] = size + GridSizeX.value = size.x + GridSizeZ.value = size.y + _grid.grid_size = Vector3(size.x, 0, size.y) + save_config() + + +# Gets the user selected mirror(s) +func get_mirrors() -> Array: + var mirrors := [] + + if MirrorX.pressed: + mirrors.append(Vector3(1, 0, 0)) + if MirrorZ.pressed: + mirrors.append(Vector3(1, 0, 1)) + if MirrorY.pressed: + mirrors.append(Vector3(0, 1, 0)) + if MirrorX.pressed: + mirrors.append(Vector3(1, 1, 0)) + if MirrorZ.pressed: + mirrors.append(Vector3(0, 1, 1)) + if MirrorX.pressed && MirrorZ.pressed: + mirrors.append(Vector3(1, 1, 1)) + if MirrorZ.pressed: + mirrors.append(Vector3(0, 0, 1)) + + return mirrors + + +# Gets the user's current voxel grid selection +func get_selection() -> Vector3: + return Vector3.INF if last_hit.empty() else (last_hit["position"] + last_hit["normal"] * _tools[Tool.get_selected_id()].tool_normal) + + +# Gets each of the user's voxel grid selection with mirror applied +func get_selections() -> Array: + var selections := [_cursors[Vector3.ZERO].selections] + for mirror in get_mirrors(): + selections.append(_cursors[mirror].selections) + return selections + + +# Sets the cursor's visiblity +func set_cursors_visibility(visible := Editing.pressed) -> void: + _cursors[Vector3.ZERO].visible = visible and CursorVisible.pressed + var mirrors := get_mirrors() + for cursor in _cursors: + if not cursor == Vector3.ZERO: + _cursors[cursor].visible = _cursors[Vector3.ZERO].visible and mirrors.has(cursor) + + +# Sets the cursors selection +func set_cursors_selections( + selections := [last_hit["position"] + last_hit["normal"] * _tools[Tool.get_selected_id()].tool_normal] if not last_hit.empty() else [] + ) -> void: + _cursors[Vector3.ZERO].selections = selections + var mirrors := get_mirrors() + for mirror in mirrors: + _cursors[mirror].selections = mirror_positions(selections, mirror) + + +# Updats the cursor visuals +func update_cursors() -> void: + var mirrors := get_mirrors() + for cursor in _cursors: + if not cursor == Vector3.ZERO: + _cursors[cursor].visible = _cursors[Vector3.ZERO].visible and mirrors.has(cursor) + if mirrors.has(cursor): + _cursors[cursor].selections = mirror_positions( + _cursors[Vector3.ZERO].selections, + cursor + ) + + +# Sets the palette +func set_palette(palette : int, voxel_id : int) -> void: + _palette[palette] = voxel_id + if palette == Palette.get_selected_id(): + ColorPicked.color = Voxel.get_color(get_rpalette()) + if CursorDynamic.pressed: + var color = ColorPicked.color + color.a = 0.5 + set_cursor_color(color) + if not VoxelSetViewer.has_selected(voxel_id): + VoxelSetViewer.select(voxel_id) + + +# Returns the voxel id of palette +func get_palette(palette : int = Palette.get_selected_id()) -> int: + return _palette[palette] + + +# Returns the voxel dictionary of palette +func get_rpalette(palette : int = get_palette()) -> Dictionary: + return voxel_object.voxel_set.get_voxel(palette) + + +# Setter for voxel raycasting, saves to config +func set_voxel_raycasting(value : bool) -> void: + VoxelRaycasting.pressed = value + config["cursor.voxel_raycasting"] = value + _update_editing_hint() + save_config() + + +# Saves the current editor config to file +func save_config() -> void: + var file := File.new() + var opened = file.open( + "res://addons/voxel-core/engine/voxel_object_editor/config.var", + File.WRITE) + if opened == OK: + file.store_var(config) + if file.is_open(): + file.close() + + +# Loads and sets the config file +func load_config() -> void: + var loaded := false + var config_file := File.new() + var opened = config_file.open( + "res://addons/voxel-core/engine/voxel_object_editor/config.var", + File.READ) + if opened == OK and not config_file.eof_reached(): + var config_file_data = config_file.get_var() + if typeof(config_file_data) == TYPE_DICTIONARY: + config = config_file_data + loaded = true + + if not loaded: + config = ConfigDefault.duplicate() + + if config_file.is_open(): + config_file.close() + + if config.has("cursor.visible"): + set_cursor_visible(config["cursor.visible"]) + if config.has("cursor.dynamic"): + set_cursor_dynamic(config["cursor.dynamic"]) + + if config.has("cursor.voxel_raycasting"): + set_voxel_raycasting(config["cursor.voxel_raycasting"]) + + if config.has("cursor.color"): + set_cursor_color(config["cursor.color"]) + + if config.has("grid.visible"): + set_grid_visible(config["grid.visible"]) + if config.has("grid.mode"): + set_grid_mode(config["grid.mode"]) + if config.has("grid.color"): + set_grid_color(config["grid.color"]) + if config.has("grid.constant"): + set_grid_constant(config["grid.constant"]) + if config.has("grid.size"): + set_grid_size(config["grid.size"]) + + +# Sets the current editor config to default +func reset_config() -> void: + config = ConfigDefault.duplicate() + save_config() + load_config() + + +# Attempts to raycast for the VoxelObject +func raycast_for(camera : Camera, screen_position : Vector2, target : Node) -> Dictionary: + var hit := {} + var from := camera.project_ray_origin(screen_position) + var direction := camera.project_ray_normal(screen_position) + + if VoxelRaycasting.pressed: + hit = voxel_object.intersect_ray(from, direction, 64, funcref(self, "_raycast_stop")) + else: + var exclude := [] + var to := from + direction * 1000 + while true: + hit = camera.get_world().direct_space_state.intersect_ray(from, to, exclude) + if not hit.empty(): + if target.is_a_parent_of(hit.collider): + if _grid.is_a_parent_of(hit.collider): + hit["normal"] = Vector3.ZERO + hit["position"] = Voxel.world_to_grid( + voxel_object.to_local( + hit.position + -hit.normal * (Voxel.VoxelWorldSize / 2))) + hit["normal"] = hit["normal"].round() + break + else: + exclude.append(hit.collider) + else: + break + + return hit + + +# Returns given grid position mirrored in accordance to mirror +func mirror_position(position : Vector3, mirror : Vector3) -> Vector3: + match mirror: + Vector3(1, 0, 0): + return Vector3(position.x, position.y, (position.z + 1) * -1) + Vector3(1, 0, 1): + return Vector3((position.x + 1) * -1, position.y, (position.z + 1) * -1) + Vector3(0, 1, 0): + return Vector3(position.x, (position.y + 1) * -1, position.z) + Vector3(1, 1, 0): + return Vector3(position.x, (position.y + 1) * -1, (position.z + 1) * -1) + Vector3(0, 1, 1): + return Vector3((position.x + 1) * -1, (position.y + 1) * -1, position.z) + Vector3(1, 1, 1): + return Vector3((position.x + 1) * -1, (position.y + 1) * -1, (position.z + 1) * -1) + Vector3(0, 0, 1): + return Vector3((position.x + 1) * -1, position.y, position.z) + return position + + +# Mirrors and returns given grid positions in accordance to mirror +func mirror_positions(positions : Array, mirror : Vector3) -> Array: + var mirrored := [] + for position in positions: + match typeof(position): + TYPE_VECTOR3: + mirrored.append(mirror_position(position, mirror)) + TYPE_ARRAY: + var mirroring := [] + for index in range(position.size()): + mirroring.append(mirror_position(position[index], mirror)) + mirrored.append(mirroring) + return mirrored + + +# Disconnects the previous VoxelSet and connects the given VoxelSet +func setup_voxel_set(voxel_set : VoxelSet) -> void: + VoxelSetViewer.voxel_set = voxel_set + VoxelSetViewer.unselect_all() + if is_instance_valid(voxel_set) and not voxel_set.empty(): + var first_voxel_id = voxel_set.get_ids()[0] + _palette.clear() + _palette.append(first_voxel_id) + _palette.append(first_voxel_id) + VoxelSetViewer.select(first_voxel_id) + + Editing.pressed = false + Editing.disabled = not is_instance_valid(voxel_set) + Options.visible = is_instance_valid(voxel_set) + Notice.visible = not is_instance_valid(voxel_set) + + +# Attach editor components to current voxelobject +func attach_editor_components() -> void: + detach_editor_components() + voxel_object.add_child(_grid) + for cursor in _cursors.values(): + voxel_object.add_child(cursor) + + +# Detach editor components from their parents +func detach_editor_components() -> void: + if is_instance_valid(_grid.get_parent()): + _grid.get_parent().remove_child(_grid) + for cursor in _cursors: + cursor = _cursors[cursor] + if is_instance_valid(cursor.get_parent()): + cursor.get_parent().remove_child(cursor) + + +# Disconnect previous edited VoxelObject and starts editing the new one +func start_editing(new_voxel_object : VoxelObject) -> void: + if new_voxel_object == voxel_object: + return + + stop_editing() + + voxel_object = new_voxel_object + + setup_voxel_set(voxel_object.voxel_set) + voxel_object.connect("set_voxel_set", self, "setup_voxel_set") + voxel_object.connect("tree_exiting", self, "stop_editing", [true]) + + +# Disconnect currently edited VoxelObject +func stop_editing(close := false) -> void: + if is_instance_valid(voxel_object): + voxel_object.edit_hint = 0 + + detach_editor_components() + + voxel_object.disconnect("set_voxel_set", self, "setup_voxel_set") + voxel_object.disconnect("tree_exiting", self, "stop_editing") + + Editing.pressed = false + voxel_object = null + + if close: + emit_signal("close") + + +func get_tool_normal() -> int: + return _tools[Tool.get_selected_id()].tool_normal + +# Applies current tool +func work_tool() -> void: + _tools[Tool.get_selected_id()].work(self) + + +# Handles editor input +func handle_input(camera : Camera, event : InputEvent) -> bool: + if is_instance_valid(voxel_object): + if event is InputEventMouse: + var prev_hit = last_hit + last_hit = raycast_for(camera, event.position, voxel_object) + if Editing.pressed: + if event.button_mask & ~BUTTON_MASK_LEFT > 0 or (event is InputEventMouseButton and not event.button_index == BUTTON_LEFT): + set_cursors_visibility(false) + return false + + var handle_result = _selection_modes[SelectionMode.get_selected_id()].select( + self, + event, + prev_hit) + + if not GridConstant.pressed: + _grid.disabled = is_grid_disabled() + + return handle_result + return false + + +# Shows color menu centered +func show_color_menu(color := ColorPicked.color) -> void: + ColorMenuColor.color = color + ColorMenu.popup_centered() + + +# Hide color menu +func hide_color_menu() -> void: + ColorMenu.hide() + + +# Shows import menu centered +func show_import_menu() -> void: + ImportMenu.popup_centered() + + +# Hides import menu +func hide_import_menu() -> void: + ImportMenu.hide() + + + +## Private Methods +func _raycast_stop(hit : Dictionary) -> bool: + if not is_grid_disabled() and (hit["position"].y == -1 or hit["position"].y == 0): + hit["normal"] = Vector3.ZERO + return true + return false + + +func _update_editing_hint() -> void: + if is_instance_valid(voxel_object): + var flag = 0 + if Editing.pressed: + if VoxelRaycasting.pressed: + flag = 1 + else: + flag = 2 + voxel_object.edit_hint = flag + + +func _on_Editing_toggled(editing : bool): + _update_editing_hint() + + _grid.disabled = is_grid_disabled() + set_cursors_visibility(editing) + if editing: + attach_editor_components() + set_cursors_selections() + + emit_signal("editing", editing) + + +func _on_ColorMenu_Add_pressed(): + var voxel_id = voxel_object.voxel_set.size() + undo_redo.create_action("VoxelObjectEditor : Add voxel to used VoxeSet") + undo_redo.add_do_method(voxel_object.voxel_set, "add_voxel", Voxel.colored(ColorMenuColor.color)) + undo_redo.add_undo_method(voxel_object.voxel_set, "erase_voxel", voxel_id) + undo_redo.add_do_method(voxel_object.voxel_set, "request_refresh") + undo_redo.add_undo_method(voxel_object.voxel_set, "request_refresh") + undo_redo.commit_action() + VoxelSetViewer.select(voxel_id) + hide_color_menu() + + +func _on_Tool_selected(id : int): + update_mirrors(_tools[id].mirror_modes) + update_selections(_tools[id].selection_modes) + + +func _on_Palette_selected(id : int) -> void: + set_palette(Palette.get_selected_id(), _palette[Palette.get_selected_id()]) + + +func _on_SelectionMode_selected(id : int): + set_cursors_selections() + + +func _on_VoxelSetViewer_selected(voxel_id : int) -> void: + set_palette(Palette.get_selected_id(), voxel_id) + + +func _on_NewVoxelSet_pressed(): + voxel_object.voxel_set = VoxelSet.new() + voxel_object.property_list_changed_notify() + + +func _on_Translate_Apply_pressed(): + var translation := Vector3(MoveX.value, MoveY.value, MoveZ.value) + undo_redo.create_action("VoxelObjectEditor : Moved voxels") + undo_redo.add_do_method(voxel_object, "move", translation) + undo_redo.add_undo_method(voxel_object, "move", -translation) + undo_redo.add_do_method(voxel_object, "update_mesh") + undo_redo.add_undo_method(voxel_object, "update_mesh") + undo_redo.commit_action() + + +func _on_Center_Apply_pressed(): + var translation = voxel_object.vec_to_center(Vector3( + CenterX.value, + CenterY.value, + CenterZ.value)) + undo_redo.create_action("VoxelObjectEditor : Center voxels") + undo_redo.add_do_method(voxel_object, "move", translation) + undo_redo.add_undo_method(voxel_object, "move", -translation) + undo_redo.add_do_method(voxel_object, "update_mesh") + undo_redo.add_undo_method(voxel_object, "update_mesh") + undo_redo.commit_action() + + +func _on_Flip_X_pressed(): + undo_redo.create_action("VoxelObjectEditor : X flip voxels") + undo_redo.add_do_method(voxel_object, "flip", true, false, false) + undo_redo.add_undo_method(voxel_object, "flip", true, false, false) + undo_redo.add_do_method(voxel_object, "update_mesh") + undo_redo.add_undo_method(voxel_object, "update_mesh") + undo_redo.commit_action() + + +func _on_Flip_Y_pressed(): + undo_redo.create_action("VoxelObjectEditor : Y flip voxels") + undo_redo.add_do_method(voxel_object, "flip", false, true, false) + undo_redo.add_undo_method(voxel_object, "flip", false, true, false) + undo_redo.add_do_method(voxel_object, "update_mesh") + undo_redo.add_undo_method(voxel_object, "update_mesh") + undo_redo.commit_action() + + +func _on_Flip_Z_pressed(): + undo_redo.create_action("VoxelObjectEditor : Z flip voxels") + undo_redo.add_do_method(voxel_object, "flip", false, false, true) + undo_redo.add_undo_method(voxel_object, "flip", false, false, true) + undo_redo.add_do_method(voxel_object, "update_mesh") + undo_redo.add_undo_method(voxel_object, "update_mesh") + undo_redo.commit_action() + + +func _on_Clear_pressed(): + var voxels = {} + for voxel in voxel_object.get_voxels(): + voxels[voxel] = voxel_object.get_voxel_id(voxel) + undo_redo.create_action("VoxelObjectEditor : Clear voxels") + undo_redo.add_do_method(voxel_object, "erase_voxels") + undo_redo.add_undo_method(voxel_object, "set_voxels", voxels) + undo_redo.add_do_method(voxel_object, "update_mesh") + undo_redo.add_undo_method(voxel_object, "update_mesh") + undo_redo.commit_action() + + +func _on_ImportFile_file_selected(path : String): + import_file_path = path + if is_instance_valid(voxel_object.voxel_set): + ImportHow.popup_centered() + else: + _on_Import_New_pressed() + + +func _on_Import_Overwrite_pressed(): + var result := voxel_object.load_file(import_file_path, false) + if result == OK: + voxel_object.voxel_set.request_refresh() + else: + printerr(result) + ImportHow.hide() + + +func _on_Import_New_pressed(): + var result := voxel_object.load_file(import_file_path, true) + if result == OK: + voxel_object.voxel_set.request_refresh() + else: + printerr(result) + ImportHow.hide() + + +func _on_Import_Cancel_pressed(): + ImportHow.hide() + + +func _on_Docs_pressed(): + OS.shell_open("https://github.com/ClarkThyLord/voxel-core/wiki") + + +func _on_Issues_pressed(): + OS.shell_open("https://github.com/ClarkThyLord/voxel-core/issues") + + +func _on_GitHub_pressed(): + OS.shell_open("https://github.com/ClarkThyLord/Voxel-Core") + + +func _on_Update_pressed(): + voxel_object.update_mesh() + + +func _on_Grid_Size_X_value_changed(value : int): + set_grid_size(Vector2(value, _grid.grid_size.z)) + + +func _on_Grid_Size_Z_value_changed(value : int): + set_grid_size(Vector2(_grid.grid_size.x, value)) diff --git a/assets/addons/voxel-core/engine/voxel_object_editor/voxel_object_editor.tscn b/assets/addons/voxel-core/engine/voxel_object_editor/voxel_object_editor.tscn new file mode 100644 index 0000000..2ac31ca --- /dev/null +++ b/assets/addons/voxel-core/engine/voxel_object_editor/voxel_object_editor.tscn @@ -0,0 +1,1011 @@ +[gd_scene load_steps=46 format=2] + +[ext_resource path="res://assets/addons/voxel-core/assets/controls/secondary.png" type="Texture" id=1] +[ext_resource path="res://assets/addons/voxel-core/assets/controls/solid.png" type="Texture" id=2] +[ext_resource path="res://assets/addons/voxel-core/assets/controls/cursor.png" type="Texture" id=3] +[ext_resource path="res://assets/addons/voxel-core/assets/controls/fill.png" type="Texture" id=4] +[ext_resource path="res://assets/addons/voxel-core/assets/classes/voxel_core.png" type="Texture" id=5] +[ext_resource path="res://assets/addons/voxel-core/assets/controls/primary.png" type="Texture" id=6] +[ext_resource path="res://assets/addons/voxel-core/assets/controls/export.png" type="Texture" id=7] +[ext_resource path="res://assets/addons/voxel-core/assets/controls/extrude.png" type="Texture" id=8] +[ext_resource path="res://assets/addons/voxel-core/assets/controls/import.png" type="Texture" id=9] +[ext_resource path="res://assets/addons/voxel-core/assets/controls/sub.png" type="Texture" id=10] +[ext_resource path="res://assets/addons/voxel-core/assets/controls/docs.png" type="Texture" id=11] +[ext_resource path="res://assets/addons/voxel-core/assets/controls/area.png" type="Texture" id=12] +[ext_resource path="res://assets/addons/voxel-core/assets/controls/add.png" type="Texture" id=13] +[ext_resource path="res://assets/addons/voxel-core/controls/voxel_set_viewer/voxel_set_viewer.tscn" type="PackedScene" id=14] +[ext_resource path="res://assets/addons/voxel-core/engine/voxel_object_editor/voxel_object_editor.gd" type="Script" id=15] +[ext_resource path="res://assets/addons/voxel-core/assets/controls/mirrorx.png" type="Texture" id=16] +[ext_resource path="res://assets/addons/voxel-core/assets/controls/refresh.png" type="Texture" id=17] +[ext_resource path="res://assets/addons/voxel-core/assets/controls/reset.png" type="Texture" id=18] +[ext_resource path="res://assets/addons/voxel-core/assets/controls/mirrory.png" type="Texture" id=19] +[ext_resource path="res://assets/addons/voxel-core/assets/controls/general.png" type="Texture" id=20] +[ext_resource path="res://assets/addons/voxel-core/assets/controls/issues.png" type="Texture" id=21] +[ext_resource path="res://assets/addons/voxel-core/assets/controls/swap.png" type="Texture" id=22] +[ext_resource path="res://assets/addons/voxel-core/assets/controls/wired.png" type="Texture" id=23] +[ext_resource path="res://assets/addons/voxel-core/assets/controls/pick.png" type="Texture" id=24] +[ext_resource path="res://assets/addons/voxel-core/assets/controls/individual.png" type="Texture" id=25] +[ext_resource path="res://assets/addons/voxel-core/assets/logos/GitHub.png" type="Texture" id=26] +[ext_resource path="res://assets/addons/voxel-core/assets/controls/grid.png" type="Texture" id=27] +[ext_resource path="res://assets/addons/voxel-core/assets/controls/edit.png" type="Texture" id=28] +[ext_resource path="res://assets/addons/voxel-core/assets/controls/mirrorz.png" type="Texture" id=29] + +[sub_resource type="InputEventKey" id=1] +scancode = 32 + +[sub_resource type="ShortCut" id=2] +shortcut = SubResource( 1 ) + +[sub_resource type="InputEventKey" id=3] +scancode = 49 + +[sub_resource type="ShortCut" id=4] +shortcut = SubResource( 3 ) + +[sub_resource type="InputEventKey" id=5] +scancode = 50 + +[sub_resource type="ShortCut" id=6] +shortcut = SubResource( 5 ) + +[sub_resource type="InputEventKey" id=7] +scancode = 51 + +[sub_resource type="ShortCut" id=8] +shortcut = SubResource( 7 ) + +[sub_resource type="InputEventKey" id=9] +shift = true +scancode = 49 + +[sub_resource type="ShortCut" id=10] +shortcut = SubResource( 9 ) + +[sub_resource type="InputEventKey" id=11] +shift = true +scancode = 50 + +[sub_resource type="ShortCut" id=12] +shortcut = SubResource( 11 ) + +[sub_resource type="InputEventKey" id=13] +shift = true +scancode = 51 + +[sub_resource type="ShortCut" id=14] +shortcut = SubResource( 13 ) + +[sub_resource type="InputEventKey" id=15] +scancode = 52 + +[sub_resource type="ShortCut" id=16] +shortcut = SubResource( 15 ) + +[node name="Control" type="Control"] +anchor_right = 1.0 +rect_min_size = Vector2( 0, 200 ) +script = ExtResource( 15 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="VoxelObjectEditor" type="ScrollContainer" parent="."] +anchor_right = 1.0 +anchor_bottom = 1.0 +rect_min_size = Vector2( 0, 200 ) +size_flags_horizontal = 3 +size_flags_vertical = 3 +follow_focus = true +scroll_vertical_enabled = false +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="HBoxContainer" type="HBoxContainer" parent="VoxelObjectEditor"] +margin_right = 1024.0 +margin_bottom = 200.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="VBoxContainer" type="VBoxContainer" parent="VoxelObjectEditor/HBoxContainer"] +margin_right = 332.0 +margin_bottom = 200.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="HBoxContainer" type="HBoxContainer" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer"] +margin_right = 332.0 +margin_bottom = 24.0 + +[node name="ToolButton" type="ToolButton" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer/HBoxContainer"] +margin_right = 109.0 +margin_bottom = 24.0 +mouse_filter = 2 +text = "VoxelObject" +icon = ExtResource( 5 ) + +[node name="HSeparator" type="HSeparator" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer/HBoxContainer"] +margin_left = 113.0 +margin_right = 175.0 +margin_bottom = 24.0 +size_flags_horizontal = 3 + +[node name="Editing" type="CheckBox" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer/HBoxContainer"] +margin_left = 179.0 +margin_right = 270.0 +margin_bottom = 24.0 +hint_tooltip = "Enable editing" +shortcut = SubResource( 2 ) +text = "Editing" +icon = ExtResource( 28 ) +flat = true + +[node name="Update" type="Button" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer/HBoxContainer"] +margin_left = 274.0 +margin_right = 332.0 +margin_bottom = 24.0 +hint_tooltip = "Update voxel content" +text = "Update" + +[node name="Options" type="VBoxContainer" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer"] +margin_top = 28.0 +margin_right = 332.0 +margin_bottom = 200.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="VBoxContainer" type="VBoxContainer" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer/Options"] +margin_right = 332.0 +margin_bottom = 74.0 + +[node name="HBoxContainer" type="HBoxContainer" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer/Options/VBoxContainer"] +margin_right = 332.0 +margin_bottom = 22.0 + +[node name="Tool" type="OptionButton" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer/Options/VBoxContainer/HBoxContainer"] +margin_right = 107.0 +margin_bottom = 22.0 +hint_tooltip = "Tools" +size_flags_horizontal = 3 +shortcut = SubResource( 4 ) +text = "Add" +icon = ExtResource( 13 ) +items = [ "Add", ExtResource( 13 ), false, 0, null, "Sub", ExtResource( 10 ), false, 1, null, "Swap", ExtResource( 22 ), false, 2, null, "Fill", ExtResource( 4 ), false, 3, null, "Pick", ExtResource( 24 ), false, 4, null ] +selected = 0 + +[node name="Palette" type="OptionButton" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer/Options/VBoxContainer/HBoxContainer"] +margin_left = 111.0 +margin_right = 218.0 +margin_bottom = 22.0 +hint_tooltip = "Palettes" +size_flags_horizontal = 3 +shortcut = SubResource( 6 ) +text = "Primary" +icon = ExtResource( 6 ) +items = [ "Primary", ExtResource( 6 ), false, 0, null, "Secondary", ExtResource( 1 ), false, 1, null ] +selected = 0 + +[node name="SelectionMode" type="OptionButton" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer/Options/VBoxContainer/HBoxContainer"] +margin_left = 222.0 +margin_right = 332.0 +margin_bottom = 22.0 +hint_tooltip = "Selection modes" +size_flags_horizontal = 3 +shortcut = SubResource( 8 ) +text = "Individual" +icon = ExtResource( 25 ) +items = [ "Individual", ExtResource( 25 ), false, 0, null, "Area", ExtResource( 12 ), false, 1, null, "Extrude", ExtResource( 8 ), false, 2, null ] +selected = 0 + +[node name="HBoxContainer2" type="HBoxContainer" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer/Options/VBoxContainer"] +margin_top = 26.0 +margin_right = 332.0 +margin_bottom = 50.0 +alignment = 1 + +[node name="MirrorX" type="CheckBox" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer/Options/VBoxContainer/HBoxContainer2"] +margin_right = 108.0 +margin_bottom = 24.0 +hint_tooltip = "Mirror operations over x-axis" +size_flags_horizontal = 3 +shortcut = SubResource( 10 ) +text = "Mirror X" +icon = ExtResource( 19 ) + +[node name="MirrorY" type="CheckBox" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer/Options/VBoxContainer/HBoxContainer2"] +margin_left = 112.0 +margin_right = 220.0 +margin_bottom = 24.0 +hint_tooltip = "Mirror operations over y-axis" +size_flags_horizontal = 3 +shortcut = SubResource( 12 ) +text = "Mirror Y" +icon = ExtResource( 16 ) + +[node name="MirrorZ" type="CheckBox" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer/Options/VBoxContainer/HBoxContainer2"] +margin_left = 224.0 +margin_right = 332.0 +margin_bottom = 24.0 +hint_tooltip = "Mirror operations over z-axis" +size_flags_horizontal = 3 +shortcut = SubResource( 14 ) +text = "Mirror Z" +icon = ExtResource( 29 ) + +[node name="ColorChooser" type="Button" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer/Options/VBoxContainer"] +margin_top = 54.0 +margin_right = 332.0 +margin_bottom = 74.0 +hint_tooltip = "Add voxel to VoxelSet" +size_flags_horizontal = 3 +shortcut = SubResource( 16 ) + +[node name="ColorPicked" type="ColorRect" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer/Options/VBoxContainer/ColorChooser"] +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_left = 4.0 +margin_top = 4.0 +margin_right = -4.0 +margin_bottom = -4.0 +mouse_filter = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +__meta__ = { +"_edit_lock_": true, +"_edit_use_anchors_": false +} + +[node name="VoxelSetViewer" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer/Options" instance=ExtResource( 14 )] +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_top = 78.0 +margin_right = 332.0 +margin_bottom = 172.0 +size_flags_vertical = 3 +selection_max = 1 + +[node name="Notice" type="VBoxContainer" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer"] +visible = false +margin_left = 115.0 +margin_top = 122.0 +margin_right = 216.0 +margin_bottom = 194.0 +size_flags_horizontal = 6 +size_flags_vertical = 6 + +[node name="Label" type="Label" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer/Notice"] +margin_right = 101.0 +margin_bottom = 48.0 +text = "No set VoxelSet +set / load one +or" +align = 1 + +[node name="NewVoxelSet" type="Button" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer/Notice"] +margin_top = 52.0 +margin_right = 101.0 +margin_bottom = 72.0 +text = "New VoxelSet" + +[node name="VSeparator" type="VSeparator" parent="VoxelObjectEditor/HBoxContainer"] +margin_left = 336.0 +margin_right = 340.0 +margin_bottom = 200.0 + +[node name="VBoxContainer2" type="VBoxContainer" parent="VoxelObjectEditor/HBoxContainer"] +margin_left = 344.0 +margin_right = 679.0 +margin_bottom = 200.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="ScrollContainer" type="ScrollContainer" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2"] +margin_right = 335.0 +margin_bottom = 200.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 +follow_focus = true +scroll_horizontal_enabled = false +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="VBoxContainer" type="VBoxContainer" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer"] +margin_right = 335.0 +margin_bottom = 200.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="EditHeader" type="HBoxContainer" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer"] +margin_right = 335.0 +margin_bottom = 22.0 + +[node name="ToolButton" type="ToolButton" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/EditHeader"] +margin_right = 36.0 +margin_bottom = 22.0 +text = "Edit" + +[node name="HSeparator" type="HSeparator" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/EditHeader"] +margin_left = 40.0 +margin_right = 335.0 +margin_bottom = 22.0 +size_flags_horizontal = 3 + +[node name="Move" type="HBoxContainer" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer"] +margin_top = 26.0 +margin_right = 335.0 +margin_bottom = 50.0 + +[node name="Label" type="Label" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/Move"] +margin_top = 5.0 +margin_right = 12.0 +margin_bottom = 19.0 +text = "X:" + +[node name="X" type="SpinBox" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/Move"] +margin_left = 16.0 +margin_right = 90.0 +margin_bottom = 24.0 +hint_tooltip = "X translation" +rounded = true +allow_greater = true +allow_lesser = true + +[node name="Label2" type="Label" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/Move"] +margin_left = 94.0 +margin_top = 5.0 +margin_right = 105.0 +margin_bottom = 19.0 +text = "Y:" + +[node name="Y" type="SpinBox" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/Move"] +margin_left = 109.0 +margin_right = 183.0 +margin_bottom = 24.0 +hint_tooltip = "Y translation" +rounded = true +allow_greater = true +allow_lesser = true + +[node name="Label3" type="Label" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/Move"] +margin_left = 187.0 +margin_top = 5.0 +margin_right = 199.0 +margin_bottom = 19.0 +text = "Z:" + +[node name="Z" type="SpinBox" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/Move"] +margin_left = 203.0 +margin_right = 277.0 +margin_bottom = 24.0 +hint_tooltip = "Z translation" +rounded = true +allow_greater = true +allow_lesser = true + +[node name="Apply" type="Button" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/Move"] +margin_left = 281.0 +margin_right = 335.0 +margin_bottom = 24.0 +hint_tooltip = "Move all voxels by translation" +size_flags_horizontal = 3 +text = "Move" + +[node name="Center" type="HBoxContainer" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer"] +margin_top = 54.0 +margin_right = 335.0 +margin_bottom = 78.0 + +[node name="Label" type="Label" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/Center"] +margin_top = 5.0 +margin_right = 12.0 +margin_bottom = 19.0 +text = "X:" + +[node name="X" type="SpinBox" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/Center"] +margin_left = 16.0 +margin_right = 90.0 +margin_bottom = 24.0 +hint_tooltip = "X-axis alignment +1.0, RIGHT of axis +0.0, LEFT of axis" +max_value = 1.0 +step = 0.1 +value = 0.5 + +[node name="Label2" type="Label" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/Center"] +margin_left = 94.0 +margin_top = 5.0 +margin_right = 105.0 +margin_bottom = 19.0 +text = "Y:" + +[node name="Y" type="SpinBox" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/Center"] +margin_left = 109.0 +margin_right = 183.0 +margin_bottom = 24.0 +hint_tooltip = "Y-axis alignment +1.0, UP of axis +0.0, DOWN of axis" +max_value = 1.0 +step = 0.1 +value = 0.5 + +[node name="Label3" type="Label" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/Center"] +margin_left = 187.0 +margin_top = 5.0 +margin_right = 199.0 +margin_bottom = 19.0 +text = "Z:" + +[node name="Z" type="SpinBox" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/Center"] +margin_left = 203.0 +margin_right = 277.0 +margin_bottom = 24.0 +hint_tooltip = "Z-axis alignment +1.0, FORWARD of axis +0.0, BACK of axis" +max_value = 1.0 +step = 0.1 +value = 0.5 + +[node name="Apply" type="Button" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/Center"] +margin_left = 281.0 +margin_right = 335.0 +margin_bottom = 24.0 +hint_tooltip = "Center all voxels with alignment" +size_flags_horizontal = 3 +text = "Center" + +[node name="Flip" type="HBoxContainer" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer"] +margin_top = 82.0 +margin_right = 335.0 +margin_bottom = 102.0 + +[node name="X" type="Button" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/Flip"] +margin_right = 109.0 +margin_bottom = 20.0 +hint_tooltip = "Flip voxels over x-axis" +size_flags_horizontal = 3 +text = "Flip X" + +[node name="Y" type="Button" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/Flip"] +margin_left = 113.0 +margin_right = 222.0 +margin_bottom = 20.0 +hint_tooltip = "Flip voxels over y-axis" +size_flags_horizontal = 3 +text = "Flip Y" + +[node name="Z" type="Button" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/Flip"] +margin_left = 226.0 +margin_right = 335.0 +margin_bottom = 20.0 +hint_tooltip = "Flip voxels over z-axis" +size_flags_horizontal = 3 +text = "Flip Z" + +[node name="Clear" type="Button" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer"] +margin_top = 106.0 +margin_right = 335.0 +margin_bottom = 126.0 +hint_tooltip = "Removes all voxels" +text = "Clear Voxels" + +[node name="FileHeader" type="HBoxContainer" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer"] +margin_top = 130.0 +margin_right = 335.0 +margin_bottom = 152.0 + +[node name="ToolButton" type="ToolButton" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/FileHeader"] +margin_right = 35.0 +margin_bottom = 22.0 +text = "File" + +[node name="HSeparator" type="HSeparator" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/FileHeader"] +margin_left = 39.0 +margin_right = 335.0 +margin_bottom = 22.0 +size_flags_horizontal = 3 + +[node name="File" type="HBoxContainer" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer"] +margin_top = 156.0 +margin_right = 335.0 +margin_bottom = 178.0 + +[node name="Export" type="Button" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/File"] +visible = false +margin_right = 173.0 +margin_bottom = 22.0 +size_flags_horizontal = 3 +text = "Export" +icon = ExtResource( 7 ) + +[node name="Import" type="Button" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/File"] +margin_right = 335.0 +margin_bottom = 22.0 +hint_tooltip = "Import voxels from file" +size_flags_horizontal = 3 +text = "Import" +icon = ExtResource( 9 ) + +[node name="ImportFile" type="FileDialog" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/File/Import"] +margin_right = 400.0 +margin_bottom = 300.0 +rect_min_size = Vector2( 400, 300 ) +window_title = "Open a File" +resizable = true +mode = 0 +filters = PoolStringArray( "*.vox ; VOX Files", "*.png, *.bmp, *.dds, *.exr, *.hdr, *.jpg, *.jpeg, *.tga, *.svg, *.svgz, *.webp; Image Files" ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="ImportHow" type="PopupDialog" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/File/Import"] +margin_right = 322.0 +margin_bottom = 97.0 +rect_min_size = Vector2( 325, 100 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="VBoxContainer" type="VBoxContainer" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/File/Import/ImportHow"] +anchor_right = 1.0 +anchor_bottom = 1.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Label" type="Label" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/File/Import/ImportHow/VBoxContainer"] +margin_right = 325.0 +margin_bottom = 48.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 +text = "Overwrite or make new VoxelSet?" +align = 1 +valign = 1 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="HBoxContainer" type="HBoxContainer" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/File/Import/ImportHow/VBoxContainer"] +margin_top = 52.0 +margin_right = 325.0 +margin_bottom = 100.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 +alignment = 1 + +[node name="Overwrite" type="Button" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/File/Import/ImportHow/VBoxContainer/HBoxContainer"] +margin_left = 15.0 +margin_top = 14.0 +margin_right = 149.0 +margin_bottom = 34.0 +size_flags_horizontal = 4 +size_flags_vertical = 4 +text = "Overwrite VoxelSet" + +[node name="New" type="Button" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/File/Import/ImportHow/VBoxContainer/HBoxContainer"] +margin_left = 153.0 +margin_top = 14.0 +margin_right = 252.0 +margin_bottom = 34.0 +size_flags_horizontal = 4 +size_flags_vertical = 4 +text = "New VoxelSet" + +[node name="Cancel" type="Button" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/File/Import/ImportHow/VBoxContainer/HBoxContainer"] +margin_left = 256.0 +margin_top = 14.0 +margin_right = 310.0 +margin_bottom = 34.0 +size_flags_horizontal = 4 +size_flags_vertical = 4 +text = "Cancel" + +[node name="VSeparator2" type="VSeparator" parent="VoxelObjectEditor/HBoxContainer"] +margin_left = 683.0 +margin_right = 687.0 +margin_bottom = 200.0 + +[node name="VBoxContainer3" type="VBoxContainer" parent="VoxelObjectEditor/HBoxContainer"] +margin_left = 691.0 +margin_right = 1024.0 +margin_bottom = 200.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="Settings" type="TabContainer" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer3"] +margin_right = 333.0 +margin_bottom = 200.0 +size_flags_vertical = 3 +tab_align = 0 + +[node name="General" type="VBoxContainer" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings"] +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_left = 4.0 +margin_top = 34.0 +margin_right = -4.0 +margin_bottom = -4.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 +__meta__ = { +"_tab_icon": ExtResource( 20 ) +} + +[node name="ScrollContainer" type="ScrollContainer" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/General"] +margin_right = 325.0 +margin_bottom = 162.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 +follow_focus = true +scroll_horizontal_enabled = false +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="VBoxContainer" type="VBoxContainer" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/General/ScrollContainer"] +margin_right = 325.0 +margin_bottom = 162.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="HBoxContainer2" type="HBoxContainer" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/General/ScrollContainer/VBoxContainer"] +margin_right = 325.0 +margin_bottom = 136.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 +alignment = 1 + +[node name="Docs" type="ToolButton" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/General/ScrollContainer/VBoxContainer/HBoxContainer2"] +margin_left = 52.0 +margin_top = 56.0 +margin_right = 115.0 +margin_bottom = 80.0 +mouse_default_cursor_shape = 2 +size_flags_horizontal = 4 +size_flags_vertical = 4 +text = "Docs" +icon = ExtResource( 11 ) +align = 0 + +[node name="Issues" type="ToolButton" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/General/ScrollContainer/VBoxContainer/HBoxContainer2"] +margin_left = 119.0 +margin_top = 56.0 +margin_right = 192.0 +margin_bottom = 80.0 +mouse_default_cursor_shape = 2 +size_flags_horizontal = 4 +size_flags_vertical = 4 +text = "Issues" +icon = ExtResource( 21 ) +align = 0 + +[node name="GitHub" type="ToolButton" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/General/ScrollContainer/VBoxContainer/HBoxContainer2"] +margin_left = 196.0 +margin_top = 56.0 +margin_right = 272.0 +margin_bottom = 80.0 +mouse_default_cursor_shape = 2 +size_flags_horizontal = 4 +size_flags_vertical = 4 +text = "GitHub" +icon = ExtResource( 26 ) +align = 0 + +[node name="HBoxContainer" type="HBoxContainer" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/General/ScrollContainer/VBoxContainer"] +margin_top = 140.0 +margin_right = 325.0 +margin_bottom = 162.0 +size_flags_horizontal = 3 + +[node name="SettingsRefresh" type="Button" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/General/ScrollContainer/VBoxContainer/HBoxContainer"] +margin_right = 160.0 +margin_bottom = 22.0 +hint_tooltip = "Reload config file" +size_flags_horizontal = 3 +size_flags_vertical = 0 +text = "Refresh Settings" +icon = ExtResource( 17 ) +align = 0 + +[node name="SettingsReset2" type="Button" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/General/ScrollContainer/VBoxContainer/HBoxContainer"] +margin_left = 164.0 +margin_right = 325.0 +margin_bottom = 22.0 +size_flags_horizontal = 3 +size_flags_vertical = 0 +text = "Reset Settings" +icon = ExtResource( 18 ) +align = 0 + +[node name="Cursor" type="VBoxContainer" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings"] +visible = false +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_left = 4.0 +margin_top = 34.0 +margin_right = -4.0 +margin_bottom = -4.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 +__meta__ = { +"_tab_icon": ExtResource( 3 ) +} + +[node name="ScrollContainer" type="ScrollContainer" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Cursor"] +margin_right = 325.0 +margin_bottom = 162.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 +follow_focus = true +scroll_horizontal_enabled = false +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="VBoxContainer" type="VBoxContainer" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Cursor/ScrollContainer"] +margin_right = 325.0 +margin_bottom = 162.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="VoxelRaycasting" type="CheckBox" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Cursor/ScrollContainer/VBoxContainer"] +margin_right = 325.0 +margin_bottom = 24.0 +hint_tooltip = "Might significantly improve performance when editing Voxel Object +!!! Warning Experimental !!!" +text = "Voxel Raycasting" + +[node name="CursorVisible" type="CheckBox" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Cursor/ScrollContainer/VBoxContainer"] +margin_top = 28.0 +margin_right = 325.0 +margin_bottom = 52.0 +pressed = true +text = "Visible" + +[node name="CursorDynamic" type="CheckBox" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Cursor/ScrollContainer/VBoxContainer"] +margin_top = 56.0 +margin_right = 325.0 +margin_bottom = 80.0 +hint_tooltip = "Cursor changes color based on selected palette" +pressed = true +text = "Dynamic Color" + +[node name="HBoxContainer" type="HBoxContainer" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Cursor/ScrollContainer/VBoxContainer"] +margin_top = 84.0 +margin_right = 325.0 +margin_bottom = 104.0 + +[node name="CursorColor" type="ColorPickerButton" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Cursor/ScrollContainer/VBoxContainer/HBoxContainer"] +margin_right = 32.0 +margin_bottom = 20.0 +rect_min_size = Vector2( 32, 0 ) +disabled = true +color = Color( 1, 1, 1, 0.75 ) + +[node name="Label" type="Label" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Cursor/ScrollContainer/VBoxContainer/HBoxContainer"] +margin_left = 36.0 +margin_top = 3.0 +margin_right = 114.0 +margin_bottom = 17.0 +text = "Cursor Color" + +[node name="Grid" type="VBoxContainer" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings"] +visible = false +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_left = 4.0 +margin_top = 34.0 +margin_right = -4.0 +margin_bottom = -4.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 +__meta__ = { +"_tab_icon": ExtResource( 27 ) +} + +[node name="ScrollContainer" type="ScrollContainer" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Grid"] +margin_right = 325.0 +margin_bottom = 162.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 +follow_focus = true +scroll_horizontal_enabled = false +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="VBoxContainer" type="VBoxContainer" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Grid/ScrollContainer"] +margin_right = 325.0 +margin_bottom = 162.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="GridVisible" type="CheckBox" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Grid/ScrollContainer/VBoxContainer"] +margin_right = 325.0 +margin_bottom = 24.0 +pressed = true +text = "Visible" + +[node name="GridConstant" type="CheckBox" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Grid/ScrollContainer/VBoxContainer"] +margin_top = 28.0 +margin_right = 325.0 +margin_bottom = 52.0 +hint_tooltip = "If disabled grid is only visible while VoxelObject is empty" +text = "Constant" + +[node name="HBoxContainer2" type="HBoxContainer" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Grid/ScrollContainer/VBoxContainer"] +margin_top = 56.0 +margin_right = 325.0 +margin_bottom = 76.0 + +[node name="GridColor" type="ColorPickerButton" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Grid/ScrollContainer/VBoxContainer/HBoxContainer2"] +margin_right = 32.0 +margin_bottom = 20.0 +rect_min_size = Vector2( 32, 0 ) +color = Color( 1, 1, 1, 1 ) + +[node name="Label" type="Label" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Grid/ScrollContainer/VBoxContainer/HBoxContainer2"] +margin_left = 36.0 +margin_top = 3.0 +margin_right = 100.0 +margin_bottom = 17.0 +text = "Grid Color" + +[node name="GridMode" type="OptionButton" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Grid/ScrollContainer/VBoxContainer"] +margin_top = 80.0 +margin_right = 325.0 +margin_bottom = 102.0 +text = "Wired" +icon = ExtResource( 23 ) +items = [ "Solid", ExtResource( 2 ), false, 0, null, "Wired", ExtResource( 23 ), false, 1, null ] +selected = 1 + +[node name="VBoxContainer" type="VBoxContainer" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Grid/ScrollContainer/VBoxContainer"] +margin_top = 106.0 +margin_right = 325.0 +margin_bottom = 148.0 + +[node name="Label" type="Label" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Grid/ScrollContainer/VBoxContainer/VBoxContainer"] +margin_right = 325.0 +margin_bottom = 14.0 +text = "Grid Size" + +[node name="Size" type="HBoxContainer" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Grid/ScrollContainer/VBoxContainer/VBoxContainer"] +margin_top = 18.0 +margin_right = 325.0 +margin_bottom = 42.0 +alignment = 1 + +[node name="Label" type="Label" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Grid/ScrollContainer/VBoxContainer/VBoxContainer/Size"] +margin_top = 5.0 +margin_right = 12.0 +margin_bottom = 19.0 +text = "X:" + +[node name="X" type="SpinBox" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Grid/ScrollContainer/VBoxContainer/VBoxContainer/Size"] +margin_left = 16.0 +margin_right = 160.0 +margin_bottom = 24.0 +hint_tooltip = "X-axis alignment +1.0, RIGHT of axis +0.0, LEFT of axis" +size_flags_horizontal = 3 +min_value = 1.0 +value = 16.0 +rounded = true +allow_greater = true + +[node name="Label3" type="Label" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Grid/ScrollContainer/VBoxContainer/VBoxContainer/Size"] +margin_left = 164.0 +margin_top = 5.0 +margin_right = 176.0 +margin_bottom = 19.0 +text = "Z:" + +[node name="Z" type="SpinBox" parent="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Grid/ScrollContainer/VBoxContainer/VBoxContainer/Size"] +margin_left = 180.0 +margin_right = 325.0 +margin_bottom = 24.0 +hint_tooltip = "X-axis alignment +1.0, RIGHT of axis +0.0, LEFT of axis" +size_flags_horizontal = 3 +min_value = 1.0 +value = 16.0 +rounded = true +allow_greater = true + +[node name="ColorMenu" type="WindowDialog" parent="."] +margin_right = 325.0 +margin_bottom = 545.0 +window_title = "Color Picker" +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="VBoxContainer" type="VBoxContainer" parent="ColorMenu"] +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_left = 5.0 +margin_top = 5.0 +margin_right = -5.0 +margin_bottom = -5.0 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Color" type="ColorPicker" parent="ColorMenu/VBoxContainer"] +margin_left = 20.0 +margin_top = 20.0 +margin_right = 335.0 +margin_bottom = 527.0 +size_flags_vertical = 3 +edit_alpha = false + +[node name="VSplitContainer" type="VSplitContainer" parent="ColorMenu/VBoxContainer"] +margin_top = 511.0 +margin_right = 315.0 +margin_bottom = 511.0 + +[node name="HBoxContainer" type="HBoxContainer" parent="ColorMenu/VBoxContainer"] +margin_top = 515.0 +margin_right = 315.0 +margin_bottom = 535.0 + +[node name="Add" type="Button" parent="ColorMenu/VBoxContainer/HBoxContainer"] +margin_right = 155.0 +margin_bottom = 20.0 +size_flags_horizontal = 3 +text = "Add To VoxelSet" + +[node name="Cancel" type="Button" parent="ColorMenu/VBoxContainer/HBoxContainer"] +margin_left = 159.0 +margin_right = 315.0 +margin_bottom = 20.0 +size_flags_horizontal = 3 +text = "Cancel" + +[connection signal="toggled" from="VoxelObjectEditor/HBoxContainer/VBoxContainer/HBoxContainer/Editing" to="." method="_on_Editing_toggled"] +[connection signal="pressed" from="VoxelObjectEditor/HBoxContainer/VBoxContainer/HBoxContainer/Update" to="." method="_on_Update_pressed"] +[connection signal="item_selected" from="VoxelObjectEditor/HBoxContainer/VBoxContainer/Options/VBoxContainer/HBoxContainer/Tool" to="." method="_on_Tool_selected"] +[connection signal="item_selected" from="VoxelObjectEditor/HBoxContainer/VBoxContainer/Options/VBoxContainer/HBoxContainer/Palette" to="." method="_on_Palette_selected"] +[connection signal="item_selected" from="VoxelObjectEditor/HBoxContainer/VBoxContainer/Options/VBoxContainer/HBoxContainer/SelectionMode" to="." method="_on_SelectionMode_selected"] +[connection signal="pressed" from="VoxelObjectEditor/HBoxContainer/VBoxContainer/Options/VBoxContainer/HBoxContainer2/MirrorX" to="." method="update_cursors"] +[connection signal="pressed" from="VoxelObjectEditor/HBoxContainer/VBoxContainer/Options/VBoxContainer/HBoxContainer2/MirrorY" to="." method="update_cursors"] +[connection signal="pressed" from="VoxelObjectEditor/HBoxContainer/VBoxContainer/Options/VBoxContainer/HBoxContainer2/MirrorZ" to="." method="update_cursors"] +[connection signal="pressed" from="VoxelObjectEditor/HBoxContainer/VBoxContainer/Options/VBoxContainer/ColorChooser" to="." method="show_color_menu"] +[connection signal="selected_voxel" from="VoxelObjectEditor/HBoxContainer/VBoxContainer/Options/VoxelSetViewer" to="." method="_on_VoxelSetViewer_selected"] +[connection signal="pressed" from="VoxelObjectEditor/HBoxContainer/VBoxContainer/Notice/NewVoxelSet" to="." method="_on_NewVoxelSet_pressed"] +[connection signal="pressed" from="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/Move/Apply" to="." method="_on_Translate_Apply_pressed"] +[connection signal="pressed" from="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/Center/Apply" to="." method="_on_Center_Apply_pressed"] +[connection signal="pressed" from="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/Flip/X" to="." method="_on_Flip_X_pressed"] +[connection signal="pressed" from="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/Flip/Y" to="." method="_on_Flip_Y_pressed"] +[connection signal="pressed" from="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/Flip/Z" to="." method="_on_Flip_Z_pressed"] +[connection signal="pressed" from="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/Clear" to="." method="_on_Clear_pressed"] +[connection signal="pressed" from="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/File/Import" to="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/File/Import/ImportFile" method="popup_centered"] +[connection signal="file_selected" from="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/File/Import/ImportFile" to="." method="_on_ImportFile_file_selected"] +[connection signal="pressed" from="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/File/Import/ImportHow/VBoxContainer/HBoxContainer/Overwrite" to="." method="_on_Import_Overwrite_pressed"] +[connection signal="pressed" from="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/File/Import/ImportHow/VBoxContainer/HBoxContainer/New" to="." method="_on_Import_New_pressed"] +[connection signal="pressed" from="VoxelObjectEditor/HBoxContainer/VBoxContainer2/ScrollContainer/VBoxContainer/File/Import/ImportHow/VBoxContainer/HBoxContainer/Cancel" to="." method="_on_Import_Cancel_pressed"] +[connection signal="pressed" from="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/General/ScrollContainer/VBoxContainer/HBoxContainer2/Docs" to="." method="_on_Docs_pressed"] +[connection signal="pressed" from="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/General/ScrollContainer/VBoxContainer/HBoxContainer2/Issues" to="." method="_on_Issues_pressed"] +[connection signal="pressed" from="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/General/ScrollContainer/VBoxContainer/HBoxContainer2/GitHub" to="." method="_on_GitHub_pressed"] +[connection signal="pressed" from="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/General/ScrollContainer/VBoxContainer/HBoxContainer/SettingsRefresh" to="." method="load_config"] +[connection signal="pressed" from="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/General/ScrollContainer/VBoxContainer/HBoxContainer/SettingsReset2" to="." method="reset_config"] +[connection signal="toggled" from="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Cursor/ScrollContainer/VBoxContainer/VoxelRaycasting" to="." method="set_voxel_raycasting"] +[connection signal="toggled" from="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Cursor/ScrollContainer/VBoxContainer/CursorVisible" to="." method="set_cursor_visible"] +[connection signal="toggled" from="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Cursor/ScrollContainer/VBoxContainer/CursorDynamic" to="." method="set_cursor_dynamic"] +[connection signal="color_changed" from="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Cursor/ScrollContainer/VBoxContainer/HBoxContainer/CursorColor" to="." method="set_cursor_color"] +[connection signal="toggled" from="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Grid/ScrollContainer/VBoxContainer/GridVisible" to="." method="set_grid_visible"] +[connection signal="toggled" from="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Grid/ScrollContainer/VBoxContainer/GridConstant" to="." method="set_grid_constant"] +[connection signal="color_changed" from="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Grid/ScrollContainer/VBoxContainer/HBoxContainer2/GridColor" to="." method="set_grid_color"] +[connection signal="item_selected" from="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Grid/ScrollContainer/VBoxContainer/GridMode" to="." method="set_grid_mode"] +[connection signal="value_changed" from="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Grid/ScrollContainer/VBoxContainer/VBoxContainer/Size/X" to="." method="_on_Grid_Size_X_value_changed"] +[connection signal="value_changed" from="VoxelObjectEditor/HBoxContainer/VBoxContainer3/Settings/Grid/ScrollContainer/VBoxContainer/VBoxContainer/Size/Z" to="." method="_on_Grid_Size_Z_value_changed"] +[connection signal="pressed" from="ColorMenu/VBoxContainer/HBoxContainer/Add" to="." method="_on_ColorMenu_Add_pressed"] +[connection signal="pressed" from="ColorMenu/VBoxContainer/HBoxContainer/Cancel" to="ColorMenu" method="hide"] diff --git a/assets/addons/voxel-core/engine/voxel_set_editor/voxel_set_editor.gd b/assets/addons/voxel-core/engine/voxel_set_editor/voxel_set_editor.gd new file mode 100644 index 0000000..53acba2 --- /dev/null +++ b/assets/addons/voxel-core/engine/voxel_set_editor/voxel_set_editor.gd @@ -0,0 +1,210 @@ +tool +extends ScrollContainer + + + +## Signals +# Emited when editor needs closing +signal close + + + +## Exported Variables +export(Resource) var voxel_set = null setget set_voxel_set + + + +## Public Variables +var undo_redo : UndoRedo + + + +## Private Variables +var import_file_path := "" + + + +## OnReady Variables +onready var ImportMenu := get_node("HBoxContainer/VBoxContainer/HBoxContainer/HBoxContainer/Import/ImportFile") + +onready var ImportHow := get_node("HBoxContainer/VBoxContainer/HBoxContainer/HBoxContainer/Import/ImportHow") + +onready var VoxelSetInfo := get_node("HBoxContainer/VBoxContainer/VoxelSetInfo") + +onready var VoxelInfo := get_node("HBoxContainer/VBoxContainer/VoxelInfo") + +onready var VoxelID := get_node("HBoxContainer/VBoxContainer/VoxelInfo/HBoxContainer/VoxelID") + +onready var VoxelName := get_node("HBoxContainer/VBoxContainer/VoxelInfo/HBoxContainer/VoxelName") + +onready var VoxelData := get_node("HBoxContainer/VBoxContainer/VoxelInfo/VoxelData") + +onready var VoxelSetViewer := get_node("HBoxContainer/VBoxContainer2/VoxelSetViewer") + +onready var VoxelInspector := get_node("HBoxContainer/VoxelInspector") + +onready var VoxelViewer := get_node("HBoxContainer/VoxelInspector/VoxelViewer") + + + +## Built-In Virtual Methods +func _ready(): + set_voxel_set(voxel_set) + + if not is_instance_valid(undo_redo): + undo_redo = UndoRedo.new() + VoxelSetViewer.undo_redo = undo_redo + VoxelViewer.undo_redo = undo_redo + + + +## Public Methods +func set_voxel_set(value : Resource, update := true) -> void: + if not typeof(voxel_set) == TYPE_NIL and not voxel_set is VoxelSet: + printerr("VoxelSetEditor : Invalid Resource given expected VoxelSet") + return + + if is_instance_valid(voxel_set): + if voxel_set.is_connected("requested_refresh", self, "update_view"): + voxel_set.disconnect("requested_refresh", self, "update_view") + + voxel_set = value + if is_instance_valid(voxel_set): + if not voxel_set.is_connected("requested_refresh", self, "update_view"): + voxel_set.connect("requested_refresh", self, "update_view") + if is_instance_valid(VoxelSetViewer): + VoxelSetViewer.voxel_set = voxel_set + + if update: + update_view() + + +func update_view() -> void: + if is_instance_valid(voxel_set): + if is_instance_valid(VoxelSetInfo): + VoxelSetInfo.text = "Voxels:\t\t" + str(voxel_set.size()) + VoxelSetInfo.text += "\nUV Ready:\t" + str(voxel_set.uv_ready()) + + if is_instance_valid(VoxelSetViewer): + var editing_single : bool = VoxelSetViewer.get_selected_size() == 1 + VoxelSetInfo.size_flags_vertical = Container.SIZE_FILL if editing_single else Container.SIZE_EXPAND_FILL + VoxelInfo.visible = editing_single + VoxelInspector.visible = editing_single + + if editing_single: + var id = VoxelSetViewer.get_selected(0) + + VoxelID.text = str(id) + VoxelName.text = voxel_set.id_to_name(id) + VoxelData.text = var2str(voxel_set.get_voxel(id)) + + VoxelViewer.setup(voxel_set, id) + else: + if not is_instance_valid(VoxelSetInfo): + return + VoxelSetInfo.text = "" + + +# Show import menu centered +func show_import_menu() -> void: + ImportMenu.popup_centered() + + +# Hide import menu +func hide_import_menu() -> void: + ImportMenu.hide() + + +# Show import how centered +func show_import_how(): + ImportHow.popup_centered() + + +# Hide import how +func hide_import_how(): + ImportHow.hide() + + + +## Private Methods +func _on_Refresh_pressed(): + voxel_set.request_refresh() + + +func _on_Import_file_selected(path): + import_file_path = path + show_import_how() + + +func _on_Import_Append_pressed(): + var result = voxel_set.load_file(import_file_path, true) + if result == OK: + voxel_set.request_refresh() + else: + printerr(result) + hide_import_how() + + +func _on_Import_Replace_pressed(): + var result = voxel_set.load_file(import_file_path, false) + if result == OK: + voxel_set.request_refresh() + else: + printerr(result) + hide_import_how() + + +func _on_Close_pressed(): + emit_signal("close") + + +func _on_VoxelID_text_entered(new_id): + if not new_id.is_valid_integer(): + return + new_id = new_id.to_int() + if new_id == VoxelSetViewer.get_selected(0): + return + elif new_id <= -1 or new_id >= voxel_set.size(): + return + + var id = VoxelSetViewer.get_selected(0) + var voxel = voxel_set.get_voxel(id) + undo_redo.create_action("VoxelSetEditor : Set voxel id") + undo_redo.add_do_method(voxel_set, "erase_voxel", id) + undo_redo.add_undo_method(voxel_set, "insert_voxel", id, voxel) + undo_redo.add_do_method(voxel_set, "insert_voxel", new_id, voxel) + undo_redo.add_undo_method(voxel_set, "erase_voxel", new_id) + undo_redo.add_do_method(voxel_set, "request_refresh") + undo_redo.add_undo_method(voxel_set, "request_refresh") + undo_redo.commit_action() + VoxelSetViewer.unselect_all() + VoxelSetViewer.select(new_id) + + +func _on_VoxelName_text_entered(new_name : String): + var voxel_id = VoxelSetViewer.get_selected(0) + var voxel = voxel_set.get_voxel(voxel_id) + if new_name == Voxel.get_name(voxel): + return + + var _voxel = voxel.duplicate(true) + if new_name.empty(): + undo_redo.create_action("VoxelSetEditor : Remove voxel name") + Voxel.remove_name(_voxel) + else: + undo_redo.create_action("VoxelSetEditor : Set voxel name") + Voxel.set_name(_voxel, new_name) + Voxel.clean(_voxel) + undo_redo.add_do_method(voxel_set, "set_voxel", voxel_id, _voxel) + undo_redo.add_undo_method(voxel_set, "set_voxel", voxel_id, voxel) + undo_redo.add_do_method(voxel_set, "request_refresh") + undo_redo.add_undo_method(voxel_set, "request_refresh") + undo_redo.commit_action() + + +func _on_VoxelSetViewer_selected(voxel_id : int): + update_view() + + +func _on_VoxelSetViewer_unselected(voxel_id : int): + update_view() diff --git a/assets/addons/voxel-core/engine/voxel_set_editor/voxel_set_editor.tscn b/assets/addons/voxel-core/engine/voxel_set_editor/voxel_set_editor.tscn new file mode 100644 index 0000000..0ae0bbb --- /dev/null +++ b/assets/addons/voxel-core/engine/voxel_set_editor/voxel_set_editor.tscn @@ -0,0 +1,257 @@ +[gd_scene load_steps=5 format=2] + +[ext_resource path="res://assets/addons/voxel-core/controls/voxel_viewer/voxel_viewer.tscn" type="PackedScene" id=1] +[ext_resource path="res://assets/addons/voxel-core/engine/voxel_set_editor/voxel_set_editor.gd" type="Script" id=2] +[ext_resource path="res://assets/addons/voxel-core/assets/classes/voxel_set.png" type="Texture" id=3] +[ext_resource path="res://assets/addons/voxel-core/controls/voxel_set_viewer/voxel_set_viewer.tscn" type="PackedScene" id=4] + +[node name="VoxelSetEditor" type="ScrollContainer"] +anchor_right = 1.0 +margin_bottom = 200.0 +rect_min_size = Vector2( 0, 200 ) +follow_focus = true +scroll_vertical_enabled = false +script = ExtResource( 2 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="HBoxContainer" type="HBoxContainer" parent="."] +margin_right = 1024.0 +margin_bottom = 200.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="VBoxContainer" type="VBoxContainer" parent="HBoxContainer"] +margin_right = 300.0 +margin_bottom = 200.0 +rect_min_size = Vector2( 300, 0 ) +size_flags_vertical = 3 + +[node name="HBoxContainer" type="HBoxContainer" parent="HBoxContainer/VBoxContainer"] +margin_right = 300.0 +margin_bottom = 20.0 + +[node name="TextureRect" type="TextureRect" parent="HBoxContainer/VBoxContainer/HBoxContainer"] +margin_right = 16.0 +margin_bottom = 20.0 +size_flags_vertical = 3 +texture = ExtResource( 3 ) +stretch_mode = 4 + +[node name="Label" type="Label" parent="HBoxContainer/VBoxContainer/HBoxContainer"] +margin_left = 20.0 +margin_top = 3.0 +margin_right = 75.0 +margin_bottom = 17.0 +text = "VoxelSet" + +[node name="HBoxContainer" type="HBoxContainer" parent="HBoxContainer/VBoxContainer/HBoxContainer"] +margin_left = 79.0 +margin_right = 300.0 +margin_bottom = 20.0 +size_flags_horizontal = 3 +alignment = 2 + +[node name="Import" type="Button" parent="HBoxContainer/VBoxContainer/HBoxContainer/HBoxContainer"] +margin_left = 50.0 +margin_right = 106.0 +margin_bottom = 20.0 +hint_tooltip = "Import voxels from file" +text = "Import" + +[node name="ImportFile" type="FileDialog" parent="HBoxContainer/VBoxContainer/HBoxContainer/HBoxContainer/Import"] +margin_right = 315.0 +margin_bottom = 130.0 +rect_min_size = Vector2( 400, 300 ) +window_title = "Open a File" +resizable = true +mode = 0 +filters = PoolStringArray( "*.vox ; VOX Files", "*.png, *.bmp, *.dds, *.exr, *.hdr, *.jpg, *.jpeg, *.tga, *.svg, *.svgz, *.webp; Image Files", "*.gpl; GIMP Palette" ) + +[node name="ImportHow" type="PopupDialog" parent="HBoxContainer/VBoxContainer/HBoxContainer/HBoxContainer/Import"] +margin_right = 40.0 +margin_bottom = 40.0 +rect_min_size = Vector2( 325, 100 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="VBoxContainer" type="VBoxContainer" parent="HBoxContainer/VBoxContainer/HBoxContainer/HBoxContainer/Import/ImportHow"] +anchor_right = 1.0 +anchor_bottom = 1.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="Label" type="Label" parent="HBoxContainer/VBoxContainer/HBoxContainer/HBoxContainer/Import/ImportHow/VBoxContainer"] +margin_top = 17.0 +margin_right = 325.0 +margin_bottom = 31.0 +size_flags_horizontal = 3 +size_flags_vertical = 6 +text = "How to import voxels to VoxelSet?" +align = 1 +valign = 1 + +[node name="HBoxContainer" type="HBoxContainer" parent="HBoxContainer/VBoxContainer/HBoxContainer/HBoxContainer/Import/ImportHow/VBoxContainer"] +margin_top = 52.0 +margin_right = 325.0 +margin_bottom = 100.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 +alignment = 1 + +[node name="Append" type="Button" parent="HBoxContainer/VBoxContainer/HBoxContainer/HBoxContainer/Import/ImportHow/VBoxContainer/HBoxContainer"] +margin_left = 70.0 +margin_top = 14.0 +margin_right = 131.0 +margin_bottom = 34.0 +size_flags_horizontal = 4 +size_flags_vertical = 4 +text = "Append" + +[node name="Replace" type="Button" parent="HBoxContainer/VBoxContainer/HBoxContainer/HBoxContainer/Import/ImportHow/VBoxContainer/HBoxContainer"] +margin_left = 135.0 +margin_top = 14.0 +margin_right = 197.0 +margin_bottom = 34.0 +size_flags_horizontal = 4 +size_flags_vertical = 4 +text = "Replace" + +[node name="Cancel" type="Button" parent="HBoxContainer/VBoxContainer/HBoxContainer/HBoxContainer/Import/ImportHow/VBoxContainer/HBoxContainer"] +margin_left = 201.0 +margin_top = 14.0 +margin_right = 255.0 +margin_bottom = 34.0 +size_flags_horizontal = 4 +size_flags_vertical = 4 +text = "Cancel" + +[node name="Refresh" type="Button" parent="HBoxContainer/VBoxContainer/HBoxContainer/HBoxContainer"] +margin_left = 110.0 +margin_right = 170.0 +margin_bottom = 20.0 +hint_tooltip = "Request refresh from all connected objects" +text = "Refresh" + +[node name="Close" type="Button" parent="HBoxContainer/VBoxContainer/HBoxContainer/HBoxContainer"] +margin_left = 174.0 +margin_right = 221.0 +margin_bottom = 20.0 +hint_tooltip = "Close the VoxelSetEditor" +text = "Close" + +[node name="VoxelSetInfo" type="RichTextLabel" parent="HBoxContainer/VBoxContainer"] +margin_top = 24.0 +margin_right = 300.0 +margin_bottom = 200.0 +rect_min_size = Vector2( 0, 50 ) +size_flags_vertical = 3 + +[node name="VoxelInfo" type="VBoxContainer" parent="HBoxContainer/VBoxContainer"] +visible = false +margin_top = 114.0 +margin_right = 300.0 +margin_bottom = 200.0 +size_flags_vertical = 3 + +[node name="HBoxContainer" type="HBoxContainer" parent="HBoxContainer/VBoxContainer/VoxelInfo"] +margin_right = 300.0 +margin_bottom = 24.0 + +[node name="Label" type="Label" parent="HBoxContainer/VBoxContainer/VoxelInfo/HBoxContainer"] +margin_top = 5.0 +margin_right = 19.0 +margin_bottom = 19.0 +text = "ID:" + +[node name="VoxelID" type="LineEdit" parent="HBoxContainer/VBoxContainer/VoxelInfo/HBoxContainer"] +margin_left = 23.0 +margin_right = 81.0 +margin_bottom = 24.0 +hint_tooltip = "Enter to change id" + +[node name="Label2" type="Label" parent="HBoxContainer/VBoxContainer/VoxelInfo/HBoxContainer"] +margin_left = 85.0 +margin_top = 5.0 +margin_right = 127.0 +margin_bottom = 19.0 +text = "Name:" + +[node name="VoxelName" type="LineEdit" parent="HBoxContainer/VBoxContainer/VoxelInfo/HBoxContainer"] +margin_left = 131.0 +margin_right = 300.0 +margin_bottom = 24.0 +hint_tooltip = "Enter to change name" +size_flags_horizontal = 3 +placeholder_text = "Enter name..." + +[node name="VoxelData" type="RichTextLabel" parent="HBoxContainer/VBoxContainer/VoxelInfo"] +margin_top = 28.0 +margin_right = 300.0 +margin_bottom = 86.0 +size_flags_vertical = 3 + +[node name="HSplitContainer" type="VSeparator" parent="HBoxContainer"] +margin_left = 304.0 +margin_right = 308.0 +margin_bottom = 200.0 + +[node name="VBoxContainer2" type="VBoxContainer" parent="HBoxContainer"] +margin_left = 312.0 +margin_right = 1024.0 +margin_bottom = 200.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="VoxelSetViewer" parent="HBoxContainer/VBoxContainer2" instance=ExtResource( 4 )] +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_right = 712.0 +margin_bottom = 200.0 +size_flags_horizontal = 7 +size_flags_vertical = 3 +search = "" +allow_edit = true +selection_max = -1 +show_hints = true +voxel_set = null + +[node name="VoxelInspector" type="HBoxContainer" parent="HBoxContainer"] +visible = false +margin_left = 684.0 +margin_right = 1024.0 +margin_bottom = 200.0 + +[node name="HSplitContainer2" type="VSeparator" parent="HBoxContainer/VoxelInspector"] +margin_right = 4.0 +margin_bottom = 200.0 + +[node name="VoxelViewer" parent="HBoxContainer/VoxelInspector" instance=ExtResource( 1 )] +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 8.0 +margin_right = 340.0 +margin_bottom = 200.0 +rect_min_size = Vector2( 332, 200 ) +size_flags_horizontal = 0 +size_flags_vertical = 4 +selection_max = 6 +allow_edit = true +view_mode = 1 +camera_sensitivity = 8 +voxel_id = 0 +voxel_set = null + +[connection signal="pressed" from="HBoxContainer/VBoxContainer/HBoxContainer/HBoxContainer/Import" to="." method="show_import_menu"] +[connection signal="file_selected" from="HBoxContainer/VBoxContainer/HBoxContainer/HBoxContainer/Import/ImportFile" to="." method="_on_Import_file_selected"] +[connection signal="pressed" from="HBoxContainer/VBoxContainer/HBoxContainer/HBoxContainer/Import/ImportHow/VBoxContainer/HBoxContainer/Append" to="." method="_on_Import_Append_pressed"] +[connection signal="pressed" from="HBoxContainer/VBoxContainer/HBoxContainer/HBoxContainer/Import/ImportHow/VBoxContainer/HBoxContainer/Replace" to="." method="_on_Import_Replace_pressed"] +[connection signal="pressed" from="HBoxContainer/VBoxContainer/HBoxContainer/HBoxContainer/Import/ImportHow/VBoxContainer/HBoxContainer/Cancel" to="." method="hide_import_how"] +[connection signal="pressed" from="HBoxContainer/VBoxContainer/HBoxContainer/HBoxContainer/Refresh" to="." method="_on_Refresh_pressed"] +[connection signal="pressed" from="HBoxContainer/VBoxContainer/HBoxContainer/HBoxContainer/Close" to="." method="_on_Close_pressed"] +[connection signal="text_entered" from="HBoxContainer/VBoxContainer/VoxelInfo/HBoxContainer/VoxelID" to="." method="_on_VoxelID_text_entered"] +[connection signal="text_entered" from="HBoxContainer/VBoxContainer/VoxelInfo/HBoxContainer/VoxelName" to="." method="_on_VoxelName_text_entered"] +[connection signal="selected_voxel" from="HBoxContainer/VBoxContainer2/VoxelSetViewer" to="." method="_on_VoxelSetViewer_selected"] +[connection signal="unselected_voxel" from="HBoxContainer/VBoxContainer2/VoxelSetViewer" to="." method="_on_VoxelSetViewer_unselected"] -- cgit v1.2.3-54-g00ecf