kodi
TransformMatrix.h
1 /*
2  * Copyright (C) 2005-2018 Team Kodi
3  * This file is part of Kodi - https://kodi.tv
4  *
5  * SPDX-License-Identifier: GPL-2.0-or-later
6  * See LICENSES/README.md for more information.
7  */
8 
9 #pragma once
10 
11 #include "utils/ColorUtils.h"
12 
13 #include <algorithm>
14 #include <math.h>
15 #include <memory>
16 #include <string.h>
17 
18 #ifdef __GNUC__
19 // under gcc, inline will only take place if optimizations are applied (-O). this will force inline even with optimizations.
20 #define XBMC_FORCE_INLINE __attribute__((always_inline))
21 #else
22 #define XBMC_FORCE_INLINE
23 #endif
24 
26 {
27 public:
29  {
30  Reset();
31  };
32  void Reset()
33  {
34  m[0][0] = 1.0f; m[0][1] = m[0][2] = m[0][3] = 0.0f;
35  m[1][0] = m[1][2] = m[1][3] = 0.0f; m[1][1] = 1.0f;
36  m[2][0] = m[2][1] = m[2][3] = 0.0f; m[2][2] = 1.0f;
37  alpha = red = green = blue = 1.0f;
38  identity = true;
39  };
40  static TransformMatrix CreateTranslation(float transX, float transY, float transZ = 0)
41  {
42  TransformMatrix translation;
43  translation.SetTranslation(transX, transY, transZ);
44  return translation;
45  }
46  void SetTranslation(float transX, float transY, float transZ)
47  {
48  m[0][1] = m[0][2] = 0.0f; m[0][0] = 1.0f; m[0][3] = transX;
49  m[1][0] = m[1][2] = 0.0f; m[1][1] = 1.0f; m[1][3] = transY;
50  m[2][0] = m[2][1] = 0.0f; m[2][2] = 1.0f; m[2][3] = transZ;
51  alpha = red = green = blue = 1.0f;
52  identity = (transX == 0 && transY == 0 && transZ == 0);
53  }
54  static TransformMatrix CreateScaler(float scaleX, float scaleY, float scaleZ = 1.0f)
55  {
56  TransformMatrix scaler;
57  scaler.m[0][0] = scaleX;
58  scaler.m[1][1] = scaleY;
59  scaler.m[2][2] = scaleZ;
60  scaler.identity = (scaleX == 1 && scaleY == 1 && scaleZ == 1);
61  return scaler;
62  };
63  void SetScaler(float scaleX, float scaleY, float centerX, float centerY)
64  {
65  // Trans(centerX,centerY,centerZ)*Scale(scaleX,scaleY,scaleZ)*Trans(-centerX,-centerY,-centerZ)
66  float centerZ = 0.0f, scaleZ = 1.0f;
67  m[0][0] = scaleX; m[0][1] = 0.0f; m[0][2] = 0.0f; m[0][3] = centerX*(1-scaleX);
68  m[1][0] = 0.0f; m[1][1] = scaleY; m[1][2] = 0.0f; m[1][3] = centerY*(1-scaleY);
69  m[2][0] = 0.0f; m[2][1] = 0.0f; m[2][2] = scaleZ; m[2][3] = centerZ*(1-scaleZ);
70  alpha = red = green = blue = 1.0f;
71  identity = (scaleX == 1 && scaleY == 1);
72  };
73  void SetXRotation(float angle, float y, float z, float ar = 1.0f)
74  { // angle about the X axis, centered at y,z where our coordinate system has aspect ratio ar.
75  // Trans(0,y,z)*Scale(1,1/ar,1)*RotateX(angle)*Scale(ar,1,1)*Trans(0,-y,-z);
76  float c = cos(angle); float s = sin(angle);
77  m[0][0] = ar; m[0][1] = 0.0f; m[0][2] = 0.0f; m[0][3] = 0.0f;
78  m[1][0] = 0.0f; m[1][1] = c/ar; m[1][2] = -s/ar; m[1][3] = (-y*c+s*z)/ar + y;
79  m[2][0] = 0.0f; m[2][1] = s; m[2][2] = c; m[2][3] = (-y*s-c*z) + z;
80  alpha = red = green = blue = 1.0f;
81  identity = (angle == 0);
82  }
83  void SetYRotation(float angle, float x, float z, float ar = 1.0f)
84  { // angle about the Y axis, centered at x,z where our coordinate system has aspect ratio ar.
85  // Trans(x,0,z)*Scale(1/ar,1,1)*RotateY(angle)*Scale(ar,1,1)*Trans(-x,0,-z);
86  float c = cos(angle); float s = sin(angle);
87  m[0][0] = c; m[0][1] = 0.0f; m[0][2] = -s/ar; m[0][3] = -x*c + s*z/ar + x;
88  m[1][0] = 0.0f; m[1][1] = 1.0f; m[1][2] = 0.0f; m[1][3] = 0.0f;
89  m[2][0] = ar*s; m[2][1] = 0.0f; m[2][2] = c; m[2][3] = -ar*x*s - c*z + z;
90  alpha = red = green = blue = 1.0f;
91  identity = (angle == 0);
92  }
93  static TransformMatrix CreateZRotation(float angle, float x, float y, float ar = 1.0f)
94  { // angle about the Z axis, centered at x,y where our coordinate system has aspect ratio ar.
95  // Trans(x,y,0)*Scale(1/ar,1,1)*RotateZ(angle)*Scale(ar,1,1)*Trans(-x,-y,0)
96  TransformMatrix rot;
97  rot.SetZRotation(angle, x, y, ar);
98  return rot;
99  }
100  void SetZRotation(float angle, float x, float y, float ar = 1.0f)
101  { // angle about the Z axis, centered at x,y where our coordinate system has aspect ratio ar.
102  // Trans(x,y,0)*Scale(1/ar,1,1)*RotateZ(angle)*Scale(ar,1,1)*Trans(-x,-y,0)
103  float c = cos(angle); float s = sin(angle);
104  m[0][0] = c; m[0][1] = -s/ar; m[0][2] = 0.0f; m[0][3] = -x*c + s*y/ar + x;
105  m[1][0] = s*ar; m[1][1] = c; m[1][2] = 0.0f; m[1][3] = -ar*x*s - c*y + y;
106  m[2][0] = 0.0f; m[2][1] = 0.0f; m[2][2] = 1.0f; m[2][3] = 0.0f;
107  alpha = red = green = blue = 1.0f;
108  identity = (angle == 0);
109  }
110  static TransformMatrix CreateFader(float a)
111  {
112  TransformMatrix fader;
113  fader.SetFader(a);
114  return fader;
115  }
116  static TransformMatrix CreateFader(float a, float r, float g, float b)
117  {
118  TransformMatrix fader;
119  fader.SetFader(a, r, g, b);
120  return fader;
121  }
122  void SetFader(float a)
123  {
124  m[0][0] = 1.0f; m[0][1] = 0.0f; m[0][2] = 0.0f; m[0][3] = 0.0f;
125  m[1][0] = 0.0f; m[1][1] = 1.0f; m[1][2] = 0.0f; m[1][3] = 0.0f;
126  m[2][0] = 0.0f; m[2][1] = 0.0f; m[2][2] = 1.0f; m[2][3] = 0.0f;
127  alpha = a;
128  red = green = blue = 1.0f;
129  identity = (a == 1.0f);
130  }
131 
132  void SetFader(float a, float r, float g, float b)
133  {
134  m[0][0] = 1.0f; m[0][1] = 0.0f; m[0][2] = 0.0f; m[0][3] = 0.0f;
135  m[1][0] = 0.0f; m[1][1] = 1.0f; m[1][2] = 0.0f; m[1][3] = 0.0f;
136  m[2][0] = 0.0f; m[2][1] = 0.0f; m[2][2] = 1.0f; m[2][3] = 0.0f;
137  alpha = a;
138  red = r;
139  green = g;
140  blue = b;
141  identity = ((a == 1.0f) && (r == 1.0f) && (g == 1.0f) && (b == 1.0f));
142  }
143 
144  // multiplication operators
145  const TransformMatrix &operator *=(const TransformMatrix &right)
146  {
147  if (right.identity)
148  return *this;
149  if (identity)
150  {
151  *this = right;
152  return *this;
153  }
154  float t00 = m[0][0] * right.m[0][0] + m[0][1] * right.m[1][0] + m[0][2] * right.m[2][0];
155  float t01 = m[0][0] * right.m[0][1] + m[0][1] * right.m[1][1] + m[0][2] * right.m[2][1];
156  float t02 = m[0][0] * right.m[0][2] + m[0][1] * right.m[1][2] + m[0][2] * right.m[2][2];
157  m[0][3] = m[0][0] * right.m[0][3] + m[0][1] * right.m[1][3] + m[0][2] * right.m[2][3] + m[0][3];
158  m[0][0] = t00; m[0][1] = t01; m[0][2] = t02;
159  t00 = m[1][0] * right.m[0][0] + m[1][1] * right.m[1][0] + m[1][2] * right.m[2][0];
160  t01 = m[1][0] * right.m[0][1] + m[1][1] * right.m[1][1] + m[1][2] * right.m[2][1];
161  t02 = m[1][0] * right.m[0][2] + m[1][1] * right.m[1][2] + m[1][2] * right.m[2][2];
162  m[1][3] = m[1][0] * right.m[0][3] + m[1][1] * right.m[1][3] + m[1][2] * right.m[2][3] + m[1][3];
163  m[1][0] = t00; m[1][1] = t01; m[1][2] = t02;
164  t00 = m[2][0] * right.m[0][0] + m[2][1] * right.m[1][0] + m[2][2] * right.m[2][0];
165  t01 = m[2][0] * right.m[0][1] + m[2][1] * right.m[1][1] + m[2][2] * right.m[2][1];
166  t02 = m[2][0] * right.m[0][2] + m[2][1] * right.m[1][2] + m[2][2] * right.m[2][2];
167  m[2][3] = m[2][0] * right.m[0][3] + m[2][1] * right.m[1][3] + m[2][2] * right.m[2][3] + m[2][3];
168  m[2][0] = t00; m[2][1] = t01; m[2][2] = t02;
169  alpha *= right.alpha;
170  red *= right.red;
171  green *= right.green;
172  blue *= right.blue;
173  identity = false;
174  return *this;
175  }
176 
177  TransformMatrix operator *(const TransformMatrix &right) const
178  {
179  if (right.identity)
180  return *this;
181  if (identity)
182  return right;
183  TransformMatrix result;
184  result.m[0][0] = m[0][0] * right.m[0][0] + m[0][1] * right.m[1][0] + m[0][2] * right.m[2][0];
185  result.m[0][1] = m[0][0] * right.m[0][1] + m[0][1] * right.m[1][1] + m[0][2] * right.m[2][1];
186  result.m[0][2] = m[0][0] * right.m[0][2] + m[0][1] * right.m[1][2] + m[0][2] * right.m[2][2];
187  result.m[0][3] = m[0][0] * right.m[0][3] + m[0][1] * right.m[1][3] + m[0][2] * right.m[2][3] + m[0][3];
188  result.m[1][0] = m[1][0] * right.m[0][0] + m[1][1] * right.m[1][0] + m[1][2] * right.m[2][0];
189  result.m[1][1] = m[1][0] * right.m[0][1] + m[1][1] * right.m[1][1] + m[1][2] * right.m[2][1];
190  result.m[1][2] = m[1][0] * right.m[0][2] + m[1][1] * right.m[1][2] + m[1][2] * right.m[2][2];
191  result.m[1][3] = m[1][0] * right.m[0][3] + m[1][1] * right.m[1][3] + m[1][2] * right.m[2][3] + m[1][3];
192  result.m[2][0] = m[2][0] * right.m[0][0] + m[2][1] * right.m[1][0] + m[2][2] * right.m[2][0];
193  result.m[2][1] = m[2][0] * right.m[0][1] + m[2][1] * right.m[1][1] + m[2][2] * right.m[2][1];
194  result.m[2][2] = m[2][0] * right.m[0][2] + m[2][1] * right.m[1][2] + m[2][2] * right.m[2][2];
195  result.m[2][3] = m[2][0] * right.m[0][3] + m[2][1] * right.m[1][3] + m[2][2] * right.m[2][3] + m[2][3];
196  result.alpha = alpha * right.alpha;
197  result.red = red * right.red;
198  result.green = green * right.green;
199  result.blue = blue * right.blue;
200  result.identity = false;
201  return result;
202  }
203 
204  inline void TransformPosition(float &x, float &y, float &z) const XBMC_FORCE_INLINE
205  {
206  float newX = m[0][0] * x + m[0][1] * y + m[0][2] * z + m[0][3];
207  float newY = m[1][0] * x + m[1][1] * y + m[1][2] * z + m[1][3];
208  z = m[2][0] * x + m[2][1] * y + m[2][2] * z + m[2][3];
209  y = newY;
210  x = newX;
211  }
212 
213  inline void TransformPositionUnscaled(float &x, float &y, float &z) const XBMC_FORCE_INLINE
214  {
215  float n;
216  // calculate the norm of the transformed (but not translated) vectors involved
217  n = sqrt(m[0][0]*m[0][0] + m[0][1]*m[0][1] + m[0][2]*m[0][2]);
218  float newX = (m[0][0] * x + m[0][1] * y + m[0][2] * z)/n + m[0][3];
219  n = sqrt(m[1][0]*m[1][0] + m[1][1]*m[1][1] + m[1][2]*m[1][2]);
220  float newY = (m[1][0] * x + m[1][1] * y + m[1][2] * z)/n + m[1][3];
221  n = sqrt(m[2][0]*m[2][0] + m[2][1]*m[2][1] + m[2][2]*m[2][2]);
222  float newZ = (m[2][0] * x + m[2][1] * y + m[2][2] * z)/n + m[2][3];
223  z = newZ;
224  y = newY;
225  x = newX;
226  }
227 
228  inline void InverseTransformPosition(float &x, float &y) const XBMC_FORCE_INLINE
229  { // used for mouse - no way to find z
230  x -= m[0][3]; y -= m[1][3];
231  float detM = m[0][0]*m[1][1] - m[0][1]*m[1][0];
232  float newX = (m[1][1] * x - m[0][1] * y)/detM;
233  y = (-m[1][0] * x + m[0][0] * y)/detM;
234  x = newX;
235  }
236 
237  inline float TransformXCoord(float x, float y, float z) const XBMC_FORCE_INLINE
238  {
239  return m[0][0] * x + m[0][1] * y + m[0][2] * z + m[0][3];
240  }
241 
242  inline float TransformYCoord(float x, float y, float z) const XBMC_FORCE_INLINE
243  {
244  return m[1][0] * x + m[1][1] * y + m[1][2] * z + m[1][3];
245  }
246 
247  inline float TransformZCoord(float x, float y, float z) const XBMC_FORCE_INLINE
248  {
249  return m[2][0] * x + m[2][1] * y + m[2][2] * z + m[2][3];
250  }
251 
252  inline UTILS::COLOR::Color TransformAlpha(UTILS::COLOR::Color color) const XBMC_FORCE_INLINE
253  {
254  return static_cast<UTILS::COLOR::Color>(color * alpha);
255  }
256 
257  inline UTILS::COLOR::Color TransformColor(UTILS::COLOR::Color color) const XBMC_FORCE_INLINE
258  {
259  UTILS::COLOR::Color a = static_cast<UTILS::COLOR::Color>(((color >> 24) & 0xff) * alpha);
260  UTILS::COLOR::Color r = static_cast<UTILS::COLOR::Color>(((color >> 16) & 0xff) * red);
261  UTILS::COLOR::Color g = static_cast<UTILS::COLOR::Color>(((color >> 8) & 0xff) * green);
262  UTILS::COLOR::Color b = static_cast<UTILS::COLOR::Color>(((color)&0xff) * blue);
263  if (a > 255)
264  a = 255;
265  if (r > 255)
266  r = 255;
267  if (g > 255)
268  g = 255;
269  if (b > 255)
270  b = 255;
271 
272  return ((a << 24) & 0xff000000) | ((r << 16) & 0xff0000) | ((g << 8) & 0xff00) | (b & 0xff);
273  }
274 
275  float m[3][4];
276  float alpha;
277  float red;
278  float green;
279  float blue;
280  bool identity;
281 };
282 
283 inline bool operator==(const TransformMatrix &a, const TransformMatrix &b)
284 {
285  bool comparison =
286  a.alpha == b.alpha && a.red == b.red && a.green == b.green && a.blue == b.blue &&
287  ((a.identity && b.identity) ||
288  (!a.identity && !b.identity &&
289  std::equal(&a.m[0][0], &a.m[0][0] + sizeof(a.m) / sizeof(a.m[0][0]), &b.m[0][0])));
290  return comparison;
291 }
292 
293 inline bool operator!=(const TransformMatrix &a, const TransformMatrix &b)
294 {
295  return !operator==(a, b);
296 }
Definition: TransformMatrix.h:25