From 4c122e65816473f4b59ce471bb9bd761fac79f33 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Thu, 20 Oct 2016 18:13:20 -0300 Subject: [PATCH] Add love.graphics.transformPoint and love.graphics.inverseTransformPoint. --HG-- branch : minor --- src/common/Matrix.cpp | 201 +++++++++++++++--- src/common/Matrix.h | 8 + src/modules/graphics/opengl/Graphics.cpp | 16 ++ src/modules/graphics/opengl/Graphics.h | 2 + src/modules/graphics/opengl/wrap_Graphics.cpp | 24 +++ 5 files changed, 218 insertions(+), 33 deletions(-) diff --git a/src/common/Matrix.cpp b/src/common/Matrix.cpp index 14cacba6e..a8483e1e5 100644 --- a/src/common/Matrix.cpp +++ b/src/common/Matrix.cpp @@ -27,6 +27,43 @@ namespace love { +// | e0 e4 e8 e12 | +// | e1 e5 e9 e13 | +// | e2 e6 e10 e14 | +// | e3 e7 e11 e15 | +// | e0 e4 e8 e12 | +// | e1 e5 e9 e13 | +// | e2 e6 e10 e14 | +// | e3 e7 e11 e15 | + +void Matrix4::multiply(const Matrix4 &a, const Matrix4 &b, float t[16]) +{ + t[0] = (a.e[0]*b.e[0]) + (a.e[4]*b.e[1]) + (a.e[8]*b.e[2]) + (a.e[12]*b.e[3]); + t[4] = (a.e[0]*b.e[4]) + (a.e[4]*b.e[5]) + (a.e[8]*b.e[6]) + (a.e[12]*b.e[7]); + t[8] = (a.e[0]*b.e[8]) + (a.e[4]*b.e[9]) + (a.e[8]*b.e[10]) + (a.e[12]*b.e[11]); + t[12] = (a.e[0]*b.e[12]) + (a.e[4]*b.e[13]) + (a.e[8]*b.e[14]) + (a.e[12]*b.e[15]); + + t[1] = (a.e[1]*b.e[0]) + (a.e[5]*b.e[1]) + (a.e[9]*b.e[2]) + (a.e[13]*b.e[3]); + t[5] = (a.e[1]*b.e[4]) + (a.e[5]*b.e[5]) + (a.e[9]*b.e[6]) + (a.e[13]*b.e[7]); + t[9] = (a.e[1]*b.e[8]) + (a.e[5]*b.e[9]) + (a.e[9]*b.e[10]) + (a.e[13]*b.e[11]); + t[13] = (a.e[1]*b.e[12]) + (a.e[5]*b.e[13]) + (a.e[9]*b.e[14]) + (a.e[13]*b.e[15]); + + t[2] = (a.e[2]*b.e[0]) + (a.e[6]*b.e[1]) + (a.e[10]*b.e[2]) + (a.e[14]*b.e[3]); + t[6] = (a.e[2]*b.e[4]) + (a.e[6]*b.e[5]) + (a.e[10]*b.e[6]) + (a.e[14]*b.e[7]); + t[10] = (a.e[2]*b.e[8]) + (a.e[6]*b.e[9]) + (a.e[10]*b.e[10]) + (a.e[14]*b.e[11]); + t[14] = (a.e[2]*b.e[12]) + (a.e[6]*b.e[13]) + (a.e[10]*b.e[14]) + (a.e[14]*b.e[15]); + + t[3] = (a.e[3]*b.e[0]) + (a.e[7]*b.e[1]) + (a.e[11]*b.e[2]) + (a.e[15]*b.e[3]); + t[7] = (a.e[3]*b.e[4]) + (a.e[7]*b.e[5]) + (a.e[11]*b.e[6]) + (a.e[15]*b.e[7]); + t[11] = (a.e[3]*b.e[8]) + (a.e[7]*b.e[9]) + (a.e[11]*b.e[10]) + (a.e[15]*b.e[11]); + t[15] = (a.e[3]*b.e[12]) + (a.e[7]*b.e[13]) + (a.e[11]*b.e[14]) + (a.e[15]*b.e[15]); +} + +void Matrix4::multiply(const Matrix4 &a, const Matrix4 &b, Matrix4 &t) +{ + multiply(a, b, t.e); +} + // | e0 e4 e8 e12 | // | e1 e5 e9 e13 | // | e2 e6 e10 e14 | @@ -46,46 +83,18 @@ Matrix4::~Matrix4() { } -// | e0 e4 e8 e12 | -// | e1 e5 e9 e13 | -// | e2 e6 e10 e14 | -// | e3 e7 e11 e15 | -// | e0 e4 e8 e12 | -// | e1 e5 e9 e13 | -// | e2 e6 e10 e14 | -// | e3 e7 e11 e15 | - Matrix4 Matrix4::operator * (const Matrix4 &m) const { Matrix4 t; - - t.e[0] = (e[0]*m.e[0]) + (e[4]*m.e[1]) + (e[8]*m.e[2]) + (e[12]*m.e[3]); - t.e[4] = (e[0]*m.e[4]) + (e[4]*m.e[5]) + (e[8]*m.e[6]) + (e[12]*m.e[7]); - t.e[8] = (e[0]*m.e[8]) + (e[4]*m.e[9]) + (e[8]*m.e[10]) + (e[12]*m.e[11]); - t.e[12] = (e[0]*m.e[12]) + (e[4]*m.e[13]) + (e[8]*m.e[14]) + (e[12]*m.e[15]); - - t.e[1] = (e[1]*m.e[0]) + (e[5]*m.e[1]) + (e[9]*m.e[2]) + (e[13]*m.e[3]); - t.e[5] = (e[1]*m.e[4]) + (e[5]*m.e[5]) + (e[9]*m.e[6]) + (e[13]*m.e[7]); - t.e[9] = (e[1]*m.e[8]) + (e[5]*m.e[9]) + (e[9]*m.e[10]) + (e[13]*m.e[11]); - t.e[13] = (e[1]*m.e[12]) + (e[5]*m.e[13]) + (e[9]*m.e[14]) + (e[13]*m.e[15]); - - t.e[2] = (e[2]*m.e[0]) + (e[6]*m.e[1]) + (e[10]*m.e[2]) + (e[14]*m.e[3]); - t.e[6] = (e[2]*m.e[4]) + (e[6]*m.e[5]) + (e[10]*m.e[6]) + (e[14]*m.e[7]); - t.e[10] = (e[2]*m.e[8]) + (e[6]*m.e[9]) + (e[10]*m.e[10]) + (e[14]*m.e[11]); - t.e[14] = (e[2]*m.e[12]) + (e[6]*m.e[13]) + (e[10]*m.e[14]) + (e[14]*m.e[15]); - - t.e[3] = (e[3]*m.e[0]) + (e[7]*m.e[1]) + (e[11]*m.e[2]) + (e[15]*m.e[3]); - t.e[7] = (e[3]*m.e[4]) + (e[7]*m.e[5]) + (e[11]*m.e[6]) + (e[15]*m.e[7]); - t.e[11] = (e[3]*m.e[8]) + (e[7]*m.e[9]) + (e[11]*m.e[10]) + (e[15]*m.e[11]); - t.e[15] = (e[3]*m.e[12]) + (e[7]*m.e[13]) + (e[11]*m.e[14]) + (e[15]*m.e[15]); - + multiply(*this, m, t); return t; } void Matrix4::operator *= (const Matrix4 &m) { - Matrix4 t = (*this) * m; - memcpy(this->e, t.e, sizeof(float)*16); + float t[16]; + multiply(*this, m, t); + memcpy(this->e, t, sizeof(float)*16); } const float *Matrix4::getElements() const @@ -96,7 +105,7 @@ const float *Matrix4::getElements() const void Matrix4::setIdentity() { memset(e, 0, sizeof(float)*16); - e[0] = e[5] = e[10] = e[15] = 1; + e[15] = e[10] = e[5] = e[0] = 1; } void Matrix4::setTranslation(float x, float y) @@ -177,6 +186,132 @@ void Matrix4::shear(float kx, float ky) this->operator *=(t); } +Matrix4 Matrix4::inverse() const +{ + Matrix4 inv; + + inv.e[0] = e[5] * e[10] * e[15] - + e[5] * e[11] * e[14] - + e[9] * e[6] * e[15] + + e[9] * e[7] * e[14] + + e[13] * e[6] * e[11] - + e[13] * e[7] * e[10]; + + inv.e[4] = -e[4] * e[10] * e[15] + + e[4] * e[11] * e[14] + + e[8] * e[6] * e[15] - + e[8] * e[7] * e[14] - + e[12] * e[6] * e[11] + + e[12] * e[7] * e[10]; + + inv.e[8] = e[4] * e[9] * e[15] - + e[4] * e[11] * e[13] - + e[8] * e[5] * e[15] + + e[8] * e[7] * e[13] + + e[12] * e[5] * e[11] - + e[12] * e[7] * e[9]; + + inv.e[12] = -e[4] * e[9] * e[14] + + e[4] * e[10] * e[13] + + e[8] * e[5] * e[14] - + e[8] * e[6] * e[13] - + e[12] * e[5] * e[10] + + e[12] * e[6] * e[9]; + + inv.e[1] = -e[1] * e[10] * e[15] + + e[1] * e[11] * e[14] + + e[9] * e[2] * e[15] - + e[9] * e[3] * e[14] - + e[13] * e[2] * e[11] + + e[13] * e[3] * e[10]; + + inv.e[5] = e[0] * e[10] * e[15] - + e[0] * e[11] * e[14] - + e[8] * e[2] * e[15] + + e[8] * e[3] * e[14] + + e[12] * e[2] * e[11] - + e[12] * e[3] * e[10]; + + inv.e[9] = -e[0] * e[9] * e[15] + + e[0] * e[11] * e[13] + + e[8] * e[1] * e[15] - + e[8] * e[3] * e[13] - + e[12] * e[1] * e[11] + + e[12] * e[3] * e[9]; + + inv.e[13] = e[0] * e[9] * e[14] - + e[0] * e[10] * e[13] - + e[8] * e[1] * e[14] + + e[8] * e[2] * e[13] + + e[12] * e[1] * e[10] - + e[12] * e[2] * e[9]; + + inv.e[2] = e[1] * e[6] * e[15] - + e[1] * e[7] * e[14] - + e[5] * e[2] * e[15] + + e[5] * e[3] * e[14] + + e[13] * e[2] * e[7] - + e[13] * e[3] * e[6]; + + inv.e[6] = -e[0] * e[6] * e[15] + + e[0] * e[7] * e[14] + + e[4] * e[2] * e[15] - + e[4] * e[3] * e[14] - + e[12] * e[2] * e[7] + + e[12] * e[3] * e[6]; + + inv.e[10] = e[0] * e[5] * e[15] - + e[0] * e[7] * e[13] - + e[4] * e[1] * e[15] + + e[4] * e[3] * e[13] + + e[12] * e[1] * e[7] - + e[12] * e[3] * e[5]; + + inv.e[14] = -e[0] * e[5] * e[14] + + e[0] * e[6] * e[13] + + e[4] * e[1] * e[14] - + e[4] * e[2] * e[13] - + e[12] * e[1] * e[6] + + e[12] * e[2] * e[5]; + + inv.e[3] = -e[1] * e[6] * e[11] + + e[1] * e[7] * e[10] + + e[5] * e[2] * e[11] - + e[5] * e[3] * e[10] - + e[9] * e[2] * e[7] + + e[9] * e[3] * e[6]; + + inv.e[7] = e[0] * e[6] * e[11] - + e[0] * e[7] * e[10] - + e[4] * e[2] * e[11] + + e[4] * e[3] * e[10] + + e[8] * e[2] * e[7] - + e[8] * e[3] * e[6]; + + inv.e[11] = -e[0] * e[5] * e[11] + + e[0] * e[7] * e[9] + + e[4] * e[1] * e[11] - + e[4] * e[3] * e[9] - + e[8] * e[1] * e[7] + + e[8] * e[3] * e[5]; + + inv.e[15] = e[0] * e[5] * e[10] - + e[0] * e[6] * e[9] - + e[4] * e[1] * e[10] + + e[4] * e[2] * e[9] + + e[8] * e[1] * e[6] - + e[8] * e[2] * e[5]; + + float det = e[0] * inv.e[0] + e[1] * inv.e[4] + e[2] * inv.e[8] + e[3] * inv.e[12]; + + float invdet = 1.0f / det; + + for (int i = 0; i < 16; i++) + inv.e[i] *= invdet; + + return inv; +} + Matrix4 Matrix4::ortho(float left, float right, float bottom, float top) { Matrix4 m; diff --git a/src/common/Matrix.h b/src/common/Matrix.h index 406d49328..ba91e2308 100644 --- a/src/common/Matrix.h +++ b/src/common/Matrix.h @@ -34,8 +34,14 @@ namespace love **/ class Matrix4 { +private: + + static void multiply(const Matrix4 &a, const Matrix4 &b, float t[16]); + public: + static void multiply(const Matrix4 &a, const Matrix4 &b, Matrix4 &result); + /** * Creates a new identity matrix. **/ @@ -156,6 +162,8 @@ public: template void transform(V *dst, const V *src, int size) const; + Matrix4 inverse() const; + /** * Creates a new orthographic projection matrix with depth in the range of * [-1, 1]. diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 7c5c68ae8..2ce372fbc 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -1789,6 +1789,22 @@ void Graphics::origin() pixelSizeStack.back() = 1; } +Vector Graphics::transformPoint(Vector point) +{ + Vector p; + gl.getTransform().transform(&p, &point, 1); + return p; +} + +Vector Graphics::inverseTransformPoint(Vector point) +{ + Vector p; + // TODO: We should probably cache the inverse transform so we don't have to + // re-calculate it every time this is called. + gl.getTransform().inverse().transform(&p, &point, 1); + return p; +} + } // opengl } // graphics } // love diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index 2a4e0ecb8..138858103 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -459,6 +459,8 @@ public: void translate(float x, float y); void shear(float kx, float ky); void origin(); + Vector transformPoint(Vector point); + Vector inverseTransformPoint(Vector point); private: diff --git a/src/modules/graphics/opengl/wrap_Graphics.cpp b/src/modules/graphics/opengl/wrap_Graphics.cpp index db7d3eb3b..99ee0e37b 100644 --- a/src/modules/graphics/opengl/wrap_Graphics.cpp +++ b/src/modules/graphics/opengl/wrap_Graphics.cpp @@ -1960,6 +1960,28 @@ int w_origin(lua_State * /*L*/) return 0; } +int w_transformPoint(lua_State *L) +{ + Vector p; + p.x = (float) luaL_checknumber(L, 1); + p.y = (float) luaL_checknumber(L, 2); + p = instance()->transformPoint(p); + lua_pushnumber(L, p.x); + lua_pushnumber(L, p.y); + return 2; +} + +int w_inverseTransformPoint(lua_State *L) +{ + Vector p; + p.x = (float) luaL_checknumber(L, 1); + p.y = (float) luaL_checknumber(L, 2); + p = instance()->inverseTransformPoint(p); + lua_pushnumber(L, p.x); + lua_pushnumber(L, p.y); + return 2; +} + // List of functions to wrap. static const luaL_Reg functions[] = @@ -2060,6 +2082,8 @@ static const luaL_Reg functions[] = { "translate", w_translate }, { "shear", w_shear }, { "origin", w_origin }, + { "transformPoint", w_transformPoint }, + { "inverseTransformPoint", w_inverseTransformPoint }, { 0, 0 } };