]> git.lizzy.rs Git - hydra-dragonfire.git/blob - builtin/vector.lua
eed368f328ea2c9315e6b83d5a903f3c75b14c18
[hydra-dragonfire.git] / builtin / vector.lua
1 --[[ builtin/vector.lua ]]--
2
3 local function wrap(op, body_wrapper, ...)
4         return loadstring("return function(a, b) " .. body_wrapper(op, ...) .. "end")()
5 end
6
7 local function arith_mt(...)
8         return {
9                 __add = wrap("+", ...),
10                 __sub = wrap("-", ...),
11                 __mul = wrap("*", ...),
12                 __div = wrap("/", ...),
13                 __mod = wrap("%", ...),
14         }
15 end
16
17 -- vec2
18
19 local mt_vec2 = arith_mt(function(op)
20         return [[
21                 if type(b) == "number" then
22                         return vec2(a.x ]] .. op.. [[ b, a.y ]] .. op .. [[ b)
23                 else
24                         return vec2(a.x ]] .. op.. [[ b.x, a.y ]] .. op.. [[ b.y)
25                 end
26         ]]
27 end)
28
29 function mt_vec2:__neg()
30         return vec2(-self.x, -self.y)
31 end
32
33 function mt_vec2:__len()
34         return math.sqrt(self.x ^ 2 + self.y ^ 2)
35 end
36
37 function mt_vec2:__tostring()
38         return "(" .. self.x .. ", " .. self.y .. ")"
39 end
40
41 mt_vec2.__index = {
42         validate = function(self)
43                 assert(type(self.x) == "number")
44                 assert(type(self.y) == "number")
45                 return self
46         end
47 }
48
49 function vec2(a, b)
50         local o = {}
51
52         if type(a) == "number" then
53                 o.x = a
54                 o.y = b or a
55         else
56                 o.x = a.x
57                 o.y = a.y
58         end
59
60         setmetatable(o, mt_vec2)
61         return o:validate()
62 end
63
64 -- vec3
65
66 local mt_vec3 = arith_mt(function(op)
67         return [[
68                 if type(b) == "number" then
69                         return vec3(a.x ]] .. op.. [[ b, a.y ]] .. op .. [[ b, a.z ]] .. op .. [[ b)
70                 else
71                         return vec3(a.x ]] .. op.. [[ b.x, a.y ]] .. op.. [[ b.y, a.z ]] .. op.. [[ b.z)
72                 end
73         ]]
74 end)
75
76 function mt_vec3:__neg()
77         return vec3(-self.x, -self.y, -self.z)
78 end
79
80 function mt_vec3:__len()
81         return math.sqrt(self.x ^ 2 + self.y ^ 2 + self.z ^ 2)
82 end
83
84 function mt_vec3:__tostring()
85         return "(" .. self.x .. ", " .. self.y .. ", " .. self.z .. ")"
86 end
87
88 mt_vec3.__index = {
89         validate = function(self)
90                 assert(type(self.x) == "number")
91                 assert(type(self.y) == "number")
92                 assert(type(self.z) == "number")
93                 return self
94         end
95 }
96
97 function vec3(a, b, c)
98         local o = {}
99
100         if type(a) == "number" then
101                 o.x = a
102                 o.y = b or a
103                 o.z = c or a
104         else
105                 o.x = a.x
106                 o.y = a.y
107                 o.z = a.z
108         end
109
110         setmetatable(o, mt_vec3)
111         return o:validate()
112 end
113
114 -- box
115
116 local mt_box = arith_mt(function(op)
117         return "return box(a.min " .. op .. " b, a.max " .. op .. " b)"
118 end)
119
120 function mt_box:__neg()
121         return box(-self.min, -self.max)
122 end
123
124 function mt_box:__tostring()
125         return "[" .. self.min .. "; " .. self.max .. "]"
126 end
127
128 mt_box.__index = {
129         contains = function(a, b)
130                 if type(b) == "number" or b.x then
131                         return a.min <= b and a.max >= b
132                 else
133                         return a.min <= b.min and a.max >= b.max
134                 end
135         end,
136         validate = function(self)
137                 if type(self.min) == "number" then
138                         assert(type(self.max) == "number")
139                 else
140                         assert(not self.min.z == not self.max.z)
141                         self.min:validate()
142                         self.max:validate()
143                 end
144         end,
145 }
146
147 function box(a, b)
148         local o = {}
149
150         if type(a) == "number" or a.x then
151                 o.min = a
152                 o.max = b
153         else
154                 o.min = a.min
155                 o.max = a.max
156         end
157
158         setmetatable(o, mt_box)
159         return o:validate()
160 end