main.lua 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. -- Written by Pedro Gimeno.
  2. -- This work is in the public domain if your jurisdiction allows it.
  3. -- If not, the author allows anyone to do anything with this work, to the
  4. -- maximum extent allowed by law.
  5. if not love.graphics.isActive then
  6. function love.graphics.isActive()
  7. return true
  8. end
  9. end
  10. local fbcanvas
  11. local script
  12. local started = false
  13. local corosc -- coroutine for the script
  14. local huge = math.huge
  15. local wait = {}
  16. local peek = {}
  17. local curEventName
  18. local curEventData = {0}
  19. local lg = love.graphics
  20. local timerTime = huge
  21. local sleepTime = huge
  22. local saveCanvas = false
  23. local function pack_n(...)
  24. curEventData[1] = select('#', ...)
  25. for i = 1, curEventData[1] do
  26. curEventData[i + 1] = (select(i, ...))
  27. end
  28. end
  29. local unpack_n
  30. do
  31. local function unpack_count(x, n)
  32. if n == x[1] + 1 then
  33. return
  34. end
  35. n = n + 1
  36. return x[n], unpack_count(x, n)
  37. end
  38. function unpack_n(a)
  39. return unpack_count(a, 1)
  40. end
  41. end
  42. local function nullFunc() end
  43. local function handleEvent(event, ...)
  44. if event == "update" then
  45. timerTime = timerTime - ...
  46. sleepTime = sleepTime - ...
  47. if sleepTime <= 0 then
  48. sleepTime = huge
  49. curEventName = "sleep"
  50. assert(coroutine.resume(corosc))
  51. end
  52. if timerTime <= 0 then
  53. timerTime = huge
  54. handleEvent("timer")
  55. end
  56. end
  57. curEventName = event
  58. pack_n(...)
  59. if coroutine.status(corosc) == "suspended" then
  60. return select(2, assert(coroutine.resume(corosc)))
  61. end
  62. end
  63. -- Handlers not in love.handlers
  64. function love.load(...)
  65. handleEvent("load", ...)
  66. -- Hack: love.event.pump() can't work with a canvas active.
  67. -- The first time it's executed is immediately after this.
  68. if love.graphics.isActive() then
  69. saveCanvas = love.graphics.getCanvas()
  70. love.graphics.setCanvas()
  71. else
  72. saveCanvas = nil -- shouldn't be false
  73. end
  74. end
  75. do
  76. local savePump = love.event.pump
  77. -- Replace love.event.pump to restore the canvas
  78. local function afterPump(...)
  79. if saveCanvas ~= false then
  80. if love.graphics.isActive() then
  81. love.graphics.setCanvas(saveCanvas)
  82. saveCanvas = false -- This distinguishes pump() calls from love.run
  83. -- from pump() calls from user code.
  84. end
  85. -- if we saved it, it means we're in a new frame
  86. handleEvent("newframe")
  87. end
  88. return ...
  89. end
  90. function love.event.pump(...)
  91. return afterPump(savePump(...))
  92. end
  93. -- Replace love.graphics.setMode to (re)create the canvas and activate it
  94. local origSetMode = love.window.setMode
  95. function love.window.setMode(...)
  96. if fbcanvas then
  97. if love.graphics.isActive() then
  98. love.graphics.setCanvas()
  99. end
  100. fbcanvas:release()
  101. end
  102. origSetMode(...)
  103. fbcanvas = love.graphics.newCanvas()
  104. _G.fbcanvas = fbcanvas
  105. love.graphics.clear(0, 0, 0, 255)
  106. love.graphics.setCanvas(fbcanvas)
  107. end
  108. local origClear
  109. function love.update(...)
  110. handleEvent("update", ...)
  111. if love.graphics.isActive() then -- love.draw isn't called otherwise
  112. -- To prevent the internal call to love.graphics.clear from clearing the
  113. -- framebuffer, we patch it here to do nothing.
  114. origClear = love.graphics.clear
  115. love.graphics.clear = nullFunc
  116. love.graphics.push()
  117. end
  118. end
  119. function love.draw(...)
  120. love.graphics.clear = origClear
  121. saveCanvas = love.graphics.getCanvas()
  122. love.graphics.setCanvas()
  123. local r,g,b,a = love.graphics.getColor()
  124. local rgbmode, alphamode = love.graphics.getBlendMode()
  125. love.graphics.setColor(255, 255, 255, 255)
  126. love.graphics.setBlendMode("replace", "premultiplied")
  127. love.graphics.draw(fbcanvas)
  128. love.graphics.setBlendMode(rgbmode, alphamode)
  129. love.graphics.setColor(r, g, b, a)
  130. love.graphics.pop()
  131. -- Notify about the event. Unfortunately we have to restore the canvas;
  132. -- otherwise stuff drawn by user code during this event will be lost.
  133. love.graphics.setCanvas(saveCanvas)
  134. handleEvent("draw")
  135. saveCanvas = love.graphics.getCanvas()
  136. love.graphics.setCanvas() -- for present/pump
  137. end
  138. end
  139. local function waitEvent(event, ...)
  140. coroutine.yield(...)
  141. while curEventName ~= event do
  142. coroutine.yield()
  143. end
  144. return unpack_n(curEventData)
  145. end
  146. local function peekEvent(event)
  147. if event == curEventName then
  148. return true, unpack_n(curEventData)
  149. end
  150. end
  151. local function poll(...)
  152. coroutine.yield(...)
  153. end
  154. local function quit()
  155. love.event.quit()
  156. waitEvent("quit")
  157. coroutine.yield()
  158. end
  159. local function getEvent(...)
  160. poll(...)
  161. return curEventName, unpack_n(curEventData)
  162. end
  163. local function startTimer(time)
  164. timerTime = time + 0
  165. end
  166. local function pause(time, ...)
  167. if time == nil then
  168. time = huge
  169. end
  170. sleepTime = time + 0
  171. poll(...)
  172. repeat
  173. local ret, k = peekEvent("keypressed")
  174. if k == "escape" then
  175. quit()
  176. end
  177. if ret then
  178. break
  179. end
  180. if peekEvent("mousepressed") then
  181. break
  182. end
  183. if curEventName =="sleep" then
  184. break
  185. end
  186. poll()
  187. until false
  188. sleepTime = huge
  189. end
  190. local function sleep(time)
  191. sleepTime = time + 0
  192. waitEvent("sleep")
  193. end
  194. -- Assign the default love2d handlers
  195. for k in next, love.handlers do
  196. love[k] = function(...)
  197. return handleEvent(k, ...)
  198. end
  199. wait[k] = function () return waitEvent(k) end
  200. peek[k] = function () return peekEvent(k) end
  201. end
  202. -- Special events
  203. wait.load = function () return waitEvent("load") end
  204. peek.load = function () return peekEvent("load") end
  205. wait.update = function () return waitEvent("update") end
  206. peek.update = function () return peekEvent("update") end
  207. wait.draw = function () return waitEvent("draw") end
  208. peek.draw = function () return peekEvent("draw") end
  209. wait.newframe = function () return waitEvent("newframe") end
  210. peek.newframe = function () return peekEvent("newframe") end
  211. wait.timer = function () return waitEvent("timer") end
  212. peek.timer = function () return peekEvent("timer") end
  213. -- Special functions that aren't events
  214. wait.event = waitEvent
  215. peek.event = peekEvent
  216. -- Set the API globals
  217. _G.fbcanvas = fbcanvas
  218. _G.wait = wait
  219. _G.peek = peek
  220. _G.sleep = sleep
  221. _G.pause = pause
  222. _G.event = getEvent
  223. _G.poll = poll
  224. _G.timer = startTimer
  225. _G.quit = quit
  226. -- Load the script
  227. do
  228. local scriptName = arg[2] or 'mycode.lua'
  229. script = love.filesystem.load(arg[love.filesystem.isFused() and 1 or 2] or 'mycode.lua')
  230. if script == nil then
  231. love.window.showMessageBox("Error: Script not found",
  232. "Script not found: " .. scriptName, "error", false)
  233. end
  234. end
  235. -- Prepare the coroutine and start it
  236. corosc = coroutine.create(script)
  237. assert(coroutine.resume(corosc))