extends SceneTree
## Is the heightfield actually the terrain?
##
## With heightfield_only the density is height(x,z) - y on BOTH paths, so
## sample_density() -- which is the CPU generator -- finally reports the same
## field the GPU shader reads. That makes this runnable headless, with no GPU,
## and it checks the whole chain: the .hblk parsed, addressed on the right axes,
## and the sign convention right.
##
## It CAN fail: the block's own value at the probe column is read straight from
## the file by an independent path (a raw FileAccess read below), so a wrong
## axis order, a wrong origin or a half-texel slip all show up as a mismatch
## rather than as agreement between two copies of the same mistake.
##
## "$HYPER_TPS_GODOT" --headless --path . --script res://scenes/test/hblk_field_gate.gd
const HBLK := "res://assets/terrain/diffusion_gully_30km.hblk"
const PX := 53760.0
const PZ := 38400.0
var _map: Node = null
var _fails := 0
func _init() -> void:
var packed := load("res://scenes/maps/map_dc_diffusion.tscn") as PackedScene
if packed == null:
print("FAIL — map_dc_diffusion.tscn did not load"); quit(2); return
_map = packed.instantiate()
root.add_child(_map)
## Read the block directly, so the expected value does not come from the code
## under test. Row = world Z, column = world X (stitch_block.py).
func _raw_height(x: float, z: float) -> float:
var f := FileAccess.open(HBLK, FileAccess.READ)
f.seek(4); var _ver := f.get_32()
var n := f.get_32()
var mpp := f.get_float()
var ox := f.get_float(); var oz := f.get_float()
var u := (x - ox) / mpp
var v := (z - oz) / mpp
var i0 := int(u); var j0 := int(v)
var fu := u - float(i0); var fv := v - float(j0)
var base := 32
f.seek(base + (j0 * n + i0) * 2); var h00 := float(f.get_16())
f.seek(base + (j0 * n + i0 + 1) * 2); var h10 := float(f.get_16())
f.seek(base + ((j0 + 1) * n + i0) * 2); var h01 := float(f.get_16())
f.seek(base + ((j0 + 1) * n + i0 + 1) * 2); var h11 := float(f.get_16())
f.close()
var a := h00 + (h10 - h00) * fu
var b := h01 + (h11 - h01) * fu
return a + (b - a) * fv
func _process(_dt: float) -> bool:
var terrain = _map.get_node_or_null("DCTerrain")
if terrain == null:
print("FAIL — no DCTerrain"); _fails += 1; _done(); return true
var expect := _raw_height(PX, PZ)
print(" block file says the surface at (%.0f, %.0f) is %.1f m" % [PX, PZ, expect])
# get_16() is unsigned; elevations below sea level are negative int16.
if expect > 32767.0:
expect -= 65536.0
print(" (corrected for unsigned read: %.1f m)" % expect)
var at_surface: float = terrain.sample_density(Vector3(PX, expect, PZ))
var below: float = terrain.sample_density(Vector3(PX, expect - 100.0, PZ))
var above: float = terrain.sample_density(Vector3(PX, expect + 100.0, PZ))
print(" density at surface %+.2f, 100 m below %+.2f, 100 m above %+.2f"
% [at_surface, below, above])
if abs(at_surface) > 1.0:
print(" FAIL — the surface is not where the block says it is"); _fails += 1
if below <= 0.0:
print(" FAIL — 100 m below the surface is not solid"); _fails += 1
if above >= 0.0:
print(" FAIL — 100 m above the surface is not air"); _fails += 1
# CONTROL: a column far outside the block must clamp to the edge, not match
# the probe column. If these agree, the sampler is ignoring position.
var far: float = terrain.sample_density(Vector3(PX + 400000.0, expect, PZ))
print(" CONTROL 400 km away: density %+.2f (must differ from %+.2f)" % [far, at_surface])
if abs(far - at_surface) < 1.0:
print(" FAIL — the field does not vary with position at all"); _fails += 1
_done()
return true
func _done() -> void:
print("")
if _fails == 0:
print("VERDICT: the heightfield IS the terrain — right axes, right origin,")
print(" right sign. Whatever is on screen, the field is in.")
else:
print("VERDICT: ", _fails, " check(s) failed.")
quit(0 if _fails == 0 else 1)