diff --git a/Makefile b/Makefile
index 22030da47c..43c968ec2f 100644
--- a/Makefile
+++ b/Makefile
@@ -180,7 +180,7 @@ ifeq ($(HAVE_SDL), 1)
endif
ifeq ($(HAVE_VG), 1)
- OBJ += gfx/vg.o
+ OBJ += gfx/vg.o gfx/math/matrix_3x3.o
DEFINES += $(VG_CFLAGS)
LIBS += $(VG_LIBS)
endif
diff --git a/gfx/math/matrix_3x3.c b/gfx/math/matrix_3x3.c
new file mode 100644
index 0000000000..fdadab2ef0
--- /dev/null
+++ b/gfx/math/matrix_3x3.c
@@ -0,0 +1,234 @@
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2010-2012 - Hans-Kristian Arntzen
+ * Copyright (C) 2012 - Michael Lelli
+ *
+ * RetroArch is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with RetroArch.
+ * If not, see .
+ */
+
+#include "matrix_3x3.h"
+#include
+#include
+
+#define floatsEqual(x, y) (fabs(x - y) <= 0.00001f * ((x) > (y) ? (y) : (x)))
+#define floatIsZero(x) (floatsEqual((x) + 1, 1))
+
+void matrix_3x3_identity(math_matrix_3x3 *mat)
+{
+ memset(mat, 0, sizeof(*mat));
+ for (unsigned i = 0; i < 3; i++)
+ MAT_ELEM_3X3(*mat, i, i) = 1.0f;
+}
+
+void matrix_3x3_inits(math_matrix_3x3 *mat,
+ const float n11, const float n12, const float n13,
+ const float n21, const float n22, const float n23,
+ const float n31, const float n32, const float n33)
+{
+ MAT_ELEM_3X3(*mat, 0, 0) = n11;
+ MAT_ELEM_3X3(*mat, 0, 1) = n12;
+ MAT_ELEM_3X3(*mat, 0, 2) = n13;
+ MAT_ELEM_3X3(*mat, 1, 0) = n21;
+ MAT_ELEM_3X3(*mat, 1, 1) = n22;
+ MAT_ELEM_3X3(*mat, 1, 2) = n23;
+ MAT_ELEM_3X3(*mat, 2, 0) = n31;
+ MAT_ELEM_3X3(*mat, 2, 1) = n32;
+ MAT_ELEM_3X3(*mat, 2, 2) = n33;
+}
+
+void matrix_3x3_transpose(math_matrix_3x3 *out, const math_matrix_3x3 *in)
+{
+ math_matrix_3x3 mat;
+ for (unsigned i = 0; i < 3; i++)
+ for (unsigned j = 0; j < 3; j++)
+ MAT_ELEM_3X3(mat, j, i) = MAT_ELEM_3X3(*in, i, j);
+
+ *out = mat;
+}
+
+void matrix_3x3_multiply(math_matrix_3x3 *out,
+ const math_matrix_3x3 *a, const math_matrix_3x3 *b)
+{
+ math_matrix_3x3 mat;
+ for (unsigned r = 0; r < 3; r++)
+ {
+ for (unsigned c = 0; c < 3; c++)
+ {
+ float dot = 0.0f;
+ for (unsigned k = 0; k < 3; k++)
+ dot += MAT_ELEM_3X3(*a, r, k) * MAT_ELEM_3X3(*b, k, c);
+ MAT_ELEM_3X3(mat, r, c) = dot;
+ }
+ }
+
+ *out = mat;
+}
+
+void matrix_3x3_divide_scalar(math_matrix_3x3 *mat, const float s)
+{
+ for (unsigned i = 0; i < 3; i++)
+ for (unsigned j = 0; j < 3; j++)
+ MAT_ELEM_3X3(*mat, i, j) /= s;
+}
+
+float matrix_3x3_determinant(const math_matrix_3x3 *mat)
+{
+ float det = MAT_ELEM_3X3(*mat, 0, 0) * (MAT_ELEM_3X3(*mat, 1, 1) * MAT_ELEM_3X3(*mat, 2, 2) - MAT_ELEM_3X3(*mat, 1, 2) * MAT_ELEM_3X3(*mat, 2, 1));
+ det -= MAT_ELEM_3X3(*mat, 0, 1) * (MAT_ELEM_3X3(*mat, 1, 0) * MAT_ELEM_3X3(*mat, 2, 2) - MAT_ELEM_3X3(*mat, 1, 2) * MAT_ELEM_3X3(*mat, 2, 0));
+ det += MAT_ELEM_3X3(*mat, 0, 2) * (MAT_ELEM_3X3(*mat, 1, 0) * MAT_ELEM_3X3(*mat, 2, 1) - MAT_ELEM_3X3(*mat, 1, 1) * MAT_ELEM_3X3(*mat, 2, 0));
+
+ return det;
+}
+
+void matrix_3x3_adjoint(math_matrix_3x3 *mat)
+{
+ math_matrix_3x3 out;
+
+ MAT_ELEM_3X3(out, 0, 0) = (MAT_ELEM_3X3(*mat, 1, 1) * MAT_ELEM_3X3(*mat, 2, 2) - MAT_ELEM_3X3(*mat, 1, 2) * MAT_ELEM_3X3(*mat, 2, 1));
+ MAT_ELEM_3X3(out, 0, 1) = -(MAT_ELEM_3X3(*mat, 0, 1) * MAT_ELEM_3X3(*mat, 2, 2) - MAT_ELEM_3X3(*mat, 0, 2) * MAT_ELEM_3X3(*mat, 2, 1));
+ MAT_ELEM_3X3(out, 0, 2) = (MAT_ELEM_3X3(*mat, 0, 1) * MAT_ELEM_3X3(*mat, 1, 1) - MAT_ELEM_3X3(*mat, 0, 2) * MAT_ELEM_3X3(*mat, 1, 1));
+ MAT_ELEM_3X3(out, 1, 0) = -(MAT_ELEM_3X3(*mat, 1, 0) * MAT_ELEM_3X3(*mat, 2, 2) - MAT_ELEM_3X3(*mat, 1, 2) * MAT_ELEM_3X3(*mat, 2, 0));
+ MAT_ELEM_3X3(out, 1, 1) = (MAT_ELEM_3X3(*mat, 0, 0) * MAT_ELEM_3X3(*mat, 2, 2) - MAT_ELEM_3X3(*mat, 0, 2) * MAT_ELEM_3X3(*mat, 2, 0));
+ MAT_ELEM_3X3(out, 1, 2) = -(MAT_ELEM_3X3(*mat, 0, 0) * MAT_ELEM_3X3(*mat, 1, 2) - MAT_ELEM_3X3(*mat, 0, 2) * MAT_ELEM_3X3(*mat, 1, 0));
+ MAT_ELEM_3X3(out, 2, 0) = (MAT_ELEM_3X3(*mat, 1, 0) * MAT_ELEM_3X3(*mat, 2, 1) - MAT_ELEM_3X3(*mat, 1, 1) * MAT_ELEM_3X3(*mat, 2, 0));
+ MAT_ELEM_3X3(out, 2, 1) = -(MAT_ELEM_3X3(*mat, 0, 0) * MAT_ELEM_3X3(*mat, 2, 1) - MAT_ELEM_3X3(*mat, 0, 1) * MAT_ELEM_3X3(*mat, 2, 0));
+ MAT_ELEM_3X3(out, 2, 2) = (MAT_ELEM_3X3(*mat, 0, 0) * MAT_ELEM_3X3(*mat, 1, 1) - MAT_ELEM_3X3(*mat, 0, 1) * MAT_ELEM_3X3(*mat, 1, 0));
+
+ *mat = out;
+}
+
+bool matrix_3x3_invert(math_matrix_3x3 *mat)
+{
+ float det = matrix_3x3_determinant(mat);
+
+ if (floatIsZero(det))
+ return false;
+
+ matrix_3x3_adjoint(mat);
+ matrix_3x3_divide_scalar(mat, det);
+ return true;
+}
+
+/**************************************************************************
+ *
+ * the following code is Copyright 2009 VMware, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+bool matrix_3x3_square_to_quad(const float dx0, const float dy0,
+ const float dx1, const float dy1,
+ const float dx3, const float dy3,
+ const float dx2, const float dy2,
+ math_matrix_3x3 *mat)
+{
+ float ax = dx0 - dx1 + dx2 - dx3;
+ float ay = dy0 - dy1 + dy2 - dy3;
+
+ if (floatIsZero(ax) && floatIsZero(ay)) {
+ /* affine case */
+ matrix_3x3_inits(mat,
+ dx1 - dx0, dy1 - dy0, 0,
+ dx2 - dx1, dy2 - dy1, 0,
+ dx0, dy0, 1);
+ } else {
+ float a, b, c, d, e, f, g, h;
+ float ax1 = dx1 - dx2;
+ float ax2 = dx3 - dx2;
+ float ay1 = dy1 - dy2;
+ float ay2 = dy3 - dy2;
+
+ /* determinants */
+ float gtop = ax * ay2 - ax2 * ay;
+ float htop = ax1 * ay - ax * ay1;
+ float bottom = ax1 * ay2 - ax2 * ay1;
+
+ if (!bottom)
+ return false;
+
+ g = gtop / bottom;
+ h = htop / bottom;
+
+ a = dx1 - dx0 + g * dx1;
+ b = dx3 - dx0 + h * dx3;
+ c = dx0;
+ d = dy1 - dy0 + g * dy1;
+ e = dy3 - dy0 + h * dy3;
+ f = dy0;
+
+ matrix_3x3_inits(mat,
+ a, d, g,
+ b, e, h,
+ c, f, 1.f);
+ }
+
+ return true;
+}
+
+bool matrix_3x3_quad_to_square(const float sx0, const float sy0,
+ const float sx1, const float sy1,
+ const float sx2, const float sy2,
+ const float sx3, const float sy3,
+ math_matrix_3x3 *mat)
+{
+ if (!matrix_3x3_square_to_quad(sx0, sy0, sx1, sy1,
+ sx2, sy2, sx3, sy3,
+ mat))
+ return false;
+
+ return matrix_3x3_invert(mat);
+}
+
+bool matrix_3x3_quad_to_quad(const float dx0, const float dy0,
+ const float dx1, const float dy1,
+ const float dx2, const float dy2,
+ const float dx3, const float dy3,
+ const float sx0, const float sy0,
+ const float sx1, const float sy1,
+ const float sx2, const float sy2,
+ const float sx3, const float sy3,
+ math_matrix_3x3 *mat)
+{
+ math_matrix_3x3 quad_to_square, square_to_quad;
+
+ if (!matrix_3x3_square_to_quad(dx0, dy0, dx1, dy1,
+ dx2, dy2, dx3, dy3,
+ &square_to_quad))
+ return false;
+
+ if (!matrix_3x3_quad_to_square(sx0, sy0, sx1, sy1,
+ sx2, sy2, sx3, sy3,
+ &quad_to_square))
+ return false;
+
+ matrix_3x3_multiply(mat, &quad_to_square, &square_to_quad);
+
+ return true;
+}
diff --git a/gfx/math/matrix_3x3.h b/gfx/math/matrix_3x3.h
new file mode 100644
index 0000000000..042275341a
--- /dev/null
+++ b/gfx/math/matrix_3x3.h
@@ -0,0 +1,63 @@
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2010-2012 - Hans-Kristian Arntzen
+ * Copyright (C) 2012 - Michael Lelli
+ *
+ * RetroArch is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with RetroArch.
+ * If not, see .
+ */
+
+#ifndef MATH_MATRIX_3X3_H__
+#define MATH_MATRIX_3X3_H__
+
+#include "boolean.h"
+
+typedef struct math_matrix_3x3
+{
+ float data[9];
+} math_matrix_3x3;
+
+#define MAT_ELEM_3X3(mat, r, c) ((mat).data[3 * (r) + (c)])
+
+void matrix_3x3_inits(math_matrix_3x3 *mat,
+ const float n11, const float n12, const float n13,
+ const float n21, const float n22, const float n23,
+ const float n31, const float n32, const float n33);
+void matrix_3x3_identity(math_matrix_3x3 *mat);
+void matrix_3x3_transpose(math_matrix_3x3 *out, const math_matrix_3x3 *in);
+
+void matrix_3x3_multiply(math_matrix_3x3 *out,
+ const math_matrix_3x3 *a, const math_matrix_3x3 *b);
+void matrix_3x3_divide_scalar(math_matrix_3x3 *mat, float s);
+float matrix_3x3_determinant(const math_matrix_3x3 *mat);
+void matrix_3x3_adjoint(math_matrix_3x3 *mat);
+bool matrix_3x3_invert(math_matrix_3x3 *mat);
+
+bool matrix_3x3_square_to_quad(const float dx0, const float dy0,
+ const float dx1, const float dy1,
+ const float dx3, const float dy3,
+ const float dx2, const float dy2,
+ math_matrix_3x3 *mat);
+bool matrix_3x3_quad_to_square(const float sx0, const float sy0,
+ const float sx1, const float sy1,
+ const float sx2, const float sy2,
+ const float sx3, const float sy3,
+ math_matrix_3x3 *mat);
+bool matrix_3x3_quad_to_quad(const float dx0, const float dy0,
+ const float dx1, const float dy1,
+ const float dx2, const float dy2,
+ const float dx3, const float dy3,
+ const float sx0, const float sy0,
+ const float sx1, const float sy1,
+ const float sx2, const float sy2,
+ const float sx3, const float sy3,
+ math_matrix_3x3 *mat);
+
+#endif
diff --git a/gfx/vg.c b/gfx/vg.c
index c87e2d4324..ba2539bbb7 100644
--- a/gfx/vg.c
+++ b/gfx/vg.c
@@ -16,9 +16,9 @@
#include
#include
-#include
#include
#include "gfx_context.h"
+#include "math/matrix_3x3.h"
#include "../libretro.h"
#include "../general.h"
#include "../driver.h"
@@ -42,7 +42,7 @@ typedef struct
unsigned frame_count;
VGImageFormat mTexType;
VGImage mImage;
- VGfloat mTransformMatrix[9];
+ math_matrix_3x3 mTransformMatrix;
VGint scissor[4];
#ifdef HAVE_FREETYPE
@@ -300,13 +300,13 @@ static bool vg_frame(void *data, const void *frame, unsigned width, unsigned hei
vg->mRenderWidth = width;
vg->mRenderHeight = height;
vg_calculate_quad(vg);
- vguComputeWarpQuadToQuad(
+ matrix_3x3_quad_to_quad(
vg->x1, vg->y1, vg->x2, vg->y1, vg->x2, vg->y2, vg->x1, vg->y2,
// needs to be flipped, Khronos loves their bottom-left origin
0, height, width, height, width, 0, 0, 0,
- vg->mTransformMatrix);
+ &vg->mTransformMatrix);
vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
- vgLoadMatrix(vg->mTransformMatrix);
+ vgLoadMatrix(vg->mTransformMatrix.data);
}
vgSeti(VG_SCISSORING, VG_FALSE);
vgClear(0, 0, vg->mScreenWidth, vg->mScreenHeight);