view.lua 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. local View = class()
  2. local g = love.graphics
  3. function View:init()
  4. --[[love.window.setMode(ctx.options.windowWidth, ctx.options.windowHeight, {
  5. fullscreen = ctx.options.fullscreen,
  6. fullscreentype = ctx.options.borderless and 'desktop' or 'normal',
  7. vsync = ctx.options.vsync
  8. })]]
  9. self.x = 0
  10. self.y = 0
  11. self.width = 800
  12. self.height = 600
  13. self.xmin = 0
  14. self.ymin = 0
  15. self.xmax = self.width
  16. self.ymax = self.height
  17. self.frame = {}
  18. self.frame.x = 0
  19. self.frame.y = 0
  20. self.frame.width = love.window.getWidth()
  21. self.frame.height = love.window.getHeight()
  22. self.draws = {}
  23. self.guis = {}
  24. self.effects = {}
  25. self.target = nil
  26. self:resize()
  27. self.prevx = 0
  28. self.prevy = 0
  29. self.prevscale = self.scale
  30. self.shake = 0
  31. end
  32. function View:update()
  33. self.prevx = self.x
  34. self.prevy = self.y
  35. self.prevscale = self.scale
  36. self:follow()
  37. self:contain()
  38. self.shake = math.lerp(self.shake, 0, 8 * tickRate)
  39. table.sort(self.draws, function(a, b)
  40. return a.depth > b.depth
  41. end)
  42. end
  43. function View:draw()
  44. local w, h = g.getDimensions()
  45. self:worldPush()
  46. self.sourceCanvas:clear()
  47. self.targetCanvas:clear()
  48. self.sourceCanvas:renderTo(function()
  49. for i = 1, #self.draws do self.draws[i]:draw() end
  50. end)
  51. g.pop()
  52. for i = 1, #self.effects do
  53. g.setColor(255, 255, 255)
  54. if self.effects[i].applyEffect then
  55. self.effects[i]:applyEffect(self.sourceCanvas, self.targetCanvas)
  56. else
  57. g.setShader(self.effects[i].shader)
  58. g.setCanvas(self.targetCanvas)
  59. g.draw(self.sourceCanvas)
  60. end
  61. g.setCanvas()
  62. g.setShader()
  63. self.sourceCanvas, self.targetCanvas = self.targetCanvas, self.sourceCanvas
  64. end
  65. g.setColor(255, 255, 255)
  66. g.draw(self.sourceCanvas)
  67. g.push()
  68. g.translate(self.frame.x, self.frame.y)
  69. for i = 1, #self.guis do self.guis[i]:gui() end
  70. g.pop()
  71. g.setColor(0, 0, 0, 255)
  72. g.rectangle('fill', 0, 0, w, self.frame.y)
  73. g.rectangle('fill', 0, 0, self.frame.x, h)
  74. g.rectangle('fill', 0, self.frame.y + self.frame.height, w, h - (self.frame.y + self.frame.height))
  75. g.rectangle('fill', self.frame.x + self.frame.width, 0, w - (self.frame.x + self.frame.width), h)
  76. end
  77. function View:resize()
  78. local w, h = love.graphics.getDimensions()
  79. self.frame.x, self.frame.y, self.frame.width, self.frame.height = 0, 0, self.width, self.height
  80. if (self.width / self.height) > (w / h) then
  81. self.scale = w / self.width
  82. local margin = math.max(math.round(((h - w * (self.height / self.width)) / 2)), 0)
  83. self.frame.y = margin
  84. self.frame.height = h - 2 * margin
  85. self.frame.width = w
  86. else
  87. self.scale = h / self.height
  88. local margin = math.max(math.round(((w - h * (self.width / self.height)) / 2)), 0)
  89. self.frame.x = margin
  90. self.frame.width = w - 2 * margin
  91. self.frame.height = h
  92. end
  93. self.sourceCanvas = love.graphics.newCanvas(w, h)
  94. self.targetCanvas = love.graphics.newCanvas(w, h)
  95. Typo.resize()
  96. ctx.event:emit('view.resize')
  97. end
  98. function View:register(x, action)
  99. action = action or 'draw'
  100. if action == 'draw' then
  101. table.insert(self.draws, x)
  102. x.depth = x.depth or 0
  103. elseif action == 'gui' then
  104. table.insert(self.guis, x)
  105. elseif action == 'effect' then
  106. table.insert(self.effects, x)
  107. end
  108. end
  109. function View:unregister(x)
  110. if x.draw then
  111. for i = 1, #self.draws do
  112. if self.draws[i] == x then table.remove(self.draws, i) return end
  113. end
  114. end
  115. if x.gui then
  116. for i = 1, #self.guis do
  117. if self.guis[i] == x then table.remove(self.guis, i) return end
  118. end
  119. end
  120. for i = 1, #self.effects do
  121. if self.effects[i] == x then table.remove(self.effects, i) return end
  122. end
  123. end
  124. function View:convertZ(z)
  125. return (.8 * z) ^ (1 + (.0008 * z))
  126. end
  127. function View:three(x, y, z)
  128. local sx, sy = math.lerp(self.prevx, self.x, tickDelta / tickRate), math.lerp(self.prevy, self.y, tickDelta / tickRate)
  129. z = self:convertZ(z)
  130. return x - (z * ((sx + self.width / 2 - x) / 500)), y - (z * ((sy + self.height / 2 - y) / 500))
  131. end
  132. function View:threeDepth(x, y, z)
  133. return math.clamp(math.distance(x, y, self.x + self.width / 2, self.y + self.height / 2) * self.scale - 1000 - z, -4096, -16)
  134. end
  135. function View:contain()
  136. self.x = math.clamp(self.x, 0, self.xmax - self.width)
  137. self.y = math.clamp(self.y, 0, self.ymax - self.height)
  138. end
  139. function View:follow()
  140. if not self.target then return end
  141. local dis, dir = math.vector(self.target.x, self.target.y, self:worldMouseX(), self:worldMouseY())
  142. local margin = 0.8
  143. dis = dis / 2
  144. self.x = math.lerp(self.x, self.target.x + math.dx(dis, dir) - (self.width / 2), math.min(25 * tickRate, 1))
  145. self.y = math.lerp(self.y, self.target.y + math.dy(dis, dir) - (self.height / 2), math.min(25 * tickRate, 1))
  146. self.x = math.clamp(self.x, self.target.x - (self.width * margin), self.target.x + (self.width * margin) - self.width)
  147. self.y = math.clamp(self.y, self.target.y - (self.height * margin), self.target.y + (self.height * margin) - self.height)
  148. end
  149. function View:worldPoint(x, y)
  150. x = math.round(((x - self.frame.x) / self.scale) + self.x)
  151. if y then y = math.round(((y - self.frame.y) / self.scale) + self.y) end
  152. return x, y
  153. end
  154. function View:worldMouseX()
  155. return math.round(((love.mouse.getX() - self.frame.x) / self.scale) + self.x)
  156. end
  157. function View:worldMouseY()
  158. return math.round(((love.mouse.getY() - self.frame.y) / self.scale) + self.y)
  159. end
  160. function View:frameMouseX()
  161. return love.mouse.getX() - self.frame.x
  162. end
  163. function View:frameMouseY()
  164. return love.mouse.getY() - self.frame.y
  165. end
  166. function View:screenshake(amount)
  167. if self.shake > amount then self.shake = self.shake + (amount / 2) end
  168. self.shake = amount
  169. end
  170. function View:worldPush()
  171. local x, y, s = unpack(table.interpolate({self.prevx, self.prevy, self.prevscale}, {self.x, self.y, self.scale}, tickDelta / tickRate))
  172. local shakex = 1 - (2 * love.math.noise(self.shake + x + tickDelta))
  173. local shakey = 1 - (2 * love.math.noise(self.shake + y + tickDelta))
  174. x = x + (shakex * self.shake)
  175. y = y + (shakey * self.shake)
  176. g.push()
  177. g.translate(self.frame.x, self.frame.y)
  178. g.scale(s)
  179. g.translate(-x, -y)
  180. end
  181. return View