view.lua 5.8 KB

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