1 | /** |
2 | * Copyright (c) 2006-2023 LOVE Development Team |
3 | * |
4 | * This software is provided 'as-is', without any express or implied |
5 | * warranty. In no event will the authors be held liable for any damages |
6 | * arising from the use of this software. |
7 | * |
8 | * Permission is granted to anyone to use this software for any purpose, |
9 | * including commercial applications, and to alter it and redistribute it |
10 | * freely, subject to the following restrictions: |
11 | * |
12 | * 1. The origin of this software must not be misrepresented; you must not |
13 | * claim that you wrote the original software. If you use this software |
14 | * in a product, an acknowledgment in the product documentation would be |
15 | * appreciated but is not required. |
16 | * 2. Altered source versions must be plainly marked as such, and must not be |
17 | * misrepresented as being the original software. |
18 | * 3. This notice may not be removed or altered from any source distribution. |
19 | **/ |
20 | |
21 | #include "wrap_Transform.h" |
22 | |
23 | namespace love |
24 | { |
25 | namespace math |
26 | { |
27 | |
28 | Transform *luax_checktransform(lua_State *L, int idx) |
29 | { |
30 | return luax_checktype<Transform>(L, idx, Transform::type); |
31 | } |
32 | |
33 | int w_Transform_clone(lua_State *L) |
34 | { |
35 | Transform *t = luax_checktransform(L, 1); |
36 | Transform *newtransform = t->clone(); |
37 | luax_pushtype(L, newtransform); |
38 | newtransform->release(); |
39 | return 1; |
40 | } |
41 | |
42 | int w_Transform_inverse(lua_State *L) |
43 | { |
44 | Transform *t = luax_checktransform(L, 1); |
45 | Transform *inverse = t->inverse(); |
46 | luax_pushtype(L, inverse); |
47 | inverse->release(); |
48 | return 1; |
49 | } |
50 | |
51 | int w_Transform_apply(lua_State *L) |
52 | { |
53 | Transform *t = luax_checktransform(L, 1); |
54 | Transform *other = luax_checktransform(L, 2); |
55 | t->apply(other); |
56 | lua_pushvalue(L, 1); |
57 | return 1; |
58 | } |
59 | |
60 | int w_Transform_isAffine2DTransform(lua_State *L) |
61 | { |
62 | Transform *t = luax_checktransform(L, 1); |
63 | luax_pushboolean(L, t->getMatrix().isAffine2DTransform()); |
64 | return 1; |
65 | } |
66 | |
67 | int w_Transform_translate(lua_State *L) |
68 | { |
69 | Transform *t = luax_checktransform(L, 1); |
70 | float x = (float) luaL_checknumber(L, 2); |
71 | float y = (float) luaL_checknumber(L, 3); |
72 | t->translate(x, y); |
73 | lua_pushvalue(L, 1); |
74 | return 1; |
75 | } |
76 | |
77 | int w_Transform_rotate(lua_State *L) |
78 | { |
79 | Transform *t = luax_checktransform(L, 1); |
80 | float angle = (float) luaL_checknumber(L, 2); |
81 | t->rotate(angle); |
82 | lua_pushvalue(L, 1); |
83 | return 1; |
84 | } |
85 | |
86 | int w_Transform_scale(lua_State *L) |
87 | { |
88 | Transform *t = luax_checktransform(L, 1); |
89 | float sx = (float) luaL_checknumber(L, 2); |
90 | float sy = (float) luaL_optnumber(L, 3, sx); |
91 | t->scale(sx, sy); |
92 | lua_pushvalue(L, 1); |
93 | return 1; |
94 | } |
95 | |
96 | int w_Transform_shear(lua_State *L) |
97 | { |
98 | Transform *t = luax_checktransform(L, 1); |
99 | float kx = (float) luaL_checknumber(L, 2); |
100 | float ky = (float) luaL_checknumber(L, 3); |
101 | t->shear(kx, ky); |
102 | lua_pushvalue(L, 1); |
103 | return 1; |
104 | } |
105 | |
106 | int w_Transform_reset(lua_State *L) |
107 | { |
108 | Transform *t = luax_checktransform(L, 1); |
109 | t->reset(); |
110 | lua_pushvalue(L, 1); |
111 | return 1; |
112 | } |
113 | |
114 | int w_Transform_setTransformation(lua_State *L) |
115 | { |
116 | Transform *t = luax_checktransform(L, 1); |
117 | float x = (float) luaL_optnumber(L, 2, 0.0); |
118 | float y = (float) luaL_optnumber(L, 3, 0.0); |
119 | float a = (float) luaL_optnumber(L, 4, 0.0); |
120 | float sx = (float) luaL_optnumber(L, 5, 1.0); |
121 | float sy = (float) luaL_optnumber(L, 6, sx); |
122 | float ox = (float) luaL_optnumber(L, 7, 0.0); |
123 | float oy = (float) luaL_optnumber(L, 8, 0.0); |
124 | float kx = (float) luaL_optnumber(L, 9, 0.0); |
125 | float ky = (float) luaL_optnumber(L, 10, 0.0); |
126 | t->setTransformation(x, y, a, sx, sy, ox, oy, kx, ky); |
127 | lua_pushvalue(L, 1); |
128 | return 1; |
129 | } |
130 | |
131 | int w_Transform_setMatrix(lua_State *L) |
132 | { |
133 | Transform *t = luax_checktransform(L, 1); |
134 | |
135 | bool columnmajor = false; |
136 | |
137 | int idx = 2; |
138 | if (lua_type(L, idx) == LUA_TSTRING) |
139 | { |
140 | const char *layoutstr = lua_tostring(L, idx); |
141 | Transform::MatrixLayout layout; |
142 | if (!Transform::getConstant(layoutstr, layout)) |
143 | return luax_enumerror(L, "matrix layout" , Transform::getConstants(layout), layoutstr); |
144 | |
145 | columnmajor = (layout == Transform::MATRIX_COLUMN_MAJOR); |
146 | idx++; |
147 | } |
148 | |
149 | float elements[16]; |
150 | |
151 | if (lua_istable(L, idx)) |
152 | { |
153 | lua_rawgeti(L, idx, 1); |
154 | bool tableoftables = lua_istable(L, -1); |
155 | lua_pop(L, 1); |
156 | |
157 | if (tableoftables) |
158 | { |
159 | if (columnmajor) |
160 | { |
161 | for (int column = 0; column < 4; column++) |
162 | { |
163 | lua_rawgeti(L, idx, column + 1); |
164 | |
165 | for (int row = 0; row < 4; row++) |
166 | { |
167 | lua_rawgeti(L, -(row + 1), row + 1); |
168 | elements[column * 4 + row] = (float) luaL_checknumber(L, -1); |
169 | } |
170 | |
171 | lua_pop(L, 4 + 1); |
172 | } |
173 | } |
174 | else |
175 | { |
176 | for (int row = 0; row < 4; row++) |
177 | { |
178 | lua_rawgeti(L, idx, row + 1); |
179 | |
180 | for (int column = 0; column < 4; column++) |
181 | { |
182 | // The table has the matrix elements laid out in row-major |
183 | // order, but we need to store them column-major in memory. |
184 | lua_rawgeti(L, -(column + 1), column + 1); |
185 | elements[column * 4 + row] = (float) luaL_checknumber(L, -1); |
186 | } |
187 | |
188 | lua_pop(L, 4 + 1); |
189 | } |
190 | } |
191 | } |
192 | else |
193 | { |
194 | if (columnmajor) |
195 | { |
196 | for (int column = 0; column < 4; column++) |
197 | { |
198 | for (int row = 0; row < 4; row++) |
199 | { |
200 | lua_rawgeti(L, idx, column * 4 + row + 1); |
201 | elements[column * 4 + row] = (float) luaL_checknumber(L, -1); |
202 | } |
203 | } |
204 | } |
205 | else |
206 | { |
207 | for (int column = 0; column < 4; column++) |
208 | { |
209 | for (int row = 0; row < 4; row++) |
210 | { |
211 | // The table has the matrix elements laid out in row-major |
212 | // order, but we need to store them column-major in memory. |
213 | lua_rawgeti(L, idx, row * 4 + column + 1); |
214 | elements[column * 4 + row] = (float) luaL_checknumber(L, -1); |
215 | } |
216 | } |
217 | } |
218 | |
219 | lua_pop(L, 16); |
220 | } |
221 | } |
222 | else |
223 | { |
224 | if (columnmajor) |
225 | { |
226 | for (int i = 0; i < 16; i++) |
227 | elements[i] = (float) luaL_checknumber(L, idx + i); |
228 | } |
229 | else |
230 | { |
231 | for (int column = 0; column < 4; column++) |
232 | { |
233 | for (int row = 0; row < 4; row++) |
234 | elements[column * 4 + row] = (float) luaL_checknumber(L, row * 4 + column + idx); |
235 | } |
236 | } |
237 | } |
238 | |
239 | t->setMatrix(Matrix4(elements)); |
240 | lua_pushvalue(L, 1); |
241 | return 1; |
242 | } |
243 | |
244 | int w_Transform_getMatrix(lua_State *L) |
245 | { |
246 | Transform *t = luax_checktransform(L, 1); |
247 | const float *elements = t->getMatrix().getElements(); |
248 | |
249 | // We want to push elements in row-major order, but they're stored column- |
250 | // major. |
251 | for (int row = 0; row < 4; row++) |
252 | { |
253 | for (int column = 0; column < 4; column++) |
254 | lua_pushnumber(L, elements[column * 4 + row]); |
255 | } |
256 | |
257 | return 16; |
258 | } |
259 | |
260 | int w_Transform_transformPoint(lua_State *L) |
261 | { |
262 | Transform *t = luax_checktransform(L, 1); |
263 | love::Vector2 p; |
264 | p.x = (float) luaL_checknumber(L, 2); |
265 | p.y = (float) luaL_checknumber(L, 3); |
266 | p = t->transformPoint(p); |
267 | lua_pushnumber(L, p.x); |
268 | lua_pushnumber(L, p.y); |
269 | return 2; |
270 | } |
271 | |
272 | int w_Transform_inverseTransformPoint(lua_State *L) |
273 | { |
274 | Transform *t = luax_checktransform(L, 1); |
275 | love::Vector2 p; |
276 | p.x = (float) luaL_checknumber(L, 2); |
277 | p.y = (float) luaL_checknumber(L, 3); |
278 | p = t->inverseTransformPoint(p); |
279 | lua_pushnumber(L, p.x); |
280 | lua_pushnumber(L, p.y); |
281 | return 2; |
282 | } |
283 | |
284 | int w_Transform__mul(lua_State *L) |
285 | { |
286 | Transform *t1 = luax_checktransform(L, 1); |
287 | Transform *t2 = luax_checktransform(L, 2); |
288 | Transform *t3 = new Transform(t1->getMatrix() * t2->getMatrix()); |
289 | luax_pushtype(L, t3); |
290 | t3->release(); |
291 | return 1; |
292 | } |
293 | |
294 | static const luaL_Reg functions[] = |
295 | { |
296 | { "clone" , w_Transform_clone }, |
297 | { "inverse" , w_Transform_inverse }, |
298 | { "apply" , w_Transform_apply }, |
299 | { "isAffine2DTransform" , w_Transform_isAffine2DTransform }, |
300 | { "translate" , w_Transform_translate }, |
301 | { "rotate" , w_Transform_rotate }, |
302 | { "scale" , w_Transform_scale }, |
303 | { "shear" , w_Transform_shear }, |
304 | { "reset" , w_Transform_reset }, |
305 | { "setTransformation" , w_Transform_setTransformation }, |
306 | { "setMatrix" , w_Transform_setMatrix }, |
307 | { "getMatrix" , w_Transform_getMatrix }, |
308 | { "transformPoint" , w_Transform_transformPoint }, |
309 | { "inverseTransformPoint" , w_Transform_inverseTransformPoint }, |
310 | { "__mul" , w_Transform__mul }, |
311 | { 0, 0 } |
312 | }; |
313 | |
314 | extern "C" int luaopen_transform(lua_State *L) |
315 | { |
316 | return luax_register_type(L, &Transform::type, functions, nullptr); |
317 | } |
318 | |
319 | } // math |
320 | } // love |
321 | |