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
23namespace love
24{
25namespace math
26{
27
28Transform *luax_checktransform(lua_State *L, int idx)
29{
30 return luax_checktype<Transform>(L, idx, Transform::type);
31}
32
33int 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
42int 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
51int 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
60int 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
67int 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
77int 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
86int 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
96int 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
106int 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
114int 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
131int 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
244int 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
260int 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
272int 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
284int 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
294static 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
314extern "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