xform.lua 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. Xform = {}
  2. Xform.__index = Xform
  3. -- TODO
  4. -- [x] optional constructor args, usually want to set pos, maybe rot
  5. -- [x] values should be copied into persistant properties
  6. -- [ ] ensure that `xform.position.x += 1` triggers an update
  7. -- [x] allow user data
  8. -- [x] fns to add and remove children from parent
  9. -- [ ] prevent DAG cycle in parent/child
  10. -- [ ] correct mat4 calc (need to do parent.world * child.local??)
  11. -- [ ] ensure children vector is loop/remove safe
  12. -- [ ] parenting xform should preserve it's world space in the new
  13. -- parent local
  14. -- [ ] stub out all transform fns from Unity
  15. -- [ ] write test suite?
  16. local function index_of(list, o)
  17. for i,v in pairs(list) do
  18. if v == o then
  19. return i
  20. end
  21. end
  22. end
  23. function remove(list, o)
  24. table.remove(list, index_of(list, o))
  25. return list
  26. end
  27. local function append(list, o)
  28. list[#list + 1] = o
  29. end
  30. local function copy_v3(s, t)
  31. t.x = s.x
  32. t.y = s.y
  33. t.z = s.z
  34. end
  35. local function copy_quat(s, t)
  36. t.x = s.x
  37. t.y = s.y
  38. t.z = s.z
  39. t.w = s.w
  40. end
  41. local function is_xform(o)
  42. return o['__members'] and o.__members.type == "Xform"
  43. end
  44. local function update(xform)
  45. -- compose local mat4
  46. xform.mat4:set(xform.position, xform.scale, xform.rotation)
  47. if xform.parent then
  48. -- parent world * child local
  49. xform.mat4:mul(xform.parent.mat4)
  50. end
  51. for i, child in ipairs(xform.children) do
  52. update(child)
  53. end
  54. end
  55. local function mount(child, parent)
  56. assert(parent == nil or is_xform(parent), "parent must be an Xform")
  57. assert(child ~= parent, "parent can't be self")
  58. if child['parent'] == parent then return end
  59. if child['parent'] and child.parent ~= parent then
  60. remove(child.parent.children, child)
  61. end
  62. child.__members.parent = parent
  63. if parent then
  64. append(parent.children, child)
  65. end
  66. update(child)
  67. end
  68. function Xform:new(position, scale, rotation)
  69. local o = {
  70. __members = {
  71. type = "Xform",
  72. mat4 = lovr.math.newMat4(),
  73. parent = nil,
  74. children = {},
  75. -- TODO these need to be copied over
  76. position = position or lovr.math.newVec3(),
  77. scale = scale or lovr.math.newVec3(1),
  78. rotation = rotation or lovr.math.newQuat()
  79. }
  80. }
  81. setmetatable(o, Xform)
  82. update(o)
  83. return o
  84. end
  85. function Xform:__newindex(index, value)
  86. if index == "position" or index == "scale" then
  87. copy_v3(value, self.__members[index])
  88. update(self)
  89. elseif index == "rotation" then
  90. copy_quat(value, self.__members[index])
  91. update(self)
  92. elseif index == "parent" then
  93. mount(self, value)
  94. elseif index == "children" or
  95. index == "mat4" then
  96. elseif index ~= "__members" then
  97. rawset(self, index, value)
  98. end
  99. end
  100. function Xform:__index(index)
  101. return self.__members[index]
  102. end
  103. return Xform