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>
2026-04-18 13:24:27 -04:00
|
|
|
extends Node3D
|
|
|
|
|
|
|
|
|
|
# Blobber dungeon builder. Calls BrogueGen.generate_dungeon() and assembles
|
|
|
|
|
# per-material MeshInstance3D children from the returned mesh surface arrays.
|
|
|
|
|
# Material ids mirror src/mesh/material_ids.h.
|
2026-04-18 14:00:53 -04:00
|
|
|
#
|
|
|
|
|
# If `party_path` is set, the builder also feeds the generated Dictionary to
|
|
|
|
|
# the party controller so it lands on the entry stair with fresh cell data.
|
|
|
|
|
|
|
|
|
|
const BlobberPartyScript := preload("res://scripts/blobber_party.gd")
|
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>
2026-04-18 13:24:27 -04:00
|
|
|
|
|
|
|
|
const MAT_STONE_FLOOR := 0
|
|
|
|
|
const MAT_STONE_CEILING := 1
|
|
|
|
|
const MAT_STONE_WALL := 2
|
|
|
|
|
const MAT_DOOR_FLOOR := 3
|
|
|
|
|
const MAT_STAIR_UP := 4
|
|
|
|
|
const MAT_STAIR_DOWN := 5
|
|
|
|
|
const MAT_WATER := 6
|
|
|
|
|
const MAT_LAVA := 7
|
|
|
|
|
const MAT_BRIDGE := 8
|
|
|
|
|
const MAT_CAVE_FLOOR := 9
|
|
|
|
|
const MAT_CAVE_CEILING := 10
|
|
|
|
|
const MAT_CAVE_WALL := 11
|
|
|
|
|
|
|
|
|
|
@export var seed_value: int = 42
|
|
|
|
|
@export var num_levels: int = 1
|
|
|
|
|
@export var depth: int = 1
|
|
|
|
|
@export var regenerate_on_ready: bool = true
|
2026-04-18 14:00:53 -04:00
|
|
|
@export var party_path: NodePath
|
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>
2026-04-18 13:24:27 -04:00
|
|
|
|
|
|
|
|
var _materials: Dictionary = {}
|
2026-04-18 14:00:53 -04:00
|
|
|
var _mesh_parent: Node3D
|
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>
2026-04-18 13:24:27 -04:00
|
|
|
|
|
|
|
|
func _ready() -> void:
|
|
|
|
|
_materials = _build_materials()
|
|
|
|
|
if regenerate_on_ready:
|
|
|
|
|
regenerate()
|
|
|
|
|
|
|
|
|
|
func regenerate() -> void:
|
2026-04-18 14:00:53 -04:00
|
|
|
if _mesh_parent and is_instance_valid(_mesh_parent):
|
|
|
|
|
_mesh_parent.queue_free()
|
|
|
|
|
_mesh_parent = Node3D.new()
|
|
|
|
|
_mesh_parent.name = "Meshes"
|
|
|
|
|
add_child(_mesh_parent)
|
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>
2026-04-18 13:24:27 -04:00
|
|
|
|
|
|
|
|
var gen := BrogueGen.new()
|
|
|
|
|
var dungeon: Dictionary = gen.generate_dungeon(seed_value, num_levels, depth)
|
|
|
|
|
gen.free()
|
|
|
|
|
|
|
|
|
|
if dungeon.is_empty():
|
|
|
|
|
push_error("generate_dungeon returned empty dictionary")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
var meshes: Array = dungeon.get("meshes", [])
|
|
|
|
|
for entry_v in meshes:
|
|
|
|
|
var entry: Dictionary = entry_v
|
|
|
|
|
var material_id: int = entry.get("material", -1)
|
|
|
|
|
var arrays: Array = entry.get("arrays", [])
|
|
|
|
|
if material_id < 0 or arrays.is_empty():
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
var mesh := ArrayMesh.new()
|
|
|
|
|
mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays)
|
|
|
|
|
mesh.surface_set_material(0, _materials.get(material_id, _fallback_material()))
|
|
|
|
|
|
|
|
|
|
var mi := MeshInstance3D.new()
|
|
|
|
|
mi.mesh = mesh
|
|
|
|
|
mi.name = "Surface_%d" % material_id
|
2026-04-18 14:00:53 -04:00
|
|
|
_mesh_parent.add_child(mi)
|
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>
2026-04-18 13:24:27 -04:00
|
|
|
|
|
|
|
|
var dims: Vector3i = dungeon.get("dimensions", Vector3i(79, 1, 29))
|
|
|
|
|
var levels: Array = dungeon.get("levels", [])
|
|
|
|
|
print("Dungeon built: seed=%d dims=%s surfaces=%d levels=%d" %
|
|
|
|
|
[seed_value, dims, meshes.size(), levels.size()])
|
|
|
|
|
|
2026-04-18 14:00:53 -04:00
|
|
|
if party_path != NodePath(""):
|
|
|
|
|
var party := get_node_or_null(party_path)
|
|
|
|
|
if party and party.has_method("setup"):
|
|
|
|
|
party.setup(dungeon)
|
|
|
|
|
|
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>
2026-04-18 13:24:27 -04:00
|
|
|
# Distinct albedo colors per material for instant visual debugging.
|
|
|
|
|
# Later PRs replace these with proper StandardMaterial3D + textures.
|
|
|
|
|
func _build_materials() -> Dictionary:
|
|
|
|
|
var m := {}
|
|
|
|
|
m[MAT_STONE_FLOOR] = _flat(Color(0.45, 0.42, 0.38))
|
|
|
|
|
m[MAT_STONE_CEILING] = _flat(Color(0.30, 0.28, 0.26))
|
|
|
|
|
m[MAT_STONE_WALL] = _flat(Color(0.55, 0.50, 0.45))
|
|
|
|
|
m[MAT_DOOR_FLOOR] = _flat(Color(0.62, 0.38, 0.18))
|
|
|
|
|
m[MAT_STAIR_UP] = _flat(Color(0.20, 0.75, 0.40))
|
|
|
|
|
m[MAT_STAIR_DOWN] = _flat(Color(0.85, 0.25, 0.20))
|
|
|
|
|
m[MAT_WATER] = _flat(Color(0.15, 0.40, 0.75))
|
|
|
|
|
m[MAT_LAVA] = _flat(Color(0.95, 0.40, 0.10))
|
|
|
|
|
m[MAT_BRIDGE] = _flat(Color(0.50, 0.35, 0.20))
|
|
|
|
|
m[MAT_CAVE_FLOOR] = _flat(Color(0.35, 0.32, 0.28))
|
|
|
|
|
m[MAT_CAVE_CEILING] = _flat(Color(0.22, 0.20, 0.18))
|
|
|
|
|
m[MAT_CAVE_WALL] = _flat(Color(0.42, 0.38, 0.34))
|
|
|
|
|
return m
|
|
|
|
|
|
|
|
|
|
func _flat(c: Color) -> StandardMaterial3D:
|
|
|
|
|
var sm := StandardMaterial3D.new()
|
|
|
|
|
sm.albedo_color = c
|
|
|
|
|
sm.roughness = 0.85
|
|
|
|
|
sm.metallic = 0.0
|
|
|
|
|
return sm
|
|
|
|
|
|
|
|
|
|
func _fallback_material() -> StandardMaterial3D:
|
|
|
|
|
return _flat(Color.MAGENTA)
|