108 lines
3.6 KiB
Text
108 lines
3.6 KiB
Text
-- A large heightmap is drawn in chunks, each culled alone, and looks as it did drawn whole.
|
|
-- testScripts/ridges.png is 257 samples a side, so meshHeightmap makes 256 by 256 cells in 16
|
|
-- chunks of 64; a twin built cell for cell through meshNew from the same formula is one mesh
|
|
-- with no chunks. sceneGetStats has to count 16 draws for the chunked one, fewer of them inside
|
|
-- the view (the camera stands in the middle, so what is behind it is not drawn), and one for the
|
|
-- twin. terrainGetHeight has to read the samples exactly, which a greyscale PNG did not until
|
|
-- the loader's grey ramp was fixed. The screenshots chunked and whole should match: the
|
|
-- triangles are the same and only the order the normals are summed in differs. Each check prints
|
|
-- "CHUNKS ok" or "CHUNKS FAIL". No disc: run with -C 720x480.
|
|
dofile("Singe/Framework.singe")
|
|
|
|
local font = fontLoad("Singe/FreeSansBold.ttf", 14)
|
|
local ground = materialNew()
|
|
local camera = nodeNew()
|
|
local sun = lightNew(LIGHT_DIRECTIONAL)
|
|
local chunked = nodeNew()
|
|
local whole = nodeNew()
|
|
local frames = 0
|
|
local failures = 0
|
|
local SAMPLES = 257
|
|
local SIZE = 256 -- Across, so every vertex lands on a whole number
|
|
local HEIGHT = 16
|
|
local LAST = 10
|
|
|
|
|
|
local function check(name, ok, detail)
|
|
if ok then
|
|
debugPrint("CHUNKS ok " .. name)
|
|
else
|
|
failures = failures + 1
|
|
debugPrint("CHUNKS FAIL " .. name .. (detail and (" (" .. detail .. ")") or ""))
|
|
end
|
|
end
|
|
|
|
|
|
-- The sample at column x, row y, as the PNG holds it: the same formula made ridges.png.
|
|
local function sample(x, y)
|
|
return math.floor((0.5 + 0.25 * math.sin(x * 0.05) + 0.25 * math.cos(y * 0.07)) * 255 + 0.5) / 255
|
|
end
|
|
|
|
|
|
-- The grid meshHeightmap makes, a vertex per sample with row 0 at -Z, wound to face up.
|
|
local function twinMesh()
|
|
local positions = {}
|
|
local indices = {}
|
|
local cells = SAMPLES - 1
|
|
|
|
for y = 0, cells do
|
|
for x = 0, cells do
|
|
positions[#positions + 1] = -SIZE / 2 + x
|
|
positions[#positions + 1] = sample(x, y) * HEIGHT
|
|
positions[#positions + 1] = -SIZE / 2 + y
|
|
end
|
|
end
|
|
for y = 0, cells - 1 do
|
|
for x = 0, cells - 1 do
|
|
local a = y * SAMPLES + x + 1
|
|
local b = a + 1
|
|
local c = a + SAMPLES
|
|
local d = c + 1
|
|
|
|
for _, index in ipairs({ a, d, b, a, c, d }) do
|
|
indices[#indices + 1] = index
|
|
end
|
|
end
|
|
end
|
|
return meshNew(positions, nil, nil, indices)
|
|
end
|
|
|
|
|
|
fontSelect(font)
|
|
overlaySetResolution(720, 480)
|
|
sceneEnable(true)
|
|
cameraSet(camera)
|
|
nodeSetPosition(camera, 0, 30, 0)
|
|
nodeLookAt(camera, 60, 6, 80)
|
|
nodeLookAt(sun, -1, -2, -0.5)
|
|
materialSetColor(ground, 110, 160, 90)
|
|
nodeSetMesh(chunked, meshHeightmap("testScripts/ridges.png", SIZE, HEIGHT, SIZE), ground)
|
|
nodeSetMesh(whole, twinMesh(), ground)
|
|
nodeSetVisible(whole, false)
|
|
do
|
|
local got = terrainGetHeight(chunked, -SIZE / 2 + 10, -SIZE / 2 + 20)
|
|
|
|
check("terrainGetHeight reads the samples", (got ~= nil) and (math.abs(got - sample(10, 20) * HEIGHT) < 0.001), tostring(got) .. " against " .. (sample(10, 20) * HEIGHT))
|
|
end
|
|
|
|
|
|
function onOverlayUpdate()
|
|
local total, drawn = sceneGetStats()
|
|
|
|
frames = frames + 1
|
|
overlayClear()
|
|
if frames == 3 then
|
|
check("16 chunk draws", total == 16, tostring(total))
|
|
check("chunks out of view are culled", (drawn > 0) and (drawn < total), drawn .. " of " .. total)
|
|
singeScreenshot("chunked")
|
|
nodeSetVisible(chunked, false)
|
|
nodeSetVisible(whole, true)
|
|
elseif frames == 6 then
|
|
check("the twin is one draw", total == 1, tostring(total))
|
|
singeScreenshot("whole")
|
|
elseif frames == LAST then
|
|
debugPrint(string.format("CHUNKS RESULT failures=%d", failures))
|
|
singeQuit()
|
|
end
|
|
return OVERLAY_UPDATED
|
|
end
|