diff --git a/CMakeLists.txt b/CMakeLists.txt index 14cdc3178..b1d3a3f39 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -655,6 +655,8 @@ set(LOVE_SRC_MODULE_MATH src/modules/math/MathModule.h src/modules/math/RandomGenerator.cpp src/modules/math/RandomGenerator.h + src/modules/math/Transform.cpp + src/modules/math/Transform.h src/modules/math/wrap_BezierCurve.cpp src/modules/math/wrap_BezierCurve.h src/modules/math/wrap_CompressedData.cpp @@ -663,6 +665,8 @@ set(LOVE_SRC_MODULE_MATH src/modules/math/wrap_Math.h src/modules/math/wrap_RandomGenerator.cpp src/modules/math/wrap_RandomGenerator.h + src/modules/math/wrap_Transform.cpp + src/modules/math/wrap_Transform.h ) source_group("modules\\math" FILES ${LOVE_SRC_MODULE_MATH}) diff --git a/platform/xcode/liblove.xcodeproj/project.pbxproj b/platform/xcode/liblove.xcodeproj/project.pbxproj index a5e757144..8426b1588 100644 --- a/platform/xcode/liblove.xcodeproj/project.pbxproj +++ b/platform/xcode/liblove.xcodeproj/project.pbxproj @@ -895,6 +895,12 @@ FA4F2BB31DE1E4B800CA37D7 /* RecordingDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA4F2BA21DE1E36400CA37D7 /* RecordingDevice.cpp */; }; FA4F2BB41DE1E4BD00CA37D7 /* RecordingDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA4F2BAA1DE1E37000CA37D7 /* RecordingDevice.cpp */; }; FA4F2BB51DE1E4C300CA37D7 /* wrap_RecordingDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA4F2BA41DE1E36400CA37D7 /* wrap_RecordingDevice.cpp */; }; + FA4F2BE31DE6650600CA37D7 /* Transform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA4F2BDF1DE6650600CA37D7 /* Transform.cpp */; }; + FA4F2BE41DE6650600CA37D7 /* Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = FA4F2BE01DE6650600CA37D7 /* Transform.h */; }; + FA4F2BE51DE6650600CA37D7 /* wrap_Transform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA4F2BE11DE6650600CA37D7 /* wrap_Transform.cpp */; }; + FA4F2BE61DE6650600CA37D7 /* wrap_Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = FA4F2BE21DE6650600CA37D7 /* wrap_Transform.h */; }; + FA4F2BE71DE6650D00CA37D7 /* Transform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA4F2BDF1DE6650600CA37D7 /* Transform.cpp */; }; + FA4F2BE81DE6651000CA37D7 /* wrap_Transform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA4F2BE11DE6650600CA37D7 /* wrap_Transform.cpp */; }; FA56D9BC1C208A0200D8D3C7 /* libmodplug.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FA56D9BA1C2089EE00D8D3C7 /* libmodplug.a */; }; FA577AB016C7507900860150 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA577A7916C71A1700860150 /* Cocoa.framework */; }; FA577AC216C7512D00860150 /* FreeType.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA577A6716C719D900860150 /* FreeType.framework */; }; @@ -1600,6 +1606,10 @@ FA4F2BAB1DE1E37000CA37D7 /* RecordingDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecordingDevice.h; sourceTree = ""; }; FA4F2BAE1DE1E37B00CA37D7 /* RecordingDevice.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RecordingDevice.cpp; sourceTree = ""; }; FA4F2BAF1DE1E37B00CA37D7 /* RecordingDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecordingDevice.h; sourceTree = ""; }; + FA4F2BDF1DE6650600CA37D7 /* Transform.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Transform.cpp; sourceTree = ""; }; + FA4F2BE01DE6650600CA37D7 /* Transform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Transform.h; sourceTree = ""; }; + FA4F2BE11DE6650600CA37D7 /* wrap_Transform.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Transform.cpp; sourceTree = ""; }; + FA4F2BE21DE6650600CA37D7 /* wrap_Transform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Transform.h; sourceTree = ""; }; FA56D9BA1C2089EE00D8D3C7 /* libmodplug.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libmodplug.a; sourceTree = ""; }; FA577A6716C719D900860150 /* FreeType.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FreeType.framework; path = /Library/Frameworks/FreeType.framework; sourceTree = ""; }; FA577A6D16C719EA00860150 /* Lua.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Lua.framework; path = /Library/Frameworks/Lua.framework; sourceTree = ""; }; @@ -2559,6 +2569,8 @@ FA0B7C041A95902C000E1D17 /* MathModule.h */, FA0B7C051A95902C000E1D17 /* RandomGenerator.cpp */, FA0B7C061A95902C000E1D17 /* RandomGenerator.h */, + FA4F2BDF1DE6650600CA37D7 /* Transform.cpp */, + FA4F2BE01DE6650600CA37D7 /* Transform.h */, FA0B7C071A95902C000E1D17 /* wrap_BezierCurve.cpp */, FA0B7C081A95902C000E1D17 /* wrap_BezierCurve.h */, FAB17BEE1ABFB37500F9BA27 /* wrap_CompressedData.cpp */, @@ -2569,6 +2581,8 @@ FA0B7C0B1A95902C000E1D17 /* wrap_RandomGenerator.cpp */, FA0B7C0C1A95902C000E1D17 /* wrap_RandomGenerator.h */, FA2E9BFE1C19E00C0004A1EE /* wrap_RandomGenerator.lua */, + FA4F2BE11DE6650600CA37D7 /* wrap_Transform.cpp */, + FA4F2BE21DE6650600CA37D7 /* wrap_Transform.h */, ); path = math; sourceTree = ""; @@ -3191,6 +3205,7 @@ FA0B7E6B1A95902C000E1D17 /* wrap_PulleyJoint.h in Headers */, FA0B7E051A95902C000E1D17 /* Contact.h in Headers */, FA0B7A691A958EA3000E1D17 /* b2Island.h in Headers */, + FA4F2BE41DE6650600CA37D7 /* Transform.h in Headers */, FA0B7E0E1A95902C000E1D17 /* Fixture.h in Headers */, FA0B7A401A958EA3000E1D17 /* b2ChainShape.h in Headers */, 217DFBE81D9F6D490055D849 /* inet.h in Headers */, @@ -3266,6 +3281,7 @@ 217DFBF71D9F6D490055D849 /* options.h in Headers */, FA0B7E3B1A95902C000E1D17 /* World.h in Headers */, FA0B7DC31A95902C000E1D17 /* wrap_Joystick.h in Headers */, + FA4F2BE61DE6650600CA37D7 /* wrap_Transform.h in Headers */, FA0B7EE71A95902D000E1D17 /* Window.h in Headers */, FA0B7E651A95902C000E1D17 /* wrap_PolygonShape.h in Headers */, FA0B7AC91A958EA3000E1D17 /* win32.h in Headers */, @@ -3501,6 +3517,7 @@ FA0B7AAB1A958EA3000E1D17 /* b2WeldJoint.cpp in Sources */, FA0B7EC21A95902C000E1D17 /* threads.cpp in Sources */, FA0B79371A958E3B000E1D17 /* macosx.mm in Sources */, + FA4F2BE81DE6651000CA37D7 /* wrap_Transform.cpp in Sources */, FA0B7D011A95902C000E1D17 /* Filesystem.cpp in Sources */, FA0B7ED91A95902D000E1D17 /* wrap_Timer.cpp in Sources */, FA0B7DD11A95902C000E1D17 /* love.cpp in Sources */, @@ -3583,6 +3600,7 @@ FA0B7D681A95902C000E1D17 /* wrap_ParticleSystem.cpp in Sources */, FA0B7AD51A958EA3000E1D17 /* unix.c in Sources */, FAB17BE71ABFAA9000F9BA27 /* lz4.c in Sources */, + FA4F2BE71DE6650D00CA37D7 /* Transform.cpp in Sources */, FA0B7D651A95902C000E1D17 /* wrap_Mesh.cpp in Sources */, FA0B7A531A958EA3000E1D17 /* b2Math.cpp in Sources */, FA0B7CDA1A95902C000E1D17 /* Pool.cpp in Sources */, @@ -3861,6 +3879,7 @@ FA0B7EDF1A95902D000E1D17 /* wrap_Touch.cpp in Sources */, FA0B794A1A958E3B000E1D17 /* wrap_Data.cpp in Sources */, 217DFBFB1D9F6D490055D849 /* serial.c in Sources */, + FA4F2BE51DE6650600CA37D7 /* wrap_Transform.cpp in Sources */, 217DFC0D1D9F6D490055D849 /* unixudp.c in Sources */, FA0B7CDC1A95902C000E1D17 /* Source.cpp in Sources */, FA0B7DC41A95902C000E1D17 /* wrap_JoystickModule.cpp in Sources */, @@ -4045,6 +4064,7 @@ FA0B7CDF1A95902C000E1D17 /* Source.cpp in Sources */, FA0B7ECE1A95902C000E1D17 /* wrap_LuaThread.cpp in Sources */, FA0B79431A958E3B000E1D17 /* Variant.cpp in Sources */, + FA4F2BE31DE6650600CA37D7 /* Transform.cpp in Sources */, FA0B7EA01A95902C000E1D17 /* Sound.cpp in Sources */, FA0B7DE51A95902C000E1D17 /* Cursor.cpp in Sources */, FA0B7EDB1A95902D000E1D17 /* Touch.cpp in Sources */, diff --git a/src/common/Matrix.cpp b/src/common/Matrix.cpp index 9e6077fa9..f6f6b4dcd 100644 --- a/src/common/Matrix.cpp +++ b/src/common/Matrix.cpp @@ -73,6 +73,12 @@ Matrix4::Matrix4() { setIdentity(); } + + +Matrix4::Matrix4(const float elements[16]) +{ + memcpy(e, elements, sizeof(float) * 16); +} Matrix4::Matrix4(float t00, float t10, float t01, float t11, float x, float y) { diff --git a/src/common/Matrix.h b/src/common/Matrix.h index 98945adc8..d5fd49a2b 100644 --- a/src/common/Matrix.h +++ b/src/common/Matrix.h @@ -52,6 +52,12 @@ public: **/ Matrix4(float t00, float t10, float t01, float t11, float x, float y); + /** + * Creates a new matrix from the specified elements. Be sure to pass + * exactly 16 elements in! + **/ + Matrix4(const float elements[16]); + /** * Creates a new matrix set to a transformation. **/ @@ -182,6 +188,9 @@ public: template void transform(V *dst, const V *src, int size) const; + /** + * Computes and returns the inverse of the matrix. + **/ Matrix4 inverse() const; /** diff --git a/src/common/types.cpp b/src/common/types.cpp index 2385315c9..80667c7a3 100644 --- a/src/common/types.cpp +++ b/src/common/types.cpp @@ -68,7 +68,8 @@ static const TypeBits *createTypeFlags() // Math. b[MATH_RANDOM_GENERATOR_ID] = (one << MATH_RANDOM_GENERATOR_ID) | b[OBJECT_ID]; b[MATH_BEZIER_CURVE_ID] = (one << MATH_BEZIER_CURVE_ID) | b[OBJECT_ID]; - b[MATH_COMPRESSED_DATA_ID] = (one <getMatrix(); +} + +void Graphics::replaceTransform(love::math::Transform *transform) +{ + gl.getTransform() = transform->getMatrix(); +} + Vector Graphics::transformPoint(Vector point) { Vector p; diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index 4bef0968f..9fbb5fdac 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -38,6 +38,8 @@ #include "video/VideoStream.h" +#include "math/Transform.h" + #include "Font.h" #include "Image.h" #include "graphics/Quad.h" @@ -488,6 +490,10 @@ public: void translate(float x, float y); void shear(float kx, float ky); void origin(); + + void applyTransform(love::math::Transform *transform); + void replaceTransform(love::math::Transform *transform); + Vector transformPoint(Vector point); Vector inverseTransformPoint(Vector point); diff --git a/src/modules/graphics/opengl/wrap_Graphics.cpp b/src/modules/graphics/opengl/wrap_Graphics.cpp index 7abed19cd..9833b2b05 100644 --- a/src/modules/graphics/opengl/wrap_Graphics.cpp +++ b/src/modules/graphics/opengl/wrap_Graphics.cpp @@ -1667,24 +1667,37 @@ int w_draw(lua_State *L) startidx = 2; } - float x = (float) luaL_optnumber(L, startidx + 0, 0.0); - float y = (float) luaL_optnumber(L, startidx + 1, 0.0); - float a = (float) luaL_optnumber(L, startidx + 2, 0.0); - float sx = (float) luaL_optnumber(L, startidx + 3, 1.0); - float sy = (float) luaL_optnumber(L, startidx + 4, sx); - float ox = (float) luaL_optnumber(L, startidx + 5, 0.0); - float oy = (float) luaL_optnumber(L, startidx + 6, 0.0); - float kx = (float) luaL_optnumber(L, startidx + 7, 0.0); - float ky = (float) luaL_optnumber(L, startidx + 8, 0.0); + if (luax_istype(L, startidx, MATH_TRANSFORM_ID)) + { + math::Transform *tf = luax_totype(L, startidx, MATH_TRANSFORM_ID); + luax_catchexcept(L, [&]() { + if (texture && quad) + instance()->drawq(texture, quad, tf->getMatrix()); + else + instance()->draw(drawable, tf->getMatrix()); + }); + } + else + { + float x = (float) luaL_optnumber(L, startidx + 0, 0.0); + float y = (float) luaL_optnumber(L, startidx + 1, 0.0); + float a = (float) luaL_optnumber(L, startidx + 2, 0.0); + float sx = (float) luaL_optnumber(L, startidx + 3, 1.0); + float sy = (float) luaL_optnumber(L, startidx + 4, sx); + float ox = (float) luaL_optnumber(L, startidx + 5, 0.0); + float oy = (float) luaL_optnumber(L, startidx + 6, 0.0); + float kx = (float) luaL_optnumber(L, startidx + 7, 0.0); + float ky = (float) luaL_optnumber(L, startidx + 8, 0.0); - Matrix4 m(x, y, a, sx, sy, ox, oy, kx, ky); + Matrix4 m(x, y, a, sx, sy, ox, oy, kx, ky); - luax_catchexcept(L, [&]() { - if (texture && quad) - instance()->drawq(texture, quad, m); - else if (drawable) - instance()->draw(drawable, m); - }); + luax_catchexcept(L, [&]() { + if (texture && quad) + instance()->drawq(texture, quad, m); + else if (drawable) + instance()->draw(drawable, m); + }); + } return 0; } @@ -1694,19 +1707,27 @@ int w_print(lua_State *L) std::vector str; luax_checkcoloredstring(L, 1, str); - float x = (float)luaL_optnumber(L, 2, 0.0); - float y = (float)luaL_optnumber(L, 3, 0.0); - float angle = (float)luaL_optnumber(L, 4, 0.0f); - float sx = (float)luaL_optnumber(L, 5, 1.0f); - float sy = (float)luaL_optnumber(L, 6, sx); - float ox = (float)luaL_optnumber(L, 7, 0.0f); - float oy = (float)luaL_optnumber(L, 8, 0.0f); - float kx = (float)luaL_optnumber(L, 9, 0.0f); - float ky = (float)luaL_optnumber(L, 10, 0.0f); + if (luax_istype(L, 2, MATH_TRANSFORM_ID)) + { + math::Transform *tf = luax_totype(L, 2, MATH_TRANSFORM_ID); + luax_catchexcept(L, [&](){ instance()->print(str, tf->getMatrix()); }); + } + else + { + float x = (float)luaL_optnumber(L, 2, 0.0); + float y = (float)luaL_optnumber(L, 3, 0.0); + float angle = (float)luaL_optnumber(L, 4, 0.0f); + float sx = (float)luaL_optnumber(L, 5, 1.0f); + float sy = (float)luaL_optnumber(L, 6, sx); + float ox = (float)luaL_optnumber(L, 7, 0.0f); + float oy = (float)luaL_optnumber(L, 8, 0.0f); + float kx = (float)luaL_optnumber(L, 9, 0.0f); + float ky = (float)luaL_optnumber(L, 10, 0.0f); - Matrix4 m(x, y, angle, sx, sy, ox, oy, kx, ky); + Matrix4 m(x, y, angle, sx, sy, ox, oy, kx, ky); - luax_catchexcept(L, [&](){ instance()->print(str, m); }); + luax_catchexcept(L, [&](){ instance()->print(str, m); }); + } return 0; } @@ -1715,36 +1736,38 @@ int w_printf(lua_State *L) std::vector str; luax_checkcoloredstring(L, 1, str); - float x = (float)luaL_checknumber(L, 2); - float y = (float)luaL_checknumber(L, 3); - float wrap = (float)luaL_checknumber(L, 4); - - float angle = 0.0f; - float sx = 1.0f, sy = 1.0f; - float ox = 0.0f, oy = 0.0f; - float kx = 0.0f, ky = 0.0f; - Font::AlignMode align = Font::ALIGN_LEFT; + Matrix4 m; - if (lua_gettop(L) >= 5) + int formatidx = 4; + + if (luax_istype(L, 2, MATH_TRANSFORM_ID)) { - if (!lua_isnil(L, 5)) - { - const char *str = luaL_checkstring(L, 5); - if (!Font::getConstant(str, align)) - return luaL_error(L, "Incorrect alignment: %s", str); - } + math::Transform *tf = luax_totype(L, 2, MATH_TRANSFORM_ID); + m = tf->getMatrix(); + formatidx = 3; + } + else + { + float x = (float)luaL_checknumber(L, 2); + float y = (float)luaL_checknumber(L, 3); - angle = (float) luaL_optnumber(L, 6, 0.0f); - sx = (float) luaL_optnumber(L, 7, 1.0f); - sy = (float) luaL_optnumber(L, 8, sx); - ox = (float) luaL_optnumber(L, 9, 0.0f); - oy = (float) luaL_optnumber(L, 10, 0.0f); - kx = (float) luaL_optnumber(L, 11, 0.0f); - ky = (float) luaL_optnumber(L, 12, 0.0f); + float angle = (float) luaL_optnumber(L, 6, 0.0f); + float sx = (float) luaL_optnumber(L, 7, 1.0f); + float sy = (float) luaL_optnumber(L, 8, sx); + float ox = (float) luaL_optnumber(L, 9, 0.0f); + float oy = (float) luaL_optnumber(L, 10, 0.0f); + float kx = (float) luaL_optnumber(L, 11, 0.0f); + float ky = (float) luaL_optnumber(L, 12, 0.0f); + + m = Matrix4(x, y, angle, sx, sy, ox, oy, kx, ky); } - Matrix4 m(x, y, angle, sx, sy, ox, oy, kx, ky); + float wrap = (float)luaL_checknumber(L, formatidx); + + const char *astr = lua_isnoneornil(L, formatidx + 1) ? nullptr : luaL_checkstring(L, formatidx + 1); + if (astr != nullptr && !Font::getConstant(astr, align)) + return luaL_error(L, "Incorrect alignment: %s", astr); luax_catchexcept(L, [&](){ instance()->printf(str, wrap, align, m); }); return 0; @@ -2048,6 +2071,13 @@ int w_push(lua_State *L) return luaL_error(L, "Invalid graphics stack type: %s", sname); luax_catchexcept(L, [&](){ instance()->push(stype); }); + + if (luax_istype(L, 2, MATH_TRANSFORM_ID)) + { + math::Transform *t = luax_totype(L, 2, MATH_TRANSFORM_ID); + instance()->applyTransform(t); + } + return 0; } diff --git a/src/modules/graphics/opengl/wrap_Shader.cpp b/src/modules/graphics/opengl/wrap_Shader.cpp index 25701c9e0..8a25c5ab8 100644 --- a/src/modules/graphics/opengl/wrap_Shader.cpp +++ b/src/modules/graphics/opengl/wrap_Shader.cpp @@ -21,6 +21,7 @@ #include "wrap_Shader.h" #include "graphics/wrap_Texture.h" #include "math/MathModule.h" +#include "math/Transform.h" #include #include @@ -164,6 +165,13 @@ int w_Shader_sendMatrices(lua_State *L, int startidx, Shader *shader, const Shad for (int i = 0; i < count; i++) { + if (columns == 4 && rows == 4 && luax_istype(L, startidx + i, MATH_TRANSFORM_ID)) + { + math::Transform *t = luax_totype(L, startidx + i, MATH_TRANSFORM_ID); + memcpy(&values[i * 16], t->getMatrix().getElements(), sizeof(float) * 16); + continue; + } + luaL_checktype(L, startidx + i, LUA_TTABLE); lua_rawgeti(L, startidx + i, 1); diff --git a/src/modules/graphics/opengl/wrap_SpriteBatch.cpp b/src/modules/graphics/opengl/wrap_SpriteBatch.cpp index 06b0312da..0bfbc4f58 100644 --- a/src/modules/graphics/opengl/wrap_SpriteBatch.cpp +++ b/src/modules/graphics/opengl/wrap_SpriteBatch.cpp @@ -23,6 +23,7 @@ #include "Image.h" #include "Canvas.h" #include "graphics/wrap_Texture.h" +#include "math/wrap_Transform.h" // C++ #include @@ -51,24 +52,37 @@ static inline int w_SpriteBatch_add_or_set(lua_State *L, SpriteBatch *t, int sta else if (lua_isnil(L, startidx) && !lua_isnoneornil(L, startidx + 1)) return luax_typerror(L, startidx, "Quad"); - float x = (float) luaL_optnumber(L, startidx + 0, 0.0); - float y = (float) luaL_optnumber(L, startidx + 1, 0.0); - float a = (float) luaL_optnumber(L, startidx + 2, 0.0); - float sx = (float) luaL_optnumber(L, startidx + 3, 1.0); - float sy = (float) luaL_optnumber(L, startidx + 4, sx); - float ox = (float) luaL_optnumber(L, startidx + 5, 0.0); - float oy = (float) luaL_optnumber(L, startidx + 6, 0.0); - float kx = (float) luaL_optnumber(L, startidx + 7, 0.0); - float ky = (float) luaL_optnumber(L, startidx + 8, 0.0); + if (luax_istype(L, startidx, MATH_TRANSFORM_ID)) + { + math::Transform *tf = luax_totype(L, startidx, MATH_TRANSFORM_ID); + luax_catchexcept(L, [&]() { + if (quad) + index = t->addq(quad, tf->getMatrix(), index); + else + index = t->add(tf->getMatrix(), index); + }); + } + else + { + float x = (float) luaL_optnumber(L, startidx + 0, 0.0); + float y = (float) luaL_optnumber(L, startidx + 1, 0.0); + float a = (float) luaL_optnumber(L, startidx + 2, 0.0); + float sx = (float) luaL_optnumber(L, startidx + 3, 1.0); + float sy = (float) luaL_optnumber(L, startidx + 4, sx); + float ox = (float) luaL_optnumber(L, startidx + 5, 0.0); + float oy = (float) luaL_optnumber(L, startidx + 6, 0.0); + float kx = (float) luaL_optnumber(L, startidx + 7, 0.0); + float ky = (float) luaL_optnumber(L, startidx + 8, 0.0); - Matrix4 m(x, y, a, sx, sy, ox, oy, kx, ky); + Matrix4 m(x, y, a, sx, sy, ox, oy, kx, ky); - luax_catchexcept(L, [&]() { - if (quad) - index = t->addq(quad, m, index); - else - index = t->add(m, index); - }); + luax_catchexcept(L, [&]() { + if (quad) + index = t->addq(quad, m, index); + else + index = t->add(m, index); + }); + } return index; } diff --git a/src/modules/graphics/opengl/wrap_Text.cpp b/src/modules/graphics/opengl/wrap_Text.cpp index 793b7ad11..dd8f7594b 100644 --- a/src/modules/graphics/opengl/wrap_Text.cpp +++ b/src/modules/graphics/opengl/wrap_Text.cpp @@ -19,6 +19,7 @@ **/ #include "wrap_Text.h" +#include "math/wrap_Transform.h" namespace love { @@ -126,24 +127,33 @@ int w_Text_add(lua_State *L) { Text *t = luax_checktext(L, 1); + int index = 0; + std::vector text; luax_checkcoloredstring(L, 2, text); - float x = (float) luaL_optnumber(L, 3, 0.0); - float y = (float) luaL_optnumber(L, 4, 0.0); - float a = (float) luaL_optnumber(L, 5, 0.0); - float sx = (float) luaL_optnumber(L, 6, 1.0); - float sy = (float) luaL_optnumber(L, 7, sx); - float ox = (float) luaL_optnumber(L, 8, 0.0); - float oy = (float) luaL_optnumber(L, 9, 0.0); - float kx = (float) luaL_optnumber(L, 10, 0.0); - float ky = (float) luaL_optnumber(L, 11, 0.0); + if (luax_istype(L, 3, MATH_TRANSFORM_ID)) + { + math::Transform *tf = luax_totype(L, 3, MATH_TRANSFORM_ID); + luax_catchexcept(L, [&](){ index = t->add(text, tf->getMatrix()); }); + } + else + { + float x = (float) luaL_optnumber(L, 3, 0.0); + float y = (float) luaL_optnumber(L, 4, 0.0); + float a = (float) luaL_optnumber(L, 5, 0.0); + float sx = (float) luaL_optnumber(L, 6, 1.0); + float sy = (float) luaL_optnumber(L, 7, sx); + float ox = (float) luaL_optnumber(L, 8, 0.0); + float oy = (float) luaL_optnumber(L, 9, 0.0); + float kx = (float) luaL_optnumber(L, 10, 0.0); + float ky = (float) luaL_optnumber(L, 11, 0.0); + + Matrix4 m(x, y, a, sx, sy, ox, oy, kx, ky); + luax_catchexcept(L, [&](){ index = t->add(text, m); }); + } - Matrix4 m(x, y, a, sx, sy, ox, oy, kx, ky); - int index = 0; - luax_catchexcept(L, [&](){ index = t->add(text, m); }); lua_pushnumber(L, index + 1); - return 1; } @@ -151,6 +161,8 @@ int w_Text_addf(lua_State *L) { Text *t = luax_checktext(L, 1); + int index = 0; + std::vector text; luax_checkcoloredstring(L, 2, text); @@ -162,21 +174,28 @@ int w_Text_addf(lua_State *L) if (!Font::getConstant(alignstr, align)) return luaL_error(L, "Invalid align mode: %s", alignstr); - float x = (float) luaL_optnumber(L, 5, 0.0); - float y = (float) luaL_optnumber(L, 6, 0.0); - float a = (float) luaL_optnumber(L, 7, 0.0); - float sx = (float) luaL_optnumber(L, 8, 1.0); - float sy = (float) luaL_optnumber(L, 9, sx); - float ox = (float) luaL_optnumber(L, 10, 0.0); - float oy = (float) luaL_optnumber(L, 11, 0.0); - float kx = (float) luaL_optnumber(L, 12, 0.0); - float ky = (float) luaL_optnumber(L, 13, 0.0); + if (luax_istype(L, 5, MATH_TRANSFORM_ID)) + { + math::Transform *tf = luax_totype(L, 5, MATH_TRANSFORM_ID); + luax_catchexcept(L, [&](){ index = t->addf(text, wrap, align, tf->getMatrix()); }); + } + else + { + float x = (float) luaL_optnumber(L, 5, 0.0); + float y = (float) luaL_optnumber(L, 6, 0.0); + float a = (float) luaL_optnumber(L, 7, 0.0); + float sx = (float) luaL_optnumber(L, 8, 1.0); + float sy = (float) luaL_optnumber(L, 9, sx); + float ox = (float) luaL_optnumber(L, 10, 0.0); + float oy = (float) luaL_optnumber(L, 11, 0.0); + float kx = (float) luaL_optnumber(L, 12, 0.0); + float ky = (float) luaL_optnumber(L, 13, 0.0); + + Matrix4 m(x, y, a, sx, sy, ox, oy, kx, ky); + luax_catchexcept(L, [&](){ index = t->addf(text, wrap, align, m); }); + } - Matrix4 m(x, y, a, sx, sy, ox, oy, kx, ky); - int index = 0; - luax_catchexcept(L, [&](){ index = t->addf(text, wrap, align, m); }); lua_pushnumber(L, index + 1); - return 1; } diff --git a/src/modules/math/MathModule.cpp b/src/modules/math/MathModule.cpp index 02250e569..34dc04b8d 100644 --- a/src/modules/math/MathModule.cpp +++ b/src/modules/math/MathModule.cpp @@ -25,6 +25,7 @@ #include "common/int.h" #include "common/StringMap.h" #include "BezierCurve.h" +#include "Transform.h" // STL #include @@ -374,6 +375,16 @@ BezierCurve *Math::newBezierCurve(const std::vector &points) return new BezierCurve(points); } +Transform *Math::newTransform() +{ + return new Transform(); +} + +Transform *Math::newTransform(float x, float y, float a, float sx, float sy, float ox, float oy, float kx, float ky) +{ + return new Transform(x, y, a, sx, sy, ox, oy, kx, ky); +} + std::string hash(HashFunction::Function function, Data *input) { return hash(function, (const char*) input->getData(), input->getSize()); diff --git a/src/modules/math/MathModule.h b/src/modules/math/MathModule.h index 8937308b4..027848010 100644 --- a/src/modules/math/MathModule.h +++ b/src/modules/math/MathModule.h @@ -45,6 +45,7 @@ namespace math { class BezierCurve; +class Transform; struct Triangle { @@ -176,6 +177,9 @@ public: **/ BezierCurve *newBezierCurve(const std::vector &points); + Transform *newTransform(); + Transform *newTransform(float x, float y, float a, float sx, float sy, float ox, float oy, float kx, float ky); + // Implements Module. virtual ModuleType getModuleType() const { diff --git a/src/modules/math/Transform.cpp b/src/modules/math/Transform.cpp new file mode 100644 index 000000000..e650692db --- /dev/null +++ b/src/modules/math/Transform.cpp @@ -0,0 +1,131 @@ +/** + * Copyright (c) 2006-2016 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#include "Transform.h" + +namespace love +{ +namespace math +{ + +Transform::Transform() + : matrix() + , inverseDirty(true) + , inverseMatrix() +{ +} + +Transform::Transform(const Matrix4 &m) + : matrix(m) + , inverseDirty(true) + , inverseMatrix() +{ +} + +Transform::Transform(float x, float y, float a, float sx, float sy, float ox, float oy, float kx, float ky) + : matrix(x, y, a, sx, sy, ox, oy, kx, ky) + , inverseDirty(true) + , inverseMatrix() +{ +} + +Transform::~Transform() +{ +} + +Transform *Transform::clone() +{ + return new Transform(*this); +} + +Transform *Transform::inverse() +{ + return new Transform(getInverseMatrix()); +} + +void Transform::apply(Transform *other) +{ + matrix *= other->getMatrix(); + inverseDirty = true; +} + +void Transform::translate(float x, float y) +{ + matrix.translate(x, y); + inverseDirty = true; +} + +void Transform::rotate(float angle) +{ + matrix.rotate(angle); + inverseDirty = true; +} + +void Transform::scale(float x, float y) +{ + matrix.scale(x, y); + inverseDirty = true; +} + +void Transform::shear(float x, float y) +{ + matrix.shear(x, y); + inverseDirty = true; +} + +void Transform::reset() +{ + matrix.setIdentity(); + inverseDirty = true; +} + +void Transform::setTransformation(float x, float y, float a, float sx, float sy, float ox, float oy, float kx, float ky) +{ + matrix.setTransformation(x, y, a, sx, sy, ox, oy, kx, ky); + inverseDirty = true; +} + +love::Vector Transform::transformPoint(love::Vector p) const +{ + love::Vector result; + matrix.transform(&result, &p, 1); + return result; +} + +love::Vector Transform::inverseTransformPoint(love::Vector p) +{ + love::Vector result; + getInverseMatrix().transform(&result, &p, 1); + return result; +} + +const Matrix4 &Transform::getMatrix() const +{ + return matrix; +} + +void Transform::setMatrix(const Matrix4 &m) +{ + matrix = m; + inverseDirty = true; +} + +} // math +} // love diff --git a/src/modules/math/Transform.h b/src/modules/math/Transform.h new file mode 100644 index 000000000..b70e62d60 --- /dev/null +++ b/src/modules/math/Transform.h @@ -0,0 +1,83 @@ +/** + * Copyright (c) 2006-2016 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#pragma once + +// LOVE +#include "common/Object.h" +#include "common/Matrix.h" +#include "common/Vector.h" + +namespace love +{ +namespace math +{ + +class Transform : public Object +{ +public: + + Transform(); + Transform(const Matrix4 &m); + Transform(float x, float y, float a, float sx, float sy, float ox, float oy, float kx, float ky); + + virtual ~Transform(); + + Transform *clone(); + Transform *inverse(); + + void apply(Transform *other); + + void translate(float x, float y); + void rotate(float angle); + void scale(float x, float y); + void shear(float x, float y); + + void reset(); + void setTransformation(float x, float y, float a, float sx, float sy, float ox, float oy, float kx, float ky); + + love::Vector transformPoint(love::Vector p) const; + love::Vector inverseTransformPoint(love::Vector p); + + const Matrix4 &getMatrix() const; + void setMatrix(const Matrix4 &m); + +private: + + inline const Matrix4 &getInverseMatrix() + { + if (inverseDirty) + { + inverseDirty = false; + inverseMatrix = matrix.inverse(); + } + + return inverseMatrix; + } + + Matrix4 matrix; + bool inverseDirty; + Matrix4 inverseMatrix; + +}; // Transform + + +} // math +} // love diff --git a/src/modules/math/wrap_Math.cpp b/src/modules/math/wrap_Math.cpp index c53531c96..341a30342 100644 --- a/src/modules/math/wrap_Math.cpp +++ b/src/modules/math/wrap_Math.cpp @@ -22,8 +22,10 @@ #include "wrap_RandomGenerator.h" #include "wrap_BezierCurve.h" #include "wrap_CompressedData.h" +#include "wrap_Transform.h" #include "MathModule.h" #include "BezierCurve.h" +#include "Transform.h" #include "common/b64.h" #include @@ -118,6 +120,31 @@ int w_newBezierCurve(lua_State *L) return 1; } +int w_newTransform(lua_State *L) +{ + Transform *t = nullptr; + + if (lua_isnoneornil(L, 1)) + t = Math::instance.newTransform(); + else + { + float x = (float) luaL_checknumber(L, 1); + float y = (float) luaL_checknumber(L, 2); + float a = (float) luaL_optnumber(L, 3, 0.0); + float sx = (float) luaL_optnumber(L, 4, 1.0); + float sy = (float) luaL_optnumber(L, 5, sx); + float ox = (float) luaL_optnumber(L, 6, 0.0); + float oy = (float) luaL_optnumber(L, 7, 0.0); + float kx = (float) luaL_optnumber(L, 8, 0.0); + float ky = (float) luaL_optnumber(L, 9, 0.0); + t = Math::instance.newTransform(x, y, a, sx, sy, ox, oy, kx, ky); + } + + luax_pushtype(L, MATH_TRANSFORM_ID, t); + t->release(); + return 1; +} + int w_triangulate(lua_State *L) { std::vector vertices; @@ -507,6 +534,7 @@ static const luaL_Reg functions[] = { "_getRandomGenerator", w__getRandomGenerator }, { "newRandomGenerator", w_newRandomGenerator }, { "newBezierCurve", w_newBezierCurve }, + { "newTransform", w_newTransform }, { "triangulate", w_triangulate }, { "isConvex", w_isConvex }, { "gammaToLinear", w_gammaToLinear }, @@ -525,6 +553,7 @@ static const lua_CFunction types[] = luaopen_randomgenerator, luaopen_beziercurve, luaopen_compresseddata, + luaopen_transform, 0 }; diff --git a/src/modules/math/wrap_Transform.cpp b/src/modules/math/wrap_Transform.cpp new file mode 100644 index 000000000..e9e96781b --- /dev/null +++ b/src/modules/math/wrap_Transform.cpp @@ -0,0 +1,305 @@ +/** + * Copyright (c) 2006-2016 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#include "wrap_Transform.h" + +namespace love +{ +namespace math +{ + +Transform *luax_checktransform(lua_State *L, int idx) +{ + return luax_checktype(L, idx, MATH_TRANSFORM_ID); +} + +int w_Transform_clone(lua_State *L) +{ + Transform *t = luax_checktransform(L, 1); + Transform *newtransform = t->clone(); + luax_pushtype(L, MATH_TRANSFORM_ID, newtransform); + newtransform->release(); + return 1; +} + +int w_Transform_inverse(lua_State *L) +{ + Transform *t = luax_checktransform(L, 1); + Transform *inverse = t->inverse(); + luax_pushtype(L, MATH_TRANSFORM_ID, inverse); + inverse->release(); + return 1; +} + +int w_Transform_apply(lua_State *L) +{ + Transform *t = luax_checktransform(L, 1); + Transform *other = luax_checktransform(L, 2); + t->apply(other); + lua_pushvalue(L, 1); + return 1; +} + +int w_Transform_translate(lua_State *L) +{ + Transform *t = luax_checktransform(L, 1); + float x = (float) luaL_checknumber(L, 2); + float y = (float) luaL_checknumber(L, 3); + t->translate(x, y); + lua_pushvalue(L, 1); + return 1; +} + +int w_Transform_rotate(lua_State *L) +{ + Transform *t = luax_checktransform(L, 1); + float angle = (float) luaL_checknumber(L, 2); + t->rotate(angle); + lua_pushvalue(L, 1); + return 1; +} + +int w_Transform_scale(lua_State *L) +{ + Transform *t = luax_checktransform(L, 1); + float sx = (float) luaL_checknumber(L, 2); + float sy = (float) luaL_optnumber(L, 3, sx); + t->scale(sx, sy); + lua_pushvalue(L, 1); + return 1; +} + +int w_Transform_shear(lua_State *L) +{ + Transform *t = luax_checktransform(L, 1); + float kx = (float) luaL_checknumber(L, 2); + float ky = (float) luaL_checknumber(L, 3); + t->shear(kx, ky); + lua_pushvalue(L, 1); + return 1; +} + +int w_Transform_reset(lua_State *L) +{ + Transform *t = luax_checktransform(L, 1); + t->reset(); + lua_pushvalue(L, 1); + return 1; +} + +int w_Transform_setTransformation(lua_State *L) +{ + Transform *t = luax_checktransform(L, 1); + float x = (float) luaL_optnumber(L, 2, 0.0); + float y = (float) luaL_optnumber(L, 3, 0.0); + float a = (float) luaL_optnumber(L, 4, 0.0); + float sx = (float) luaL_optnumber(L, 5, 1.0); + float sy = (float) luaL_optnumber(L, 6, sx); + float ox = (float) luaL_optnumber(L, 7, 0.0); + float oy = (float) luaL_optnumber(L, 8, 0.0); + float kx = (float) luaL_optnumber(L, 9, 0.0); + float ky = (float) luaL_optnumber(L, 10, 0.0); + t->setTransformation(x, y, a, sx, sy, ox, oy, kx, ky); + lua_pushvalue(L, 1); + return 1; +} + +int w_Transform_setMatrix(lua_State *L) +{ + Transform *t = luax_checktransform(L, 1); + + bool columnmajor = false; + + int idx = 2; + if (lua_isboolean(L, idx)) + { + columnmajor = lua_toboolean(L, idx); + idx++; + } + + float elements[16]; + + if (lua_istable(L, idx)) + { + lua_rawgeti(L, idx, 1); + bool tableoftables = lua_istable(L, -1); + lua_pop(L, 1); + + if (tableoftables) + { + if (columnmajor) + { + for (int column = 0; column < 4; column++) + { + lua_rawgeti(L, idx, column + 1); + + for (int row = 0; row < 4; row++) + { + lua_rawgeti(L, -(row + 1), row + 1); + elements[column * 4 + row] = (float) luaL_checknumber(L, -1); + } + + lua_pop(L, 4 + 1); + } + } + else + { + for (int row = 0; row < 4; row++) + { + lua_rawgeti(L, idx, row + 1); + + for (int column = 0; column < 4; column++) + { + // The table has the matrix elements laid out in row-major + // order, but we need to store them column-major in memory. + lua_rawgeti(L, -(column + 1), column + 1); + elements[column * 4 + row] = (float) luaL_checknumber(L, -1); + } + + lua_pop(L, 4 + 1); + } + } + } + else + { + if (columnmajor) + { + for (int column = 0; column < 4; column++) + { + for (int row = 0; row < 4; row++) + { + lua_rawgeti(L, idx, column * 4 + row + 1); + elements[column * 4 + row] = (float) luaL_checknumber(L, -1); + } + } + } + else + { + for (int column = 0; column < 4; column++) + { + for (int row = 0; row < 4; row++) + { + // The table has the matrix elements laid out in row-major + // order, but we need to store them column-major in memory. + lua_rawgeti(L, idx, row * 4 + column + 1); + elements[column * 4 + row] = (float) luaL_checknumber(L, -1); + } + } + } + + lua_pop(L, 16); + } + } + else + { + if (columnmajor) + { + for (int i = 0; i < 16; i++) + elements[i] = (float) luaL_checknumber(L, idx + i); + } + else + { + for (int column = 0; column < 4; column++) + { + for (int row = 0; row < 4; row++) + elements[column * 4 + row] = (float) luaL_checknumber(L, row * 4 + column + idx); + } + } + } + + t->setMatrix(Matrix4(elements)); + lua_pushvalue(L, 1); + return 1; +} + +int w_Transform_getMatrix(lua_State *L) +{ + Transform *t = luax_checktransform(L, 1); + const float *elements = t->getMatrix().getElements(); + + // We want to push elements in row-major order, but they're stored column- + // major. + for (int row = 0; row < 4; row++) + { + for (int column = 0; column < 4; column++) + lua_pushnumber(L, elements[column * 4 + row]); + } + + return 16; +} + +int w_Transform_transformPoint(lua_State *L) +{ + Transform *t = luax_checktransform(L, 1); + love::Vector p; + p.x = (float) luaL_checknumber(L, 2); + p.y = (float) luaL_checknumber(L, 3); + p = t->transformPoint(p); + lua_pushnumber(L, p.x); + lua_pushnumber(L, p.y); + return 2; +} + +int w_Transform_inverseTransformPoint(lua_State *L) +{ + Transform *t = luax_checktransform(L, 1); + love::Vector p; + p.x = (float) luaL_checknumber(L, 2); + p.y = (float) luaL_checknumber(L, 3); + p = t->inverseTransformPoint(p); + lua_pushnumber(L, p.x); + lua_pushnumber(L, p.y); + return 2; +} + +int w_Transform__mul(lua_State *L) +{ + Transform *t1 = luax_checktransform(L, 1); + Transform *t2 = luax_checktransform(L, 2); + Transform *t3 = new Transform(t1->getMatrix() * t2->getMatrix()); + luax_pushtype(L, MATH_TRANSFORM_ID, t3); + t3->release(); + return 1; +} + +static const luaL_Reg functions[] = +{ + { "clone", w_Transform_clone }, + { "inverse", w_Transform_inverse }, + { "apply", w_Transform_apply }, + { "translate", w_Transform_translate }, + { "rotate", w_Transform_rotate }, + { "scale", w_Transform_scale }, + { "shear", w_Transform_shear }, + { "reset", w_Transform_reset }, + { "setTransformation", w_Transform_setTransformation }, + { "transformPoint", w_Transform_transformPoint }, + { "inverseTransformPoint", w_Transform_inverseTransformPoint }, + { "__mul", w_Transform__mul }, + { 0, 0 } +}; + +extern "C" int luaopen_transform(lua_State *L) +{ + return luax_register_type(L, MATH_TRANSFORM_ID, "Transform", functions, nullptr); +} + +} // math +} // love diff --git a/src/modules/math/wrap_Transform.h b/src/modules/math/wrap_Transform.h new file mode 100644 index 000000000..1ad732c34 --- /dev/null +++ b/src/modules/math/wrap_Transform.h @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2006-2016 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#pragma once + +// LOVE +#include "Transform.h" +#include "common/runtime.h" + +namespace love +{ +namespace math +{ + +extern "C" int luaopen_transform(lua_State *L); + +} // math +} // love