1 /* EINA - Drawing Library
2  * Copyright (C) 2007-2014 Jorge Luis Zapata
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library.
16  * If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #endif
22 
23 #include "eina_private.h"
24 
25 #include <math.h>
26 #include <float.h>
27 #include <string.h>
28 
29 #include "eina_fp.h"
30 #include "eina_rectangle.h"
31 #include "eina_quad.h"
32 #include "eina_matrix.h"
33 #include "eina_util.h"
34 
35 #define MATRIX_XX(m) (m)->xx
36 #define MATRIX_XY(m) (m)->xy
37 #define MATRIX_XZ(m) (m)->xz
38 #define MATRIX_XW(m) (m)->xw
39 #define MATRIX_YX(m) (m)->yx
40 #define MATRIX_YY(m) (m)->yy
41 #define MATRIX_YZ(m) (m)->yz
42 #define MATRIX_YW(m) (m)->yw
43 #define MATRIX_ZX(m) (m)->zx
44 #define MATRIX_ZY(m) (m)->zy
45 #define MATRIX_ZZ(m) (m)->zz
46 #define MATRIX_ZW(m) (m)->zw
47 #define MATRIX_WX(m) (m)->wx
48 #define MATRIX_WY(m) (m)->wy
49 #define MATRIX_WZ(m) (m)->wz
50 #define MATRIX_WW(m) (m)->ww
51 #define MATRIX_SIZE 9
52 
53 #define QUAD_X0(q) q->x0
54 #define QUAD_Y0(q) q->y0
55 #define QUAD_X1(q) q->x1
56 #define QUAD_Y1(q) q->y1
57 #define QUAD_X2(q) q->x2
58 #define QUAD_Y2(q) q->y2
59 #define QUAD_X3(q) q->x3
60 #define QUAD_Y3(q) q->y3
61 
62 /*============================================================================*
63  *                                  Local                                     *
64  *============================================================================*/
65 
66 /*============================================================================*
67  *                                   API                                      *
68  *============================================================================*/
69 EAPI Eina_Matrix_Type
eina_matrix3_type_get(const Eina_Matrix3 * m)70 eina_matrix3_type_get(const Eina_Matrix3 *m)
71 {
72    if (!EINA_DBL_EQ(MATRIX_ZX(m), 0.0) ||
73        !EINA_DBL_EQ(MATRIX_ZY(m), 0.0) ||
74        !EINA_DBL_EQ(MATRIX_ZZ(m), 1.0))
75      return EINA_MATRIX_TYPE_PROJECTIVE;
76    else
77      {
78         if (EINA_DBL_EQ(MATRIX_XX(m), 1.0) &&
79             EINA_DBL_EQ(MATRIX_XY(m), 0.0) &&
80             EINA_DBL_EQ(MATRIX_XZ(m), 0.0) &&
81             EINA_DBL_EQ(MATRIX_YX(m), 0.0) &&
82             EINA_DBL_EQ(MATRIX_YY(m), 1.0) &&
83             EINA_DBL_EQ(MATRIX_YZ(m), 0.0))
84           return EINA_MATRIX_TYPE_IDENTITY;
85         else
86           return EINA_MATRIX_TYPE_AFFINE;
87      }
88 }
89 
90 EAPI Eina_Matrix_Type
eina_matrix4_type_get(const Eina_Matrix4 * m)91 eina_matrix4_type_get(const Eina_Matrix4 *m)
92 {
93    if (EINA_DBL_EQ(MATRIX_XX(m), 1.0) &&
94        EINA_DBL_EQ(MATRIX_XY(m), 0.0) &&
95        EINA_DBL_EQ(MATRIX_XZ(m), 0.0) &&
96        EINA_DBL_EQ(MATRIX_XW(m), 0.0) &&
97        EINA_DBL_EQ(MATRIX_YX(m), 0.0) &&
98        EINA_DBL_EQ(MATRIX_YY(m), 1.0) &&
99        EINA_DBL_EQ(MATRIX_YZ(m), 0.0) &&
100        EINA_DBL_EQ(MATRIX_YW(m), 0.0) &&
101        EINA_DBL_EQ(MATRIX_ZX(m), 0.0) &&
102        EINA_DBL_EQ(MATRIX_ZY(m), 0.0) &&
103        EINA_DBL_EQ(MATRIX_ZZ(m), 1.0) &&
104        EINA_DBL_EQ(MATRIX_ZW(m), 0.0) &&
105        EINA_DBL_EQ(MATRIX_WX(m), 0.0) &&
106        EINA_DBL_EQ(MATRIX_WY(m), 0.0) &&
107        EINA_DBL_EQ(MATRIX_WZ(m), 0.0) &&
108        EINA_DBL_EQ(MATRIX_WW(m), 1.0))
109      return EINA_MATRIX_TYPE_IDENTITY;
110    return EINA_MATRIX_TYPE_AFFINE;
111 }
112 
113 EAPI Eina_Matrix_Type
eina_matrix3_f16p16_type_get(const Eina_Matrix3_F16p16 * m)114 eina_matrix3_f16p16_type_get(const Eina_Matrix3_F16p16 *m)
115 {
116    if ((MATRIX_ZX(m) != 0) || (MATRIX_ZY(m) != 0) || (MATRIX_ZZ(m) != 65536))
117      return EINA_MATRIX_TYPE_PROJECTIVE;
118    else
119      {
120         if ((MATRIX_XX(m) == 65536) && (MATRIX_XY(m) == 0) && (MATRIX_XZ(m) == 0) &&
121             (MATRIX_YX(m) == 0) && (MATRIX_YY(m) == 65536) && (MATRIX_YZ(m) == 0))
122           return EINA_MATRIX_TYPE_IDENTITY;
123         else
124           return EINA_MATRIX_TYPE_AFFINE;
125      }
126 }
127 
128 EAPI void
eina_matrix3_values_set(Eina_Matrix3 * m,double xx,double xy,double xz,double yx,double yy,double yz,double zx,double zy,double zz)129 eina_matrix3_values_set(Eina_Matrix3 *m,
130                         double xx, double xy, double xz,
131                         double yx, double yy, double yz,
132                         double zx, double zy, double zz)
133 {
134    MATRIX_XX(m) = xx;
135    MATRIX_XY(m) = xy;
136    MATRIX_XZ(m) = xz;
137    MATRIX_YX(m) = yx;
138    MATRIX_YY(m) = yy;
139    MATRIX_YZ(m) = yz;
140    MATRIX_ZX(m) = zx;
141    MATRIX_ZY(m) = zy;
142    MATRIX_ZZ(m) = zz;
143 }
144 
145 EAPI void
eina_matrix3_values_get(const Eina_Matrix3 * m,double * xx,double * xy,double * xz,double * yx,double * yy,double * yz,double * zx,double * zy,double * zz)146 eina_matrix3_values_get(const Eina_Matrix3 *m,
147                         double *xx, double *xy, double *xz,
148                         double *yx, double *yy, double *yz,
149                         double *zx, double *zy, double *zz)
150 {
151    if (xx) *xx = MATRIX_XX(m);
152    if (xy) *xy = MATRIX_XY(m);
153    if (xz) *xz = MATRIX_XZ(m);
154    if (yx) *yx = MATRIX_YX(m);
155    if (yy) *yy = MATRIX_YY(m);
156    if (yz) *yz = MATRIX_YZ(m);
157    if (zx) *zx = MATRIX_ZX(m);
158    if (zy) *zy = MATRIX_ZY(m);
159    if (zz) *zz = MATRIX_ZZ(m);
160 }
161 
162 EAPI void
eina_matrix4_values_set(Eina_Matrix4 * m,double xx,double xy,double xz,double xw,double yx,double yy,double yz,double yw,double zx,double zy,double zz,double zw,double wx,double wy,double wz,double ww)163 eina_matrix4_values_set(Eina_Matrix4 *m,
164                         double xx, double xy, double xz, double xw,
165                         double yx, double yy, double yz, double yw,
166                         double zx, double zy, double zz, double zw,
167                         double wx, double wy, double wz, double ww)
168 {
169    MATRIX_XX(m) = xx;
170    MATRIX_XY(m) = xy;
171    MATRIX_XZ(m) = xz;
172    MATRIX_XW(m) = xw;
173    MATRIX_YX(m) = yx;
174    MATRIX_YY(m) = yy;
175    MATRIX_YZ(m) = yz;
176    MATRIX_YW(m) = yw;
177    MATRIX_ZX(m) = zx;
178    MATRIX_ZY(m) = zy;
179    MATRIX_ZZ(m) = zz;
180    MATRIX_ZW(m) = zw;
181    MATRIX_WX(m) = wx;
182    MATRIX_WY(m) = wy;
183    MATRIX_WZ(m) = wz;
184    MATRIX_WW(m) = ww;
185 }
186 
187 EAPI void
eina_matrix4_values_get(const Eina_Matrix4 * m,double * xx,double * xy,double * xz,double * xw,double * yx,double * yy,double * yz,double * yw,double * zx,double * zy,double * zz,double * zw,double * wx,double * wy,double * wz,double * ww)188 eina_matrix4_values_get(const Eina_Matrix4 *m,
189                         double *xx, double *xy, double *xz, double *xw,
190                         double *yx, double *yy, double *yz, double *yw,
191                         double *zx, double *zy, double *zz, double *zw,
192                         double *wx, double *wy, double *wz, double *ww)
193 {
194    if (xx) *xx = MATRIX_XX(m);
195    if (xy) *xy = MATRIX_XY(m);
196    if (xz) *xz = MATRIX_XZ(m);
197    if (xw) *xw = MATRIX_XW(m);
198    if (yx) *yx = MATRIX_YX(m);
199    if (yy) *yy = MATRIX_YY(m);
200    if (yz) *yz = MATRIX_YZ(m);
201    if (yw) *yw = MATRIX_YW(m);
202    if (zx) *zx = MATRIX_ZX(m);
203    if (zy) *zy = MATRIX_ZY(m);
204    if (zz) *zz = MATRIX_ZZ(m);
205    if (zw) *zw = MATRIX_ZW(m);
206    if (wx) *wx = MATRIX_WX(m);
207    if (wy) *wy = MATRIX_WY(m);
208    if (wz) *wz = MATRIX_WZ(m);
209    if (ww) *ww = MATRIX_WW(m);
210 }
211 
212 EAPI void
eina_matrix3_fixed_values_get(const Eina_Matrix3 * m,Eina_F16p16 * xx,Eina_F16p16 * xy,Eina_F16p16 * xz,Eina_F16p16 * yx,Eina_F16p16 * yy,Eina_F16p16 * yz,Eina_F16p16 * zx,Eina_F16p16 * zy,Eina_F16p16 * zz)213 eina_matrix3_fixed_values_get(const Eina_Matrix3 *m,
214                               Eina_F16p16 *xx, Eina_F16p16 *xy, Eina_F16p16 *xz,
215                               Eina_F16p16 *yx, Eina_F16p16 *yy, Eina_F16p16 *yz,
216                               Eina_F16p16 *zx, Eina_F16p16 *zy, Eina_F16p16 *zz)
217 {
218    if (xx) *xx = eina_f16p16_double_from(MATRIX_XX(m));
219    if (xy) *xy = eina_f16p16_double_from(MATRIX_XY(m));
220    if (xz) *xz = eina_f16p16_double_from(MATRIX_XZ(m));
221    if (yx) *yx = eina_f16p16_double_from(MATRIX_YX(m));
222    if (yy) *yy = eina_f16p16_double_from(MATRIX_YY(m));
223    if (yz) *yz = eina_f16p16_double_from(MATRIX_YZ(m));
224    if (zx) *zx = eina_f16p16_double_from(MATRIX_ZX(m));
225    if (zy) *zy = eina_f16p16_double_from(MATRIX_ZY(m));
226    if (zz) *zz = eina_f16p16_double_from(MATRIX_ZZ(m));
227 }
228 
229 EAPI void
eina_matrix3_matrix3_f16p16_to(const Eina_Matrix3 * m,Eina_Matrix3_F16p16 * fm)230 eina_matrix3_matrix3_f16p16_to(const Eina_Matrix3 *m,
231                                Eina_Matrix3_F16p16 *fm)
232 {
233    eina_matrix3_fixed_values_get(m,
234                                  &fm->xx, &fm->xy, &fm->xz,
235                                  &fm->yx, &fm->yy, &fm->yz,
236                                  &fm->zx, &fm->zy, &fm->zz);
237 }
238 
239 EAPI void
eina_matrix3_point_transform(const Eina_Matrix3 * m,double x,double y,double * xr,double * yr)240 eina_matrix3_point_transform(const Eina_Matrix3 *m,
241                              double x, double y,
242                              double *xr, double *yr)
243 {
244    double xrr, yrr;
245 
246    if (!EINA_DBL_EQ(MATRIX_ZX(m), 0.0) &&
247        !EINA_DBL_EQ(MATRIX_ZY(m), 0.0))
248      {
249         xrr = (x * MATRIX_XX(m) + y * MATRIX_XY(m) + MATRIX_XZ(m));
250         yrr = (x * MATRIX_YX(m) + y * MATRIX_YY(m) + MATRIX_YZ(m));
251      }
252    else
253      {
254         xrr = (x * MATRIX_XX(m) + y * MATRIX_XY(m) + MATRIX_XZ(m)) /
255           (x * MATRIX_ZX(m) + y * MATRIX_ZY(m) + MATRIX_ZZ(m));
256         yrr = (x * MATRIX_YX(m) + y * MATRIX_YY(m) + MATRIX_YZ(m)) /
257           (x * MATRIX_ZX(m) + y * MATRIX_ZY(m) + MATRIX_ZZ(m));
258      }
259 
260    if (xr) *xr = xrr;
261    if (yr) *yr = yrr;
262 }
263 
264 EAPI void
eina_matrix3_rectangle_transform(const Eina_Matrix3 * m,const Eina_Rectangle * r,const Eina_Quad * q)265 eina_matrix3_rectangle_transform(const Eina_Matrix3 *m,
266                                  const Eina_Rectangle *r,
267                                  const Eina_Quad *q)
268 {
269    eina_matrix3_point_transform(m, r->x, r->y, &((Eina_Quad *)q)->x0, &((Eina_Quad *)q)->y0);
270    eina_matrix3_point_transform(m, r->x + r->w, r->y, &((Eina_Quad *)q)->x1, &((Eina_Quad *)q)->y1);
271    eina_matrix3_point_transform(m, r->x + r->w, r->y + r->h, &((Eina_Quad *)q)->x2, &((Eina_Quad *)q)->y2);
272    eina_matrix3_point_transform(m, r->x, r->y + r->h, &((Eina_Quad *)q)->x3, &((Eina_Quad *)q)->y3);
273 }
274 
275 EAPI void
eina_matrix3_cofactor(const Eina_Matrix3 * m,Eina_Matrix3 * a)276 eina_matrix3_cofactor(const Eina_Matrix3 *m, Eina_Matrix3 *a)
277 {
278    double a11, a12, a13, a21, a22, a23, a31, a32, a33;
279 
280    a11 = (MATRIX_YY(m) * MATRIX_ZZ(m)) - (MATRIX_YZ(m) * MATRIX_ZY(m));
281    a12 = -1 * ((MATRIX_YX(m) * MATRIX_ZZ(m)) - (MATRIX_YZ(m) * MATRIX_ZX(m)));
282    a13 = (MATRIX_YX(m) * MATRIX_ZY(m)) - (MATRIX_YY(m) * MATRIX_ZX(m));
283 
284    a21 = -1 * ((MATRIX_XY(m) * MATRIX_ZZ(m)) - (MATRIX_XZ(m) * MATRIX_ZY(m)));
285    a22 = (MATRIX_XX(m) * MATRIX_ZZ(m)) - (MATRIX_XZ(m) * MATRIX_ZX(m));
286    a23 = -1 * ((MATRIX_XX(m) * MATRIX_ZY(m)) - (MATRIX_XY(m) * MATRIX_ZX(m)));
287 
288    a31 = (MATRIX_XY(m) * MATRIX_YZ(m)) - (MATRIX_XZ(m) * MATRIX_YY(m));
289    a32 = -1 * ((MATRIX_XX(m) * MATRIX_YZ(m)) - (MATRIX_XZ(m) * MATRIX_YX(m)));
290    a33 = (MATRIX_XX(m) * MATRIX_YY(m)) - (MATRIX_XY(m) * MATRIX_YX(m));
291 
292    MATRIX_XX(a) = a11;
293    MATRIX_XY(a) = a12;
294    MATRIX_XZ(a) = a13;
295 
296    MATRIX_YX(a) = a21;
297    MATRIX_YY(a) = a22;
298    MATRIX_YZ(a) = a23;
299 
300    MATRIX_ZX(a) = a31;
301    MATRIX_ZY(a) = a32;
302    MATRIX_ZZ(a) = a33;
303 }
304 
305 EAPI void
eina_matrix3_transpose(const Eina_Matrix3 * m,Eina_Matrix3 * a)306 eina_matrix3_transpose(const Eina_Matrix3 *m, Eina_Matrix3 *a)
307 {
308    MATRIX_XX(a) = MATRIX_XX(m);
309    MATRIX_XY(a) = MATRIX_YX(m);
310    MATRIX_XZ(a) = MATRIX_ZX(m);
311 
312    MATRIX_YX(a) = MATRIX_XY(m);
313    MATRIX_YY(a) = MATRIX_YY(m);
314    MATRIX_YZ(a) = MATRIX_ZY(m);
315 
316    MATRIX_ZX(a) = MATRIX_XZ(m);
317    MATRIX_ZY(a) = MATRIX_YZ(m);
318    MATRIX_ZZ(a) = MATRIX_ZZ(m);
319 }
320 
321 EAPI void
eina_matrix3_adjoint(const Eina_Matrix3 * m,Eina_Matrix3 * a)322 eina_matrix3_adjoint(const Eina_Matrix3 *m, Eina_Matrix3 *a)
323 {
324    Eina_Matrix3 cofactor;
325 
326    /* cofactor */
327    eina_matrix3_cofactor(m, &cofactor);
328    /* transpose */
329    eina_matrix3_transpose(&cofactor, a);
330 }
331 
332 EAPI double
eina_matrix3_determinant(const Eina_Matrix3 * m)333 eina_matrix3_determinant(const Eina_Matrix3 *m)
334 {
335    double det;
336 
337    det = MATRIX_XX(m) * ((MATRIX_YY(m) * MATRIX_ZZ(m)) - (MATRIX_YZ(m) * MATRIX_ZY(m)));
338    det -= MATRIX_XY(m) * ((MATRIX_YX(m) * MATRIX_ZZ(m)) - (MATRIX_YZ(m) * MATRIX_ZX(m)));
339    det += MATRIX_XZ(m) * ((MATRIX_YX(m) * MATRIX_ZY(m)) - (MATRIX_YY(m) * MATRIX_ZX(m)));
340 
341    return det;
342 }
343 
344 EAPI void
eina_matrix3_divide(Eina_Matrix3 * m,double scalar)345 eina_matrix3_divide(Eina_Matrix3 *m, double scalar)
346 {
347    MATRIX_XX(m) /= scalar;
348    MATRIX_XY(m) /= scalar;
349    MATRIX_XZ(m) /= scalar;
350 
351    MATRIX_YX(m) /= scalar;
352    MATRIX_YY(m) /= scalar;
353    MATRIX_YZ(m) /= scalar;
354 
355    MATRIX_ZX(m) /= scalar;
356    MATRIX_ZY(m) /= scalar;
357    MATRIX_ZZ(m) /= scalar;
358 }
359 
360 EAPI void
eina_matrix3_inverse(const Eina_Matrix3 * m,Eina_Matrix3 * m2)361 eina_matrix3_inverse(const Eina_Matrix3 *m, Eina_Matrix3 *m2)
362 {
363    double scalar;
364 
365    /* determinant */
366    scalar = eina_matrix3_determinant(m);
367    if (EINA_DBL_EQ(scalar, 0.0))
368      {
369         eina_matrix3_identity(m2);
370         return;
371      }
372    /* do its adjoint */
373    eina_matrix3_adjoint(m, m2);
374    /* divide */
375    eina_matrix3_divide(m2, scalar);
376 }
377 
378 EAPI void
eina_matrix3_compose(const Eina_Matrix3 * m1,const Eina_Matrix3 * m2,Eina_Matrix3 * dst)379 eina_matrix3_compose(const Eina_Matrix3 *m1,
380                      const Eina_Matrix3 *m2,
381                      Eina_Matrix3 *dst)
382 {
383    double a11, a12, a13, a21, a22, a23, a31, a32, a33;
384 
385    a11 = (MATRIX_XX(m1) * MATRIX_XX(m2)) + (MATRIX_XY(m1) * MATRIX_YX(m2)) + (MATRIX_XZ(m1) * MATRIX_ZX(m2));
386    a12 = (MATRIX_XX(m1) * MATRIX_XY(m2)) + (MATRIX_XY(m1) * MATRIX_YY(m2)) + (MATRIX_XZ(m1) * MATRIX_ZY(m2));
387    a13 = (MATRIX_XX(m1) * MATRIX_XZ(m2)) + (MATRIX_XY(m1) * MATRIX_YZ(m2)) + (MATRIX_XZ(m1) * MATRIX_ZZ(m2));
388 
389    a21 = (MATRIX_YX(m1) * MATRIX_XX(m2)) + (MATRIX_YY(m1) * MATRIX_YX(m2)) + (MATRIX_YZ(m1) * MATRIX_ZX(m2));
390    a22 = (MATRIX_YX(m1) * MATRIX_XY(m2)) + (MATRIX_YY(m1) * MATRIX_YY(m2)) + (MATRIX_YZ(m1) * MATRIX_ZY(m2));
391    a23 = (MATRIX_YX(m1) * MATRIX_XZ(m2)) + (MATRIX_YY(m1) * MATRIX_YZ(m2)) + (MATRIX_YZ(m1) * MATRIX_ZZ(m2));
392 
393    a31 = (MATRIX_ZX(m1) * MATRIX_XX(m2)) + (MATRIX_ZY(m1) * MATRIX_YX(m2)) + (MATRIX_ZZ(m1) * MATRIX_ZX(m2));
394    a32 = (MATRIX_ZX(m1) * MATRIX_XY(m2)) + (MATRIX_ZY(m1) * MATRIX_YY(m2)) + (MATRIX_ZZ(m1) * MATRIX_ZY(m2));
395    a33 = (MATRIX_ZX(m1) * MATRIX_XZ(m2)) + (MATRIX_ZY(m1) * MATRIX_YZ(m2)) + (MATRIX_ZZ(m1) * MATRIX_ZZ(m2));
396 
397    MATRIX_XX(dst) = a11;
398    MATRIX_XY(dst) = a12;
399    MATRIX_XZ(dst) = a13;
400    MATRIX_YX(dst) = a21;
401    MATRIX_YY(dst) = a22;
402    MATRIX_YZ(dst) = a23;
403    MATRIX_ZX(dst) = a31;
404    MATRIX_ZY(dst) = a32;
405    MATRIX_ZZ(dst) = a33;
406 }
407 
408 EAPI Eina_Bool
eina_matrix3_equal(const Eina_Matrix3 * m1,const Eina_Matrix3 * m2)409 eina_matrix3_equal(const Eina_Matrix3 *m1, const Eina_Matrix3 *m2)
410 {
411    if (!EINA_DBL_EQ(m1->xx, m2->xx) ||
412        !EINA_DBL_EQ(m1->xy, m2->xy) ||
413        !EINA_DBL_EQ(m1->xz, m2->xz) ||
414        !EINA_DBL_EQ(m1->yx, m2->yx) ||
415        !EINA_DBL_EQ(m1->yy, m2->yy) ||
416        !EINA_DBL_EQ(m1->yz, m2->yz) ||
417        !EINA_DBL_EQ(m1->zx, m2->zx) ||
418        !EINA_DBL_EQ(m1->zy, m2->zy) ||
419        !EINA_DBL_EQ(m1->zz, m2->zz))
420      return EINA_FALSE;
421    return EINA_TRUE;
422 }
423 
424 EAPI void
eina_matrix3_f16p16_compose(const Eina_Matrix3_F16p16 * m1,const Eina_Matrix3_F16p16 * m2,Eina_Matrix3_F16p16 * dst)425 eina_matrix3_f16p16_compose(const Eina_Matrix3_F16p16 *m1,
426                             const Eina_Matrix3_F16p16 *m2,
427                             Eina_Matrix3_F16p16 *dst)
428 {
429    Eina_F16p16 a11, a12, a13, a21, a22, a23, a31, a32, a33;
430 
431    a11 = eina_f16p16_mul(MATRIX_XX(m1), MATRIX_XX(m2)) +
432      eina_f16p16_mul(MATRIX_XY(m1), MATRIX_YX(m2)) +
433      eina_f16p16_mul(MATRIX_XZ(m1), MATRIX_ZX(m2));
434    a12 = eina_f16p16_mul(MATRIX_XX(m1), MATRIX_XY(m2)) +
435      eina_f16p16_mul(MATRIX_XY(m1), MATRIX_YY(m2)) +
436      eina_f16p16_mul(MATRIX_XZ(m1), MATRIX_ZY(m2));
437    a13 = eina_f16p16_mul(MATRIX_XX(m1), MATRIX_XZ(m2)) +
438      eina_f16p16_mul(MATRIX_XY(m1), MATRIX_YZ(m2)) +
439      eina_f16p16_mul(MATRIX_XZ(m1), MATRIX_ZZ(m2));
440 
441    a21 = eina_f16p16_mul(MATRIX_YX(m1), MATRIX_XX(m2)) +
442      eina_f16p16_mul(MATRIX_YY(m1), MATRIX_YX(m2)) +
443      eina_f16p16_mul(MATRIX_YZ(m1), MATRIX_ZX(m2));
444    a22 = eina_f16p16_mul(MATRIX_YX(m1), MATRIX_XY(m2)) +
445      eina_f16p16_mul(MATRIX_YY(m1), MATRIX_YY(m2)) +
446      eina_f16p16_mul(MATRIX_YZ(m1), MATRIX_ZY(m2));
447    a23 = eina_f16p16_mul(MATRIX_YX(m1), MATRIX_XZ(m2)) +
448      eina_f16p16_mul(MATRIX_YY(m1), MATRIX_YZ(m2)) +
449      eina_f16p16_mul(MATRIX_YZ(m1), MATRIX_ZZ(m2));
450 
451    a31 = eina_f16p16_mul(MATRIX_ZX(m1), MATRIX_XX(m2)) +
452      eina_f16p16_mul(MATRIX_ZY(m1), MATRIX_YX(m2)) +
453      eina_f16p16_mul(MATRIX_ZZ(m1), MATRIX_ZX(m2));
454    a32 = eina_f16p16_mul(MATRIX_ZX(m1), MATRIX_XY(m2)) +
455      eina_f16p16_mul(MATRIX_ZY(m1), MATRIX_YY(m2)) +
456      eina_f16p16_mul(MATRIX_ZZ(m1), MATRIX_ZY(m2));
457    a33 = eina_f16p16_mul(MATRIX_ZX(m1), MATRIX_XZ(m2)) +
458      eina_f16p16_mul(MATRIX_ZY(m1), MATRIX_YZ(m2)) +
459      eina_f16p16_mul(MATRIX_ZZ(m1), MATRIX_ZZ(m2));
460 
461    MATRIX_XX(dst) = a11;
462    MATRIX_XY(dst) = a12;
463    MATRIX_XZ(dst) = a13;
464    MATRIX_YX(dst) = a21;
465    MATRIX_YY(dst) = a22;
466    MATRIX_YZ(dst) = a23;
467    MATRIX_ZX(dst) = a31;
468    MATRIX_ZY(dst) = a32;
469    MATRIX_ZZ(dst) = a33;
470 }
471 
472 EAPI void
eina_matrix3_translate(Eina_Matrix3 * m,double tx,double ty)473 eina_matrix3_translate(Eina_Matrix3 *m, double tx, double ty)
474 {
475    Eina_Matrix3 tmp;
476    MATRIX_XX(&tmp) = 1;
477    MATRIX_XY(&tmp) = 0;
478    MATRIX_XZ(&tmp) = tx;
479    MATRIX_YX(&tmp) = 0;
480    MATRIX_YY(&tmp) = 1;
481    MATRIX_YZ(&tmp) = ty;
482    MATRIX_ZX(&tmp) = 0;
483    MATRIX_ZY(&tmp) = 0;
484    MATRIX_ZZ(&tmp) = 1;
485    eina_matrix3_compose(m, &tmp, m);
486 }
487 
488 EAPI void
eina_matrix3_scale(Eina_Matrix3 * m,double sx,double sy)489 eina_matrix3_scale(Eina_Matrix3 *m, double sx, double sy)
490 {
491    Eina_Matrix3 tmp;
492    MATRIX_XX(&tmp) = sx;
493    MATRIX_XY(&tmp) = 0;
494    MATRIX_XZ(&tmp) = 0;
495    MATRIX_YX(&tmp) = 0;
496    MATRIX_YY(&tmp) = sy;
497    MATRIX_YZ(&tmp) = 0;
498    MATRIX_ZX(&tmp) = 0;
499    MATRIX_ZY(&tmp) = 0;
500    MATRIX_ZZ(&tmp) = 1;
501    eina_matrix3_compose(m, &tmp, m);
502 }
503 
504 EAPI void
eina_matrix3_rotate(Eina_Matrix3 * m,double rad)505 eina_matrix3_rotate(Eina_Matrix3 *m, double rad)
506 {
507    double c, s;
508 
509    /* Note: Local functions do not guarantee accuracy.
510     *       Errors occur in the calculation of very small or very large numbers.
511     *       Local cos and sin functions differ from the math header cosf and sinf functions
512     *       by result values. The 4th decimal place is different.
513     *       But local functions are certainly faster than functions in math library.
514     *       Later we would want someone to look at this and improve accuracy.
515     */
516 #if 1
517    c = cos(rad);
518    s = sin(rad);
519 #else
520    /* normalize the angle between -pi,pi */
521    rad = fmod(rad + M_PI, 2 * M_PI) - M_PI;
522    c = _cos(rad);
523    s = _sin(rad);
524 #endif
525 
526    Eina_Matrix3 tmp;
527    MATRIX_XX(&tmp) = c;
528    MATRIX_XY(&tmp) = -s;
529    MATRIX_XZ(&tmp) = 0;
530    MATRIX_YX(&tmp) = s;
531    MATRIX_YY(&tmp) = c;
532    MATRIX_YZ(&tmp) = 0;
533    MATRIX_ZX(&tmp) = 0;
534    MATRIX_ZY(&tmp) = 0;
535    MATRIX_ZZ(&tmp) = 1;
536    eina_matrix3_compose(m, &tmp, m);
537 }
538 
539 EAPI void
eina_matrix3_identity(Eina_Matrix3 * m)540 eina_matrix3_identity(Eina_Matrix3 *m)
541 {
542    MATRIX_XX(m) = 1;
543    MATRIX_XY(m) = 0;
544    MATRIX_XZ(m) = 0;
545    MATRIX_YX(m) = 0;
546    MATRIX_YY(m) = 1;
547    MATRIX_YZ(m) = 0;
548    MATRIX_ZX(m) = 0;
549    MATRIX_ZY(m) = 0;
550    MATRIX_ZZ(m) = 1;
551 }
552 
553 EAPI void
eina_matrix3_f16p16_identity(Eina_Matrix3_F16p16 * m)554 eina_matrix3_f16p16_identity(Eina_Matrix3_F16p16 *m)
555 {
556    MATRIX_XX(m) = 65536;
557    MATRIX_XY(m) = 0;
558    MATRIX_XZ(m) = 0;
559    MATRIX_YX(m) = 0;
560    MATRIX_YY(m) = 65536;
561    MATRIX_YZ(m) = 0;
562    MATRIX_ZX(m) = 0;
563    MATRIX_ZY(m) = 0;
564    MATRIX_ZZ(m) = 65536;
565 }
566 
567 EAPI Eina_Bool
eina_matrix3_square_quad_map(Eina_Matrix3 * m,const Eina_Quad * q)568 eina_matrix3_square_quad_map(Eina_Matrix3 *m, const Eina_Quad *q)
569 {
570    // x0 - x1 + x2 - x3
571    double ex = QUAD_X0(q) - QUAD_X1(q) + QUAD_X2(q) - QUAD_X3(q);
572    // y0 - y1 + y2 - y3
573    double ey = QUAD_Y0(q) - QUAD_Y1(q) + QUAD_Y2(q) - QUAD_Y3(q);
574 
575    /* parallelogram */
576    if (EINA_DBL_EQ(ex, 0.0) && EINA_DBL_EQ(ey, 0.0))
577      {
578         /* create the affine matrix */
579         MATRIX_XX(m) = QUAD_X1(q) - QUAD_X0(q);
580         MATRIX_XY(m) = QUAD_X2(q) - QUAD_X1(q);
581         MATRIX_XZ(m) = QUAD_X0(q);
582 
583         MATRIX_YX(m) = QUAD_Y1(q) - QUAD_Y0(q);
584         MATRIX_YY(m) = QUAD_Y2(q) - QUAD_Y1(q);
585         MATRIX_YZ(m) = QUAD_Y0(q);
586 
587         MATRIX_ZX(m) = 0;
588         MATRIX_ZY(m) = 0;
589         MATRIX_ZZ(m) = 1;
590 
591         return EINA_TRUE;
592      }
593    else
594      {
595         double dx1 = QUAD_X1(q) - QUAD_X2(q); // x1 - x2
596         double dx2 = QUAD_X3(q) - QUAD_X2(q); // x3 - x2
597         double dy1 = QUAD_Y1(q) - QUAD_Y2(q); // y1 - y2
598         double dy2 = QUAD_Y3(q) - QUAD_Y2(q); // y3 - y2
599         double den = (dx1 * dy2) - (dx2 * dy1);
600 
601         if (EINA_DBL_EQ(den, 0.0))
602           return EINA_FALSE;
603 
604         MATRIX_ZX(m) = ((ex * dy2) - (dx2 * ey)) / den;
605         MATRIX_ZY(m) = ((dx1 * ey) - (ex * dy1)) / den;
606         MATRIX_ZZ(m) = 1;
607         MATRIX_XX(m) = QUAD_X1(q) - QUAD_X0(q) + (MATRIX_ZX(m) * QUAD_X1(q));
608         MATRIX_XY(m) = QUAD_X3(q) - QUAD_X0(q) + (MATRIX_ZY(m) * QUAD_X3(q));
609         MATRIX_XZ(m) = QUAD_X0(q);
610         MATRIX_YX(m) = QUAD_Y1(q) - QUAD_Y0(q) + (MATRIX_ZX(m) * QUAD_Y1(q));
611         MATRIX_YY(m) = QUAD_Y3(q) - QUAD_Y0(q) + (MATRIX_ZY(m) * QUAD_Y3(q));
612         MATRIX_YZ(m) = QUAD_Y0(q);
613 
614         return EINA_TRUE;
615      }
616 }
617 
618 EAPI Eina_Bool
eina_matrix3_quad_square_map(Eina_Matrix3 * m,const Eina_Quad * q)619 eina_matrix3_quad_square_map(Eina_Matrix3 *m,
620                              const Eina_Quad *q)
621 {
622    Eina_Matrix3 tmp;
623 
624    /* compute square to quad */
625    if (!eina_matrix3_square_quad_map(&tmp, q))
626      return EINA_FALSE;
627 
628    eina_matrix3_inverse(&tmp, m);
629    /* make the projective matrix3 always have 1 on zz */
630    if (!EINA_DBL_EQ(MATRIX_ZZ(m), 1.0))
631      {
632         eina_matrix3_divide(m, MATRIX_ZZ(m));
633      }
634 
635    return EINA_TRUE;
636 }
637 
638 EAPI Eina_Bool
eina_matrix3_quad_quad_map(Eina_Matrix3 * m,const Eina_Quad * src,const Eina_Quad * dst)639 eina_matrix3_quad_quad_map(Eina_Matrix3 *m,
640                            const Eina_Quad *src,
641                            const Eina_Quad *dst)
642 {
643    Eina_Matrix3 tmp;
644 
645    /* TODO check that both are actually quadrangles */
646    if (!eina_matrix3_quad_square_map(m, src))
647      return EINA_FALSE;
648    if (!eina_matrix3_square_quad_map(&tmp, dst))
649      return EINA_FALSE;
650    eina_matrix3_compose(&tmp, m, m);
651 
652    return EINA_TRUE;
653 }
654 
655 EAPI void
eina_matrix4_matrix3_to(Eina_Matrix3 * m3,const Eina_Matrix4 * m4)656 eina_matrix4_matrix3_to(Eina_Matrix3 *m3, const Eina_Matrix4 *m4)
657 {
658    MATRIX_XX(m3) = MATRIX_XX(m4);
659    MATRIX_XY(m3) = MATRIX_XY(m4);
660    MATRIX_XZ(m3) = MATRIX_XW(m4);
661    MATRIX_YX(m3) = MATRIX_YX(m4);
662    MATRIX_YY(m3) = MATRIX_YY(m4);
663    MATRIX_YZ(m3) = MATRIX_YW(m4);
664    MATRIX_ZX(m3) = MATRIX_WX(m4);
665    MATRIX_ZY(m3) = MATRIX_WY(m4);
666    MATRIX_ZZ(m3) = MATRIX_WW(m4);
667 }
668 
669 EAPI void
eina_matrix3_matrix4_to(Eina_Matrix4 * m4,const Eina_Matrix3 * m3)670 eina_matrix3_matrix4_to(Eina_Matrix4 *m4, const Eina_Matrix3 *m3)
671 {
672    MATRIX_XX(m4) = MATRIX_XX(m3);
673    MATRIX_XY(m4) = MATRIX_XY(m3);
674    MATRIX_XZ(m4) = 0;
675    MATRIX_XW(m4) = MATRIX_XZ(m3);
676    MATRIX_YX(m4) = MATRIX_YX(m3);
677    MATRIX_YY(m4) = MATRIX_YY(m3);
678    MATRIX_YZ(m4) = 0;
679    MATRIX_YW(m4) = MATRIX_YZ(m3);
680    MATRIX_ZX(m4) = 0;
681    MATRIX_ZY(m4) = 0;
682    MATRIX_ZZ(m4) = 1;
683    MATRIX_ZW(m4) = 0;
684    MATRIX_WX(m4) = MATRIX_ZX(m3);
685    MATRIX_WY(m4) = MATRIX_ZY(m3);
686    MATRIX_WZ(m4) = 0;
687    MATRIX_WW(m4) = MATRIX_ZZ(m3);
688 }
689 
690 EAPI double
eina_matrix4_determinant(const Eina_Matrix4 * m)691 eina_matrix4_determinant(const Eina_Matrix4 *m)
692 {
693    return
694        MATRIX_XW(m) * MATRIX_YZ(m) * MATRIX_ZY(m) * MATRIX_WX(m)
695      - MATRIX_XZ(m) * MATRIX_YW(m) * MATRIX_ZY(m) * MATRIX_WX(m)
696      - MATRIX_XW(m) * MATRIX_YY(m) * MATRIX_ZZ(m) * MATRIX_WX(m)
697      + MATRIX_XY(m) * MATRIX_YW(m) * MATRIX_ZZ(m) * MATRIX_WX(m)
698      + MATRIX_XZ(m) * MATRIX_YY(m) * MATRIX_ZW(m) * MATRIX_WX(m)
699      - MATRIX_XY(m) * MATRIX_YZ(m) * MATRIX_ZW(m) * MATRIX_WX(m)
700      - MATRIX_XW(m) * MATRIX_YZ(m) * MATRIX_ZX(m) * MATRIX_WY(m)
701      + MATRIX_XZ(m) * MATRIX_YW(m) * MATRIX_ZX(m) * MATRIX_WY(m)
702      + MATRIX_XW(m) * MATRIX_YX(m) * MATRIX_ZZ(m) * MATRIX_WY(m)
703      - MATRIX_XX(m) * MATRIX_YW(m) * MATRIX_ZZ(m) * MATRIX_WY(m)
704      - MATRIX_XZ(m) * MATRIX_YX(m) * MATRIX_ZW(m) * MATRIX_WY(m)
705      + MATRIX_XX(m) * MATRIX_YZ(m) * MATRIX_ZW(m) * MATRIX_WY(m)
706      + MATRIX_XW(m) * MATRIX_YY(m) * MATRIX_ZX(m) * MATRIX_WZ(m)
707      - MATRIX_XY(m) * MATRIX_YW(m) * MATRIX_ZX(m) * MATRIX_WZ(m)
708      - MATRIX_XW(m) * MATRIX_YX(m) * MATRIX_ZY(m) * MATRIX_WZ(m)
709      + MATRIX_XX(m) * MATRIX_YW(m) * MATRIX_ZY(m) * MATRIX_WZ(m)
710      + MATRIX_XY(m) * MATRIX_YX(m) * MATRIX_ZW(m) * MATRIX_WZ(m)
711      - MATRIX_XX(m) * MATRIX_YY(m) * MATRIX_ZW(m) * MATRIX_WZ(m)
712      - MATRIX_XZ(m) * MATRIX_YY(m) * MATRIX_ZX(m) * MATRIX_WW(m)
713      + MATRIX_XY(m) * MATRIX_YZ(m) * MATRIX_ZX(m) * MATRIX_WW(m)
714      + MATRIX_XZ(m) * MATRIX_YX(m) * MATRIX_ZY(m) * MATRIX_WW(m)
715      - MATRIX_XX(m) * MATRIX_YZ(m) * MATRIX_ZY(m) * MATRIX_WW(m)
716      - MATRIX_XY(m) * MATRIX_YX(m) * MATRIX_ZZ(m) * MATRIX_WW(m)
717      + MATRIX_XX(m) * MATRIX_YY(m) * MATRIX_ZZ(m) * MATRIX_WW(m);
718 }
719 
720 EAPI Eina_Bool
eina_matrix4_normalized(Eina_Matrix4 * out,const Eina_Matrix4 * in)721 eina_matrix4_normalized(Eina_Matrix4 *out, const Eina_Matrix4 *in)
722 {
723    double det;
724 
725    det = eina_matrix4_determinant(in);
726    if (fabs(det) < DBL_EPSILON) return EINA_FALSE;
727 
728    MATRIX_XX(out) = MATRIX_XX(in) / det;
729    MATRIX_XY(out) = MATRIX_XY(in) / det;
730    MATRIX_XZ(out) = MATRIX_XZ(in) / det;
731    MATRIX_XW(out) = MATRIX_XW(in) / det;
732    MATRIX_YX(out) = MATRIX_YX(in) / det;
733    MATRIX_YY(out) = MATRIX_YY(in) / det;
734    MATRIX_YZ(out) = MATRIX_YZ(in) / det;
735    MATRIX_YW(out) = MATRIX_YW(in) / det;
736    MATRIX_ZX(out) = MATRIX_ZX(in) / det;
737    MATRIX_ZY(out) = MATRIX_ZY(in) / det;
738    MATRIX_ZZ(out) = MATRIX_ZZ(in) / det;
739    MATRIX_ZW(out) = MATRIX_ZW(in) / det;
740    MATRIX_WX(out) = MATRIX_WX(in) / det;
741    MATRIX_WY(out) = MATRIX_WY(in) / det;
742    MATRIX_WZ(out) = MATRIX_WZ(in) / det;
743    MATRIX_WW(out) = MATRIX_WW(in) / det;
744 
745    return EINA_TRUE;
746 }
747 
748 EAPI Eina_Bool
eina_matrix4_inverse(Eina_Matrix4 * out,const Eina_Matrix4 * in)749 eina_matrix4_inverse(Eina_Matrix4 *out, const Eina_Matrix4 *in)
750 {
751    double det;
752 
753    MATRIX_XX(out) =
754        MATRIX_YY(in)  * MATRIX_ZZ(in) * MATRIX_WW(in)
755      - MATRIX_YY(in)  * MATRIX_ZW(in) * MATRIX_WZ(in)
756      - MATRIX_ZY(in)  * MATRIX_YZ(in)  * MATRIX_WW(in)
757      + MATRIX_ZY(in)  * MATRIX_YW(in)  * MATRIX_WZ(in)
758      + MATRIX_WY(in) * MATRIX_YZ(in)  * MATRIX_ZW(in)
759      - MATRIX_WY(in) * MATRIX_YW(in)  * MATRIX_ZZ(in);
760 
761    MATRIX_YX(out) =
762      - MATRIX_YX(in)  * MATRIX_ZZ(in) * MATRIX_WW(in)
763      + MATRIX_YX(in)  * MATRIX_ZW(in) * MATRIX_WZ(in)
764      + MATRIX_ZX(in)  * MATRIX_YZ(in)  * MATRIX_WW(in)
765      - MATRIX_ZX(in)  * MATRIX_YW(in)  * MATRIX_WZ(in)
766      - MATRIX_WX(in) * MATRIX_YZ(in)  * MATRIX_ZW(in)
767      + MATRIX_WX(in) * MATRIX_YW(in)  * MATRIX_ZZ(in);
768 
769    MATRIX_ZX(out) =
770        MATRIX_YX(in)  * MATRIX_ZY(in) * MATRIX_WW(in)
771      - MATRIX_YX(in)  * MATRIX_ZW(in) * MATRIX_WY(in)
772      - MATRIX_ZX(in)  * MATRIX_YY(in) * MATRIX_WW(in)
773      + MATRIX_ZX(in)  * MATRIX_YW(in) * MATRIX_WY(in)
774      + MATRIX_WX(in) * MATRIX_YY(in) * MATRIX_ZW(in)
775      - MATRIX_WX(in) * MATRIX_YW(in) * MATRIX_ZY(in);
776 
777    MATRIX_WX(out) =
778      - MATRIX_YX(in)  * MATRIX_ZY(in) * MATRIX_WZ(in)
779      + MATRIX_YX(in)  * MATRIX_ZZ(in) * MATRIX_WY(in)
780      + MATRIX_ZX(in)  * MATRIX_YY(in) * MATRIX_WZ(in)
781      - MATRIX_ZX(in)  * MATRIX_YZ(in) * MATRIX_WY(in)
782      - MATRIX_WX(in) * MATRIX_YY(in) * MATRIX_ZZ(in)
783      + MATRIX_WX(in) * MATRIX_YZ(in) * MATRIX_ZY(in);
784 
785    MATRIX_XY(out) =
786      - MATRIX_XY(in)  * MATRIX_ZZ(in) * MATRIX_WW(in)
787      + MATRIX_XY(in)  * MATRIX_ZW(in) * MATRIX_WZ(in)
788      + MATRIX_ZY(in)  * MATRIX_XZ(in) * MATRIX_WW(in)
789      - MATRIX_ZY(in)  * MATRIX_XW(in) * MATRIX_WZ(in)
790      - MATRIX_WY(in) * MATRIX_XZ(in) * MATRIX_ZW(in)
791      + MATRIX_WY(in) * MATRIX_XW(in) * MATRIX_ZZ(in);
792 
793    MATRIX_YY(out) =
794        MATRIX_XX(in)  * MATRIX_ZZ(in) * MATRIX_WW(in)
795      - MATRIX_XX(in)  * MATRIX_ZW(in) * MATRIX_WZ(in)
796      - MATRIX_ZX(in)  * MATRIX_XZ(in) * MATRIX_WW(in)
797      + MATRIX_ZX(in)  * MATRIX_XW(in) * MATRIX_WZ(in)
798      + MATRIX_WX(in) * MATRIX_XZ(in) * MATRIX_ZW(in)
799      - MATRIX_WX(in) * MATRIX_XW(in) * MATRIX_ZZ(in);
800 
801    MATRIX_ZY(out) =
802      - MATRIX_XX(in)  * MATRIX_ZY(in) * MATRIX_WW(in)
803      + MATRIX_XX(in)  * MATRIX_ZW(in) * MATRIX_WY(in)
804      + MATRIX_ZX(in)  * MATRIX_XY(in) * MATRIX_WW(in)
805      - MATRIX_ZX(in)  * MATRIX_XW(in) * MATRIX_WY(in)
806      - MATRIX_WX(in) * MATRIX_XY(in) * MATRIX_ZW(in)
807      + MATRIX_WX(in) * MATRIX_XW(in) * MATRIX_ZY(in);
808 
809    MATRIX_WY(out) =
810        MATRIX_XX(in)  * MATRIX_ZY(in) * MATRIX_WZ(in)
811      - MATRIX_XX(in)  * MATRIX_ZZ(in) * MATRIX_WY(in)
812      - MATRIX_ZX(in)  * MATRIX_XY(in) * MATRIX_WZ(in)
813      + MATRIX_ZX(in)  * MATRIX_XZ(in) * MATRIX_WY(in)
814      + MATRIX_WX(in) * MATRIX_XY(in) * MATRIX_ZZ(in)
815      - MATRIX_WX(in) * MATRIX_XZ(in) * MATRIX_ZY(in);
816 
817    MATRIX_XZ(out) =
818        MATRIX_XY(in)  * MATRIX_YZ(in) * MATRIX_WW(in)
819      - MATRIX_XY(in)  * MATRIX_YW(in) * MATRIX_WZ(in)
820      - MATRIX_YY(in)  * MATRIX_XZ(in) * MATRIX_WW(in)
821      + MATRIX_YY(in)  * MATRIX_XW(in) * MATRIX_WZ(in)
822      + MATRIX_WY(in) * MATRIX_XZ(in) * MATRIX_YW(in)
823      - MATRIX_WY(in) * MATRIX_XW(in) * MATRIX_YZ(in);
824 
825    MATRIX_YZ(out) =
826      - MATRIX_XX(in)  * MATRIX_YZ(in) * MATRIX_WW(in)
827      + MATRIX_XX(in)  * MATRIX_YW(in) * MATRIX_WZ(in)
828      + MATRIX_YX(in)  * MATRIX_XZ(in) * MATRIX_WW(in)
829      - MATRIX_YX(in)  * MATRIX_XW(in) * MATRIX_WZ(in)
830      - MATRIX_WX(in) * MATRIX_XZ(in) * MATRIX_YW(in)
831      + MATRIX_WX(in) * MATRIX_XW(in) * MATRIX_YZ(in);
832 
833    MATRIX_ZZ(out) =
834        MATRIX_XX(in)  * MATRIX_YY(in) * MATRIX_WW(in)
835      - MATRIX_XX(in)  * MATRIX_YW(in) * MATRIX_WY(in)
836      - MATRIX_YX(in)  * MATRIX_XY(in) * MATRIX_WW(in)
837      + MATRIX_YX(in)  * MATRIX_XW(in) * MATRIX_WY(in)
838      + MATRIX_WX(in) * MATRIX_XY(in) * MATRIX_YW(in)
839      - MATRIX_WX(in) * MATRIX_XW(in) * MATRIX_YY(in);
840 
841    MATRIX_WZ(out) =
842      - MATRIX_XX(in)  * MATRIX_YY(in) * MATRIX_WZ(in)
843      + MATRIX_XX(in)  * MATRIX_YZ(in) * MATRIX_WY(in)
844      + MATRIX_YX(in)  * MATRIX_XY(in) * MATRIX_WZ(in)
845      - MATRIX_YX(in)  * MATRIX_XZ(in) * MATRIX_WY(in)
846      - MATRIX_WX(in) * MATRIX_XY(in) * MATRIX_YZ(in)
847      + MATRIX_WX(in) * MATRIX_XZ(in) * MATRIX_YY(in);
848 
849    MATRIX_XW(out) =
850      - MATRIX_XY(in) * MATRIX_YZ(in) * MATRIX_ZW(in)
851      + MATRIX_XY(in) * MATRIX_YW(in) * MATRIX_ZZ(in)
852      + MATRIX_YY(in) * MATRIX_XZ(in) * MATRIX_ZW(in)
853      - MATRIX_YY(in) * MATRIX_XW(in) * MATRIX_ZZ(in)
854      - MATRIX_ZY(in) * MATRIX_XZ(in) * MATRIX_YW(in)
855      + MATRIX_ZY(in) * MATRIX_XW(in) * MATRIX_YZ(in);
856 
857    MATRIX_YW(out) =
858        MATRIX_XX(in) * MATRIX_YZ(in) * MATRIX_ZW(in)
859      - MATRIX_XX(in) * MATRIX_YW(in) * MATRIX_ZZ(in)
860      - MATRIX_YX(in) * MATRIX_XZ(in) * MATRIX_ZW(in)
861      + MATRIX_YX(in) * MATRIX_XW(in) * MATRIX_ZZ(in)
862      + MATRIX_ZX(in) * MATRIX_XZ(in) * MATRIX_YW(in)
863      - MATRIX_ZX(in) * MATRIX_XW(in) * MATRIX_YZ(in);
864 
865    MATRIX_ZW(out) =
866      - MATRIX_XX(in) * MATRIX_YY(in) * MATRIX_ZW(in)
867      + MATRIX_XX(in) * MATRIX_YW(in) * MATRIX_ZY(in)
868      + MATRIX_YX(in) * MATRIX_XY(in) * MATRIX_ZW(in)
869      - MATRIX_YX(in) * MATRIX_XW(in) * MATRIX_ZY(in)
870      - MATRIX_ZX(in) * MATRIX_XY(in) * MATRIX_YW(in)
871      + MATRIX_ZX(in) * MATRIX_XW(in) * MATRIX_YY(in);
872 
873    MATRIX_WW(out) =
874        MATRIX_XX(in) * MATRIX_YY(in) * MATRIX_ZZ(in)
875      - MATRIX_XX(in) * MATRIX_YZ(in) * MATRIX_ZY(in)
876      - MATRIX_YX(in) * MATRIX_XY(in) * MATRIX_ZZ(in)
877      + MATRIX_YX(in) * MATRIX_XZ(in) * MATRIX_ZY(in)
878      + MATRIX_ZX(in) * MATRIX_XY(in) * MATRIX_YZ(in)
879      - MATRIX_ZX(in) * MATRIX_XZ(in) * MATRIX_YY(in);
880 
881    det =
882        MATRIX_XX(in) * MATRIX_XX(out)
883      + MATRIX_XY(in) * MATRIX_YX(out)
884      + MATRIX_XZ(in) * MATRIX_ZX(out)
885      + MATRIX_XW(in) * MATRIX_WX(out);
886 
887    if (fabs(det) < DBL_EPSILON) return EINA_FALSE;
888 
889    det = 1.0 / det;
890 
891    MATRIX_XX(out) = MATRIX_XX(out) * det;
892    MATRIX_XY(out) = MATRIX_XY(out) * det;
893    MATRIX_XZ(out) = MATRIX_XZ(out) * det;
894    MATRIX_XW(out) = MATRIX_XW(out) * det;
895    MATRIX_YX(out) = MATRIX_YX(out) * det;
896    MATRIX_YY(out) = MATRIX_YY(out) * det;
897    MATRIX_YZ(out) = MATRIX_YZ(out) * det;
898    MATRIX_YW(out) = MATRIX_YW(out) * det;
899    MATRIX_ZX(out) = MATRIX_ZX(out) * det;
900    MATRIX_ZY(out) = MATRIX_ZY(out) * det;
901    MATRIX_ZZ(out) = MATRIX_ZZ(out) * det;
902    MATRIX_ZW(out) = MATRIX_ZW(out) * det;
903    MATRIX_WX(out) = MATRIX_WX(out) * det;
904    MATRIX_WY(out) = MATRIX_WY(out) * det;
905    MATRIX_WZ(out) = MATRIX_WZ(out) * det;
906    MATRIX_WW(out) = MATRIX_WW(out) * det;
907 
908    return EINA_TRUE;
909 }
910 
911 EAPI void
eina_matrix4_transpose(Eina_Matrix4 * out,const Eina_Matrix4 * in)912 eina_matrix4_transpose(Eina_Matrix4 *out, const Eina_Matrix4 *in)
913 {
914    MATRIX_XX(out) = MATRIX_XX(in);
915    MATRIX_XY(out) = MATRIX_YX(in);
916    MATRIX_XZ(out) = MATRIX_ZX(in);
917    MATRIX_XW(out) = MATRIX_WX(in);
918    MATRIX_YX(out) = MATRIX_XY(in);
919    MATRIX_YY(out) = MATRIX_YY(in);
920    MATRIX_YZ(out) = MATRIX_ZY(in);
921    MATRIX_YW(out) = MATRIX_WY(in);
922    MATRIX_ZX(out) = MATRIX_XZ(in);
923    MATRIX_ZY(out) = MATRIX_YZ(in);
924    MATRIX_ZZ(out) = MATRIX_ZZ(in);
925    MATRIX_ZW(out) = MATRIX_WZ(in);
926    MATRIX_WX(out) = MATRIX_XW(in);
927    MATRIX_WY(out) = MATRIX_YW(in);
928    MATRIX_WZ(out) = MATRIX_ZW(in);
929    MATRIX_WW(out) = MATRIX_WW(in);
930 }
931 
932 EAPI void
eina_matrix4_multiply_copy(Eina_Matrix4 * out,const Eina_Matrix4 * mat_a,const Eina_Matrix4 * mat_b)933 eina_matrix4_multiply_copy(Eina_Matrix4 *out,
934                       const Eina_Matrix4 *mat_a, const Eina_Matrix4 *mat_b)
935 {
936    if (out != mat_a && out != mat_b)
937      {
938         eina_matrix4_multiply(out, mat_a, mat_b);
939      }
940    else
941      {
942         Eina_Matrix4 result;
943 
944         eina_matrix4_multiply(&result, mat_a, mat_b);
945         eina_matrix4_copy(out, &result);
946      }
947 }
948 
949 EAPI void
eina_matrix4_identity(Eina_Matrix4 * out)950 eina_matrix4_identity(Eina_Matrix4 *out)
951 {
952    memset(out, 0, sizeof (Eina_Matrix4));
953 
954    MATRIX_XX(out) = 1.0;
955    MATRIX_YY(out) = 1.0;
956    MATRIX_ZZ(out) = 1.0;
957    MATRIX_WW(out) = 1.0;
958 }
959 
960 EAPI Eina_Matrix_Type
eina_matrix2_type_get(const Eina_Matrix2 * m)961 eina_matrix2_type_get(const Eina_Matrix2 *m)
962 {
963    if (EINA_DBL_EQ(MATRIX_XX(m), 1.0) &&
964        EINA_DBL_EQ(MATRIX_XY(m), 0.0) &&
965        EINA_DBL_EQ(MATRIX_YX(m), 0.0) &&
966        EINA_DBL_EQ(MATRIX_YY(m), 1.0))
967      return EINA_MATRIX_TYPE_IDENTITY;
968    return EINA_MATRIX_TYPE_AFFINE;
969 }
970 
971 EAPI void
eina_matrix4_array_set(Eina_Matrix4 * m,const double * v)972 eina_matrix4_array_set(Eina_Matrix4 *m, const double *v)
973 {
974    memcpy(&MATRIX_XX(m), v, sizeof(double) * 16);
975 }
976 
977 EAPI void
eina_matrix4_copy(Eina_Matrix4 * dst,const Eina_Matrix4 * src)978 eina_matrix4_copy(Eina_Matrix4 *dst, const Eina_Matrix4 *src)
979 {
980    memcpy(dst, src, sizeof(Eina_Matrix4));
981 }
982 
983 EAPI void
eina_matrix4_multiply(Eina_Matrix4 * out,const Eina_Matrix4 * mat_a,const Eina_Matrix4 * mat_b)984 eina_matrix4_multiply(Eina_Matrix4 *out, const Eina_Matrix4 *mat_a,
985                            const Eina_Matrix4 *mat_b)
986 {
987    if (eina_matrix4_type_get(mat_a) == EINA_MATRIX_TYPE_IDENTITY)
988      {
989         eina_matrix4_copy(out, mat_b);
990         return;
991      }
992 
993    if (eina_matrix4_type_get(mat_b) == EINA_MATRIX_TYPE_IDENTITY)
994      {
995         eina_matrix4_copy(out, mat_a);
996         return;
997      }
998 
999    eina_matrix4_compose(mat_a, mat_b, out);
1000 }
1001 
1002 EAPI void
eina_matrix4_ortho_set(Eina_Matrix4 * m,double left,double right,double bottom,double top,double dnear,double dfar)1003 eina_matrix4_ortho_set(Eina_Matrix4 *m,
1004                     double left, double right, double bottom, double top,
1005                     double dnear, double dfar)
1006 {
1007    double   w = right - left;
1008    double   h = top - bottom;
1009    double   depth = dnear - dfar;
1010 
1011    MATRIX_XX(m) = 2.0f / w;
1012    MATRIX_XY(m) = 0.0f;
1013    MATRIX_XZ(m) = 0.0f;
1014    MATRIX_XW(m) = 0.0f;
1015 
1016    MATRIX_YX(m) = 0.0f;
1017    MATRIX_YY(m) = 2.0f / h;
1018    MATRIX_YZ(m) = 0.0f;
1019    MATRIX_YW(m) = 0.0f;
1020 
1021    MATRIX_ZX(m) = 0.0f;
1022    MATRIX_ZY(m) = 0.0f;
1023    MATRIX_ZZ(m) = 2.0f / depth;
1024    MATRIX_ZW(m) = 0.0f;
1025 
1026    MATRIX_WX(m) = -(right + left) / w;
1027    MATRIX_WY(m) = -(top + bottom) / h;
1028    MATRIX_WZ(m) = (dfar + dnear) / depth;
1029    MATRIX_WW(m) = 1.0f;
1030 }
1031 
1032 EAPI void
eina_matrix4_compose(const Eina_Matrix4 * mat_a,const Eina_Matrix4 * mat_b,Eina_Matrix4 * out)1033 eina_matrix4_compose(const Eina_Matrix4 *mat_a,
1034                      const Eina_Matrix4 *mat_b,
1035                      Eina_Matrix4 *out)
1036 {
1037    double xx, xy, xz, xw,
1038           yx, yy, yz, yw,
1039           zx, zy, zz, zw,
1040           wx, wy, wz, ww;
1041 
1042    xx = MATRIX_XX(mat_a) * MATRIX_XX(mat_b) + MATRIX_XY(mat_a) * MATRIX_YX(mat_b) +
1043         MATRIX_XZ(mat_a) * MATRIX_ZX(mat_b) + MATRIX_XW(mat_a) * MATRIX_WX(mat_b);
1044    xy = MATRIX_XX(mat_a) * MATRIX_XY(mat_b) + MATRIX_XY(mat_a) * MATRIX_YY(mat_b) +
1045         MATRIX_XZ(mat_a) * MATRIX_ZY(mat_b) + MATRIX_XW(mat_a) * MATRIX_WY(mat_b);
1046    xz = MATRIX_XX(mat_a) * MATRIX_XZ(mat_b) + MATRIX_XY(mat_a) * MATRIX_YZ(mat_b) +
1047         MATRIX_XZ(mat_a) * MATRIX_ZZ(mat_b) + MATRIX_XW(mat_a) * MATRIX_WZ(mat_b);
1048    xw = MATRIX_XX(mat_a) * MATRIX_XW(mat_b) + MATRIX_XY(mat_a) * MATRIX_YW(mat_b) +
1049         MATRIX_XZ(mat_a) * MATRIX_ZW(mat_b) + MATRIX_XW(mat_a) * MATRIX_WW(mat_b);
1050 
1051    yx = MATRIX_YX(mat_a) * MATRIX_XX(mat_b) + MATRIX_YY(mat_a) * MATRIX_YX(mat_b) +
1052         MATRIX_YZ(mat_a) * MATRIX_ZX(mat_b) + MATRIX_YW(mat_a) * MATRIX_WX(mat_b);
1053    yy = MATRIX_YX(mat_a) * MATRIX_XY(mat_b) + MATRIX_YY(mat_a) * MATRIX_YY(mat_b) +
1054         MATRIX_YZ(mat_a) * MATRIX_ZY(mat_b) + MATRIX_YW(mat_a) * MATRIX_WY(mat_b);
1055    yz = MATRIX_YX(mat_a) * MATRIX_XZ(mat_b) + MATRIX_YY(mat_a) * MATRIX_YZ(mat_b) +
1056         MATRIX_YZ(mat_a) * MATRIX_ZZ(mat_b) + MATRIX_YW(mat_a) * MATRIX_WZ(mat_b);
1057    yw = MATRIX_YX(mat_a) * MATRIX_XW(mat_b) + MATRIX_YY(mat_a) * MATRIX_YW(mat_b) +
1058         MATRIX_YZ(mat_a) * MATRIX_ZW(mat_b) + MATRIX_YW(mat_a) * MATRIX_WW(mat_b);
1059 
1060    zx = MATRIX_ZX(mat_a) * MATRIX_XX(mat_b) + MATRIX_ZY(mat_a) * MATRIX_YX(mat_b) +
1061         MATRIX_ZZ(mat_a) * MATRIX_ZX(mat_b) + MATRIX_ZW(mat_a) * MATRIX_WX(mat_b);
1062    zy = MATRIX_ZX(mat_a) * MATRIX_XY(mat_b) + MATRIX_ZY(mat_a) * MATRIX_YY(mat_b) +
1063         MATRIX_ZZ(mat_a) * MATRIX_ZY(mat_b) + MATRIX_ZW(mat_a) * MATRIX_WY(mat_b);
1064    zz = MATRIX_ZX(mat_a) * MATRIX_XZ(mat_b) + MATRIX_ZY(mat_a) * MATRIX_YZ(mat_b) +
1065         MATRIX_ZZ(mat_a) * MATRIX_ZZ(mat_b) + MATRIX_ZW(mat_a) * MATRIX_WZ(mat_b);
1066    zw = MATRIX_ZX(mat_a) * MATRIX_XW(mat_b) + MATRIX_ZY(mat_a) * MATRIX_YW(mat_b) +
1067         MATRIX_ZZ(mat_a) * MATRIX_ZW(mat_b) + MATRIX_ZW(mat_a) * MATRIX_WW(mat_b);
1068 
1069    wx = MATRIX_WX(mat_a) * MATRIX_XX(mat_b) + MATRIX_WY(mat_a) * MATRIX_YX(mat_b) +
1070         MATRIX_WZ(mat_a) * MATRIX_ZX(mat_b) + MATRIX_WW(mat_a) * MATRIX_WX(mat_b);
1071    wy = MATRIX_WX(mat_a) * MATRIX_XY(mat_b) + MATRIX_WY(mat_a) * MATRIX_YY(mat_b) +
1072         MATRIX_WZ(mat_a) * MATRIX_ZY(mat_b) + MATRIX_WW(mat_a) * MATRIX_WY(mat_b);
1073    wz = MATRIX_WX(mat_a) * MATRIX_XZ(mat_b) + MATRIX_WY(mat_a) * MATRIX_YZ(mat_b) +
1074         MATRIX_WZ(mat_a) * MATRIX_ZZ(mat_b) + MATRIX_WW(mat_a) * MATRIX_WZ(mat_b);
1075    ww = MATRIX_WX(mat_a) * MATRIX_XW(mat_b) + MATRIX_WY(mat_a) * MATRIX_YW(mat_b) +
1076         MATRIX_WZ(mat_a) * MATRIX_ZW(mat_b) + MATRIX_WW(mat_a) * MATRIX_WW(mat_b);
1077 
1078    MATRIX_XX(out) = xx;
1079    MATRIX_XY(out) = xy;
1080    MATRIX_XZ(out) = xz;
1081    MATRIX_XW(out) = xw;
1082 
1083    MATRIX_YX(out) = yx;
1084    MATRIX_YY(out) = yy;
1085    MATRIX_YZ(out) = yz;
1086    MATRIX_YW(out) = yw;
1087 
1088    MATRIX_ZX(out) = zx;
1089    MATRIX_ZY(out) = zy;
1090    MATRIX_ZZ(out) = zz;
1091    MATRIX_ZW(out) = zw;
1092 
1093    MATRIX_WX(out) = wx;
1094    MATRIX_WY(out) = wy;
1095    MATRIX_WZ(out) = wz;
1096    MATRIX_WW(out) = ww;
1097 }
1098 
1099 EAPI void
eina_matrix4_translate(Eina_Matrix4 * t,double tx,double ty,double tz)1100 eina_matrix4_translate(Eina_Matrix4 *t, double tx, double ty, double tz)
1101 {
1102    Eina_Matrix4 tmp;
1103    MATRIX_XX(&tmp) = 1;
1104    MATRIX_XY(&tmp) = 0;
1105    MATRIX_XZ(&tmp) = 0;
1106    MATRIX_XW(&tmp) = tx;
1107 
1108    MATRIX_YX(&tmp) = 0;
1109    MATRIX_YY(&tmp) = 1;
1110    MATRIX_YZ(&tmp) = 0;
1111    MATRIX_YW(&tmp) = ty;
1112 
1113    MATRIX_ZX(&tmp) = 0;
1114    MATRIX_ZY(&tmp) = 0;
1115    MATRIX_ZZ(&tmp) = 1;
1116    MATRIX_ZW(&tmp) = tz;
1117 
1118    MATRIX_WX(&tmp) = 0;
1119    MATRIX_WY(&tmp) = 0;
1120    MATRIX_WZ(&tmp) = 0;
1121    MATRIX_WW(&tmp) = 1;
1122 
1123    eina_matrix4_compose(&tmp, t, t);
1124 }
1125 
1126 EAPI void
eina_matrix4_scale(Eina_Matrix4 * t,double sx,double sy,double sz)1127 eina_matrix4_scale(Eina_Matrix4 *t, double sx, double sy, double sz)
1128 {
1129    Eina_Matrix4 tmp;
1130    MATRIX_XX(&tmp) = sx;
1131    MATRIX_XY(&tmp) = 0;
1132    MATRIX_XZ(&tmp) = 0;
1133    MATRIX_XW(&tmp) = 0;
1134 
1135    MATRIX_YX(&tmp) = 0;
1136    MATRIX_YY(&tmp) = sy;
1137    MATRIX_YZ(&tmp) = 0;
1138    MATRIX_YW(&tmp) = 0;
1139 
1140    MATRIX_ZX(&tmp) = 0;
1141    MATRIX_ZY(&tmp) = 0;
1142    MATRIX_ZZ(&tmp) = sz;
1143    MATRIX_ZW(&tmp) = 0;
1144 
1145    MATRIX_WX(&tmp) = 0;
1146    MATRIX_WY(&tmp) = 0;
1147    MATRIX_WZ(&tmp) = 0;
1148    MATRIX_WW(&tmp) = 1;
1149 
1150    eina_matrix4_compose(&tmp, t, t);
1151 }
1152 
1153 EAPI void
eina_matrix4_rotate(Eina_Matrix4 * t,double rad,Eina_Matrix_Axis axis)1154 eina_matrix4_rotate(Eina_Matrix4 *t, double rad, Eina_Matrix_Axis axis)
1155 {
1156    double c, s;
1157 
1158    /* Note: Local functions do not guarantee accuracy.
1159     *       Errors occur in the calculation of very small or very large numbers.
1160     *       Local cos and sin functions differ from the math header cosf and sinf functions
1161     *       by result values. The 4th decimal place is different.
1162     *       But local functions are certainly faster than functions in math library.
1163     *       Later we would want someone to look at this and improve accuracy.
1164     */
1165 #if 1
1166    c = cos(rad);
1167    s = sin(rad);
1168 #else
1169    /* normalize the angle between -pi,pi */
1170    rad = fmod(rad + M_PI, 2 * M_PI) - M_PI;
1171    c = _cos(rad);
1172    s = _sin(rad);
1173 #endif
1174 
1175    Eina_Matrix4 tmp;
1176    eina_matrix4_identity(&tmp);
1177 
1178    switch (axis)
1179      {
1180         case EINA_MATRIX_AXIS_X:
1181           MATRIX_YY(&tmp) = c;
1182           MATRIX_YZ(&tmp) = -s;
1183           MATRIX_ZY(&tmp) = s;
1184           MATRIX_ZZ(&tmp) = c;
1185           break;
1186         case EINA_MATRIX_AXIS_Y:
1187           MATRIX_XX(&tmp) = c;
1188           MATRIX_XZ(&tmp) = s;
1189           MATRIX_ZX(&tmp) = -s;
1190           MATRIX_ZZ(&tmp) = c;
1191           break;
1192         case EINA_MATRIX_AXIS_Z:
1193           MATRIX_XX(&tmp) = c;
1194           MATRIX_XY(&tmp) = -s;
1195           MATRIX_YX(&tmp) = s;
1196           MATRIX_YY(&tmp) = c;
1197           break;
1198      }
1199    eina_matrix4_compose(&tmp, t, t);
1200 }
1201 
1202 EAPI void
eina_matrix3_array_set(Eina_Matrix3 * m,const double * v)1203 eina_matrix3_array_set(Eina_Matrix3 *m, const double *v)
1204 {
1205    memcpy(&MATRIX_XX(m), v, sizeof(double) * 9);
1206 }
1207 
1208 EAPI void
eina_matrix3_copy(Eina_Matrix3 * dst,const Eina_Matrix3 * src)1209 eina_matrix3_copy(Eina_Matrix3 *dst, const Eina_Matrix3 *src)
1210 {
1211    memcpy(dst, src, sizeof(Eina_Matrix3));
1212 }
1213 
1214 EAPI void
eina_matrix3_multiply(Eina_Matrix3 * out,const Eina_Matrix3 * mat_a,const Eina_Matrix3 * mat_b)1215 eina_matrix3_multiply(Eina_Matrix3 *out, const Eina_Matrix3 *mat_a, const Eina_Matrix3 *mat_b)
1216 {
1217    if (eina_matrix3_type_get(mat_a) == EINA_MATRIX_TYPE_IDENTITY)
1218      {
1219         eina_matrix3_copy(out, mat_b);
1220         return;
1221      }
1222 
1223    if (eina_matrix3_type_get(mat_b) == EINA_MATRIX_TYPE_IDENTITY)
1224      {
1225         eina_matrix3_copy(out, mat_a);
1226         return;
1227      }
1228 
1229    eina_matrix3_compose(mat_a, mat_b, out);
1230 }
1231 
1232 EAPI void
eina_matrix3_multiply_copy(Eina_Matrix3 * out,const Eina_Matrix3 * mat_a,const Eina_Matrix3 * mat_b)1233 eina_matrix3_multiply_copy(Eina_Matrix3 *out, const Eina_Matrix3 *mat_a, const Eina_Matrix3 *mat_b)
1234 {
1235    if (out != mat_a && out != mat_b)
1236      {
1237         eina_matrix3_multiply(out, mat_a, mat_b);
1238      }
1239    else
1240      {
1241         Eina_Matrix3 tmp;
1242 
1243         eina_matrix3_multiply(&tmp, mat_a, mat_b);
1244         eina_matrix3_copy(out, &tmp);
1245      }
1246 }
1247 
1248 EAPI void
eina_matrix3_position_transform_set(Eina_Matrix3 * out,const double p_x,const double p_y)1249 eina_matrix3_position_transform_set(Eina_Matrix3 *out, const double p_x,
1250 								 const double p_y)
1251 {
1252    eina_matrix3_identity(out);
1253    MATRIX_XZ(out) = p_x;
1254    MATRIX_YZ(out) = p_y;
1255 }
1256 
1257 EAPI void
eina_matrix3_scale_transform_set(Eina_Matrix3 * out,double s_x,double s_y)1258 eina_matrix3_scale_transform_set(Eina_Matrix3 *out, double s_x, double s_y)
1259 {
1260    eina_matrix3_identity(out);
1261    MATRIX_XX(out) = s_x;
1262    MATRIX_YY(out) = s_y;
1263 }
1264 
1265 EAPI void
eina_normal3_matrix_get(Eina_Matrix3 * out,const Eina_Matrix4 * m)1266 eina_normal3_matrix_get(Eina_Matrix3 *out, const Eina_Matrix4 *m)
1267 {
1268    /* Normal matrix is a transposed matrix of inversed modelview.
1269     * And we need only upper-left 3x3 terms to work with. */
1270 
1271    double   det;
1272 
1273    double   a = MATRIX_XX(m);
1274    double   b = MATRIX_YX(m);
1275    double   c = MATRIX_ZX(m);
1276 
1277    double   d = MATRIX_XY(m);
1278    double   e = MATRIX_YY(m);
1279    double   f = MATRIX_ZY(m);
1280 
1281    double   g = MATRIX_XZ(m);
1282    double   h = MATRIX_YZ(m);
1283    double   i = MATRIX_ZZ(m);
1284 
1285    det = a * e * i + b * f * g + c * d * h - g * e * c - h * f * a - i * d * b;
1286 
1287    if (fabs(det) >= DBL_EPSILON) det = 1.0 / det;
1288    else det = 0.0;
1289 
1290    MATRIX_XX(out) = (e * i - f * h) * det;
1291    MATRIX_XY(out) = (h * c - i * b) * det;
1292    MATRIX_XZ(out) = (b * f - c * e) * det;
1293 
1294    MATRIX_YX(out) = (g * f - d * i) * det;
1295    MATRIX_YY(out) = (a * i - g * c) * det;
1296    MATRIX_YZ(out) = (d * c - a * f) * det;
1297 
1298    MATRIX_ZX(out) = (d * h - g * e) * det;
1299    MATRIX_ZY(out) = (g * b - a * h) * det;
1300    MATRIX_ZZ(out) = (a * e - d * b) * det;
1301 }
1302 
1303 EAPI void
eina_matrix2_values_set(Eina_Matrix2 * m,double xx,double xy,double yx,double yy)1304 eina_matrix2_values_set(Eina_Matrix2 *m,
1305                         double xx, double xy,
1306                         double yx, double yy)
1307 {
1308    MATRIX_XX(m) = xx;
1309    MATRIX_XY(m) = xy;
1310    MATRIX_YX(m) = yx;
1311    MATRIX_YY(m) = yy;
1312 }
1313 
1314 EAPI void
eina_matrix2_values_get(const Eina_Matrix2 * m,double * xx,double * xy,double * yx,double * yy)1315 eina_matrix2_values_get(const Eina_Matrix2 *m,
1316                         double *xx, double *xy,
1317                         double *yx, double *yy)
1318 {
1319    if (xx) *xx = MATRIX_XX(m);
1320    if (xy) *xy = MATRIX_XY(m);
1321    if (yx) *yx = MATRIX_YX(m);
1322    if (yy) *yy = MATRIX_YY(m);
1323 }
1324 
1325 EAPI void
eina_matrix2_inverse(Eina_Matrix2 * out,const Eina_Matrix2 * mat)1326 eina_matrix2_inverse(Eina_Matrix2 *out, const Eina_Matrix2 *mat)
1327 {
1328    double         det;
1329 
1330    if (eina_matrix2_type_get(mat) == EINA_MATRIX_TYPE_IDENTITY)
1331      {
1332         eina_matrix2_copy(out, mat);
1333         return;
1334      }
1335 
1336    det = MATRIX_XX(mat) * MATRIX_YY(mat) - MATRIX_YX(mat) * MATRIX_XY(mat);
1337 
1338    if (EINA_DBL_EQ(det, 0.0))
1339      return;
1340 
1341    det = 1.0 / det;
1342 
1343    MATRIX_XX(out) =  MATRIX_YY(mat) * det;
1344    MATRIX_XY(out) = -MATRIX_XY(mat) * det;
1345    MATRIX_YX(out) = -MATRIX_YX(mat) * det;
1346    MATRIX_YY(out) =  MATRIX_XX(mat) * det;
1347 }
1348 
1349 EAPI void
eina_matrix2_identity(Eina_Matrix2 * m)1350 eina_matrix2_identity(Eina_Matrix2 *m)
1351 {
1352    MATRIX_XX(m) = 1.0;
1353    MATRIX_XY(m) = 0.0;
1354 
1355    MATRIX_YX(m) = 0.0;
1356    MATRIX_YY(m) = 1.0;
1357 }
1358 
1359 EAPI void
eina_matrix2_array_set(Eina_Matrix2 * m,const double * v)1360 eina_matrix2_array_set(Eina_Matrix2 *m, const double *v)
1361 {
1362    memcpy(&MATRIX_XX(m), v, sizeof(double) * 4);
1363 }
1364 
1365 EAPI void
eina_matrix2_copy(Eina_Matrix2 * dst,const Eina_Matrix2 * src)1366 eina_matrix2_copy(Eina_Matrix2 *dst, const Eina_Matrix2 *src)
1367 {
1368    memcpy(dst, src, sizeof(Eina_Matrix2));
1369 }
1370 
1371 EAPI void
eina_matrix2_multiply(Eina_Matrix2 * out,const Eina_Matrix2 * mat_a,const Eina_Matrix2 * mat_b)1372 eina_matrix2_multiply(Eina_Matrix2 *out, const Eina_Matrix2 *mat_a, const Eina_Matrix2 *mat_b)
1373 {
1374    if (eina_matrix2_type_get(mat_a) == EINA_MATRIX_TYPE_IDENTITY)
1375      {
1376         eina_matrix2_copy(out, mat_b);
1377         return;
1378      }
1379 
1380    if (eina_matrix2_type_get(mat_b) == EINA_MATRIX_TYPE_IDENTITY)
1381      {
1382         eina_matrix2_copy(out, mat_a);
1383         return;
1384      }
1385 
1386    MATRIX_XX(out) = MATRIX_XX(mat_a) * MATRIX_XX(mat_b) + MATRIX_YX(mat_a) * MATRIX_XY(mat_b);
1387    MATRIX_YX(out) = MATRIX_XX(mat_a) * MATRIX_YX(mat_b) + MATRIX_YX(mat_a) * MATRIX_YY(mat_b);
1388 
1389    MATRIX_XY(out) = MATRIX_XY(mat_a) * MATRIX_XX(mat_b) + MATRIX_YY(mat_a) * MATRIX_XY(mat_b);
1390    MATRIX_YY(out) = MATRIX_XY(mat_a) * MATRIX_YX(mat_b) + MATRIX_YY(mat_a) * MATRIX_YY(mat_b);
1391 }
1392 
1393 EAPI void
eina_matrix2_multiply_copy(Eina_Matrix2 * out,const Eina_Matrix2 * mat_a,const Eina_Matrix2 * mat_b)1394 eina_matrix2_multiply_copy(Eina_Matrix2 *out, const Eina_Matrix2 *mat_a, const Eina_Matrix2 *mat_b)
1395 {
1396    if (out != mat_a && out != mat_b)
1397      {
1398         eina_matrix2_multiply(out, mat_a, mat_b);
1399      }
1400    else
1401      {
1402         Eina_Matrix2 tmp;
1403 
1404         eina_matrix2_multiply(&tmp, mat_a, mat_b);
1405         eina_matrix2_copy(out, &tmp);
1406      }
1407 }
1408