From 2c0114357997c6869ccd837afe326406f15149c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojte=CC=8Cch=20Struha=CC=81r?= Date: Mon, 24 Feb 2025 18:38:38 +0100 Subject: [PATCH] Test procedural mesh generation --- addons/inspector_buttons/inspector_buttons.gd | 49 ++++++++++++ .../inspector_buttons.gd.uid | 1 + addons/inspector_buttons/plugin.cfg | 7 ++ levels/test_procedural_portal.tscn | 12 +++ procedural_mesh_maker.gd | 77 +++++++++++++++++++ procedural_mesh_maker.gd.uid | 1 + procedural_mesh_maker.tscn | 6 ++ project.godot | 2 +- 8 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 addons/inspector_buttons/inspector_buttons.gd create mode 100644 addons/inspector_buttons/inspector_buttons.gd.uid create mode 100644 addons/inspector_buttons/plugin.cfg create mode 100644 levels/test_procedural_portal.tscn create mode 100644 procedural_mesh_maker.gd create mode 100644 procedural_mesh_maker.gd.uid create mode 100644 procedural_mesh_maker.tscn diff --git a/addons/inspector_buttons/inspector_buttons.gd b/addons/inspector_buttons/inspector_buttons.gd new file mode 100644 index 0000000..7c24c00 --- /dev/null +++ b/addons/inspector_buttons/inspector_buttons.gd @@ -0,0 +1,49 @@ +@tool +extends EditorPlugin + +var editor_button_plugin:EditorButtonPlugin + +func _enter_tree() -> void: + print("[inspector_buttons] enter") + editor_button_plugin = EditorButtonPlugin.new() + add_inspector_plugin(editor_button_plugin) + + +func _exit_tree() -> void: + if is_instance_valid(editor_button_plugin): + print("[inspector_buttons] exit") + remove_inspector_plugin(editor_button_plugin) + editor_button_plugin = null + + +class EditorButtonPlugin extends EditorInspectorPlugin: + func _can_handle(object: Object) -> bool: + return object.has_method('_add_inspector_buttons') + + + func _parse_begin(object: Object) -> void: + var buttons_data = object._add_inspector_buttons() + for button_data in buttons_data: + var name = button_data.get("name", null) + var icon = button_data.get("icon", null) + var pressed = button_data.get("pressed", null) + if not name: + push_warning('_add_inspector_buttons(): A button does not have a name key. Defaulting to: "Button"') + name = "Button" + if icon and not icon is Texture: + push_warning('_add_inspector_buttons(): The button <{name}> icon is not a texture.'.format({"name":name})) + icon = null + if not pressed: + push_warning('_add_inspector_buttons(): The button <{name}> does not have a pressed key. Skipping.'.format({"name":name})) + continue + if not pressed is Callable: + push_warning('_add_inspector_buttons(): The button <{name}> pressed is not a Callable. Skipping.'.format({"name":name})) + continue + + var button = Button.new() + button.text = name + if icon: + button.icon = icon + button.expand_icon = true + button.pressed.connect(pressed) + add_custom_control(button) diff --git a/addons/inspector_buttons/inspector_buttons.gd.uid b/addons/inspector_buttons/inspector_buttons.gd.uid new file mode 100644 index 0000000..2163767 --- /dev/null +++ b/addons/inspector_buttons/inspector_buttons.gd.uid @@ -0,0 +1 @@ +uid://cmkf6s21ky7b5 diff --git a/addons/inspector_buttons/plugin.cfg b/addons/inspector_buttons/plugin.cfg new file mode 100644 index 0000000..7102f7c --- /dev/null +++ b/addons/inspector_buttons/plugin.cfg @@ -0,0 +1,7 @@ +[plugin] + +name="Inspector Buttons" +description="Quick and dirty Godot inspector plugins. Taken from the internets" +author="mrcdk" +version="0.1" +script="inspector_buttons.gd" diff --git a/levels/test_procedural_portal.tscn b/levels/test_procedural_portal.tscn new file mode 100644 index 0000000..f1638c5 --- /dev/null +++ b/levels/test_procedural_portal.tscn @@ -0,0 +1,12 @@ +[gd_scene load_steps=3 format=3 uid="uid://c0ieh1abu1xne"] + +[ext_resource type="Script" uid="uid://d2bvvjsibau8c" path="res://addons/simple-portal-system/scripts/portal.gd" id="1_ksg6r"] +[ext_resource type="PackedScene" uid="uid://d1dtxvwk86ple" path="res://procedural_mesh_maker.tscn" id="2_4vena"] + +[node name="ProceduralPortal" type="Node3D"] + +[node name="MeshInstance3D" type="MeshInstance3D" parent="."] +script = ExtResource("1_ksg6r") + +[node name="ProceduralMeshMaker" parent="." node_paths=PackedStringArray("portal") instance=ExtResource("2_4vena")] +portal = NodePath("../MeshInstance3D") diff --git a/procedural_mesh_maker.gd b/procedural_mesh_maker.gd new file mode 100644 index 0000000..cfaab15 --- /dev/null +++ b/procedural_mesh_maker.gd @@ -0,0 +1,77 @@ +@tool +extends Node + +@export_range(0.1, 10, 0.01) var height: float = 2.0 +@export_range(0.1, 10, 0.01) var width: float = 1.0 +@export var portal: Portal + +func _add_inspector_buttons() -> Array: + var buttons = [] + + buttons.push_back({ + "name": "Generate Portal Mesh", + "pressed": generate_portal_mesh + }) + + return buttons + +func _get_configuration_warnings() -> PackedStringArray: + var warnings = [] + + if portal == null: + warnings.append("Assign a portal to generate the mesh for") + + return warnings + +func generate_portal_mesh() -> void: + if portal == null: + push_error("No portal") + return + + if portal.mesh != null: + push_warning("The portal %s already has a mesh!" % portal.name) + return + + var mesh = ArrayMesh.new() + print("[PMM] Creating mesh") + + var surface_array = [] + surface_array.resize(Mesh.ARRAY_MAX) + + var verts = PackedVector3Array() + var uvs = PackedVector2Array() + var normals = PackedVector3Array() + var indices = PackedInt32Array() + + # Bottom left triangle of a rect + verts.append(Vector3(-width/2, 0, 0)) + verts.append(Vector3(width/2, 0, 0)) + verts.append(Vector3(width/2, height, 0)) + + uvs.append(Vector2(0, 1)) + uvs.append(Vector2(1, 1)) + uvs.append(Vector2(0, 0)) + + normals.append_array([Vector3.FORWARD, Vector3.FORWARD, Vector3.FORWARD]) + indices.append_array([0, 1, 2]) + + # Top right triangle of a rect + verts.append(Vector3(-width/2, 0, 0)) + verts.append(Vector3(width/2, height, 0)) + verts.append(Vector3(-width/2, height, 0)) + + uvs.append(Vector2(0, 1)) + uvs.append(Vector2(1, 0)) + uvs.append(Vector2(0, 0)) + normals.append_array([Vector3.FORWARD, Vector3.FORWARD, Vector3.FORWARD]) + indices.append_array([3, 4, 5]) + + surface_array[Mesh.ARRAY_VERTEX] = verts + surface_array[Mesh.ARRAY_TEX_UV] = uvs + surface_array[Mesh.ARRAY_NORMAL] = normals + surface_array[Mesh.ARRAY_INDEX] = indices + + # No blendshapes, lods, or compression used. + mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, surface_array) + portal.mesh = mesh + print("[PMM] Mesh assigned") diff --git a/procedural_mesh_maker.gd.uid b/procedural_mesh_maker.gd.uid new file mode 100644 index 0000000..02d435f --- /dev/null +++ b/procedural_mesh_maker.gd.uid @@ -0,0 +1 @@ +uid://xt85yw2lp6dw diff --git a/procedural_mesh_maker.tscn b/procedural_mesh_maker.tscn new file mode 100644 index 0000000..0c3a375 --- /dev/null +++ b/procedural_mesh_maker.tscn @@ -0,0 +1,6 @@ +[gd_scene load_steps=2 format=3 uid="uid://d1dtxvwk86ple"] + +[ext_resource type="Script" uid="uid://xt85yw2lp6dw" path="res://procedural_mesh_maker.gd" id="1_1a4ua"] + +[node name="ProceduralMeshMaker" type="Node"] +script = ExtResource("1_1a4ua") diff --git a/project.godot b/project.godot index 09ef8c2..4f447a7 100644 --- a/project.godot +++ b/project.godot @@ -22,7 +22,7 @@ window/size/viewport_height=1080 [editor_plugins] -enabled=PackedStringArray("res://addons/portal_gizmos/plugin.cfg") +enabled=PackedStringArray("res://addons/inspector_buttons/plugin.cfg", "res://addons/portal_gizmos/plugin.cfg") [input]