]> git.lizzy.rs Git - hydra-dragonfire.git/blob - builtin/vector.lua
Add map component
[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         round = function(self)
48                 return vec2(math.round(self.x), math.round(self.y))
49         end,
50 }
51
52 function vec2(a, b)
53         local o = {}
54
55         if type(a) == "number" then
56                 o.x = a
57                 o.y = b or a
58         else
59                 o.x = a.x
60                 o.y = a.y
61         end
62
63         setmetatable(o, mt_vec2)
64         return o:validate()
65 end
66
67 -- vec3
68
69 local mt_vec3 = arith_mt(function(op)
70         return [[
71                 if type(b) == "number" then
72                         return vec3(a.x ]] .. op.. [[ b, a.y ]] .. op .. [[ b, a.z ]] .. op .. [[ b)
73                 else
74                         return vec3(a.x ]] .. op.. [[ b.x, a.y ]] .. op.. [[ b.y, a.z ]] .. op.. [[ b.z)
75                 end
76         ]]
77 end)
78
79 function mt_vec3:__neg()
80         return vec3(-self.x, -self.y, -self.z)
81 end
82
83 function mt_vec3:__len()
84         return math.sqrt(self.x ^ 2 + self.y ^ 2 + self.z ^ 2)
85 end
86
87 function mt_vec3:__tostring()
88         return "(" .. self.x .. ", " .. self.y .. ", " .. self.z .. ")"
89 end
90
91 mt_vec3.__index = {
92         validate = function(self)
93                 assert(type(self.x) == "number")
94                 assert(type(self.y) == "number")
95                 assert(type(self.z) == "number")
96                 return self
97         end,
98         round = function(self)
99                 return vec3(math.floor(self.x), math.floor(self.y), math.floor(self.z))
100         end,
101 }
102
103 function vec3(a, b, c)
104         local o = {}
105
106         if type(a) == "number" then
107                 o.x = a
108                 o.y = b or a
109                 o.z = c or a
110         else
111                 o.x = a.x
112                 o.y = a.y
113                 o.z = a.z
114         end
115
116         setmetatable(o, mt_vec3)
117         return o:validate()
118 end
119
120 -- box
121
122 local mt_box = arith_mt(function(op)
123         return "return box(a.min " .. op .. " b, a.max " .. op .. " b)"
124 end)
125
126 function mt_box:__neg()
127         return box(-self.min, -self.max)
128 end
129
130 function mt_box:__tostring()
131         return "[" .. self.min .. "; " .. self.max .. "]"
132 end
133
134 mt_box.__index = {
135         contains = function(a, b)
136                 if type(b) == "number" or b.x then
137                         return a.min <= b and a.max >= b
138                 else
139                         return a.min <= b.min and a.max >= b.max
140                 end
141         end,
142         validate = function(self)
143                 if type(self.min) == "number" then
144                         assert(type(self.max) == "number")
145                 else
146                         assert(not self.min.z == not self.max.z)
147                         self.min:validate()
148                         self.max:validate()
149                 end
150         end,
151 }
152
153 function box(a, b)
154         local o = {}
155
156         if type(a) == "number" or a.x then
157                 o.min = a
158                 o.max = b
159         else
160                 o.min = a.min
161                 o.max = a.max
162         end
163
164         setmetatable(o, mt_box)
165         return o:validate()
166 end