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:
parent
6ee49c3375
commit
7a6ae79d01
160 changed files with 7209 additions and 2072 deletions
97
demo/scripts/export_tb_config.gd
Normal file
97
demo/scripts/export_tb_config.gd
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
extends SceneTree
|
||||
|
||||
# Usage:
|
||||
# godot --headless --path demo --script scripts/export_tb_config.gd -- OUT_DIR
|
||||
#
|
||||
# Writes a complete TrenchBroom game config to OUT_DIR:
|
||||
# OUT_DIR/GameConfig.cfg — game definition (name, formats, texture dirs)
|
||||
# OUT_DIR/FuncGodot.fgd — entity definitions, generated from
|
||||
# res://data/fgd/brogue_fgd.tres via
|
||||
# FuncGodotFGDFile.build_class_text().
|
||||
#
|
||||
# Skips the Inspector's "Export FGD" button entirely. Safe to re-run after
|
||||
# any change to brogue_fgd.tres or entity resources under data/entities/.
|
||||
|
||||
const GAME_CONFIG := """{
|
||||
\t\"version\": 9,
|
||||
\t\"name\": \"brogue-genesis\",
|
||||
\t\"icon\": \"icon.png\",
|
||||
\t\"fileformats\": [
|
||||
\t\t{ \"format\": \"Valve\", \"initialmap\": \"initial_valve.map\" },
|
||||
\t\t{ \"format\": \"Standard\", \"initialmap\": \"initial_standard.map\" }
|
||||
\t],
|
||||
\t\"filesystem\": {
|
||||
\t\t\"searchpath\": \".\",
|
||||
\t\t\"packageformat\": { \"extension\": \".zip\", \"format\": \"zip\" }
|
||||
\t},
|
||||
\t\"materials\": {
|
||||
\t\t\"root\": \"textures\",
|
||||
\t\t\"extensions\": [\".bmp\", \".jpeg\", \".jpg\", \".png\", \".tga\", \".webp\"],
|
||||
\t\t\"excludes\": [ \"*_albedo\", \"*_ao\", \"*_emission\", \"*_height\", \"*_metallic\", \"*_normal\", \"*_orm\", \"*_roughness\", \"*_sss\" ],
|
||||
\t\t\"palette\": \"textures/palette.lmp\",
|
||||
\t\t\"attribute\": \"wad\"
|
||||
\t},
|
||||
\t\"entities\": {
|
||||
\t\t\"definitions\": [ \"FuncGodot.fgd\" ],
|
||||
\t\t\"defaultcolor\": \"0.6 0.6 0.6 1.0\",
|
||||
\t\t\"scale\": 32
|
||||
\t},
|
||||
\t\"tags\": {
|
||||
\t\t\"brush\": [],
|
||||
\t\t\"brushface\": [
|
||||
\t\t\t{ \"name\": \"Clip\", \"attribs\": [ \"transparent\" ], \"match\": \"material\", \"pattern\": \"clip\" },
|
||||
\t\t\t{ \"name\": \"Skip\", \"attribs\": [ \"transparent\" ], \"match\": \"material\", \"pattern\": \"skip\" },
|
||||
\t\t\t{ \"name\": \"Origin\", \"attribs\": [ \"transparent\" ], \"match\": \"material\", \"pattern\": \"origin\" }
|
||||
\t\t]
|
||||
\t},
|
||||
\t\"faceattribs\": {
|
||||
\t\t\"defaults\": { \"scale\": [1.0, 1.0] },
|
||||
\t\t\"contentflags\": [],
|
||||
\t\t\"surfaceflags\": []
|
||||
\t}
|
||||
}
|
||||
"""
|
||||
|
||||
func _init() -> void:
|
||||
var args := OS.get_cmdline_user_args()
|
||||
if args.size() != 1:
|
||||
push_error("usage: -- OUT_DIR")
|
||||
quit(1)
|
||||
return
|
||||
var out_dir: String = args[0]
|
||||
|
||||
if not DirAccess.dir_exists_absolute(out_dir):
|
||||
if DirAccess.make_dir_recursive_absolute(out_dir) != OK:
|
||||
push_error("failed to create %s" % out_dir)
|
||||
quit(1)
|
||||
return
|
||||
|
||||
var cfg_path := out_dir.path_join("GameConfig.cfg")
|
||||
var cfg_file := FileAccess.open(cfg_path, FileAccess.WRITE)
|
||||
if cfg_file == null:
|
||||
push_error("cannot open %s for write" % cfg_path)
|
||||
quit(1)
|
||||
return
|
||||
cfg_file.store_string(GAME_CONFIG)
|
||||
cfg_file.close()
|
||||
|
||||
var fgd: Resource = load("res://data/fgd/brogue_fgd.tres")
|
||||
if fgd == null:
|
||||
push_error("failed to load res://data/fgd/brogue_fgd.tres")
|
||||
quit(1)
|
||||
return
|
||||
|
||||
var fgd_text: String = fgd.build_class_text(1) # 1 == TRENCHBROOM
|
||||
var fgd_path := out_dir.path_join("FuncGodot.fgd")
|
||||
var fgd_file := FileAccess.open(fgd_path, FileAccess.WRITE)
|
||||
if fgd_file == null:
|
||||
push_error("cannot open %s for write" % fgd_path)
|
||||
quit(1)
|
||||
return
|
||||
fgd_file.store_string(fgd_text)
|
||||
fgd_file.close()
|
||||
|
||||
print("synced TrenchBroom config to %s" % out_dir)
|
||||
print(" GameConfig.cfg %d bytes" % GAME_CONFIG.length())
|
||||
print(" FuncGodot.fgd %d bytes" % fgd_text.length())
|
||||
quit(0)
|
||||
Loading…
Add table
Add a link
Reference in a new issue