view.lua 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. local view = lib.object.create()
  2. function view:init()
  3. self.x = 0
  4. self.y = 0
  5. self.width = 960
  6. self.height = 720
  7. self.xmin = -math.huge
  8. self.ymin = -math.huge
  9. self.xmax = math.huge--self.width
  10. self.ymax = math.huge--self.height
  11. self.frame = {
  12. x = 0,
  13. y = 0,
  14. width = g.getWidth(),
  15. height = g.getHeight()
  16. }
  17. self.viewId = 0
  18. self.draws = {}
  19. self.guis = {}
  20. self.effects = {}
  21. self.toRemove = {}
  22. self.target = nil
  23. self.prevx = 0
  24. self.prevy = 0
  25. self.prevscale = 1
  26. self.shake = 0
  27. end
  28. function view:bind()
  29. self:resize()
  30. self.draw = lib.rx.Subject.create()
  31. self.hud = lib.rx.Subject.create()
  32. self.draw.onNext = f.self(self.doDraw, self)
  33. self.hud.onNext = f.self(self.doHud, self)
  34. return {
  35. love.resize
  36. :subscribe(function()
  37. self:resize()
  38. end),
  39. love.update
  40. :subscribe(function()
  41. self:update()
  42. end),
  43. love.draw
  44. :subscribe(function()
  45. self.draw:onNext()
  46. self.hud:onNext()
  47. end)
  48. }
  49. end
  50. function view:update()
  51. self.prevx = self.x
  52. self.prevy = self.y
  53. self.prevscale = self.scale
  54. self:contain()
  55. self.shake = math.max(self.shake - lib.tick.rate, 0)
  56. end
  57. function view:doDraw()
  58. local w, h = g.getDimensions()
  59. local subject = self.draw
  60. local source, target = self.sourceCanvas, self.targetCanvas
  61. self:worldPush()
  62. g.setCanvas(source)
  63. for i = #subject.observers, 1, -1 do
  64. if subject.observers[i] then
  65. subject.observers[i].depth = subject.observers[i]:onNext() or 0
  66. if subject.observers[i] then
  67. subject.observers[i].depthNudge = subject.observers[i].depthNudge or love.math.random() * .01
  68. end
  69. end
  70. end
  71. table.sort(subject.observers, function(a, b)
  72. return (a.depth or 0) + (a.depthNudge or 0) < (b.depth or 0) + (b.depthNudge or 0)
  73. end)
  74. g.setCanvas()
  75. g.pop()
  76. g.setCanvas()
  77. g.white()
  78. g.draw(source)
  79. --[[local fr = self.frame
  80. local fx, fy, fw, fh = fr.x, fr.y, fr.width, fr.height
  81. g.setColor(0, 0, 0)
  82. g.rectangle('fill', 0, 0, w, fy)
  83. g.rectangle('fill', 0, 0, fx, h)
  84. g.rectangle('fill', 0, fy + fh, w, h - (fy + fh))
  85. g.rectangle('fill', fx + fw, 0, w - (fx + fw), h)]]
  86. end
  87. function view:doHud()
  88. local w, h = g.getDimensions()
  89. local subject = self.hud
  90. local source, target = self.sourceCanvas, self.targetCanvas
  91. table.sort(subject.observers, function(a, b)
  92. return (a.depth or 0) < (b.depth or 0)
  93. end)
  94. for i = #subject.observers, 1, -1 do
  95. if subject.observers[i] then
  96. subject.observers[i].depth = subject.observers[i]:onNext() or 0
  97. end
  98. end
  99. end
  100. function view:resize()
  101. local w, h = g.getDimensions()
  102. local ratio = w / h
  103. self.frame.x, self.frame.y, self.frame.width, self.frame.height = 0, 0, self.width, self.height
  104. if true or (self.width / self.height) > (w / h) then
  105. self.scale = w / self.width
  106. local margin = math.max(util.round(((h - w * (self.height / self.width)) / 2)), 0)
  107. self.frame.y = margin
  108. self.frame.height = h - 2 * margin
  109. self.frame.width = w
  110. else
  111. self.scale = h / self.height
  112. local margin = math.max(util.round(((w - h * (self.width / self.height)) / 2)), 0)
  113. self.frame.x = margin
  114. self.frame.width = w - 2 * margin
  115. self.frame.height = h
  116. end
  117. self.sourceCanvas = g.newCanvas(w, h)
  118. self.targetCanvas = g.newCanvas(w, h)
  119. end
  120. function view:register(x, action)
  121. x.viewId = self.viewId
  122. action = action or 'draw'
  123. if action == 'draw' then
  124. table.insert(self.draws, x)
  125. x.depth = x.depth or 0
  126. elseif action == 'gui' then
  127. table.insert(self.guis, x)
  128. elseif action == 'effect' then
  129. table.insert(self.effects, x)
  130. end
  131. self.viewId = self.viewId + 1
  132. end
  133. function view:unregister(x)
  134. table.insert(self.toRemove, x)
  135. end
  136. function view:convertZ(z)
  137. return (.8 * z) ^ (1 + (.0008 * z))
  138. end
  139. function view:three(x, y, z)
  140. local sx, sy = util.lerp(self.prevx, self.x, lib.tick.accum / lib.tick.rate), util.lerp(self.prevy, self.y, lib.tick.accum / lib.tick.rate)
  141. z = self:convertZ(z)
  142. return x - (z * ((sx + self.width / 2 - x) / 500)), y - (z * ((sy + self.height / 2 - y) / 500))
  143. end
  144. function view:threeDepth(x, y, z)
  145. return util.clamp(util.distance(x, y, self.x + self.width / 2, self.y + self.height / 2) * self.scale - 1000 - z, -4096, -16)
  146. end
  147. function view:contain()
  148. --self.x = util.clamp(self.x, self.xmin, self.xmax - self.width)
  149. --self.y = util.clamp(self.y, self.ymin, self.ymax - self.height)
  150. end
  151. function view:worldPoint(x, y)
  152. x = util.round(((x - self.frame.x) / self.scale) + self.x)
  153. if y then y = util.round(((y - self.frame.y) / self.scale) + self.y) end
  154. return x, y
  155. end
  156. function view:screenPoint(x, y)
  157. local vx, vy = util.lerp(self.prevx, self.x, lib.tick.accum / lib.tick.rate), util.lerp(self.prevy, self.y, lib.tick.accum / lib.tick.rate)
  158. x = (x - vx) * self.scale
  159. if y then y = (y - vy) * self.scale end
  160. return x, y
  161. end
  162. function view:worldMouseX()
  163. return util.round(((love.mouse.getX() - self.frame.x) / self.scale) + self.x)
  164. end
  165. function view:worldMouseY()
  166. return util.round(((love.mouse.getY() - self.frame.y) / self.scale) + self.y)
  167. end
  168. function view:frameMouseX()
  169. return love.mouse.getX() - self.frame.x
  170. end
  171. function view:frameMouseY()
  172. return love.mouse.getY() - self.frame.y
  173. end
  174. function view:screenshake(amount)
  175. self.shake = math.max(self.shake, amount)
  176. end
  177. function view:worldPush()
  178. local x, y, s = unpack(util.interpolateTable({self.prevx, self.prevy, self.prevscale}, {self.x, self.y, self.scale}, lib.tick.accum / lib.tick.rate))
  179. if self.shake > .01 then
  180. local shakex = -1 + love.math.random() * 2
  181. local shakey = -1 + love.math.random() * 2
  182. x = x + (shakex * 5)
  183. y = y + (shakey * 5)
  184. end
  185. g.push()
  186. g.translate(self.frame.x, self.frame.y)
  187. g.scale(s)
  188. g.translate(-x, -y)
  189. end
  190. function view:guiPush()
  191. g.push()
  192. g.translate(self.self.frame.x, self.self.frame.y)
  193. end
  194. return view