1 /**
2  * Copyright (c) 2006-2019 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 
luax_checktransform(lua_State * L,int idx)28 Transform *luax_checktransform(lua_State *L, int idx)
29 {
30 	return luax_checktype<Transform>(L, idx, Transform::type);
31 }
32 
w_Transform_clone(lua_State * L)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 
w_Transform_inverse(lua_State * L)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 
w_Transform_apply(lua_State * L)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 
w_Transform_isAffine2DTransform(lua_State * L)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 
w_Transform_translate(lua_State * L)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 
w_Transform_rotate(lua_State * L)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 
w_Transform_scale(lua_State * L)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 
w_Transform_shear(lua_State * L)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 
w_Transform_reset(lua_State * L)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 
w_Transform_setTransformation(lua_State * L)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 
w_Transform_setMatrix(lua_State * L)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 
w_Transform_getMatrix(lua_State * L)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 
w_Transform_transformPoint(lua_State * L)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 
w_Transform_inverseTransformPoint(lua_State * L)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 
w_Transform__mul(lua_State * L)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 
luaopen_transform(lua_State * L)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