eina_matrix: Add eina_matrix4 operator(translate, rotate, scale)

Summary:
Add an operator related to the 3D transform in eina_matrix.

enum eina_matrix_axis
  EINA_MATRIX_AXIS_X
  EINA_MATRIX_AXIS_Y
  EINA_MATRIX_AXIS_Z
eina_matrix4_translate
eina_matrix4_scale
eina_matrix4_rotate
eina_matrix4_transpose

Test Plan: src/tests/eina/eina_test_matrix.c

Reviewers: Hermet, bu5hm4n, kimcinoo, segfaultxavi

Reviewed By: segfaultxavi

Subscribers: cedric, #reviewers, #committers

Tags: #efl

Differential Revision: https://phab.enlightenment.org/D11159
This commit is contained in:
junsu choi 2020-01-29 14:56:05 +09:00
parent b8f5d12d4e
commit d1660bdfe5
3 changed files with 358 additions and 35 deletions

View File

@ -1033,41 +1033,7 @@ eina_matrix4_multiply(Eina_Matrix4 *out, const Eina_Matrix4 *mat_a,
return;
}
MATRIX_XX(out) = MATRIX_XX(mat_a) * MATRIX_XX(mat_b) + MATRIX_YX(mat_a) * MATRIX_XY(mat_b) +
MATRIX_ZX(mat_a) * MATRIX_XZ(mat_b) + MATRIX_WX(mat_a) * MATRIX_XW(mat_b);
MATRIX_YX(out) = MATRIX_XX(mat_a) * MATRIX_YX(mat_b) + MATRIX_YX(mat_a) * MATRIX_YY(mat_b) +
MATRIX_ZX(mat_a) * MATRIX_YZ(mat_b) + MATRIX_WX(mat_a) * MATRIX_YW(mat_b);
MATRIX_ZX(out) = MATRIX_XX(mat_a) * MATRIX_ZX(mat_b) + MATRIX_YX(mat_a) * MATRIX_ZY(mat_b) +
MATRIX_ZX(mat_a) * MATRIX_ZZ(mat_b) + MATRIX_WX(mat_a) * MATRIX_ZW(mat_b);
MATRIX_WX(out) = MATRIX_XX(mat_a) * MATRIX_WX(mat_b) + MATRIX_YX(mat_a) * MATRIX_WY(mat_b) +
MATRIX_ZX(mat_a) * MATRIX_WZ(mat_b) + MATRIX_WX(mat_a) * MATRIX_WW(mat_b);
MATRIX_XY(out) = MATRIX_XY(mat_a) * MATRIX_XX(mat_b) + MATRIX_YY(mat_a) * MATRIX_XY(mat_b) +
MATRIX_ZY(mat_a) * MATRIX_XZ(mat_b) + MATRIX_WY(mat_a) * MATRIX_XW(mat_b);
MATRIX_YY(out) = MATRIX_XY(mat_a) * MATRIX_YX(mat_b) + MATRIX_YY(mat_a) * MATRIX_YY(mat_b) +
MATRIX_ZY(mat_a) * MATRIX_YZ(mat_b) + MATRIX_WY(mat_a) * MATRIX_YW(mat_b);
MATRIX_ZY(out) = MATRIX_XY(mat_a) * MATRIX_ZX(mat_b) + MATRIX_YY(mat_a) * MATRIX_ZY(mat_b) +
MATRIX_ZY(mat_a) * MATRIX_ZZ(mat_b) + MATRIX_WY(mat_a) * MATRIX_ZW(mat_b);
MATRIX_WY(out) = MATRIX_XY(mat_a) * MATRIX_WX(mat_b) + MATRIX_YY(mat_a) * MATRIX_WY(mat_b) +
MATRIX_ZY(mat_a) * MATRIX_WZ(mat_b) + MATRIX_WY(mat_a) * MATRIX_WW(mat_b);
MATRIX_XZ(out) = MATRIX_XZ(mat_a) * MATRIX_XX(mat_b) + MATRIX_YZ(mat_a) * MATRIX_XY(mat_b) +
MATRIX_ZZ(mat_a) * MATRIX_XZ(mat_b) + MATRIX_WZ(mat_a) * MATRIX_XW(mat_b);
MATRIX_YZ(out) = MATRIX_XZ(mat_a) * MATRIX_YX(mat_b) + MATRIX_YZ(mat_a) * MATRIX_YY(mat_b) +
MATRIX_ZZ(mat_a) * MATRIX_YZ(mat_b) + MATRIX_WZ(mat_a) * MATRIX_YW(mat_b);
MATRIX_ZZ(out) = MATRIX_XZ(mat_a) * MATRIX_ZX(mat_b) + MATRIX_YZ(mat_a) * MATRIX_ZY(mat_b) +
MATRIX_ZZ(mat_a) * MATRIX_ZZ(mat_b) + MATRIX_WZ(mat_a) * MATRIX_ZW(mat_b);
MATRIX_WZ(out) = MATRIX_XZ(mat_a) * MATRIX_WX(mat_b) + MATRIX_YZ(mat_a) * MATRIX_WY(mat_b) +
MATRIX_ZZ(mat_a) * MATRIX_WZ(mat_b) + MATRIX_WZ(mat_a) * MATRIX_WW(mat_b);
MATRIX_XW(out) = MATRIX_XW(mat_a) * MATRIX_XX(mat_b) + MATRIX_YW(mat_a) * MATRIX_XY(mat_b) +
MATRIX_ZW(mat_a) * MATRIX_XZ(mat_b) + MATRIX_WW(mat_a) * MATRIX_XW(mat_b);
MATRIX_YW(out) = MATRIX_XW(mat_a) * MATRIX_YX(mat_b) + MATRIX_YW(mat_a) * MATRIX_YY(mat_b) +
MATRIX_ZW(mat_a) * MATRIX_YZ(mat_b) + MATRIX_WW(mat_a) * MATRIX_YW(mat_b);
MATRIX_ZW(out) = MATRIX_XW(mat_a) * MATRIX_ZX(mat_b) + MATRIX_YW(mat_a) * MATRIX_ZY(mat_b) +
MATRIX_ZW(mat_a) * MATRIX_ZZ(mat_b) + MATRIX_WW(mat_a) * MATRIX_ZW(mat_b);
MATRIX_WW(out) = MATRIX_XW(mat_a) * MATRIX_WX(mat_b) + MATRIX_YW(mat_a) * MATRIX_WY(mat_b) +
MATRIX_ZW(mat_a) * MATRIX_WZ(mat_b) + MATRIX_WW(mat_a) * MATRIX_WW(mat_b);
eina_matrix4_compose(mat_a, mat_b, out);
}
EAPI void
@ -1100,6 +1066,176 @@ eina_matrix4_ortho_set(Eina_Matrix4 *m,
MATRIX_WW(m) = 1.0f;
}
EAPI void
eina_matrix4_compose(const Eina_Matrix4 *mat_a,
const Eina_Matrix4 *mat_b,
Eina_Matrix4 *out)
{
double xx, xy, xz, xw,
yx, yy, yz, yw,
zx, zy, zz, zw,
wx, wy, wz, ww;
xx = MATRIX_XX(mat_a) * MATRIX_XX(mat_b) + MATRIX_XY(mat_a) * MATRIX_YX(mat_b) +
MATRIX_XZ(mat_a) * MATRIX_ZX(mat_b) + MATRIX_XW(mat_a) * MATRIX_WX(mat_b);
xy = MATRIX_XX(mat_a) * MATRIX_XY(mat_b) + MATRIX_XY(mat_a) * MATRIX_YY(mat_b) +
MATRIX_XZ(mat_a) * MATRIX_ZY(mat_b) + MATRIX_XW(mat_a) * MATRIX_WY(mat_b);
xz = MATRIX_XX(mat_a) * MATRIX_XZ(mat_b) + MATRIX_XY(mat_a) * MATRIX_YZ(mat_b) +
MATRIX_XZ(mat_a) * MATRIX_ZZ(mat_b) + MATRIX_XW(mat_a) * MATRIX_WZ(mat_b);
xw = MATRIX_XX(mat_a) * MATRIX_XW(mat_b) + MATRIX_XY(mat_a) * MATRIX_YW(mat_b) +
MATRIX_XZ(mat_a) * MATRIX_ZW(mat_b) + MATRIX_XW(mat_a) * MATRIX_WW(mat_b);
yx = MATRIX_YX(mat_a) * MATRIX_XX(mat_b) + MATRIX_YY(mat_a) * MATRIX_YX(mat_b) +
MATRIX_YZ(mat_a) * MATRIX_ZX(mat_b) + MATRIX_YW(mat_a) * MATRIX_WX(mat_b);
yy = MATRIX_YX(mat_a) * MATRIX_XY(mat_b) + MATRIX_YY(mat_a) * MATRIX_YY(mat_b) +
MATRIX_YZ(mat_a) * MATRIX_ZY(mat_b) + MATRIX_YW(mat_a) * MATRIX_WY(mat_b);
yz = MATRIX_YX(mat_a) * MATRIX_XZ(mat_b) + MATRIX_YY(mat_a) * MATRIX_YZ(mat_b) +
MATRIX_YZ(mat_a) * MATRIX_ZZ(mat_b) + MATRIX_YW(mat_a) * MATRIX_WZ(mat_b);
yw = MATRIX_YX(mat_a) * MATRIX_XW(mat_b) + MATRIX_YY(mat_a) * MATRIX_YW(mat_b) +
MATRIX_YZ(mat_a) * MATRIX_ZW(mat_b) + MATRIX_YW(mat_a) * MATRIX_WW(mat_b);
zx = MATRIX_ZX(mat_a) * MATRIX_XX(mat_b) + MATRIX_ZY(mat_a) * MATRIX_YX(mat_b) +
MATRIX_ZZ(mat_a) * MATRIX_ZX(mat_b) + MATRIX_ZW(mat_a) * MATRIX_WX(mat_b);
zy = MATRIX_ZX(mat_a) * MATRIX_XY(mat_b) + MATRIX_ZY(mat_a) * MATRIX_YY(mat_b) +
MATRIX_ZZ(mat_a) * MATRIX_ZY(mat_b) + MATRIX_ZW(mat_a) * MATRIX_WY(mat_b);
zz = MATRIX_ZX(mat_a) * MATRIX_XZ(mat_b) + MATRIX_ZY(mat_a) * MATRIX_YZ(mat_b) +
MATRIX_ZZ(mat_a) * MATRIX_ZZ(mat_b) + MATRIX_ZW(mat_a) * MATRIX_WZ(mat_b);
zw = MATRIX_ZX(mat_a) * MATRIX_XW(mat_b) + MATRIX_ZY(mat_a) * MATRIX_YW(mat_b) +
MATRIX_ZZ(mat_a) * MATRIX_ZW(mat_b) + MATRIX_ZW(mat_a) * MATRIX_WW(mat_b);
wx = MATRIX_WX(mat_a) * MATRIX_XX(mat_b) + MATRIX_WY(mat_a) * MATRIX_YX(mat_b) +
MATRIX_WZ(mat_a) * MATRIX_ZX(mat_b) + MATRIX_WW(mat_a) * MATRIX_WX(mat_b);
wy = MATRIX_WX(mat_a) * MATRIX_XY(mat_b) + MATRIX_WY(mat_a) * MATRIX_YY(mat_b) +
MATRIX_WZ(mat_a) * MATRIX_ZY(mat_b) + MATRIX_WW(mat_a) * MATRIX_WY(mat_b);
wz = MATRIX_WX(mat_a) * MATRIX_XZ(mat_b) + MATRIX_WY(mat_a) * MATRIX_YZ(mat_b) +
MATRIX_WZ(mat_a) * MATRIX_ZZ(mat_b) + MATRIX_WW(mat_a) * MATRIX_WZ(mat_b);
ww = MATRIX_WX(mat_a) * MATRIX_XW(mat_b) + MATRIX_WY(mat_a) * MATRIX_YW(mat_b) +
MATRIX_WZ(mat_a) * MATRIX_ZW(mat_b) + MATRIX_WW(mat_a) * MATRIX_WW(mat_b);
MATRIX_XX(out) = xx;
MATRIX_XY(out) = xy;
MATRIX_XZ(out) = xz;
MATRIX_XW(out) = xw;
MATRIX_YX(out) = yx;
MATRIX_YY(out) = yy;
MATRIX_YZ(out) = yz;
MATRIX_YW(out) = yw;
MATRIX_ZX(out) = zx;
MATRIX_ZY(out) = zy;
MATRIX_ZZ(out) = zz;
MATRIX_ZW(out) = zw;
MATRIX_WX(out) = wx;
MATRIX_WY(out) = wy;
MATRIX_WZ(out) = wz;
MATRIX_WW(out) = ww;
}
EAPI void
eina_matrix4_translate(Eina_Matrix4 *t, double tx, double ty, double tz)
{
Eina_Matrix4 tmp;
MATRIX_XX(&tmp) = 1;
MATRIX_XY(&tmp) = 0;
MATRIX_XZ(&tmp) = 0;
MATRIX_XW(&tmp) = tx;
MATRIX_YX(&tmp) = 0;
MATRIX_YY(&tmp) = 1;
MATRIX_YZ(&tmp) = 0;
MATRIX_YW(&tmp) = ty;
MATRIX_ZX(&tmp) = 0;
MATRIX_ZY(&tmp) = 0;
MATRIX_ZZ(&tmp) = 1;
MATRIX_ZW(&tmp) = tz;
MATRIX_WX(&tmp) = 0;
MATRIX_WY(&tmp) = 0;
MATRIX_WZ(&tmp) = 0;
MATRIX_WW(&tmp) = 1;
eina_matrix4_compose(&tmp, t, t);
}
EAPI void
eina_matrix4_scale(Eina_Matrix4 *t, double sx, double sy, double sz)
{
Eina_Matrix4 tmp;
MATRIX_XX(&tmp) = sx;
MATRIX_XY(&tmp) = 0;
MATRIX_XZ(&tmp) = 0;
MATRIX_XW(&tmp) = 0;
MATRIX_YX(&tmp) = 0;
MATRIX_YY(&tmp) = sy;
MATRIX_YZ(&tmp) = 0;
MATRIX_YW(&tmp) = 0;
MATRIX_ZX(&tmp) = 0;
MATRIX_ZY(&tmp) = 0;
MATRIX_ZZ(&tmp) = sz;
MATRIX_ZW(&tmp) = 0;
MATRIX_WX(&tmp) = 0;
MATRIX_WY(&tmp) = 0;
MATRIX_WZ(&tmp) = 0;
MATRIX_WW(&tmp) = 1;
eina_matrix4_compose(&tmp, t, t);
}
EAPI void
eina_matrix4_rotate(Eina_Matrix4 *t, double rad, Eina_Matrix_Axis axis)
{
double c, s;
/* Note: Local functions do not guarantee accuracy.
* Errors occur in the calculation of very small or very large numbers.
* Local cos and sin functions differ from the math header cosf and sinf functions
* by result values. The 4th decimal place is different.
* But local functions are certainly faster than functions in math library.
* Later we would want someone to look at this and improve accuracy.
*/
#if 1
c = cos(rad);
s = sin(rad);
#else
/* normalize the angle between -pi,pi */
rad = fmod(rad + M_PI, 2 * M_PI) - M_PI;
c = _cos(rad);
s = _sin(rad);
#endif
Eina_Matrix4 tmp;
eina_matrix4_identity(&tmp);
switch (axis)
{
case EINA_MATRIX_AXIS_X:
MATRIX_YY(&tmp) = c;
MATRIX_YZ(&tmp) = -s;
MATRIX_ZY(&tmp) = s;
MATRIX_ZZ(&tmp) = c;
break;
case EINA_MATRIX_AXIS_Y:
MATRIX_XX(&tmp) = c;
MATRIX_XZ(&tmp) = s;
MATRIX_ZX(&tmp) = -s;
MATRIX_ZZ(&tmp) = c;
break;
case EINA_MATRIX_AXIS_Z:
MATRIX_XX(&tmp) = c;
MATRIX_XY(&tmp) = -s;
MATRIX_YX(&tmp) = s;
MATRIX_YY(&tmp) = c;
break;
}
eina_matrix4_compose(&tmp, t, t);
}
EAPI void
eina_matrix3_array_set(Eina_Matrix3 *m, const double *v)
{

View File

@ -56,6 +56,17 @@ typedef enum _Eina_Matrix_Type
EINA_MATRIX_TYPE_LAST /**< The total number of matrix types */
} Eina_Matrix_Type;
/**
* @typedef Eina_Matrix_Axis
* Matrix Axes
*/
typedef enum _Eina_Matrix_Axis
{
EINA_MATRIX_AXIS_X, /**< X-Axis */
EINA_MATRIX_AXIS_Y, /**< Y-Axis */
EINA_MATRIX_AXIS_Z, /**< Z-Axis */
} Eina_Matrix_Axis;
/**
* @defgroup Eina_Matrix3_Group 3x3 floating point matrices
*
@ -932,6 +943,59 @@ EAPI void eina_matrix4_ortho_set(Eina_Matrix4 *m,
double left, double right, double bottom, double top,
double dnear, double dfar);
/**
* @brief Sets out as the matrix multiplication (composition) of two matrices.
*
* @param[in] mat_a The first matrix. Must be non-NULL.
* @param[in] mat_b The second matrix. Must be non-NULL.
* @param[out] out The results matrix.
*
* In matrix multiplication, AB, the resultant matrix is created from
* the rows of A multiplied against the columns of B and summed. This
* is not commutative; i.e. AB != BA, so the ordering of arguments
* @p m1 and @p m2 matters.
*
* @since 1.24
*/
EAPI void eina_matrix4_compose(const Eina_Matrix4 *mat_a,
const Eina_Matrix4 *mat_b,
Eina_Matrix4 *out);
/**
* @brief Sets the matrix values for a translation operation.
*
* @param[out] t Where to store the resulting matrix.
* @param[in] tx The X coordinate translation.
* @param[in] ty The Y coordinate translation.
* @param[in] tz The Z coordinate translation.
*
* @since 1.24
*/
EAPI void eina_matrix4_translate(Eina_Matrix4 *t, double tx, double ty, double tz);
/**
* @brief Sets the matrix values for a scaling operation.
*
* @param[out] t Where to store the resulting matrix.
* @param[in] sx The X coordinate scaling factor.
* @param[in] sy The Y coordinate scaling factor.
* @param[in] sz The Z coordinate scaling factor.
*
* @since 1.24
*/
EAPI void eina_matrix4_scale(Eina_Matrix4 *t, double sx, double sy, double sz);
/**
* @brief Sets the matrix values for a rotation operation.
* @param[out] t Where to store the resulting matrix.
* @param[in] rad The number of radians to rotate.
* @param[in] axis The Axis of rotation.
*
* @since 1.24
*/
EAPI void eina_matrix4_rotate(Eina_Matrix4 *t, double rad, Eina_Matrix_Axis axis);
/**
* @}
*/

View File

@ -192,6 +192,24 @@ EFL_START_TEST(eina_matrix4)
}
EFL_END_TEST
#define MATRIX4_CMP(XX, XY, XZ, XW, YX, YY, YZ, YW, ZX, ZY, ZZ, ZW, WX, WY, WZ, WW, AXX, AXY, AXZ, AXW, AYX, AYY, AYZ, AYW, AZX, AZY, AZZ, AZW, AWX, AWY, AWZ, AWW) \
(EINA_DBL_EQ(XX, AXX) && \
EINA_DBL_EQ(XY, AXY) && \
EINA_DBL_EQ(XZ, AXZ) && \
EINA_DBL_EQ(XW, AXW) && \
EINA_DBL_EQ(YX, AYX) && \
EINA_DBL_EQ(YY, AYY) && \
EINA_DBL_EQ(YZ, AYZ) && \
EINA_DBL_EQ(YW, AYW) && \
EINA_DBL_EQ(ZX, AZX) && \
EINA_DBL_EQ(ZY, AZY) && \
EINA_DBL_EQ(ZZ, AZZ) && \
EINA_DBL_EQ(ZW, AZW) && \
EINA_DBL_EQ(WX, AWX) && \
EINA_DBL_EQ(WY, AWY) && \
EINA_DBL_EQ(WZ, AWZ) && \
EINA_DBL_EQ(WW, AWW))
EFL_START_TEST(eina_matrix4_operation)
{
double det;
@ -202,6 +220,7 @@ EFL_START_TEST(eina_matrix4_operation)
zx, zy, zz, zw,
wx, wy, wz, ww;
const double arr[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
double rotate_radian = 45.0 * M_PI / 180.0;
eina_matrix4_values_set(&m,
0, 0, 2, 0,
@ -311,6 +330,110 @@ EFL_START_TEST(eina_matrix4_operation)
!EINA_DBL_EQ(wy, 7) ||
!EINA_DBL_EQ(wz, 5) ||
!EINA_DBL_EQ(ww, 1));
eina_matrix4_identity(&m);
eina_matrix4_scale(&m, 5, 5, 5);
eina_matrix4_values_get(&m,
&xx, &xy, &xz, &xw,
&yx, &yy, &yz, &yw,
&zx, &zy, &zz, &zw,
&wx, &wy, &wz, &ww);
fail_if(!MATRIX4_CMP(xx, xy, xz, xw,
yx, yy, yz, yw,
zx, zy, zz, zw,
wx, wy, wz, ww,
5, 0, 0, 0,
0, 5, 0, 0,
0, 0, 5, 0,
0, 0, 0, 1));
eina_matrix4_translate(&m, 5, 5, 5);
eina_matrix4_values_get(&m,
&xx, &xy, &xz, &xw,
&yx, &yy, &yz, &yw,
&zx, &zy, &zz, &zw,
&wx, &wy, &wz, &ww);
fail_if(!MATRIX4_CMP(xx, xy, xz, xw,
yx, yy, yz, yw,
zx, zy, zz, zw,
wx, wy, wz, ww,
5, 0, 0, 5,
0, 5, 0, 5,
0, 0, 5, 5,
0, 0, 0, 1));
eina_matrix4_identity(&m);
eina_matrix4_rotate(&m, rotate_radian, EINA_MATRIX_AXIS_X);
eina_matrix4_values_get(&m,
&xx, &xy, &xz, &xw,
&yx, &yy, &yz, &yw,
&zx, &zy, &zz, &zw,
&wx, &wy, &wz, &ww);
fail_if(!MATRIX4_CMP(xx, xy, xz, xw,
yx, yy, yz, yw,
zx, zy, zz, zw,
wx, wy, wz, ww,
1, 0, 0, 0,
0, cos(rotate_radian), -sin(rotate_radian), 0,
0, sin(rotate_radian), cos(rotate_radian), 0,
0, 0, 0, 1));
eina_matrix4_identity(&m);
eina_matrix4_rotate(&m, rotate_radian, EINA_MATRIX_AXIS_Y);
eina_matrix4_values_get(&m,
&xx, &xy, &xz, &xw,
&yx, &yy, &yz, &yw,
&zx, &zy, &zz, &zw,
&wx, &wy, &wz, &ww);
fail_if(!MATRIX4_CMP(xx, xy, xz, xw,
yx, yy, yz, yw,
zx, zy, zz, zw,
wx, wy, wz, ww,
cos(rotate_radian), 0, sin(rotate_radian), 0,
0, 1, 0, 0,
-sin(rotate_radian), 0, cos(rotate_radian), 0,
0, 0, 0, 1));
eina_matrix4_identity(&m);
eina_matrix4_rotate(&m, rotate_radian, EINA_MATRIX_AXIS_Z);
eina_matrix4_values_get(&m,
&xx, &xy, &xz, &xw,
&yx, &yy, &yz, &yw,
&zx, &zy, &zz, &zw,
&wx, &wy, &wz, &ww);
fail_if(!MATRIX4_CMP(xx, xy, xz, xw,
yx, yy, yz, yw,
zx, zy, zz, zw,
wx, wy, wz, ww,
cos(rotate_radian), -sin(rotate_radian), 0, 0,
sin(rotate_radian), cos(rotate_radian), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1));
eina_matrix4_identity(&m1);
eina_matrix4_values_set(&m2,
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16);
eina_matrix4_compose(&m1, &m2, &m);
eina_matrix4_values_get(&m,
&xx, &xy, &xz, &xw,
&yx, &yy, &yz, &yw,
&zx, &zy, &zz, &zw,
&wx, &wy, &wz, &ww);
fail_if(!MATRIX4_CMP(xx, xy, xz, xw,
yx, yy, yz, yw,
zx, zy, zz, zw,
wx, wy, wz, ww,
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16));
}
EFL_END_TEST