HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
UT_Matrix3.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  */
7 
8 #pragma once
9 
10 #ifndef __UT_Matrix3_h__
11 #define __UT_Matrix3_h__
12 
13 #include "UT_API.h"
14 #include "UT_Assert.h"
15 #include "UT_Axis.h"
16 #include "UT_FixedVector.h"
17 #include "UT_Swap.h"
18 #include "UT_SymMatrix3.h"
19 #include "UT_Vector3.h"
20 #include "UT_VectorTypes.h"
21 
22 #include <SYS/SYS_Deprecated.h>
23 #include <SYS/SYS_Math.h>
24 #include <iosfwd>
25 
26 class UT_IStream;
27 class UT_JSONParser;
28 class UT_JSONWriter;
29 class UT_JSONValue;
30 
31 // Free floating operators that return a UT_Matrix3T object.
32 template <typename T>
34 template <typename T>
36 template <typename T>
38 template <typename T, typename S>
40 template <typename T, typename S>
41 inline UT_Matrix3T<T> operator+(const UT_Vector3T<S> &v, const UT_Matrix3T<T> &m);
42 template <typename T, typename S>
44 template <typename T, typename S>
46 template <typename T, typename S>
48 template <typename T, typename S>
49 inline UT_Matrix3T<T> operator-(const UT_Matrix3T<T> &mat, S sc);
50 template <typename T, typename S>
52 template <typename T, typename S>
53 inline UT_Matrix3T<T> operator/(const UT_Matrix3T<T> &mat, S sc);
54 template <typename T, typename S>
55 inline UT_Matrix3T<T> operator+(S sc, const UT_Matrix3T<T> &mat);
56 template <typename T, typename S>
58 template <typename T, typename S>
59 inline UT_Matrix3T<T> operator*(S sc, const UT_Matrix3T<T> &mat);
60 template <typename T, typename S>
62 
63 template <typename T>
64 inline UT_Matrix3T<T> SYSmin (const UT_Matrix3T<T> &v1, const UT_Matrix3T<T> &v2);
65 template <typename T>
66 inline UT_Matrix3T<T> SYSmax (const UT_Matrix3T<T> &v1, const UT_Matrix3T<T> &v2);
67 template <typename T,typename S>
68 inline UT_Matrix3T<T> SYSlerp(const UT_Matrix3T<T> &v1, const UT_Matrix3T<T> &v2, S t);
69 template <typename T,typename S>
70 inline UT_Matrix3T<T> SYSbilerp(const UT_Matrix3T<T> &u0v0, const UT_Matrix3T<T> &u1v0,
71  const UT_Matrix3T<T> &u0v1, const UT_Matrix3T<T> &u1v1,
72  S u, S v)
73 { return SYSlerp(SYSlerp(u0v0, u0v1, v), SYSlerp(u1v0, u1v1, v), u); }
74 
75 /// This class implements a 3x3 float matrix in row-major order.
76 ///
77 /// Most of Houdini operates with row vectors that are left-multiplied with
78 /// matrices. e.g., z = v * M
79 ///
80 /// This convention, combined with row-major order, is directly compatible
81 /// with OpenGL matrix requirements.
82 template <typename T>
84 {
85 public:
86 
87  typedef T value_type;
88  static const int tuple_size = 9;
89 
90  /// Construct uninitialized matrix.
91  SYS_FORCE_INLINE UT_Matrix3T() = default;
92 
93  /// Default copy constructor
94  constexpr UT_Matrix3T(const UT_Matrix3T &) = default;
95 
96  /// Default move constructor
97  constexpr UT_Matrix3T(UT_Matrix3T &&) = default;
98 
99  /// Construct identity matrix, multipled by scalar.
100  explicit constexpr UT_Matrix3T(fpreal64 val) noexcept
101  : matx{{T(val),0,0},{0,T(val),0},{0,0,T(val)}}
102  {
103  SYS_STATIC_ASSERT(sizeof(UT_Matrix3T<T>) == tuple_size * sizeof(T));
104  }
105  /// Construct a deep copy of the input row-major data.
106  /// @{
107  template <typename S>
108  explicit constexpr UT_Matrix3T(const S m[3][3]) noexcept
109  : matx{
110  {T(m[0][0]),T(m[0][1]),T(m[0][2])},
111  {T(m[1][0]),T(m[1][1]),T(m[1][2])},
112  {T(m[2][0]),T(m[2][1]),T(m[2][2])}}
113  {}
114  /// @}
115 
116  /// Arbitrary UT_FixedVector of the same size
117  template <typename S,bool INST>
119  : matx{
120  {v[0],v[1],v[2]},
121  {v[3],v[4],v[5]},
122  {v[6],v[7],v[8]}}
123  {}
124 
125  /// Construct from 3 row vectors
126  template <typename S,bool INST>
128  const UT_FixedVector<S,3,INST> &r0,
129  const UT_FixedVector<S,3,INST> &r1,
130  const UT_FixedVector<S,3,INST> &r2) noexcept
131  : matx{
132  {r0[0],r0[1],r0[2]},
133  {r1[0],r1[1],r1[2]},
134  {r2[0],r2[1],r2[2]}}
135  {}
136 
137  /// This constructor is for convenience.
138  constexpr UT_Matrix3T(
139  T val00, T val01, T val02,
140  T val10, T val11, T val12,
141  T val20, T val21, T val22) noexcept
142  : matx{
143  {val00,val01,val02},
144  {val10,val11,val12},
145  {val20,val21,val22}}
146  {}
147 
148  /// Base type conversion constructor
149  template <typename S>
150  UT_Matrix3T(const UT_Matrix3T<S> &m) noexcept
151  : matx{
152  {T(m(0,0)),T(m(0,1)),T(m(0,2))},
153  {T(m(1,0)),T(m(1,1)),T(m(1,2))},
154  {T(m(2,0)),T(m(2,1)),T(m(2,2))}}
155  {}
156  explicit UT_Matrix3T(const UT_Matrix4T<fpreal32> &m);
157  explicit UT_Matrix3T(const UT_Matrix4T<fpreal64> &m);
158 
159  /// Construct from a symmetric 3x3 matrix
160  template <typename S>
161  explicit UT_Matrix3T(const UT_SymMatrix3T<S> m)
162  {
163  this->operator=(m);
164  }
165 
166  /// Default copy assignment operator
167  UT_Matrix3T<T> &operator=(const UT_Matrix3T<T> &m) = default;
168 
169  /// Default move assignment operator
170  UT_Matrix3T<T> &operator=(UT_Matrix3T<T> &&m) = default;
171 
172  /// Conversion operator that returns a 3x3 from a 4x4 matrix by ignoring the
173  /// last row and last column.
174  /// @{
175  UT_Matrix3T<T> &operator=(const UT_Matrix4T<fpreal32> &m);
176  UT_Matrix3T<T> &operator=(const UT_Matrix4T<fpreal64> &m);
177  /// @}
178  template <typename S>
180  {
181  matx[0][0]=m(0,0); matx[0][1]=m(0,1); matx[0][2]=m(0,2);
182  matx[1][0]=m(1,0); matx[1][1]=m(1,1); matx[1][2]=m(1,2);
183  matx[2][0]=m(2,0); matx[2][1]=m(2,1); matx[2][2]=m(2,2);
184  return *this;
185  }
186 
187  /// Convert from a symmetric matrix to non-symmetric.
188  template <typename S>
190  {
191  typedef typename UT_SymMatrix3T<S>::LowerTri LowerTri;
192  const LowerTri &l = m.lowerTri();
193  matx[0][0] = l.q00; matx[0][1] = l.q10; matx[0][2] = l.q20;
194  matx[1][0] = l.q10; matx[1][1] = l.q11; matx[1][2] = l.q21;
195  matx[2][0] = l.q20; matx[2][1] = l.q21; matx[2][2] = l.q22;
196  return *this;
197  }
198 
199  /// Convert this to a symmetric matrix, using the lower-triangular portion
201  {
202  return UT_SymMatrix3T<T>(matx[0][0],
203  matx[1][0], matx[1][1],
204  matx[2][0], matx[2][1], matx[2][2]);
205  }
206 
207  /// Convert this to a symmetric matrix, using the upper-triangular portion
209  {
210  return UT_SymMatrix3T<T>(matx[0][0],
211  matx[0][1], matx[1][1],
212  matx[0][2], matx[1][2], matx[2][2]);
213  }
214 
215  /// Convert this to a symmetric matrix, using averaged components
217  {
218  return UT_SymMatrix3T<T>(matx[0][0],
219  (matx[0][1] + matx[1][0]) / 2,
220  matx[1][1],
221  (matx[0][2] + matx[2][0]) / 2,
222  (matx[1][2] + matx[2][1]) / 2,
223  matx[2][2]);
224  }
225 
227  {
228  return UT_Matrix3T<T>(-matx[0][0], -matx[0][1], -matx[0][2],
229  -matx[1][0], -matx[1][1], -matx[1][2],
230  -matx[2][0], -matx[2][1], -matx[2][2]);
231  }
232 
233  // Does += k * m
235  void addScaledMat(T k, const UT_Matrix3T<T> &m)
236  {
237  matx[0][0]+=k*m.matx[0][0];
238  matx[0][1]+=k*m.matx[0][1];
239  matx[0][2]+=k*m.matx[0][2];
240 
241  matx[1][0]+=k*m.matx[1][0];
242  matx[1][1]+=k*m.matx[1][1];
243  matx[1][2]+=k*m.matx[1][2];
244 
245  matx[2][0]+=k*m.matx[2][0];
246  matx[2][1]+=k*m.matx[2][1];
247  matx[2][2]+=k*m.matx[2][2];
248  }
251  {
252  matx[0][0]+=m.matx[0][0];
253  matx[0][1]+=m.matx[0][1];
254  matx[0][2]+=m.matx[0][2];
255 
256  matx[1][0]+=m.matx[1][0];
257  matx[1][1]+=m.matx[1][1];
258  matx[1][2]+=m.matx[1][2];
259 
260  matx[2][0]+=m.matx[2][0];
261  matx[2][1]+=m.matx[2][1];
262  matx[2][2]+=m.matx[2][2];
263  return *this;
264  }
267  {
268  matx[0][0]-=m.matx[0][0];
269  matx[0][1]-=m.matx[0][1];
270  matx[0][2]-=m.matx[0][2];
271 
272  matx[1][0]-=m.matx[1][0];
273  matx[1][1]-=m.matx[1][1];
274  matx[1][2]-=m.matx[1][2];
275 
276  matx[2][0]-=m.matx[2][0];
277  matx[2][1]-=m.matx[2][1];
278  matx[2][2]-=m.matx[2][2];
279  return *this;
280  }
281 
283  {
284  T a, b, c;
285  a = matx[0][0]; b = matx[0][1]; c = matx[0][2];
286  matx[0][0] = a*m(0,0) + b*m(1,0) + c*m(2,0);
287  matx[0][1] = a*m(0,1) + b*m(1,1) + c*m(2,1);
288  matx[0][2] = a*m(0,2) + b*m(1,2) + c*m(2,2);
289 
290  a = matx[1][0]; b = matx[1][1]; c = matx[1][2];
291  matx[1][0] = a*m(0,0) + b*m(1,0) + c*m(2,0);
292  matx[1][1] = a*m(0,1) + b*m(1,1) + c*m(2,1);
293  matx[1][2] = a*m(0,2) + b*m(1,2) + c*m(2,2);
294 
295  a = matx[2][0]; b = matx[2][1]; c = matx[2][2];
296  matx[2][0] = a*m(0,0) + b*m(1,0) + c*m(2,0);
297  matx[2][1] = a*m(0,1) + b*m(1,1) + c*m(2,1);
298  matx[2][2] = a*m(0,2) + b*m(1,2) + c*m(2,2);
299  return *this;
300  }
301 
302  /// Multiply given symmetric matrix on the right
303  template <typename S>
305  {
306  typedef typename UT_SymMatrix3T<S>::LowerTri LowerTri;
307 
308  const LowerTri& l = m.lowerTri();
309  T a, b, c;
310 
311  a = matx[0][0]; b = matx[0][1]; c = matx[0][2];
312  matx[0][0] = a*l.q00 + b*l.q10 + c*l.q20;
313  matx[0][1] = a*l.q10 + b*l.q11 + c*l.q21;
314  matx[0][2] = a*l.q20 + b*l.q21 + c*l.q22;
315 
316  a = matx[1][0]; b = matx[1][1]; c = matx[1][2];
317  matx[1][0] = a*l.q00 + b*l.q10 + c*l.q20;
318  matx[1][1] = a*l.q10 + b*l.q11 + c*l.q21;
319  matx[1][2] = a*l.q20 + b*l.q21 + c*l.q22;
320 
321  a = matx[2][0]; b = matx[2][1]; c = matx[2][2];
322  matx[2][0] = a*l.q00 + b*l.q10 + c*l.q20;
323  matx[2][1] = a*l.q10 + b*l.q11 + c*l.q21;
324  matx[2][2] = a*l.q20 + b*l.q21 + c*l.q22;
325 
326  return *this;
327  }
328 
329  /// Multiply given symmetric matrix on the left
330  template <typename S>
332  {
333  typedef typename UT_SymMatrix3T<S>::LowerTri LowerTri;
334 
335  const LowerTri& l = m.lowerTri();
336  T a, b, c;
337 
338  a = matx[0][0]; b = matx[1][0]; c = matx[2][0];
339  matx[0][0] = a*l.q00 + b*l.q10 + c*l.q20;
340  matx[1][0] = a*l.q10 + b*l.q11 + c*l.q21;
341  matx[2][0] = a*l.q20 + b*l.q21 + c*l.q22;
342 
343  a = matx[0][1]; b = matx[1][1]; c = matx[2][1];
344  matx[0][1] = a*l.q00 + b*l.q10 + c*l.q20;
345  matx[1][1] = a*l.q10 + b*l.q11 + c*l.q21;
346  matx[2][1] = a*l.q20 + b*l.q21 + c*l.q22;
347 
348  a = matx[0][2]; b = matx[1][2]; c = matx[2][2];
349  matx[0][2] = a*l.q00 + b*l.q10 + c*l.q20;
350  matx[1][2] = a*l.q10 + b*l.q11 + c*l.q21;
351  matx[2][2] = a*l.q20 + b*l.q21 + c*l.q22;
352  }
353 
354  /// Multiply given matrix3 on the left
355  template <typename S>
356  void leftMult(const UT_Matrix3T<S> &m)
357  {
358  T a, b, c;
359 
360  a = matx[0][0]; b = matx[1][0]; c = matx[2][0];
361  matx[0][0] = a*m(0,0) + b*m(0,1) + c*m(0,2);
362  matx[1][0] = a*m(1,0) + b*m(1,1) + c*m(1,2);
363  matx[2][0] = a*m(2,0) + b*m(2,1) + c*m(2,2);
364 
365  a = matx[0][1]; b = matx[1][1]; c = matx[2][1];
366  matx[0][1] = a*m(0,0) + b*m(0,1) + c*m(0,2);
367  matx[1][1] = a*m(1,0) + b*m(1,1) + c*m(1,2);
368  matx[2][1] = a*m(2,0) + b*m(2,1) + c*m(2,2);
369 
370  a = matx[0][2]; b = matx[1][2]; c = matx[2][2];
371  matx[0][2] = a*m(0,0) + b*m(0,1) + c*m(0,2);
372  matx[1][2] = a*m(1,0) + b*m(1,1) + c*m(1,2);
373  matx[2][2] = a*m(2,0) + b*m(2,1) + c*m(2,2);
374  }
375 
376  void multiply3(const UT_Matrix4 &m);
377  void multiply3(const UT_DMatrix4 &m);
378 
379  constexpr bool operator==(const UT_Matrix3T<T> &m) const noexcept
380  {
381  return (&m == this) || (
382  matx[0][0]==m(0,0) && matx[0][1]==m(0,1) && matx[0][2]==m(0,2) &&
383  matx[1][0]==m(1,0) && matx[1][1]==m(1,1) && matx[1][2]==m(1,2) &&
384  matx[2][0]==m(2,0) && matx[2][1]==m(2,1) && matx[2][2]==m(2,2) );
385  }
386  constexpr bool operator!=(const UT_Matrix3T<T> &m) const noexcept
387  {
388  return !(*this == m);
389  }
390 
391  // Scalar operators:
392  UT_Matrix3T<T> &operator= (T val)
393  {
394  matx[0][0] = val; matx[0][1] = 0; matx[0][2] = 0;
395  matx[1][0] = 0; matx[1][1] = val; matx[1][2] = 0;
396  matx[2][0] = 0; matx[2][1] = 0; matx[2][2] = val;
397  return *this;
398  }
401  {
402  matx[0][0]*=scalar; matx[0][1]*=scalar; matx[0][2]*=scalar;
403  matx[1][0]*=scalar; matx[1][1]*=scalar; matx[1][2]*=scalar;
404  matx[2][0]*=scalar; matx[2][1]*=scalar; matx[2][2]*=scalar;
405  return *this;
406  }
409  {
410  return operator*=( 1.0f/scalar );
411  }
412 
413  // Vector3 operators:
414  template <typename S>
415  inline UT_Matrix3T<T> &operator= (const UT_Vector3T<S> &vec);
416  template <typename S>
417  inline UT_Matrix3T<T> &operator+=(const UT_Vector3T<S> &vec);
418  template <typename S>
419  inline UT_Matrix3T<T> &operator-=(const UT_Vector3T<S> &vec);
420 
421  /// Scaled outer product update (given scalar b, row vectors v1 and v2)
422  /// this += b * transpose(v1) * v2
423  /// @{
424  template <typename S>
425  inline void outerproductUpdateT(T b,
426  const UT_Vector3T<S> &v1,
427  const UT_Vector3T<S> &v2);
430  const UT_Vector3F &v1,
431  const UT_Vector3F &v2)
432  { outerproductUpdateT(b, v1, v2); }
435  const UT_Vector3D &v1,
436  const UT_Vector3D &v2)
437  { outerproductUpdateT(b, v1, v2); }
438  /// @}
439 
440  // Other matrix operations:
441  // Computes the basis of a 3x3 matrix. This is used by OBB code
442  // to determine what orientation of a bounding box best represents
443  // a cloud of points. To do this, first fill this matrix with
444  // the sum of p*pT for all points in the cloud.
445  // The result is in this matrix itself.
446  void getBasis();
447 
448  // Sets this matrix to the canonical 180 rotation matrix (about the y axis)
449  // that is used in the orient() and dihedral() functions when given two
450  // opposing vectors.
451  void arbitrary180rot();
452 
453  /// Compute the dihedral: return the matrix that computes the rotation
454  /// around the axes normal to both a and b, (their cross product), by the
455  /// angle which is between a and b. The resulting matrix maps a onto b. If
456  /// a and b have the same direction, what comes out is the identity matrix.
457  /// If a and b are opposed, the rotation is undefined and the method
458  /// returns a vector c of zeroes (check with !c); if all is OK, c != 0.
459  /// The transformation is a symmetry around vector a, then a symmetry
460  /// around (norm(a) and norm(b)). If a or b needs to be normalized, pass a
461  /// non-zero value in norm.
462  /// The second function places the result in 'm', and returns 0 if a and b
463  /// are not opposed; otherwise, it returns 1.
464  // @{
465  template <typename S>
466  static UT_Matrix3T<T> dihedral(UT_Vector3T<S> &a, UT_Vector3T<S> &b,
467  UT_Vector3T<S> &c,int norm=1);
468  /// @note If dihedral() returns 1, this matrix is NOT modified!
469  template <typename S>
470  int dihedral(UT_Vector3T<S> &a, UT_Vector3T<S> &b,
471  int norm=1);
472  // @}
473 
474  // Compute a lookat matrix: These functions will compute a rotation matrix
475  // (yes, with all the properties of a rotation matrix), which will provide
476  // the rotates needed for "from" to look at "to". One method uses a "roll"
477  // the other method uses an "up" vector to determine the orientation. The
478  // "roll" is not as well defined as using an "up" vector. If the two points
479  // are co-incident, the result will be an identity matrix. If norm is set,
480  // then the up vector will be normalized.
481  // The lookat matrix will have the -Z axis pointing at the "to" point.
482  // The y axis will be pointing "up"
483  template <typename S>
484  void lookat(const UT_Vector3T<S> &from, const UT_Vector3T<S> &to,
485  T roll = 0);
486  template <typename S>
487  void lookat(const UT_Vector3T<S> &from, const UT_Vector3T<S> &to,
488  const UT_Vector3T<S> &up);
489 
490 
491  // Compute the transform matrix to orient given a direction and an up vector
492  // If the direction and up are not orthogonal, then the up vector will be
493  // shifted along the direction to make it orthogonal... If the up and
494  // direction vectors are co-linear, then an identity matrix will be
495  // returned.
496  // The second function will return 0 to indicate this. The inputs may
497  // be modified by the orient functions.
498  template <typename S>
499  int orient(UT_Vector3T<S> &dir, UT_Vector3T<S> &up, int norm=1);
500  template <typename S>
501  int orientInverse(UT_Vector3T<S> &dir, UT_Vector3T<S> &up, int norm=1);
502 
503 
504  // Computes a transform to orient to a given direction (v) with a scale
505  // (pscale). The up vector (up) is optional and will orient the matrix to
506  // this up vector. If no up vector is given, the z axis will be oriented to
507  // point in the v direction. If a quaternion (q) is specified, the
508  // orientation will be additionally transformed by the rotation specified
509  // by the quaternion.
510  // The matrix is scaled non-uniformly about each axis using s3, if s3
511  // is non-zero. A uniform scale of pscale is applied regardless, so if
512  // s3 is non-zero, the x axis will be scaled by pscale * s3->x().
513  template <typename S>
514  void orientT(const UT_Vector3T<S>& v,
515  T pscale, const UT_Vector3T<S> *s3,
516  const UT_Vector3T<S>* up,
517  const UT_QuaternionT<S> * q);
518  void orient(const UT_Vector3F &v,
519  T pscale, const UT_Vector3F *s3,
520  const UT_Vector3F *up,
521  const UT_QuaternionF *q)
522  { orientT(v, pscale, s3, up, q); }
523  void orient(const UT_Vector3D &v,
524  T pscale, const UT_Vector3D *s3,
525  const UT_Vector3D *up,
526  const UT_QuaternionD *q)
527  { orientT(v, pscale, s3, up, q); }
528  template <typename S>
529  void orientInverseT(const UT_Vector3T<S>& v,
530  T pscale, const UT_Vector3T<S> *s3,
531  const UT_Vector3T<S>* up,
532  const UT_QuaternionT<S> * q);
534  T pscale, const UT_Vector3F *s3,
535  const UT_Vector3F *up,
536  const UT_QuaternionF *q)
537  { orientInverseT(v, pscale, s3, up, q); }
539  T pscale, const UT_Vector3D *s3,
540  const UT_Vector3D *up,
541  const UT_QuaternionD *q)
542  { orientInverseT(v, pscale, s3, up, q); }
543 
544  // Return the cofactor of the matrix, ie the determinant of the 2x2
545  // submatrix that results from removing row 'k' and column 'l' from the
546  // 3x3.
548  T coFactor(int k, int l) const
549  {
550  int r[2], c[2];
551 
552  // r, c should evaluate to compile time constants
553  coVals(k, r);
554  coVals(l, c);
555  if ((k ^ l) & 1)
556  UTswap(c[0], c[1]);
557 
558  return matx[r[0]][c[0]]*matx[r[1]][c[1]] -
559  matx[r[0]][c[1]]*matx[r[1]][c[0]];
560  }
561 
562  T determinant() const
563  {
564  return(matx[0][0]*coFactor(0,0) +
565  matx[0][1]*coFactor(0,1) +
566  matx[0][2]*coFactor(0,2));
567  }
568  T trace() const
569  { return matx[0][0] + matx[1][1] + matx[2][2]; }
570 
571  /// Computes the eigenvalues. Returns number of real eigenvalues
572  /// found. Uses UT_RootFinder::cubic
573  /// @param r The real eigenvalues
574  /// @param i The imaginary eigenvalues
575  template <typename S>
576  int eigenvalues(UT_Vector3T<S> &r, UT_Vector3T<S> &i) const;
577 
578  /// Invert this matrix and return 0 if OK, 1 if singular.
579  int invert();
580  /// Invert the matrix and return 0 if OK, 1 if singular.
581  /// Puts the inverted matrix in m, and leaves this matrix unchanged.
582  int invert(UT_Matrix3T<T> &m)const;
583 
584  /// Use Kramer's method to compute the matrix inverse
585  /// If abs( det(m) ) <= abs_det_threshold, then return 1 without changing m
586  /// Otherwise, return 0, storing the inverse matrix in m
587  ///
588  /// NOTE: The default FLT_EPSILON is kept here to preserve existing behavior
589  /// This is not a good default!
590  /// The right threshold must be decided separately for each use case.
591  int invertKramer(UT_Matrix3T<T> &m, T abs_det_threshold = FLT_EPSILON) const;
592 
593  // Shorthand for invertKramer(*this)
594  int invertKramer(T abs_det_threshold = FLT_EPSILON);
595 
596  // Invert *this.
597  // *this should be symmetric.
598  // *this does NOT have to be non-singular. Singular matrices will be
599  // inverted by filtering out the singular component.
600  // This means you can reliably solve:
601  // M x = b
602  // for the x that is closest to satisfying b
603  // Returns 0 on success, 1 if something really bad happened.
604  int safeInvertSymmetric(T tol=1e-6f);
605 
606  // Diagonalize *this.
607  // *this should be symmetric.
608  // The matrix is factored into:
609  // *this = Rt D R
610  // The diagonalization is done with a serios of jacobi rotations.
611  // *this is unchanged by the operations.
612  // Returns true if successful, false if reached maximum iterations rather
613  // than desired tolerance.
614  // Tolerance is with respect to the maximal element of the matrix.
615  bool diagonalizeSymmetric(UT_Matrix3T<T> &R, UT_Matrix3T<T> &D, T tol=1e-6f, int maxiter = 100) const;
616 
617  // Compute the SVD decomposition of *this
618  // The matrix is factored into
619  // *this = U * S * Vt
620  // Where S is diagonal, and U and Vt are both orthognal matrices
621  // Tolerance is with respect to the maximal element of the matrix
622  void svdDecomposition(UT_Matrix3T<T> &U, UT_Matrix3T<T> &S, UT_Matrix3T<T> &V, T tol=1e-6f) const;
623 
624  /// Splits a covariance matrix into a scale & rotation component.
625  /// This should be built by a series of outer product updates.
626  /// R is the rotation component, S the inverse scale.
627  /// If this is A, finds the inverse square root of AtA, S.
628  /// We then set R = transpose(AS) to give us a rotation matrix.
629  /// NOTE: For general matrices, use makeRotationMatrix()!
630  void splitCovarianceToRotationScale(UT_Matrix3T<T> &R, UT_Matrix3T<T> &S, T tol=1e-6f) const;
631 
632  bool isSymmetric(T tolerance = T(SYS_FTOLERANCE)) const;
633 
634  // Transpose this matrix or return its transpose.
635  void transpose(void)
636  {
637  T tmp;
638  tmp=matx[0][1]; matx[0][1]=matx[1][0]; matx[1][0]=tmp;
639  tmp=matx[0][2]; matx[0][2]=matx[2][0]; matx[2][0]=tmp;
640  tmp=matx[1][2]; matx[1][2]=matx[2][1]; matx[2][1]=tmp;
641  }
643  {
644  return UT_Matrix3T<T>(matx[0][0], matx[1][0], matx[2][0],
645  matx[0][1], matx[1][1], matx[2][1],
646  matx[0][2], matx[1][2], matx[2][2]);
647  }
648 
649  // check for equality within a tolerance level
650  bool isEqual( const UT_Matrix3T<T> &m,
651  T tolerance=T(SYS_FTOLERANCE) ) const
652  {
653  return (&m == this) || (
654  SYSisEqual( matx[0][0], m.matx[0][0], tolerance ) &&
655  SYSisEqual( matx[0][1], m.matx[0][1], tolerance ) &&
656  SYSisEqual( matx[0][2], m.matx[0][2], tolerance ) &&
657 
658  SYSisEqual( matx[1][0], m.matx[1][0], tolerance ) &&
659  SYSisEqual( matx[1][1], m.matx[1][1], tolerance ) &&
660  SYSisEqual( matx[1][2], m.matx[1][2], tolerance ) &&
661 
662  SYSisEqual( matx[2][0], m.matx[2][0], tolerance ) &&
663  SYSisEqual( matx[2][1], m.matx[2][1], tolerance ) &&
664  SYSisEqual( matx[2][2], m.matx[2][2], tolerance ) );
665  }
666 
667  /// Post-multiply this matrix by a 3x3 rotation matrix determined by the
668  /// axis and angle of rotation in radians.
669  /// If 'norm' is not 0, the axis vector is normalized before computing the
670  /// rotation matrix. rotationMat() returns a rotation matrix, and could as
671  /// well be defined as a free floating function.
672  /// @{
673  template <typename S>
674  void rotate(UT_Vector3T<S> &axis, T theta, int norm=1);
675  void rotate(UT_Axis3::axis a, T theta);
676  template<UT_Axis3::axis A>
677  void rotate(T theta);
678  /// @}
679 
680  /// Create a rotation matrix for the given angle in radians around the axis
681  /// @{
682  template <typename S>
683  static UT_Matrix3T<T> rotationMat(UT_Vector3T<S> &axis, T theta, int norm=1);
684  static UT_Matrix3T<T> rotationMat(UT_Axis3::axis a, T theta);
685  /// @}
686 
687  /// Pre-multiply this matrix by the theta radians rotation around the axis
688  /// @{
689  template <typename S>
690  void prerotate(UT_Vector3T<S> &axis, T theta, int norm=1);
691  void prerotate(UT_Axis3::axis a, T theta);
692  template<UT_Axis3::axis A>
693  void prerotate(T theta);
694  /// @}
695 
696  /// Pre-rotate by rx, ry, rz radians around the three basic axes in the
697  /// order given by UT_XformOrder.
698  /// @{
699  void prerotate(T rx, T ry, T rz,
700  const UT_XformOrder &order);
701  inline void prerotate(const UT_Vector3T<T> &rad, const UT_XformOrder &order)
702  { prerotate(rad(0), rad(1), rad(2), order); }
703  /// @}
704 
705 
706  /// Post-rotate by rx, ry, rz radians around the three basic axes in the
707  /// order given by UT_XformOrder.
708  /// @{
709  void rotate(T rx, T ry, T rz,
710  const UT_XformOrder &ord);
711  inline void rotate(const UT_Vector3T<T> &rad, const UT_XformOrder &ord)
712  { rotate(rad(0), rad(1), rad(2), ord); }
713  /// @}
714 
715  /// Post-multiply this matrix by a scale matrix with diagonal (sx, sy, sz)
716  /// @{
717  void scale(T sx, T sy, T sz)
718  {
719  matx[0][0] *= sx; matx[0][1] *= sy; matx[0][2] *= sz;
720  matx[1][0] *= sx; matx[1][1] *= sy; matx[1][2] *= sz;
721  matx[2][0] *= sx; matx[2][1] *= sy; matx[2][2] *= sz;
722  }
724  void scale(const UT_Vector3T<T> &s)
725  { scale(s(0), s(1), s(2)); }
726  /// @}
727 
728  /// Pre-multiply this matrix by a scale matrix with diagonal (sx, sy, sz)
729  /// @{
730  void prescale(T sx, T sy, T sz)
731  {
732  matx[0][0] *= sx; matx[1][0] *= sy; matx[2][0] *= sz;
733  matx[0][1] *= sx; matx[1][1] *= sy; matx[2][1] *= sz;
734  matx[0][2] *= sx; matx[1][2] *= sy; matx[2][2] *= sz;
735  }
737  void prescale(const UT_Vector3T<T> &s)
738  { prescale(s(0), s(1), s(2)); }
739  /// @}
740 
741  /// Negates this matrix, i.e. multiplies it by -1.
743  {
744  matx[0][0] = -matx[0][0]; matx[0][1] = -matx[0][1]; matx[0][2] = -matx[0][2];
745  matx[1][0] = -matx[1][0]; matx[1][1] = -matx[1][1]; matx[1][2] = -matx[1][2];
746  matx[2][0] = -matx[2][0]; matx[2][1] = -matx[2][1]; matx[2][2] = -matx[2][2];
747  }
748 
749  /// Post-multiply this matrix by a translation matrix determined by (dx,dy)
750  /// @{
751  void translate(T dx, T dy)
752  {
753  matx[0][0] += matx[0][2] * dx;
754  matx[0][1] += matx[0][2] * dy;
755  matx[1][0] += matx[1][2] * dx;
756  matx[1][1] += matx[1][2] * dy;
757  matx[2][0] += matx[2][2] * dx;
758  matx[2][1] += matx[2][2] * dy;
759  }
761  void translate(const UT_Vector2T<T> &delta)
762  { translate(delta(0), delta(1)); }
763  /// @}
764 
765  /// Pre-multiply this matrix by the translation matrix determined by (dx,dy)
766  /// @{
767  void pretranslate(T dx, T dy)
768  {
769  matx[2][0] += matx[0][0] * dx + matx[1][0] * dy;
770  matx[2][1] += matx[0][1] * dx + matx[1][1] * dy;
771  matx[2][2] += matx[0][2] * dx + matx[1][2] * dy;
772  }
774  void pretranslate(const UT_Vector2T<T> &delta)
775  { pretranslate(delta(0), delta(1)); }
776  /// @}
777 
778  /// Generate the x, y, and z values of rotation in radians.
779  /// Return 0 if successful, and a non-zero value otherwise: 1 if the matrix
780  /// is not a valid rotation matrix, 2 if rotOrder is invalid, and 3 for
781  /// other errors. rotOrder must be given as a UT_XformOrder permulation.
782  /// WARNING: For animation or transform blending, use polarDecompose()
783  /// or makeRotationMatrix()!
784  /// WARNING: The non-const method changes the matrix!
785  template <typename S>
786  int crack(UT_Vector3T<S> &rvec, const UT_XformOrder &order,
787  int remove_scales=1);
788  template <typename S>
789  int crack(UT_Vector3T<S> &rvec, const UT_XformOrder &order,
790  int remove_scales=1) const;
791  int crack2D(T &r) const;
792 
793  /// Perform the polar decomposition M into an orthogonal matrix Q and an
794  /// symmetric positive-semidefinite matrix S. This is more useful than
795  /// crack() or conditionRotate() when the desire is to blend transforms.
796  /// By default, it gives M=SQ, a left polar decomposition. If reverse is
797  /// false, then it gives M=QS, a right polar decomposition.
798  /// @pre *this is non-singular
799  /// @post *this = Q, and if stretch != 0: *stretch = S
800  /// @return True if successful
801  bool polarDecompose(
802  UT_Matrix3T<T> *stretch = nullptr,
803  bool reverse = true,
804  const int max_iter = 64,
805  const T rel_tol = FLT_EPSILON);
806 
807  /// Turn this matrix into the "closest" rotation matrix.
808  ///
809  /// It uses polarDecompose and then negates the matrix and stretch
810  /// if there is a negative determinant (scale). It returns false iff
811  /// polarDecompose failed, possibly due to a singular matrix.
812  ///
813  /// This is currently the one true way to turn an arbitrary
814  /// matrix into a rotation matrix. If that ever changes,
815  /// put a warning here, and you may want to update
816  /// UT_Matrix4::makeRigidMatrix too.
817  bool makeRotationMatrix(
818  UT_Matrix3T<T> *stretch = nullptr,
819  bool reverse = true,
820  const int max_iter = 64,
821  const T rel_tol = FLT_EPSILON);
822 
823  /// This method will condition the matrix so that it's a valid rotation
824  /// matrix (i.e. crackable). Ideally, the scales should be removed first,
825  /// but this method will attempt to do this as well. It will return the
826  /// conditioned scales if a vector is passed in.
827  /// WARNING: If you just want a rotation matrix, use makeRotationMatrix()!
828  /// @{
829  template <typename S>
830  void conditionRotateT(UT_Vector3T<S> *scales);
831  void conditionRotate(UT_Vector3F *scales=0)
832  { conditionRotateT(scales); }
834  { conditionRotateT(scales); }
835  /// @}
836 
837  /// Extract scales and shears from the matrix leaving the matrix as a nice
838  /// orthogonal rotation matrix. The shears are:
839  /// XY, XZ, and YZ
840  /// WARNING: If you just want a rotation matrix, use makeRotationMatrix()!
841  /// @{
842  template <typename S>
843  void extractScalesT(UT_Vector3T<S> &scales, UT_Vector3T<S> *shears);
844  void extractScales(UT_Vector3D &scales, UT_Vector3D *shears=0)
845  { extractScalesT(scales, shears); }
846  void extractScales(UT_Vector3F &scales, UT_Vector3F *shears=0)
847  { extractScalesT(scales, shears); }
849  UT_Vector3T<fpreal16> *shears=0)
850  { extractScalesT(scales, shears); }
851  /// @}
852 
853  // Extract scales and shears from the matrix leaving the matrix as a nice
854  // orthogonal rotation matrix (assuming it was only a 2D xform to begin
855  // with). The shears are:
856  // XY
857  template <typename S>
858  void extractScales2D(UT_Vector2T<S> &scales, T *shears=0);
859 
860  // Shear the matrix according to the values. This is equivalent to
861  // multiplying the matrix by the shear matrix with the given value.
862  void shearXY(T val);
863  void shearXZ(T val);
864  void shearYZ(T val);
865 
866  /// Post-multiply this matrix by the shear matrix formed by (sxy, sxz, syz)
867  /// @{
868  void shear(T s_xy, T s_xz, T s_yz)
869  {
870  matx[0][0] += matx[0][1]*s_xy + matx[0][2]*s_xz;
871  matx[0][1] += matx[0][2]*s_yz;
872 
873  matx[1][0] += matx[1][1]*s_xy + matx[1][2]*s_xz;
874  matx[1][1] += matx[1][2]*s_yz;
875 
876  matx[2][0] += matx[2][1]*s_xy + matx[2][2]*s_xz;
877  matx[2][1] += matx[2][2]*s_yz;
878  }
880  void shear(const UT_Vector3T<T> &sh)
881  { shear(sh(0), sh(1), sh(2)); }
882  /// @}
883 
884  // Solve a 3x3 system of equations whose parameters are held in this
885  // matrix, and whose rhs constants are cx, cy, and cz. The method returns
886  // 0 if the determinant is not 0, and 1 otherwise.
887  template <typename S>
888  int solve(T cx, T cy, T cz,
889  UT_Vector3T<S> &result) const;
890 
891  // Space change operation: right multiply this matrix by the 3x3 matrix
892  // of the transformation which moves the vector space defined by
893  // (iSrc, jSrc, cross(iSrc,jSrc)) into the space defined by
894  // (iDest, jDest, cross(iDest,jDest)). iSrc, jSrc, iDest, and jDest will
895  // be normalized before the operation if norm is 1. This matrix transforms
896  // iSrc into iDest, and jSrc into jDest.
897  template <typename S>
898  void changeSpace(UT_Vector3T<S> &iSrc, UT_Vector3T<S> &jSrc,
899  UT_Vector3T<S> &iDest,UT_Vector3T<S> &jDest,
900  int norm=1);
901 
902  // Multiply this matrix by the general transform matrix built from
903  // translations (tx,ty), degree rotation (rz), scales (sx,sy),
904  // and possibly a pivot point (px,py). The second methos leaves us
905  // unchanged, and returns a new (this*xform) instead. The order of the
906  // multiplies (SRT, RST, Rz, etc) is stored in 'order'. Normally you
907  // will ignore the 'reverse' parameter, which tells us to build the
908  // matrix from last to first xform, and to apply some inverses to
909  // txy, rz, and sxy.
910  void xform(const UT_XformOrder &order,
911  T tx=0.0f, T ty=0.0f, T rz=0.0f,
912  T sx=1.0f, T sy=1.0f,T px=0.0f,T py=0.0f,
913  int reverse=0);
914 
915  // this version handles shears as well
916  void xform(const UT_XformOrder &order,
917  T tx, T ty, T rz,
918  T sx, T sy, T s_xy,
919  T px, T py,
920  int reverse=0);
921 
922  // Right multiply this matrix by a 3x3 matrix which scales by a given
923  // amount along the direction of vector v. When applied to a vector w,
924  // the stretched matrix (*this) stretches w in v by the amount given.
925  // If norm is non-zero, v will be normalized prior to the operation.
926  template <typename S>
927  void stretch(UT_Vector3T<S> &v, T amount, int norm=1);
928  template <typename S>
929  SYS_DEPRECATED(12.0) UT_Matrix3T<T> stretch(UT_Vector3T<S> &v, T amount, int norm=1) const;
930 
931  //
932  // This does a test to see if a vector transformed by the matrix
933  // will maintain it's length (i.e. there are no scales in the matrix)
934  int isNormalized() const;
935 
936  // Return the dot product between two rows i and j:
937  T dot(unsigned i, unsigned j) const
938  {
939  return (i <= 2 && j <= 2) ?
940  matx[i][0]*matx[j][0] + matx[i][1]*matx[j][1] +
941  matx[i][2]*matx[j][2] : (T)0;
942  }
943 
944  /// Set the matrix to identity
945  void identity() { *this = 1; }
946  /// Set the matrix to zero
947  void zero() { *this = 0; }
948 
949  int isIdentity() const
950  {
951  // NB: DO NOT USE TOLERANCES
952  return(
953  matx[0][0]==1.0f && matx[0][1]==0.0f &&
954  matx[0][2]==0.0f && matx[1][0]==0.0f &&
955  matx[1][1]==1.0f && matx[1][2]==0.0f &&
956  matx[2][0]==0.0f && matx[2][1]==0.0f &&
957  matx[2][2]==1.0f
958  );
959  }
960 
961  int isZero() const
962  {
963  // NB: DO NOT USE TOLERANCES
964  return (
965  matx[0][0]==0.0f && matx[0][1]==0.0f &&
966  matx[0][2]==0.0f && matx[1][0]==0.0f &&
967  matx[1][1]==0.0f && matx[1][2]==0.0f &&
968  matx[2][0]==0.0f && matx[2][1]==0.0f &&
969  matx[2][2]==0.0f
970  );
971  }
972 
973  /// Return the raw matrix data.
974  // @{
975  const T *data(void) const { return myFloats; }
976  T *data(void) { return myFloats; }
977  // @}
978 
979  /// Compute a hash
980  unsigned hash() const { return SYSvector_hash(data(), tuple_size); }
981 
982  /// Return a matrix entry. No bounds checking on subscripts.
983  // @{
984  SYS_FORCE_INLINE T &operator()(unsigned row, unsigned col) noexcept
985  {
986  UT_ASSERT_P(row < 3 && col < 3);
987  return matx[row][col];
988  }
990  T operator()(unsigned row, unsigned col) const noexcept
991  {
992  UT_ASSERT_P(row < 3 && col < 3);
993  return matx[row][col];
994  }
995  // @}
996 
997  /// Return a matrix row. No bounds checking on subscript.
998  // @{
999  T *operator()(unsigned row)
1000  {
1001  UT_ASSERT_P(row < 3);
1002  return matx[row];
1003  }
1004  const T *operator()(unsigned row) const
1005  {
1006  UT_ASSERT_P(row < 3);
1007  return matx[row];
1008  }
1009  inline const UT_Vector3T<T> &operator[](unsigned row) const;
1010  inline UT_Vector3T<T> &operator[](unsigned row);
1011  // @}
1012 
1013  /// Euclidean or Frobenius norm of a matrix.
1014  /// Does sqrt(sum(a_ij ^2))
1016  { return SYSsqrt(getEuclideanNorm2()); }
1017  /// Euclidean norm squared.
1018  T getEuclideanNorm2() const;
1019 
1020  /// Get the squared Euclidean distance between '*this' and 'from'
1021  /// Returns sum_ij(sqr(b_ij-a_ij))
1022  T distanceSquared(const UT_Matrix3T<T> &src);
1023 
1024  /// Get the 1-norm of this matrix, assuming a row vector convention.
1025  /// Returns the maximum absolute row sum. ie. max_i(sum_j(abs(a_ij)))
1026  T getNorm1() const;
1027 
1028  /// Get the inf-norm of this matrix, assuming a row vector convention.
1029  /// Returns the maximum absolute column sum. ie. max_j(sum_i(abs(a_ij)))
1030  T getNormInf() const;
1031 
1032  // I/O methods. Return 0 if read/write successful, -1 if unsuccessful.
1033  int save(std::ostream &os, int binary) const;
1034  bool load(UT_IStream &is);
1035 
1036  void outAsciiNoName(std::ostream &os) const;
1037 
1038  static const UT_Matrix3T<T> &getIdentityMatrix();
1039 
1040  // I/O friends:
1041  friend std::ostream &operator<<(std::ostream &os, const UT_Matrix3T<T> &v)
1042  {
1043  v.writeClassName(os);
1044  v.outAsciiNoName(os);
1045  return os;
1046  }
1047 
1048  /// @{
1049  /// Methods to serialize to a JSON stream. The matrix is stored as an
1050  /// array of 9 reals.
1051  bool save(UT_JSONWriter &w) const;
1052  bool save(UT_JSONValue &v) const;
1053  bool load(UT_JSONParser &p);
1054  /// @}
1055 
1056  /// Returns the vector size
1057  static int entries() { return tuple_size; }
1058 
1059 private:
1060  // Check this matrix to see if it is a valid rotation matrix, and permute
1061  // its elements depending on the rotOrder value in crack(). checkRot()
1062  // returns 0 if OK and 1 otherwise.
1063  int checkRot() const;
1064  void permute(int l0, int l1, int l2);
1065 
1066  // Operation to aid in cofactor computation
1068  void coVals(int k, int r[2]) const
1069  {
1070  switch(k)
1071  {
1072  case 0: r[0] = 1; r[1] = 2; break;
1073  case 1: r[0] = 0; r[1] = 2; break;
1074  case 2: r[0] = 0; r[1] = 1; break;
1075  }
1076  }
1077 
1078 
1079  void writeClassName(std::ostream &os) const;
1080  static const char *className();
1081 
1082  // The matrix data:
1083  union {
1084  T matx[3][3];
1085  T myFloats[tuple_size];
1086  };
1087 };
1088 
1089 #include "UT_Vector3.h"
1090 
1091 template <typename T>
1092 template <typename S>
1093 inline
1095 {
1096  matx[0][0] = matx[0][1] = matx[0][2] = vec.x();
1097  matx[1][0] = matx[1][1] = matx[1][2] = vec.y();
1098  matx[2][0] = matx[2][1] = matx[2][2] = vec.z();
1099  return *this;
1100 }
1101 
1102 template <typename T>
1103 template <typename S>
1104 inline
1106 {
1107  T x = vec.x(); T y = vec.y(); T z = vec.z();
1108  matx[0][0]+=x; matx[0][1]+=x; matx[0][2]+=x;
1109  matx[1][0]+=y; matx[1][1]+=y; matx[1][2]+=y;
1110  matx[2][0]+=z; matx[2][1]+=z; matx[2][2]+=z;
1111  return *this;
1112 }
1113 
1114 template <typename T>
1115 template <typename S>
1116 inline
1118 {
1119  T x = vec.x(); T y = vec.y(); T z = vec.z();
1120  matx[0][0]-=x; matx[0][1]-=x; matx[0][2]-=x;
1121  matx[1][0]-=y; matx[1][1]-=y; matx[1][2]-=y;
1122  matx[2][0]-=z; matx[2][1]-=z; matx[2][2]-=z;
1123  return *this;
1124 }
1125 
1126 #ifndef UT_DISABLE_VECTORIZE_MATRIX
1127 template <> inline UT_Matrix3T<float>&
1129 {
1130  v4uf r0(m.matx[0]);
1131  v4uf r1(m.matx[1]);
1132  v4uf r2(m(2,0), m(2,1), m(2,2), 0.f);
1133 
1134  // Do not alter the order in which the rows are computed.
1135  // This routine relies on overriding
1136  const float m10 = matx[1][0];
1137  const float m20 = matx[2][0];
1138  {
1139  const v4uf row =
1140  r0 * v4uf(matx[0][0])
1141  + r1 * v4uf(matx[0][1])
1142  + r2 * v4uf(matx[0][2]);
1143  vm_store(matx[0], row.vector);
1144  }
1145  {
1146  const v4uf row =
1147  r0 * v4uf(m10)
1148  + r1 * v4uf(matx[1][1])
1149  + r2 * v4uf(matx[1][2]);
1150  vm_store(matx[1], row.vector);
1151  }
1152  {
1153  const v4uf row =
1154  r0 * v4uf(m20)
1155  + r1 * v4uf(matx[2][1])
1156  + r2 * v4uf(matx[2][2]);
1157 
1158  matx[2][0] = row[0];
1159  matx[2][1] = row[1];
1160  matx[2][2] = row[2];
1161  }
1162  return *this;
1163 }
1164 template <> template <> inline UT_Matrix3T<float>&
1166 {
1167  const auto& l = m.lowerTri();
1168 
1169  v4uf r0(l.q00, l.q10, l.q20, 0.f);
1170  v4uf r1(l.q10, l.q11, l.q21, 0.f);
1171  v4uf r2(l.q20, l.q21, l.q22, 0.f);
1172 
1173  // Do not alter the order in which the rows are computed.
1174  // This routine relies on overriding
1175  const float m10 = matx[1][0];
1176  const float m20 = matx[2][0];
1177  {
1178  const v4uf row =
1179  r0 * v4uf(matx[0][0])
1180  + r1 * v4uf(matx[0][1])
1181  + r2 * v4uf(matx[0][2]);
1182  vm_store(matx[0], row.vector);
1183  }
1184  {
1185  const v4uf row =
1186  r0 * v4uf(m10)
1187  + r1 * v4uf(matx[1][1])
1188  + r2 * v4uf(matx[1][2]);
1189  vm_store(matx[1], row.vector);
1190  }
1191  {
1192  const v4uf row =
1193  r0 * v4uf(m20)
1194  + r1 * v4uf(matx[2][1])
1195  + r2 * v4uf(matx[2][2]);
1196 
1197  matx[2][0] = row[0];
1198  matx[2][1] = row[1];
1199  matx[2][2] = row[2];
1200  }
1201  return *this;
1202 }
1203 #endif
1204 
1205 // Scaled outer product update (given scalar b, row vectors v1 and v2)
1206 // this += b * transpose(v1) * v2
1207 template <typename T>
1208 template <typename S>
1209 inline
1211  const UT_Vector3T<S> &v1,
1212  const UT_Vector3T<S> &v2)
1213 {
1214  T bv1;
1215  bv1 = b * v1.x();
1216  matx[0][0]+=bv1*v2.x();
1217  matx[0][1]+=bv1*v2.y();
1218  matx[0][2]+=bv1*v2.z();
1219  bv1 = b * v1.y();
1220  matx[1][0]+=bv1*v2.x();
1221  matx[1][1]+=bv1*v2.y();
1222  matx[1][2]+=bv1*v2.z();
1223  bv1 = b * v1.z();
1224  matx[2][0]+=bv1*v2.x();
1225  matx[2][1]+=bv1*v2.y();
1226  matx[2][2]+=bv1*v2.z();
1227 }
1228 
1229 template <typename T>
1230 inline
1232 {
1233  UT_ASSERT_P(row < 3);
1234  return *(const UT_Vector3T<T>*)(matx[row]);
1235 }
1236 
1237 template <typename T>
1238 inline
1240 {
1241  UT_ASSERT_P(row < 3);
1242  return *(UT_Vector3T<T>*)(matx[row]);
1243 }
1244 
1245 
1246 // Free floating functions:
1247 template <typename T, typename S>
1248 inline
1250 {
1251  return mat+vec;
1252 }
1253 
1254 template <typename T, typename S>
1255 inline
1257 {
1258  return m1*sc;
1259 }
1260 
1261 template <typename T, typename S>
1262 inline
1264 {
1265  return (m1 * (1.0f/scalar));
1266 }
1267 
1268 /// Multiplication of a row or column vector by a matrix (ie. right vs. left
1269 /// multiplication respectively). The operator*() declared above is an alias
1270 /// for rowVecMult(). The functions that take a 4x4 matrix first extend
1271 /// the vector to 4D (with a trailing 1.0 element).
1272 //
1273 // @{
1274 // Notes on optimisation of matrix/vector multiplies:
1275 // - multiply(dest, mat) functions have been deprecated in favour of
1276 // rowVecMult/colVecMult routines, which produce temporaries. For these to
1277 // offer comparable performance, the compiler has to optimize away the
1278 // temporary, but most modern compilers can do this. Performance tests with
1279 // gcc3.3 indicate that this is a realistic expectation for modern
1280 // compilers.
1281 // - since matrix/vector multiplies cannot be done without temporary data,
1282 // the "primary" functions are the global matrix/vector
1283 // rowVecMult/colVecMult routines, rather than the member functions.
1284 // - inlining is explicitly requested only for non-deprecated functions
1285 // involving the native types (UT_Vector3 and UT_Matrix3)
1286 
1287 template <typename T, typename S>
1288 inline UT_Vector3T<T> rowVecMult(const UT_Vector3T<T> &v, const UT_Matrix3T<S> &m);
1289 template <typename T, typename S>
1290 inline UT_Vector3T<T> colVecMult(const UT_Matrix3T<S> &m, const UT_Vector3T<T> &v);
1291 // @}
1292 
1293 template <typename T, typename S>
1294 inline
1296 {
1297  return UT_Vector3T<T>(
1298  v.x()*m(0,0) + v.y()*m(1,0) + v.z()*m(2,0),
1299  v.x()*m(0,1) + v.y()*m(1,1) + v.z()*m(2,1),
1300  v.x()*m(0,2) + v.y()*m(1,2) + v.z()*m(2,2)
1301  );
1302 }
1303 
1304 template <typename T, typename S>
1305 inline
1307 {
1308  return rowVecMult(v, m);
1309 }
1310 
1311 template <typename T, typename S>
1312 inline
1314 {
1315  return UT_Vector3T<T>(
1316  v.x()*m(0,0) + v.y()*m(0,1) + v.z()*m(0,2),
1317  v.x()*m(1,0) + v.y()*m(1,1) + v.z()*m(1,2),
1318  v.x()*m(2,0) + v.y()*m(2,1) + v.z()*m(2,2)
1319  );
1320 }
1321 
1322 template <typename T>
1323 SYS_FORCE_INLINE void
1325 {
1326  operator=(::rowVecMult(*this, m));
1327 }
1328 template <typename T>
1329 SYS_FORCE_INLINE void
1331 {
1332  operator=(::rowVecMult(*this, m));
1333 }
1334 template <typename T>
1335 SYS_FORCE_INLINE void
1337 {
1338  operator=(::colVecMult(m, *this));
1339 }
1340 template <typename T>
1341 SYS_FORCE_INLINE void
1343 {
1344  operator=(::colVecMult(m, *this));
1345 }
1346 template <typename T>
1347 template <typename S>
1350 {
1351  rowVecMult(m);
1352  return *this;
1353 }
1354 template <typename T>
1355 template <typename S>
1356 SYS_FORCE_INLINE void
1358 {
1359  colVecMult(mat);
1360 }
1361 template <typename T>
1362 template <typename S>
1363 SYS_FORCE_INLINE void
1365 {
1366  dest = ::colVecMult(mat, *this);
1367 }
1368 template <typename T>
1369 template <typename S>
1370 SYS_FORCE_INLINE void
1372 {
1373  dest = ::rowVecMult(*this, mat);
1374 }
1375 
1376 template <typename T>
1377 inline
1379 {
1380  return UT_Matrix3T<T>(
1381  SYSmin(v1(0,0), v2(0,0)),
1382  SYSmin(v1(0,1), v2(0,1)),
1383  SYSmin(v1(0,2), v2(0,2)),
1384  SYSmin(v1(1,0), v2(1,0)),
1385  SYSmin(v1(1,1), v2(1,1)),
1386  SYSmin(v1(1,2), v2(1,2)),
1387  SYSmin(v1(2,0), v2(2,0)),
1388  SYSmin(v1(2,1), v2(2,1)),
1389  SYSmin(v1(2,2), v2(2,2))
1390  );
1391 }
1392 
1393 template <typename T>
1394 inline
1396 {
1397  return UT_Matrix3T<T>(
1398  SYSmax(v1(0,0), v2(0,0)),
1399  SYSmax(v1(0,1), v2(0,1)),
1400  SYSmax(v1(0,2), v2(0,2)),
1401  SYSmax(v1(1,0), v2(1,0)),
1402  SYSmax(v1(1,1), v2(1,1)),
1403  SYSmax(v1(1,2), v2(1,2)),
1404  SYSmax(v1(2,0), v2(2,0)),
1405  SYSmax(v1(2,1), v2(2,1)),
1406  SYSmax(v1(2,2), v2(2,2))
1407  );
1408 }
1409 
1410 template <typename T,typename S>
1411 inline
1413 {
1414  return UT_Matrix3T<T>(
1415  SYSlerp(v1(0,0), v2(0,0), t),
1416  SYSlerp(v1(0,1), v2(0,1), t),
1417  SYSlerp(v1(0,2), v2(0,2), t),
1418  SYSlerp(v1(1,0), v2(1,0), t),
1419  SYSlerp(v1(1,1), v2(1,1), t),
1420  SYSlerp(v1(1,2), v2(1,2), t),
1421  SYSlerp(v1(2,0), v2(2,0), t),
1422  SYSlerp(v1(2,1), v2(2,1), t),
1423  SYSlerp(v1(2,2), v2(2,2), t)
1424  );
1425 }
1426 
1427 #ifndef UT_DISABLE_VECTORIZE_MATRIX
1428 template <>
1429 inline
1431 {
1432  UT_Matrix3T<float> result;
1433  {
1434  const v4uf l(v1.data());
1435  const v4uf r(v2.data());
1436  vm_store(result.data(), SYSlerp(l, r, t).vector);
1437  }
1438  {
1439  const v4uf l(v1.data() + 4);
1440  const v4uf r(v2.data() + 4);
1441  vm_store(result.data() + 4, SYSlerp(l, r, t).vector);
1442  }
1443  {
1444  result(2,2) = SYSlerp(v1(2,2), v2(2,2), t);
1445  }
1446  return result;
1447 }
1448 #endif
1449 
1450 template<typename T>
1452 {
1454  typedef T DataType;
1455  static const exint TupleSize = 9;
1456  static const bool isVectorType = true;
1457 };
1458 
1459 // Overload for custom formatting of UT_Matrix3T<T> with UTformat.
1460 template<typename T>
1461 UT_API size_t format(char *buffer, size_t buffer_size, const UT_Matrix3T<T> &v);
1462 
1463 #endif
static int entries()
Returns the vector size.
Definition: UT_Matrix3.h:1057
UT_Vector3T< T > rowVecMult(const UT_Vector3T< T > &v, const UT_Matrix3T< S > &m)
Definition: UT_Matrix3.h:1295
SYS_FORCE_INLINE T & operator()(unsigned row, unsigned col) noexcept
Return a matrix entry. No bounds checking on subscripts.
Definition: UT_Matrix3.h:984
int isZero() const
Definition: UT_Matrix3.h:961
UT_Matrix3T< T > & operator=(const UT_SymMatrix3T< S > &m)
Convert from a symmetric matrix to non-symmetric.
Definition: UT_Matrix3.h:189
Mat3< typename promote< S, T >::type > operator*(S scalar, const Mat3< T > &m)
Multiply each element of the given matrix by scalar and return the result.
Definition: Mat3.h:609
SYS_FORCE_INLINE T coFactor(int k, int l) const
Definition: UT_Matrix3.h:548
SYS_FORCE_INLINE UT_Matrix3T< T > & operator/=(T scalar)
Definition: UT_Matrix3.h:408
void leftMult(const UT_SymMatrix3T< S > &m)
Multiply given symmetric matrix on the left.
Definition: UT_Matrix3.h:331
#define SYS_STATIC_ASSERT(expr)
UT_Matrix3T< T > transposedCopy() const
Definition: UT_Matrix3.h:642
UT_SymMatrix3T< T > averagedSymMatrix3() const
Convert this to a symmetric matrix, using averaged components.
Definition: UT_Matrix3.h:216
#define SYS_DEPRECATED(__V__)
UT_SymMatrix3T< T > upperTriangularSymMatrix3() const
Convert this to a symmetric matrix, using the upper-triangular portion.
Definition: UT_Matrix3.h:208
void leftMult(const UT_Matrix3T< S > &m)
Multiply given matrix3 on the left.
Definition: UT_Matrix3.h:356
constexpr bool operator!=(const UT_Matrix3T< T > &m) const noexcept
Definition: UT_Matrix3.h:386
void orientInverse(const UT_Vector3F &v, T pscale, const UT_Vector3F *s3, const UT_Vector3F *up, const UT_QuaternionF *q)
Definition: UT_Matrix3.h:533
const T * operator()(unsigned row) const
Return a matrix row. No bounds checking on subscript.
Definition: UT_Matrix3.h:1004
SYS_FORCE_INLINE void translate(const UT_Vector2T< T > &delta)
Definition: UT_Matrix3.h:761
void UTswap(T &a, T &b)
Definition: UT_Swap.h:35
void scale(T sx, T sy, T sz)
Definition: UT_Matrix3.h:717
MatType shear(Axis axis0, Axis axis1, typename MatType::value_type shear)
Set the matrix to a shear along axis0 by a fraction of axis1.
Definition: Mat.h:720
GLboolean invert
Definition: glcorearb.h:548
constexpr bool operator==(const UT_Matrix3T< T > &m) const noexcept
Definition: UT_Matrix3.h:379
const GLdouble * v
Definition: glcorearb.h:836
SYS_FORCE_INLINE void colVecMult(const UT_Matrix3F &m)
Definition: UT_Matrix3.h:1336
UT_Matrix3T< T > & operator*=(const UT_Matrix3T< T > &m)
Definition: UT_Matrix3.h:282
Mat3< typename promote< T0, T1 >::type > operator+(const Mat3< T0 > &m0, const Mat3< T1 > &m1)
Add corresponding elements of m0 and m1 and return the result.
Definition: Mat3.h:625
UT_Matrix3T(const UT_SymMatrix3T< S > m)
Construct from a symmetric 3x3 matrix.
Definition: UT_Matrix3.h:161
void extractScales(UT_Vector3F &scales, UT_Vector3F *shears=0)
Definition: UT_Matrix3.h:846
SYS_FORCE_INLINE T operator()(unsigned row, unsigned col) const noexcept
Return a matrix entry. No bounds checking on subscripts.
Definition: UT_Matrix3.h:990
T determinant() const
Definition: UT_Matrix3.h:562
const GLuint GLenum const void * binary
Definition: glcorearb.h:1923
GLdouble GLdouble GLdouble z
Definition: glcorearb.h:847
void prerotate(const UT_Vector3T< T > &rad, const UT_XformOrder &order)
Definition: UT_Matrix3.h:701
UT_Matrix3T< T > SYSmax(const UT_Matrix3T< T > &v1, const UT_Matrix3T< T > &v2)
Definition: UT_Matrix3.h:1395
const LowerTri & lowerTri() const
Return reference to the lower triangular elements for symbolic access.
GLboolean GLboolean GLboolean GLboolean a
Definition: glcorearb.h:1221
UT_API size_t format(char *buffer, size_t buffer_size, const UT_Matrix3T< T > &v)
SYS_FORCE_INLINE UT_Matrix3T< T > & operator+=(const UT_Matrix3T< T > &m)
Definition: UT_Matrix3.h:250
int isIdentity() const
Definition: UT_Matrix3.h:949
JSON reader class which handles parsing of JSON or bJSON files.
Definition: UT_JSONParser.h:75
#define UT_API
Definition: UT_API.h:13
Generic symmetric 3x3 matrix.
Definition: UT_SymMatrix3.h:26
GLint y
Definition: glcorearb.h:102
T * operator()(unsigned row)
Return a matrix row. No bounds checking on subscript.
Definition: UT_Matrix3.h:999
Class which writes ASCII or binary JSON streams.
Definition: UT_JSONWriter.h:32
void extractScales(UT_Vector3T< fpreal16 > &scales, UT_Vector3T< fpreal16 > *shears=0)
Definition: UT_Matrix3.h:848
void prescale(T sx, T sy, T sz)
Definition: UT_Matrix3.h:730
static const exint TupleSize
GLfloat GLfloat GLfloat v2
Definition: glcorearb.h:817
SYS_FORCE_INLINE T & x(void)
Definition: UT_Vector3.h:498
void orient(const UT_Vector3D &v, T pscale, const UT_Vector3D *s3, const UT_Vector3D *up, const UT_QuaternionD *q)
Definition: UT_Matrix3.h:523
T * data(void)
Return the raw matrix data.
Definition: UT_Matrix3.h:976
UT_Matrix3T< T > SYSmin(const UT_Matrix3T< T > &v1, const UT_Matrix3T< T > &v2)
Definition: UT_Matrix3.h:1378
2D Vector class.
Definition: UT_Vector2.h:138
GLuint buffer
Definition: glcorearb.h:659
png_uint_32 i
Definition: png.h:2877
SYS_FORCE_INLINE void pretranslate(const UT_Vector2T< T > &delta)
Definition: UT_Matrix3.h:774
SYS_FORCE_INLINE void prescale(const UT_Vector3T< T > &s)
Definition: UT_Matrix3.h:737
SYS_FORCE_INLINE T & z(void)
Definition: UT_Vector3.h:502
UT_Matrix3T< T > SYSbilerp(const UT_Matrix3T< T > &u0v0, const UT_Matrix3T< T > &u1v0, const UT_Matrix3T< T > &u0v1, const UT_Matrix3T< T > &u1v1, S u, S v)
Definition: UT_Matrix3.h:70
SYS_FORCE_INLINE void outerproductUpdate(T b, const UT_Vector3F &v1, const UT_Vector3F &v2)
Definition: UT_Matrix3.h:429
GA_API const UT_StringHolder scale
SYS_FORCE_INLINE void shear(const UT_Vector3T< T > &sh)
Definition: UT_Matrix3.h:880
GLfloat f
Definition: glcorearb.h:1925
SYS_FORCE_INLINE void negate()
Negates this matrix, i.e. multiplies it by -1.
Definition: UT_Matrix3.h:742
SYS_FORCE_INLINE void multiplyT(const UT_Matrix3T< S > &mat)
Definition: UT_Matrix3.h:1357
bool isEqual(const UT_Matrix3T< T > &m, T tolerance=T(SYS_FTOLERANCE)) const
Definition: UT_Matrix3.h:650
void identity()
Set the matrix to identity.
Definition: UT_Matrix3.h:945
UT_Matrix3T< T > SYSlerp(const UT_Matrix3T< T > &v1, const UT_Matrix3T< T > &v2, S t)
Definition: UT_Matrix3.h:1412
Mat3< typename promote< T0, T1 >::type > operator-(const Mat3< T0 > &m0, const Mat3< T1 > &m1)
Subtract corresponding elements of m0 and m1 and return the result.
Definition: Mat3.h:635
State solve(const PositiveDefMatrix &A, const Vector< typename PositiveDefMatrix::ValueType > &b, Vector< typename PositiveDefMatrix::ValueType > &x, Preconditioner< typename PositiveDefMatrix::ValueType > &preconditioner, const State &termination=terminationDefaults< typename PositiveDefMatrix::ValueType >())
Solve Ax = b via the preconditioned conjugate gradient method.
int64 exint
Definition: SYS_Types.h:116
#define UT_ASSERT_P(ZZ)
Definition: UT_Assert.h:125
SYS_FORCE_INLINE void scale(const UT_Vector3T< T > &s)
Definition: UT_Matrix3.h:724
double fpreal64
Definition: SYS_Types.h:192
class UT_API UT_Matrix3T
fpreal64 dot(const CE_VectorT< T > &a, const CE_VectorT< T > &b)
Definition: CE_Vector.h:218
static const bool isVectorType
void outerproductUpdateT(T b, const UT_Vector3T< S > &v1, const UT_Vector3T< S > &v2)
Definition: UT_Matrix3.h:1210
#define SYS_FORCE_INLINE
Definition: SYS_Inline.h:45
T matx[3][3]
Definition: UT_Matrix3.h:1084
Definition: VM_SIMD.h:180
SYS_FORCE_INLINE void rowVecMult(const UT_Matrix3F &m)
Definition: UT_Matrix3.h:1324
SYS_FORCE_INLINE void outerproductUpdate(T b, const UT_Vector3D &v1, const UT_Vector3D &v2)
Definition: UT_Matrix3.h:434
UT_Matrix3T< T > & operator=(const UT_Matrix3T< S > &m) noexcept
Definition: UT_Matrix3.h:179
constexpr UT_Matrix3T(fpreal64 val) noexcept
Construct identity matrix, multipled by scalar.
Definition: UT_Matrix3.h:100
GLboolean * data
Definition: glcorearb.h:130
png_bytepp row
Definition: png.h:1836
bool INST SYS_FORCE_INLINE UT_Matrix3T(const UT_FixedVector< S, 3, INST > &r0, const UT_FixedVector< S, 3, INST > &r1, const UT_FixedVector< S, 3, INST > &r2) noexcept
Definition: UT_Matrix3.h:127
const Vec2< S > & operator*=(Vec2< S > &v, const Matrix33< T > &m)
Definition: ImathMatrix.h:3322
GLboolean GLboolean GLboolean b
Definition: glcorearb.h:1221
void orientInverse(const UT_Vector3D &v, T pscale, const UT_Vector3D *s3, const UT_Vector3D *up, const UT_QuaternionD *q)
Definition: UT_Matrix3.h:538
void translate(T dx, T dy)
Definition: UT_Matrix3.h:751
SYS_FORCE_INLINE UT_Vector3T< T > & operator*=(const UT_Matrix3T< S > &m)
Definition: UT_Matrix3.h:1349
GA_API const UT_StringHolder orient
UT_SymMatrix3T< T > lowerTriangularSymMatrix3() const
Convert this to a symmetric matrix, using the lower-triangular portion.
Definition: UT_Matrix3.h:200
UT_Matrix3T< T > & operator=(const UT_Matrix3T< T > &m)=default
Default copy assignment operator.
UT_Matrix3T< T > & operator*=(const UT_SymMatrix3T< S > &m)
Multiply given symmetric matrix on the right.
Definition: UT_Matrix3.h:304
UT_Matrix3T< T > operator-() const
Definition: UT_Matrix3.h:226
const UT_Vector3T< T > & operator[](unsigned row) const
Return a matrix row. No bounds checking on subscript.
Definition: UT_Matrix3.h:1231
void shear(T s_xy, T s_xz, T s_yz)
Definition: UT_Matrix3.h:868
Inner class to access the elements symbolically.
IFDmantra py
Definition: HDK_Image.dox:266
SYS_FORCE_INLINE T & y(void)
Definition: UT_Vector3.h:500
Quaternion class.
Definition: UT_Quaternion.h:51
const T * data(void) const
Return the raw matrix data.
Definition: UT_Matrix3.h:975
GA_API const UT_StringHolder up
bool isSymmetric(const MatType &m)
Determine if a matrix is symmetric.
Definition: Mat.h:912
png_infop png_bytep png_size_t buffer_size
Definition: png.h:2124
SYS_FORCE_INLINE UT_Matrix3T< T > & operator-=(const UT_Matrix3T< T > &m)
Definition: UT_Matrix3.h:266
void extractScales(UT_Vector3D &scales, UT_Vector3D *shears=0)
Definition: UT_Matrix3.h:844
GLint GLenum GLint x
Definition: glcorearb.h:408
UT_Vector3T< T > colVecMult(const UT_Matrix3T< S > &m, const UT_Vector3T< T > &v)
Definition: UT_Matrix3.h:1313
GLfloat GLfloat v1
Definition: glcorearb.h:816
GLuint GLfloat * val
Definition: glcorearb.h:1607
GA_API const UT_StringHolder pscale
unsigned hash() const
Compute a hash.
Definition: UT_Matrix3.h:980
Class to store JSON objects as C++ objects.
Definition: UT_JSONValue.h:75
SYS_FORCE_INLINE void addScaledMat(T k, const UT_Matrix3T< T > &m)
Definition: UT_Matrix3.h:235
T getEuclideanNorm() const
Definition: UT_Matrix3.h:1015
void orient(const UT_Vector3F &v, T pscale, const UT_Vector3F *s3, const UT_Vector3F *up, const UT_QuaternionF *q)
Definition: UT_Matrix3.h:518
#define SYS_FTOLERANCE
Definition: SYS_Types.h:203
void zero()
Set the matrix to zero.
Definition: UT_Matrix3.h:947
GLubyte GLubyte GLubyte GLubyte w
Definition: glcorearb.h:856
void conditionRotate(UT_Vector3F *scales=0)
Definition: UT_Matrix3.h:831
void conditionRotate(UT_Vector3D *scales)
Definition: UT_Matrix3.h:833
GLboolean r
Definition: glcorearb.h:1221
#define const
Definition: zconf.h:214
SYS_FORCE_INLINE void multiply(UT_Vector3T< T > &dest, const UT_Matrix4T< S > &mat) const
Definition: UT_Matrix4.h:1961
UT_Matrix3T< T > operator/(const UT_Matrix3T< T > &mat, S sc)
Definition: UT_Matrix3.h:1263
void transpose(void)
Definition: UT_Matrix3.h:635
void pretranslate(T dx, T dy)
Definition: UT_Matrix3.h:767
UT_FixedVector< T, 9 > FixedVectorType
Definition: UT_Matrix3.h:1453
T trace() const
Definition: UT_Matrix3.h:568
v4sf vector
Definition: VM_SIMD.h:336
bool INST SYS_FORCE_INLINE UT_Matrix3T(const UT_FixedVector< S, tuple_size, INST > &v) noexcept
Definition: UT_Matrix3.h:118
void rotate(const UT_Vector3T< T > &rad, const UT_XformOrder &ord)
Definition: UT_Matrix3.h:711
SYS_FORCE_INLINE UT_Matrix3T< T > & operator*=(T scalar)
Definition: UT_Matrix3.h:400
GLenum src
Definition: glcorearb.h:1792