small godot addon for gizmo creation
-rw-r--r--.gitattributes5
-rw-r--r--.github/image.pngbin0 -> 67240 bytes
-rw-r--r--.gitignore1
-rw-r--r--LICENSE21
-rw-r--r--README.md17
-rw-r--r--addons/@bendn/LICENSE21
-rw-r--r--addons/@bendn/gizmo3d/README.md16
-rw-r--r--addons/@bendn/gizmo3d/center.tres6
-rw-r--r--addons/@bendn/gizmo3d/gizmo.gd36
-rw-r--r--addons/@bendn/gizmo3d/package.json25
-rw-r--r--addons/@bendn/gizmo3d/rotation/rotation.gd13
-rw-r--r--addons/@bendn/gizmo3d/rotation/rotation.tscn65
-rw-r--r--addons/@bendn/gizmo3d/rotation/torus.shapebin0 -> 2047 bytes
-rw-r--r--addons/@bendn/gizmo3d/rotation/torus.tres6
-rw-r--r--addons/@bendn/gizmo3d/scale/box.tres4
-rw-r--r--addons/@bendn/gizmo3d/scale/cylinder.tres9
-rw-r--r--addons/@bendn/gizmo3d/scale/scale.tscn94
-rw-r--r--addons/@bendn/gizmo3d/selection_marker.gd2
-rw-r--r--addons/@bendn/gizmo3d/selection_marker.tscn13
-rw-r--r--addons/@bendn/gizmo3d/translate/center.gd40
-rw-r--r--addons/@bendn/gizmo3d/translate/cylinder.tres8
-rw-r--r--addons/@bendn/gizmo3d/translate/handle.gd55
-rw-r--r--addons/@bendn/gizmo3d/translate/point.tres8
-rw-r--r--addons/@bendn/gizmo3d/translate/translate.tscn104
-rw-r--r--addons/@bendn/gizmo3d/translate/translate_arm.shapebin0 -> 232 bytes
-rw-r--r--addons/@bendn/gizmo3d/x.tres7
-rw-r--r--addons/@bendn/gizmo3d/y.tres6
-rw-r--r--addons/@bendn/gizmo3d/z.tres7
-rw-r--r--project.godot26
-rw-r--r--test.gd67
-rw-r--r--test.tscn90
31 files changed, 772 insertions, 0 deletions
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..dceb116
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,5 @@
+* text=auto eol=lf
+
+/** export-ignore
+/addons !export-ignore
+/addons/** !export-ignore
diff --git a/.github/image.png b/.github/image.png
new file mode 100644
index 0000000..6010617
--- /dev/null
+++ b/.github/image.png
Binary files differ
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..16293bd
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+.godot
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..1fafc15
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2023 bendn
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..4636bae
--- /dev/null
+++ b/README.md
@@ -0,0 +1,17 @@
+# gizmo3d
+
+[![version](https://img.shields.io/badge/4.x-blue?logo=godot-engine&logoColor=white&label=godot&style=for-the-badge)](https://godotengine.org "Made with godot")
+[![package](https://img.shields.io/npm/v/@bendn/gizmo3d?label=version&style=for-the-badge)](https://www.npmjs.com/package/@bendn/gizmo3d)
+<a href='https://ko-fi.com/bendn' title='Buy me a coffee' target='_blank'><img height='28' src='https://storage.ko-fi.com/cdn/brandasset/kofi_button_red.png' alt='Buy me a coffee'> </a>
+
+Smalll addon for gizmo creation.
+
+[![image](https://raw.githubusercontent.com/bend-n/gizmo3d/main/.github/image.png)](_blank "Picture!")
+
+## Usage
+
+See [test.gd](https://raw.githubusercontent.com/bend-n/gizmo3d/main/test.gd) for a usage example.
+
+## Installation
+
+See [gpm#using-packages](https://github.com/godot-package-manager#using-packages-quickstart).
diff --git a/addons/@bendn/LICENSE b/addons/@bendn/LICENSE
new file mode 100644
index 0000000..1fafc15
--- /dev/null
+++ b/addons/@bendn/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2023 bendn
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/addons/@bendn/gizmo3d/README.md b/addons/@bendn/gizmo3d/README.md
new file mode 100644
index 0000000..45ab827
--- /dev/null
+++ b/addons/@bendn/gizmo3d/README.md
@@ -0,0 +1,16 @@
+# gizmo3d
+
+[![version](https://img.shields.io/badge/4.x-blue?logo=godot-engine&logoColor=white&label=godot&style=for-the-badge)](https://godotengine.org "Made with godot")
+<a href='https://ko-fi.com/bendn' title='Buy me a coffee' target='_blank'><img height='28' src='https://storage.ko-fi.com/cdn/brandasset/kofi_button_red.png' alt='Buy me a coffee'> </a>
+
+Smalll addon for gizmo creation.
+
+[![image](https://raw.githubusercontent.com/bend-n/gizmo3d/main/.github/image.png)](_blank "Picture!")
+
+## Usage
+
+See [test.gd](https://raw.githubusercontent.com/bend-n/gizmo3d/main/test.gd) for a usage example.
+
+## Installation
+
+See [gpm#using-packages](https://github.com/godot-package-manager#using-packages-quickstart).
diff --git a/addons/@bendn/gizmo3d/center.tres b/addons/@bendn/gizmo3d/center.tres
new file mode 100644
index 0000000..ac77ed2
--- /dev/null
+++ b/addons/@bendn/gizmo3d/center.tres
@@ -0,0 +1,6 @@
+[gd_resource type="StandardMaterial3D" format=3 uid="uid://boc66segplbdg"]
+
+[resource]
+no_depth_test = true
+shading_mode = 0
+albedo_color = Color(0.92549, 0.886275, 0, 1)
diff --git a/addons/@bendn/gizmo3d/gizmo.gd b/addons/@bendn/gizmo3d/gizmo.gd
new file mode 100644
index 0000000..8bb4791
--- /dev/null
+++ b/addons/@bendn/gizmo3d/gizmo.gd
@@ -0,0 +1,36 @@
+extends Node3D
+class_name Gizmo
+
+## A 3D Gizmo, doesn't directly move objects, instead emits signals.
+## Thereby allowing you to do anything, including use the [UndoRedo] system,
+## without being constrained by defaults.
+
+## Emitted when this gizmo is clicked.
+signal clicked
+## Gizmo was rotated by [param change].
+signal rotated(change: Vector3)
+## Gizmo was translated by [param offset].
+signal displaced(offset: Vector3)
+## Gizmo scaled by [param change].
+signal scaled(change: Vector3)
+## Gizmo finished moving, lock it in.
+signal finalize
+
+## I couldn't get [member BaseMaterial3D.fixed_size] to work soooo.
+@export_exp_easing("attenuation") var scale_multiplier := 0.00011
+
+@onready var _camera := get_viewport().get_camera_3d()
+
+func _physics_process(_delta: float) -> void:
+ _update_scale()
+
+func _update_scale():
+ var distance := (_camera.global_position - global_position).length()
+ var size := distance * .00011 * _camera.fov
+ scale = size * Vector3.ONE
+
+func _ready() -> void:
+ _update_scale()
+ for c in get_children():
+ if c.has_signal(&"clicked"):
+ c.clicked.connect(emit_signal.bind(&"clicked"))
diff --git a/addons/@bendn/gizmo3d/package.json b/addons/@bendn/gizmo3d/package.json
new file mode 100644
index 0000000..54266c7
--- /dev/null
+++ b/addons/@bendn/gizmo3d/package.json
@@ -0,0 +1,25 @@
+{
+ "name": "@bendn/gizmo3d",
+ "version": "1.0.2",
+ "description": "small addon for gizmo creation",
+ "main": "gizmo.gd",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/bend-n/gizmo3d.git"
+ },
+ "keywords": [
+ "godot",
+ "godot-engine",
+ "3d",
+ "gizmo"
+ ],
+ "author": "bendn",
+ "license": "MIT",
+ "bugs": {
+ "url": "https://github.com/bend-n/gizmo3d/issues"
+ },
+ "homepage": "https://github.com/bend-n/gizmo3d#readme"
+}
diff --git a/addons/@bendn/gizmo3d/rotation/rotation.gd b/addons/@bendn/gizmo3d/rotation/rotation.gd
new file mode 100644
index 0000000..eda9f7a
--- /dev/null
+++ b/addons/@bendn/gizmo3d/rotation/rotation.gd
@@ -0,0 +1,13 @@
+extends Gizmo
+class_name RotationGizmo
+
+@export var rotate_cw: Shortcut
+@export var rotate_ccw: Shortcut
+
+func _input(event: InputEvent) -> void:
+ if rotate_cw.matches_event(event) and event.is_pressed():
+ rotated.emit(Vector3(0, PI/2, 0))
+ finalize.emit()
+ elif rotate_ccw.matches_event(event) and event.is_pressed():
+ rotated.emit(Vector3(0, -(PI/2), 0))
+ finalize.emit()
diff --git a/addons/@bendn/gizmo3d/rotation/rotation.tscn b/addons/@bendn/gizmo3d/rotation/rotation.tscn
new file mode 100644
index 0000000..4f29f61
--- /dev/null
+++ b/addons/@bendn/gizmo3d/rotation/rotation.tscn
@@ -0,0 +1,65 @@
+[gd_scene load_steps=11 format=3 uid="uid://b5deeyfr2umhx"]
+
+[ext_resource type="Script" path="res://addons/@bendn/gizmo3d/rotation/rotation.gd" id="1_7laj6"]
+[ext_resource type="TorusMesh" uid="uid://bw6rig250ekqw" path="res://addons/@bendn/gizmo3d/rotation/torus.tres" id="2_wpi22"]
+[ext_resource type="Material" uid="uid://dc4qnnjootkhu" path="res://addons/@bendn/gizmo3d/y.tres" id="3_cf2qn"]
+[ext_resource type="Shape3D" uid="uid://cai5e0kk8b0sq" path="res://addons/@bendn/gizmo3d/rotation/torus.shape" id="4_aoydv"]
+[ext_resource type="Material" uid="uid://do26tijfu1ibj" path="res://addons/@bendn/gizmo3d/x.tres" id="5_ohutw"]
+[ext_resource type="Material" uid="uid://btbrwby3db6t5" path="res://addons/@bendn/gizmo3d/z.tres" id="6_61do5"]
+
+[sub_resource type="InputEventKey" id="InputEventKey_3st8s"]
+device = -1
+keycode = 82
+unicode = 114
+
+[sub_resource type="Shortcut" id="Shortcut_jvc8g"]
+events = [SubResource("InputEventKey_3st8s")]
+
+[sub_resource type="InputEventKey" id="InputEventKey_gor3q"]
+device = -1
+shift_pressed = true
+keycode = 82
+unicode = 82
+
+[sub_resource type="Shortcut" id="Shortcut_0sfr4"]
+events = [SubResource("InputEventKey_gor3q")]
+
+[node name="rotation" type="Node3D"]
+script = ExtResource("1_7laj6")
+rotate_cw = SubResource("Shortcut_jvc8g")
+rotate_ccw = SubResource("Shortcut_0sfr4")
+
+[node name="Y" type="StaticBody3D" parent="."]
+
+[node name="mesh" type="MeshInstance3D" parent="Y"]
+mesh = ExtResource("2_wpi22")
+skeleton = NodePath("../..")
+surface_material_override/0 = ExtResource("3_cf2qn")
+
+[node name="collider" type="CollisionShape3D" parent="Y"]
+visible = false
+shape = ExtResource("4_aoydv")
+
+[node name="X" type="StaticBody3D" parent="."]
+transform = Transform3D(-4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 0, 1, 0, 0, 0)
+
+[node name="mesh" type="MeshInstance3D" parent="X"]
+mesh = ExtResource("2_wpi22")
+skeleton = NodePath("../..")
+surface_material_override/0 = ExtResource("5_ohutw")
+
+[node name="collider" type="CollisionShape3D" parent="X"]
+visible = false
+shape = ExtResource("4_aoydv")
+
+[node name="Z" type="StaticBody3D" parent="."]
+transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 0)
+
+[node name="mesh" type="MeshInstance3D" parent="Z"]
+mesh = ExtResource("2_wpi22")
+skeleton = NodePath("../..")
+surface_material_override/0 = ExtResource("6_61do5")
+
+[node name="collider" type="CollisionShape3D" parent="Z"]
+visible = false
+shape = ExtResource("4_aoydv")
diff --git a/addons/@bendn/gizmo3d/rotation/torus.shape b/addons/@bendn/gizmo3d/rotation/torus.shape
new file mode 100644
index 0000000..2c7dbee
--- /dev/null
+++ b/addons/@bendn/gizmo3d/rotation/torus.shape
Binary files differ
diff --git a/addons/@bendn/gizmo3d/rotation/torus.tres b/addons/@bendn/gizmo3d/rotation/torus.tres
new file mode 100644
index 0000000..3fa5889
--- /dev/null
+++ b/addons/@bendn/gizmo3d/rotation/torus.tres
@@ -0,0 +1,6 @@
+[gd_resource type="TorusMesh" format=3 uid="uid://bw6rig250ekqw"]
+
+[resource]
+inner_radius = 14.0
+outer_radius = 15.0
+ring_segments = 8
diff --git a/addons/@bendn/gizmo3d/scale/box.tres b/addons/@bendn/gizmo3d/scale/box.tres
new file mode 100644
index 0000000..76aab11
--- /dev/null
+++ b/addons/@bendn/gizmo3d/scale/box.tres
@@ -0,0 +1,4 @@
+[gd_resource type="BoxMesh" format=3 uid="uid://dqf33w5edcobv"]
+
+[resource]
+size = Vector3(3, 3, 3)
diff --git a/addons/@bendn/gizmo3d/scale/cylinder.tres b/addons/@bendn/gizmo3d/scale/cylinder.tres
new file mode 100644
index 0000000..88f9e73
--- /dev/null
+++ b/addons/@bendn/gizmo3d/scale/cylinder.tres
@@ -0,0 +1,9 @@
+[gd_resource type="CylinderMesh" format=3 uid="uid://lc08lgqf086"]
+
+[resource]
+top_radius = 1.0
+bottom_radius = 1.0
+height = 14.0
+radial_segments = 8
+cap_top = false
+cap_bottom = false
diff --git a/addons/@bendn/gizmo3d/scale/scale.tscn b/addons/@bendn/gizmo3d/scale/scale.tscn
new file mode 100644
index 0000000..957fc54
--- /dev/null
+++ b/addons/@bendn/gizmo3d/scale/scale.tscn
@@ -0,0 +1,94 @@
+[gd_scene load_steps=11 format=3 uid="uid://bqcjdbse5n5lb"]
+
+[ext_resource type="Script" path="res://addons/@bendn/gizmo3d/gizmo.gd" id="1_ocjut"]
+[ext_resource type="Script" path="res://addons/@bendn/gizmo3d/translate/handle.gd" id="2_dbfpj"]
+[ext_resource type="CylinderMesh" uid="uid://lc08lgqf086" path="res://addons/@bendn/gizmo3d/scale/cylinder.tres" id="3_15ibc"]
+[ext_resource type="Material" uid="uid://dc4qnnjootkhu" path="res://addons/@bendn/gizmo3d/y.tres" id="4_cm82e"]
+[ext_resource type="BoxMesh" uid="uid://dqf33w5edcobv" path="res://addons/@bendn/gizmo3d/scale/box.tres" id="5_dsdp5"]
+[ext_resource type="Shape3D" uid="uid://k6i72vyyvx5a" path="res://addons/@bendn/gizmo3d/translate/translate_arm.shape" id="6_d5tgp"]
+[ext_resource type="Material" uid="uid://do26tijfu1ibj" path="res://addons/@bendn/gizmo3d/x.tres" id="7_n5pes"]
+[ext_resource type="Material" uid="uid://btbrwby3db6t5" path="res://addons/@bendn/gizmo3d/z.tres" id="8_pk3gt"]
+[ext_resource type="Material" uid="uid://boc66segplbdg" path="res://addons/@bendn/gizmo3d/center.tres" id="9_ka3tc"]
+
+[sub_resource type="SphereMesh" id="SphereMesh_qsd58"]
+radius = 1.0
+height = 2.0
+radial_segments = 16
+rings = 8
+
+[node name="scale" type="Node3D"]
+transform = Transform3D(0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0, 0)
+script = ExtResource("1_ocjut")
+
+[node name="handle_y" type="StaticBody3D" parent="."]
+transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 10, 0)
+collision_layer = 1073741824
+collision_mask = 0
+script = ExtResource("2_dbfpj")
+dir = 2
+mode = 1
+
+[node name="cylinder" type="MeshInstance3D" parent="handle_y"]
+transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 1.31134e-07, 3)
+mesh = ExtResource("3_15ibc")
+surface_material_override/0 = ExtResource("4_cm82e")
+
+[node name="point" type="MeshInstance3D" parent="handle_y"]
+transform = Transform3D(-1, -8.74228e-08, 3.82137e-15, 0, -4.37114e-08, -1, 8.74228e-08, -1, 4.37114e-08, 0, -2.84217e-14, -5)
+mesh = ExtResource("5_dsdp5")
+surface_material_override/0 = ExtResource("4_cm82e")
+
+[node name="collider" type="CollisionShape3D" parent="handle_y"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 4.37114e-08, 1)
+visible = false
+shape = ExtResource("6_d5tgp")
+
+[node name="handle_x" type="StaticBody3D" parent="."]
+transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 10, 0, 0)
+collision_layer = 1073741824
+collision_mask = 0
+script = ExtResource("2_dbfpj")
+dir = 0
+mode = 1
+
+[node name="cylinder" type="MeshInstance3D" parent="handle_x"]
+transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 1.31134e-07, 0, -3)
+mesh = ExtResource("3_15ibc")
+surface_material_override/0 = ExtResource("7_n5pes")
+
+[node name="point" type="MeshInstance3D" parent="handle_x"]
+transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, -2.84217e-14, 0, 5)
+mesh = ExtResource("5_dsdp5")
+surface_material_override/0 = ExtResource("7_n5pes")
+
+[node name="collider" type="CollisionShape3D" parent="handle_x"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 4.37114e-08, 0, -1)
+visible = false
+shape = ExtResource("6_d5tgp")
+
+[node name="handle_z" type="StaticBody3D" parent="."]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 10)
+collision_layer = 1073741824
+collision_mask = 0
+script = ExtResource("2_dbfpj")
+dir = 1
+mode = 1
+
+[node name="cylinder" type="MeshInstance3D" parent="handle_z"]
+transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, -3)
+mesh = ExtResource("3_15ibc")
+surface_material_override/0 = ExtResource("8_pk3gt")
+
+[node name="point" type="MeshInstance3D" parent="handle_z"]
+transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 5)
+mesh = ExtResource("5_dsdp5")
+surface_material_override/0 = ExtResource("8_pk3gt")
+
+[node name="collider" type="CollisionShape3D" parent="handle_z"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -1)
+visible = false
+shape = ExtResource("6_d5tgp")
+
+[node name="center" type="MeshInstance3D" parent="."]
+mesh = SubResource("SphereMesh_qsd58")
+surface_material_override/0 = ExtResource("9_ka3tc")
diff --git a/addons/@bendn/gizmo3d/selection_marker.gd b/addons/@bendn/gizmo3d/selection_marker.gd
new file mode 100644
index 0000000..08b4e01
--- /dev/null
+++ b/addons/@bendn/gizmo3d/selection_marker.gd
@@ -0,0 +1,2 @@
+extends Gizmo
+class_name SelectionMarker
diff --git a/addons/@bendn/gizmo3d/selection_marker.tscn b/addons/@bendn/gizmo3d/selection_marker.tscn
new file mode 100644
index 0000000..0ad4415
--- /dev/null
+++ b/addons/@bendn/gizmo3d/selection_marker.tscn
@@ -0,0 +1,13 @@
+[gd_scene load_steps=4 format=3]
+
+[ext_resource type="Material" uid="uid://boc66segplbdg" path="res://addons/@bendn/gizmo3d/center.tres" id="1_sojt7"]
+[ext_resource type="Script" path="res://addons/@bendn/gizmo3d/selection_marker.gd" id="2_gai3n"]
+
+[sub_resource type="BoxMesh" id="BoxMesh_8slg5"]
+size = Vector3(10, 10, 10)
+
+[node name="selection marker" type="MeshInstance3D"]
+transform = Transform3D(0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0, 0)
+mesh = SubResource("BoxMesh_8slg5")
+surface_material_override/0 = ExtResource("1_sojt7")
+script = ExtResource("2_gai3n")
diff --git a/addons/@bendn/gizmo3d/translate/center.gd b/addons/@bendn/gizmo3d/translate/center.gd
new file mode 100644
index 0000000..db00bf6
--- /dev/null
+++ b/addons/@bendn/gizmo3d/translate/center.gd
@@ -0,0 +1,40 @@
+extends StaticBody3D
+class_name TranslateGizmoCenter
+
+var dragged := false
+var clicked_position := Vector3.ZERO
+var click_plane: Plane
+
+signal clicked
+
+func _process(_delta: float):
+ if dragged and not Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT):
+ dragged = false
+ owner.finalize.emit()
+ if dragged:
+ var cam := get_viewport().get_camera_3d()
+ var mp := get_viewport().get_mouse_position()
+
+ var from := cam.project_ray_origin(mp)
+ var toward := cam.project_ray_normal(mp)
+ var intersection_of_movement_point = click_plane.intersects_ray(from, toward)
+ if intersection_of_movement_point == null:
+ # dont move if its exactly parallel to plane
+ return
+ var displacement: Vector3 = intersection_of_movement_point - clicked_position
+ owner.displaced.emit(displacement)
+
+func _ready() -> void:
+ input_event.connect(click)
+
+func click(camera: Camera3D, event: InputEvent, click_position: Vector3, _click_normal: Vector3, _shape_idx: int):
+ if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
+ clicked.emit()
+ dragged = true
+ var mp := get_viewport().get_mouse_position()
+ var plane_normal := camera.project_ray_normal(mp).normalized()
+ var distance := Plane(plane_normal, 0).distance_to(click_position)
+ click_plane = Plane(plane_normal, distance)
+
+ clicked_position = click_position
+
diff --git a/addons/@bendn/gizmo3d/translate/cylinder.tres b/addons/@bendn/gizmo3d/translate/cylinder.tres
new file mode 100644
index 0000000..4dc8f04
--- /dev/null
+++ b/addons/@bendn/gizmo3d/translate/cylinder.tres
@@ -0,0 +1,8 @@
+[gd_resource type="CylinderMesh" format=3 uid="uid://c3hxlx3k1jmfb"]
+
+[resource]
+top_radius = 1.0
+bottom_radius = 1.0
+height = 10.0
+radial_segments = 8
+cap_top = false
diff --git a/addons/@bendn/gizmo3d/translate/handle.gd b/addons/@bendn/gizmo3d/translate/handle.gd
new file mode 100644
index 0000000..3a1a1ff
--- /dev/null
+++ b/addons/@bendn/gizmo3d/translate/handle.gd
@@ -0,0 +1,55 @@
+extends StaticBody3D
+class_name TranslateGizmoHandle
+# copied from https://github.com/TinyLegions/runtime-spatial-gizmos/ vaguely
+
+@export var dir: Direction = Direction.NONE
+enum Direction { X, Z, Y, RELATIVE, NONE } # relative not implemented
+var direction2vector := { Direction.X: Vector3.RIGHT, Direction.Y: Vector3.UP, Direction.Z: Vector3.BACK }
+@onready var drag_direction: Vector3 = direction2vector[dir]
+
+var dragged := false
+var clicked_position := Vector3.ZERO
+var click_plane: Plane
+
+@onready var gizmo: Gizmo = owner
+enum Mode { Translate, Scale }
+@export var mode: Mode
+
+signal clicked
+
+func _process(_delta: float):
+ if dragged and not Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT):
+ dragged = false
+ gizmo.finalize.emit()
+ if dragged:
+ var cam := get_viewport().get_camera_3d()
+ var mp := get_viewport().get_mouse_position()
+
+ var from := cam.project_ray_origin(mp)
+ var toward := cam.project_ray_normal(mp)
+ var intersection_of_movement_point = click_plane.intersects_ray(from, toward)
+ if intersection_of_movement_point == null:
+ # dont move if its exactly parallel to plane
+ return
+ var dist = intersection_of_movement_point - clicked_position
+ var displacement: Vector3 = dist.project(drag_direction)
+ match mode:
+ Mode.Translate:
+ gizmo.displaced.emit(displacement)
+ Mode.Scale:
+ gizmo.scaled.emit(displacement)
+
+func _ready() -> void:
+ input_event.connect(click)
+
+func click(camera: Camera3D, event: InputEvent, click_position: Vector3, _click_normal: Vector3, _shape_idx: int):
+ if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
+ clicked.emit()
+ dragged = true
+ var mp := get_viewport().get_mouse_position()
+ var vertical_vector = camera.project_ray_normal(mp).normalized().cross(drag_direction)
+ var plane_normal := drag_direction.cross(vertical_vector)
+ var distance := Plane(plane_normal, 0).distance_to(click_position)
+ click_plane = Plane(plane_normal, distance)
+
+ clicked_position = click_position
diff --git a/addons/@bendn/gizmo3d/translate/point.tres b/addons/@bendn/gizmo3d/translate/point.tres
new file mode 100644
index 0000000..8e59ed2
--- /dev/null
+++ b/addons/@bendn/gizmo3d/translate/point.tres
@@ -0,0 +1,8 @@
+[gd_resource type="CylinderMesh" format=3 uid="uid://cd0844dj635dv"]
+
+[resource]
+top_radius = 0.0
+bottom_radius = 2.0
+height = 3.0
+radial_segments = 16
+cap_top = false
diff --git a/addons/@bendn/gizmo3d/translate/translate.tscn b/addons/@bendn/gizmo3d/translate/translate.tscn
new file mode 100644
index 0000000..231e7cb
--- /dev/null
+++ b/addons/@bendn/gizmo3d/translate/translate.tscn
@@ -0,0 +1,104 @@
+[gd_scene load_steps=13 format=3 uid="uid://d2recqdx4hj38"]
+
+[ext_resource type="Script" path="res://addons/@bendn/gizmo3d/gizmo.gd" id="1_e30nb"]
+[ext_resource type="Script" path="res://addons/@bendn/gizmo3d/translate/center.gd" id="2_vs4q7"]
+[ext_resource type="Material" uid="uid://boc66segplbdg" path="res://addons/@bendn/gizmo3d/center.tres" id="3_t3mv1"]
+[ext_resource type="Script" path="res://addons/@bendn/gizmo3d/translate/handle.gd" id="4_3ja1b"]
+[ext_resource type="CylinderMesh" uid="uid://c3hxlx3k1jmfb" path="res://addons/@bendn/gizmo3d/translate/cylinder.tres" id="5_tlymd"]
+[ext_resource type="Material" uid="uid://dc4qnnjootkhu" path="res://addons/@bendn/gizmo3d/y.tres" id="6_ohmps"]
+[ext_resource type="CylinderMesh" uid="uid://cd0844dj635dv" path="res://addons/@bendn/gizmo3d/translate/point.tres" id="7_j0wec"]
+[ext_resource type="Shape3D" uid="uid://k6i72vyyvx5a" path="res://addons/@bendn/gizmo3d/translate/translate_arm.shape" id="8_upb4q"]
+[ext_resource type="Material" uid="uid://do26tijfu1ibj" path="res://addons/@bendn/gizmo3d/x.tres" id="9_ivepe"]
+[ext_resource type="Material" uid="uid://btbrwby3db6t5" path="res://addons/@bendn/gizmo3d/z.tres" id="10_4d87b"]
+
+[sub_resource type="BoxMesh" id="BoxMesh_rttof"]
+size = Vector3(10, 10, 10)
+
+[sub_resource type="BoxShape3D" id="BoxShape3D_tep2a"]
+size = Vector3(10, 10, 10)
+
+[node name="translate" type="Node3D"]
+transform = Transform3D(0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0, 0)
+script = ExtResource("1_e30nb")
+
+[node name="center" type="StaticBody3D" parent="."]
+collision_layer = 1073741824
+collision_mask = 0
+script = ExtResource("2_vs4q7")
+
+[node name="mesh" type="MeshInstance3D" parent="center"]
+mesh = SubResource("BoxMesh_rttof")
+skeleton = NodePath("../..")
+surface_material_override/0 = ExtResource("3_t3mv1")
+
+[node name="collider" type="CollisionShape3D" parent="center"]
+shape = SubResource("BoxShape3D_tep2a")
+
+[node name="handle_y" type="StaticBody3D" parent="."]
+transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 10, 0)
+collision_layer = 1073741824
+collision_mask = 0
+script = ExtResource("4_3ja1b")
+dir = 2
+
+[node name="cylinder" type="MeshInstance3D" parent="handle_y"]
+transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 0)
+mesh = ExtResource("5_tlymd")
+skeleton = NodePath("../..")
+surface_material_override/0 = ExtResource("6_ohmps")
+
+[node name="point" type="MeshInstance3D" parent="handle_y"]
+transform = Transform3D(-1, -8.74228e-08, 3.82137e-15, 0, -4.37114e-08, -1, 8.74228e-08, -1, 4.37114e-08, 0, 0, -6)
+mesh = ExtResource("7_j0wec")
+skeleton = NodePath("../..")
+surface_material_override/0 = ExtResource("6_ohmps")
+
+[node name="collider" type="CollisionShape3D" parent="handle_y"]
+visible = false
+shape = ExtResource("8_upb4q")
+
+[node name="handle_x" type="StaticBody3D" parent="."]
+transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 10, 0, 0)
+collision_layer = 1073741824
+collision_mask = 0
+script = ExtResource("4_3ja1b")
+dir = 0
+
+[node name="cylinder" type="MeshInstance3D" parent="handle_x"]
+transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 0)
+mesh = ExtResource("5_tlymd")
+skeleton = NodePath("../..")
+surface_material_override/0 = ExtResource("9_ivepe")
+
+[node name="point" type="MeshInstance3D" parent="handle_x"]
+transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 6)
+mesh = ExtResource("7_j0wec")
+skeleton = NodePath("../..")
+surface_material_override/0 = ExtResource("9_ivepe")
+
+[node name="collider" type="CollisionShape3D" parent="handle_x"]
+visible = false
+shape = ExtResource("8_upb4q")
+
+[node name="handle_z" type="StaticBody3D" parent="."]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 10)
+collision_layer = 1073741824
+collision_mask = 0
+script = ExtResource("4_3ja1b")
+dir = 1
+
+[node name="cylinder" type="MeshInstance3D" parent="handle_z"]
+transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 0)
+mesh = ExtResource("5_tlymd")
+skeleton = NodePath("../..")
+surface_material_override/0 = ExtResource("10_4d87b")
+
+[node name="point" type="MeshInstance3D" parent="handle_z"]
+transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 6)
+mesh = ExtResource("7_j0wec")
+skeleton = NodePath("../..")
+surface_material_override/0 = ExtResource("10_4d87b")
+
+[node name="collider" type="CollisionShape3D" parent="handle_z"]
+visible = false
+shape = ExtResource("8_upb4q")
diff --git a/addons/@bendn/gizmo3d/translate/translate_arm.shape b/addons/@bendn/gizmo3d/translate/translate_arm.shape
new file mode 100644
index 0000000..59b63d0
--- /dev/null
+++ b/addons/@bendn/gizmo3d/translate/translate_arm.shape
Binary files differ
diff --git a/addons/@bendn/gizmo3d/x.tres b/addons/@bendn/gizmo3d/x.tres
new file mode 100644
index 0000000..ef88641
--- /dev/null
+++ b/addons/@bendn/gizmo3d/x.tres
@@ -0,0 +1,7 @@
+[gd_resource type="StandardMaterial3D" format=3 uid="uid://do26tijfu1ibj"]
+
+[resource]
+render_priority = 2
+no_depth_test = true
+shading_mode = 0
+albedo_color = Color(0.980392, 0.239216, 0.403922, 1)
diff --git a/addons/@bendn/gizmo3d/y.tres b/addons/@bendn/gizmo3d/y.tres
new file mode 100644
index 0000000..9348031
--- /dev/null
+++ b/addons/@bendn/gizmo3d/y.tres
@@ -0,0 +1,6 @@
+[gd_resource type="StandardMaterial3D" format=3 uid="uid://dc4qnnjootkhu"]
+
+[resource]
+no_depth_test = true
+shading_mode = 0
+albedo_color = Color(0.666667, 0.917647, 0, 1)
diff --git a/addons/@bendn/gizmo3d/z.tres b/addons/@bendn/gizmo3d/z.tres
new file mode 100644
index 0000000..201bdc6
--- /dev/null
+++ b/addons/@bendn/gizmo3d/z.tres
@@ -0,0 +1,7 @@
+[gd_resource type="StandardMaterial3D" format=3 uid="uid://btbrwby3db6t5"]
+
+[resource]
+render_priority = 1
+no_depth_test = true
+shading_mode = 0
+albedo_color = Color(0.180392, 0.686275, 0.980392, 1)
diff --git a/project.godot b/project.godot
new file mode 100644
index 0000000..d71750b
--- /dev/null
+++ b/project.godot
@@ -0,0 +1,26 @@
+; Engine configuration file.
+; It's best edited using the editor UI and not directly,
+; since the parameters that go here are not all obvious.
+;
+; Format:
+; [section] ; section goes between []
+; param=value ; assign values to parameters
+
+config_version=5
+
+[application]
+
+config/name="gizmo test"
+run/main_scene="res://test.tscn"
+config/features=PackedStringArray("4.1")
+
+[display]
+
+window/stretch/mode="viewport"
+window/stretch/aspect="expand"
+window/stretch/scale=2.0
+
+[rendering]
+
+anti_aliasing/quality/msaa_3d=3
+anti_aliasing/quality/screen_space_aa=1
diff --git a/test.gd b/test.gd
new file mode 100644
index 0000000..17cf142
--- /dev/null
+++ b/test.gd
@@ -0,0 +1,67 @@
+extends Node3D
+
+var current: Gizmo
+var gizmo_holder := Node3D.new()
+
+var original_gh_p: Vector3
+var original_positions: PackedVector3Array = []
+var original_rotations: PackedVector3Array = []
+var original_scales: PackedVector3Array = []
+
+@export var target: Node3D
+@export var gizmo: PackedScene
+@onready var targets: Array[Node3D] = [target]
+
+func _ready() -> void:
+ add_child(gizmo_holder)
+ current = gizmo.instantiate()
+ _position_gizmo_holder()
+ gizmo_holder.add_child(current)
+ _setup_originals()
+ current.finalize.connect(_gizmo_finalize)
+ current.displaced.connect(_gizmo_displace)
+ current.scaled.connect(_gizmo_scale)
+ current.rotated.connect(_gizmo_rotate)
+
+func _position_gizmo_holder() -> void:
+ var sum := Vector3.ZERO
+ for node in targets:
+ sum += node.global_position
+ gizmo_holder.global_position = sum / len(targets)
+
+func _setup_originals() -> void:
+ original_positions.resize(len(targets))
+ original_rotations.resize(len(targets))
+ original_scales.resize(len(targets))
+ for i in len(targets):
+ var n := targets[i]
+ original_positions[i] = n.global_position
+ original_rotations[i] = n.global_rotation
+ original_scales[i] = n.scale
+ original_gh_p = gizmo_holder.global_position
+
+func _gizmo_displace(offset: Vector3):
+ for i in len(targets):
+ targets[i].global_position = original_positions[i] + offset
+ gizmo_holder.global_position = original_gh_p + offset
+
+func _gizmo_scale(change: Vector3):
+ for i in len(targets):
+ var n := targets[i]
+ var scl := original_scales[i] + change
+ if scl.x <= 0 || scl.y <= 0: # no flipping allowed
+ scl = Vector3.ONE
+ n.scale = scl
+
+func _gizmo_rotate(change: Vector3):
+ for i in len(targets):
+ var n := targets[i]
+ n.global_rotation = original_rotations[i] + change
+
+func _gizmo_finalize():
+ for i in len(targets):
+ var n := targets[i]
+ original_positions[i] = n.global_position
+ original_scales[i] = n.scale
+ original_rotations[i] = n.global_rotation
+ original_gh_p = gizmo_holder.global_position
diff --git a/test.tscn b/test.tscn
new file mode 100644
index 0000000..24fdde8
--- /dev/null
+++ b/test.tscn
@@ -0,0 +1,90 @@
+[gd_scene load_steps=12 format=3 uid="uid://rdw1tgxqv6l1"]
+
+[ext_resource type="Script" path="res://test.gd" id="1_yg00y"]
+[ext_resource type="PackedScene" uid="uid://d2recqdx4hj38" path="res://addons/@bendn/gizmo3d/translate/translate.tscn" id="2_nyr7l"]
+
+[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_q35d8"]
+albedo_color = Color(2, 1, 2, 1)
+
+[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_38wvv"]
+albedo_color = Color(2, 3, 3, 1)
+
+[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_k2mgk"]
+albedo_color = Color(1, 1.5, 1, 1)
+roughness = 0.61
+
+[sub_resource type="Gradient" id="Gradient_1n4v5"]
+offsets = PackedFloat32Array(0.0962963, 0.762963)
+
+[sub_resource type="GradientTexture1D" id="GradientTexture1D_og18u"]
+gradient = SubResource("Gradient_1n4v5")
+
+[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_7o86r"]
+sky_top_color = Color(0.266667, 0.454902, 0.698039, 1)
+sky_horizon_color = Color(0.572549, 0.67451, 0.709804, 1)
+ground_bottom_color = Color(0.572549, 0.67451, 0.709804, 1)
+ground_horizon_color = Color(0.572549, 0.67451, 0.709804, 1)
+
+[sub_resource type="Sky" id="Sky_8nx2j"]
+sky_material = SubResource("ProceduralSkyMaterial_7o86r")
+
+[sub_resource type="Environment" id="Environment_k6esw"]
+background_mode = 2
+sky = SubResource("Sky_8nx2j")
+ambient_light_source = 3
+ssao_intensity = 6.88
+ssao_power = 1.60766
+glow_enabled = true
+glow_levels/2 = 3.6
+glow_levels/3 = 0.0
+volumetric_fog_enabled = true
+volumetric_fog_density = 0.0184
+volumetric_fog_sky_affect = 0.263
+adjustment_enabled = true
+adjustment_contrast = 1.1
+adjustment_saturation = 1.1
+adjustment_color_correction = SubResource("GradientTexture1D_og18u")
+
+[sub_resource type="CameraAttributesPractical" id="CameraAttributesPractical_iq4p8"]
+dof_blur_far_enabled = true
+dof_blur_far_distance = 64.44
+
+[node name="test" type="Node3D" node_paths=PackedStringArray("target")]
+script = ExtResource("1_yg00y")
+target = NodePath("box")
+gizmo = ExtResource("2_nyr7l")
+
+[node name="box" type="Node3D" parent="."]
+
+[node name="CSGBox3D" type="CSGBox3D" parent="box"]
+transform = Transform3D(0.707107, 0.5, -0.5, -0.707107, 0.5, -0.5, 0, 0.707107, 0.707107, 0, 0, 0)
+size = Vector3(10, 10, 10)
+material = SubResource("StandardMaterial3D_q35d8")
+
+[node name="CSGBox3D2" type="CSGBox3D" parent="box"]
+transform = Transform3D(1, 0, 0, 0, 0.707107, -0.707107, 0, 0.707107, 0.707107, 0, 0, 0)
+size = Vector3(10, 10, 10)
+material = SubResource("StandardMaterial3D_38wvv")
+
+[node name="CSGSphere3D" type="CSGSphere3D" parent="box"]
+radius = 7.167
+radial_segments = 64
+rings = 32
+material = SubResource("StandardMaterial3D_k2mgk")
+
+[node name="cam" type="Camera3D" parent="."]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 15.8429)
+
+[node name="sun" type="DirectionalLight3D" parent="."]
+transform = Transform3D(-0.258819, -0.965926, 7.19671e-09, 0.482963, -0.129409, 0.866025, -0.836516, 0.224144, 0.5, 10, -2, 2)
+light_energy = 0.5
+shadow_enabled = true
+directional_shadow_blend_splits = true
+
+[node name="CSGBox3D" type="CSGBox3D" parent="."]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -16, 0)
+size = Vector3(500, 1, 500)
+
+[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
+environment = SubResource("Environment_k6esw")
+camera_attributes = SubResource("CameraAttributesPractical_iq4p8")