cam11.lua 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. -- Camera library using the new Transform features in love2d 11.0+
  2. --
  3. -- Copyright © 2019 Pedro Gimeno Fortea
  4. --
  5. -- You can do whatever you want with this software, under the sole condition
  6. -- that this notice and any copyright notices are preserved. It is offered
  7. -- with no warrany, not even implied.
  8. -- Cache some functions into locals
  9. local newTransform = love.math.newTransform
  10. local replaceTransform, applyTransform, push, pop, getWidth, getHeight
  11. local getScissor, intersectScissor, setScissor
  12. local xfSetXf, xfGetMatrix
  13. do
  14. local lg = love.graphics
  15. replaceTransform = lg.replaceTransform
  16. applyTransform = lg.applyTransform
  17. push = lg.push
  18. pop = lg.pop
  19. getWidth = lg.getWidth
  20. getHeight = lg.getHeight
  21. getScissor = lg.getScissor
  22. intersectScissor = lg.intersectScissor
  23. setScissor = lg.setScissor
  24. local Xf = debug.getregistry().Transform
  25. xfSetXf = Xf.setTransformation
  26. xfGetMatrix = Xf.getMatrix
  27. end
  28. local Camera = {}
  29. local CameraClassMT = {__call = function (c, ...) return c.new(...) end}
  30. local CameraInstanceMT = {__index = Camera}
  31. local function lazyUpdateXf(self)
  32. if self.dirty then
  33. self.dirty = false
  34. local vp = self.vp
  35. self.matdirty = true
  36. self.invmatdirty = true
  37. return xfSetXf(self.xf,
  38. vp[1] + (vp[3] or getWidth()) * vp[5],
  39. vp[2] + (vp[4] or getHeight()) * vp[6],
  40. self.angle, self.zoom, self.zoom, self.x, self.y)
  41. end
  42. end
  43. local function lazyUpdateMat(self)
  44. lazyUpdateXf(self)
  45. if self.matdirty then
  46. self.matdirty = false
  47. local mat = self.mat
  48. local t
  49. mat[1], mat[2], t, mat[5], mat[3], mat[4], t, mat[6] = xfGetMatrix(self.xf)
  50. end
  51. end
  52. local function lazyUpdateInvMat(self)
  53. lazyUpdateMat(self)
  54. if self.invmatdirty then
  55. self.invmatdirty = false
  56. local imat = self.invmat
  57. local mat = self.mat
  58. local a11, a12, a21, a22 = mat[1], mat[2], mat[3], mat[4]
  59. local det = a11*a22 - a12*a21
  60. imat[1], imat[2], imat[3], imat[4] = a22/det, a12/-det, a21/-det, a11/det
  61. imat[5] = mat[5]
  62. imat[6] = mat[6]
  63. end
  64. end
  65. function Camera:setDirty(dirty)
  66. self.dirty = dirty ~= false and true or false
  67. end
  68. function Camera:attach(clip)
  69. lazyUpdateXf(self)
  70. push()
  71. local vp = self.vp
  72. if clip or clip == nil and (vp[1] ~= 0 or vp[2] ~= 0 or vp[3] or vp[4]) then
  73. local x, y, w, h = getScissor()
  74. local scissor = self.scissor
  75. scissor[1] = x
  76. scissor[2] = y
  77. scissor[3] = w
  78. scissor[4] = h
  79. intersectScissor(vp[1], vp[2], vp[3] or getWidth(), vp[4] or getHeight())
  80. end
  81. return replaceTransform(self.xf)
  82. end
  83. function Camera:detach()
  84. local scissor = self.scissor
  85. if scissor[1] ~= false then
  86. setScissor(scissor[1], scissor[2], scissor[3], scissor[4])
  87. scissor[1] = false
  88. end
  89. return pop()
  90. end
  91. function Camera:setPos(x, y)
  92. self.dirty = self.x ~= x or self.y ~= y or self.dirty
  93. self.x = x
  94. self.y = y
  95. end
  96. function Camera:setZoom(zoom)
  97. self.dirty = self.zoom ~= zoom or self.dirty
  98. self.zoom = zoom
  99. end
  100. function Camera:setAngle(angle)
  101. self.dirty = self.angle ~= angle or self.dirty
  102. self.angle = angle
  103. end
  104. function Camera:setViewport(x, y, w, h, cx, cy)
  105. x, y = x or 0, y or 0
  106. w, h = w or false, h or false
  107. cx, cy = cx or 0.5, cy or 0.5
  108. if x ~= self.vp[1] or y ~= self.vp[2] or w ~= self.vp[3] or h ~= self.vp[4]
  109. or cx ~= self.vp[5] or cy ~= self.vp[6]
  110. then
  111. self.dirty = true
  112. end
  113. local vp = self.vp
  114. vp[1] = x
  115. vp[2] = y
  116. vp[3] = w
  117. vp[4] = h
  118. vp[5] = cx
  119. vp[6] = cy
  120. end
  121. function Camera:toScreen(x, y)
  122. lazyUpdateMat(self)
  123. local mat = self.mat
  124. return mat[1] * x + mat[2] * y + mat[5], mat[3] * x + mat[4] * y + mat[6]
  125. end
  126. function Camera:toWorld(x, y)
  127. lazyUpdateInvMat(self)
  128. local imat = self.invmat
  129. x = x - imat[5]
  130. y = y - imat[6]
  131. return imat[1] * x + imat[2] * y, imat[3] * x + imat[4] * y
  132. end
  133. function Camera:getTransform()
  134. lazyUpdateXf(self)
  135. return self.xf
  136. end
  137. function Camera:getPos()
  138. return self.x, self.y
  139. end
  140. function Camera:getX()
  141. return self.x
  142. end
  143. function Camera:getY()
  144. return self.y
  145. end
  146. function Camera:getZoom()
  147. return self.zoom
  148. end
  149. function Camera:getAngle()
  150. return self.angle
  151. end
  152. function Camera:getViewport()
  153. local vp = self.vp
  154. return vp[1], vp[2], vp[3], vp[4], vp[5], vp[6]
  155. end
  156. function Camera:getVPTopLeft()
  157. local vp = self.vp
  158. return vp[1], vp[2]
  159. end
  160. function Camera:getVPBottomRight()
  161. local vp = self.vp
  162. return vp[1] + (vp[3] or getWidth()), vp[2] + (vp[4] or getHeight())
  163. end
  164. function Camera:getVPFocusPoint()
  165. local vp = self.vp
  166. return vp[1] + (vp[3] or getWidth()) * vp[5],
  167. vp[2] + (vp[4] or getHeight()) * vp[6]
  168. end
  169. function Camera.new(x, y, zoom, angle, vpx, vpy, vpw, vph, cx, cy)
  170. vpx, vpy = vpx or 0, vpy or 0
  171. vpw, vph = vpw or false, vph or false
  172. cx, cy = cx or 0.5, cy or 0.5
  173. local self = {
  174. x = x or 0;
  175. y = y or 0;
  176. zoom = zoom or 1;
  177. angle = angle or 0;
  178. vp = {vpx, vpy, vpw, vph, cx, cy};
  179. xf = newTransform();
  180. dirty = true;
  181. matdirty = true;
  182. invmatdirty = true;
  183. scissor = {false,false,false,false};
  184. mat = {0, 0, 0, 0, 0, 0};
  185. invmat = {0, 0, 0, 0, 0, 0};
  186. }
  187. return setmetatable(self, CameraInstanceMT)
  188. end
  189. return setmetatable(Camera, CameraClassMT)