xform.lua 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. Xform = {}
  2. Xform.__index = Xform
  3. local function index_of(list, o)
  4. for i,v in pairs(list) do
  5. if v == o then
  6. return i
  7. end
  8. end
  9. end
  10. function remove(list, o)
  11. table.remove(list, index_of(list, o))
  12. return list
  13. end
  14. local function append(list, o)
  15. list[#list + 1] = o
  16. end
  17. local function copy_v3(s, t)
  18. t.x = s.x
  19. t.y = s.y
  20. t.z = s.z
  21. return t
  22. end
  23. local function copy_quat(s, t)
  24. t.x = s.x
  25. t.y = s.y
  26. t.z = s.z
  27. t.w = s.w
  28. return t
  29. end
  30. local function is_xform(o)
  31. return o['__members'] and o.__members.type == "Xform"
  32. end
  33. local function update(xform)
  34. xform.mat4:set(xform.position, xform.scale, xform.rotation)
  35. if xform.parent then
  36. xform.mat4:set(xform.parent.mat4 * xform.mat4)
  37. end
  38. for i, child in ipairs(xform.__members.children) do
  39. update(child)
  40. end
  41. end
  42. local function mount(child, parent)
  43. assert(parent == nil or is_xform(parent), "parent must be an Xform")
  44. local _parent = parent
  45. while _parent do
  46. assert(_parent ~= child, "cyclical scene graph")
  47. _parent = _parent.parent
  48. end
  49. if child['parent'] == parent then return end
  50. if child['parent'] and child.parent ~= parent then
  51. remove(child.parent.__members.children, child)
  52. end
  53. child.__members.parent = parent
  54. if parent then
  55. append(parent.__members.children, child)
  56. end
  57. update(child)
  58. end
  59. function Xform:new(position, scale, rotation)
  60. local o = {
  61. __members = {
  62. type = "Xform",
  63. mat4 = lovr.math.newMat4(),
  64. parent = nil,
  65. children = {},
  66. position = position and copy_v3(position, lovr.math.newVec3())
  67. or lovr.math.newVec3(),
  68. scale = scale and copy_v3(scale, lovr.math.newVec3(1))
  69. or lovr.math.newVec3(1),
  70. rotation = rotation and copy_quat(rotation, lovr.math.newQuat())
  71. or lovr.math.newQuat()
  72. }
  73. }
  74. setmetatable(o, Xform)
  75. update(o)
  76. return o
  77. end
  78. function Xform:__newindex(index, value)
  79. if index == "position" or index == "scale" then
  80. copy_v3(value, self.__members[index])
  81. update(self)
  82. elseif index == "rotation" then
  83. copy_quat(value, self.__members[index])
  84. update(self)
  85. elseif index == "parent" then
  86. mount(self, value)
  87. elseif index == "children" or
  88. index == "mat4" then
  89. elseif index ~= "__members" then
  90. rawset(self, index, value)
  91. end
  92. end
  93. function Xform:__index(index)
  94. if index == "children" then
  95. return {unpack(self.__members.children)}
  96. else
  97. return self.__members[index]
  98. end
  99. end
  100. return Xform