feat: 3D blobber dungeon generator (PR 1)

Replaces the 2D-only demo pipeline with a 3D cell-based blobber
generator. Per-cell face walls, per-material mesh emission, and a
GDExtension binding that returns a Dictionary with ArrayMesh surfaces
the demo consumes directly.

- src/blobber/: cell3d_t data model, dungeon container, pipeline that
  wraps the 2D generator per level and materializes into cell3d
- src/mesh/: face-quad emitter with per-material groups + .obj dump
- src/genesis3d_main.c: new CLI driving the blobber + mesh
- godot/: BrogueGen.generate_dungeon(seed, num_levels, depth) binding
  with dungeon_to_dict packing cells + mesh surfaces
- demo/: demo_blobber.tscn + dungeon_builder.gd, func_godot addon for
  the .map export path, point/entity templates, TrenchBroom docs
- Retired: old arcade/FPS demo scenes and their scripts, unused meshlib

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
saarsena@gmail.com 2026-04-18 13:24:27 -04:00
parent 6ee49c3375
commit 7a6ae79d01
160 changed files with 7209 additions and 2072 deletions

View file

@ -0,0 +1,15 @@
[gd_resource type="Resource" script_class="FuncGodotFGDBaseClass" load_steps=2 format=3 uid="uid://bcdsueg5pysfq"]
[ext_resource type="Script" uid="uid://ck575aqs1sbrb" path="res://addons/func_godot/src/fgd/func_godot_fgd_base_class.gd" id="1_21jph"]
[resource]
script = ExtResource("1_21jph")
classname = "CullInteriorFaces"
description = "Cull interior faces option for SolidClass Geometry"
class_properties = Dictionary[String, Variant]({
"_cull_interior_faces": false
})
class_property_descriptions = Dictionary[String, Variant]({
"_cull_interior_faces": "If true, cull interior faces with matching vertices or faces that are flush within a larger face. Note: This has a performance impact that scales with how many brushes are in the brush entity."
})
metadata/_custom_type_script = "uid://cgkrrgcimlr8y"

View file

@ -0,0 +1,18 @@
[gd_resource type="Resource" script_class="FuncGodotFGDSolidClass" load_steps=5 format=3 uid="uid://cxy7jnh6d7msn"]
[ext_resource type="Script" uid="uid://5cow84q03m6a" path="res://addons/func_godot/src/fgd/func_godot_fgd_solid_class.gd" id="1_0fsmp"]
[ext_resource type="Resource" uid="uid://nayxb8n7see2" path="res://addons/func_godot/fgd/phong_base.tres" id="1_c3bns"]
[ext_resource type="Resource" uid="uid://doo4ly322b4jc" path="res://addons/func_godot/fgd/vertex_merge_distance_base.tres" id="2_c03gr"]
[ext_resource type="Resource" uid="uid://bcdsueg5pysfq" path="res://addons/func_godot/fgd/cull_interior_faces.tres" id="3_wuxhx"]
[resource]
script = ExtResource("1_0fsmp")
collision_shape_type = 2
collision_mask = 0
classname = "func_detail"
description = "Static collidable geometry. Builds a StaticBody3D with a MeshInstance3D and a single concave CollisionShape3D. Does not occlude other VisualInstance3D nodes."
base_classes = Array[Resource]([ExtResource("1_c3bns"), ExtResource("2_c03gr"), ExtResource("3_wuxhx")])
meta_properties = Dictionary[String, Variant]({
"color": Color(0.8, 0.8, 0.8, 1)
})
node_class = "StaticBody3D"

View file

@ -0,0 +1,17 @@
[gd_resource type="Resource" script_class="FuncGodotFGDSolidClass" load_steps=5 format=3 uid="uid://ch3e0dix85uhb"]
[ext_resource type="Resource" uid="uid://nayxb8n7see2" path="res://addons/func_godot/fgd/phong_base.tres" id="1_ar63x"]
[ext_resource type="Resource" uid="uid://doo4ly322b4jc" path="res://addons/func_godot/fgd/vertex_merge_distance_base.tres" id="2_j7vgq"]
[ext_resource type="Script" uid="uid://5cow84q03m6a" path="res://addons/func_godot/src/fgd/func_godot_fgd_solid_class.gd" id="2_lhb87"]
[ext_resource type="Resource" uid="uid://bcdsueg5pysfq" path="res://addons/func_godot/fgd/cull_interior_faces.tres" id="3_1mhrv"]
[resource]
script = ExtResource("2_lhb87")
collision_shape_type = 0
classname = "func_detail_illusionary"
description = "Static geometry with no collision. Builds a Node3D with a MeshInstance3D. Does not occlude other VisualInstance3D nodes."
base_classes = Array[Resource]([ExtResource("1_ar63x"), ExtResource("2_j7vgq"), ExtResource("3_1mhrv")])
meta_properties = Dictionary[String, Variant]({
"color": Color(0.8, 0.8, 0.8, 1)
})
node_class = "Node3D"

View file

@ -0,0 +1,19 @@
[gd_resource type="Resource" script_class="FuncGodotFGDSolidClass" load_steps=5 format=3 uid="uid://b70vf4t5dc70t"]
[ext_resource type="Resource" uid="uid://nayxb8n7see2" path="res://addons/func_godot/fgd/phong_base.tres" id="1_5mwee"]
[ext_resource type="Script" uid="uid://5cow84q03m6a" path="res://addons/func_godot/src/fgd/func_godot_fgd_solid_class.gd" id="2_8o081"]
[ext_resource type="Resource" uid="uid://doo4ly322b4jc" path="res://addons/func_godot/fgd/vertex_merge_distance_base.tres" id="2_bp8pb"]
[ext_resource type="Resource" uid="uid://bcdsueg5pysfq" path="res://addons/func_godot/fgd/cull_interior_faces.tres" id="3_xnsya"]
[resource]
script = ExtResource("2_8o081")
build_occlusion = true
collision_shape_type = 2
collision_mask = 0
classname = "func_geo"
description = "Static collidable geometry. Builds a StaticBody3D with a MeshInstance3D, a single concave CollisionShape3D, and an OccluderInstance3D."
base_classes = Array[Resource]([ExtResource("1_5mwee"), ExtResource("2_bp8pb"), ExtResource("3_xnsya")])
meta_properties = Dictionary[String, Variant]({
"color": Color(0.8, 0.8, 0.8, 1)
})
node_class = "StaticBody3D"

View file

@ -0,0 +1,15 @@
[gd_resource type="Resource" script_class="FuncGodotFGDFile" load_steps=10 format=3 uid="uid://crgpdahjaj"]
[ext_resource type="Script" uid="uid://drlmgulwbjwqu" path="res://addons/func_godot/src/fgd/func_godot_fgd_file.gd" id="1_axt3h"]
[ext_resource type="Resource" uid="uid://nayxb8n7see2" path="res://addons/func_godot/fgd/phong_base.tres" id="1_ehab8"]
[ext_resource type="Resource" uid="uid://doo4ly322b4jc" path="res://addons/func_godot/fgd/vertex_merge_distance_base.tres" id="2_7jebp"]
[ext_resource type="Resource" uid="uid://bdji3873bg32h" path="res://addons/func_godot/fgd/worldspawn.tres" id="2_ri2rx"]
[ext_resource type="Resource" uid="uid://b70vf4t5dc70t" path="res://addons/func_godot/fgd/func_geo.tres" id="3_7jigp"]
[ext_resource type="Resource" uid="uid://cxy7jnh6d7msn" path="res://addons/func_godot/fgd/func_detail.tres" id="3_fqfww"]
[ext_resource type="Resource" uid="uid://bcdsueg5pysfq" path="res://addons/func_godot/fgd/cull_interior_faces.tres" id="3_h5cmk"]
[ext_resource type="Resource" uid="uid://dg5x44cc7flew" path="res://addons/func_godot/fgd/func_illusionary.tres" id="4_c4ucw"]
[ext_resource type="Resource" uid="uid://ch3e0dix85uhb" path="res://addons/func_godot/fgd/func_detail_illusionary.tres" id="5_b2q3p"]
[resource]
script = ExtResource("1_axt3h")
entity_definitions = Array[Resource]([ExtResource("1_ehab8"), ExtResource("2_7jebp"), ExtResource("3_h5cmk"), ExtResource("2_ri2rx"), ExtResource("3_7jigp"), ExtResource("3_fqfww"), ExtResource("5_b2q3p"), ExtResource("4_c4ucw")])

View file

@ -0,0 +1,18 @@
[gd_resource type="Resource" script_class="FuncGodotFGDSolidClass" load_steps=5 format=3 uid="uid://dg5x44cc7flew"]
[ext_resource type="Resource" uid="uid://nayxb8n7see2" path="res://addons/func_godot/fgd/phong_base.tres" id="1_kv0mq"]
[ext_resource type="Resource" uid="uid://doo4ly322b4jc" path="res://addons/func_godot/fgd/vertex_merge_distance_base.tres" id="2_hovr4"]
[ext_resource type="Script" uid="uid://5cow84q03m6a" path="res://addons/func_godot/src/fgd/func_godot_fgd_solid_class.gd" id="2_uffhi"]
[ext_resource type="Resource" uid="uid://bcdsueg5pysfq" path="res://addons/func_godot/fgd/cull_interior_faces.tres" id="3_woywv"]
[resource]
script = ExtResource("2_uffhi")
build_occlusion = true
collision_shape_type = 0
classname = "func_illusionary"
description = "Static geometry with no collision. Builds a Node3D with a MeshInstance3D and an Occluder3D to aid in render culling of other VisualInstance3D nodes."
base_classes = Array[Resource]([ExtResource("1_kv0mq"), ExtResource("2_hovr4"), ExtResource("3_woywv")])
meta_properties = Dictionary[String, Variant]({
"color": Color(0.8, 0.8, 0.8, 1)
})
node_class = "Node3D"

View file

@ -0,0 +1,19 @@
[gd_resource type="Resource" script_class="FuncGodotFGDBaseClass" load_steps=2 format=3 uid="uid://nayxb8n7see2"]
[ext_resource type="Script" uid="uid://ck575aqs1sbrb" path="res://addons/func_godot/src/fgd/func_godot_fgd_base_class.gd" id="1_04y3n"]
[resource]
script = ExtResource("1_04y3n")
classname = "Phong"
description = "Phong shading options for SolidClass geometry."
class_properties = Dictionary[String, Variant]({
"_phong": {
"Disabled": 0,
"Smooth shading": 1
},
"_phong_angle": 89.0
})
class_property_descriptions = Dictionary[String, Variant]({
"_phong": ["Phong shading", 0],
"_phong_angle": "Phong smoothing angle"
})

View file

@ -0,0 +1,15 @@
[gd_resource type="Resource" script_class="FuncGodotFGDBaseClass" load_steps=2 format=3 uid="uid://doo4ly322b4jc"]
[ext_resource type="Script" uid="uid://ck575aqs1sbrb" path="res://addons/func_godot/src/fgd/func_godot_fgd_base_class.gd" id="1_h3atm"]
[resource]
script = ExtResource("1_h3atm")
classname = "VertexMergeDistance"
description = "Adjustable value to snap vertices to on map build. This can reduce instances of seams between polygons."
class_properties = Dictionary[String, Variant]({
"_vertex_merge_distance": 0.03125
})
class_property_descriptions = Dictionary[String, Variant]({
"_vertex_merge_distance": "Adjustable value to snap vertices to on map build. This can reduce instances of seams between polygons."
})
metadata/_custom_type_script = "uid://ck575aqs1sbrb"

View file

@ -0,0 +1,18 @@
[gd_resource type="Resource" script_class="FuncGodotFGDSolidClass" load_steps=4 format=3 uid="uid://bdji3873bg32h"]
[ext_resource type="Script" uid="uid://5cow84q03m6a" path="res://addons/func_godot/src/fgd/func_godot_fgd_solid_class.gd" id="1_62t8m"]
[ext_resource type="Resource" uid="uid://doo4ly322b4jc" path="res://addons/func_godot/fgd/vertex_merge_distance_base.tres" id="1_h1046"]
[ext_resource type="Resource" uid="uid://bcdsueg5pysfq" path="res://addons/func_godot/fgd/cull_interior_faces.tres" id="2_ky6lr"]
[resource]
script = ExtResource("1_62t8m")
spawn_type = 0
origin_type = 1
collision_mask = 0
classname = "worldspawn"
description = "Default static world geometry. Builds a StaticBody3D with a single MeshInstance3D and a single convex CollisionShape3D shape."
base_classes = Array[Resource]([ExtResource("1_h1046"), ExtResource("2_ky6lr")])
meta_properties = Dictionary[String, Variant]({
"color": Color(0.8, 0.8, 0.8, 1)
})
node_class = "StaticBody3D"