## The bounded generator, end to end: a bridged graph in, a shader and a box out.
##
## What this can see that the density-parity gate cannot: that gate compares the
## GRAPH's field on two devices. This one asks whether dc-terrain accepted the
## graph at all -- whether the wrapper compiled, and whether the box the graph
## declared survived the trip out of Blender's frame.
##
## Usage: godot --headless --path demo --script res://gate_bounded_procnodes.gd -- <graph.json>
extends SceneTree
var _pass := 0
var _fail := 0
func _check(name: String, ok: bool, note: String = "") -> void:
if ok:
_pass += 1
print(" %-46s PASS %s" % [name, note])
else:
_fail += 1
print(" %-46s FAIL %s" % [name, note])
func _init() -> void:
var a := OS.get_cmdline_user_args()
var g: ProcNodeGraph = GraphImporter.import_from_json(FileAccess.get_file_as_string(a[0]))
_check("graph imported", g != null, "%d nodes" % (g.get_node_count() if g else 0))
if g == null:
quit(1); return
var gen := DCTerrainGeneratorProcNodesBounded.new()
gen.set_graph(g)
_check("wrapper compiled", gen.has_compiled_shader(),
gen.get_last_compile_error() if not gen.has_compiled_shader()
else "%d chars" % gen.get_compiled_glsl().length())
var glsl: String = gen.get_compiled_glsl()
_check("emits evaluate_density", glsl.find("float evaluate_density(") != -1)
# THE WHOLE POINT: world coordinates straight through, no rescale. A future
# terrain_height creeping in here would be invisible except as an asset that
# arrives the wrong size, so assert the identity call by text.
_check("world coords pass through unscaled",
glsl.find("proc_density(vec3(x, y, z))") != -1,
"no terrain_height mapping on this path")
_check("graph declared bounds", gen.has_bounds())
if gen.has_bounds():
var lo: Vector3 = gen.get_bounds_min()
var hi: Vector3 = gen.get_bounds_max()
print(" bounds min=%v max=%v voxel=%.4f" % [lo, hi, gen.get_authored_voxel_size()])
# M negates x, so an unsorted conversion inverts that axis. A box that
# is not strictly increasing on every axis meshes nothing and looks
# exactly like a missing generator.
_check("box is not inverted", hi.x > lo.x and hi.y > lo.y and hi.z > lo.z)
# Blender's up is z; after M it must be Godot's y. The mountain is much
# taller than it is deep in Blender's z, so a frame slip shows here.
# Blender's up is z and must land on Godot's y. Asserted as a SHAPE
# rather than a number: the mountain is far taller than its footprint is
# deep in Blender z, so a frame slip puts the tall axis somewhere else.
# A hardcoded height would only ever have matched the one .blend it was
# written against.
var span := hi - lo
_check("footprint is square in x/z", absf(span.x - span.z) < 0.01,
"%.2f x %.2f" % [span.x, span.z])
_check("Blender up became Godot y", span.y > span.x * 0.25 and span.y < span.x * 2.0,
"height %.4f over footprint %.4f" % [span.y, span.x])
_check("authored voxel size crossed", gen.get_authored_voxel_size() > 0.0,
"%.4f" % gen.get_authored_voxel_size())
# An unbounded graph must say so rather than guess a box.
var g2: ProcNodeGraph = GraphImporter.import_from_json(FileAccess.get_file_as_string(a[0]))
var gen2 := DCTerrainGeneratorProcNodesBounded.new()
_check("unconfigured generator is not an error", not gen2.has_compiled_shader()
and gen2.get_last_compile_error() != "",
gen2.get_last_compile_error())
print("\n%d/%d passed" % [_pass, _pass + _fail])
quit(1 if _fail > 0 else 0)