lottie/vector: move pixman code to separate pixman folder.
[platform/core/uifw/lottie-player.git] / src / vector / vmatrix.cpp
1 /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved.
3  *
4  * Licensed under the Flora License, Version 1.1 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://floralicense.org/license/
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "vmatrix.h"
18 #include <vglobal.h>
19 #include <cassert>
20 #include <cmath>
21 #include <cstring>
22
23 V_BEGIN_NAMESPACE
24
25 /*  m11  m21  mtx
26  *  m12  m22  mty
27  *  m13  m23  m33
28  */
29
30 inline float VMatrix::determinant() const
31 {
32     return m11 * (m33 * m22 - mty * m23) - m21 * (m33 * m12 - mty * m13) +
33            mtx * (m23 * m12 - m22 * m13);
34 }
35
36 bool VMatrix::isAffine() const
37 {
38     return type() < MatrixType::Project;
39 }
40
41 bool VMatrix::isIdentity() const
42 {
43     return type() == MatrixType::None;
44 }
45
46 bool VMatrix::isInvertible() const
47 {
48     return !vIsZero(determinant());
49 }
50
51 bool VMatrix::isScaling() const
52 {
53     return type() >= MatrixType::Scale;
54 }
55 bool VMatrix::isRotating() const
56 {
57     return type() >= MatrixType::Rotate;
58 }
59
60 bool VMatrix::isTranslating() const
61 {
62     return type() >= MatrixType::Translate;
63 }
64
65 VMatrix &VMatrix::operator*=(float num)
66 {
67     if (num == 1.) return *this;
68
69     m11 *= num;
70     m12 *= num;
71     m13 *= num;
72     m21 *= num;
73     m22 *= num;
74     m23 *= num;
75     mtx *= num;
76     mty *= num;
77     m33 *= num;
78     if (dirty < MatrixType::Scale) dirty = MatrixType::Scale;
79
80     return *this;
81 }
82
83 VMatrix &VMatrix::operator/=(float div)
84 {
85     if (div == 0) return *this;
86
87     div = 1 / div;
88     return operator*=(div);
89 }
90
91 VMatrix::MatrixType VMatrix::type() const
92 {
93     if (dirty == MatrixType::None || dirty < mType) return mType;
94
95     switch (dirty) {
96     case MatrixType::Project:
97         if (!vIsZero(m13) || !vIsZero(m23) || !vIsZero(m33 - 1)) {
98             mType = MatrixType::Project;
99             break;
100         }
101     case MatrixType::Shear:
102     case MatrixType::Rotate:
103         if (!vIsZero(m12) || !vIsZero(m21)) {
104             const float dot = m11 * m12 + m21 * m22;
105             if (vIsZero(dot))
106                 mType = MatrixType::Rotate;
107             else
108                 mType = MatrixType::Shear;
109             break;
110         }
111     case MatrixType::Scale:
112         if (!vIsZero(m11 - 1) || !vIsZero(m22 - 1)) {
113             mType = MatrixType::Scale;
114             break;
115         }
116     case MatrixType::Translate:
117         if (!vIsZero(mtx) || !vIsZero(mty)) {
118             mType = MatrixType::Translate;
119             break;
120         }
121     case MatrixType::None:
122         mType = MatrixType::None;
123         break;
124     }
125
126     dirty = MatrixType::None;
127     return mType;
128 }
129
130 VMatrix &VMatrix::translate(float dx, float dy)
131 {
132     if (dx == 0 && dy == 0) return *this;
133
134     switch (type()) {
135     case MatrixType::None:
136         mtx = dx;
137         mty = dy;
138         break;
139     case MatrixType::Translate:
140         mtx += dx;
141         mty += dy;
142         break;
143     case MatrixType::Scale:
144         mtx += dx * m11;
145         mty += dy * m22;
146         break;
147     case MatrixType::Project:
148         m33 += dx * m13 + dy * m23;
149         VECTOR_FALLTHROUGH
150     case MatrixType::Shear:
151     case MatrixType::Rotate:
152         mtx += dx * m11 + dy * m21;
153         mty += dy * m22 + dx * m12;
154         break;
155     }
156     if (dirty < MatrixType::Translate) dirty = MatrixType::Translate;
157     return *this;
158 }
159
160 VMatrix &VMatrix::scale(float sx, float sy)
161 {
162     if (sx == 1 && sy == 1) return *this;
163
164     switch (type()) {
165     case MatrixType::None:
166     case MatrixType::Translate:
167         m11 = sx;
168         m22 = sy;
169         break;
170     case MatrixType::Project:
171         m13 *= sx;
172         m23 *= sy;
173         VECTOR_FALLTHROUGH
174     case MatrixType::Rotate:
175     case MatrixType::Shear:
176         m12 *= sx;
177         m21 *= sy;
178         VECTOR_FALLTHROUGH
179     case MatrixType::Scale:
180         m11 *= sx;
181         m22 *= sy;
182         break;
183     }
184     if (dirty < MatrixType::Scale) dirty = MatrixType::Scale;
185     return *this;
186 }
187
188 VMatrix &VMatrix::shear(float sh, float sv)
189 {
190     if (sh == 0 && sv == 0) return *this;
191
192     switch (type()) {
193     case MatrixType::None:
194     case MatrixType::Translate:
195         m12 = sv;
196         m21 = sh;
197         break;
198     case MatrixType::Scale:
199         m12 = sv * m22;
200         m21 = sh * m11;
201         break;
202     case MatrixType::Project: {
203         float tm13 = sv * m23;
204         float tm23 = sh * m13;
205         m13 += tm13;
206         m23 += tm23;
207         VECTOR_FALLTHROUGH
208     }
209     case MatrixType::Rotate:
210     case MatrixType::Shear: {
211         float tm11 = sv * m21;
212         float tm22 = sh * m12;
213         float tm12 = sv * m22;
214         float tm21 = sh * m11;
215         m11 += tm11;
216         m12 += tm12;
217         m21 += tm21;
218         m22 += tm22;
219         break;
220     }
221     }
222     if (dirty < MatrixType::Shear) dirty = MatrixType::Shear;
223     return *this;
224 }
225
226 static const float deg2rad = float(0.017453292519943295769);  // pi/180
227 static const float inv_dist_to_plane = 1. / 1024.;
228
229 VMatrix &VMatrix::rotate(float a, Axis axis)
230 {
231     if (a == 0) return *this;
232
233     float sina = 0;
234     float cosa = 0;
235     if (a == 90. || a == -270.)
236         sina = 1.;
237     else if (a == 270. || a == -90.)
238         sina = -1.;
239     else if (a == 180.)
240         cosa = -1.;
241     else {
242         float b = deg2rad * a;  // convert to radians
243         sina = std::sin(b);     // fast and convenient
244         cosa = std::cos(b);
245     }
246
247     if (axis == Axis::Z) {
248         switch (type()) {
249         case MatrixType::None:
250         case MatrixType::Translate:
251             m11 = cosa;
252             m12 = sina;
253             m21 = -sina;
254             m22 = cosa;
255             break;
256         case MatrixType::Scale: {
257             float tm11 = cosa * m11;
258             float tm12 = sina * m22;
259             float tm21 = -sina * m11;
260             float tm22 = cosa * m22;
261             m11 = tm11;
262             m12 = tm12;
263             m21 = tm21;
264             m22 = tm22;
265             break;
266         }
267         case MatrixType::Project: {
268             float tm13 = cosa * m13 + sina * m23;
269             float tm23 = -sina * m13 + cosa * m23;
270             m13 = tm13;
271             m23 = tm23;
272             VECTOR_FALLTHROUGH
273         }
274         case MatrixType::Rotate:
275         case MatrixType::Shear: {
276             float tm11 = cosa * m11 + sina * m21;
277             float tm12 = cosa * m12 + sina * m22;
278             float tm21 = -sina * m11 + cosa * m21;
279             float tm22 = -sina * m12 + cosa * m22;
280             m11 = tm11;
281             m12 = tm12;
282             m21 = tm21;
283             m22 = tm22;
284             break;
285         }
286         }
287         if (dirty < MatrixType::Rotate) dirty = MatrixType::Rotate;
288     } else {
289         VMatrix result;
290         if (axis == Axis::Y) {
291             result.m11 = cosa;
292             result.m13 = -sina * inv_dist_to_plane;
293         } else {
294             result.m22 = cosa;
295             result.m23 = -sina * inv_dist_to_plane;
296         }
297         result.mType = MatrixType::Project;
298         *this = result * *this;
299     }
300
301     return *this;
302 }
303
304 VMatrix VMatrix::operator*(const VMatrix &m) const
305 {
306     const MatrixType otherType = m.type();
307     if (otherType == MatrixType::None) return *this;
308
309     const MatrixType thisType = type();
310     if (thisType == MatrixType::None) return m;
311
312     VMatrix    t;
313     MatrixType type = vMax(thisType, otherType);
314     switch (type) {
315     case MatrixType::None:
316         break;
317     case MatrixType::Translate:
318         t.mtx = mtx + m.mtx;
319         t.mty += mty + m.mty;
320         break;
321     case MatrixType::Scale: {
322         float m11v = m11 * m.m11;
323         float m22v = m22 * m.m22;
324
325         float m31v = mtx * m.m11 + m.mtx;
326         float m32v = mty * m.m22 + m.mty;
327
328         t.m11 = m11v;
329         t.m22 = m22v;
330         t.mtx = m31v;
331         t.mty = m32v;
332         break;
333     }
334     case MatrixType::Rotate:
335     case MatrixType::Shear: {
336         float m11v = m11 * m.m11 + m12 * m.m21;
337         float m12v = m11 * m.m12 + m12 * m.m22;
338
339         float m21v = m21 * m.m11 + m22 * m.m21;
340         float m22v = m21 * m.m12 + m22 * m.m22;
341
342         float m31v = mtx * m.m11 + mty * m.m21 + m.mtx;
343         float m32v = mtx * m.m12 + mty * m.m22 + m.mty;
344
345         t.m11 = m11v;
346         t.m12 = m12v;
347         t.m21 = m21v;
348         t.m22 = m22v;
349         t.mtx = m31v;
350         t.mty = m32v;
351         break;
352     }
353     case MatrixType::Project: {
354         float m11v = m11 * m.m11 + m12 * m.m21 + m13 * m.mtx;
355         float m12v = m11 * m.m12 + m12 * m.m22 + m13 * m.mty;
356         float m13v = m11 * m.m13 + m12 * m.m23 + m13 * m.m33;
357
358         float m21v = m21 * m.m11 + m22 * m.m21 + m23 * m.mtx;
359         float m22v = m21 * m.m12 + m22 * m.m22 + m23 * m.mty;
360         float m23v = m21 * m.m13 + m22 * m.m23 + m23 * m.m33;
361
362         float m31v = mtx * m.m11 + mty * m.m21 + m33 * m.mtx;
363         float m32v = mtx * m.m12 + mty * m.m22 + m33 * m.mty;
364         float m33v = mtx * m.m13 + mty * m.m23 + m33 * m.m33;
365
366         t.m11 = m11v;
367         t.m12 = m12v;
368         t.m13 = m13v;
369         t.m21 = m21v;
370         t.m22 = m22v;
371         t.m23 = m23v;
372         t.mtx = m31v;
373         t.mty = m32v;
374         t.m33 = m33v;
375     }
376     }
377
378     t.dirty = type;
379     t.mType = type;
380
381     return t;
382 }
383
384 VMatrix &VMatrix::operator*=(const VMatrix &o)
385 {
386     const MatrixType otherType = o.type();
387     if (otherType == MatrixType::None) return *this;
388
389     const MatrixType thisType = type();
390     if (thisType == MatrixType::None) return operator=(o);
391
392     MatrixType t = vMax(thisType, otherType);
393     switch (t) {
394     case MatrixType::None:
395         break;
396     case MatrixType::Translate:
397         mtx += o.mtx;
398         mty += o.mty;
399         break;
400     case MatrixType::Scale: {
401         float m11v = m11 * o.m11;
402         float m22v = m22 * o.m22;
403
404         float m31v = mtx * o.m11 + o.mtx;
405         float m32v = mty * o.m22 + o.mty;
406
407         m11 = m11v;
408         m22 = m22v;
409         mtx = m31v;
410         mty = m32v;
411         break;
412     }
413     case MatrixType::Rotate:
414     case MatrixType::Shear: {
415         float m11v = m11 * o.m11 + m12 * o.m21;
416         float m12v = m11 * o.m12 + m12 * o.m22;
417
418         float m21v = m21 * o.m11 + m22 * o.m21;
419         float m22v = m21 * o.m12 + m22 * o.m22;
420
421         float m31v = mtx * o.m11 + mty * o.m21 + o.mtx;
422         float m32v = mtx * o.m12 + mty * o.m22 + o.mty;
423
424         m11 = m11v;
425         m12 = m12v;
426         m21 = m21v;
427         m22 = m22v;
428         mtx = m31v;
429         mty = m32v;
430         break;
431     }
432     case MatrixType::Project: {
433         float m11v = m11 * o.m11 + m12 * o.m21 + m13 * o.mtx;
434         float m12v = m11 * o.m12 + m12 * o.m22 + m13 * o.mty;
435         float m13v = m11 * o.m13 + m12 * o.m23 + m13 * o.m33;
436
437         float m21v = m21 * o.m11 + m22 * o.m21 + m23 * o.mtx;
438         float m22v = m21 * o.m12 + m22 * o.m22 + m23 * o.mty;
439         float m23v = m21 * o.m13 + m22 * o.m23 + m23 * o.m33;
440
441         float m31v = mtx * o.m11 + mty * o.m21 + m33 * o.mtx;
442         float m32v = mtx * o.m12 + mty * o.m22 + m33 * o.mty;
443         float m33v = mtx * o.m13 + mty * o.m23 + m33 * o.m33;
444
445         m11 = m11v;
446         m12 = m12v;
447         m13 = m13v;
448         m21 = m21v;
449         m22 = m22v;
450         m23 = m23v;
451         mtx = m31v;
452         mty = m32v;
453         m33 = m33v;
454     }
455     }
456
457     dirty = t;
458     mType = t;
459
460     return *this;
461 }
462
463 VMatrix VMatrix::adjoint() const
464 {
465     float h11, h12, h13, h21, h22, h23, h31, h32, h33;
466     h11 = m22 * m33 - m23 * mty;
467     h21 = m23 * mtx - m21 * m33;
468     h31 = m21 * mty - m22 * mtx;
469     h12 = m13 * mty - m12 * m33;
470     h22 = m11 * m33 - m13 * mtx;
471     h32 = m12 * mtx - m11 * mty;
472     h13 = m12 * m23 - m13 * m22;
473     h23 = m13 * m21 - m11 * m23;
474     h33 = m11 * m22 - m12 * m21;
475
476     VMatrix res;
477     res.m11 = h11;
478     res.m12 = h12;
479     res.m13 = h13;
480     res.m21 = h21;
481     res.m22 = h22;
482     res.m23 = h23;
483     res.mtx = h31;
484     res.mty = h32;
485     res.m33 = h33;
486     res.mType = MatrixType::None;
487     res.dirty = MatrixType::Project;
488
489     return res;
490 }
491
492 VMatrix VMatrix::inverted(bool *invertible) const
493 {
494     VMatrix invert;
495     bool    inv = true;
496
497     switch (type()) {
498     case MatrixType::None:
499         break;
500     case MatrixType::Translate:
501         invert.mtx = -mtx;
502         invert.mty = -mty;
503         break;
504     case MatrixType::Scale:
505         inv = !vIsZero(m11);
506         inv &= !vIsZero(m22);
507         if (inv) {
508             invert.m11 = 1. / m11;
509             invert.m22 = 1. / m22;
510             invert.mtx = -mtx * invert.m11;
511             invert.mty = -mty * invert.m22;
512         }
513         break;
514     default:
515         // general case
516         float det = determinant();
517         inv = !vIsZero(det);
518         if (inv) invert = (adjoint() /= det);
519         // TODO Test above line
520         break;
521     }
522
523     if (invertible) *invertible = inv;
524
525     if (inv) {
526         // inverting doesn't change the type
527         invert.mType = mType;
528         invert.dirty = dirty;
529     }
530
531     return invert;
532 }
533
534 bool VMatrix::operator==(const VMatrix &o) const
535 {
536     return fuzzyCompare(o);
537 }
538
539 bool VMatrix::operator!=(const VMatrix &o) const
540 {
541     return !operator==(o);
542 }
543
544 bool VMatrix::fuzzyCompare(const VMatrix &o) const
545 {
546     return vCompare(m11, o.m11) && vCompare(m12, o.m12) &&
547            vCompare(m21, o.m21) && vCompare(m22, o.m22) &&
548            vCompare(mtx, o.mtx) && vCompare(mty, o.mty);
549 }
550
551 #define V_NEAR_CLIP 0.000001
552 #ifdef MAP
553 #undef MAP
554 #endif
555 #define MAP(x, y, nx, ny)                                \
556     do {                                                 \
557         float FX_ = x;                                   \
558         float FY_ = y;                                   \
559         switch (t) {                                     \
560         case MatrixType::None:                           \
561             nx = FX_;                                    \
562             ny = FY_;                                    \
563             break;                                       \
564         case MatrixType::Translate:                      \
565             nx = FX_ + mtx;                              \
566             ny = FY_ + mty;                              \
567             break;                                       \
568         case MatrixType::Scale:                          \
569             nx = m11 * FX_ + mtx;                        \
570             ny = m22 * FY_ + mty;                        \
571             break;                                       \
572         case MatrixType::Rotate:                         \
573         case MatrixType::Shear:                          \
574         case MatrixType::Project:                        \
575             nx = m11 * FX_ + m21 * FY_ + mtx;            \
576             ny = m12 * FX_ + m22 * FY_ + mty;            \
577             if (t == MatrixType::Project) {              \
578                 float w = (m13 * FX_ + m23 * FY_ + m33); \
579                 if (w < V_NEAR_CLIP) w = V_NEAR_CLIP;    \
580                 w = 1. / w;                              \
581                 nx *= w;                                 \
582                 ny *= w;                                 \
583             }                                            \
584         }                                                \
585     } while (0)
586
587 VRect VMatrix::map(const VRect &rect) const
588 {
589     VMatrix::MatrixType t = type();
590     if (t <= MatrixType::Translate)
591         return rect.translated(std::round(mtx), std::round(mty));
592
593     if (t <= MatrixType::Scale) {
594         int x = std::round(m11 * rect.x() + mtx);
595         int y = std::round(m22 * rect.y() + mty);
596         int w = std::round(m11 * rect.width());
597         int h = std::round(m22 * rect.height());
598         if (w < 0) {
599             w = -w;
600             x -= w;
601         }
602         if (h < 0) {
603             h = -h;
604             y -= h;
605         }
606         return {x, y, w, h};
607     } else if (t < MatrixType::Project) {
608         // see mapToPolygon for explanations of the algorithm.
609         float x = 0, y = 0;
610         MAP(rect.left(), rect.top(), x, y);
611         float xmin = x;
612         float ymin = y;
613         float xmax = x;
614         float ymax = y;
615         MAP(rect.right() + 1, rect.top(), x, y);
616         xmin = vMin(xmin, x);
617         ymin = vMin(ymin, y);
618         xmax = vMax(xmax, x);
619         ymax = vMax(ymax, y);
620         MAP(rect.right() + 1, rect.bottom() + 1, x, y);
621         xmin = vMin(xmin, x);
622         ymin = vMin(ymin, y);
623         xmax = vMax(xmax, x);
624         ymax = vMax(ymax, y);
625         MAP(rect.left(), rect.bottom() + 1, x, y);
626         xmin = vMin(xmin, x);
627         ymin = vMin(ymin, y);
628         xmax = vMax(xmax, x);
629         ymax = vMax(ymax, y);
630         return VRect(std::round(xmin), std::round(ymin),
631                      std::round(xmax) - std::round(xmin),
632                      std::round(ymax) - std::round(ymin));
633     } else {
634         // Not supported
635         assert(0);
636     }
637 }
638
639 VRegion VMatrix::map(const VRegion &r) const
640 {
641     VMatrix::MatrixType t = type();
642     if (t == MatrixType::None) return r;
643
644     if (t == MatrixType::Translate) {
645         VRegion copy(r);
646         copy.translate(std::round(mtx), std::round(mty));
647         return copy;
648     }
649
650     if (t == MatrixType::Scale && r.rectCount() == 1)
651         return VRegion(map(r.boundingRect()));
652     // handle mapping of region properly
653     assert(0);
654     return r;
655 }
656
657 VPointF VMatrix::map(const VPointF &p) const
658 {
659     float fx = p.x();
660     float fy = p.y();
661
662     float x = 0, y = 0;
663
664     VMatrix::MatrixType t = type();
665     switch (t) {
666     case MatrixType::None:
667         x = fx;
668         y = fy;
669         break;
670     case MatrixType::Translate:
671         x = fx + mtx;
672         y = fy + mty;
673         break;
674     case MatrixType::Scale:
675         x = m11 * fx + mtx;
676         y = m22 * fy + mty;
677         break;
678     case MatrixType::Rotate:
679     case MatrixType::Shear:
680     case MatrixType::Project:
681         x = m11 * fx + m21 * fy + mtx;
682         y = m12 * fx + m22 * fy + mty;
683         if (t == MatrixType::Project) {
684             float w = 1. / (m13 * fx + m23 * fy + m33);
685             x *= w;
686             y *= w;
687         }
688     }
689     return {x, y};
690 }
691 static std::string type_helper(VMatrix::MatrixType t)
692 {
693     switch (t) {
694     case VMatrix::MatrixType::None:
695         return "MatrixType::None";
696         break;
697     case VMatrix::MatrixType::Translate:
698         return "MatrixType::Translate";
699         break;
700     case VMatrix::MatrixType::Scale:
701         return "MatrixType::Scale";
702         break;
703     case VMatrix::MatrixType::Rotate:
704         return "MatrixType::Rotate";
705         break;
706     case VMatrix::MatrixType::Shear:
707         return "MatrixType::Shear";
708         break;
709     case VMatrix::MatrixType::Project:
710         return "MatrixType::Project";
711         break;
712     }
713     return "";
714 }
715 std::ostream &operator<<(std::ostream &os, const VMatrix &o)
716 {
717     os << "[Matrix: "
718        << "type =" << type_helper(o.type()) << ", Data : " << o.m11 << " "
719        << o.m12 << " " << o.m13 << " " << o.m21 << " " << o.m22 << " " << o.m23
720        << " " << o.mtx << " " << o.mty << " " << o.m33 << " "
721        << "]" << std::endl;
722     return os;
723 }
724
725 V_END_NAMESPACE