summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorthe lemons <citrons@mondecitronne.com>2023-03-25 04:51:36 -0500
committerthe lemons <citrons@mondecitronne.com>2023-03-25 04:51:36 -0500
commitf9c0d381e1f7ec8eb0e93a296b1dcd32f9c4d57e (patch)
tree0f27b6ff4773889887469c31487b588d7c6193c8
parent1ee0d588a6840d96194381e252b37d52d77a2f14 (diff)
event loop
-rw-r--r--evloop.lua96
1 files changed, 96 insertions, 0 deletions
diff --git a/evloop.lua b/evloop.lua
new file mode 100644
index 0000000..c72f920
--- /dev/null
+++ b/evloop.lua
@@ -0,0 +1,96 @@
+local M = {}
+M.__index = M
+
+local queue = {}
+
+local function resume_task(task, e)
+ if coroutine.status(task.co) == "dead" then
+ return false
+ end
+
+ if task.filter then
+ for _, f in ipairs(task.filter) do
+ if f == e[1] then
+ goto resume
+ end
+ end
+ return true
+ end
+
+ ::resume::
+ local ok, ret = coroutine.resume(task.co, e)
+ if not ok then
+ io.stderr:write(debug.traceback(task.co, ret)..'\n\n')
+ error "error in event loop"
+ end
+ task.filter = ret
+ return coroutine.status(task.co) ~= "dead"
+end
+
+local function create_task(fn)
+ local task = {}
+ task.co = coroutine.create(fn)
+ return task
+end
+
+function M.poll(...)
+ local filter = {...}
+ return unpack(coroutine.yield(#filter > 0 and filter))
+end
+
+function M.sleep(secs)
+ local t = 0
+ while t < secs do
+ local e, dt = M.poll "update"
+ t = t + dt
+ end
+ return t
+end
+
+function M.queue(...)
+ table.insert(queue, {...})
+end
+
+function M.mainloop(start)
+ local main = create_task(function()
+ start()
+ end)
+
+ return function()
+ love.event.pump()
+ local es = love.event.poll()
+ while true do
+ local e = {es()}
+ if not e[1] then break end
+ if e[1] == "quit" then
+ if not love.quit or not love.quit() then
+ return e[2] or 0
+ end
+ end
+ if love.handlers[e[1]] then
+ love.handlers[e[1]](unpack(e, 2))
+ end
+ table.insert(queue, e)
+ end
+
+ local q = queue
+ queue = {}
+ for i, e in ipairs(q) do
+ if not resume_task(main, e) then return end
+ end
+
+ local dt = love.timer.step()
+ if not resume_task(main, {"update", dt}) then return end
+
+ if love.graphics and love.graphics.isActive() then
+ love.graphics.origin()
+ love.graphics.clear(love.graphics.getBackgroundColor())
+ if not resume_task(main, {"draw", dt}) then return end
+ love.graphics.present()
+ end
+
+ love.timer.sleep(0.001)
+ end
+end
+
+return M