mirror of
https://github.com/DramaticShape/DramaticShapeVoxelMod.git
synced 2026-08-12 17:50:51 +02:00
62 lines
1.9 KiB
Lua
62 lines
1.9 KiB
Lua
-- Voxel world mode: the cooperative build budget.
|
|
--
|
|
-- Mesh building runs inside a plain coroutine that ChunkMesher pumps for
|
|
-- a few milliseconds a frame (there is no worker thread: LOVE's graphics
|
|
-- objects are main-thread only, and the build is pure Lua that slices
|
|
-- cleanly). The long loops in Structures and ChunkMesher call tick() as
|
|
-- they go; when the frame's slice is spent, tick() suspends the build
|
|
-- coroutine and the frame carries on rendering whatever is already
|
|
-- cached.
|
|
--
|
|
-- tick() is deliberately safe to call from ANY context: outside the pump
|
|
-- (headless tests, the pure geometry API, a driver poking a build
|
|
-- function directly) it recognises it is not inside the build coroutine
|
|
-- and does nothing, so synchronous callers keep their synchronous
|
|
-- behavior.
|
|
|
|
local B = { n = 0 }
|
|
|
|
local clock = (love and love.timer and love.timer.getTime) or os.clock
|
|
|
|
local deadline = math.huge
|
|
local buildCo = nil
|
|
|
|
-- Enter/leave a pumped slice. `co` is the coroutine being resumed, so
|
|
-- tick() can tell the build apart from any other coroutine the engine
|
|
-- happens to be running (drivers are coroutines too).
|
|
function B.begin(co, seconds)
|
|
buildCo = co
|
|
deadline = clock() + seconds
|
|
end
|
|
|
|
function B.finish()
|
|
buildCo = nil
|
|
deadline = math.huge
|
|
end
|
|
|
|
function B.expired()
|
|
return clock() > deadline
|
|
end
|
|
|
|
-- Cheap enough to sprinkle through inner loops: one modulo most calls,
|
|
-- a clock read every 32nd.
|
|
function B.tick()
|
|
local n = B.n + 1
|
|
B.n = n
|
|
if n % 32 ~= 0 then return end
|
|
if buildCo and coroutine.running() == buildCo and clock() > deadline then
|
|
coroutine.yield("budget")
|
|
end
|
|
end
|
|
|
|
-- Like tick() but consults the clock every call -- for coarse loops
|
|
-- whose single iteration already costs milliseconds (mesh upload
|
|
-- slices), where tick()'s 1-in-32 sampling would never fire.
|
|
function B.check()
|
|
if buildCo and coroutine.running() == buildCo and clock() > deadline then
|
|
coroutine.yield("budget")
|
|
end
|
|
end
|
|
|
|
return B
|