1 /**
2  * Contains the definition of an affine 4x3 matrix (4 columns, 3 rows) of doubles, and associated functions to transform
3  * it. The matrix is column-major to match OpenGL's interpretation, and it looks like this:
4  * <p>
5  *      m00  m10  m20  m30<br>
6  *      m01  m11  m21  m31<br>
7  *      m02  m12  m22  m32<br>
8  * 
9  * @author Richard Greenlees
10  * @author Kai Burjack
11  */
12 module doml.matrix_4x3d;
13 
14 import Math = doml.math;
15 import MemUtil = doml.mem_util;
16 
17 import doml.matrix_3d;
18 import doml.matrix_4d;
19 
20 import doml.vector_3d;
21 import doml.vector_4d;
22 
23 import doml.axis_angle_4d;
24 import doml.quaternion_d;
25 
26 /*
27  * The MIT License
28  *
29  * Copyright (c) 2015-2021 Richard Greenlees
30  @$!@$# Translated by jordan4ibanez
31  *
32  * Permission is hereby granted, free of charge, to any person obtaining a copy
33  * of this software and associated documentation files (the "Software"), to deal
34  * in the Software without restriction, including without limitation the rights
35  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
36  * copies of the Software, and to permit persons to whom the Software is
37  * furnished to do so, subject to the following conditions:
38  *
39  * The above copyright notice and this permission notice shall be included in
40  * all copies or substantial portions of the Software.
41  *
42  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
43  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
44  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
45  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
46  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
47  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
48  * THE SOFTWARE.
49  */
50 
51 /**
52  * Contains the definition of an affine 4x3 matrix (4 columns, 3 rows) of doubles, and associated functions to transform
53  * it. The matrix is column-major to match OpenGL's interpretation, and it looks like this:
54  * <p>
55  *      m00  m10  m20  m30<br>
56  *      m01  m11  m21  m31<br>
57  *      m02  m12  m22  m32<br>
58  * 
59  * @author Richard Greenlees
60  * @author Kai Burjack
61  */
62 struct Matrix4x3d {
63 
64     double m00 = 1.0;
65     double m01 = 0.0;
66     double m02 = 0.0;
67 
68     double m10 = 0.0;
69     double m11 = 1.0;
70     double m12 = 0.0;
71 
72     double m20 = 0.0;
73     double m21 = 0.0;
74     double m22 = 1.0;
75 
76     double m30 = 0.0;
77     double m31 = 0.0;
78     double m32 = 0.0;
79 
80     /**
81      * Argument to the first parameter of {@link #frustumPlane(int, Vector4d)}
82      * identifying the plane with equation <code>x=-1</code> when using the identity matrix.  
83      */
84     immutable static int PLANE_NX = 0;
85     /**
86      * Argument to the first parameter of {@link #frustumPlane(int, Vector4d)}
87      * identifying the plane with equation <code>x=1</code> when using the identity matrix.  
88      */
89     immutable static int PLANE_PX = 1;
90     /**
91      * Argument to the first parameter of {@link #frustumPlane(int, Vector4d)}
92      * identifying the plane with equation <code>y=-1</code> when using the identity matrix.  
93      */
94     immutable static int PLANE_NY = 2;
95     /**
96      * Argument to the first parameter of {@link #frustumPlane(int, Vector4d)}
97      * identifying the plane with equation <code>y=1</code> when using the identity matrix.  
98      */
99     immutable static int PLANE_PY = 3;
100     /**
101      * Argument to the first parameter of {@link #frustumPlane(int, Vector4d)}
102      * identifying the plane with equation <code>z=-1</code> when using the identity matrix.  
103      */
104     immutable static int PLANE_NZ = 4;
105     /**
106      * Argument to the first parameter of {@link #frustumPlane(int, Vector4d)}
107      * identifying the plane with equation <code>z=1</code> when using the identity matrix.  
108      */
109     immutable static int PLANE_PZ = 5;
110 
111     /**
112      * Bit returned by {@link #properties()} to indicate that the matrix represents the identity transformation.
113      */
114     immutable static byte PROPERTY_IDENTITY = 1<<2;
115     /**
116      * Bit returned by {@link #properties()} to indicate that the matrix represents a pure translation transformation.
117      */
118     immutable static byte PROPERTY_TRANSLATION = 1<<3;
119     /**
120      * Bit returned by {@link #properties()} to indicate that the left 3x3 submatrix represents an orthogonal
121      * matrix (i.e. orthonormal basis).
122      */
123     immutable static byte PROPERTY_ORTHONORMAL = 1<<4;
124 
125 
126     int properties = PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL;
127 
128     /**
129      * Create a new {@link Matrix4x3d} and make it a copy of the given matrix.
130      * 
131      * @param mat
132      *          the {@link Matrix4x3d} to copy the values from
133      */
134     this(Matrix4x3d mat) {
135         set(mat);
136     }
137 
138 
139     /**
140      * Create a new {@link Matrix4x3d} by setting its left 3x3 submatrix to the values of the given {@link Matrix3d}
141      * and the rest to identity.
142      * 
143      * @param mat
144      *          the {@link Matrix3d}
145      */
146     this(Matrix3d mat) {
147         set(mat);
148     }
149 
150     /**
151      * Create a new 4x4 matrix using the supplied double values.
152      * 
153      * @param m00
154      *          the value of m00
155      * @param m01
156      *          the value of m01
157      * @param m02
158      *          the value of m02
159      * @param m10
160      *          the value of m10
161      * @param m11
162      *          the value of m11
163      * @param m12
164      *          the value of m12
165      * @param m20
166      *          the value of m20
167      * @param m21
168      *          the value of m21
169      * @param m22
170      *          the value of m22
171      * @param m30
172      *          the value of m30
173      * @param m31
174      *          the value of m31
175      * @param m32
176      *          the value of m32
177      */
178     this(double m00, double m01, double m02,
179                       double m10, double m11, double m12, 
180                       double m20, double m21, double m22, 
181                       double m30, double m31, double m32) {
182         this.m00 = m00;
183         this.m01 = m01;
184         this.m02 = m02;
185         this.m10 = m10;
186         this.m11 = m11;
187         this.m12 = m12;
188         this.m20 = m20;
189         this.m21 = m21;
190         this.m22 = m22;
191         this.m30 = m30;
192         this.m31 = m31;
193         this.m32 = m32;
194         determineProperties();
195     }
196 
197     /**
198      * Assume the given properties about this matrix.
199      * <p>
200      * Use one or multiple of 0, {@link Matrix4x3d#PROPERTY_IDENTITY},
201      * {@link Matrix4x3d#PROPERTY_TRANSLATION}, {@link Matrix4x3d#PROPERTY_ORTHONORMAL}.
202      * 
203      * @param properties
204      *          bitset of the properties to assume about this matrix
205      * @return this
206      */
207     ref public Matrix4x3d assume(int properties) return {
208         this.properties = properties;
209         return this;
210     }
211 
212     /**
213      * Compute and set the matrix properties returned by {@link #properties()} based
214      * on the current matrix element values.
215      * 
216      * @return this
217      */
218     ref public Matrix4x3d determineProperties() return {
219         int __properties = 0;
220         if (m00 == 1.0 && m01 == 0.0 && m02 == 0.0 && m10 == 0.0 && m11 == 1.0 && m12 == 0.0
221                 && m20 == 0.0 && m21 == 0.0 && m22 == 1.0) {
222             __properties |= PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL;
223             if (m30 == 0.0 && m31 == 0.0 && m32 == 0.0)
224                 __properties |= PROPERTY_IDENTITY;
225         }
226         /* 
227          * We do not determine orthogonality, since it would require arbitrary epsilons
228          * and is rather expensive (6 dot products) in the worst case.
229          */
230         this.properties = __properties;
231         return this;
232     }
233 
234     public int getproperties() {
235         return properties;
236     }
237 
238     ref Matrix4x3d _properties(int properties) return {
239         this.properties = properties;
240         return this;
241     }
242 
243     /**
244      * Set the value of the matrix element at column 0 and row 0 without updating the properties of the matrix.
245      * 
246      * @param m00
247      *          the new value
248      * @return this
249      */
250     ref Matrix4x3d _m00(double m00) return {
251         this.m00 = m00;
252         return this;
253     }
254     /**
255      * Set the value of the matrix element at column 0 and row 1 without updating the properties of the matrix.
256      * 
257      * @param m01
258      *          the new value
259      * @return this
260      */
261     ref Matrix4x3d _m01(double m01) return {
262         this.m01 = m01;
263         return this;
264     }
265     /**
266      * Set the value of the matrix element at column 0 and row 2 without updating the properties of the matrix.
267      * 
268      * @param m02
269      *          the new value
270      * @return this
271      */
272     ref Matrix4x3d _m02(double m02) return {
273         this.m02 = m02;
274         return this;
275     }
276     /**
277      * Set the value of the matrix element at column 1 and row 0 without updating the properties of the matrix.
278      * 
279      * @param m10
280      *          the new value
281      * @return this
282      */
283     ref Matrix4x3d _m10(double m10) return {
284         this.m10 = m10;
285         return this;
286     }
287     /**
288      * Set the value of the matrix element at column 1 and row 1 without updating the properties of the matrix.
289      * 
290      * @param m11
291      *          the new value
292      * @return this
293      */
294     ref Matrix4x3d _m11(double m11) return {
295         this.m11 = m11;
296         return this;
297     }
298     /**
299      * Set the value of the matrix element at column 1 and row 2 without updating the properties of the matrix.
300      * 
301      * @param m12
302      *          the new value
303      * @return this
304      */
305     ref Matrix4x3d _m12(double m12) return {
306         this.m12 = m12;
307         return this;
308     }
309     /**
310      * Set the value of the matrix element at column 2 and row 0 without updating the properties of the matrix.
311      * 
312      * @param m20
313      *          the new value
314      * @return this
315      */
316     ref Matrix4x3d _m20(double m20) return {
317         this.m20 = m20;
318         return this;
319     }
320     /**
321      * Set the value of the matrix element at column 2 and row 1 without updating the properties of the matrix.
322      * 
323      * @param m21
324      *          the new value
325      * @return this
326      */
327     ref Matrix4x3d _m21(double m21) return {
328         this.m21 = m21;
329         return this;
330     }
331     /**
332      * Set the value of the matrix element at column 2 and row 2 without updating the properties of the matrix.
333      * 
334      * @param m22
335      *          the new value
336      * @return this
337      */
338     ref Matrix4x3d _m22(double m22) return {
339         this.m22 = m22;
340         return this;
341     }
342     /**
343      * Set the value of the matrix element at column 3 and row 0 without updating the properties of the matrix.
344      * 
345      * @param m30
346      *          the new value
347      * @return this
348      */
349     ref Matrix4x3d _m30(double m30) return {
350         this.m30 = m30;
351         return this;
352     }
353     /**
354      * Set the value of the matrix element at column 3 and row 1 without updating the properties of the matrix.
355      * 
356      * @param m31
357      *          the new value
358      * @return this
359      */
360     ref Matrix4x3d _m31(double m31) return {
361         this.m31 = m31;
362         return this;
363     }
364     /**
365      * Set the value of the matrix element at column 3 and row 2 without updating the properties of the matrix.
366      * 
367      * @param m32
368      *          the new value
369      * @return this
370      */
371     ref Matrix4x3d _m32(double m32) return {
372         this.m32 = m32;
373         return this;
374     }
375 
376     /**
377      * Set the value of the matrix element at column 0 and row 0.
378      * 
379      * @param m00
380      *          the new value
381      * @return this
382      */
383     ref public Matrix4x3d setm00(double m00) return {
384         this.m00 = m00;
385         properties &= ~PROPERTY_ORTHONORMAL;
386         if (m00 != 1.0)
387             properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
388         return this;
389     }
390     /**
391      * Set the value of the matrix element at column 0 and row 1.
392      * 
393      * @param m01
394      *          the new value
395      * @return this
396      */
397     ref public Matrix4x3d setm01(double m01) return {
398         this.m01 = m01;
399         properties &= ~PROPERTY_ORTHONORMAL;
400         if (m01 != 0.0)
401             properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
402         return this;
403     }
404     /**
405      * Set the value of the matrix element at column 0 and row 2.
406      * 
407      * @param m02
408      *          the new value
409      * @return this
410      */
411     ref public Matrix4x3d setm02(double m02) return {
412         this.m02 = m02;
413         properties &= ~PROPERTY_ORTHONORMAL;
414         if (m02 != 0.0)
415             properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
416         return this;
417     }
418     /**
419      * Set the value of the matrix element at column 1 and row 0.
420      * 
421      * @param m10
422      *          the new value
423      * @return this
424      */
425     ref public Matrix4x3d setm10(double m10) return {
426         this.m10 = m10;
427         properties &= ~PROPERTY_ORTHONORMAL;
428         if (m10 != 0.0)
429             properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
430         return this;
431     }
432     /**
433      * Set the value of the matrix element at column 1 and row 1.
434      * 
435      * @param m11
436      *          the new value
437      * @return this
438      */
439     ref public Matrix4x3d setm11(double m11) return {
440         this.m11 = m11;
441         properties &= ~PROPERTY_ORTHONORMAL;
442         if (m11 != 1.0)
443             properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
444         return this;
445     }
446     /**
447      * Set the value of the matrix element at column 1 and row 2.
448      * 
449      * @param m12
450      *          the new value
451      * @return this
452      */
453     ref public Matrix4x3d setm12(double m12) return {
454         this.m12 = m12;
455         properties &= ~PROPERTY_ORTHONORMAL;
456         if (m12 != 0.0)
457             properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
458         return this;
459     }
460     /**
461      * Set the value of the matrix element at column 2 and row 0.
462      * 
463      * @param m20
464      *          the new value
465      * @return this
466      */
467     ref public Matrix4x3d setm20(double m20) return {
468         this.m20 = m20;
469         properties &= ~PROPERTY_ORTHONORMAL;
470         if (m20 != 0.0)
471             properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
472         return this;
473     }
474     /**
475      * Set the value of the matrix element at column 2 and row 1.
476      * 
477      * @param m21
478      *          the new value
479      * @return this
480      */
481     ref public Matrix4x3d setm21(double m21) return {
482         this.m21 = m21;
483         properties &= ~PROPERTY_ORTHONORMAL;
484         if (m21 != 0.0)
485             properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
486         return this;
487     }
488     /**
489      * Set the value of the matrix element at column 2 and row 2.
490      * 
491      * @param m22
492      *          the new value
493      * @return this
494      */
495     ref public Matrix4x3d setm22(double m22) return {
496         this.m22 = m22;
497         properties &= ~PROPERTY_ORTHONORMAL;
498         if (m22 != 1.0)
499             properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
500         return this;
501     }
502     /**
503      * Set the value of the matrix element at column 3 and row 0.
504      * 
505      * @param m30
506      *          the new value
507      * @return this
508      */
509     ref public Matrix4x3d setm30(double m30) return {
510         this.m30 = m30;
511         if (m30 != 0.0)
512             properties &= ~PROPERTY_IDENTITY;
513         return this;
514     }
515     /**
516      * Set the value of the matrix element at column 3 and row 1.
517      * 
518      * @param m31
519      *          the new value
520      * @return this
521      */
522     ref public Matrix4x3d setm31(double m31) return {
523         this.m31 = m31;
524         if (m31 != 0.0)
525             properties &= ~PROPERTY_IDENTITY;
526         return this;
527     }
528     /**
529      * Set the value of the matrix element at column 3 and row 2.
530      * 
531      * @param m32
532      *          the new value
533      * @return this
534      */
535     ref public Matrix4x3d setm32(double m32) return {
536         this.m32 = m32;
537         if (m32 != 0.0)
538             properties &= ~PROPERTY_IDENTITY;
539         return this;
540     }
541 
542     /**
543      * Reset this matrix to the identity.
544      * <p>
545      * Please note that if a call to {@link #identity()} is immediately followed by a call to:
546      * {@link #translate(double, double, double) translate}, 
547      * {@link #rotate(double, double, double, double) rotate},
548      * {@link #scale(double, double, double) scale},
549      * {@link #ortho(double, double, double, double, double, double) ortho},
550      * {@link #ortho2D(double, double, double, double) ortho2D},
551      * {@link #lookAt(double, double, double, double, double, double, double, double, double) lookAt},
552      * {@link #lookAlong(double, double, double, double, double, double) lookAlong},
553      * or any of their overloads, then the call to {@link #identity()} can be omitted and the subsequent call replaced with:
554      * {@link #translation(double, double, double) translation},
555      * {@link #rotation(double, double, double, double) rotation},
556      * {@link #scaling(double, double, double) scaling},
557      * {@link #setOrtho(double, double, double, double, double, double) setOrtho},
558      * {@link #setOrtho2D(double, double, double, double) setOrtho2D},
559      * {@link #setLookAt(double, double, double, double, double, double, double, double, double) setLookAt},
560      * {@link #setLookAlong(double, double, double, double, double, double) setLookAlong},
561      * or any of their overloads.
562      * 
563      * @return this
564      */
565     ref public Matrix4x3d identity() return {
566         if ((properties & PROPERTY_IDENTITY) != 0)
567             return this;
568         m00 = 1.0;
569         m01 = 0.0;
570         m02 = 0.0;
571         m10 = 0.0;
572         m11 = 1.0;
573         m12 = 0.0;
574         m20 = 0.0;
575         m21 = 0.0;
576         m22 = 1.0;
577         m30 = 0.0;
578         m31 = 0.0;
579         m32 = 0.0;
580         properties = PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL;
581         return this;
582     }
583 
584     /**
585      * Store the values of the given matrix <code>m</code> into <code>this</code> matrix.
586      * 
587      * @param m
588      *          the matrix to copy the values from
589      * @return this
590      */
591     ref public Matrix4x3d set(Matrix4x3d m) return {
592         m00 = m.m00;
593         m01 = m.m01;
594         m02 = m.m02;
595         m10 = m.m10;
596         m11 = m.m11;
597         m12 = m.m12;
598         m20 = m.m20;
599         m21 = m.m21;
600         m22 = m.m22;
601         m30 = m.m30;
602         m31 = m.m31;
603         m32 = m.m32;
604         properties = m.properties;
605         return this;
606     }
607 
608 
609     /**
610      * Store the values of the upper 4x3 submatrix of <code>m</code> into <code>this</code> matrix.
611      * 
612      * @see Matrix4d#get4x3(Matrix4x3d)
613      * 
614      * @param m
615      *          the matrix to copy the values from
616      * @return this
617      */
618     ref public Matrix4x3d set(Matrix4d m) return {
619         m00 = m.m00;
620         m01 = m.m01;
621         m02 = m.m02;
622         m10 = m.m10;
623         m11 = m.m11;
624         m12 = m.m12;
625         m20 = m.m20;
626         m21 = m.m21;
627         m22 = m.m22;
628         m30 = m.m30;
629         m31 = m.m31;
630         m32 = m.m32;
631         properties = m.properties & (PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
632         return this;
633     }
634 
635     public Matrix4d get(ref Matrix4d dest) {
636         return dest.set4x3(this);
637     }
638 
639     /**
640      * Set the left 3x3 submatrix of this {@link Matrix4x3d} to the given {@link Matrix3d} 
641      * and the rest to identity.
642      * 
643      * @see #Matrix4x3d(Matrix3d)
644      * 
645      * @param mat
646      *          the {@link Matrix3d}
647      * @return this
648      */
649     ref public Matrix4x3d set(Matrix3d mat) return {
650         m00 = mat.m00;
651         m01 = mat.m01;
652         m02 = mat.m02;
653         m10 = mat.m10;
654         m11 = mat.m11;
655         m12 = mat.m12;
656         m20 = mat.m20;
657         m21 = mat.m21;
658         m22 = mat.m22;
659         m30 = 0.0;
660         m31 = 0.0;
661         m32 = 0.0;
662         return determineProperties();
663     }
664 
665 
666     /**
667      * Set the four columns of this matrix to the supplied vectors, respectively.
668      * 
669      * @param col0
670      *          the first column
671      * @param col1
672      *          the second column
673      * @param col2
674      *          the third column
675      * @param col3
676      *          the fourth column
677      * @return this
678      */
679     ref public Matrix4x3d set(Vector3d col0,
680                           Vector3d col1, 
681                           Vector3d col2,
682                           Vector3d col3) return {
683         this.m00 = col0.x;
684         this.m01 = col0.y;
685         this.m02 = col0.z;
686         this.m10 = col1.x;
687         this.m11 = col1.y;
688         this.m12 = col1.z;
689         this.m20 = col2.x;
690         this.m21 = col2.y;
691         this.m22 = col2.z;
692         this.m30 = col3.x;
693         this.m31 = col3.y;
694         this.m32 = col3.z;
695         return determineProperties();
696     }
697 
698     /**
699      * Set the left 3x3 submatrix of this {@link Matrix4x3d} to that of the given {@link Matrix4x3d} 
700      * and don't change the other elements.
701      * 
702      * @param mat
703      *          the {@link Matrix4x3d}
704      * @return this
705      */
706     ref public Matrix4x3d set3x3(Matrix4x3d mat) return {
707         m00 = mat.m00;
708         m01 = mat.m01;
709         m02 = mat.m02;
710         m10 = mat.m10;
711         m11 = mat.m11;
712         m12 = mat.m12;
713         m20 = mat.m20;
714         m21 = mat.m21;
715         m22 = mat.m22;
716         properties &= mat.properties;
717         return this;
718     }
719 
720     /**
721      * Set this matrix to be equivalent to the rotation specified by the given {@link AxisAngle4d}.
722      * 
723      * @param axisAngle
724      *          the {@link AxisAngle4d}
725      * @return this
726      */
727     ref public Matrix4x3d set(AxisAngle4d axisAngle) return {
728         double x = axisAngle.x;
729         double y = axisAngle.y;
730         double z = axisAngle.z;
731         double angle = axisAngle.angle;
732         double invLength = Math.invsqrt(x*x + y*y + z*z);
733         x *= invLength;
734         y *= invLength;
735         z *= invLength;
736         double s = Math.sin(angle);
737         double c = Math.cosFromSin(s, angle);
738         double omc = 1.0 - c;
739         m00 = c + x*x*omc;
740         m11 = c + y*y*omc;
741         m22 = c + z*z*omc;
742         double tmp1 = x*y*omc;
743         double tmp2 = z*s;
744         m10 = tmp1 - tmp2;
745         m01 = tmp1 + tmp2;
746         tmp1 = x*z*omc;
747         tmp2 = y*s;
748         m20 = tmp1 + tmp2;
749         m02 = tmp1 - tmp2;
750         tmp1 = y*z*omc;
751         tmp2 = x*s;
752         m21 = tmp1 - tmp2;
753         m12 = tmp1 + tmp2;
754         m30 = 0.0;
755         m31 = 0.0;
756         m32 = 0.0;
757         properties = PROPERTY_ORTHONORMAL;
758         return this;
759     }
760 
761 
762     /**
763      * Set this matrix to be equivalent to the rotation - and possibly scaling - specified by the given {@link Quaterniond}.
764      * <p>
765      * This method is equivalent to calling: <code>rotation(q)</code>
766      * 
767      * @param q
768      *          the {@link Quaterniond}
769      * @return this
770      */
771     ref public Matrix4x3d set(Quaterniond q) return {
772         return rotation(q);
773     }
774 
775     /**
776      * Multiply this matrix by the supplied <code>right</code> matrix.
777      * <p>
778      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the <code>right</code> matrix,
779      * then the new matrix will be <code>M * R</code>. So when transforming a
780      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
781      * transformation of the right matrix will be applied first!
782      * 
783      * @param right
784      *          the right operand of the multiplication
785      * @return this
786      */
787     ref public Matrix4x3d mul(Matrix4x3d right) return {
788         mul(right, this);
789         return this;
790     }
791 
792     public Matrix4x3d mul(Matrix4x3d right, ref Matrix4x3d dest) {
793         if ((properties & PROPERTY_IDENTITY) != 0)
794             return dest.set(right);
795         else if ((right.properties & PROPERTY_IDENTITY) != 0)
796             return dest.set(this);
797         else if ((properties & PROPERTY_TRANSLATION) != 0)
798             return mulTranslation(right, dest);
799         return mulGeneric(right, dest);
800     }
801     private Matrix4x3d mulGeneric(Matrix4x3d right, ref Matrix4x3d dest) {
802         double __m00 = this.m00, __m01 = this.m01, __m02 = this.m02;
803         double __m10 = this.m10, __m11 = this.m11, __m12 = this.m12;
804         double __m20 = this.m20, __m21 = this.m21, __m22 = this.m22;
805         double rm00 = right.m00, rm01 = right.m01, rm02 = right.m02;
806         double rm10 = right.m10, rm11 = right.m11, rm12 = right.m12;
807         double rm20 = right.m20, rm21 = right.m21, rm22 = right.m22;
808         double rm30 = right.m30, rm31 = right.m31, rm32 = right.m32;
809         return dest
810         ._m00(Math.fma(__m00, rm00, Math.fma(__m10, rm01, __m20 * rm02)))
811         ._m01(Math.fma(__m01, rm00, Math.fma(__m11, rm01, __m21 * rm02)))
812         ._m02(Math.fma(__m02, rm00, Math.fma(__m12, rm01, __m22 * rm02)))
813         ._m10(Math.fma(__m00, rm10, Math.fma(__m10, rm11, __m20 * rm12)))
814         ._m11(Math.fma(__m01, rm10, Math.fma(__m11, rm11, __m21 * rm12)))
815         ._m12(Math.fma(__m02, rm10, Math.fma(__m12, rm11, __m22 * rm12)))
816         ._m20(Math.fma(__m00, rm20, Math.fma(__m10, rm21, __m20 * rm22)))
817         ._m21(Math.fma(__m01, rm20, Math.fma(__m11, rm21, __m21 * rm22)))
818         ._m22(Math.fma(__m02, rm20, Math.fma(__m12, rm21, __m22 * rm22)))
819         ._m30(Math.fma(__m00, rm30, Math.fma(__m10, rm31, Math.fma(__m20, rm32, m30))))
820         ._m31(Math.fma(__m01, rm30, Math.fma(__m11, rm31, Math.fma(__m21, rm32, m31))))
821         ._m32(Math.fma(__m02, rm30, Math.fma(__m12, rm31, Math.fma(__m22, rm32, m32))))
822         ._properties(properties & right.properties & PROPERTY_ORTHONORMAL);
823     }
824 
825 
826     public Matrix4x3d mulTranslation(Matrix4x3d right, ref Matrix4x3d dest) {
827         return dest
828         ._m00(right.m00)
829         ._m01(right.m01)
830         ._m02(right.m02)
831         ._m10(right.m10)
832         ._m11(right.m11)
833         ._m12(right.m12)
834         ._m20(right.m20)
835         ._m21(right.m21)
836         ._m22(right.m22)
837         ._m30(right.m30 + m30)
838         ._m31(right.m31 + m31)
839         ._m32(right.m32 + m32)
840         ._properties(right.properties & PROPERTY_ORTHONORMAL);
841     }
842 
843     /**
844      * Multiply <code>this</code> orthographic projection matrix by the supplied <code>view</code> matrix.
845      * <p>
846      * If <code>M</code> is <code>this</code> matrix and <code>V</code> the <code>view</code> matrix,
847      * then the new matrix will be <code>M * V</code>. So when transforming a
848      * vector <code>v</code> with the new matrix by using <code>M * V * v</code>, the
849      * transformation of the <code>view</code> matrix will be applied first!
850      *
851      * @param view
852      *          the matrix which to multiply <code>this</code> with
853      * @return this
854      */
855     ref public Matrix4x3d mulOrtho(Matrix4x3d view) return {
856         mulOrtho(view, this);
857         return this;
858     }
859 
860     public Matrix4x3d mulOrtho(Matrix4x3d view, ref Matrix4x3d dest) {
861         double nm00 = m00 * view.m00;
862         double nm01 = m11 * view.m01;
863         double nm02 = m22 * view.m02;
864         double nm10 = m00 * view.m10;
865         double nm11 = m11 * view.m11;
866         double nm12 = m22 * view.m12;
867         double nm20 = m00 * view.m20;
868         double nm21 = m11 * view.m21;
869         double nm22 = m22 * view.m22;
870         double nm30 = m00 * view.m30 + m30;
871         double nm31 = m11 * view.m31 + m31;
872         double nm32 = m22 * view.m32 + m32;
873         dest.m00 = nm00;
874         dest.m01 = nm01;
875         dest.m02 = nm02;
876         dest.m10 = nm10;
877         dest.m11 = nm11;
878         dest.m12 = nm12;
879         dest.m20 = nm20;
880         dest.m21 = nm21;
881         dest.m22 = nm22;
882         dest.m30 = nm30;
883         dest.m31 = nm31;
884         dest.m32 = nm32;
885         dest.properties = (this.properties & view.properties & PROPERTY_ORTHONORMAL);
886         return dest;
887     }
888 
889     /**
890      * Multiply <code>this</code> by the 4x3 matrix with the column vectors <code>(rm00, rm01, rm02)</code>,
891      * <code>(rm10, rm11, rm12)</code>, <code>(rm20, rm21, rm22)</code> and <code>(0, 0, 0)</code>.
892      * <p>
893      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the specified matrix,
894      * then the new matrix will be <code>M * R</code>. So when transforming a
895      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
896      * transformation of the <code>R</code> matrix will be applied first!
897      * 
898      * @param rm00
899      *          the value of the m00 element
900      * @param rm01
901      *          the value of the m01 element
902      * @param rm02
903      *          the value of the m02 element
904      * @param rm10
905      *          the value of the m10 element
906      * @param rm11
907      *          the value of the m11 element
908      * @param rm12
909      *          the value of the m12 element
910      * @param rm20
911      *          the value of the m20 element
912      * @param rm21
913      *          the value of the m21 element
914      * @param rm22
915      *          the value of the m22 element
916      * @return this
917      */
918     ref public Matrix4x3d mul3x3(
919             double rm00, double rm01, double rm02,
920             double rm10, double rm11, double rm12,
921             double rm20, double rm21, double rm22) return {
922         mul3x3(rm00, rm01, rm02, rm10, rm11, rm12, rm20, rm21, rm22, this);
923         return this;
924     }
925     public Matrix4x3d mul3x3(
926             double rm00, double rm01, double rm02,
927             double rm10, double rm11, double rm12,
928             double rm20, double rm21, double rm22,
929             ref Matrix4x3d dest) {
930         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
931         double m10 = this.m10, m11 = this.m11, m12 = this.m12;
932         double m20 = this.m20, m21 = this.m21, m22 = this.m22;
933         return dest
934         ._m00(Math.fma(m00, rm00, Math.fma(m10, rm01, m20 * rm02)))
935         ._m01(Math.fma(m01, rm00, Math.fma(m11, rm01, m21 * rm02)))
936         ._m02(Math.fma(m02, rm00, Math.fma(m12, rm01, m22 * rm02)))
937         ._m10(Math.fma(m00, rm10, Math.fma(m10, rm11, m20 * rm12)))
938         ._m11(Math.fma(m01, rm10, Math.fma(m11, rm11, m21 * rm12)))
939         ._m12(Math.fma(m02, rm10, Math.fma(m12, rm11, m22 * rm12)))
940         ._m20(Math.fma(m00, rm20, Math.fma(m10, rm21, m20 * rm22)))
941         ._m21(Math.fma(m01, rm20, Math.fma(m11, rm21, m21 * rm22)))
942         ._m22(Math.fma(m02, rm20, Math.fma(m12, rm21, m22 * rm22)))
943         ._m30(m30)
944         ._m31(m31)
945         ._m32(m32)
946         ._properties(0);
947     }
948 
949     /**
950      * Component-wise add <code>this</code> and <code>other</code>
951      * by first multiplying each component of <code>other</code> by <code>otherFactor</code> and
952      * adding that result to <code>this</code>.
953      * <p>
954      * The matrix <code>other</code> will not be changed.
955      * 
956      * @param other
957      *          the other matrix 
958      * @param otherFactor
959      *          the factor to multiply each of the other matrix's components
960      * @return this
961      */
962     ref public Matrix4x3d fma(Matrix4x3d other, double otherFactor) return {
963         fma(other, otherFactor, this);
964         return this;
965     }
966 
967     public Matrix4x3d fma(Matrix4x3d other, double otherFactor, ref Matrix4x3d dest) {
968         dest
969         ._m00(Math.fma(other.m00, otherFactor, m00))
970         ._m01(Math.fma(other.m01, otherFactor, m01))
971         ._m02(Math.fma(other.m02, otherFactor, m02))
972         ._m10(Math.fma(other.m10, otherFactor, m10))
973         ._m11(Math.fma(other.m11, otherFactor, m11))
974         ._m12(Math.fma(other.m12, otherFactor, m12))
975         ._m20(Math.fma(other.m20, otherFactor, m20))
976         ._m21(Math.fma(other.m21, otherFactor, m21))
977         ._m22(Math.fma(other.m22, otherFactor, m22))
978         ._m30(Math.fma(other.m30, otherFactor, m30))
979         ._m31(Math.fma(other.m31, otherFactor, m31))
980         ._m32(Math.fma(other.m32, otherFactor, m32))
981         ._properties(0);
982         return dest;
983     }
984 
985     /**
986      * Component-wise add <code>this</code> and <code>other</code>.
987      * 
988      * @param other
989      *          the other addend
990      * @return this
991      */
992     ref public Matrix4x3d add(Matrix4x3d other) return {
993         add(other, this);
994         return this;
995     }
996 
997     public Matrix4x3d add(Matrix4x3d other, ref Matrix4x3d dest) {
998         dest.m00 = m00 + other.m00;
999         dest.m01 = m01 + other.m01;
1000         dest.m02 = m02 + other.m02;
1001         dest.m10 = m10 + other.m10;
1002         dest.m11 = m11 + other.m11;
1003         dest.m12 = m12 + other.m12;
1004         dest.m20 = m20 + other.m20;
1005         dest.m21 = m21 + other.m21;
1006         dest.m22 = m22 + other.m22;
1007         dest.m30 = m30 + other.m30;
1008         dest.m31 = m31 + other.m31;
1009         dest.m32 = m32 + other.m32;
1010         dest.properties = 0;
1011         return dest;
1012     }
1013 
1014 
1015     /**
1016      * Component-wise subtract <code>subtrahend</code> from <code>this</code>.
1017      * 
1018      * @param subtrahend
1019      *          the subtrahend
1020      * @return this
1021      */
1022     ref public Matrix4x3d sub(Matrix4x3d subtrahend) return {
1023         sub(subtrahend, this);
1024         return this;
1025     }
1026 
1027     public Matrix4x3d sub(Matrix4x3d subtrahend, ref Matrix4x3d dest) {
1028         dest.m00 = m00 - subtrahend.m00;
1029         dest.m01 = m01 - subtrahend.m01;
1030         dest.m02 = m02 - subtrahend.m02;
1031         dest.m10 = m10 - subtrahend.m10;
1032         dest.m11 = m11 - subtrahend.m11;
1033         dest.m12 = m12 - subtrahend.m12;
1034         dest.m20 = m20 - subtrahend.m20;
1035         dest.m21 = m21 - subtrahend.m21;
1036         dest.m22 = m22 - subtrahend.m22;
1037         dest.m30 = m30 - subtrahend.m30;
1038         dest.m31 = m31 - subtrahend.m31;
1039         dest.m32 = m32 - subtrahend.m32;
1040         dest.properties = 0;
1041         return dest;
1042     }
1043 
1044     /**
1045      * Component-wise multiply <code>this</code> by <code>other</code>.
1046      * 
1047      * @param other
1048      *          the other matrix
1049      * @return this
1050      */
1051     ref public Matrix4x3d mulComponentWise(Matrix4x3d other) return {
1052         mulComponentWise(other, this);
1053         return this;
1054     }
1055 
1056     public Matrix4x3d mulComponentWise(Matrix4x3d other, ref Matrix4x3d dest) {
1057         dest.m00 = m00 * other.m00;
1058         dest.m01 = m01 * other.m01;
1059         dest.m02 = m02 * other.m02;
1060         dest.m10 = m10 * other.m10;
1061         dest.m11 = m11 * other.m11;
1062         dest.m12 = m12 * other.m12;
1063         dest.m20 = m20 * other.m20;
1064         dest.m21 = m21 * other.m21;
1065         dest.m22 = m22 * other.m22;
1066         dest.m30 = m30 * other.m30;
1067         dest.m31 = m31 * other.m31;
1068         dest.m32 = m32 * other.m32;
1069         dest.properties = 0;
1070         return dest;
1071     }
1072 
1073     /**
1074      * Set the values within this matrix to the supplied double values. The matrix will look like this:<br><br>
1075      *
1076      * m00, m10, m20, m30<br>
1077      * m01, m11, m21, m31<br>
1078      * m02, m12, m22, m32<br>
1079      *
1080      * @param m00
1081      *          the new value of m00
1082      * @param m01
1083      *          the new value of m01
1084      * @param m02
1085      *          the new value of m02
1086      * @param m10
1087      *          the new value of m10
1088      * @param m11
1089      *          the new value of m11
1090      * @param m12
1091      *          the new value of m12
1092      * @param m20
1093      *          the new value of m20
1094      * @param m21
1095      *          the new value of m21
1096      * @param m22
1097      *          the new value of m22
1098      * @param m30
1099      *          the new value of m30
1100      * @param m31
1101      *          the new value of m31
1102      * @param m32
1103      *          the new value of m32
1104      * @return this
1105      */
1106     ref public Matrix4x3d set(double m00, double m01, double m02,
1107                           double m10, double m11, double m12,
1108                           double m20, double m21, double m22, 
1109                           double m30, double m31, double m32) return {
1110         this.m00 = m00;
1111         this.m10 = m10;
1112         this.m20 = m20;
1113         this.m30 = m30;
1114         this.m01 = m01;
1115         this.m11 = m11;
1116         this.m21 = m21;
1117         this.m31 = m31;
1118         this.m02 = m02;
1119         this.m12 = m12;
1120         this.m22 = m22;
1121         this.m32 = m32;
1122         return determineProperties();
1123     }
1124 
1125     /**
1126      * Set the values in the matrix using a double array that contains the matrix elements in column-major order.
1127      * <p>
1128      * The results will look like this:<br><br>
1129      * 
1130      * 0, 3, 6, 9<br>
1131      * 1, 4, 7, 10<br>
1132      * 2, 5, 8, 11<br>
1133      * 
1134      * @see #set(double[])
1135      * 
1136      * @param m
1137      *          the array to read the matrix values from
1138      * @param off
1139      *          the offset into the array
1140      * @return this
1141      */
1142     ref public Matrix4x3d set(double[] m, int off) return {
1143         m00 = m[off+0];
1144         m01 = m[off+1];
1145         m02 = m[off+2];
1146         m10 = m[off+3];
1147         m11 = m[off+4];
1148         m12 = m[off+5];
1149         m20 = m[off+6];
1150         m21 = m[off+7];
1151         m22 = m[off+8];
1152         m30 = m[off+9];
1153         m31 = m[off+10];
1154         m32 = m[off+11];
1155         return determineProperties();
1156     }
1157 
1158     /**
1159      * Set the values in the matrix using a double array that contains the matrix elements in column-major order.
1160      * <p>
1161      * The results will look like this:<br><br>
1162      * 
1163      * 0, 3, 6, 9<br>
1164      * 1, 4, 7, 10<br>
1165      * 2, 5, 8, 11<br>
1166      * 
1167      * @see #set(double[], int)
1168      * 
1169      * @param m
1170      *          the array to read the matrix values from
1171      * @return this
1172      */
1173     ref public Matrix4x3d set(double[] m) return {
1174         return set(m, 0);
1175     }
1176 
1177 
1178 
1179     public double determinant() {
1180         return (m00 * m11 - m01 * m10) * m22
1181              + (m02 * m10 - m00 * m12) * m21
1182              + (m01 * m12 - m02 * m11) * m20;
1183     }
1184 
1185     /**
1186      * Invert this matrix.
1187      * 
1188      * @return this
1189      */
1190     ref public Matrix4x3d invert() return {
1191         invert(this);
1192         return this;
1193     }
1194 
1195     public Matrix4x3d invert(ref Matrix4x3d dest) {
1196         if ((properties & PROPERTY_IDENTITY) != 0)
1197             return dest.identity();
1198         else if ((properties & PROPERTY_ORTHONORMAL) != 0)
1199             return invertOrthonormal(dest);
1200         return invertGeneric(dest);
1201     }
1202     private Matrix4x3d invertGeneric(ref Matrix4x3d dest) {
1203         double m11m00 = m00 * m11, m10m01 = m01 * m10, m10m02 = m02 * m10;
1204         double m12m00 = m00 * m12, m12m01 = m01 * m12, m11m02 = m02 * m11;
1205         double s = 1.0 / ((m11m00 - m10m01) * m22 + (m10m02 - m12m00) * m21 + (m12m01 - m11m02) * m20);
1206         double m10m22 = m10 * m22, m10m21 = m10 * m21, m11m22 = m11 * m22;
1207         double m11m20 = m11 * m20, m12m21 = m12 * m21, m12m20 = m12 * m20;
1208         double m20m02 = m20 * m02, m20m01 = m20 * m01, m21m02 = m21 * m02;
1209         double m21m00 = m21 * m00, m22m01 = m22 * m01, m22m00 = m22 * m00;
1210         double nm00 = (m11m22 - m12m21) * s;
1211         double nm01 = (m21m02 - m22m01) * s;
1212         double nm02 = (m12m01 - m11m02) * s;
1213         double nm10 = (m12m20 - m10m22) * s;
1214         double nm11 = (m22m00 - m20m02) * s;
1215         double nm12 = (m10m02 - m12m00) * s;
1216         double nm20 = (m10m21 - m11m20) * s;
1217         double nm21 = (m20m01 - m21m00) * s;
1218         double nm22 = (m11m00 - m10m01) * s;
1219         double nm30 = (m10m22 * m31 - m10m21 * m32 + m11m20 * m32 - m11m22 * m30 + m12m21 * m30 - m12m20 * m31) * s;
1220         double nm31 = (m20m02 * m31 - m20m01 * m32 + m21m00 * m32 - m21m02 * m30 + m22m01 * m30 - m22m00 * m31) * s;
1221         double nm32 = (m11m02 * m30 - m12m01 * m30 + m12m00 * m31 - m10m02 * m31 + m10m01 * m32 - m11m00 * m32) * s;
1222         dest.m00 = nm00;
1223         dest.m01 = nm01;
1224         dest.m02 = nm02;
1225         dest.m10 = nm10;
1226         dest.m11 = nm11;
1227         dest.m12 = nm12;
1228         dest.m20 = nm20;
1229         dest.m21 = nm21;
1230         dest.m22 = nm22;
1231         dest.m30 = nm30;
1232         dest.m31 = nm31;
1233         dest.m32 = nm32;
1234         dest.properties = 0;
1235         return dest;
1236     }
1237     private Matrix4x3d invertOrthonormal(ref Matrix4x3d dest) {
1238         double nm30 = -(m00 * m30 + m01 * m31 + m02 * m32);
1239         double nm31 = -(m10 * m30 + m11 * m31 + m12 * m32);
1240         double nm32 = -(m20 * m30 + m21 * m31 + m22 * m32);
1241         double m01 = this.m01;
1242         double m02 = this.m02;
1243         double m12 = this.m12;
1244         dest.m00 = m00;
1245         dest.m01 = m10;
1246         dest.m02 = m20;
1247         dest.m10 = m01;
1248         dest.m11 = m11;
1249         dest.m12 = m21;
1250         dest.m20 = m02;
1251         dest.m21 = m12;
1252         dest.m22 = m22;
1253         dest.m30 = nm30;
1254         dest.m31 = nm31;
1255         dest.m32 = nm32;
1256         dest.properties = PROPERTY_ORTHONORMAL;
1257         return dest;
1258     }
1259 
1260     public Matrix4x3d invertOrtho(ref Matrix4x3d dest) {
1261         double invM00 = 1.0 / m00;
1262         double invM11 = 1.0 / m11;
1263         double invM22 = 1.0 / m22;
1264         dest.set(invM00, 0, 0,
1265                  0, invM11, 0,
1266                  0, 0, invM22,
1267                  -m30 * invM00, -m31 * invM11, -m32 * invM22);
1268         dest.properties = 0;
1269         return dest;
1270     }
1271 
1272     /**
1273      * Invert <code>this</code> orthographic projection matrix.
1274      * <p>
1275      * This method can be used to quickly obtain the inverse of an orthographic projection matrix.
1276      * 
1277      * @return this
1278      */
1279     ref public Matrix4x3d invertOrtho() return {
1280         invertOrtho(this);
1281         return this;
1282     }
1283 
1284     /**
1285      * Transpose only the left 3x3 submatrix of this matrix and set the rest of the matrix elements to identity.
1286      * 
1287      * @return this
1288      */
1289     ref public Matrix4x3d transpose3x3() return {
1290         transpose3x3(this);
1291         return this;
1292     }
1293 
1294     public Matrix4x3d transpose3x3(ref Matrix4x3d dest) {
1295         double nm00 = m00;
1296         double nm01 = m10;
1297         double nm02 = m20;
1298         double nm10 = m01;
1299         double nm11 = m11;
1300         double nm12 = m21;
1301         double nm20 = m02;
1302         double nm21 = m12;
1303         double nm22 = m22;
1304         dest.m00 = nm00;
1305         dest.m01 = nm01;
1306         dest.m02 = nm02;
1307         dest.m10 = nm10;
1308         dest.m11 = nm11;
1309         dest.m12 = nm12;
1310         dest.m20 = nm20;
1311         dest.m21 = nm21;
1312         dest.m22 = nm22;
1313         dest.properties = properties;
1314         return dest;
1315     }
1316 
1317     public Matrix3d transpose3x3(Matrix3d dest) {
1318         dest.m00 = (m00);
1319         dest.m01 = (m10);
1320         dest.m02 = (m20);
1321         dest.m10 = (m01);
1322         dest.m11 = (m11);
1323         dest.m12 = (m21);
1324         dest.m20 = (m02);
1325         dest.m21 = (m12);
1326         dest.m22 = (m22);
1327         return dest;
1328     }
1329 
1330     /**
1331      * Set this matrix to be a simple translation matrix.
1332      * <p>
1333      * The resulting matrix can be multiplied against another transformation
1334      * matrix to obtain an additional translation.
1335      * 
1336      * @param x
1337      *          the offset to translate in x
1338      * @param y
1339      *          the offset to translate in y
1340      * @param z
1341      *          the offset to translate in z
1342      * @return this
1343      */
1344     ref public Matrix4x3d translation(double x, double y, double z) return {
1345         if ((properties & PROPERTY_IDENTITY) == 0)
1346             this.identity();
1347         m30 = x;
1348         m31 = y;
1349         m32 = z;
1350         properties = PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL;
1351         return this;
1352     }
1353 
1354 
1355     /**
1356      * Set this matrix to be a simple translation matrix.
1357      * <p>
1358      * The resulting matrix can be multiplied against another transformation
1359      * matrix to obtain an additional translation.
1360      *
1361      * @param offset
1362      *              the offsets in x, y and z to translate
1363      * @return this
1364      */
1365     ref public Matrix4x3d translation(Vector3d offset) return {
1366         return translation(offset.x, offset.y, offset.z);
1367     }
1368 
1369     /**
1370      * Set only the translation components <code>(m30, m31, m32)</code> of this matrix to the given values <code>(x, y, z)</code>.
1371      * <p>
1372      * To build a translation matrix instead, use {@link #translation(double, double, double)}.
1373      * To apply a translation, use {@link #translate(double, double, double)}.
1374      * 
1375      * @see #translation(double, double, double)
1376      * @see #translate(double, double, double)
1377      * 
1378      * @param x
1379      *          the units to translate in x
1380      * @param y
1381      *          the units to translate in y
1382      * @param z
1383      *          the units to translate in z
1384      * @return this
1385      */
1386     ref public Matrix4x3d setTranslation(double x, double y, double z) return {
1387         m30 = x;
1388         m31 = y;
1389         m32 = z;
1390         properties &= ~(PROPERTY_IDENTITY);
1391         return this;
1392     }
1393 
1394     /**
1395      * Set only the translation components <code>(m30, m31, m32)</code> of this matrix to the given values <code>(xyz.x, xyz.y, xyz.z)</code>.
1396      * <p>
1397      * To build a translation matrix instead, use {@link #translation(Vector3d)}.
1398      * To apply a translation, use {@link #translate(Vector3d)}.
1399      * 
1400      * @see #translation(Vector3d)
1401      * @see #translate(Vector3d)
1402      * 
1403      * @param xyz
1404      *          the units to translate in <code>(x, y, z)</code>
1405      * @return this
1406      */
1407     ref public Matrix4x3d setTranslation(Vector3d xyz) return {
1408         return setTranslation(xyz.x, xyz.y, xyz.z);
1409     }
1410 
1411     public Vector3d getTranslation(ref Vector3d dest) {
1412         dest.x = m30;
1413         dest.y = m31;
1414         dest.z = m32;
1415         return dest;
1416     }
1417 
1418     public Vector3d getScale(ref Vector3d dest) {
1419         dest.x = Math.sqrt(m00 * m00 + m01 * m01 + m02 * m02);
1420         dest.y = Math.sqrt(m10 * m10 + m11 * m11 + m12 * m12);
1421         dest.z = Math.sqrt(m20 * m20 + m21 * m21 + m22 * m22);
1422         return dest;
1423     }
1424     
1425     /**
1426      * Get the current values of <code>this</code> matrix and store them into
1427      * <code>dest</code>.
1428      * <p>
1429      * This is the reverse method of {@link #set(Matrix4x3d)} and allows to obtain
1430      * intermediate calculation results when chaining multiple transformations.
1431      * 
1432      * @see #set(Matrix4x3d)
1433      * 
1434      * @param dest
1435      *          the destination matrix
1436      * @return the passed in destination
1437      */
1438     public Matrix4x3d get(ref Matrix4x3d dest) {
1439         return dest.set(this);
1440     }
1441 
1442     public Quaterniond getUnnormalizedRotation(Quaterniond dest) {
1443         return dest.setFromUnnormalized(this);
1444     }
1445 
1446     public Quaterniond getNormalizedRotation(Quaterniond dest) {
1447         return dest.setFromNormalized(this);
1448     }
1449 
1450     public double[] get(double[] arr, int offset) {
1451         arr[offset+0]  = m00;
1452         arr[offset+1]  = m01;
1453         arr[offset+2]  = m02;
1454         arr[offset+3]  = m10;
1455         arr[offset+4]  = m11;
1456         arr[offset+5]  = m12;
1457         arr[offset+6]  = m20;
1458         arr[offset+7]  = m21;
1459         arr[offset+8]  = m22;
1460         arr[offset+9]  = m30;
1461         arr[offset+10] = m31;
1462         arr[offset+11] = m32;
1463         return arr;
1464     }
1465 
1466     public double[] get(double[] arr) {
1467         return get(arr, 0);
1468     }
1469 
1470 
1471     public double[] get4x4(double[] arr, int offset) {
1472         MemUtil.copy4x4(this, arr, offset);
1473         return arr;
1474     }
1475 
1476     public double[] get4x4(double[] arr) {
1477         return get4x4(arr, 0);
1478     }
1479 
1480 
1481     public double[] getTransposed(double[] arr, int offset) {
1482         arr[offset+0]  = m00;
1483         arr[offset+1]  = m10;
1484         arr[offset+2]  = m20;
1485         arr[offset+3]  = m30;
1486         arr[offset+4]  = m01;
1487         arr[offset+5]  = m11;
1488         arr[offset+6]  = m21;
1489         arr[offset+7]  = m31;
1490         arr[offset+8]  = m02;
1491         arr[offset+9]  = m12;
1492         arr[offset+10] = m22;
1493         arr[offset+11] = m32;
1494         return arr;
1495     }
1496 
1497     public double[] getTransposed(double[] arr) {
1498         return getTransposed(arr, 0);
1499     }
1500 
1501     /**
1502      * Set all the values within this matrix to 0.
1503      * 
1504      * @return this
1505      */
1506     ref public Matrix4x3d zero() return {
1507         m00 = 0.0;
1508         m01 = 0.0;
1509         m02 = 0.0;
1510         m10 = 0.0;
1511         m11 = 0.0;
1512         m12 = 0.0;
1513         m20 = 0.0;
1514         m21 = 0.0;
1515         m22 = 0.0;
1516         m30 = 0.0;
1517         m31 = 0.0;
1518         m32 = 0.0;
1519         properties = 0;
1520         return this;
1521     }
1522 
1523     /**
1524      * Set this matrix to be a simple scale matrix, which scales all axes uniformly by the given factor.
1525      * <p>
1526      * The resulting matrix can be multiplied against another transformation
1527      * matrix to obtain an additional scaling.
1528      * <p>
1529      * In order to post-multiply a scaling transformation directly to a
1530      * matrix, use {@link #scale(double) scale()} instead.
1531      * 
1532      * @see #scale(double)
1533      * 
1534      * @param factor
1535      *             the scale factor in x, y and z
1536      * @return this
1537      */
1538     ref public Matrix4x3d scaling(double factor) return {
1539         return scaling(factor, factor, factor);
1540     }
1541 
1542     /**
1543      * Set this matrix to be a simple scale matrix.
1544      * 
1545      * @param x
1546      *          the scale in x
1547      * @param y
1548      *          the scale in y
1549      * @param z
1550      *          the scale in z         
1551      * @return this
1552      */
1553     ref public Matrix4x3d scaling(double x, double y, double z) return {
1554         if ((properties & PROPERTY_IDENTITY) == 0)
1555             this.identity();
1556         m00 = x;
1557         m11 = y;
1558         m22 = z;
1559         bool one = Math.absEqualsOne(x) && Math.absEqualsOne(y) && Math.absEqualsOne(z);
1560         properties = one ? PROPERTY_ORTHONORMAL : 0;
1561         return this;
1562     }
1563 
1564     /**
1565      * Set this matrix to be a simple scale matrix which scales the base axes by
1566      * <code>xyz.x</code>, <code>xyz.y</code> and <code>xyz.z</code>, respectively.
1567      * <p>
1568      * The resulting matrix can be multiplied against another transformation
1569      * matrix to obtain an additional scaling.
1570      * <p>
1571      * In order to post-multiply a scaling transformation directly to a
1572      * matrix use {@link #scale(Vector3d) scale()} instead.
1573      * 
1574      * @see #scale(Vector3d)
1575      * 
1576      * @param xyz
1577      *             the scale in x, y and z, respectively
1578      * @return this
1579      */
1580     ref public Matrix4x3d scaling(Vector3d xyz) return {
1581         return scaling(xyz.x, xyz.y, xyz.z);
1582     }
1583 
1584     /**
1585      * Set this matrix to a rotation matrix which rotates the given radians about a given axis.
1586      * <p>
1587      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1588      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1589      * When used with a left-handed coordinate system, the rotation is clockwise.
1590      * <p>
1591      * From <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">Wikipedia</a>
1592      * 
1593      * @param angle
1594      *          the angle in radians
1595      * @param x
1596      *          the x-coordinate of the axis to rotate about
1597      * @param y
1598      *          the y-coordinate of the axis to rotate about
1599      * @param z
1600      *          the z-coordinate of the axis to rotate about
1601      * @return this
1602      */
1603     ref public Matrix4x3d rotation(double angle, double x, double y, double z) return {
1604         if (y == 0.0 && z == 0.0 && Math.absEqualsOne(x))
1605             rotationX(x * angle);
1606         else if (x == 0.0 && z == 0.0 && Math.absEqualsOne(y))
1607             rotationY(y * angle);
1608         else if (x == 0.0 && y == 0.0 && Math.absEqualsOne(z))
1609             rotationZ(z * angle);
1610         else
1611             rotationInternal(angle, x, y, z);
1612         return this;
1613     }
1614     private Matrix4x3d rotationInternal(double angle, double x, double y, double z) {
1615         double sin = Math.sin(angle);
1616         double cos = Math.cosFromSin(sin, angle);
1617         double C = 1.0 - cos;
1618         double xy = x * y, xz = x * z, yz = y * z;
1619         m00 = cos + x * x * C;
1620         m01 = xy * C + z * sin;
1621         m02 = xz * C - y * sin;
1622         m10 = xy * C - z * sin;
1623         m11 = cos + y * y * C;
1624         m12 = yz * C + x * sin;
1625         m20 = xz * C + y * sin;
1626         m21 = yz * C - x * sin;
1627         m22 = cos + z * z * C;
1628         m30 = 0.0;
1629         m31 = 0.0;
1630         m32 = 0.0;
1631         properties = PROPERTY_ORTHONORMAL;
1632         return this;
1633     }
1634 
1635     /**
1636      * Set this matrix to a rotation transformation about the X axis.
1637      * <p>
1638      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1639      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1640      * When used with a left-handed coordinate system, the rotation is clockwise.
1641      * <p>
1642      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">http://en.wikipedia.org</a>
1643      * 
1644      * @param ang
1645      *            the angle in radians
1646      * @return this
1647      */
1648     ref public Matrix4x3d rotationX(double ang) return {
1649         double sin, cos;
1650         sin = Math.sin(ang);
1651         cos = Math.cosFromSin(sin, ang);
1652         m00 = 1.0;
1653         m01 = 0.0;
1654         m02 = 0.0;
1655         m10 = 0.0;
1656         m11 = cos;
1657         m12 = sin;
1658         m20 = 0.0;
1659         m21 = -sin;
1660         m22 = cos;
1661         m30 = 0.0;
1662         m31 = 0.0;
1663         m32 = 0.0;
1664         properties = PROPERTY_ORTHONORMAL;
1665         return this;
1666     }
1667 
1668     /**
1669      * Set this matrix to a rotation transformation about the Y axis.
1670      * <p>
1671      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1672      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1673      * When used with a left-handed coordinate system, the rotation is clockwise.
1674      * <p>
1675      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">http://en.wikipedia.org</a>
1676      * 
1677      * @param ang
1678      *            the angle in radians
1679      * @return this
1680      */
1681     ref public Matrix4x3d rotationY(double ang) return {
1682         double sin, cos;
1683         sin = Math.sin(ang);
1684         cos = Math.cosFromSin(sin, ang);
1685         m00 = cos;
1686         m01 = 0.0;
1687         m02 = -sin;
1688         m10 = 0.0;
1689         m11 = 1.0;
1690         m12 = 0.0;
1691         m20 = sin;
1692         m21 = 0.0;
1693         m22 = cos;
1694         m30 = 0.0;
1695         m31 = 0.0;
1696         m32 = 0.0;
1697         properties = PROPERTY_ORTHONORMAL;
1698         return this;
1699     }
1700 
1701     /**
1702      * Set this matrix to a rotation transformation about the Z axis.
1703      * <p>
1704      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1705      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1706      * When used with a left-handed coordinate system, the rotation is clockwise.
1707      * <p>
1708      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">http://en.wikipedia.org</a>
1709      * 
1710      * @param ang
1711      *            the angle in radians
1712      * @return this
1713      */
1714     ref public Matrix4x3d rotationZ(double ang) return {
1715         double sin, cos;
1716         sin = Math.sin(ang);
1717         cos = Math.cosFromSin(sin, ang);
1718         m00 = cos;
1719         m01 = sin;
1720         m02 = 0.0;
1721         m10 = -sin;
1722         m11 = cos;
1723         m12 = 0.0;
1724         m20 = 0.0;
1725         m21 = 0.0;
1726         m22 = 1.0;
1727         m30 = 0.0;
1728         m31 = 0.0;
1729         m32 = 0.0;
1730         properties = PROPERTY_ORTHONORMAL;
1731         return this;
1732     }
1733 
1734     /**
1735      * Set this matrix to a rotation of <code>angleX</code> radians about the X axis, followed by a rotation
1736      * of <code>angleY</code> radians about the Y axis and followed by a rotation of <code>angleZ</code> radians about the Z axis.
1737      * <p>
1738      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1739      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1740      * When used with a left-handed coordinate system, the rotation is clockwise.
1741      * <p>
1742      * This method is equivalent to calling: <code>rotationX(angleX).rotateY(angleY).rotateZ(angleZ)</code>
1743      * 
1744      * @param angleX
1745      *            the angle to rotate about X
1746      * @param angleY
1747      *            the angle to rotate about Y
1748      * @param angleZ
1749      *            the angle to rotate about Z
1750      * @return this
1751      */
1752     ref public Matrix4x3d rotationXYZ(double angleX, double angleY, double angleZ) return {
1753         double sinX = Math.sin(angleX);
1754         double cosX = Math.cosFromSin(sinX, angleX);
1755         double sinY = Math.sin(angleY);
1756         double cosY = Math.cosFromSin(sinY, angleY);
1757         double sinZ = Math.sin(angleZ);
1758         double cosZ = Math.cosFromSin(sinZ, angleZ);
1759         double m_sinX = -sinX;
1760         double m_sinY = -sinY;
1761         double m_sinZ = -sinZ;
1762 
1763         // rotateX
1764         double nm11 = cosX;
1765         double nm12 = sinX;
1766         double nm21 = m_sinX;
1767         double nm22 = cosX;
1768         // rotateY
1769         double nm00 = cosY;
1770         double nm01 = nm21 * m_sinY;
1771         double nm02 = nm22 * m_sinY;
1772         m20 = sinY;
1773         m21 = nm21 * cosY;
1774         m22 = nm22 * cosY;
1775         // rotateZ
1776         m00 = nm00 * cosZ;
1777         m01 = nm01 * cosZ + nm11 * sinZ;
1778         m02 = nm02 * cosZ + nm12 * sinZ;
1779         m10 = nm00 * m_sinZ;
1780         m11 = nm01 * m_sinZ + nm11 * cosZ;
1781         m12 = nm02 * m_sinZ + nm12 * cosZ;
1782         // set last column to identity
1783         m30 = 0.0;
1784         m31 = 0.0;
1785         m32 = 0.0;
1786         properties = PROPERTY_ORTHONORMAL;
1787         return this;
1788     }
1789 
1790     /**
1791      * Set this matrix to a rotation of <code>angleZ</code> radians about the Z axis, followed by a rotation
1792      * of <code>angleY</code> radians about the Y axis and followed by a rotation of <code>angleX</code> radians about the X axis.
1793      * <p>
1794      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1795      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1796      * When used with a left-handed coordinate system, the rotation is clockwise.
1797      * <p>
1798      * This method is equivalent to calling: <code>rotationZ(angleZ).rotateY(angleY).rotateX(angleX)</code>
1799      * 
1800      * @param angleZ
1801      *            the angle to rotate about Z
1802      * @param angleY
1803      *            the angle to rotate about Y
1804      * @param angleX
1805      *            the angle to rotate about X
1806      * @return this
1807      */
1808     ref public Matrix4x3d rotationZYX(double angleZ, double angleY, double angleX) return {
1809         double sinX = Math.sin(angleX);
1810         double cosX = Math.cosFromSin(sinX, angleX);
1811         double sinY = Math.sin(angleY);
1812         double cosY = Math.cosFromSin(sinY, angleY);
1813         double sinZ = Math.sin(angleZ);
1814         double cosZ = Math.cosFromSin(sinZ, angleZ);
1815         double m_sinZ = -sinZ;
1816         double m_sinY = -sinY;
1817         double m_sinX = -sinX;
1818 
1819         // rotateZ
1820         double nm00 = cosZ;
1821         double nm01 = sinZ;
1822         double nm10 = m_sinZ;
1823         double nm11 = cosZ;
1824         // rotateY
1825         double nm20 = nm00 * sinY;
1826         double nm21 = nm01 * sinY;
1827         double nm22 = cosY;
1828         m00 = nm00 * cosY;
1829         m01 = nm01 * cosY;
1830         m02 = m_sinY;
1831         // rotateX
1832         m10 = nm10 * cosX + nm20 * sinX;
1833         m11 = nm11 * cosX + nm21 * sinX;
1834         m12 = nm22 * sinX;
1835         m20 = nm10 * m_sinX + nm20 * cosX;
1836         m21 = nm11 * m_sinX + nm21 * cosX;
1837         m22 = nm22 * cosX;
1838         // set last column to identity
1839         m30 = 0.0;
1840         m31 = 0.0;
1841         m32 = 0.0;
1842         properties = PROPERTY_ORTHONORMAL;
1843         return this;
1844     }
1845 
1846     /**
1847      * Set this matrix to a rotation of <code>angleY</code> radians about the Y axis, followed by a rotation
1848      * of <code>angleX</code> radians about the X axis and followed by a rotation of <code>angleZ</code> radians about the Z axis.
1849      * <p>
1850      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1851      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1852      * When used with a left-handed coordinate system, the rotation is clockwise.
1853      * <p>
1854      * This method is equivalent to calling: <code>rotationY(angleY).rotateX(angleX).rotateZ(angleZ)</code>
1855      * 
1856      * @param angleY
1857      *            the angle to rotate about Y
1858      * @param angleX
1859      *            the angle to rotate about X
1860      * @param angleZ
1861      *            the angle to rotate about Z
1862      * @return this
1863      */
1864     ref public Matrix4x3d rotationYXZ(double angleY, double angleX, double angleZ) return {
1865         double sinX = Math.sin(angleX);
1866         double cosX = Math.cosFromSin(sinX, angleX);
1867         double sinY = Math.sin(angleY);
1868         double cosY = Math.cosFromSin(sinY, angleY);
1869         double sinZ = Math.sin(angleZ);
1870         double cosZ = Math.cosFromSin(sinZ, angleZ);
1871         double m_sinY = -sinY;
1872         double m_sinX = -sinX;
1873         double m_sinZ = -sinZ;
1874 
1875         // rotateY
1876         double nm00 = cosY;
1877         double nm02 = m_sinY;
1878         double nm20 = sinY;
1879         double nm22 = cosY;
1880         // rotateX
1881         double nm10 = nm20 * sinX;
1882         double nm11 = cosX;
1883         double nm12 = nm22 * sinX;
1884         m20 = nm20 * cosX;
1885         m21 = m_sinX;
1886         m22 = nm22 * cosX;
1887         // rotateZ
1888         m00 = nm00 * cosZ + nm10 * sinZ;
1889         m01 = nm11 * sinZ;
1890         m02 = nm02 * cosZ + nm12 * sinZ;
1891         m10 = nm00 * m_sinZ + nm10 * cosZ;
1892         m11 = nm11 * cosZ;
1893         m12 = nm02 * m_sinZ + nm12 * cosZ;
1894         // set last column to identity
1895         m30 = 0.0;
1896         m31 = 0.0;
1897         m32 = 0.0;
1898         properties = PROPERTY_ORTHONORMAL;
1899         return this;
1900     }
1901 
1902     /**
1903      * Set only the left 3x3 submatrix of this matrix to a rotation of <code>angleX</code> radians about the X axis, followed by a rotation
1904      * of <code>angleY</code> radians about the Y axis and followed by a rotation of <code>angleZ</code> radians about the Z axis.
1905      * <p>
1906      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1907      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1908      * When used with a left-handed coordinate system, the rotation is clockwise.
1909      * 
1910      * @param angleX
1911      *            the angle to rotate about X
1912      * @param angleY
1913      *            the angle to rotate about Y
1914      * @param angleZ
1915      *            the angle to rotate about Z
1916      * @return this
1917      */
1918     ref public Matrix4x3d setRotationXYZ(double angleX, double angleY, double angleZ) return {
1919         double sinX = Math.sin(angleX);
1920         double cosX = Math.cosFromSin(sinX, angleX);
1921         double sinY = Math.sin(angleY);
1922         double cosY = Math.cosFromSin(sinY, angleY);
1923         double sinZ = Math.sin(angleZ);
1924         double cosZ = Math.cosFromSin(sinZ, angleZ);
1925         double m_sinX = -sinX;
1926         double m_sinY = -sinY;
1927         double m_sinZ = -sinZ;
1928 
1929         // rotateX
1930         double nm11 = cosX;
1931         double nm12 = sinX;
1932         double nm21 = m_sinX;
1933         double nm22 = cosX;
1934         // rotateY
1935         double nm00 = cosY;
1936         double nm01 = nm21 * m_sinY;
1937         double nm02 = nm22 * m_sinY;
1938         m20 = sinY;
1939         m21 = nm21 * cosY;
1940         m22 = nm22 * cosY;
1941         // rotateZ
1942         m00 = nm00 * cosZ;
1943         m01 = nm01 * cosZ + nm11 * sinZ;
1944         m02 = nm02 * cosZ + nm12 * sinZ;
1945         m10 = nm00 * m_sinZ;
1946         m11 = nm01 * m_sinZ + nm11 * cosZ;
1947         m12 = nm02 * m_sinZ + nm12 * cosZ;
1948         properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
1949         return this;
1950     }
1951 
1952     /**
1953      * Set only the left 3x3 submatrix of this matrix to a rotation of <code>angleZ</code> radians about the Z axis, followed by a rotation
1954      * of <code>angleY</code> radians about the Y axis and followed by a rotation of <code>angleX</code> radians about the X axis.
1955      * <p>
1956      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1957      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1958      * When used with a left-handed coordinate system, the rotation is clockwise.
1959      * 
1960      * @param angleZ
1961      *            the angle to rotate about Z
1962      * @param angleY
1963      *            the angle to rotate about Y
1964      * @param angleX
1965      *            the angle to rotate about X
1966      * @return this
1967      */
1968     ref public Matrix4x3d setRotationZYX(double angleZ, double angleY, double angleX) return {
1969         double sinX = Math.sin(angleX);
1970         double cosX = Math.cosFromSin(sinX, angleX);
1971         double sinY = Math.sin(angleY);
1972         double cosY = Math.cosFromSin(sinY, angleY);
1973         double sinZ = Math.sin(angleZ);
1974         double cosZ = Math.cosFromSin(sinZ, angleZ);
1975         double m_sinZ = -sinZ;
1976         double m_sinY = -sinY;
1977         double m_sinX = -sinX;
1978 
1979         // rotateZ
1980         double nm00 = cosZ;
1981         double nm01 = sinZ;
1982         double nm10 = m_sinZ;
1983         double nm11 = cosZ;
1984         // rotateY
1985         double nm20 = nm00 * sinY;
1986         double nm21 = nm01 * sinY;
1987         double nm22 = cosY;
1988         m00 = nm00 * cosY;
1989         m01 = nm01 * cosY;
1990         m02 = m_sinY;
1991         // rotateX
1992         m10 = nm10 * cosX + nm20 * sinX;
1993         m11 = nm11 * cosX + nm21 * sinX;
1994         m12 = nm22 * sinX;
1995         m20 = nm10 * m_sinX + nm20 * cosX;
1996         m21 = nm11 * m_sinX + nm21 * cosX;
1997         m22 = nm22 * cosX;
1998         properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
1999         return this;
2000     }
2001 
2002     /**
2003      * Set only the left 3x3 submatrix of this matrix to a rotation of <code>angleY</code> radians about the Y axis, followed by a rotation
2004      * of <code>angleX</code> radians about the X axis and followed by a rotation of <code>angleZ</code> radians about the Z axis.
2005      * <p>
2006      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2007      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2008      * When used with a left-handed coordinate system, the rotation is clockwise.
2009      * 
2010      * @param angleY
2011      *            the angle to rotate about Y
2012      * @param angleX
2013      *            the angle to rotate about X
2014      * @param angleZ
2015      *            the angle to rotate about Z
2016      * @return this
2017      */
2018     ref public Matrix4x3d setRotationYXZ(double angleY, double angleX, double angleZ) return {
2019         double sinX = Math.sin(angleX);
2020         double cosX = Math.cosFromSin(sinX, angleX);
2021         double sinY = Math.sin(angleY);
2022         double cosY = Math.cosFromSin(sinY, angleY);
2023         double sinZ = Math.sin(angleZ);
2024         double cosZ = Math.cosFromSin(sinZ, angleZ);
2025         double m_sinY = -sinY;
2026         double m_sinX = -sinX;
2027         double m_sinZ = -sinZ;
2028 
2029         // rotateY
2030         double nm00 = cosY;
2031         double nm02 = m_sinY;
2032         double nm20 = sinY;
2033         double nm22 = cosY;
2034         // rotateX
2035         double nm10 = nm20 * sinX;
2036         double nm11 = cosX;
2037         double nm12 = nm22 * sinX;
2038         m20 = nm20 * cosX;
2039         m21 = m_sinX;
2040         m22 = nm22 * cosX;
2041         // rotateZ
2042         m00 = nm00 * cosZ + nm10 * sinZ;
2043         m01 = nm11 * sinZ;
2044         m02 = nm02 * cosZ + nm12 * sinZ;
2045         m10 = nm00 * m_sinZ + nm10 * cosZ;
2046         m11 = nm11 * cosZ;
2047         m12 = nm02 * m_sinZ + nm12 * cosZ;
2048         properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
2049         return this;
2050     }
2051 
2052     /**
2053      * Set this matrix to a rotation matrix which rotates the given radians about a given axis.
2054      * <p>
2055      * The axis described by the <code>axis</code> vector needs to be a unit vector.
2056      * <p>
2057      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2058      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2059      * When used with a left-handed coordinate system, the rotation is clockwise.
2060      * 
2061      * @param angle
2062      *          the angle in radians
2063      * @param axis
2064      *          the axis to rotate about
2065      * @return this
2066      */
2067     ref public Matrix4x3d rotation(double angle, Vector3d axis) return {
2068         return rotation(angle, axis.x, axis.y, axis.z);
2069     }
2070 
2071     public Vector4d transform(Vector4d v) {
2072         return v.mul(this);
2073     }
2074 
2075     public Vector4d transform(Vector4d v, Vector4d dest) {
2076         return v.mul(this, dest);
2077     }
2078 
2079     public Vector3d transformPosition(ref Vector3d v) {
2080         v.set(m00 * v.x + m10 * v.y + m20 * v.z + m30,
2081               m01 * v.x + m11 * v.y + m21 * v.z + m31,
2082               m02 * v.x + m12 * v.y + m22 * v.z + m32);
2083         return v;
2084     }
2085 
2086     public Vector3d transformPosition(ref Vector3d v, ref Vector3d dest) {
2087         dest.set(m00 * v.x + m10 * v.y + m20 * v.z + m30,
2088                  m01 * v.x + m11 * v.y + m21 * v.z + m31,
2089                  m02 * v.x + m12 * v.y + m22 * v.z + m32);
2090         return dest;
2091     }
2092 
2093     public Vector3d transformDirection(ref Vector3d v) {
2094         v.set(m00 * v.x + m10 * v.y + m20 * v.z,
2095               m01 * v.x + m11 * v.y + m21 * v.z,
2096               m02 * v.x + m12 * v.y + m22 * v.z);
2097         return v;
2098     }
2099 
2100     public Vector3d transformDirection(ref Vector3d v, ref Vector3d dest) {
2101         dest.set(m00 * v.x + m10 * v.y + m20 * v.z,
2102                  m01 * v.x + m11 * v.y + m21 * v.z,
2103                  m02 * v.x + m12 * v.y + m22 * v.z);
2104         return dest;
2105     }
2106 
2107     /**
2108      * Set the left 3x3 submatrix of this {@link Matrix4x3d} to the given {@link Matrix3d} and don't change the other elements.
2109      * 
2110      * @param mat
2111      *          the 3x3 matrix
2112      * @return this
2113      */
2114     ref public Matrix4x3d set3x3(Matrix3d mat) return {
2115         m00 = mat.m00;
2116         m01 = mat.m01;
2117         m02 = mat.m02;
2118         m10 = mat.m10;
2119         m11 = mat.m11;
2120         m12 = mat.m12;
2121         m20 = mat.m20;
2122         m21 = mat.m21;
2123         m22 = mat.m22;
2124         properties = 0;
2125         return this;
2126     }
2127 
2128 
2129     public Matrix4x3d scale(Vector3d xyz, ref Matrix4x3d dest) {
2130         return scale(xyz.x, xyz.y, xyz.z, dest);
2131     }
2132 
2133     /**
2134      * Apply scaling to this matrix by scaling the base axes by the given <code>xyz.x</code>,
2135      * <code>xyz.y</code> and <code>xyz.z</code> factors, respectively.
2136      * <p>
2137      * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix,
2138      * then the new matrix will be <code>M * S</code>. So when transforming a
2139      * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the
2140      * scaling will be applied first!
2141      * 
2142      * @param xyz
2143      *            the factors of the x, y and z component, respectively
2144      * @return this
2145      */
2146     ref public Matrix4x3d scale(Vector3d xyz) return {
2147         scale(xyz.x, xyz.y, xyz.z, this);
2148         return this;
2149     }
2150 
2151     public Matrix4x3d scale(double x, double y, double z, ref Matrix4x3d dest) {
2152         if ((properties & PROPERTY_IDENTITY) != 0)
2153             return dest.scaling(x, y, z);
2154         return scaleGeneric(x, y, z, dest);
2155     }
2156     private Matrix4x3d scaleGeneric(double x, double y, double z, ref Matrix4x3d dest) {
2157         dest.m00 = m00 * x;
2158         dest.m01 = m01 * x;
2159         dest.m02 = m02 * x;
2160         dest.m10 = m10 * y;
2161         dest.m11 = m11 * y;
2162         dest.m12 = m12 * y;
2163         dest.m20 = m20 * z;
2164         dest.m21 = m21 * z;
2165         dest.m22 = m22 * z;
2166         dest.m30 = m30;
2167         dest.m31 = m31;
2168         dest.m32 = m32;
2169         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
2170         return dest;
2171     }
2172 
2173     /**
2174      * Apply scaling to <code>this</code> matrix by scaling the base axes by the given x,
2175      * y and z factors.
2176      * <p>
2177      * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix,
2178      * then the new matrix will be <code>M * S</code>. So when transforming a
2179      * vector <code>v</code> with the new matrix by using <code>M * S * v</code>
2180      * , the scaling will be applied first!
2181      * 
2182      * @param x
2183      *            the factor of the x component
2184      * @param y
2185      *            the factor of the y component
2186      * @param z
2187      *            the factor of the z component
2188      * @return this
2189      */
2190     ref public Matrix4x3d scale(double x, double y, double z) return {
2191         scale(x, y, z, this);
2192         return this;
2193     }
2194 
2195     public Matrix4x3d scale(double xyz, ref Matrix4x3d dest) {
2196         return scale(xyz, xyz, xyz, dest);
2197     }
2198 
2199     /**
2200      * Apply scaling to this matrix by uniformly scaling all base axes by the given xyz factor.
2201      * <p>
2202      * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix,
2203      * then the new matrix will be <code>M * S</code>. So when transforming a
2204      * vector <code>v</code> with the new matrix by using <code>M * S * v</code>
2205      * , the scaling will be applied first!
2206      * 
2207      * @see #scale(double, double, double)
2208      * 
2209      * @param xyz
2210      *            the factor for all components
2211      * @return this
2212      */
2213     ref public Matrix4x3d scale(double xyz) return {
2214         return scale(xyz, xyz, xyz);
2215     }
2216 
2217     public Matrix4x3d scaleXY(double x, double y, ref Matrix4x3d dest) {
2218         return scale(x, y, 1.0, dest);
2219     }
2220 
2221     /**
2222      * Apply scaling to this matrix by scaling the X axis by <code>x</code> and the Y axis by <code>y</code>.
2223      * <p>
2224      * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix,
2225      * then the new matrix will be <code>M * S</code>. So when transforming a
2226      * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the
2227      * scaling will be applied first!
2228      * 
2229      * @param x
2230      *            the factor of the x component
2231      * @param y
2232      *            the factor of the y component
2233      * @return this
2234      */
2235     ref public Matrix4x3d scaleXY(double x, double y) return {
2236         return scale(x, y, 1.0);
2237     }
2238 
2239     public Matrix4x3d scaleAround(double sx, double sy, double sz, double ox, double oy, double oz, ref Matrix4x3d dest) {
2240         double nm30 = m00 * ox + m10 * oy + m20 * oz + m30;
2241         double nm31 = m01 * ox + m11 * oy + m21 * oz + m31;
2242         double nm32 = m02 * ox + m12 * oy + m22 * oz + m32;
2243         bool one = Math.absEqualsOne(sx) && Math.absEqualsOne(sy) && Math.absEqualsOne(sz);
2244         return dest
2245         ._m00(m00 * sx)
2246         ._m01(m01 * sx)
2247         ._m02(m02 * sx)
2248         ._m10(m10 * sy)
2249         ._m11(m11 * sy)
2250         ._m12(m12 * sy)
2251         ._m20(m20 * sz)
2252         ._m21(m21 * sz)
2253         ._m22(m22 * sz)
2254         ._m30(-dest.m00 * ox - dest.m10 * oy - dest.m20 * oz + nm30)
2255         ._m31(-dest.m01 * ox - dest.m11 * oy - dest.m21 * oz + nm31)
2256         ._m32(-dest.m02 * ox - dest.m12 * oy - dest.m22 * oz + nm32)
2257         ._properties(properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | (one ? 0 : PROPERTY_ORTHONORMAL)));
2258     }
2259 
2260     /**
2261      * Apply scaling to this matrix by scaling the base axes by the given sx,
2262      * sy and sz factors while using <code>(ox, oy, oz)</code> as the scaling origin.
2263      * <p>
2264      * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix,
2265      * then the new matrix will be <code>M * S</code>. So when transforming a
2266      * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the
2267      * scaling will be applied first!
2268      * <p>
2269      * This method is equivalent to calling: <code>translate(ox, oy, oz).scale(sx, sy, sz).translate(-ox, -oy, -oz)</code>
2270      * 
2271      * @param sx
2272      *            the scaling factor of the x component
2273      * @param sy
2274      *            the scaling factor of the y component
2275      * @param sz
2276      *            the scaling factor of the z component
2277      * @param ox
2278      *            the x coordinate of the scaling origin
2279      * @param oy
2280      *            the y coordinate of the scaling origin
2281      * @param oz
2282      *            the z coordinate of the scaling origin
2283      * @return this
2284      */
2285     ref public Matrix4x3d scaleAround(double sx, double sy, double sz, double ox, double oy, double oz) return {
2286         scaleAround(sx, sy, sz, ox, oy, oz, this);
2287         return this;
2288     }
2289 
2290     /**
2291      * Apply scaling to this matrix by scaling all three base axes by the given <code>factor</code>
2292      * while using <code>(ox, oy, oz)</code> as the scaling origin.
2293      * <p>
2294      * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix,
2295      * then the new matrix will be <code>M * S</code>. So when transforming a
2296      * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the
2297      * scaling will be applied first!
2298      * <p>
2299      * This method is equivalent to calling: <code>translate(ox, oy, oz).scale(factor).translate(-ox, -oy, -oz)</code>
2300      * 
2301      * @param factor
2302      *            the scaling factor for all three axes
2303      * @param ox
2304      *            the x coordinate of the scaling origin
2305      * @param oy
2306      *            the y coordinate of the scaling origin
2307      * @param oz
2308      *            the z coordinate of the scaling origin
2309      * @return this
2310      */
2311     ref public Matrix4x3d scaleAround(double factor, double ox, double oy, double oz) return {
2312         scaleAround(factor, factor, factor, ox, oy, oz, this);
2313         return this;
2314     }
2315 
2316     public Matrix4x3d scaleAround(double factor, double ox, double oy, double oz, ref Matrix4x3d dest) {
2317         return scaleAround(factor, factor, factor, ox, oy, oz, dest);
2318     }
2319 
2320     public Matrix4x3d scaleLocal(double x, double y, double z, ref Matrix4x3d dest) {
2321         if ((properties & PROPERTY_IDENTITY) != 0)
2322             return dest.scaling(x, y, z);
2323 
2324         double nm00 = x * m00;
2325         double nm01 = y * m01;
2326         double nm02 = z * m02;
2327         double nm10 = x * m10;
2328         double nm11 = y * m11;
2329         double nm12 = z * m12;
2330         double nm20 = x * m20;
2331         double nm21 = y * m21;
2332         double nm22 = z * m22;
2333         double nm30 = x * m30;
2334         double nm31 = y * m31;
2335         double nm32 = z * m32;
2336         dest.m00 = nm00;
2337         dest.m01 = nm01;
2338         dest.m02 = nm02;
2339         dest.m10 = nm10;
2340         dest.m11 = nm11;
2341         dest.m12 = nm12;
2342         dest.m20 = nm20;
2343         dest.m21 = nm21;
2344         dest.m22 = nm22;
2345         dest.m30 = nm30;
2346         dest.m31 = nm31;
2347         dest.m32 = nm32;
2348         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
2349         return dest;
2350     }
2351 
2352     /**
2353      * Pre-multiply scaling to this matrix by scaling the base axes by the given x,
2354      * y and z factors.
2355      * <p>
2356      * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix,
2357      * then the new matrix will be <code>S * M</code>. So when transforming a
2358      * vector <code>v</code> with the new matrix by using <code>S * M * v</code>, the
2359      * scaling will be applied last!
2360      * 
2361      * @param x
2362      *            the factor of the x component
2363      * @param y
2364      *            the factor of the y component
2365      * @param z
2366      *            the factor of the z component
2367      * @return this
2368      */
2369     ref public Matrix4x3d scaleLocal(double x, double y, double z) return {
2370         scaleLocal(x, y, z, this);
2371         return this;
2372     }
2373 
2374     public Matrix4x3d rotate(double ang, double x, double y, double z, ref Matrix4x3d dest) {
2375         if ((properties & PROPERTY_IDENTITY) != 0)
2376             return dest.rotation(ang, x, y, z);
2377         else if ((properties & PROPERTY_TRANSLATION) != 0)
2378             return rotateTranslation(ang, x, y, z, dest);
2379         return rotateGeneric(ang, x, y, z, dest);
2380     }
2381     private Matrix4x3d rotateGeneric(double ang, double x, double y, double z, ref Matrix4x3d dest) {
2382         if (y == 0.0 && z == 0.0 && Math.absEqualsOne(x))
2383             return rotateX(x * ang, dest);
2384         else if (x == 0.0 && z == 0.0 && Math.absEqualsOne(y))
2385             return rotateY(y * ang, dest);
2386         else if (x == 0.0 && y == 0.0 && Math.absEqualsOne(z))
2387             return rotateZ(z * ang, dest);
2388         return rotateGenericInternal(ang, x, y, z, dest);
2389     }
2390     private Matrix4x3d rotateGenericInternal(double ang, double x, double y, double z, ref Matrix4x3d dest) {
2391         double s = Math.sin(ang);
2392         double c = Math.cosFromSin(s, ang);
2393         double C = 1.0 - c;
2394         double xx = x * x, xy = x * y, xz = x * z;
2395         double yy = y * y, yz = y * z;
2396         double zz = z * z;
2397         double rm00 = xx * C + c;
2398         double rm01 = xy * C + z * s;
2399         double rm02 = xz * C - y * s;
2400         double rm10 = xy * C - z * s;
2401         double rm11 = yy * C + c;
2402         double rm12 = yz * C + x * s;
2403         double rm20 = xz * C + y * s;
2404         double rm21 = yz * C - x * s;
2405         double rm22 = zz * C + c;
2406         // add temporaries for dependent values
2407         double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
2408         double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
2409         double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
2410         double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
2411         double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
2412         double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
2413         // set non-dependent values directly
2414         dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
2415         dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
2416         dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
2417         // set other values
2418         dest.m00 = nm00;
2419         dest.m01 = nm01;
2420         dest.m02 = nm02;
2421         dest.m10 = nm10;
2422         dest.m11 = nm11;
2423         dest.m12 = nm12;
2424         dest.m30 = m30;
2425         dest.m31 = m31;
2426         dest.m32 = m32;
2427         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
2428         return dest;
2429     }
2430 
2431     /**
2432      * Apply rotation to this matrix by rotating the given amount of radians
2433      * about the given axis specified as x, y and z components.
2434      * <p>
2435      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2436      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2437      * When used with a left-handed coordinate system, the rotation is clockwise.
2438      * <p>
2439      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
2440      * then the new matrix will be <code>M * R</code>. So when transforming a
2441      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>
2442      * , the rotation will be applied first!
2443      * <p>
2444      * In order to set the matrix to a rotation matrix without post-multiplying the rotation
2445      * transformation, use {@link #rotation(double, double, double, double) rotation()}.
2446      * 
2447      * @see #rotation(double, double, double, double)
2448      *  
2449      * @param ang
2450      *            the angle is in radians
2451      * @param x
2452      *            the x component of the axis
2453      * @param y
2454      *            the y component of the axis
2455      * @param z
2456      *            the z component of the axis
2457      * @return this
2458      */
2459     ref public Matrix4x3d rotate(double ang, double x, double y, double z) return {
2460         rotate(ang, x, y, z, this);
2461         return this;
2462     }
2463 
2464     /**
2465      * Apply rotation to this matrix, which is assumed to only contain a translation, by rotating the given amount of radians
2466      * about the specified <code>(x, y, z)</code> axis and store the result in <code>dest</code>.
2467      * <p>
2468      * This method assumes <code>this</code> to only contain a translation.
2469      * <p>
2470      * The axis described by the three components needs to be a unit vector.
2471      * <p>
2472      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2473      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2474      * When used with a left-handed coordinate system, the rotation is clockwise.
2475      * <p>
2476      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
2477      * then the new matrix will be <code>M * R</code>. So when transforming a
2478      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
2479      * rotation will be applied first!
2480      * <p>
2481      * In order to set the matrix to a rotation matrix without post-multiplying the rotation
2482      * transformation, use {@link #rotation(double, double, double, double) rotation()}.
2483      * <p>
2484      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a>
2485      * 
2486      * @see #rotation(double, double, double, double)
2487      * 
2488      * @param ang
2489      *            the angle in radians
2490      * @param x
2491      *            the x component of the axis
2492      * @param y
2493      *            the y component of the axis
2494      * @param z
2495      *            the z component of the axis
2496      * @param dest
2497      *            will hold the result
2498      * @return dest
2499      */
2500     public Matrix4x3d rotateTranslation(double ang, double x, double y, double z, ref Matrix4x3d dest) {
2501         double tx = m30, ty = m31, tz = m32;
2502         if (y == 0.0 && z == 0.0 && Math.absEqualsOne(x))
2503             return dest.rotationX(x * ang).setTranslation(tx, ty, tz);
2504         else if (x == 0.0 && z == 0.0 && Math.absEqualsOne(y))
2505             return dest.rotationY(y * ang).setTranslation(tx, ty, tz);
2506         else if (x == 0.0 && y == 0.0 && Math.absEqualsOne(z))
2507             return dest.rotationZ(z * ang).setTranslation(tx, ty, tz);
2508         return rotateTranslationInternal(ang, x, y, z, dest);
2509     }
2510     private Matrix4x3d rotateTranslationInternal(double ang, double x, double y, double z, ref Matrix4x3d dest) {
2511         double s = Math.sin(ang);
2512         double c = Math.cosFromSin(s, ang);
2513         double C = 1.0 - c;
2514         double xx = x * x, xy = x * y, xz = x * z;
2515         double yy = y * y, yz = y * z;
2516         double zz = z * z;
2517         double rm00 = xx * C + c;
2518         double rm01 = xy * C + z * s;
2519         double rm02 = xz * C - y * s;
2520         double rm10 = xy * C - z * s;
2521         double rm11 = yy * C + c;
2522         double rm12 = yz * C + x * s;
2523         double rm20 = xz * C + y * s;
2524         double rm21 = yz * C - x * s;
2525         double rm22 = zz * C + c;
2526         dest.m20 = rm20;
2527         dest.m21 = rm21;
2528         dest.m22 = rm22;
2529         dest.m00 = rm00;
2530         dest.m01 = rm01;
2531         dest.m02 = rm02;
2532         dest.m10 = rm10;
2533         dest.m11 = rm11;
2534         dest.m12 = rm12;
2535         dest.m30 = m30;
2536         dest.m31 = m31;
2537         dest.m32 = m32;
2538         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
2539         return dest;
2540     }
2541 
2542     /**
2543      * Apply the rotation transformation of the given {@link Quaterniond} to this matrix while using <code>(ox, oy, oz)</code> as the rotation origin.
2544      * <p>
2545      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2546      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2547      * When used with a left-handed coordinate system, the rotation is clockwise.
2548      * <p>
2549      * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion,
2550      * then the new matrix will be <code>M * Q</code>. So when transforming a
2551      * vector <code>v</code> with the new matrix by using <code>M * Q * v</code>,
2552      * the quaternion rotation will be applied first!
2553      * <p>
2554      * This method is equivalent to calling: <code>translate(ox, oy, oz).rotate(quat).translate(-ox, -oy, -oz)</code>
2555      * <p>
2556      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a>
2557      * 
2558      * @param quat
2559      *          the {@link Quaterniond}
2560      * @param ox
2561      *          the x coordinate of the rotation origin
2562      * @param oy
2563      *          the y coordinate of the rotation origin
2564      * @param oz
2565      *          the z coordinate of the rotation origin
2566      * @return this
2567      */
2568     ref public Matrix4x3d rotateAround(Quaterniond quat, double ox, double oy, double oz) return {
2569         rotateAround(quat, ox, oy, oz, this);
2570         return this;
2571     }
2572 
2573     private Matrix4x3d rotateAroundAffine(Quaterniond quat, double ox, double oy, double oz, ref Matrix4x3d dest) {
2574         double w2 = quat.w * quat.w, x2 = quat.x * quat.x;
2575         double y2 = quat.y * quat.y, z2 = quat.z * quat.z;
2576         double zw = quat.z * quat.w, dzw = zw + zw, xy = quat.x * quat.y, dxy = xy + xy;
2577         double xz = quat.x * quat.z, dxz = xz + xz, yw = quat.y * quat.w, dyw = yw + yw;
2578         double yz = quat.y * quat.z, dyz = yz + yz, xw = quat.x * quat.w, dxw = xw + xw;
2579         double rm00 = w2 + x2 - z2 - y2;
2580         double rm01 = dxy + dzw;
2581         double rm02 = dxz - dyw;
2582         double rm10 = dxy - dzw;
2583         double rm11 = y2 - z2 + w2 - x2;
2584         double rm12 = dyz + dxw;
2585         double rm20 = dyw + dxz;
2586         double rm21 = dyz - dxw;
2587         double rm22 = z2 - y2 - x2 + w2;
2588         double tm30 = m00 * ox + m10 * oy + m20 * oz + m30;
2589         double tm31 = m01 * ox + m11 * oy + m21 * oz + m31;
2590         double tm32 = m02 * ox + m12 * oy + m22 * oz + m32;
2591         double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
2592         double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
2593         double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
2594         double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
2595         double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
2596         double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
2597         dest
2598         ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22)
2599         ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22)
2600         ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22)
2601         ._m00(nm00)
2602         ._m01(nm01)
2603         ._m02(nm02)
2604         ._m10(nm10)
2605         ._m11(nm11)
2606         ._m12(nm12)
2607         ._m30(-nm00 * ox - nm10 * oy - m20 * oz + tm30)
2608         ._m31(-nm01 * ox - nm11 * oy - m21 * oz + tm31)
2609         ._m32(-nm02 * ox - nm12 * oy - m22 * oz + tm32)
2610         ._properties(properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
2611         return dest;
2612     }
2613 
2614     public Matrix4x3d rotateAround(Quaterniond quat, double ox, double oy, double oz, ref Matrix4x3d dest) {
2615         if ((properties & PROPERTY_IDENTITY) != 0)
2616             return rotationAround(quat, ox, oy, oz);
2617         return rotateAroundAffine(quat, ox, oy, oz, dest);
2618     }
2619 
2620     /**
2621      * Set this matrix to a transformation composed of a rotation of the specified {@link Quaterniond} while using <code>(ox, oy, oz)</code> as the rotation origin.
2622      * <p>
2623      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2624      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2625      * When used with a left-handed coordinate system, the rotation is clockwise.
2626      * <p>
2627      * This method is equivalent to calling: <code>translation(ox, oy, oz).rotate(quat).translate(-ox, -oy, -oz)</code>
2628      * <p>
2629      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a>
2630      * 
2631      * @param quat
2632      *          the {@link Quaterniond}
2633      * @param ox
2634      *          the x coordinate of the rotation origin
2635      * @param oy
2636      *          the y coordinate of the rotation origin
2637      * @param oz
2638      *          the z coordinate of the rotation origin
2639      * @return this
2640      */
2641     ref public Matrix4x3d rotationAround(Quaterniond quat, double ox, double oy, double oz) return {
2642         double w2 = quat.w * quat.w, x2 = quat.x * quat.x;
2643         double y2 = quat.y * quat.y, z2 = quat.z * quat.z;
2644         double zw = quat.z * quat.w, dzw = zw + zw, xy = quat.x * quat.y, dxy = xy + xy;
2645         double xz = quat.x * quat.z, dxz = xz + xz, yw = quat.y * quat.w, dyw = yw + yw;
2646         double yz = quat.y * quat.z, dyz = yz + yz, xw = quat.x * quat.w, dxw = xw + xw;
2647         this._m20(dyw + dxz);
2648         this._m21(dyz - dxw);
2649         this._m22(z2 - y2 - x2 + w2);
2650         this._m00(w2 + x2 - z2 - y2);
2651         this._m01(dxy + dzw);
2652         this._m02(dxz - dyw);
2653         this._m10(dxy - dzw);
2654         this._m11(y2 - z2 + w2 - x2);
2655         this._m12(dyz + dxw);
2656         this._m30(-m00 * ox - m10 * oy - m20 * oz + ox);
2657         this._m31(-m01 * ox - m11 * oy - m21 * oz + oy);
2658         this._m32(-m02 * ox - m12 * oy - m22 * oz + oz);
2659         this.properties = PROPERTY_ORTHONORMAL;
2660         return this;
2661     }
2662 
2663     /**
2664      * Pre-multiply a rotation to this matrix by rotating the given amount of radians
2665      * about the specified <code>(x, y, z)</code> axis and store the result in <code>dest</code>.
2666      * <p>
2667      * The axis described by the three components needs to be a unit vector.
2668      * <p>
2669      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2670      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2671      * When used with a left-handed coordinate system, the rotation is clockwise.
2672      * <p>
2673      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
2674      * then the new matrix will be <code>R * M</code>. So when transforming a
2675      * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the
2676      * rotation will be applied last!
2677      * <p>
2678      * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
2679      * transformation, use {@link #rotation(double, double, double, double) rotation()}.
2680      * <p>
2681      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a>
2682      * 
2683      * @see #rotation(double, double, double, double)
2684      * 
2685      * @param ang
2686      *            the angle in radians
2687      * @param x
2688      *            the x component of the axis
2689      * @param y
2690      *            the y component of the axis
2691      * @param z
2692      *            the z component of the axis
2693      * @param dest
2694      *            will hold the result
2695      * @return dest
2696      */
2697     public Matrix4x3d rotateLocal(double ang, double x, double y, double z, ref Matrix4x3d dest) {
2698         if (y == 0.0 && z == 0.0 && Math.absEqualsOne(x))
2699             return rotateLocalX(x * ang, dest);
2700         else if (x == 0.0 && z == 0.0 && Math.absEqualsOne(y))
2701             return rotateLocalY(y * ang, dest);
2702         else if (x == 0.0 && y == 0.0 && Math.absEqualsOne(z))
2703             return rotateLocalZ(z * ang, dest);
2704         return rotateLocalInternal(ang, x, y, z, dest);
2705     }
2706     private Matrix4x3d rotateLocalInternal(double ang, double x, double y, double z, ref Matrix4x3d dest) {
2707         double s = Math.sin(ang);
2708         double c = Math.cosFromSin(s, ang);
2709         double C = 1.0 - c;
2710         double xx = x * x, xy = x * y, xz = x * z;
2711         double yy = y * y, yz = y * z;
2712         double zz = z * z;
2713         double lm00 = xx * C + c;
2714         double lm01 = xy * C + z * s;
2715         double lm02 = xz * C - y * s;
2716         double lm10 = xy * C - z * s;
2717         double lm11 = yy * C + c;
2718         double lm12 = yz * C + x * s;
2719         double lm20 = xz * C + y * s;
2720         double lm21 = yz * C - x * s;
2721         double lm22 = zz * C + c;
2722         double nm00 = lm00 * m00 + lm10 * m01 + lm20 * m02;
2723         double nm01 = lm01 * m00 + lm11 * m01 + lm21 * m02;
2724         double nm02 = lm02 * m00 + lm12 * m01 + lm22 * m02;
2725         double nm10 = lm00 * m10 + lm10 * m11 + lm20 * m12;
2726         double nm11 = lm01 * m10 + lm11 * m11 + lm21 * m12;
2727         double nm12 = lm02 * m10 + lm12 * m11 + lm22 * m12;
2728         double nm20 = lm00 * m20 + lm10 * m21 + lm20 * m22;
2729         double nm21 = lm01 * m20 + lm11 * m21 + lm21 * m22;
2730         double nm22 = lm02 * m20 + lm12 * m21 + lm22 * m22;
2731         double nm30 = lm00 * m30 + lm10 * m31 + lm20 * m32;
2732         double nm31 = lm01 * m30 + lm11 * m31 + lm21 * m32;
2733         double nm32 = lm02 * m30 + lm12 * m31 + lm22 * m32;
2734         dest.m00 = nm00;
2735         dest.m01 = nm01;
2736         dest.m02 = nm02;
2737         dest.m10 = nm10;
2738         dest.m11 = nm11;
2739         dest.m12 = nm12;
2740         dest.m20 = nm20;
2741         dest.m21 = nm21;
2742         dest.m22 = nm22;
2743         dest.m30 = nm30;
2744         dest.m31 = nm31;
2745         dest.m32 = nm32;
2746         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
2747         return dest;
2748     }
2749 
2750     /**
2751      * Pre-multiply a rotation to this matrix by rotating the given amount of radians
2752      * about the specified <code>(x, y, z)</code> axis.
2753      * <p>
2754      * The axis described by the three components needs to be a unit vector.
2755      * <p>
2756      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2757      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2758      * When used with a left-handed coordinate system, the rotation is clockwise.
2759      * <p>
2760      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
2761      * then the new matrix will be <code>R * M</code>. So when transforming a
2762      * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the
2763      * rotation will be applied last!
2764      * <p>
2765      * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
2766      * transformation, use {@link #rotation(double, double, double, double) rotation()}.
2767      * <p>
2768      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a>
2769      * 
2770      * @see #rotation(double, double, double, double)
2771      * 
2772      * @param ang
2773      *            the angle in radians
2774      * @param x
2775      *            the x component of the axis
2776      * @param y
2777      *            the y component of the axis
2778      * @param z
2779      *            the z component of the axis
2780      * @return this
2781      */
2782     ref public Matrix4x3d rotateLocal(double ang, double x, double y, double z) return {
2783         rotateLocal(ang, x, y, z, this);
2784         return this;
2785     }
2786 
2787     /**
2788      * Pre-multiply a rotation around the X axis to this matrix by rotating the given amount of radians
2789      * about the X axis and store the result in <code>dest</code>.
2790      * <p>
2791      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2792      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2793      * When used with a left-handed coordinate system, the rotation is clockwise.
2794      * <p>
2795      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
2796      * then the new matrix will be <code>R * M</code>. So when transforming a
2797      * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the
2798      * rotation will be applied last!
2799      * <p>
2800      * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
2801      * transformation, use {@link #rotationX(double) rotationX()}.
2802      * <p>
2803      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a>
2804      * 
2805      * @see #rotationX(double)
2806      * 
2807      * @param ang
2808      *            the angle in radians to rotate about the X axis
2809      * @param dest
2810      *            will hold the result
2811      * @return dest
2812      */
2813     public Matrix4x3d rotateLocalX(double ang, ref Matrix4x3d dest) {
2814         double sin = Math.sin(ang);
2815         double cos = Math.cosFromSin(sin, ang);
2816         double nm01 = cos * m01 - sin * m02;
2817         double nm02 = sin * m01 + cos * m02;
2818         double nm11 = cos * m11 - sin * m12;
2819         double nm12 = sin * m11 + cos * m12;
2820         double nm21 = cos * m21 - sin * m22;
2821         double nm22 = sin * m21 + cos * m22;
2822         double nm31 = cos * m31 - sin * m32;
2823         double nm32 = sin * m31 + cos * m32;
2824         dest.m00 = m00;
2825         dest.m01 = nm01;
2826         dest.m02 = nm02;
2827         dest.m10 = m10;
2828         dest.m11 = nm11;
2829         dest.m12 = nm12;
2830         dest.m20 = m20;
2831         dest.m21 = nm21;
2832         dest.m22 = nm22;
2833         dest.m30 = m30;
2834         dest.m31 = nm31;
2835         dest.m32 = nm32;
2836         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
2837         return dest;
2838     }
2839 
2840     /**
2841      * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the X axis.
2842      * <p>
2843      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2844      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2845      * When used with a left-handed coordinate system, the rotation is clockwise.
2846      * <p>
2847      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
2848      * then the new matrix will be <code>R * M</code>. So when transforming a
2849      * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the
2850      * rotation will be applied last!
2851      * <p>
2852      * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
2853      * transformation, use {@link #rotationX(double) rotationX()}.
2854      * <p>
2855      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a>
2856      * 
2857      * @see #rotationX(double)
2858      * 
2859      * @param ang
2860      *            the angle in radians to rotate about the X axis
2861      * @return this
2862      */
2863     ref public Matrix4x3d rotateLocalX(double ang) return {
2864         rotateLocalX(ang, this);
2865         return this;
2866     }
2867 
2868     /**
2869      * Pre-multiply a rotation around the Y axis to this matrix by rotating the given amount of radians
2870      * about the Y axis and store the result in <code>dest</code>.
2871      * <p>
2872      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2873      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2874      * When used with a left-handed coordinate system, the rotation is clockwise.
2875      * <p>
2876      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
2877      * then the new matrix will be <code>R * M</code>. So when transforming a
2878      * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the
2879      * rotation will be applied last!
2880      * <p>
2881      * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
2882      * transformation, use {@link #rotationY(double) rotationY()}.
2883      * <p>
2884      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a>
2885      * 
2886      * @see #rotationY(double)
2887      * 
2888      * @param ang
2889      *            the angle in radians to rotate about the Y axis
2890      * @param dest
2891      *            will hold the result
2892      * @return dest
2893      */
2894     public Matrix4x3d rotateLocalY(double ang, ref Matrix4x3d dest) {
2895         double sin = Math.sin(ang);
2896         double cos = Math.cosFromSin(sin, ang);
2897         double nm00 =  cos * m00 + sin * m02;
2898         double nm02 = -sin * m00 + cos * m02;
2899         double nm10 =  cos * m10 + sin * m12;
2900         double nm12 = -sin * m10 + cos * m12;
2901         double nm20 =  cos * m20 + sin * m22;
2902         double nm22 = -sin * m20 + cos * m22;
2903         double nm30 =  cos * m30 + sin * m32;
2904         double nm32 = -sin * m30 + cos * m32;
2905         dest.m00 = nm00;
2906         dest.m01 = m01;
2907         dest.m02 = nm02;
2908         dest.m10 = nm10;
2909         dest.m11 = m11;
2910         dest.m12 = nm12;
2911         dest.m20 = nm20;
2912         dest.m21 = m21;
2913         dest.m22 = nm22;
2914         dest.m30 = nm30;
2915         dest.m31 = m31;
2916         dest.m32 = nm32;
2917         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
2918         return dest;
2919     }
2920 
2921     /**
2922      * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the Y axis.
2923      * <p>
2924      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2925      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2926      * When used with a left-handed coordinate system, the rotation is clockwise.
2927      * <p>
2928      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
2929      * then the new matrix will be <code>R * M</code>. So when transforming a
2930      * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the
2931      * rotation will be applied last!
2932      * <p>
2933      * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
2934      * transformation, use {@link #rotationY(double) rotationY()}.
2935      * <p>
2936      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a>
2937      * 
2938      * @see #rotationY(double)
2939      * 
2940      * @param ang
2941      *            the angle in radians to rotate about the Y axis
2942      * @return this
2943      */
2944     ref public Matrix4x3d rotateLocalY(double ang) return {
2945         rotateLocalY(ang, this);
2946         return this;
2947     }
2948 
2949     /**
2950      * Pre-multiply a rotation around the Z axis to this matrix by rotating the given amount of radians
2951      * about the Z axis and store the result in <code>dest</code>.
2952      * <p>
2953      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2954      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2955      * When used with a left-handed coordinate system, the rotation is clockwise.
2956      * <p>
2957      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
2958      * then the new matrix will be <code>R * M</code>. So when transforming a
2959      * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the
2960      * rotation will be applied last!
2961      * <p>
2962      * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
2963      * transformation, use {@link #rotationZ(double) rotationZ()}.
2964      * <p>
2965      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a>
2966      * 
2967      * @see #rotationZ(double)
2968      * 
2969      * @param ang
2970      *            the angle in radians to rotate about the Z axis
2971      * @param dest
2972      *            will hold the result
2973      * @return dest
2974      */
2975     public Matrix4x3d rotateLocalZ(double ang, ref Matrix4x3d dest) {
2976         double sin = Math.sin(ang);
2977         double cos = Math.cosFromSin(sin, ang);
2978         double nm00 = cos * m00 - sin * m01;
2979         double nm01 = sin * m00 + cos * m01;
2980         double nm10 = cos * m10 - sin * m11;
2981         double nm11 = sin * m10 + cos * m11;
2982         double nm20 = cos * m20 - sin * m21;
2983         double nm21 = sin * m20 + cos * m21;
2984         double nm30 = cos * m30 - sin * m31;
2985         double nm31 = sin * m30 + cos * m31;
2986         dest.m00 = nm00;
2987         dest.m01 = nm01;
2988         dest.m02 = m02;
2989         dest.m10 = nm10;
2990         dest.m11 = nm11;
2991         dest.m12 = m12;
2992         dest.m20 = nm20;
2993         dest.m21 = nm21;
2994         dest.m22 = m22;
2995         dest.m30 = nm30;
2996         dest.m31 = nm31;
2997         dest.m32 = m32;
2998         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
2999         return dest;
3000     }
3001 
3002     /**
3003      * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the Z axis.
3004      * <p>
3005      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
3006      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
3007      * When used with a left-handed coordinate system, the rotation is clockwise.
3008      * <p>
3009      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
3010      * then the new matrix will be <code>R * M</code>. So when transforming a
3011      * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the
3012      * rotation will be applied last!
3013      * <p>
3014      * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
3015      * transformation, use {@link #rotationZ(double) rotationY()}.
3016      * <p>
3017      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a>
3018      * 
3019      * @see #rotationY(double)
3020      * 
3021      * @param ang
3022      *            the angle in radians to rotate about the Z axis
3023      * @return this
3024      */
3025     ref public Matrix4x3d rotateLocalZ(double ang) return {
3026         rotateLocalZ(ang, this);
3027         return this;
3028     }
3029 
3030     /**
3031      * Apply a translation to this matrix by translating by the given number of
3032      * units in x, y and z.
3033      * <p>
3034      * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation
3035      * matrix, then the new matrix will be <code>M * T</code>. So when
3036      * transforming a vector <code>v</code> with the new matrix by using
3037      * <code>M * T * v</code>, the translation will be applied first!
3038      * <p>
3039      * In order to set the matrix to a translation transformation without post-multiplying
3040      * it, use {@link #translation(Vector3d)}.
3041      * 
3042      * @see #translation(Vector3d)
3043      * 
3044      * @param offset
3045      *          the number of units in x, y and z by which to translate
3046      * @return this
3047      */
3048     ref public Matrix4x3d translate(Vector3d offset) return {
3049         return translate(offset.x, offset.y, offset.z);
3050     }
3051 
3052     /**
3053      * Apply a translation to this matrix by translating by the given number of
3054      * units in x, y and z and store the result in <code>dest</code>.
3055      * <p>
3056      * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation
3057      * matrix, then the new matrix will be <code>M * T</code>. So when
3058      * transforming a vector <code>v</code> with the new matrix by using
3059      * <code>M * T * v</code>, the translation will be applied first!
3060      * <p>
3061      * In order to set the matrix to a translation transformation without post-multiplying
3062      * it, use {@link #translation(Vector3d)}.
3063      * 
3064      * @see #translation(Vector3d)
3065      * 
3066      * @param offset
3067      *          the number of units in x, y and z by which to translate
3068      * @param dest
3069      *          will hold the result
3070      * @return dest
3071      */
3072     public Matrix4x3d translate(Vector3d offset, ref Matrix4x3d dest) {
3073         return translate(offset.x, offset.y, offset.z, dest);
3074     }
3075 
3076     /**
3077      * Apply a translation to this matrix by translating by the given number of
3078      * units in x, y and z and store the result in <code>dest</code>.
3079      * <p>
3080      * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation
3081      * matrix, then the new matrix will be <code>M * T</code>. So when
3082      * transforming a vector <code>v</code> with the new matrix by using
3083      * <code>M * T * v</code>, the translation will be applied first!
3084      * <p>
3085      * In order to set the matrix to a translation transformation without post-multiplying
3086      * it, use {@link #translation(double, double, double)}.
3087      * 
3088      * @see #translation(double, double, double)
3089      * 
3090      * @param x
3091      *          the offset to translate in x
3092      * @param y
3093      *          the offset to translate in y
3094      * @param z
3095      *          the offset to translate in z
3096      * @param dest
3097      *          will hold the result
3098      * @return dest
3099      */
3100     public Matrix4x3d translate(double x, double y, double z, ref Matrix4x3d dest) {
3101         if ((properties & PROPERTY_IDENTITY) != 0)
3102             return dest.translation(x, y, z);
3103         return translateGeneric(x, y, z, dest);
3104     }
3105     private Matrix4x3d translateGeneric(double x, double y, double z, ref Matrix4x3d dest) {
3106         dest.m00 = m00;
3107         dest.m01 = m01;
3108         dest.m02 = m02;
3109         dest.m10 = m10;
3110         dest.m11 = m11;
3111         dest.m12 = m12;
3112         dest.m20 = m20;
3113         dest.m21 = m21;
3114         dest.m22 = m22;
3115         dest.m30 = m00 * x + m10 * y + m20 * z + m30;
3116         dest.m31 = m01 * x + m11 * y + m21 * z + m31;
3117         dest.m32 = m02 * x + m12 * y + m22 * z + m32;
3118         dest.properties = properties & ~(PROPERTY_IDENTITY);
3119         return dest;
3120     }
3121 
3122     /**
3123      * Apply a translation to this matrix by translating by the given number of
3124      * units in x, y and z.
3125      * <p>
3126      * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation
3127      * matrix, then the new matrix will be <code>M * T</code>. So when
3128      * transforming a vector <code>v</code> with the new matrix by using
3129      * <code>M * T * v</code>, the translation will be applied first!
3130      * <p>
3131      * In order to set the matrix to a translation transformation without post-multiplying
3132      * it, use {@link #translation(double, double, double)}.
3133      * 
3134      * @see #translation(double, double, double)
3135      * 
3136      * @param x
3137      *          the offset to translate in x
3138      * @param y
3139      *          the offset to translate in y
3140      * @param z
3141      *          the offset to translate in z
3142      * @return this
3143      */
3144     ref public Matrix4x3d translate(double x, double y, double z) return {
3145         if ((properties & PROPERTY_IDENTITY) != 0)
3146             return translation(x, y, z);
3147         Matrix4x3d c = this;
3148         c.m30 = c.m00 * x + c.m10 * y + c.m20 * z + c.m30;
3149         c.m31 = c.m01 * x + c.m11 * y + c.m21 * z + c.m31;
3150         c.m32 = c.m02 * x + c.m12 * y + c.m22 * z + c.m32;
3151         c.properties &= ~(PROPERTY_IDENTITY);
3152         return this;
3153     }
3154 
3155 
3156     /**
3157      * Pre-multiply a translation to this matrix by translating by the given number of
3158      * units in x, y and z.
3159      * <p>
3160      * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation
3161      * matrix, then the new matrix will be <code>T * M</code>. So when
3162      * transforming a vector <code>v</code> with the new matrix by using
3163      * <code>T * M * v</code>, the translation will be applied last!
3164      * <p>
3165      * In order to set the matrix to a translation transformation without pre-multiplying
3166      * it, use {@link #translation(Vector3d)}.
3167      * 
3168      * @see #translation(Vector3d)
3169      * 
3170      * @param offset
3171      *          the number of units in x, y and z by which to translate
3172      * @return this
3173      */
3174     ref public Matrix4x3d translateLocal(Vector3d offset) return {
3175         return translateLocal(offset.x, offset.y, offset.z);
3176     }
3177 
3178     /**
3179      * Pre-multiply a translation to this matrix by translating by the given number of
3180      * units in x, y and z and store the result in <code>dest</code>.
3181      * <p>
3182      * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation
3183      * matrix, then the new matrix will be <code>T * M</code>. So when
3184      * transforming a vector <code>v</code> with the new matrix by using
3185      * <code>T * M * v</code>, the translation will be applied last!
3186      * <p>
3187      * In order to set the matrix to a translation transformation without pre-multiplying
3188      * it, use {@link #translation(Vector3d)}.
3189      * 
3190      * @see #translation(Vector3d)
3191      * 
3192      * @param offset
3193      *          the number of units in x, y and z by which to translate
3194      * @param dest
3195      *          will hold the result
3196      * @return dest
3197      */
3198     public Matrix4x3d translateLocal(Vector3d offset, ref Matrix4x3d dest) {
3199         return translateLocal(offset.x, offset.y, offset.z, dest);
3200     }
3201 
3202     /**
3203      * Pre-multiply a translation to this matrix by translating by the given number of
3204      * units in x, y and z and store the result in <code>dest</code>.
3205      * <p>
3206      * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation
3207      * matrix, then the new matrix will be <code>T * M</code>. So when
3208      * transforming a vector <code>v</code> with the new matrix by using
3209      * <code>T * M * v</code>, the translation will be applied last!
3210      * <p>
3211      * In order to set the matrix to a translation transformation without pre-multiplying
3212      * it, use {@link #translation(double, double, double)}.
3213      * 
3214      * @see #translation(double, double, double)
3215      * 
3216      * @param x
3217      *          the offset to translate in x
3218      * @param y
3219      *          the offset to translate in y
3220      * @param z
3221      *          the offset to translate in z
3222      * @param dest
3223      *          will hold the result
3224      * @return dest
3225      */
3226     public Matrix4x3d translateLocal(double x, double y, double z, ref Matrix4x3d dest) {
3227         dest.m00 = m00;
3228         dest.m01 = m01;
3229         dest.m02 = m02;
3230         dest.m10 = m10;
3231         dest.m11 = m11;
3232         dest.m12 = m12;
3233         dest.m20 = m20;
3234         dest.m21 = m21;
3235         dest.m22 = m22;
3236         dest.m30 = m30 + x;
3237         dest.m31 = m31 + y;
3238         dest.m32 = m32 + z;
3239         dest.properties = properties & ~(PROPERTY_IDENTITY);
3240         return dest;
3241     }
3242 
3243     /**
3244      * Pre-multiply a translation to this matrix by translating by the given number of
3245      * units in x, y and z.
3246      * <p>
3247      * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation
3248      * matrix, then the new matrix will be <code>T * M</code>. So when
3249      * transforming a vector <code>v</code> with the new matrix by using
3250      * <code>T * M * v</code>, the translation will be applied last!
3251      * <p>
3252      * In order to set the matrix to a translation transformation without pre-multiplying
3253      * it, use {@link #translation(double, double, double)}.
3254      * 
3255      * @see #translation(double, double, double)
3256      * 
3257      * @param x
3258      *          the offset to translate in x
3259      * @param y
3260      *          the offset to translate in y
3261      * @param z
3262      *          the offset to translate in z
3263      * @return this
3264      */
3265     ref public Matrix4x3d translateLocal(double x, double y, double z) return {
3266         translateLocal(x, y, z, this);
3267         return this;
3268     }
3269 
3270     public Matrix4x3d rotateX(double ang, ref Matrix4x3d dest) {
3271         if ((properties & PROPERTY_IDENTITY) != 0)
3272             return dest.rotationX(ang);
3273         else if ((properties & PROPERTY_TRANSLATION) != 0) {
3274             double x = m30, y = m31, z = m32;
3275             return dest.rotationX(ang).setTranslation(x, y, z);
3276         }
3277         return rotateXInternal(ang, dest);
3278     }
3279     private Matrix4x3d rotateXInternal(double ang, ref Matrix4x3d dest) {
3280         double sin, cos;
3281         sin = Math.sin(ang);
3282         cos = Math.cosFromSin(sin, ang);
3283         double rm11 = cos;
3284         double rm12 = sin;
3285         double rm21 = -sin;
3286         double rm22 = cos;
3287 
3288         // add temporaries for dependent values
3289         double nm10 = m10 * rm11 + m20 * rm12;
3290         double nm11 = m11 * rm11 + m21 * rm12;
3291         double nm12 = m12 * rm11 + m22 * rm12;
3292         // set non-dependent values directly
3293         dest.m20 = m10 * rm21 + m20 * rm22;
3294         dest.m21 = m11 * rm21 + m21 * rm22;
3295         dest.m22 = m12 * rm21 + m22 * rm22;
3296         // set other values
3297         dest.m10 = nm10;
3298         dest.m11 = nm11;
3299         dest.m12 = nm12;
3300         dest.m00 = m00;
3301         dest.m01 = m01;
3302         dest.m02 = m02;
3303         dest.m30 = m30;
3304         dest.m31 = m31;
3305         dest.m32 = m32;
3306         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
3307         return dest;
3308     }
3309 
3310     /**
3311      * Apply rotation about the X axis to this matrix by rotating the given amount of radians.
3312      * <p>
3313      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
3314      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
3315      * When used with a left-handed coordinate system, the rotation is clockwise.
3316      * <p>
3317      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
3318      * then the new matrix will be <code>M * R</code>. So when transforming a
3319      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
3320      * rotation will be applied first!
3321      * <p>
3322      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">http://en.wikipedia.org</a>
3323      * 
3324      * @param ang
3325      *            the angle in radians
3326      * @return this
3327      */
3328     ref public Matrix4x3d rotateX(double ang) return {
3329         rotateX(ang, this);
3330         return this;
3331     }
3332 
3333     public Matrix4x3d rotateY(double ang, ref Matrix4x3d dest) {
3334         if ((properties & PROPERTY_IDENTITY) != 0)
3335             return dest.rotationY(ang);
3336         else if ((properties & PROPERTY_TRANSLATION) != 0) {
3337             double x = m30, y = m31, z = m32;
3338             return dest.rotationY(ang).setTranslation(x, y, z);
3339         }
3340         return rotateYInternal(ang, dest);
3341     }
3342     private Matrix4x3d rotateYInternal(double ang, ref Matrix4x3d dest) {
3343         double sin, cos;
3344         sin = Math.sin(ang);
3345         cos = Math.cosFromSin(sin, ang);
3346         double rm00 = cos;
3347         double rm02 = -sin;
3348         double rm20 = sin;
3349         double rm22 = cos;
3350 
3351         // add temporaries for dependent values
3352         double nm00 = m00 * rm00 + m20 * rm02;
3353         double nm01 = m01 * rm00 + m21 * rm02;
3354         double nm02 = m02 * rm00 + m22 * rm02;
3355         // set non-dependent values directly
3356         dest.m20 = m00 * rm20 + m20 * rm22;
3357         dest.m21 = m01 * rm20 + m21 * rm22;
3358         dest.m22 = m02 * rm20 + m22 * rm22;
3359         // set other values
3360         dest.m00 = nm00;
3361         dest.m01 = nm01;
3362         dest.m02 = nm02;
3363         dest.m10 = m10;
3364         dest.m11 = m11;
3365         dest.m12 = m12;
3366         dest.m30 = m30;
3367         dest.m31 = m31;
3368         dest.m32 = m32;
3369         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
3370         return dest;
3371     }
3372 
3373     /**
3374      * Apply rotation about the Y axis to this matrix by rotating the given amount of radians.
3375      * <p>
3376      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
3377      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
3378      * When used with a left-handed coordinate system, the rotation is clockwise.
3379      * <p>
3380      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
3381      * then the new matrix will be <code>M * R</code>. So when transforming a
3382      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
3383      * rotation will be applied first!
3384      * <p>
3385      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">http://en.wikipedia.org</a>
3386      * 
3387      * @param ang
3388      *            the angle in radians
3389      * @return this
3390      */
3391     ref public Matrix4x3d rotateY(double ang) return {
3392         rotateY(ang, this);
3393         return this;
3394     }
3395 
3396     public Matrix4x3d rotateZ(double ang, ref Matrix4x3d dest) {
3397         if ((properties & PROPERTY_IDENTITY) != 0)
3398             return dest.rotationZ(ang);
3399         else if ((properties & PROPERTY_TRANSLATION) != 0) {
3400             double x = m30, y = m31, z = m32;
3401             return dest.rotationZ(ang).setTranslation(x, y, z);
3402         }
3403         return rotateZInternal(ang, dest);
3404     }
3405     private Matrix4x3d rotateZInternal(double ang, ref Matrix4x3d dest) {
3406         double sin, cos;
3407         sin = Math.sin(ang);
3408         cos = Math.cosFromSin(sin, ang);
3409         double rm00 = cos;
3410         double rm01 = sin;
3411         double rm10 = -sin;
3412         double rm11 = cos;
3413 
3414         // add temporaries for dependent values
3415         double nm00 = m00 * rm00 + m10 * rm01;
3416         double nm01 = m01 * rm00 + m11 * rm01;
3417         double nm02 = m02 * rm00 + m12 * rm01;
3418         // set non-dependent values directly
3419         dest.m10 = m00 * rm10 + m10 * rm11;
3420         dest.m11 = m01 * rm10 + m11 * rm11;
3421         dest.m12 = m02 * rm10 + m12 * rm11;
3422         // set other values
3423         dest.m00 = nm00;
3424         dest.m01 = nm01;
3425         dest.m02 = nm02;
3426         dest.m20 = m20;
3427         dest.m21 = m21;
3428         dest.m22 = m22;
3429         dest.m30 = m30;
3430         dest.m31 = m31;
3431         dest.m32 = m32;
3432         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
3433         return dest;
3434     }
3435 
3436     /**
3437      * Apply rotation about the Z axis to this matrix by rotating the given amount of radians.
3438      * <p>
3439      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
3440      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
3441      * When used with a left-handed coordinate system, the rotation is clockwise.
3442      * <p>
3443      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
3444      * then the new matrix will be <code>M * R</code>. So when transforming a
3445      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
3446      * rotation will be applied first!
3447      * <p>
3448      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">http://en.wikipedia.org</a>
3449      * 
3450      * @param ang
3451      *            the angle in radians
3452      * @return this
3453      */
3454     ref public Matrix4x3d rotateZ(double ang) return {
3455         rotateZ(ang, this);
3456         return this;
3457     }
3458 
3459     /**
3460      * Apply rotation of <code>angles.x</code> radians about the X axis, followed by a rotation of <code>angles.y</code> radians about the Y axis and
3461      * followed by a rotation of <code>angles.z</code> radians about the Z axis.
3462      * <p>
3463      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
3464      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
3465      * When used with a left-handed coordinate system, the rotation is clockwise.
3466      * <p>
3467      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
3468      * then the new matrix will be <code>M * R</code>. So when transforming a
3469      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
3470      * rotation will be applied first!
3471      * <p>
3472      * This method is equivalent to calling: <code>rotateX(angles.x).rotateY(angles.y).rotateZ(angles.z)</code>
3473      * 
3474      * @param angles
3475      *            the Euler angles
3476      * @return this
3477      */
3478     ref public Matrix4x3d rotateXYZ(Vector3d angles) return {
3479         return rotateXYZ(angles.x, angles.y, angles.z);
3480     }
3481 
3482     /**
3483      * Apply rotation of <code>angleX</code> radians about the X axis, followed by a rotation of <code>angleY</code> radians about the Y axis and
3484      * followed by a rotation of <code>angleZ</code> radians about the Z axis.
3485      * <p>
3486      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
3487      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
3488      * When used with a left-handed coordinate system, the rotation is clockwise.
3489      * <p>
3490      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
3491      * then the new matrix will be <code>M * R</code>. So when transforming a
3492      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
3493      * rotation will be applied first!
3494      * <p>
3495      * This method is equivalent to calling: <code>rotateX(angleX).rotateY(angleY).rotateZ(angleZ)</code>
3496      * 
3497      * @param angleX
3498      *            the angle to rotate about X
3499      * @param angleY
3500      *            the angle to rotate about Y
3501      * @param angleZ
3502      *            the angle to rotate about Z
3503      * @return this
3504      */
3505     ref public Matrix4x3d rotateXYZ(double angleX, double angleY, double angleZ) return {
3506         rotateXYZ(angleX, angleY, angleZ, this);
3507         return this;
3508     }
3509 
3510     public Matrix4x3d rotateXYZ(double angleX, double angleY, double angleZ, ref Matrix4x3d dest) {
3511         if ((properties & PROPERTY_IDENTITY) != 0)
3512             return dest.rotationXYZ(angleX, angleY, angleZ);
3513         else if ((properties & PROPERTY_TRANSLATION) != 0) {
3514             double tx = m30, ty = m31, tz = m32;
3515             return dest.rotationXYZ(angleX, angleY, angleZ).setTranslation(tx, ty, tz);
3516         }
3517         return rotateXYZInternal(angleX, angleY, angleZ, dest);
3518     }
3519     private Matrix4x3d rotateXYZInternal(double angleX, double angleY, double angleZ, ref Matrix4x3d dest) {
3520         double sinX = Math.sin(angleX);
3521         double cosX = Math.cosFromSin(sinX, angleX);
3522         double sinY = Math.sin(angleY);
3523         double cosY = Math.cosFromSin(sinY, angleY);
3524         double sinZ = Math.sin(angleZ);
3525         double cosZ = Math.cosFromSin(sinZ, angleZ);
3526         double m_sinX = -sinX;
3527         double m_sinY = -sinY;
3528         double m_sinZ = -sinZ;
3529 
3530         // rotateX
3531         double nm10 = m10 * cosX + m20 * sinX;
3532         double nm11 = m11 * cosX + m21 * sinX;
3533         double nm12 = m12 * cosX + m22 * sinX;
3534         double nm20 = m10 * m_sinX + m20 * cosX;
3535         double nm21 = m11 * m_sinX + m21 * cosX;
3536         double nm22 = m12 * m_sinX + m22 * cosX;
3537         // rotateY
3538         double nm00 = m00 * cosY + nm20 * m_sinY;
3539         double nm01 = m01 * cosY + nm21 * m_sinY;
3540         double nm02 = m02 * cosY + nm22 * m_sinY;
3541         dest.m20 = m00 * sinY + nm20 * cosY;
3542         dest.m21 = m01 * sinY + nm21 * cosY;
3543         dest.m22 = m02 * sinY + nm22 * cosY;
3544         // rotateZ
3545         dest.m00 = nm00 * cosZ + nm10 * sinZ;
3546         dest.m01 = nm01 * cosZ + nm11 * sinZ;
3547         dest.m02 = nm02 * cosZ + nm12 * sinZ;
3548         dest.m10 = nm00 * m_sinZ + nm10 * cosZ;
3549         dest.m11 = nm01 * m_sinZ + nm11 * cosZ;
3550         dest.m12 = nm02 * m_sinZ + nm12 * cosZ;
3551         // copy last column from 'this'
3552         dest.m30 = m30;
3553         dest.m31 = m31;
3554         dest.m32 = m32;
3555         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
3556         return dest;
3557     }
3558 
3559     /**
3560      * Apply rotation of <code>angles.z</code> radians about the Z axis, followed by a rotation of <code>angles.y</code> radians about the Y axis and
3561      * followed by a rotation of <code>angles.x</code> radians about the X axis.
3562      * <p>
3563      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
3564      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
3565      * When used with a left-handed coordinate system, the rotation is clockwise.
3566      * <p>
3567      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
3568      * then the new matrix will be <code>M * R</code>. So when transforming a
3569      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
3570      * rotation will be applied first!
3571      * <p>
3572      * This method is equivalent to calling: <code>rotateZ(angles.z).rotateY(angles.y).rotateX(angles.x)</code>
3573      * 
3574      * @param angles
3575      *            the Euler angles
3576      * @return this
3577      */
3578     ref public Matrix4x3d rotateZYX(Vector3d angles) return {
3579         return rotateZYX(angles.z, angles.y, angles.x);
3580     }
3581 
3582     /**
3583      * Apply rotation of <code>angleZ</code> radians about the Z axis, followed by a rotation of <code>angleY</code> radians about the Y axis and
3584      * followed by a rotation of <code>angleX</code> radians about the X axis.
3585      * <p>
3586      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
3587      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
3588      * When used with a left-handed coordinate system, the rotation is clockwise.
3589      * <p>
3590      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
3591      * then the new matrix will be <code>M * R</code>. So when transforming a
3592      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
3593      * rotation will be applied first!
3594      * <p>
3595      * This method is equivalent to calling: <code>rotateZ(angleZ).rotateY(angleY).rotateX(angleX)</code>
3596      * 
3597      * @param angleZ
3598      *            the angle to rotate about Z
3599      * @param angleY
3600      *            the angle to rotate about Y
3601      * @param angleX
3602      *            the angle to rotate about X
3603      * @return this
3604      */
3605     ref public Matrix4x3d rotateZYX(double angleZ, double angleY, double angleX) return {
3606         rotateZYX(angleZ, angleY, angleX, this);
3607         return this;
3608     }
3609 
3610     public Matrix4x3d rotateZYX(double angleZ, double angleY, double angleX, ref Matrix4x3d dest) {
3611         if ((properties & PROPERTY_IDENTITY) != 0)
3612             return dest.rotationZYX(angleZ, angleY, angleX);
3613         else if ((properties & PROPERTY_TRANSLATION) != 0) {
3614             double tx = m30, ty = m31, tz = m32;
3615             return dest.rotationZYX(angleZ, angleY, angleX).setTranslation(tx, ty, tz);
3616         }
3617         return rotateZYXInternal(angleZ, angleY, angleX, dest);
3618     }
3619     private Matrix4x3d rotateZYXInternal(double angleZ, double angleY, double angleX, ref Matrix4x3d dest) {
3620         double sinX = Math.sin(angleX);
3621         double cosX = Math.cosFromSin(sinX, angleX);
3622         double sinY = Math.sin(angleY);
3623         double cosY = Math.cosFromSin(sinY, angleY);
3624         double sinZ = Math.sin(angleZ);
3625         double cosZ = Math.cosFromSin(sinZ, angleZ);
3626         double m_sinZ = -sinZ;
3627         double m_sinY = -sinY;
3628         double m_sinX = -sinX;
3629 
3630         // rotateZ
3631         double nm00 = m00 * cosZ + m10 * sinZ;
3632         double nm01 = m01 * cosZ + m11 * sinZ;
3633         double nm02 = m02 * cosZ + m12 * sinZ;
3634         double nm10 = m00 * m_sinZ + m10 * cosZ;
3635         double nm11 = m01 * m_sinZ + m11 * cosZ;
3636         double nm12 = m02 * m_sinZ + m12 * cosZ;
3637         // rotateY
3638         double nm20 = nm00 * sinY + m20 * cosY;
3639         double nm21 = nm01 * sinY + m21 * cosY;
3640         double nm22 = nm02 * sinY + m22 * cosY;
3641         dest.m00 = nm00 * cosY + m20 * m_sinY;
3642         dest.m01 = nm01 * cosY + m21 * m_sinY;
3643         dest.m02 = nm02 * cosY + m22 * m_sinY;
3644         // rotateX
3645         dest.m10 = nm10 * cosX + nm20 * sinX;
3646         dest.m11 = nm11 * cosX + nm21 * sinX;
3647         dest.m12 = nm12 * cosX + nm22 * sinX;
3648         dest.m20 = nm10 * m_sinX + nm20 * cosX;
3649         dest.m21 = nm11 * m_sinX + nm21 * cosX;
3650         dest.m22 = nm12 * m_sinX + nm22 * cosX;
3651         // copy last column from 'this'
3652         dest.m30 = m30;
3653         dest.m31 = m31;
3654         dest.m32 = m32;
3655         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
3656         return dest;
3657     }
3658 
3659     /**
3660      * Apply rotation of <code>angles.y</code> radians about the Y axis, followed by a rotation of <code>angles.x</code> radians about the X axis and
3661      * followed by a rotation of <code>angles.z</code> radians about the Z axis.
3662      * <p>
3663      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
3664      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
3665      * When used with a left-handed coordinate system, the rotation is clockwise.
3666      * <p>
3667      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
3668      * then the new matrix will be <code>M * R</code>. So when transforming a
3669      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
3670      * rotation will be applied first!
3671      * <p>
3672      * This method is equivalent to calling: <code>rotateY(angles.y).rotateX(angles.x).rotateZ(angles.z)</code>
3673      * 
3674      * @param angles
3675      *            the Euler angles
3676      * @return this
3677      */
3678     ref public Matrix4x3d rotateYXZ(Vector3d angles) return {
3679         return rotateYXZ(angles.y, angles.x, angles.z);
3680     }
3681 
3682     /**
3683      * Apply rotation of <code>angleY</code> radians about the Y axis, followed by a rotation of <code>angleX</code> radians about the X axis and
3684      * followed by a rotation of <code>angleZ</code> radians about the Z axis.
3685      * <p>
3686      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
3687      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
3688      * When used with a left-handed coordinate system, the rotation is clockwise.
3689      * <p>
3690      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
3691      * then the new matrix will be <code>M * R</code>. So when transforming a
3692      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
3693      * rotation will be applied first!
3694      * <p>
3695      * This method is equivalent to calling: <code>rotateY(angleY).rotateX(angleX).rotateZ(angleZ)</code>
3696      * 
3697      * @param angleY
3698      *            the angle to rotate about Y
3699      * @param angleX
3700      *            the angle to rotate about X
3701      * @param angleZ
3702      *            the angle to rotate about Z
3703      * @return this
3704      */
3705     ref public Matrix4x3d rotateYXZ(double angleY, double angleX, double angleZ) return {
3706         rotateYXZ(angleY, angleX, angleZ, this);
3707         return this;
3708     }
3709 
3710     public Matrix4x3d rotateYXZ(double angleY, double angleX, double angleZ, ref Matrix4x3d dest) {
3711         if ((properties & PROPERTY_IDENTITY) != 0)
3712             return dest.rotationYXZ(angleY, angleX, angleZ);
3713         else if ((properties & PROPERTY_TRANSLATION) != 0) {
3714             double tx = m30, ty = m31, tz = m32;
3715             return dest.rotationYXZ(angleY, angleX, angleZ).setTranslation(tx, ty, tz);
3716         }
3717         return rotateYXZInternal(angleY, angleX, angleZ, dest);
3718     }
3719     private Matrix4x3d rotateYXZInternal(double angleY, double angleX, double angleZ, ref Matrix4x3d dest) {
3720         double sinX = Math.sin(angleX);
3721         double cosX = Math.cosFromSin(sinX, angleX);
3722         double sinY = Math.sin(angleY);
3723         double cosY = Math.cosFromSin(sinY, angleY);
3724         double sinZ = Math.sin(angleZ);
3725         double cosZ = Math.cosFromSin(sinZ, angleZ);
3726         double m_sinY = -sinY;
3727         double m_sinX = -sinX;
3728         double m_sinZ = -sinZ;
3729 
3730         // rotateY
3731         double nm20 = m00 * sinY + m20 * cosY;
3732         double nm21 = m01 * sinY + m21 * cosY;
3733         double nm22 = m02 * sinY + m22 * cosY;
3734         double nm00 = m00 * cosY + m20 * m_sinY;
3735         double nm01 = m01 * cosY + m21 * m_sinY;
3736         double nm02 = m02 * cosY + m22 * m_sinY;
3737         // rotateX
3738         double nm10 = m10 * cosX + nm20 * sinX;
3739         double nm11 = m11 * cosX + nm21 * sinX;
3740         double nm12 = m12 * cosX + nm22 * sinX;
3741         dest.m20 = m10 * m_sinX + nm20 * cosX;
3742         dest.m21 = m11 * m_sinX + nm21 * cosX;
3743         dest.m22 = m12 * m_sinX + nm22 * cosX;
3744         // rotateZ
3745         dest.m00 = nm00 * cosZ + nm10 * sinZ;
3746         dest.m01 = nm01 * cosZ + nm11 * sinZ;
3747         dest.m02 = nm02 * cosZ + nm12 * sinZ;
3748         dest.m10 = nm00 * m_sinZ + nm10 * cosZ;
3749         dest.m11 = nm01 * m_sinZ + nm11 * cosZ;
3750         dest.m12 = nm02 * m_sinZ + nm12 * cosZ;
3751         // copy last column from 'this'
3752         dest.m30 = m30;
3753         dest.m31 = m31;
3754         dest.m32 = m32;
3755         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
3756         return dest;
3757     }
3758 
3759 
3760     /**
3761      * Set this matrix to a rotation transformation using the given {@link AxisAngle4d}.
3762      * <p>
3763      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
3764      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
3765      * When used with a left-handed coordinate system, the rotation is clockwise.
3766      * <p>
3767      * The resulting matrix can be multiplied against another transformation
3768      * matrix to obtain an additional rotation.
3769      * <p>
3770      * In order to apply the rotation transformation to an existing transformation,
3771      * use {@link #rotate(AxisAngle4d) rotate()} instead.
3772      * <p>
3773      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Axis_and_angle">http://en.wikipedia.org</a>
3774      *
3775      * @see #rotate(AxisAngle4d)
3776      * 
3777      * @param angleAxis
3778      *          the {@link AxisAngle4d} (needs to be {@link AxisAngle4d#normalize() normalized})
3779      * @return this
3780      */
3781     ref public Matrix4x3d rotation(AxisAngle4d angleAxis) return {
3782         return rotation(angleAxis.angle, angleAxis.x, angleAxis.y, angleAxis.z);
3783     }
3784 
3785     /**
3786      * Set this matrix to the rotation - and possibly scaling - transformation of the given {@link Quaterniond}.
3787      * <p>
3788      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
3789      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
3790      * When used with a left-handed coordinate system, the rotation is clockwise.
3791      * <p>
3792      * The resulting matrix can be multiplied against another transformation
3793      * matrix to obtain an additional rotation.
3794      * <p>
3795      * In order to apply the rotation transformation to an existing transformation,
3796      * use {@link #rotate(Quaterniond) rotate()} instead.
3797      * <p>
3798      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a>
3799      * 
3800      * @see #rotate(Quaterniond)
3801      * 
3802      * @param quat
3803      *          the {@link Quaterniond}
3804      * @return this
3805      */
3806     ref public Matrix4x3d rotation(Quaterniond quat) return {
3807         double w2 = quat.w * quat.w;
3808         double x2 = quat.x * quat.x;
3809         double y2 = quat.y * quat.y;
3810         double z2 = quat.z * quat.z;
3811         double zw = quat.z * quat.w, dzw = zw + zw;
3812         double xy = quat.x * quat.y, dxy = xy + xy;
3813         double xz = quat.x * quat.z, dxz = xz + xz;
3814         double yw = quat.y * quat.w, dyw = yw + yw;
3815         double yz = quat.y * quat.z, dyz = yz + yz;
3816         double xw = quat.x * quat.w, dxw = xw + xw;
3817         _m00(w2 + x2 - z2 - y2);
3818         _m01(dxy + dzw);
3819         _m02(dxz - dyw);
3820         _m10(dxy - dzw);
3821         _m11(y2 - z2 + w2 - x2);
3822         _m12(dyz + dxw);
3823         _m20(dyw + dxz);
3824         _m21(dyz - dxw);
3825         _m22(z2 - y2 - x2 + w2);
3826         _m30(0.0);
3827         _m31(0.0);
3828         _m32(0.0);
3829         properties = PROPERTY_ORTHONORMAL;
3830         return this;
3831     }
3832 
3833 
3834     /**
3835      * Set <code>this</code> matrix to <code>T * R * S</code>, where <code>T</code> is a translation by the given <code>(tx, ty, tz)</code>,
3836      * <code>R</code> is a rotation transformation specified by the quaternion <code>(qx, qy, qz, qw)</code>, and <code>S</code> is a scaling transformation
3837      * which scales the three axes x, y and z by <code>(sx, sy, sz)</code>.
3838      * <p>
3839      * When transforming a vector by the resulting matrix the scaling transformation will be applied first, then the rotation and
3840      * at last the translation.
3841      * <p>
3842      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
3843      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
3844      * When used with a left-handed coordinate system, the rotation is clockwise.
3845      * <p>
3846      * This method is equivalent to calling: <code>translation(tx, ty, tz).rotate(quat).scale(sx, sy, sz)</code>
3847      * 
3848      * @see #translation(double, double, double)
3849      * @see #rotate(Quaterniond)
3850      * @see #scale(double, double, double)
3851      * 
3852      * @param tx
3853      *          the number of units by which to translate the x-component
3854      * @param ty
3855      *          the number of units by which to translate the y-component
3856      * @param tz
3857      *          the number of units by which to translate the z-component
3858      * @param qx
3859      *          the x-coordinate of the vector part of the quaternion
3860      * @param qy
3861      *          the y-coordinate of the vector part of the quaternion
3862      * @param qz
3863      *          the z-coordinate of the vector part of the quaternion
3864      * @param qw
3865      *          the scalar part of the quaternion
3866      * @param sx
3867      *          the scaling factor for the x-axis
3868      * @param sy
3869      *          the scaling factor for the y-axis
3870      * @param sz
3871      *          the scaling factor for the z-axis
3872      * @return this
3873      */
3874     ref public Matrix4x3d translationRotateScale(double tx, double ty, double tz, 
3875                                            double qx, double qy, double qz, double qw, 
3876                                            double sx, double sy, double sz) return {
3877         double dqx = qx + qx, dqy = qy + qy, dqz = qz + qz;
3878         double q00 = dqx * qx;
3879         double q11 = dqy * qy;
3880         double q22 = dqz * qz;
3881         double q01 = dqx * qy;
3882         double q02 = dqx * qz;
3883         double q03 = dqx * qw;
3884         double q12 = dqy * qz;
3885         double q13 = dqy * qw;
3886         double q23 = dqz * qw;
3887         m00 = sx - (q11 + q22) * sx;
3888         m01 = (q01 + q23) * sx;
3889         m02 = (q02 - q13) * sx;
3890         m10 = (q01 - q23) * sy;
3891         m11 = sy - (q22 + q00) * sy;
3892         m12 = (q12 + q03) * sy;
3893         m20 = (q02 + q13) * sz;
3894         m21 = (q12 - q03) * sz;
3895         m22 = sz - (q11 + q00) * sz;
3896         m30 = tx;
3897         m31 = ty;
3898         m32 = tz;
3899         properties = 0;
3900         return this;
3901     }
3902 
3903     /**
3904      * Set <code>this</code> matrix to <code>T * R * S</code>, where <code>T</code> is the given <code>translation</code>,
3905      * <code>R</code> is a rotation transformation specified by the given quaternion, and <code>S</code> is a scaling transformation
3906      * which scales the axes by <code>scale</code>.
3907      * <p>
3908      * When transforming a vector by the resulting matrix the scaling transformation will be applied first, then the rotation and
3909      * at last the translation.
3910      * <p>
3911      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
3912      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
3913      * When used with a left-handed coordinate system, the rotation is clockwise.
3914      * <p>
3915      * This method is equivalent to calling: <code>translation(translation).rotate(quat).scale(scale)</code>
3916      * 
3917      * @see #translation(Vector3d)
3918      * @see #rotate(Quaterniond)
3919      * 
3920      * @param translation
3921      *          the translation
3922      * @param quat
3923      *          the quaternion representing a rotation
3924      * @param scale
3925      *          the scaling factors
3926      * @return this
3927      */
3928     ref public Matrix4x3d translationRotateScale(Vector3d translation, 
3929                                            Quaterniond quat, 
3930                                            Vector3d scale) return {
3931         return translationRotateScale(translation.x, translation.y, translation.z, quat.x, quat.y, quat.z, 
3932         quat.w, scale.x, scale.y, scale.z);
3933     }
3934 
3935     /**
3936      * Set <code>this</code> matrix to <code>T * R * S * M</code>, where <code>T</code> is a translation by the given <code>(tx, ty, tz)</code>,
3937      * <code>R</code> is a rotation transformation specified by the quaternion <code>(qx, qy, qz, qw)</code>, <code>S</code> is a scaling transformation
3938      * which scales the three axes x, y and z by <code>(sx, sy, sz)</code>.
3939      * <p>
3940      * When transforming a vector by the resulting matrix the transformation described by <code>M</code> will be applied first, then the scaling, then rotation and
3941      * at last the translation.
3942      * <p>
3943      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
3944      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
3945      * When used with a left-handed coordinate system, the rotation is clockwise.
3946      * <p>
3947      * This method is equivalent to calling: <code>translation(tx, ty, tz).rotate(quat).scale(sx, sy, sz).mul(m)</code>
3948      * 
3949      * @see #translation(double, double, double)
3950      * @see #rotate(Quaterniond)
3951      * @see #scale(double, double, double)
3952      * @see #mul(Matrix4x3d)
3953      * 
3954      * @param tx
3955      *          the number of units by which to translate the x-component
3956      * @param ty
3957      *          the number of units by which to translate the y-component
3958      * @param tz
3959      *          the number of units by which to translate the z-component
3960      * @param qx
3961      *          the x-coordinate of the vector part of the quaternion
3962      * @param qy
3963      *          the y-coordinate of the vector part of the quaternion
3964      * @param qz
3965      *          the z-coordinate of the vector part of the quaternion
3966      * @param qw
3967      *          the scalar part of the quaternion
3968      * @param sx
3969      *          the scaling factor for the x-axis
3970      * @param sy
3971      *          the scaling factor for the y-axis
3972      * @param sz
3973      *          the scaling factor for the z-axis
3974      * @param m
3975      *          the matrix to multiply by
3976      * @return this
3977      */
3978     ref public Matrix4x3d translationRotateScaleMul(
3979             double tx, double ty, double tz, 
3980             double qx, double qy, double qz, double qw, 
3981             double sx, double sy, double sz,
3982             Matrix4x3d m) return {
3983         double dqx = qx + qx;
3984         double dqy = qy + qy;
3985         double dqz = qz + qz;
3986         double q00 = dqx * qx;
3987         double q11 = dqy * qy;
3988         double q22 = dqz * qz;
3989         double q01 = dqx * qy;
3990         double q02 = dqx * qz;
3991         double q03 = dqx * qw;
3992         double q12 = dqy * qz;
3993         double q13 = dqy * qw;
3994         double q23 = dqz * qw;
3995         double nm00 = sx - (q11 + q22) * sx;
3996         double nm01 = (q01 + q23) * sx;
3997         double nm02 = (q02 - q13) * sx;
3998         double nm10 = (q01 - q23) * sy;
3999         double nm11 = sy - (q22 + q00) * sy;
4000         double nm12 = (q12 + q03) * sy;
4001         double nm20 = (q02 + q13) * sz;
4002         double nm21 = (q12 - q03) * sz;
4003         double nm22 = sz - (q11 + q00) * sz;
4004         double __m00 = nm00 * m.m00 + nm10 * m.m01 + nm20 * m.m02;
4005         double __m01 = nm01 * m.m00 + nm11 * m.m01 + nm21 * m.m02;
4006         m02 = nm02 * m.m00 + nm12 * m.m01 + nm22 * m.m02;
4007         this.m00 = __m00;
4008         this.m01 = __m01;
4009         double __m10 = nm00 * m.m10 + nm10 * m.m11 + nm20 * m.m12;
4010         double __m11 = nm01 * m.m10 + nm11 * m.m11 + nm21 * m.m12;
4011         m12 = nm02 * m.m10 + nm12 * m.m11 + nm22 * m.m12;
4012         this.m10 = __m10;
4013         this.m11 = __m11;
4014         double __m20 = nm00 * m.m20 + nm10 * m.m21 + nm20 * m.m22;
4015         double __m21 = nm01 * m.m20 + nm11 * m.m21 + nm21 * m.m22;
4016         m22 = nm02 * m.m20 + nm12 * m.m21 + nm22 * m.m22;
4017         this.m20 = __m20;
4018         this.m21 = __m21;
4019         double __m30 = nm00 * m.m30 + nm10 * m.m31 + nm20 * m.m32 + tx;
4020         double __m31 = nm01 * m.m30 + nm11 * m.m31 + nm21 * m.m32 + ty;
4021         m32 = nm02 * m.m30 + nm12 * m.m31 + nm22 * m.m32 + tz;
4022         this.m30 = __m30;
4023         this.m31 = __m31;
4024         properties = 0;
4025         return this;
4026     }
4027 
4028     /**
4029      * Set <code>this</code> matrix to <code>T * R * S * M</code>, where <code>T</code> is the given <code>translation</code>,
4030      * <code>R</code> is a rotation transformation specified by the given quaternion, <code>S</code> is a scaling transformation
4031      * which scales the axes by <code>scale</code>.
4032      * <p>
4033      * When transforming a vector by the resulting matrix the transformation described by <code>M</code> will be applied first, then the scaling, then rotation and
4034      * at last the translation.
4035      * <p>
4036      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
4037      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
4038      * When used with a left-handed coordinate system, the rotation is clockwise.
4039      * <p>
4040      * This method is equivalent to calling: <code>translation(translation).rotate(quat).scale(scale).mul(m)</code>
4041      * 
4042      * @see #translation(Vector3d)
4043      * @see #rotate(Quaterniond)
4044      * @see #mul(Matrix4x3d)
4045      * 
4046      * @param translation
4047      *          the translation
4048      * @param quat
4049      *          the quaternion representing a rotation
4050      * @param scale
4051      *          the scaling factors
4052      * @param m
4053      *          the matrix to multiply by
4054      * @return this
4055      */
4056     ref public Matrix4x3d translationRotateScaleMul(Vector3d translation, Quaterniond quat, Vector3d scale, Matrix4x3d m) return {
4057         return translationRotateScaleMul(translation.x, translation.y, translation.z, quat.x, quat.y, quat.z
4058         , quat.w, scale.x, scale.y, scale.z, m);
4059     }
4060 
4061     /**
4062      * Set <code>this</code> matrix to <code>T * R</code>, where <code>T</code> is a translation by the given <code>(tx, ty, tz)</code> and
4063      * <code>R</code> is a rotation transformation specified by the given quaternion.
4064      * <p>
4065      * When transforming a vector by the resulting matrix the rotation transformation will be applied first and then the translation.
4066      * <p>
4067      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
4068      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
4069      * When used with a left-handed coordinate system, the rotation is clockwise.
4070      * <p>
4071      * This method is equivalent to calling: <code>translation(tx, ty, tz).rotate(quat)</code>
4072      * 
4073      * @see #translation(double, double, double)
4074      * @see #rotate(Quaterniond)
4075      * 
4076      * @param tx
4077      *          the number of units by which to translate the x-component
4078      * @param ty
4079      *          the number of units by which to translate the y-component
4080      * @param tz
4081      *          the number of units by which to translate the z-component
4082      * @param quat
4083      *          the quaternion representing a rotation
4084      * @return this
4085      */
4086     ref public Matrix4x3d translationRotate(double tx, double ty, double tz, Quaterniond quat) return {
4087         double dqx = quat.x + quat.x, dqy = quat.y + quat.y, dqz = quat.z + quat.z;
4088         double q00 = dqx * quat.x;
4089         double q11 = dqy * quat.y;
4090         double q22 = dqz * quat.z;
4091         double q01 = dqx * quat.y;
4092         double q02 = dqx * quat.z;
4093         double q03 = dqx * quat.w;
4094         double q12 = dqy * quat.z;
4095         double q13 = dqy * quat.w;
4096         double q23 = dqz * quat.w;
4097         m00 = 1.0 - (q11 + q22);
4098         m01 = q01 + q23;
4099         m02 = q02 - q13;
4100         m10 = q01 - q23;
4101         m11 = 1.0 - (q22 + q00);
4102         m12 = q12 + q03;
4103         m20 = q02 + q13;
4104         m21 = q12 - q03;
4105         m22 = 1.0 - (q11 + q00);
4106         m30 = tx;
4107         m31 = ty;
4108         m32 = tz;
4109         properties = PROPERTY_ORTHONORMAL;
4110         return this;
4111     }
4112 
4113     /**
4114      * Set <code>this</code> matrix to <code>T * R</code>, where <code>T</code> is a translation by the given <code>(tx, ty, tz)</code> and
4115      * <code>R</code> is a rotation - and possibly scaling - transformation specified by the quaternion <code>(qx, qy, qz, qw)</code>.
4116      * <p>
4117      * When transforming a vector by the resulting matrix the rotation - and possibly scaling - transformation will be applied first and then the translation.
4118      * <p>
4119      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
4120      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
4121      * When used with a left-handed coordinate system, the rotation is clockwise.
4122      * <p>
4123      * This method is equivalent to calling: <code>translation(tx, ty, tz).rotate(quat)</code>
4124      * 
4125      * @see #translation(double, double, double)
4126      * @see #rotate(Quaterniond)
4127      * 
4128      * @param tx
4129      *          the number of units by which to translate the x-component
4130      * @param ty
4131      *          the number of units by which to translate the y-component
4132      * @param tz
4133      *          the number of units by which to translate the z-component
4134      * @param qx
4135      *          the x-coordinate of the vector part of the quaternion
4136      * @param qy
4137      *          the y-coordinate of the vector part of the quaternion
4138      * @param qz
4139      *          the z-coordinate of the vector part of the quaternion
4140      * @param qw
4141      *          the scalar part of the quaternion
4142      * @return this
4143      */
4144     ref public Matrix4x3d translationRotate(double tx, double ty, double tz, double qx, double qy, double qz, double qw) return {
4145         double w2 = qw * qw;
4146         double x2 = qx * qx;
4147         double y2 = qy * qy;
4148         double z2 = qz * qz;
4149         double zw = qz * qw;
4150         double xy = qx * qy;
4151         double xz = qx * qz;
4152         double yw = qy * qw;
4153         double yz = qy * qz;
4154         double xw = qx * qw;
4155         this.m00 = w2 + x2 - z2 - y2;
4156         this.m01 = xy + zw + zw + xy;
4157         this.m02 = xz - yw + xz - yw;
4158         this.m10 = -zw + xy - zw + xy;
4159         this.m11 = y2 - z2 + w2 - x2;
4160         this.m12 = yz + yz + xw + xw;
4161         this.m20 = yw + xz + xz + yw;
4162         this.m21 = yz + yz - xw - xw;
4163         this.m22 = z2 - y2 - x2 + w2;
4164         this.m30 = tx;
4165         this.m31 = ty;
4166         this.m32 = tz;
4167         this.properties = PROPERTY_ORTHONORMAL;
4168         return this;
4169     }
4170 
4171     /**
4172      * Set <code>this</code> matrix to <code>T * R</code>, where <code>T</code> is the given <code>translation</code> and
4173      * <code>R</code> is a rotation transformation specified by the given quaternion.
4174      * <p>
4175      * When transforming a vector by the resulting matrix the scaling transformation will be applied first, then the rotation and
4176      * at last the translation.
4177      * <p>
4178      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
4179      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
4180      * When used with a left-handed coordinate system, the rotation is clockwise.
4181      * <p>
4182      * This method is equivalent to calling: <code>translation(translation).rotate(quat)</code>
4183      * 
4184      * @see #translation(Vector3d)
4185      * @see #rotate(Quaterniond)
4186      * 
4187      * @param translation
4188      *          the translation
4189      * @param quat
4190      *          the quaternion representing a rotation
4191      * @return this
4192      */
4193     ref public Matrix4x3d translationRotate(Vector3d translation, 
4194                                         Quaterniond quat) return {
4195         return translationRotate(translation.x, translation.y, translation.z, quat.x, quat.y, quat.z, quat.w);
4196     }
4197 
4198     /**
4199      * Set <code>this</code> matrix to <code>T * R * M</code>, where <code>T</code> is a translation by the given <code>(tx, ty, tz)</code>,
4200      * <code>R</code> is a rotation - and possibly scaling - transformation specified by the quaternion <code>(qx, qy, qz, qw)</code> and <code>M</code> is the given matrix <code>mat</code>
4201      * <p>
4202      * When transforming a vector by the resulting matrix the transformation described by <code>M</code> will be applied first, then the scaling, then rotation and
4203      * at last the translation.
4204      * <p>
4205      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
4206      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
4207      * When used with a left-handed coordinate system, the rotation is clockwise.
4208      * <p>
4209      * This method is equivalent to calling: <code>translation(tx, ty, tz).rotate(quat).mul(mat)</code>
4210      * 
4211      * @see #translation(double, double, double)
4212      * @see #rotate(Quaternionfc)
4213      * @see #mul(Matrix4x3d)
4214      * 
4215      * @param tx
4216      *          the number of units by which to translate the x-component
4217      * @param ty
4218      *          the number of units by which to translate the y-component
4219      * @param tz
4220      *          the number of units by which to translate the z-component
4221      * @param qx
4222      *          the x-coordinate of the vector part of the quaternion
4223      * @param qy
4224      *          the y-coordinate of the vector part of the quaternion
4225      * @param qz
4226      *          the z-coordinate of the vector part of the quaternion
4227      * @param qw
4228      *          the scalar part of the quaternion
4229      * @param mat
4230      *          the matrix to multiply with
4231      * @return this
4232      */
4233     ref public Matrix4x3d translationRotateMul(double tx, double ty, double tz, double qx, double qy, double qz, double qw, Matrix4x3d mat) return {
4234         double w2 = qw * qw;
4235         double x2 = qx * qx;
4236         double y2 = qy * qy;
4237         double z2 = qz * qz;
4238         double zw = qz * qw;
4239         double xy = qx * qy;
4240         double xz = qx * qz;
4241         double yw = qy * qw;
4242         double yz = qy * qz;
4243         double xw = qx * qw;
4244         double nm00 = w2 + x2 - z2 - y2;
4245         double nm01 = xy + zw + zw + xy;
4246         double nm02 = xz - yw + xz - yw;
4247         double nm10 = -zw + xy - zw + xy;
4248         double nm11 = y2 - z2 + w2 - x2;
4249         double nm12 = yz + yz + xw + xw;
4250         double nm20 = yw + xz + xz + yw;
4251         double nm21 = yz + yz - xw - xw;
4252         double nm22 = z2 - y2 - x2 + w2;
4253         m00 = nm00 * mat.m00 + nm10 * mat.m01 + nm20 * mat.m02;
4254         m01 = nm01 * mat.m00 + nm11 * mat.m01 + nm21 * mat.m02;
4255         m02 = nm02 * mat.m00 + nm12 * mat.m01 + nm22 * mat.m02;
4256         m10 = nm00 * mat.m10 + nm10 * mat.m11 + nm20 * mat.m12;
4257         m11 = nm01 * mat.m10 + nm11 * mat.m11 + nm21 * mat.m12;
4258         m12 = nm02 * mat.m10 + nm12 * mat.m11 + nm22 * mat.m12;
4259         m20 = nm00 * mat.m20 + nm10 * mat.m21 + nm20 * mat.m22;
4260         m21 = nm01 * mat.m20 + nm11 * mat.m21 + nm21 * mat.m22;
4261         m22 = nm02 * mat.m20 + nm12 * mat.m21 + nm22 * mat.m22;
4262         m30 = nm00 * mat.m30 + nm10 * mat.m31 + nm20 * mat.m32 + tx;
4263         m31 = nm01 * mat.m30 + nm11 * mat.m31 + nm21 * mat.m32 + ty;
4264         m32 = nm02 * mat.m30 + nm12 * mat.m31 + nm22 * mat.m32 + tz;
4265         this.properties = 0;
4266         return this;
4267     }
4268 
4269     /**
4270      * Set <code>this</code> matrix to <code>(T * R)<sup>-1</sup></code>, where <code>T</code> is a translation by the given <code>(tx, ty, tz)</code> and
4271      * <code>R</code> is a rotation transformation specified by the quaternion <code>(qx, qy, qz, qw)</code>.
4272      * <p>
4273      * This method is equivalent to calling: <code>translationRotate(...).invert()</code>
4274      * 
4275      * @see #translationRotate(double, double, double, double, double, double, double)
4276      * @see #invert()
4277      * 
4278      * @param tx
4279      *          the number of units by which to translate the x-component
4280      * @param ty
4281      *          the number of units by which to translate the y-component
4282      * @param tz
4283      *          the number of units by which to translate the z-component
4284      * @param qx
4285      *          the x-coordinate of the vector part of the quaternion
4286      * @param qy
4287      *          the y-coordinate of the vector part of the quaternion
4288      * @param qz
4289      *          the z-coordinate of the vector part of the quaternion
4290      * @param qw
4291      *          the scalar part of the quaternion
4292      * @return this
4293      */
4294     ref public Matrix4x3d translationRotateInvert(double tx, double ty, double tz, double qx, double qy, double qz, 
4295     double qw) return {
4296         double nqx = -qx, nqy = -qy, nqz = -qz;
4297         double dqx = nqx + nqx;
4298         double dqy = nqy + nqy;
4299         double dqz = nqz + nqz;
4300         double q00 = dqx * nqx;
4301         double q11 = dqy * nqy;
4302         double q22 = dqz * nqz;
4303         double q01 = dqx * nqy;
4304         double q02 = dqx * nqz;
4305         double q03 = dqx * qw;
4306         double q12 = dqy * nqz;
4307         double q13 = dqy * qw;
4308         double q23 = dqz * qw;
4309         return this
4310         ._m00(1.0 - q11 - q22)
4311         ._m01(q01 + q23)
4312         ._m02(q02 - q13)
4313         ._m10(q01 - q23)
4314         ._m11(1.0 - q22 - q00)
4315         ._m12(q12 + q03)
4316         ._m20(q02 + q13)
4317         ._m21(q12 - q03)
4318         ._m22(1.0 - q11 - q00)
4319         ._m30(-m00 * tx - m10 * ty - m20 * tz)
4320         ._m31(-m01 * tx - m11 * ty - m21 * tz)
4321         ._m32(-m02 * tx - m12 * ty - m22 * tz)
4322         ._properties(PROPERTY_ORTHONORMAL);
4323     }
4324 
4325     /**
4326      * Set <code>this</code> matrix to <code>(T * R)<sup>-1</sup></code>, where <code>T</code> is the given <code>translation</code> and
4327      * <code>R</code> is a rotation transformation specified by the given quaternion.
4328      * <p>
4329      * This method is equivalent to calling: <code>translationRotate(...).invert()</code>
4330      * 
4331      * @see #translationRotate(Vector3d, Quaterniond)
4332      * @see #invert()
4333      * 
4334      * @param translation
4335      *          the translation
4336      * @param quat
4337      *          the quaternion representing a rotation
4338      * @return this
4339      */
4340     ref public Matrix4x3d translationRotateInvert(Vector3d translation, 
4341                                               Quaterniond quat) return {
4342         return translationRotateInvert(translation.x, translation.y, translation.z, quat.x, quat.y, quat.z,
4343          quat.w);
4344     }
4345 
4346     /**
4347      * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniond} to this matrix and store
4348      * the result in <code>dest</code>.
4349      * <p>
4350      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
4351      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
4352      * When used with a left-handed coordinate system, the rotation is clockwise.
4353      * <p>
4354      * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion,
4355      * then the new matrix will be <code>M * Q</code>. So when transforming a
4356      * vector <code>v</code> with the new matrix by using <code>M * Q * v</code>,
4357      * the quaternion rotation will be applied first!
4358      * <p>
4359      * In order to set the matrix to a rotation transformation without post-multiplying,
4360      * use {@link #rotation(Quaterniond)}.
4361      * <p>
4362      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a>
4363      * 
4364      * @see #rotation(Quaterniond)
4365      * 
4366      * @param quat
4367      *          the {@link Quaterniond}
4368      * @param dest
4369      *          will hold the result
4370      * @return dest
4371      */
4372     public Matrix4x3d rotate(Quaterniond quat, ref Matrix4x3d dest) {
4373         if ((properties & PROPERTY_IDENTITY) != 0)
4374             return dest.rotation(quat);
4375         else if ((properties & PROPERTY_TRANSLATION) != 0)
4376             return rotateTranslation(quat, dest);
4377         return rotateGeneric(quat, dest);
4378     }
4379     private Matrix4x3d rotateGeneric(Quaterniond quat, ref Matrix4x3d dest) {
4380         double w2 = quat.w * quat.w, x2 = quat.x * quat.x;
4381         double y2 = quat.y * quat.y, z2 = quat.z * quat.z;
4382         double zw = quat.z * quat.w, dzw = zw + zw, xy = quat.x * quat.y, dxy = xy + xy;
4383         double xz = quat.x * quat.z, dxz = xz + xz, yw = quat.y * quat.w, dyw = yw + yw;
4384         double yz = quat.y * quat.z, dyz = yz + yz, xw = quat.x * quat.w, dxw = xw + xw;
4385         double rm00 = w2 + x2 - z2 - y2;
4386         double rm01 = dxy + dzw;
4387         double rm02 = dxz - dyw;
4388         double rm10 = dxy - dzw;
4389         double rm11 = y2 - z2 + w2 - x2;
4390         double rm12 = dyz + dxw;
4391         double rm20 = dyw + dxz;
4392         double rm21 = dyz - dxw;
4393         double rm22 = z2 - y2 - x2 + w2;
4394         double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
4395         double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
4396         double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
4397         double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
4398         double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
4399         double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
4400         dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
4401         dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
4402         dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
4403         dest.m00 = nm00;
4404         dest.m01 = nm01;
4405         dest.m02 = nm02;
4406         dest.m10 = nm10;
4407         dest.m11 = nm11;
4408         dest.m12 = nm12;
4409         dest.m30 = m30;
4410         dest.m31 = m31;
4411         dest.m32 = m32;
4412         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
4413         return dest;
4414     }
4415 
4416 
4417     /**
4418      * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniond} to this matrix.
4419      * <p>
4420      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
4421      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
4422      * When used with a left-handed coordinate system, the rotation is clockwise.
4423      * <p>
4424      * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion,
4425      * then the new matrix will be <code>M * Q</code>. So when transforming a
4426      * vector <code>v</code> with the new matrix by using <code>M * Q * v</code>,
4427      * the quaternion rotation will be applied first!
4428      * <p>
4429      * In order to set the matrix to a rotation transformation without post-multiplying,
4430      * use {@link #rotation(Quaterniond)}.
4431      * <p>
4432      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a>
4433      * 
4434      * @see #rotation(Quaterniond)
4435      * 
4436      * @param quat
4437      *          the {@link Quaterniond}
4438      * @return this
4439      */
4440     ref public Matrix4x3d rotate(Quaterniond quat) return {
4441         rotate(quat, this);
4442         return this;
4443     }
4444 
4445 
4446     /**
4447      * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniond} to this matrix, which is assumed to only contain a translation, and store
4448      * the result in <code>dest</code>.
4449      * <p>
4450      * This method assumes <code>this</code> to only contain a translation.
4451      * <p>
4452      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
4453      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
4454      * When used with a left-handed coordinate system, the rotation is clockwise.
4455      * <p>
4456      * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion,
4457      * then the new matrix will be <code>M * Q</code>. So when transforming a
4458      * vector <code>v</code> with the new matrix by using <code>M * Q * v</code>,
4459      * the quaternion rotation will be applied first!
4460      * <p>
4461      * In order to set the matrix to a rotation transformation without post-multiplying,
4462      * use {@link #rotation(Quaterniond)}.
4463      * <p>
4464      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a>
4465      * 
4466      * @see #rotation(Quaterniond)
4467      * 
4468      * @param quat
4469      *          the {@link Quaterniond}
4470      * @param dest
4471      *          will hold the result
4472      * @return dest
4473      */
4474     public Matrix4x3d rotateTranslation(Quaterniond quat, ref Matrix4x3d dest) {
4475         double w2 = quat.w * quat.w, x2 = quat.x * quat.x;
4476         double y2 = quat.y * quat.y, z2 = quat.z * quat.z;
4477         double zw = quat.z * quat.w, dzw = zw + zw, xy = quat.x * quat.y, dxy = xy + xy;
4478         double xz = quat.x * quat.z, dxz = xz + xz, yw = quat.y * quat.w, dyw = yw + yw;
4479         double yz = quat.y * quat.z, dyz = yz + yz, xw = quat.x * quat.w, dxw = xw + xw;
4480         double rm00 = w2 + x2 - z2 - y2;
4481         double rm01 = dxy + dzw;
4482         double rm02 = dxz - dyw;
4483         double rm10 = dxy - dzw;
4484         double rm11 = y2 - z2 + w2 - x2;
4485         double rm12 = dyz + dxw;
4486         double rm20 = dyw + dxz;
4487         double rm21 = dyz - dxw;
4488         double rm22 = z2 - y2 - x2 + w2;
4489         dest.m20 = rm20;
4490         dest.m21 = rm21;
4491         dest.m22 = rm22;
4492         dest.m00 = rm00;
4493         dest.m01 = rm01;
4494         dest.m02 = rm02;
4495         dest.m10 = rm10;
4496         dest.m11 = rm11;
4497         dest.m12 = rm12;
4498         dest.m30 = m30;
4499         dest.m31 = m31;
4500         dest.m32 = m32;
4501         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
4502         return dest;
4503     }
4504 
4505 
4506     /**
4507      * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaterniond} to this matrix and store
4508      * the result in <code>dest</code>.
4509      * <p>
4510      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
4511      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
4512      * When used with a left-handed coordinate system, the rotation is clockwise.
4513      * <p>
4514      * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion,
4515      * then the new matrix will be <code>Q * M</code>. So when transforming a
4516      * vector <code>v</code> with the new matrix by using <code>Q * M * v</code>,
4517      * the quaternion rotation will be applied last!
4518      * <p>
4519      * In order to set the matrix to a rotation transformation without pre-multiplying,
4520      * use {@link #rotation(Quaterniond)}.
4521      * <p>
4522      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a>
4523      * 
4524      * @see #rotation(Quaterniond)
4525      * 
4526      * @param quat
4527      *          the {@link Quaterniond}
4528      * @param dest
4529      *          will hold the result
4530      * @return dest
4531      */
4532     public Matrix4x3d rotateLocal(Quaterniond quat, ref Matrix4x3d dest) {
4533         double w2 = quat.w * quat.w, x2 = quat.x * quat.x;
4534         double y2 = quat.y * quat.y, z2 = quat.z * quat.z;
4535         double zw = quat.z * quat.w, dzw = zw + zw, xy = quat.x * quat.y, dxy = xy + xy;
4536         double xz = quat.x * quat.z, dxz = xz + xz, yw = quat.y * quat.w, dyw = yw + yw;
4537         double yz = quat.y * quat.z, dyz = yz + yz, xw = quat.x * quat.w, dxw = xw + xw;
4538         double lm00 = w2 + x2 - z2 - y2;
4539         double lm01 = dxy + dzw;
4540         double lm02 = dxz - dyw;
4541         double lm10 = dxy - dzw;
4542         double lm11 = y2 - z2 + w2 - x2;
4543         double lm12 = dyz + dxw;
4544         double lm20 = dyw + dxz;
4545         double lm21 = dyz - dxw;
4546         double lm22 = z2 - y2 - x2 + w2;
4547         double nm00 = lm00 * m00 + lm10 * m01 + lm20 * m02;
4548         double nm01 = lm01 * m00 + lm11 * m01 + lm21 * m02;
4549         double nm02 = lm02 * m00 + lm12 * m01 + lm22 * m02;
4550         double nm10 = lm00 * m10 + lm10 * m11 + lm20 * m12;
4551         double nm11 = lm01 * m10 + lm11 * m11 + lm21 * m12;
4552         double nm12 = lm02 * m10 + lm12 * m11 + lm22 * m12;
4553         double nm20 = lm00 * m20 + lm10 * m21 + lm20 * m22;
4554         double nm21 = lm01 * m20 + lm11 * m21 + lm21 * m22;
4555         double nm22 = lm02 * m20 + lm12 * m21 + lm22 * m22;
4556         double nm30 = lm00 * m30 + lm10 * m31 + lm20 * m32;
4557         double nm31 = lm01 * m30 + lm11 * m31 + lm21 * m32;
4558         double nm32 = lm02 * m30 + lm12 * m31 + lm22 * m32;
4559         dest.m00 = nm00;
4560         dest.m01 = nm01;
4561         dest.m02 = nm02;
4562         dest.m10 = nm10;
4563         dest.m11 = nm11;
4564         dest.m12 = nm12;
4565         dest.m20 = nm20;
4566         dest.m21 = nm21;
4567         dest.m22 = nm22;
4568         dest.m30 = nm30;
4569         dest.m31 = nm31;
4570         dest.m32 = nm32;
4571         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
4572         return dest;
4573     }
4574 
4575     /**
4576      * Pre-multiply the rotation transformation of the given {@link Quaterniond} to this matrix.
4577      * <p>
4578      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
4579      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
4580      * When used with a left-handed coordinate system, the rotation is clockwise.
4581      * <p>
4582      * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion,
4583      * then the new matrix will be <code>Q * M</code>. So when transforming a
4584      * vector <code>v</code> with the new matrix by using <code>Q * M * v</code>,
4585      * the quaternion rotation will be applied last!
4586      * <p>
4587      * In order to set the matrix to a rotation transformation without pre-multiplying,
4588      * use {@link #rotation(Quaterniond)}.
4589      * <p>
4590      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a>
4591      * 
4592      * @see #rotation(Quaterniond)
4593      * 
4594      * @param quat
4595      *          the {@link Quaterniond}
4596      * @return this
4597      */
4598     ref public Matrix4x3d rotateLocal(Quaterniond quat) return {
4599         rotateLocal(quat, this);
4600         return this;
4601     }
4602 
4603     /**
4604      * Apply a rotation transformation, rotating about the given {@link AxisAngle4d}, to this matrix.
4605      * <p>
4606      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
4607      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
4608      * When used with a left-handed coordinate system, the rotation is clockwise.
4609      * <p>
4610      * If <code>M</code> is <code>this</code> matrix and <code>A</code> the rotation matrix obtained from the given {@link AxisAngle4d},
4611      * then the new matrix will be <code>M * A</code>. So when transforming a
4612      * vector <code>v</code> with the new matrix by using <code>M * A * v</code>,
4613      * the {@link AxisAngle4d} rotation will be applied first!
4614      * <p>
4615      * In order to set the matrix to a rotation transformation without post-multiplying,
4616      * use {@link #rotation(AxisAngle4d)}.
4617      * <p>
4618      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Axis_and_angle">http://en.wikipedia.org</a>
4619      * 
4620      * @see #rotate(double, double, double, double)
4621      * @see #rotation(AxisAngle4d)
4622      * 
4623      * @param axisAngle
4624      *          the {@link AxisAngle4d} (needs to be {@link AxisAngle4d#normalize() normalized})
4625      * @return this
4626      */
4627     ref public Matrix4x3d rotate(AxisAngle4d axisAngle) return {
4628         return rotate(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z);
4629     }
4630 
4631     /**
4632      * Apply a rotation transformation, rotating about the given {@link AxisAngle4d} and store the result in <code>dest</code>.
4633      * <p>
4634      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
4635      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
4636      * When used with a left-handed coordinate system, the rotation is clockwise.
4637      * <p>
4638      * If <code>M</code> is <code>this</code> matrix and <code>A</code> the rotation matrix obtained from the given {@link AxisAngle4d},
4639      * then the new matrix will be <code>M * A</code>. So when transforming a
4640      * vector <code>v</code> with the new matrix by using <code>M * A * v</code>,
4641      * the {@link AxisAngle4d} rotation will be applied first!
4642      * <p>
4643      * In order to set the matrix to a rotation transformation without post-multiplying,
4644      * use {@link #rotation(AxisAngle4d)}.
4645      * <p>
4646      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Axis_and_angle">http://en.wikipedia.org</a>
4647      * 
4648      * @see #rotate(double, double, double, double)
4649      * @see #rotation(AxisAngle4d)
4650      * 
4651      * @param axisAngle
4652      *          the {@link AxisAngle4d} (needs to be {@link AxisAngle4d#normalize() normalized})
4653      * @param dest
4654      *          will hold the result
4655      * @return dest
4656      */
4657     public Matrix4x3d rotate(AxisAngle4d axisAngle, ref Matrix4x3d dest) {
4658         return rotate(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z, dest);
4659     }
4660 
4661     /**
4662      * Apply a rotation transformation, rotating the given radians about the specified axis, to this matrix.
4663      * <p>
4664      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
4665      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
4666      * When used with a left-handed coordinate system, the rotation is clockwise.
4667      * <p>
4668      * If <code>M</code> is <code>this</code> matrix and <code>A</code> the rotation matrix obtained from the given angle and axis,
4669      * then the new matrix will be <code>M * A</code>. So when transforming a
4670      * vector <code>v</code> with the new matrix by using <code>M * A * v</code>,
4671      * the axis-angle rotation will be applied first!
4672      * <p>
4673      * In order to set the matrix to a rotation transformation without post-multiplying,
4674      * use {@link #rotation(double, Vector3d)}.
4675      * <p>
4676      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Axis_and_angle">http://en.wikipedia.org</a>
4677      * 
4678      * @see #rotate(double, double, double, double)
4679      * @see #rotation(double, Vector3d)
4680      * 
4681      * @param angle
4682      *          the angle in radians
4683      * @param axis
4684      *          the rotation axis (needs to be {@link Vector3d#normalize() normalized})
4685      * @return this
4686      */
4687     ref public Matrix4x3d rotate(double angle, Vector3d axis) return {
4688         return rotate(angle, axis.x, axis.y, axis.z);
4689     }
4690 
4691     /**
4692      * Apply a rotation transformation, rotating the given radians about the specified axis and store the result in <code>dest</code>.
4693      * <p>
4694      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
4695      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
4696      * When used with a left-handed coordinate system, the rotation is clockwise.
4697      * <p>
4698      * If <code>M</code> is <code>this</code> matrix and <code>A</code> the rotation matrix obtained from the given angle and axis,
4699      * then the new matrix will be <code>M * A</code>. So when transforming a
4700      * vector <code>v</code> with the new matrix by using <code>M * A * v</code>,
4701      * the axis-angle rotation will be applied first!
4702      * <p>
4703      * In order to set the matrix to a rotation transformation without post-multiplying,
4704      * use {@link #rotation(double, Vector3d)}.
4705      * <p>
4706      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Axis_and_angle">http://en.wikipedia.org</a>
4707      * 
4708      * @see #rotate(double, double, double, double)
4709      * @see #rotation(double, Vector3d)
4710      * 
4711      * @param angle
4712      *          the angle in radians
4713      * @param axis
4714      *          the rotation axis (needs to be {@link Vector3d#normalize() normalized})
4715      * @param dest
4716      *          will hold the result
4717      * @return dest
4718      */
4719     public Matrix4x3d rotate(double angle, Vector3d axis, ref Matrix4x3d dest) {
4720         return rotate(angle, axis.x, axis.y, axis.z, dest);
4721     }
4722 
4723 
4724     public Vector4d getRow(int row, Vector4d dest) {
4725         switch (row) {
4726         case 0:
4727             dest.x = m00;
4728             dest.y = m10;
4729             dest.z = m20;
4730             dest.w = m30;
4731             break;
4732         case 1:
4733             dest.x = m01;
4734             dest.y = m11;
4735             dest.z = m21;
4736             dest.w = m31;
4737             break;
4738         case 2:
4739             dest.x = m02;
4740             dest.y = m12;
4741             dest.z = m22;
4742             dest.w = m32;
4743             break;
4744         default: {}
4745         }
4746         return dest;
4747     }
4748 
4749     /**
4750      * Set the row at the given <code>row</code> index, starting with <code>0</code>.
4751      * 
4752      * @param row
4753      *          the row index in <code>[0..2]</code>
4754      * @param src
4755      *          the row components to set
4756      * @return this
4757      * @throws IndexOutOfBoundsException if <code>row</code> is not in <code>[0..2]</code>
4758      */
4759     ref public Matrix4x3d setRow(int row, Vector4d src) return {
4760         switch (row) {
4761         case 0:
4762             this.m00 = src.x;
4763             this.m10 = src.y;
4764             this.m20 = src.z;
4765             this.m30 = src.w;
4766             break;
4767         case 1:
4768             this.m01 = src.x;
4769             this.m11 = src.y;
4770             this.m21 = src.z;
4771             this.m31 = src.w;
4772             break;
4773         case 2:
4774             this.m02 = src.x;
4775             this.m12 = src.y;
4776             this.m22 = src.z;
4777             this.m32 = src.w;
4778             break;
4779         default: {}
4780         }
4781         properties = 0;
4782         return this;
4783     }
4784 
4785     public Vector3d getColumn(int column, ref Vector3d dest) {
4786         switch (column) {
4787         case 0:
4788             dest.x = m00;
4789             dest.y = m01;
4790             dest.z = m02;
4791             break;
4792         case 1:
4793             dest.x = m10;
4794             dest.y = m11;
4795             dest.z = m12;
4796             break;
4797         case 2:
4798             dest.x = m20;
4799             dest.y = m21;
4800             dest.z = m22;
4801             break;
4802         case 3:
4803             dest.x = m30;
4804             dest.y = m31;
4805             dest.z = m32;
4806             break;
4807         default: {}
4808         }
4809         return dest;
4810     }
4811 
4812     /**
4813      * Set the column at the given <code>column</code> index, starting with <code>0</code>.
4814      * 
4815      * @param column
4816      *          the column index in <code>[0..3]</code>
4817      * @param src
4818      *          the column components to set
4819      * @return this
4820      * @throws IndexOutOfBoundsException if <code>column</code> is not in <code>[0..3]</code>
4821      */
4822     ref public Matrix4x3d setColumn(int column, Vector3d src) return {
4823         switch (column) {
4824         case 0:
4825             this.m00 = src.x;
4826             this.m01 = src.y;
4827             this.m02 = src.z;
4828             break;
4829         case 1:
4830             this.m10 = src.x;
4831             this.m11 = src.y;
4832             this.m12 = src.z;
4833             break;
4834         case 2:
4835             this.m20 = src.x;
4836             this.m21 = src.y;
4837             this.m22 = src.z;
4838             break;
4839         case 3:
4840             this.m30 = src.x;
4841             this.m31 = src.y;
4842             this.m32 = src.z;
4843             break;
4844         default: {}
4845         }
4846         properties = 0;
4847         return this;
4848     }
4849 
4850     /**
4851      * Compute a normal matrix from the left 3x3 submatrix of <code>this</code>
4852      * and store it into the left 3x3 submatrix of <code>this</code>.
4853      * All other values of <code>this</code> will be set to {@link #identity() identity}.
4854      * <p>
4855      * The normal matrix of <code>m</code> is the transpose of the inverse of <code>m</code>.
4856      * <p>
4857      * Please note that, if <code>this</code> is an orthogonal matrix or a matrix whose columns are orthogonal vectors, 
4858      * then this method <i>need not</i> be invoked, since in that case <code>this</code> itself is its normal matrix.
4859      * In that case, use {@link #set3x3(Matrix4x3d)} to set a given Matrix4x3d to only the left 3x3 submatrix
4860      * of this matrix.
4861      * 
4862      * @see #set3x3(Matrix4x3d)
4863      * 
4864      * @return this
4865      */
4866     ref public Matrix4x3d normal() return {
4867         normal(this);
4868         return this;
4869     }
4870 
4871     /**
4872      * Compute a normal matrix from the left 3x3 submatrix of <code>this</code>
4873      * and store it into the left 3x3 submatrix of <code>dest</code>.
4874      * All other values of <code>dest</code> will be set to {@link #identity() identity}.
4875      * <p>
4876      * The normal matrix of <code>m</code> is the transpose of the inverse of <code>m</code>.
4877      * <p>
4878      * Please note that, if <code>this</code> is an orthogonal matrix or a matrix whose columns are orthogonal vectors, 
4879      * then this method <i>need not</i> be invoked, since in that case <code>this</code> itself is its normal matrix.
4880      * In that case, use {@link #set3x3(Matrix4x3d)} to set a given Matrix4x3d to only the left 3x3 submatrix
4881      * of a given matrix.
4882      * 
4883      * @see #set3x3(Matrix4x3d)
4884      * 
4885      * @param dest
4886      *             will hold the result
4887      * @return dest
4888      */
4889     public Matrix4x3d normal(ref Matrix4x3d dest) {
4890         if ((properties & PROPERTY_IDENTITY) != 0)
4891             return dest.identity();
4892         else if ((properties & PROPERTY_ORTHONORMAL) != 0)
4893             return normalOrthonormal(dest);
4894         return normalGeneric(dest);
4895     }
4896     private Matrix4x3d normalOrthonormal(ref Matrix4x3d dest) {
4897         if (dest != this)
4898             dest.set(this);
4899         return dest._properties(PROPERTY_ORTHONORMAL);
4900     }
4901     private Matrix4x3d normalGeneric(ref Matrix4x3d dest) {
4902         double m00m11 = m00 * m11;
4903         double m01m10 = m01 * m10;
4904         double m02m10 = m02 * m10;
4905         double m00m12 = m00 * m12;
4906         double m01m12 = m01 * m12;
4907         double m02m11 = m02 * m11;
4908         double det = (m00m11 - m01m10) * m22 + (m02m10 - m00m12) * m21 + (m01m12 - m02m11) * m20;
4909         double s = 1.0 / det;
4910         /* Invert and transpose in one go */
4911         double nm00 = (m11 * m22 - m21 * m12) * s;
4912         double nm01 = (m20 * m12 - m10 * m22) * s;
4913         double nm02 = (m10 * m21 - m20 * m11) * s;
4914         double nm10 = (m21 * m02 - m01 * m22) * s;
4915         double nm11 = (m00 * m22 - m20 * m02) * s;
4916         double nm12 = (m20 * m01 - m00 * m21) * s;
4917         double nm20 = (m01m12 - m02m11) * s;
4918         double nm21 = (m02m10 - m00m12) * s;
4919         double nm22 = (m00m11 - m01m10) * s;
4920         dest.m00 = nm00;
4921         dest.m01 = nm01;
4922         dest.m02 = nm02;
4923         dest.m10 = nm10;
4924         dest.m11 = nm11;
4925         dest.m12 = nm12;
4926         dest.m20 = nm20;
4927         dest.m21 = nm21;
4928         dest.m22 = nm22;
4929         dest.m30 = 0.0;
4930         dest.m31 = 0.0;
4931         dest.m32 = 0.0;
4932         dest.properties = properties & ~PROPERTY_TRANSLATION;
4933         return dest;
4934     }
4935 
4936     public Matrix3d normal(Matrix3d dest) {
4937         if ((properties & PROPERTY_ORTHONORMAL) != 0)
4938             return normalOrthonormal(dest);
4939         return normalGeneric(dest);
4940     }
4941     private Matrix3d normalOrthonormal(Matrix3d dest) {
4942         return dest.set(this);
4943     }
4944     private Matrix3d normalGeneric(Matrix3d dest) {
4945         double m00m11 = m00 * m11;
4946         double m01m10 = m01 * m10;
4947         double m02m10 = m02 * m10;
4948         double m00m12 = m00 * m12;
4949         double m01m12 = m01 * m12;
4950         double m02m11 = m02 * m11;
4951         double det = (m00m11 - m01m10) * m22 + (m02m10 - m00m12) * m21 + (m01m12 - m02m11) * m20;
4952         double s = 1.0 / det;
4953         /* Invert and transpose in one go */
4954         dest.m00 = ((m11 * m22 - m21 * m12) * s);
4955         dest.m01 = ((m20 * m12 - m10 * m22) * s);
4956         dest.m02 = ((m10 * m21 - m20 * m11) * s);
4957         dest.m10 = ((m21 * m02 - m01 * m22) * s);
4958         dest.m11 = ((m00 * m22 - m20 * m02) * s);
4959         dest.m12 = ((m20 * m01 - m00 * m21) * s);
4960         dest.m20 = ((m01m12 - m02m11) * s);
4961         dest.m21 = ((m02m10 - m00m12) * s);
4962         dest.m22 = ((m00m11 - m01m10) * s);
4963         return dest;
4964     }
4965 
4966     /**
4967      * Compute the cofactor matrix of the left 3x3 submatrix of <code>this</code>.
4968      * <p>
4969      * The cofactor matrix can be used instead of {@link #normal()} to transform normals
4970      * when the orientation of the normals with respect to the surface should be preserved.
4971      * 
4972      * @return this
4973      */
4974     ref public Matrix4x3d cofactor3x3() return {
4975         cofactor3x3(this);
4976         return this;
4977     }
4978 
4979     /**
4980      * Compute the cofactor matrix of the left 3x3 submatrix of <code>this</code>
4981      * and store it into <code>dest</code>.
4982      * <p>
4983      * The cofactor matrix can be used instead of {@link #normal(Matrix3d)} to transform normals
4984      * when the orientation of the normals with respect to the surface should be preserved.
4985      * 
4986      * @param dest
4987      *             will hold the result
4988      * @return dest
4989      */
4990     public Matrix3d cofactor3x3(Matrix3d dest) {
4991         dest.m00 = m11 * m22 - m21 * m12;
4992         dest.m01 = m20 * m12 - m10 * m22;
4993         dest.m02 = m10 * m21 - m20 * m11;
4994         dest.m10 = m21 * m02 - m01 * m22;
4995         dest.m11 = m00 * m22 - m20 * m02;
4996         dest.m12 = m20 * m01 - m00 * m21;
4997         dest.m20 = m01 * m12 - m02 * m11;
4998         dest.m21 = m02 * m10 - m00 * m12;
4999         dest.m22 = m00 * m11 - m01 * m10;
5000         return dest;
5001     }
5002 
5003     /**
5004      * Compute the cofactor matrix of the left 3x3 submatrix of <code>this</code>
5005      * and store it into <code>dest</code>.
5006      * All other values of <code>dest</code> will be set to {@link #identity() identity}.
5007      * <p>
5008      * The cofactor matrix can be used instead of {@link #normal(Matrix4x3d)} to transform normals
5009      * when the orientation of the normals with respect to the surface should be preserved.
5010      * 
5011      * @param dest
5012      *             will hold the result
5013      * @return dest
5014      */
5015     public Matrix4x3d cofactor3x3(ref Matrix4x3d dest) {
5016         double nm00 = m11 * m22 - m21 * m12;
5017         double nm01 = m20 * m12 - m10 * m22;
5018         double nm02 = m10 * m21 - m20 * m11;
5019         double nm10 = m21 * m02 - m01 * m22;
5020         double nm11 = m00 * m22 - m20 * m02;
5021         double nm12 = m20 * m01 - m00 * m21;
5022         double nm20 = m01 * m12 - m11 * m02;
5023         double nm21 = m02 * m10 - m12 * m00;
5024         double nm22 = m00 * m11 - m10 * m01;
5025         dest.m00 = nm00;
5026         dest.m01 = nm01;
5027         dest.m02 = nm02;
5028         dest.m10 = nm10;
5029         dest.m11 = nm11;
5030         dest.m12 = nm12;
5031         dest.m20 = nm20;
5032         dest.m21 = nm21;
5033         dest.m22 = nm22;
5034         dest.m30 = 0.0;
5035         dest.m31 = 0.0;
5036         dest.m32 = 0.0;
5037         dest.properties = properties & ~PROPERTY_TRANSLATION;
5038         return dest;
5039     }
5040 
5041     /**
5042      * Normalize the left 3x3 submatrix of this matrix.
5043      * <p>
5044      * The resulting matrix will map unit vectors to unit vectors, though a pair of orthogonal input unit
5045      * vectors need not be mapped to a pair of orthogonal output vectors if the original matrix was not orthogonal itself
5046      * (i.e. had <i>skewing</i>).
5047      * 
5048      * @return this
5049      */
5050     ref public Matrix4x3d normalize3x3() return {
5051         normalize3x3(this);
5052         return this;
5053     }
5054 
5055     public Matrix4x3d normalize3x3(ref Matrix4x3d dest) {
5056         double invXlen = Math.invsqrt(m00 * m00 + m01 * m01 + m02 * m02);
5057         double invYlen = Math.invsqrt(m10 * m10 + m11 * m11 + m12 * m12);
5058         double invZlen = Math.invsqrt(m20 * m20 + m21 * m21 + m22 * m22);
5059         dest.m00 = m00 * invXlen; dest.m01 = m01 * invXlen; dest.m02 = m02 * invXlen;
5060         dest.m10 = m10 * invYlen; dest.m11 = m11 * invYlen; dest.m12 = m12 * invYlen;
5061         dest.m20 = m20 * invZlen; dest.m21 = m21 * invZlen; dest.m22 = m22 * invZlen;
5062         return dest;
5063     }
5064 
5065     public Matrix3d normalize3x3(Matrix3d dest) {
5066         double invXlen = Math.invsqrt(m00 * m00 + m01 * m01 + m02 * m02);
5067         double invYlen = Math.invsqrt(m10 * m10 + m11 * m11 + m12 * m12);
5068         double invZlen = Math.invsqrt(m20 * m20 + m21 * m21 + m22 * m22);
5069         dest.m00 = (m00 * invXlen); dest.m01 = (m01 * invXlen); dest.m02 = (m02 * invXlen);
5070         dest.m10 = (m10 * invYlen); dest.m11 = (m11 * invYlen); dest.m12 = (m12 * invYlen);
5071         dest.m20 = (m20 * invZlen); dest.m21 = (m21 * invZlen); dest.m22 = (m22 * invZlen);
5072         return dest;
5073     }
5074 
5075     public Matrix4x3d reflect(double a, double b, double c, double d, ref Matrix4x3d dest) {
5076         if ((properties & PROPERTY_IDENTITY) != 0)
5077             return dest.reflection(a, b, c, d);
5078 
5079         double da = a + a, db = b + b, dc = c + c, dd = d + d;
5080         double rm00 = 1.0 - da * a;
5081         double rm01 = -da * b;
5082         double rm02 = -da * c;
5083         double rm10 = -db * a;
5084         double rm11 = 1.0 - db * b;
5085         double rm12 = -db * c;
5086         double rm20 = -dc * a;
5087         double rm21 = -dc * b;
5088         double rm22 = 1.0 - dc * c;
5089         double rm30 = -dd * a;
5090         double rm31 = -dd * b;
5091         double rm32 = -dd * c;
5092 
5093         // matrix multiplication
5094         dest.m30 = m00 * rm30 + m10 * rm31 + m20 * rm32 + m30;
5095         dest.m31 = m01 * rm30 + m11 * rm31 + m21 * rm32 + m31;
5096         dest.m32 = m02 * rm30 + m12 * rm31 + m22 * rm32 + m32;
5097         double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
5098         double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
5099         double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
5100         double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
5101         double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
5102         double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
5103         dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
5104         dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
5105         dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
5106         dest.m00 = nm00;
5107         dest.m01 = nm01;
5108         dest.m02 = nm02;
5109         dest.m10 = nm10;
5110         dest.m11 = nm11;
5111         dest.m12 = nm12;
5112         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
5113 
5114         return dest;
5115     }
5116 
5117     /**
5118      * Apply a mirror/reflection transformation to this matrix that reflects about the given plane
5119      * specified via the equation <code>x*a + y*b + z*c + d = 0</code>.
5120      * <p>
5121      * The vector <code>(a, b, c)</code> must be a unit vector.
5122      * <p>
5123      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the reflection matrix,
5124      * then the new matrix will be <code>M * R</code>. So when transforming a
5125      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
5126      * reflection will be applied first!
5127      * <p>
5128      * Reference: <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/bb281733(v=vs.85).aspx">msdn.microsoft.com</a>
5129      * 
5130      * @param a
5131      *          the x factor in the plane equation
5132      * @param b
5133      *          the y factor in the plane equation
5134      * @param c
5135      *          the z factor in the plane equation
5136      * @param d
5137      *          the constant in the plane equation
5138      * @return this
5139      */
5140     ref public Matrix4x3d reflect(double a, double b, double c, double d) return {
5141         reflect(a, b, c, d, this);
5142         return this;
5143     }
5144 
5145     /**
5146      * Apply a mirror/reflection transformation to this matrix that reflects about the given plane
5147      * specified via the plane normal and a point on the plane.
5148      * <p>
5149      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the reflection matrix,
5150      * then the new matrix will be <code>M * R</code>. So when transforming a
5151      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
5152      * reflection will be applied first!
5153      * 
5154      * @param nx
5155      *          the x-coordinate of the plane normal
5156      * @param ny
5157      *          the y-coordinate of the plane normal
5158      * @param nz
5159      *          the z-coordinate of the plane normal
5160      * @param px
5161      *          the x-coordinate of a point on the plane
5162      * @param py
5163      *          the y-coordinate of a point on the plane
5164      * @param pz
5165      *          the z-coordinate of a point on the plane
5166      * @return this
5167      */
5168     ref public Matrix4x3d reflect(double nx, double ny, double nz, double px, double py, double pz) return {
5169         reflect(nx, ny, nz, px, py, pz, this);
5170         return this;
5171     }
5172 
5173     public Matrix4x3d reflect(double nx, double ny, double nz, double px, double py, double pz, ref Matrix4x3d dest) {
5174         double invLength = Math.invsqrt(nx * nx + ny * ny + nz * nz);
5175         double nnx = nx * invLength;
5176         double nny = ny * invLength;
5177         double nnz = nz * invLength;
5178         /* See: http://mathworld.wolfram.com/Plane.html */
5179         return reflect(nnx, nny, nnz, -nnx * px - nny * py - nnz * pz, dest);
5180     }
5181 
5182     /**
5183      * Apply a mirror/reflection transformation to this matrix that reflects about the given plane
5184      * specified via the plane normal and a point on the plane.
5185      * <p>
5186      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the reflection matrix,
5187      * then the new matrix will be <code>M * R</code>. So when transforming a
5188      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
5189      * reflection will be applied first!
5190      * 
5191      * @param normal
5192      *          the plane normal
5193      * @param point
5194      *          a point on the plane
5195      * @return this
5196      */
5197     ref public Matrix4x3d reflect(Vector3d normal, Vector3d point) return {
5198         return reflect(normal.x, normal.y, normal.z, point.x, point.y, point.z);
5199     }
5200 
5201     /**
5202      * Apply a mirror/reflection transformation to this matrix that reflects about a plane
5203      * specified via the plane orientation and a point on the plane.
5204      * <p>
5205      * This method can be used to build a reflection transformation based on the orientation of a mirror object in the scene.
5206      * It is assumed that the default mirror plane's normal is <code>(0, 0, 1)</code>. So, if the given {@link Quaterniond} is
5207      * the identity (does not apply any additional rotation), the reflection plane will be <code>z=0</code>, offset by the given <code>point</code>.
5208      * <p>
5209      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the reflection matrix,
5210      * then the new matrix will be <code>M * R</code>. So when transforming a
5211      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
5212      * reflection will be applied first!
5213      * 
5214      * @param orientation
5215      *          the plane orientation relative to an implied normal vector of <code>(0, 0, 1)</code>
5216      * @param point
5217      *          a point on the plane
5218      * @return this
5219      */
5220     ref public Matrix4x3d reflect(Quaterniond orientation, Vector3d point) return {
5221         reflect(orientation, point, this);
5222         return this;
5223     }
5224 
5225     public Matrix4x3d reflect(Quaterniond orientation, Vector3d point, ref Matrix4x3d dest) {
5226         double num1 = orientation.x + orientation.x;
5227         double num2 = orientation.y + orientation.y;
5228         double num3 = orientation.z + orientation.z;
5229         double normalX = orientation.x * num3 + orientation.w * num2;
5230         double normalY = orientation.y * num3 - orientation.w * num1;
5231         double normalZ = 1.0 - (orientation.x * num1 + orientation.y * num2);
5232         return reflect(normalX, normalY, normalZ, point.x, point.y, point.z, dest);
5233     }
5234 
5235     public Matrix4x3d reflect(Vector3d normal, Vector3d point, ref Matrix4x3d dest) {
5236         return reflect(normal.x, normal.y, normal.z, point.x, point.y, point.z, dest);
5237     }
5238 
5239     /**
5240      * Set this matrix to a mirror/reflection transformation that reflects about the given plane
5241      * specified via the equation <code>x*a + y*b + z*c + d = 0</code>.
5242      * <p>
5243      * The vector <code>(a, b, c)</code> must be a unit vector.
5244      * <p>
5245      * Reference: <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/bb281733(v=vs.85).aspx">msdn.microsoft.com</a>
5246      * 
5247      * @param a
5248      *          the x factor in the plane equation
5249      * @param b
5250      *          the y factor in the plane equation
5251      * @param c
5252      *          the z factor in the plane equation
5253      * @param d
5254      *          the constant in the plane equation
5255      * @return this
5256      */
5257     ref public Matrix4x3d reflection(double a, double b, double c, double d) return {
5258         double da = a + a, db = b + b, dc = c + c, dd = d + d;
5259         m00 = 1.0 - da * a;
5260         m01 = -da * b;
5261         m02 = -da * c;
5262         m10 = -db * a;
5263         m11 = 1.0 - db * b;
5264         m12 = -db * c;
5265         m20 = -dc * a;
5266         m21 = -dc * b;
5267         m22 = 1.0 - dc * c;
5268         m30 = -dd * a;
5269         m31 = -dd * b;
5270         m32 = -dd * c;
5271         properties = PROPERTY_ORTHONORMAL;
5272         return this;
5273     }
5274 
5275     /**
5276      * Set this matrix to a mirror/reflection transformation that reflects about the given plane
5277      * specified via the plane normal and a point on the plane.
5278      * 
5279      * @param nx
5280      *          the x-coordinate of the plane normal
5281      * @param ny
5282      *          the y-coordinate of the plane normal
5283      * @param nz
5284      *          the z-coordinate of the plane normal
5285      * @param px
5286      *          the x-coordinate of a point on the plane
5287      * @param py
5288      *          the y-coordinate of a point on the plane
5289      * @param pz
5290      *          the z-coordinate of a point on the plane
5291      * @return this
5292      */
5293     ref public Matrix4x3d reflection(double nx, double ny, double nz, double px, double py, double pz) return {
5294         double invLength = Math.invsqrt(nx * nx + ny * ny + nz * nz);
5295         double nnx = nx * invLength;
5296         double nny = ny * invLength;
5297         double nnz = nz * invLength;
5298         /* See: http://mathworld.wolfram.com/Plane.html */
5299         return reflection(nnx, nny, nnz, -nnx * px - nny * py - nnz * pz);
5300     }
5301 
5302     /**
5303      * Set this matrix to a mirror/reflection transformation that reflects about the given plane
5304      * specified via the plane normal and a point on the plane.
5305      * 
5306      * @param normal
5307      *          the plane normal
5308      * @param point
5309      *          a point on the plane
5310      * @return this
5311      */
5312     ref public Matrix4x3d reflection(Vector3d normal, Vector3d point) return {
5313         return reflection(normal.x, normal.y, normal.z, point.x, point.y, point.z);
5314     }
5315 
5316     /**
5317      * Set this matrix to a mirror/reflection transformation that reflects about a plane
5318      * specified via the plane orientation and a point on the plane.
5319      * <p>
5320      * This method can be used to build a reflection transformation based on the orientation of a mirror object in the scene.
5321      * It is assumed that the default mirror plane's normal is <code>(0, 0, 1)</code>. So, if the given {@link Quaterniond} is
5322      * the identity (does not apply any additional rotation), the reflection plane will be <code>z=0</code>, offset by the given <code>point</code>.
5323      * 
5324      * @param orientation
5325      *          the plane orientation
5326      * @param point
5327      *          a point on the plane
5328      * @return this
5329      */
5330     ref public Matrix4x3d reflection(Quaterniond orientation, Vector3d point) return {
5331         double num1 = orientation.x + orientation.x;
5332         double num2 = orientation.y + orientation.y;
5333         double num3 = orientation.z + orientation.z;
5334         double normalX = orientation.x * num3 + orientation.w * num2;
5335         double normalY = orientation.y * num3 - orientation.w * num1;
5336         double normalZ = 1.0 - (orientation.x * num1 + orientation.y * num2);
5337         return reflection(normalX, normalY, normalZ, point.x, point.y, point.z);
5338     }
5339 
5340     /**
5341      * Apply an orthographic projection transformation for a right-handed coordinate system
5342      * using the given NDC z range to this matrix and store the result in <code>dest</code>.
5343      * <p>
5344      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
5345      * then the new matrix will be <code>M * O</code>. So when transforming a
5346      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
5347      * orthographic projection transformation will be applied first!
5348      * <p>
5349      * In order to set the matrix to an orthographic projection without post-multiplying it,
5350      * use {@link #setOrtho(double, double, double, double, double, double, bool) setOrtho()}.
5351      * <p>
5352      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
5353      * 
5354      * @see #setOrtho(double, double, double, double, double, double, bool)
5355      * 
5356      * @param left
5357      *            the distance from the center to the left frustum edge
5358      * @param right
5359      *            the distance from the center to the right frustum edge
5360      * @param bottom
5361      *            the distance from the center to the bottom frustum edge
5362      * @param top
5363      *            the distance from the center to the top frustum edge
5364      * @param zNear
5365      *            near clipping plane distance
5366      * @param zFar
5367      *            far clipping plane distance
5368      * @param zZeroToOne
5369      *            whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code>
5370      *            or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code>
5371      * @param dest
5372      *            will hold the result
5373      * @return dest
5374      */
5375     public Matrix4x3d ortho(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne, ref Matrix4x3d dest) {
5376         // calculate right matrix elements
5377         double rm00 = 2.0 / (right - left);
5378         double rm11 = 2.0 / (top - bottom);
5379         double rm22 = (zZeroToOne ? 1.0 : 2.0) / (zNear - zFar);
5380         double rm30 = (left + right) / (left - right);
5381         double rm31 = (top + bottom) / (bottom - top);
5382         double rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
5383 
5384         // perform optimized multiplication
5385         // compute the last column first, because other columns do not depend on it
5386         dest.m30 = m00 * rm30 + m10 * rm31 + m20 * rm32 + m30;
5387         dest.m31 = m01 * rm30 + m11 * rm31 + m21 * rm32 + m31;
5388         dest.m32 = m02 * rm30 + m12 * rm31 + m22 * rm32 + m32;
5389         dest.m00 = m00 * rm00;
5390         dest.m01 = m01 * rm00;
5391         dest.m02 = m02 * rm00;
5392         dest.m10 = m10 * rm11;
5393         dest.m11 = m11 * rm11;
5394         dest.m12 = m12 * rm11;
5395         dest.m20 = m20 * rm22;
5396         dest.m21 = m21 * rm22;
5397         dest.m22 = m22 * rm22;
5398         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
5399 
5400         return dest;
5401     }
5402 
5403     /**
5404      * Apply an orthographic projection transformation for a right-handed coordinate system
5405      * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>.
5406      * <p>
5407      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
5408      * then the new matrix will be <code>M * O</code>. So when transforming a
5409      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
5410      * orthographic projection transformation will be applied first!
5411      * <p>
5412      * In order to set the matrix to an orthographic projection without post-multiplying it,
5413      * use {@link #setOrtho(double, double, double, double, double, double) setOrtho()}.
5414      * <p>
5415      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
5416      * 
5417      * @see #setOrtho(double, double, double, double, double, double)
5418      * 
5419      * @param left
5420      *            the distance from the center to the left frustum edge
5421      * @param right
5422      *            the distance from the center to the right frustum edge
5423      * @param bottom
5424      *            the distance from the center to the bottom frustum edge
5425      * @param top
5426      *            the distance from the center to the top frustum edge
5427      * @param zNear
5428      *            near clipping plane distance
5429      * @param zFar
5430      *            far clipping plane distance
5431      * @param dest
5432      *            will hold the result
5433      * @return dest
5434      */
5435     public Matrix4x3d ortho(double left, double right, double bottom, double top, double zNear, double zFar, ref Matrix4x3d dest) {
5436         return ortho(left, right, bottom, top, zNear, zFar, false, dest);
5437     }
5438 
5439     /**
5440      * Apply an orthographic projection transformation for a right-handed coordinate system
5441      * using the given NDC z range to this matrix.
5442      * <p>
5443      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
5444      * then the new matrix will be <code>M * O</code>. So when transforming a
5445      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
5446      * orthographic projection transformation will be applied first!
5447      * <p>
5448      * In order to set the matrix to an orthographic projection without post-multiplying it,
5449      * use {@link #setOrtho(double, double, double, double, double, double, bool) setOrtho()}.
5450      * <p>
5451      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
5452      * 
5453      * @see #setOrtho(double, double, double, double, double, double, bool)
5454      * 
5455      * @param left
5456      *            the distance from the center to the left frustum edge
5457      * @param right
5458      *            the distance from the center to the right frustum edge
5459      * @param bottom
5460      *            the distance from the center to the bottom frustum edge
5461      * @param top
5462      *            the distance from the center to the top frustum edge
5463      * @param zNear
5464      *            near clipping plane distance
5465      * @param zFar
5466      *            far clipping plane distance
5467      * @param zZeroToOne
5468      *            whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code>
5469      *            or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code>
5470      * @return this
5471      */
5472     ref public Matrix4x3d ortho(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne) return {
5473         ortho(left, right, bottom, top, zNear, zFar, zZeroToOne, this);
5474         return this;
5475     }
5476 
5477     /**
5478      * Apply an orthographic projection transformation for a right-handed coordinate system
5479      * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix.
5480      * <p>
5481      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
5482      * then the new matrix will be <code>M * O</code>. So when transforming a
5483      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
5484      * orthographic projection transformation will be applied first!
5485      * <p>
5486      * In order to set the matrix to an orthographic projection without post-multiplying it,
5487      * use {@link #setOrtho(double, double, double, double, double, double) setOrtho()}.
5488      * <p>
5489      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
5490      * 
5491      * @see #setOrtho(double, double, double, double, double, double)
5492      * 
5493      * @param left
5494      *            the distance from the center to the left frustum edge
5495      * @param right
5496      *            the distance from the center to the right frustum edge
5497      * @param bottom
5498      *            the distance from the center to the bottom frustum edge
5499      * @param top
5500      *            the distance from the center to the top frustum edge
5501      * @param zNear
5502      *            near clipping plane distance
5503      * @param zFar
5504      *            far clipping plane distance
5505      * @return this
5506      */
5507     ref public Matrix4x3d ortho(double left, double right, double bottom, double top, double zNear, double zFar) return {
5508         return ortho(left, right, bottom, top, zNear, zFar, false);
5509     }
5510 
5511     /**
5512      * Apply an orthographic projection transformation for a left-handed coordiante system
5513      * using the given NDC z range to this matrix and store the result in <code>dest</code>.
5514      * <p>
5515      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
5516      * then the new matrix will be <code>M * O</code>. So when transforming a
5517      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
5518      * orthographic projection transformation will be applied first!
5519      * <p>
5520      * In order to set the matrix to an orthographic projection without post-multiplying it,
5521      * use {@link #setOrthoLH(double, double, double, double, double, double, bool) setOrthoLH()}.
5522      * <p>
5523      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
5524      * 
5525      * @see #setOrthoLH(double, double, double, double, double, double, bool)
5526      * 
5527      * @param left
5528      *            the distance from the center to the left frustum edge
5529      * @param right
5530      *            the distance from the center to the right frustum edge
5531      * @param bottom
5532      *            the distance from the center to the bottom frustum edge
5533      * @param top
5534      *            the distance from the center to the top frustum edge
5535      * @param zNear
5536      *            near clipping plane distance
5537      * @param zFar
5538      *            far clipping plane distance
5539      * @param zZeroToOne
5540      *            whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code>
5541      *            or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code>
5542      * @param dest
5543      *            will hold the result
5544      * @return dest
5545      */
5546     public Matrix4x3d orthoLH(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne, ref Matrix4x3d dest) {
5547         // calculate right matrix elements
5548         double rm00 = 2.0 / (right - left);
5549         double rm11 = 2.0 / (top - bottom);
5550         double rm22 = (zZeroToOne ? 1.0 : 2.0) / (zFar - zNear);
5551         double rm30 = (left + right) / (left - right);
5552         double rm31 = (top + bottom) / (bottom - top);
5553         double rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
5554 
5555         // perform optimized multiplication
5556         // compute the last column first, because other columns do not depend on it
5557         dest.m30 = m00 * rm30 + m10 * rm31 + m20 * rm32 + m30;
5558         dest.m31 = m01 * rm30 + m11 * rm31 + m21 * rm32 + m31;
5559         dest.m32 = m02 * rm30 + m12 * rm31 + m22 * rm32 + m32;
5560         dest.m00 = m00 * rm00;
5561         dest.m01 = m01 * rm00;
5562         dest.m02 = m02 * rm00;
5563         dest.m10 = m10 * rm11;
5564         dest.m11 = m11 * rm11;
5565         dest.m12 = m12 * rm11;
5566         dest.m20 = m20 * rm22;
5567         dest.m21 = m21 * rm22;
5568         dest.m22 = m22 * rm22;
5569         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
5570 
5571         return dest;
5572     }
5573 
5574     /**
5575      * Apply an orthographic projection transformation for a left-handed coordiante system
5576      * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>.
5577      * <p>
5578      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
5579      * then the new matrix will be <code>M * O</code>. So when transforming a
5580      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
5581      * orthographic projection transformation will be applied first!
5582      * <p>
5583      * In order to set the matrix to an orthographic projection without post-multiplying it,
5584      * use {@link #setOrthoLH(double, double, double, double, double, double) setOrthoLH()}.
5585      * <p>
5586      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
5587      * 
5588      * @see #setOrthoLH(double, double, double, double, double, double)
5589      * 
5590      * @param left
5591      *            the distance from the center to the left frustum edge
5592      * @param right
5593      *            the distance from the center to the right frustum edge
5594      * @param bottom
5595      *            the distance from the center to the bottom frustum edge
5596      * @param top
5597      *            the distance from the center to the top frustum edge
5598      * @param zNear
5599      *            near clipping plane distance
5600      * @param zFar
5601      *            far clipping plane distance
5602      * @param dest
5603      *            will hold the result
5604      * @return dest
5605      */
5606     public Matrix4x3d orthoLH(double left, double right, double bottom, double top, double zNear, double zFar, ref Matrix4x3d dest) {
5607         return orthoLH(left, right, bottom, top, zNear, zFar, false, dest);
5608     }
5609 
5610     /**
5611      * Apply an orthographic projection transformation for a left-handed coordiante system
5612      * using the given NDC z range to this matrix.
5613      * <p>
5614      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
5615      * then the new matrix will be <code>M * O</code>. So when transforming a
5616      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
5617      * orthographic projection transformation will be applied first!
5618      * <p>
5619      * In order to set the matrix to an orthographic projection without post-multiplying it,
5620      * use {@link #setOrthoLH(double, double, double, double, double, double, bool) setOrthoLH()}.
5621      * <p>
5622      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
5623      * 
5624      * @see #setOrthoLH(double, double, double, double, double, double, bool)
5625      * 
5626      * @param left
5627      *            the distance from the center to the left frustum edge
5628      * @param right
5629      *            the distance from the center to the right frustum edge
5630      * @param bottom
5631      *            the distance from the center to the bottom frustum edge
5632      * @param top
5633      *            the distance from the center to the top frustum edge
5634      * @param zNear
5635      *            near clipping plane distance
5636      * @param zFar
5637      *            far clipping plane distance
5638      * @param zZeroToOne
5639      *            whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code>
5640      *            or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code>
5641      * @return this
5642      */
5643     ref public Matrix4x3d orthoLH(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne) return {
5644         orthoLH(left, right, bottom, top, zNear, zFar, zZeroToOne, this);
5645         return this;
5646     }
5647 
5648     /**
5649      * Apply an orthographic projection transformation for a left-handed coordiante system
5650      * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix.
5651      * <p>
5652      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
5653      * then the new matrix will be <code>M * O</code>. So when transforming a
5654      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
5655      * orthographic projection transformation will be applied first!
5656      * <p>
5657      * In order to set the matrix to an orthographic projection without post-multiplying it,
5658      * use {@link #setOrthoLH(double, double, double, double, double, double) setOrthoLH()}.
5659      * <p>
5660      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
5661      * 
5662      * @see #setOrthoLH(double, double, double, double, double, double)
5663      * 
5664      * @param left
5665      *            the distance from the center to the left frustum edge
5666      * @param right
5667      *            the distance from the center to the right frustum edge
5668      * @param bottom
5669      *            the distance from the center to the bottom frustum edge
5670      * @param top
5671      *            the distance from the center to the top frustum edge
5672      * @param zNear
5673      *            near clipping plane distance
5674      * @param zFar
5675      *            far clipping plane distance
5676      * @return this
5677      */
5678     ref public Matrix4x3d orthoLH(double left, double right, double bottom, double top, double zNear, double zFar) return {
5679         return orthoLH(left, right, bottom, top, zNear, zFar, false);
5680     }
5681 
5682     /**
5683      * Set this matrix to be an orthographic projection transformation for a right-handed coordinate system
5684      * using the given NDC z range.
5685      * <p>
5686      * In order to apply the orthographic projection to an already existing transformation,
5687      * use {@link #ortho(double, double, double, double, double, double, bool) ortho()}.
5688      * <p>
5689      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
5690      * 
5691      * @see #ortho(double, double, double, double, double, double, bool)
5692      * 
5693      * @param left
5694      *            the distance from the center to the left frustum edge
5695      * @param right
5696      *            the distance from the center to the right frustum edge
5697      * @param bottom
5698      *            the distance from the center to the bottom frustum edge
5699      * @param top
5700      *            the distance from the center to the top frustum edge
5701      * @param zNear
5702      *            near clipping plane distance
5703      * @param zFar
5704      *            far clipping plane distance
5705      * @param zZeroToOne
5706      *            whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code>
5707      *            or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code>
5708      * @return this
5709      */
5710     ref public Matrix4x3d setOrtho(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne) return {
5711         m00 = 2.0 / (right - left);
5712         m01 = 0.0;
5713         m02 = 0.0;
5714         m10 = 0.0;
5715         m11 = 2.0 / (top - bottom);
5716         m12 = 0.0;
5717         m20 = 0.0;
5718         m21 = 0.0;
5719         m22 = (zZeroToOne ? 1.0 : 2.0) / (zNear - zFar);
5720         m30 = (right + left) / (left - right);
5721         m31 = (top + bottom) / (bottom - top);
5722         m32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
5723         properties = 0;
5724         return this;
5725     }
5726 
5727     /**
5728      * Set this matrix to be an orthographic projection transformation for a right-handed coordinate system
5729      * using OpenGL's NDC z range of <code>[-1..+1]</code>.
5730      * <p>
5731      * In order to apply the orthographic projection to an already existing transformation,
5732      * use {@link #ortho(double, double, double, double, double, double) ortho()}.
5733      * <p>
5734      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
5735      * 
5736      * @see #ortho(double, double, double, double, double, double)
5737      * 
5738      * @param left
5739      *            the distance from the center to the left frustum edge
5740      * @param right
5741      *            the distance from the center to the right frustum edge
5742      * @param bottom
5743      *            the distance from the center to the bottom frustum edge
5744      * @param top
5745      *            the distance from the center to the top frustum edge
5746      * @param zNear
5747      *            near clipping plane distance
5748      * @param zFar
5749      *            far clipping plane distance
5750      * @return this
5751      */
5752     ref public Matrix4x3d setOrtho(double left, double right, double bottom, double top, double zNear, double zFar) return {
5753         return setOrtho(left, right, bottom, top, zNear, zFar, false);
5754     }
5755 
5756     /**
5757      * Set this matrix to be an orthographic projection transformation for a left-handed coordinate system
5758      * using the given NDC z range.
5759      * <p>
5760      * In order to apply the orthographic projection to an already existing transformation,
5761      * use {@link #orthoLH(double, double, double, double, double, double, bool) orthoLH()}.
5762      * <p>
5763      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
5764      * 
5765      * @see #orthoLH(double, double, double, double, double, double, bool)
5766      * 
5767      * @param left
5768      *            the distance from the center to the left frustum edge
5769      * @param right
5770      *            the distance from the center to the right frustum edge
5771      * @param bottom
5772      *            the distance from the center to the bottom frustum edge
5773      * @param top
5774      *            the distance from the center to the top frustum edge
5775      * @param zNear
5776      *            near clipping plane distance
5777      * @param zFar
5778      *            far clipping plane distance
5779      * @param zZeroToOne
5780      *            whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code>
5781      *            or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code>
5782      * @return this
5783      */
5784     ref public Matrix4x3d setOrthoLH(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne) return {
5785         m00 = 2.0 / (right - left);
5786         m01 = 0.0;
5787         m02 = 0.0;
5788         m10 = 0.0;
5789         m11 = 2.0 / (top - bottom);
5790         m12 = 0.0;
5791         m20 = 0.0;
5792         m21 = 0.0;
5793         m22 = (zZeroToOne ? 1.0 : 2.0) / (zFar - zNear);
5794         m30 = (right + left) / (left - right);
5795         m31 = (top + bottom) / (bottom - top);
5796         m32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
5797         properties = 0;
5798         return this;
5799     }
5800 
5801     /**
5802      * Set this matrix to be an orthographic projection transformation for a left-handed coordinate system
5803      * using OpenGL's NDC z range of <code>[-1..+1]</code>.
5804      * <p>
5805      * In order to apply the orthographic projection to an already existing transformation,
5806      * use {@link #orthoLH(double, double, double, double, double, double) orthoLH()}.
5807      * <p>
5808      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
5809      * 
5810      * @see #orthoLH(double, double, double, double, double, double)
5811      * 
5812      * @param left
5813      *            the distance from the center to the left frustum edge
5814      * @param right
5815      *            the distance from the center to the right frustum edge
5816      * @param bottom
5817      *            the distance from the center to the bottom frustum edge
5818      * @param top
5819      *            the distance from the center to the top frustum edge
5820      * @param zNear
5821      *            near clipping plane distance
5822      * @param zFar
5823      *            far clipping plane distance
5824      * @return this
5825      */
5826     ref public Matrix4x3d setOrthoLH(double left, double right, double bottom, double top, double zNear, double zFar) return {
5827         return setOrthoLH(left, right, bottom, top, zNear, zFar, false);
5828     }
5829 
5830     /**
5831      * Apply a symmetric orthographic projection transformation for a right-handed coordinate system
5832      * using the given NDC z range to this matrix and store the result in <code>dest</code>.
5833      * <p>
5834      * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double, bool, Matrix4x3d) ortho()} with
5835      * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>.
5836      * <p>
5837      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
5838      * then the new matrix will be <code>M * O</code>. So when transforming a
5839      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
5840      * orthographic projection transformation will be applied first!
5841      * <p>
5842      * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
5843      * use {@link #setOrthoSymmetric(double, double, double, double, bool) setOrthoSymmetric()}.
5844      * <p>
5845      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
5846      * 
5847      * @see #setOrthoSymmetric(double, double, double, double, bool)
5848      * 
5849      * @param width
5850      *            the distance between the right and left frustum edges
5851      * @param height
5852      *            the distance between the top and bottom frustum edges
5853      * @param zNear
5854      *            near clipping plane distance
5855      * @param zFar
5856      *            far clipping plane distance
5857      * @param dest
5858      *            will hold the result
5859      * @param zZeroToOne
5860      *            whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code>
5861      *            or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code>
5862      * @return dest
5863      */
5864     public Matrix4x3d orthoSymmetric(double width, double height, double zNear, double zFar, bool zZeroToOne, ref Matrix4x3d dest) {
5865         // calculate right matrix elements
5866         double rm00 = 2.0 / width;
5867         double rm11 = 2.0 / height;
5868         double rm22 = (zZeroToOne ? 1.0 : 2.0) / (zNear - zFar);
5869         double rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
5870 
5871         // perform optimized multiplication
5872         // compute the last column first, because other columns do not depend on it
5873         dest.m30 = m20 * rm32 + m30;
5874         dest.m31 = m21 * rm32 + m31;
5875         dest.m32 = m22 * rm32 + m32;
5876         dest.m00 = m00 * rm00;
5877         dest.m01 = m01 * rm00;
5878         dest.m02 = m02 * rm00;
5879         dest.m10 = m10 * rm11;
5880         dest.m11 = m11 * rm11;
5881         dest.m12 = m12 * rm11;
5882         dest.m20 = m20 * rm22;
5883         dest.m21 = m21 * rm22;
5884         dest.m22 = m22 * rm22;
5885         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
5886 
5887         return dest;
5888     }
5889 
5890     /**
5891      * Apply a symmetric orthographic projection transformation for a right-handed coordinate system
5892      * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>.
5893      * <p>
5894      * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double, Matrix4x3d) ortho()} with
5895      * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>.
5896      * <p>
5897      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
5898      * then the new matrix will be <code>M * O</code>. So when transforming a
5899      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
5900      * orthographic projection transformation will be applied first!
5901      * <p>
5902      * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
5903      * use {@link #setOrthoSymmetric(double, double, double, double) setOrthoSymmetric()}.
5904      * <p>
5905      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
5906      * 
5907      * @see #setOrthoSymmetric(double, double, double, double)
5908      * 
5909      * @param width
5910      *            the distance between the right and left frustum edges
5911      * @param height
5912      *            the distance between the top and bottom frustum edges
5913      * @param zNear
5914      *            near clipping plane distance
5915      * @param zFar
5916      *            far clipping plane distance
5917      * @param dest
5918      *            will hold the result
5919      * @return dest
5920      */
5921     public Matrix4x3d orthoSymmetric(double width, double height, double zNear, double zFar, ref Matrix4x3d dest) {
5922         return orthoSymmetric(width, height, zNear, zFar, false, dest);
5923     }
5924 
5925     /**
5926      * Apply a symmetric orthographic projection transformation for a right-handed coordinate system
5927      * using the given NDC z range to this matrix.
5928      * <p>
5929      * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double, bool) ortho()} with
5930      * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>.
5931      * <p>
5932      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
5933      * then the new matrix will be <code>M * O</code>. So when transforming a
5934      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
5935      * orthographic projection transformation will be applied first!
5936      * <p>
5937      * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
5938      * use {@link #setOrthoSymmetric(double, double, double, double, bool) setOrthoSymmetric()}.
5939      * <p>
5940      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
5941      * 
5942      * @see #setOrthoSymmetric(double, double, double, double, bool)
5943      * 
5944      * @param width
5945      *            the distance between the right and left frustum edges
5946      * @param height
5947      *            the distance between the top and bottom frustum edges
5948      * @param zNear
5949      *            near clipping plane distance
5950      * @param zFar
5951      *            far clipping plane distance
5952      * @param zZeroToOne
5953      *            whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code>
5954      *            or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code>
5955      * @return this
5956      */
5957     ref public Matrix4x3d orthoSymmetric(double width, double height, double zNear, double zFar, bool zZeroToOne) return {
5958         orthoSymmetric(width, height, zNear, zFar, zZeroToOne, this);
5959         return this;
5960     }
5961 
5962     /**
5963      * Apply a symmetric orthographic projection transformation for a right-handed coordinate system
5964      * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix.
5965      * <p>
5966      * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double) ortho()} with
5967      * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>.
5968      * <p>
5969      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
5970      * then the new matrix will be <code>M * O</code>. So when transforming a
5971      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
5972      * orthographic projection transformation will be applied first!
5973      * <p>
5974      * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
5975      * use {@link #setOrthoSymmetric(double, double, double, double) setOrthoSymmetric()}.
5976      * <p>
5977      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
5978      * 
5979      * @see #setOrthoSymmetric(double, double, double, double)
5980      * 
5981      * @param width
5982      *            the distance between the right and left frustum edges
5983      * @param height
5984      *            the distance between the top and bottom frustum edges
5985      * @param zNear
5986      *            near clipping plane distance
5987      * @param zFar
5988      *            far clipping plane distance
5989      * @return this
5990      */
5991     ref public Matrix4x3d orthoSymmetric(double width, double height, double zNear, double zFar) return {
5992         orthoSymmetric(width, height, zNear, zFar, false, this);
5993         return this;
5994     }
5995 
5996     /**
5997      * Apply a symmetric orthographic projection transformation for a left-handed coordinate system
5998      * using the given NDC z range to this matrix and store the result in <code>dest</code>.
5999      * <p>
6000      * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double, bool, Matrix4x3d) orthoLH()} with
6001      * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>.
6002      * <p>
6003      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
6004      * then the new matrix will be <code>M * O</code>. So when transforming a
6005      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
6006      * orthographic projection transformation will be applied first!
6007      * <p>
6008      * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
6009      * use {@link #setOrthoSymmetricLH(double, double, double, double, bool) setOrthoSymmetricLH()}.
6010      * <p>
6011      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
6012      * 
6013      * @see #setOrthoSymmetricLH(double, double, double, double, bool)
6014      * 
6015      * @param width
6016      *            the distance between the right and left frustum edges
6017      * @param height
6018      *            the distance between the top and bottom frustum edges
6019      * @param zNear
6020      *            near clipping plane distance
6021      * @param zFar
6022      *            far clipping plane distance
6023      * @param dest
6024      *            will hold the result
6025      * @param zZeroToOne
6026      *            whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code>
6027      *            or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code>
6028      * @return dest
6029      */
6030     public Matrix4x3d orthoSymmetricLH(double width, double height, double zNear, double zFar, bool zZeroToOne, ref Matrix4x3d dest) {
6031         // calculate right matrix elements
6032         double rm00 = 2.0 / width;
6033         double rm11 = 2.0 / height;
6034         double rm22 = (zZeroToOne ? 1.0 : 2.0) / (zFar - zNear);
6035         double rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
6036 
6037         // perform optimized multiplication
6038         // compute the last column first, because other columns do not depend on it
6039         dest.m30 = m20 * rm32 + m30;
6040         dest.m31 = m21 * rm32 + m31;
6041         dest.m32 = m22 * rm32 + m32;
6042         dest.m00 = m00 * rm00;
6043         dest.m01 = m01 * rm00;
6044         dest.m02 = m02 * rm00;
6045         dest.m10 = m10 * rm11;
6046         dest.m11 = m11 * rm11;
6047         dest.m12 = m12 * rm11;
6048         dest.m20 = m20 * rm22;
6049         dest.m21 = m21 * rm22;
6050         dest.m22 = m22 * rm22;
6051         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
6052 
6053         return dest;
6054     }
6055 
6056     /**
6057      * Apply a symmetric orthographic projection transformation for a left-handed coordinate system
6058      * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>.
6059      * <p>
6060      * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double, Matrix4x3d) orthoLH()} with
6061      * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>.
6062      * <p>
6063      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
6064      * then the new matrix will be <code>M * O</code>. So when transforming a
6065      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
6066      * orthographic projection transformation will be applied first!
6067      * <p>
6068      * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
6069      * use {@link #setOrthoSymmetricLH(double, double, double, double) setOrthoSymmetricLH()}.
6070      * <p>
6071      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
6072      * 
6073      * @see #setOrthoSymmetricLH(double, double, double, double)
6074      * 
6075      * @param width
6076      *            the distance between the right and left frustum edges
6077      * @param height
6078      *            the distance between the top and bottom frustum edges
6079      * @param zNear
6080      *            near clipping plane distance
6081      * @param zFar
6082      *            far clipping plane distance
6083      * @param dest
6084      *            will hold the result
6085      * @return dest
6086      */
6087     public Matrix4x3d orthoSymmetricLH(double width, double height, double zNear, double zFar, ref Matrix4x3d dest) {
6088         return orthoSymmetricLH(width, height, zNear, zFar, false, dest);
6089     }
6090 
6091     /**
6092      * Apply a symmetric orthographic projection transformation for a left-handed coordinate system
6093      * using the given NDC z range to this matrix.
6094      * <p>
6095      * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double, bool) orthoLH()} with
6096      * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>.
6097      * <p>
6098      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
6099      * then the new matrix will be <code>M * O</code>. So when transforming a
6100      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
6101      * orthographic projection transformation will be applied first!
6102      * <p>
6103      * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
6104      * use {@link #setOrthoSymmetricLH(double, double, double, double, bool) setOrthoSymmetricLH()}.
6105      * <p>
6106      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
6107      * 
6108      * @see #setOrthoSymmetricLH(double, double, double, double, bool)
6109      * 
6110      * @param width
6111      *            the distance between the right and left frustum edges
6112      * @param height
6113      *            the distance between the top and bottom frustum edges
6114      * @param zNear
6115      *            near clipping plane distance
6116      * @param zFar
6117      *            far clipping plane distance
6118      * @param zZeroToOne
6119      *            whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code>
6120      *            or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code>
6121      * @return this
6122      */
6123     ref public Matrix4x3d orthoSymmetricLH(double width, double height, double zNear, double zFar, bool zZeroToOne) return {
6124         orthoSymmetricLH(width, height, zNear, zFar, zZeroToOne, this);
6125         return this;
6126     }
6127 
6128     /**
6129      * Apply a symmetric orthographic projection transformation for a left-handed coordinate system
6130      * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix.
6131      * <p>
6132      * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double) orthoLH()} with
6133      * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>.
6134      * <p>
6135      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
6136      * then the new matrix will be <code>M * O</code>. So when transforming a
6137      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
6138      * orthographic projection transformation will be applied first!
6139      * <p>
6140      * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
6141      * use {@link #setOrthoSymmetricLH(double, double, double, double) setOrthoSymmetricLH()}.
6142      * <p>
6143      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
6144      * 
6145      * @see #setOrthoSymmetricLH(double, double, double, double)
6146      * 
6147      * @param width
6148      *            the distance between the right and left frustum edges
6149      * @param height
6150      *            the distance between the top and bottom frustum edges
6151      * @param zNear
6152      *            near clipping plane distance
6153      * @param zFar
6154      *            far clipping plane distance
6155      * @return this
6156      */
6157     ref public Matrix4x3d orthoSymmetricLH(double width, double height, double zNear, double zFar) return {
6158         orthoSymmetricLH(width, height, zNear, zFar, false, this);
6159         return this;
6160     }
6161 
6162     /**
6163      * Set this matrix to be a symmetric orthographic projection transformation for a right-handed coordinate system
6164      * using the given NDC z range.
6165      * <p>
6166      * This method is equivalent to calling {@link #setOrtho(double, double, double, double, double, double, bool) setOrtho()} with
6167      * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>.
6168      * <p>
6169      * In order to apply the symmetric orthographic projection to an already existing transformation,
6170      * use {@link #orthoSymmetric(double, double, double, double, bool) orthoSymmetric()}.
6171      * <p>
6172      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
6173      * 
6174      * @see #orthoSymmetric(double, double, double, double, bool)
6175      * 
6176      * @param width
6177      *            the distance between the right and left frustum edges
6178      * @param height
6179      *            the distance between the top and bottom frustum edges
6180      * @param zNear
6181      *            near clipping plane distance
6182      * @param zFar
6183      *            far clipping plane distance
6184      * @param zZeroToOne
6185      *            whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code>
6186      *            or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code>
6187      * @return this
6188      */
6189     ref public Matrix4x3d setOrthoSymmetric(double width, double height, double zNear, double zFar, bool zZeroToOne) return {
6190         m00 = 2.0 / width;
6191         m01 = 0.0;
6192         m02 = 0.0;
6193         m10 = 0.0;
6194         m11 = 2.0 / height;
6195         m12 = 0.0;
6196         m20 = 0.0;
6197         m21 = 0.0;
6198         m22 = (zZeroToOne ? 1.0 : 2.0) / (zNear - zFar);
6199         m30 = 0.0;
6200         m31 = 0.0;
6201         m32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
6202         properties = 0;
6203         return this;
6204     }
6205 
6206     /**
6207      * Set this matrix to be a symmetric orthographic projection transformation for a right-handed coordinate system
6208      * using OpenGL's NDC z range of <code>[-1..+1]</code>.
6209      * <p>
6210      * This method is equivalent to calling {@link #setOrtho(double, double, double, double, double, double) setOrtho()} with
6211      * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>.
6212      * <p>
6213      * In order to apply the symmetric orthographic projection to an already existing transformation,
6214      * use {@link #orthoSymmetric(double, double, double, double) orthoSymmetric()}.
6215      * <p>
6216      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
6217      * 
6218      * @see #orthoSymmetric(double, double, double, double)
6219      * 
6220      * @param width
6221      *            the distance between the right and left frustum edges
6222      * @param height
6223      *            the distance between the top and bottom frustum edges
6224      * @param zNear
6225      *            near clipping plane distance
6226      * @param zFar
6227      *            far clipping plane distance
6228      * @return this
6229      */
6230     ref public Matrix4x3d setOrthoSymmetric(double width, double height, double zNear, double zFar) return {
6231         return setOrthoSymmetric(width, height, zNear, zFar, false);
6232     }
6233 
6234     /**
6235      * Set this matrix to be a symmetric orthographic projection transformation for a left-handed coordinate system using the given NDC z range.
6236      * <p>
6237      * This method is equivalent to calling {@link #setOrtho(double, double, double, double, double, double, bool) setOrtho()} with
6238      * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>.
6239      * <p>
6240      * In order to apply the symmetric orthographic projection to an already existing transformation,
6241      * use {@link #orthoSymmetricLH(double, double, double, double, bool) orthoSymmetricLH()}.
6242      * <p>
6243      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
6244      * 
6245      * @see #orthoSymmetricLH(double, double, double, double, bool)
6246      * 
6247      * @param width
6248      *            the distance between the right and left frustum edges
6249      * @param height
6250      *            the distance between the top and bottom frustum edges
6251      * @param zNear
6252      *            near clipping plane distance
6253      * @param zFar
6254      *            far clipping plane distance
6255      * @param zZeroToOne
6256      *            whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code>
6257      *            or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code>
6258      * @return this
6259      */
6260     ref public Matrix4x3d setOrthoSymmetricLH(double width, double height, double zNear, double zFar, bool zZeroToOne) return {
6261         m00 = 2.0 / width;
6262         m01 = 0.0;
6263         m02 = 0.0;
6264         m10 = 0.0;
6265         m11 = 2.0 / height;
6266         m12 = 0.0;
6267         m20 = 0.0;
6268         m21 = 0.0;
6269         m22 = (zZeroToOne ? 1.0 : 2.0) / (zFar - zNear);
6270         m30 = 0.0;
6271         m31 = 0.0;
6272         m32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
6273         properties = 0;
6274         return this;
6275     }
6276 
6277     /**
6278      * Set this matrix to be a symmetric orthographic projection transformation for a left-handed coordinate system
6279      * using OpenGL's NDC z range of <code>[-1..+1]</code>.
6280      * <p>
6281      * This method is equivalent to calling {@link #setOrthoLH(double, double, double, double, double, double) setOrthoLH()} with
6282      * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>.
6283      * <p>
6284      * In order to apply the symmetric orthographic projection to an already existing transformation,
6285      * use {@link #orthoSymmetricLH(double, double, double, double) orthoSymmetricLH()}.
6286      * <p>
6287      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
6288      * 
6289      * @see #orthoSymmetricLH(double, double, double, double)
6290      * 
6291      * @param width
6292      *            the distance between the right and left frustum edges
6293      * @param height
6294      *            the distance between the top and bottom frustum edges
6295      * @param zNear
6296      *            near clipping plane distance
6297      * @param zFar
6298      *            far clipping plane distance
6299      * @return this
6300      */
6301     ref public Matrix4x3d setOrthoSymmetricLH(double width, double height, double zNear, double zFar) return {
6302         return setOrthoSymmetricLH(width, height, zNear, zFar, false);
6303     }
6304 
6305     /**
6306      * Apply an orthographic projection transformation for a right-handed coordinate system
6307      * to this matrix and store the result in <code>dest</code>.
6308      * <p>
6309      * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double, Matrix4x3d) ortho()} with
6310      * <code>zNear=-1</code> and <code>zFar=+1</code>.
6311      * <p>
6312      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
6313      * then the new matrix will be <code>M * O</code>. So when transforming a
6314      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
6315      * orthographic projection transformation will be applied first!
6316      * <p>
6317      * In order to set the matrix to an orthographic projection without post-multiplying it,
6318      * use {@link #setOrtho2D(double, double, double, double) setOrtho()}.
6319      * <p>
6320      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
6321      * 
6322      * @see #ortho(double, double, double, double, double, double, Matrix4x3d)
6323      * @see #setOrtho2D(double, double, double, double)
6324      * 
6325      * @param left
6326      *            the distance from the center to the left frustum edge
6327      * @param right
6328      *            the distance from the center to the right frustum edge
6329      * @param bottom
6330      *            the distance from the center to the bottom frustum edge
6331      * @param top
6332      *            the distance from the center to the top frustum edge
6333      * @param dest
6334      *            will hold the result
6335      * @return dest
6336      */
6337     public Matrix4x3d ortho2D(double left, double right, double bottom, double top, ref Matrix4x3d dest) {
6338         // calculate right matrix elements
6339         double rm00 = 2.0 / (right - left);
6340         double rm11 = 2.0 / (top - bottom);
6341         double rm30 = -(right + left) / (right - left);
6342         double rm31 = -(top + bottom) / (top - bottom);
6343 
6344         // perform optimized multiplication
6345         // compute the last column first, because other columns do not depend on it
6346         dest.m30 = m00 * rm30 + m10 * rm31 + m30;
6347         dest.m31 = m01 * rm30 + m11 * rm31 + m31;
6348         dest.m32 = m02 * rm30 + m12 * rm31 + m32;
6349         dest.m00 = m00 * rm00;
6350         dest.m01 = m01 * rm00;
6351         dest.m02 = m02 * rm00;
6352         dest.m10 = m10 * rm11;
6353         dest.m11 = m11 * rm11;
6354         dest.m12 = m12 * rm11;
6355         dest.m20 = -m20;
6356         dest.m21 = -m21;
6357         dest.m22 = -m22;
6358         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
6359 
6360         return dest;
6361     }
6362 
6363     /**
6364      * Apply an orthographic projection transformation for a right-handed coordinate system to this matrix.
6365      * <p>
6366      * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double) ortho()} with
6367      * <code>zNear=-1</code> and <code>zFar=+1</code>.
6368      * <p>
6369      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
6370      * then the new matrix will be <code>M * O</code>. So when transforming a
6371      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
6372      * orthographic projection transformation will be applied first!
6373      * <p>
6374      * In order to set the matrix to an orthographic projection without post-multiplying it,
6375      * use {@link #setOrtho2D(double, double, double, double) setOrtho2D()}.
6376      * <p>
6377      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
6378      * 
6379      * @see #ortho(double, double, double, double, double, double)
6380      * @see #setOrtho2D(double, double, double, double)
6381      * 
6382      * @param left
6383      *            the distance from the center to the left frustum edge
6384      * @param right
6385      *            the distance from the center to the right frustum edge
6386      * @param bottom
6387      *            the distance from the center to the bottom frustum edge
6388      * @param top
6389      *            the distance from the center to the top frustum edge
6390      * @return this
6391      */
6392     ref public Matrix4x3d ortho2D(double left, double right, double bottom, double top) return {
6393         ortho2D(left, right, bottom, top, this);
6394         return this;
6395     }
6396 
6397     /**
6398      * Apply an orthographic projection transformation for a left-handed coordinate system to this matrix and store the result in <code>dest</code>.
6399      * <p>
6400      * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double, Matrix4x3d) orthoLH()} with
6401      * <code>zNear=-1</code> and <code>zFar=+1</code>.
6402      * <p>
6403      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
6404      * then the new matrix will be <code>M * O</code>. So when transforming a
6405      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
6406      * orthographic projection transformation will be applied first!
6407      * <p>
6408      * In order to set the matrix to an orthographic projection without post-multiplying it,
6409      * use {@link #setOrtho2DLH(double, double, double, double) setOrthoLH()}.
6410      * <p>
6411      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
6412      * 
6413      * @see #orthoLH(double, double, double, double, double, double, Matrix4x3d)
6414      * @see #setOrtho2DLH(double, double, double, double)
6415      * 
6416      * @param left
6417      *            the distance from the center to the left frustum edge
6418      * @param right
6419      *            the distance from the center to the right frustum edge
6420      * @param bottom
6421      *            the distance from the center to the bottom frustum edge
6422      * @param top
6423      *            the distance from the center to the top frustum edge
6424      * @param dest
6425      *            will hold the result
6426      * @return dest
6427      */
6428     public Matrix4x3d ortho2DLH(double left, double right, double bottom, double top, ref Matrix4x3d dest) {
6429         // calculate right matrix elements
6430         double rm00 = 2.0 / (right - left);
6431         double rm11 = 2.0 / (top - bottom);
6432         double rm30 = -(right + left) / (right - left);
6433         double rm31 = -(top + bottom) / (top - bottom);
6434 
6435         // perform optimized multiplication
6436         // compute the last column first, because other columns do not depend on it
6437         dest.m30 = m00 * rm30 + m10 * rm31 + m30;
6438         dest.m31 = m01 * rm30 + m11 * rm31 + m31;
6439         dest.m32 = m02 * rm30 + m12 * rm31 + m32;
6440         dest.m00 = m00 * rm00;
6441         dest.m01 = m01 * rm00;
6442         dest.m02 = m02 * rm00;
6443         dest.m10 = m10 * rm11;
6444         dest.m11 = m11 * rm11;
6445         dest.m12 = m12 * rm11;
6446         dest.m20 = m20;
6447         dest.m21 = m21;
6448         dest.m22 = m22;
6449         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
6450 
6451         return dest;
6452     }
6453 
6454     /**
6455      * Apply an orthographic projection transformation for a left-handed coordinate system to this matrix.
6456      * <p>
6457      * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double) orthoLH()} with
6458      * <code>zNear=-1</code> and <code>zFar=+1</code>.
6459      * <p>
6460      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
6461      * then the new matrix will be <code>M * O</code>. So when transforming a
6462      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
6463      * orthographic projection transformation will be applied first!
6464      * <p>
6465      * In order to set the matrix to an orthographic projection without post-multiplying it,
6466      * use {@link #setOrtho2DLH(double, double, double, double) setOrtho2DLH()}.
6467      * <p>
6468      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
6469      * 
6470      * @see #orthoLH(double, double, double, double, double, double)
6471      * @see #setOrtho2DLH(double, double, double, double)
6472      * 
6473      * @param left
6474      *            the distance from the center to the left frustum edge
6475      * @param right
6476      *            the distance from the center to the right frustum edge
6477      * @param bottom
6478      *            the distance from the center to the bottom frustum edge
6479      * @param top
6480      *            the distance from the center to the top frustum edge
6481      * @return this
6482      */
6483     ref public Matrix4x3d ortho2DLH(double left, double right, double bottom, double top) return {
6484         ortho2DLH(left, right, bottom, top, this);
6485         return this;
6486     }
6487 
6488     /**
6489      * Set this matrix to be an orthographic projection transformation for a right-handed coordinate system.
6490      * <p>
6491      * This method is equivalent to calling {@link #setOrtho(double, double, double, double, double, double) setOrtho()} with
6492      * <code>zNear=-1</code> and <code>zFar=+1</code>.
6493      * <p>
6494      * In order to apply the orthographic projection to an already existing transformation,
6495      * use {@link #ortho2D(double, double, double, double) ortho2D()}.
6496      * <p>
6497      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
6498      * 
6499      * @see #setOrtho(double, double, double, double, double, double)
6500      * @see #ortho2D(double, double, double, double)
6501      * 
6502      * @param left
6503      *            the distance from the center to the left frustum edge
6504      * @param right
6505      *            the distance from the center to the right frustum edge
6506      * @param bottom
6507      *            the distance from the center to the bottom frustum edge
6508      * @param top
6509      *            the distance from the center to the top frustum edge
6510      * @return this
6511      */
6512     ref public Matrix4x3d setOrtho2D(double left, double right, double bottom, double top) return {
6513         m00 = 2.0 / (right - left);
6514         m01 = 0.0;
6515         m02 = 0.0;
6516         m10 = 0.0;
6517         m11 = 2.0 / (top - bottom);
6518         m12 = 0.0;
6519         m20 = 0.0;
6520         m21 = 0.0;
6521         m22 = -1.0;
6522         m30 = -(right + left) / (right - left);
6523         m31 = -(top + bottom) / (top - bottom);
6524         m32 = 0.0;
6525         properties = 0;
6526         return this;
6527     }
6528 
6529     /**
6530      * Set this matrix to be an orthographic projection transformation for a left-handed coordinate system.
6531      * <p>
6532      * This method is equivalent to calling {@link #setOrtho(double, double, double, double, double, double) setOrthoLH()} with
6533      * <code>zNear=-1</code> and <code>zFar=+1</code>.
6534      * <p>
6535      * In order to apply the orthographic projection to an already existing transformation,
6536      * use {@link #ortho2DLH(double, double, double, double) ortho2DLH()}.
6537      * <p>
6538      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
6539      * 
6540      * @see #setOrthoLH(double, double, double, double, double, double)
6541      * @see #ortho2DLH(double, double, double, double)
6542      * 
6543      * @param left
6544      *            the distance from the center to the left frustum edge
6545      * @param right
6546      *            the distance from the center to the right frustum edge
6547      * @param bottom
6548      *            the distance from the center to the bottom frustum edge
6549      * @param top
6550      *            the distance from the center to the top frustum edge
6551      * @return this
6552      */
6553     ref public Matrix4x3d setOrtho2DLH(double left, double right, double bottom, double top) return {
6554         m00 = 2.0 / (right - left);
6555         m01 = 0.0;
6556         m02 = 0.0;
6557         m10 = 0.0;
6558         m11 = 2.0 / (top - bottom);
6559         m12 = 0.0;
6560         m20 = 0.0;
6561         m21 = 0.0;
6562         m22 = 1.0;
6563         m30 = -(right + left) / (right - left);
6564         m31 = -(top + bottom) / (top - bottom);
6565         m32 = 0.0;
6566         properties = 0;
6567         return this;
6568     }
6569 
6570     /**
6571      * Apply a rotation transformation to this matrix to make <code>-z</code> point along <code>dir</code>. 
6572      * <p>
6573      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookalong rotation matrix,
6574      * then the new matrix will be <code>M * L</code>. So when transforming a
6575      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, the
6576      * lookalong rotation transformation will be applied first!
6577      * <p>
6578      * This is equivalent to calling
6579      * {@link #lookAt(Vector3d, Vector3d, Vector3d) lookAt}
6580      * with <code>eye = (0, 0, 0)</code> and <code>center = dir</code>.
6581      * <p>
6582      * In order to set the matrix to a lookalong transformation without post-multiplying it,
6583      * use {@link #setLookAlong(Vector3d, Vector3d) setLookAlong()}.
6584      * 
6585      * @see #lookAlong(double, double, double, double, double, double)
6586      * @see #lookAt(Vector3d, Vector3d, Vector3d)
6587      * @see #setLookAlong(Vector3d, Vector3d)
6588      * 
6589      * @param dir
6590      *            the direction in space to look along
6591      * @param up
6592      *            the direction of 'up'
6593      * @return this
6594      */
6595     ref public Matrix4x3d lookAlong(ref Vector3d dir, Vector3d up) return {
6596         lookAlong(dir.x, dir.y, dir.z, up.x, up.y, up.z, this);
6597         return this;
6598     }
6599 
6600     /**
6601      * Apply a rotation transformation to this matrix to make <code>-z</code> point along <code>dir</code>
6602      * and store the result in <code>dest</code>. 
6603      * <p>
6604      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookalong rotation matrix,
6605      * then the new matrix will be <code>M * L</code>. So when transforming a
6606      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, the
6607      * lookalong rotation transformation will be applied first!
6608      * <p>
6609      * This is equivalent to calling
6610      * {@link #lookAt(Vector3d, Vector3d, Vector3d) lookAt}
6611      * with <code>eye = (0, 0, 0)</code> and <code>center = dir</code>.
6612      * <p>
6613      * In order to set the matrix to a lookalong transformation without post-multiplying it,
6614      * use {@link #setLookAlong(Vector3d, Vector3d) setLookAlong()}.
6615      * 
6616      * @see #lookAlong(double, double, double, double, double, double)
6617      * @see #lookAt(Vector3d, Vector3d, Vector3d)
6618      * @see #setLookAlong(Vector3d, Vector3d)
6619      * 
6620      * @param dir
6621      *            the direction in space to look along
6622      * @param up
6623      *            the direction of 'up'
6624      * @param dest
6625      *            will hold the result
6626      * @return dest
6627      */
6628     public Matrix4x3d lookAlong(ref Vector3d dir, Vector3d up, ref Matrix4x3d dest) {
6629         return lookAlong(dir.x, dir.y, dir.z, up.x, up.y, up.z, dest);
6630     }
6631 
6632     /**
6633      * Apply a rotation transformation to this matrix to make <code>-z</code> point along <code>dir</code>
6634      * and store the result in <code>dest</code>. 
6635      * <p>
6636      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookalong rotation matrix,
6637      * then the new matrix will be <code>M * L</code>. So when transforming a
6638      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, the
6639      * lookalong rotation transformation will be applied first!
6640      * <p>
6641      * This is equivalent to calling
6642      * {@link #lookAt(double, double, double, double, double, double, double, double, double) lookAt()}
6643      * with <code>eye = (0, 0, 0)</code> and <code>center = dir</code>.
6644      * <p>
6645      * In order to set the matrix to a lookalong transformation without post-multiplying it,
6646      * use {@link #setLookAlong(double, double, double, double, double, double) setLookAlong()}
6647      * 
6648      * @see #lookAt(double, double, double, double, double, double, double, double, double)
6649      * @see #setLookAlong(double, double, double, double, double, double)
6650      * 
6651      * @param dirX
6652      *              the x-coordinate of the direction to look along
6653      * @param dirY
6654      *              the y-coordinate of the direction to look along
6655      * @param dirZ
6656      *              the z-coordinate of the direction to look along
6657      * @param upX
6658      *              the x-coordinate of the up vector
6659      * @param upY
6660      *              the y-coordinate of the up vector
6661      * @param upZ
6662      *              the z-coordinate of the up vector
6663      * @param dest
6664      *              will hold the result
6665      * @return dest
6666      */
6667     public Matrix4x3d lookAlong(double dirX, double dirY, double dirZ,
6668                                 double upX, double upY, double upZ, ref Matrix4x3d dest) {
6669         if ((properties & PROPERTY_IDENTITY) != 0)
6670             return setLookAlong(dirX, dirY, dirZ, upX, upY, upZ);
6671 
6672         // Normalize direction
6673         double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
6674         dirX *= -invDirLength;
6675         dirY *= -invDirLength;
6676         dirZ *= -invDirLength;
6677         // left = up x direction
6678         double leftX, leftY, leftZ;
6679         leftX = upY * dirZ - upZ * dirY;
6680         leftY = upZ * dirX - upX * dirZ;
6681         leftZ = upX * dirY - upY * dirX;
6682         // normalize left
6683         double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
6684         leftX *= invLeftLength;
6685         leftY *= invLeftLength;
6686         leftZ *= invLeftLength;
6687         // up = direction x left
6688         double upnX = dirY * leftZ - dirZ * leftY;
6689         double upnY = dirZ * leftX - dirX * leftZ;
6690         double upnZ = dirX * leftY - dirY * leftX;
6691 
6692         // calculate right matrix elements
6693         double rm00 = leftX;
6694         double rm01 = upnX;
6695         double rm02 = dirX;
6696         double rm10 = leftY;
6697         double rm11 = upnY;
6698         double rm12 = dirY;
6699         double rm20 = leftZ;
6700         double rm21 = upnZ;
6701         double rm22 = dirZ;
6702 
6703         // perform optimized matrix multiplication
6704         // introduce temporaries for dependent results
6705         double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
6706         double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
6707         double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
6708         double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
6709         double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
6710         double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
6711         dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
6712         dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
6713         dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
6714         // set the rest of the matrix elements
6715         dest.m00 = nm00;
6716         dest.m01 = nm01;
6717         dest.m02 = nm02;
6718         dest.m10 = nm10;
6719         dest.m11 = nm11;
6720         dest.m12 = nm12;
6721         dest.m30 = m30;
6722         dest.m31 = m31;
6723         dest.m32 = m32;
6724         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
6725 
6726         return dest;
6727     }
6728 
6729     /**
6730      * Apply a rotation transformation to this matrix to make <code>-z</code> point along <code>dir</code>. 
6731      * <p>
6732      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookalong rotation matrix,
6733      * then the new matrix will be <code>M * L</code>. So when transforming a
6734      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, the
6735      * lookalong rotation transformation will be applied first!
6736      * <p>
6737      * This is equivalent to calling
6738      * {@link #lookAt(double, double, double, double, double, double, double, double, double) lookAt()}
6739      * with <code>eye = (0, 0, 0)</code> and <code>center = dir</code>.
6740      * <p>
6741      * In order to set the matrix to a lookalong transformation without post-multiplying it,
6742      * use {@link #setLookAlong(double, double, double, double, double, double) setLookAlong()}
6743      * 
6744      * @see #lookAt(double, double, double, double, double, double, double, double, double)
6745      * @see #setLookAlong(double, double, double, double, double, double)
6746      * 
6747      * @param dirX
6748      *              the x-coordinate of the direction to look along
6749      * @param dirY
6750      *              the y-coordinate of the direction to look along
6751      * @param dirZ
6752      *              the z-coordinate of the direction to look along
6753      * @param upX
6754      *              the x-coordinate of the up vector
6755      * @param upY
6756      *              the y-coordinate of the up vector
6757      * @param upZ
6758      *              the z-coordinate of the up vector
6759      * @return this
6760      */
6761     ref public Matrix4x3d lookAlong(double dirX, double dirY, double dirZ,
6762                                 double upX, double upY, double upZ) return {
6763         lookAlong(dirX, dirY, dirZ, upX, upY, upZ, this);
6764         return this;
6765     }
6766 
6767     /**
6768      * Set this matrix to a rotation transformation to make <code>-z</code>
6769      * point along <code>dir</code>.
6770      * <p>
6771      * This is equivalent to calling
6772      * {@link #setLookAt(Vector3d, Vector3d, Vector3d) setLookAt()} 
6773      * with <code>eye = (0, 0, 0)</code> and <code>center = dir</code>.
6774      * <p>
6775      * In order to apply the lookalong transformation to any previous existing transformation,
6776      * use {@link #lookAlong(Vector3d, Vector3d)}.
6777      * 
6778      * @see #setLookAlong(Vector3d, Vector3d)
6779      * @see #lookAlong(Vector3d, Vector3d)
6780      * 
6781      * @param dir
6782      *            the direction in space to look along
6783      * @param up
6784      *            the direction of 'up'
6785      * @return this
6786      */
6787     ref public Matrix4x3d setLookAlong(ref Vector3d dir, Vector3d up) return {
6788         return setLookAlong(dir.x, dir.y, dir.z, up.x, up.y, up.z);
6789     }
6790 
6791     /**
6792      * Set this matrix to a rotation transformation to make <code>-z</code>
6793      * point along <code>dir</code>.
6794      * <p>
6795      * This is equivalent to calling
6796      * {@link #setLookAt(double, double, double, double, double, double, double, double, double)
6797      * setLookAt()} with <code>eye = (0, 0, 0)</code> and <code>center = dir</code>.
6798      * <p>
6799      * In order to apply the lookalong transformation to any previous existing transformation,
6800      * use {@link #lookAlong(double, double, double, double, double, double) lookAlong()}
6801      * 
6802      * @see #setLookAlong(double, double, double, double, double, double)
6803      * @see #lookAlong(double, double, double, double, double, double)
6804      * 
6805      * @param dirX
6806      *              the x-coordinate of the direction to look along
6807      * @param dirY
6808      *              the y-coordinate of the direction to look along
6809      * @param dirZ
6810      *              the z-coordinate of the direction to look along
6811      * @param upX
6812      *              the x-coordinate of the up vector
6813      * @param upY
6814      *              the y-coordinate of the up vector
6815      * @param upZ
6816      *              the z-coordinate of the up vector
6817      * @return this
6818      */
6819     ref public Matrix4x3d setLookAlong(double dirX, double dirY, double dirZ,
6820                                    double upX, double upY, double upZ) return {
6821         // Normalize direction
6822         double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
6823         dirX *= -invDirLength;
6824         dirY *= -invDirLength;
6825         dirZ *= -invDirLength;
6826         // left = up x direction
6827         double leftX, leftY, leftZ;
6828         leftX = upY * dirZ - upZ * dirY;
6829         leftY = upZ * dirX - upX * dirZ;
6830         leftZ = upX * dirY - upY * dirX;
6831         // normalize left
6832         double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
6833         leftX *= invLeftLength;
6834         leftY *= invLeftLength;
6835         leftZ *= invLeftLength;
6836         // up = direction x left
6837         double upnX = dirY * leftZ - dirZ * leftY;
6838         double upnY = dirZ * leftX - dirX * leftZ;
6839         double upnZ = dirX * leftY - dirY * leftX;
6840 
6841         m00 = leftX;
6842         m01 = upnX;
6843         m02 = dirX;
6844         m10 = leftY;
6845         m11 = upnY;
6846         m12 = dirY;
6847         m20 = leftZ;
6848         m21 = upnZ;
6849         m22 = dirZ;
6850         m30 = 0.0;
6851         m31 = 0.0;
6852         m32 = 0.0;
6853         properties = PROPERTY_ORTHONORMAL;
6854 
6855         return this;
6856     }
6857 
6858     /**
6859      * Set this matrix to be a "lookat" transformation for a right-handed coordinate system, that aligns
6860      * <code>-z</code> with <code>center - eye</code>.
6861      * <p>
6862      * In order to not make use of vectors to specify <code>eye</code>, <code>center</code> and <code>up</code> but use primitives,
6863      * like in the GLU function, use {@link #setLookAt(double, double, double, double, double, double, double, double, double) setLookAt()}
6864      * instead.
6865      * <p>
6866      * In order to apply the lookat transformation to a previous existing transformation,
6867      * use {@link #lookAt(Vector3d, Vector3d, Vector3d) lookAt()}.
6868      * 
6869      * @see #setLookAt(double, double, double, double, double, double, double, double, double)
6870      * @see #lookAt(Vector3d, Vector3d, Vector3d)
6871      * 
6872      * @param eye
6873      *            the position of the camera
6874      * @param center
6875      *            the point in space to look at
6876      * @param up
6877      *            the direction of 'up'
6878      * @return this
6879      */
6880     ref public Matrix4x3d setLookAt(Vector3d eye, Vector3d center, Vector3d up) return {
6881         return setLookAt(eye.x, eye.y, eye.z, center.x, center.y, center.z, up.x, up.y, up.z);
6882     }
6883 
6884     /**
6885      * Set this matrix to be a "lookat" transformation for a right-handed coordinate system, 
6886      * that aligns <code>-z</code> with <code>center - eye</code>.
6887      * <p>
6888      * In order to apply the lookat transformation to a previous existing transformation,
6889      * use {@link #lookAt(double, double, double, double, double, double, double, double, double) lookAt}.
6890      * 
6891      * @see #setLookAt(Vector3d, Vector3d, Vector3d)
6892      * @see #lookAt(double, double, double, double, double, double, double, double, double)
6893      * 
6894      * @param eyeX
6895      *              the x-coordinate of the eye/camera location
6896      * @param eyeY
6897      *              the y-coordinate of the eye/camera location
6898      * @param eyeZ
6899      *              the z-coordinate of the eye/camera location
6900      * @param centerX
6901      *              the x-coordinate of the point to look at
6902      * @param centerY
6903      *              the y-coordinate of the point to look at
6904      * @param centerZ
6905      *              the z-coordinate of the point to look at
6906      * @param upX
6907      *              the x-coordinate of the up vector
6908      * @param upY
6909      *              the y-coordinate of the up vector
6910      * @param upZ
6911      *              the z-coordinate of the up vector
6912      * @return this
6913      */
6914     ref public Matrix4x3d setLookAt(double eyeX, double eyeY, double eyeZ,
6915                                 double centerX, double centerY, double centerZ,
6916                                 double upX, double upY, double upZ) return {
6917         // Compute direction from position to lookAt
6918         double dirX, dirY, dirZ;
6919         dirX = eyeX - centerX;
6920         dirY = eyeY - centerY;
6921         dirZ = eyeZ - centerZ;
6922         // Normalize direction
6923         double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
6924         dirX *= invDirLength;
6925         dirY *= invDirLength;
6926         dirZ *= invDirLength;
6927         // left = up x direction
6928         double leftX, leftY, leftZ;
6929         leftX = upY * dirZ - upZ * dirY;
6930         leftY = upZ * dirX - upX * dirZ;
6931         leftZ = upX * dirY - upY * dirX;
6932         // normalize left
6933         double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
6934         leftX *= invLeftLength;
6935         leftY *= invLeftLength;
6936         leftZ *= invLeftLength;
6937         // up = direction x left
6938         double upnX = dirY * leftZ - dirZ * leftY;
6939         double upnY = dirZ * leftX - dirX * leftZ;
6940         double upnZ = dirX * leftY - dirY * leftX;
6941 
6942         m00 = leftX;
6943         m01 = upnX;
6944         m02 = dirX;
6945         m10 = leftY;
6946         m11 = upnY;
6947         m12 = dirY;
6948         m20 = leftZ;
6949         m21 = upnZ;
6950         m22 = dirZ;
6951         m30 = -(leftX * eyeX + leftY * eyeY + leftZ * eyeZ);
6952         m31 = -(upnX * eyeX + upnY * eyeY + upnZ * eyeZ);
6953         m32 = -(dirX * eyeX + dirY * eyeY + dirZ * eyeZ);
6954         properties = PROPERTY_ORTHONORMAL;
6955 
6956         return this;
6957     }
6958 
6959     /**
6960      * Apply a "lookat" transformation to this matrix for a right-handed coordinate system, 
6961      * that aligns <code>-z</code> with <code>center - eye</code> and store the result in <code>dest</code>.
6962      * <p>
6963      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix,
6964      * then the new matrix will be <code>M * L</code>. So when transforming a
6965      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>,
6966      * the lookat transformation will be applied first!
6967      * <p>
6968      * In order to set the matrix to a lookat transformation without post-multiplying it,
6969      * use {@link #setLookAt(Vector3d, Vector3d, Vector3d)}.
6970      * 
6971      * @see #lookAt(double, double, double, double, double, double, double, double, double)
6972      * @see #setLookAlong(Vector3d, Vector3d)
6973      * 
6974      * @param eye
6975      *            the position of the camera
6976      * @param center
6977      *            the point in space to look at
6978      * @param up
6979      *            the direction of 'up'
6980      * @param dest
6981      *            will hold the result
6982      * @return dest
6983      */
6984     public Matrix4x3d lookAt(Vector3d eye, Vector3d center, Vector3d up, ref Matrix4x3d dest) {
6985         return lookAt(eye.x, eye.y, eye.z, center.x, center.y, center.z, up.x, up.y, up.z, dest);
6986     }
6987 
6988     /**
6989      * Apply a "lookat" transformation to this matrix for a right-handed coordinate system, 
6990      * that aligns <code>-z</code> with <code>center - eye</code>.
6991      * <p>
6992      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix,
6993      * then the new matrix will be <code>M * L</code>. So when transforming a
6994      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>,
6995      * the lookat transformation will be applied first!
6996      * <p>
6997      * In order to set the matrix to a lookat transformation without post-multiplying it,
6998      * use {@link #setLookAt(Vector3d, Vector3d, Vector3d)}.
6999      * 
7000      * @see #lookAt(double, double, double, double, double, double, double, double, double)
7001      * @see #setLookAlong(Vector3d, Vector3d)
7002      * 
7003      * @param eye
7004      *            the position of the camera
7005      * @param center
7006      *            the point in space to look at
7007      * @param up
7008      *            the direction of 'up'
7009      * @return this
7010      */
7011     ref public Matrix4x3d lookAt(Vector3d eye, Vector3d center, Vector3d up) return {
7012         lookAt(eye.x, eye.y, eye.z, center.x, center.y, center.z, up.x, up.y, up.z, this);
7013         return this;
7014     }
7015 
7016     /**
7017      * Apply a "lookat" transformation to this matrix for a right-handed coordinate system, 
7018      * that aligns <code>-z</code> with <code>center - eye</code> and store the result in <code>dest</code>.
7019      * <p>
7020      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix,
7021      * then the new matrix will be <code>M * L</code>. So when transforming a
7022      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>,
7023      * the lookat transformation will be applied first!
7024      * <p>
7025      * In order to set the matrix to a lookat transformation without post-multiplying it,
7026      * use {@link #setLookAt(double, double, double, double, double, double, double, double, double) setLookAt()}.
7027      * 
7028      * @see #lookAt(Vector3d, Vector3d, Vector3d)
7029      * @see #setLookAt(double, double, double, double, double, double, double, double, double)
7030      * 
7031      * @param eyeX
7032      *              the x-coordinate of the eye/camera location
7033      * @param eyeY
7034      *              the y-coordinate of the eye/camera location
7035      * @param eyeZ
7036      *              the z-coordinate of the eye/camera location
7037      * @param centerX
7038      *              the x-coordinate of the point to look at
7039      * @param centerY
7040      *              the y-coordinate of the point to look at
7041      * @param centerZ
7042      *              the z-coordinate of the point to look at
7043      * @param upX
7044      *              the x-coordinate of the up vector
7045      * @param upY
7046      *              the y-coordinate of the up vector
7047      * @param upZ
7048      *              the z-coordinate of the up vector
7049      * @param dest
7050      *          will hold the result
7051      * @return dest
7052      */
7053     public Matrix4x3d lookAt(double eyeX, double eyeY, double eyeZ,
7054                              double centerX, double centerY, double centerZ,
7055                              double upX, double upY, double upZ, ref Matrix4x3d dest) {
7056         if ((properties & PROPERTY_IDENTITY) != 0)
7057             return dest.setLookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);
7058         return lookAtGeneric(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, dest);
7059     }
7060     private Matrix4x3d lookAtGeneric(double eyeX, double eyeY, double eyeZ,
7061                                      double centerX, double centerY, double centerZ,
7062                                      double upX, double upY, double upZ, ref Matrix4x3d dest) {
7063         // Compute direction from position to lookAt
7064         double dirX, dirY, dirZ;
7065         dirX = eyeX - centerX;
7066         dirY = eyeY - centerY;
7067         dirZ = eyeZ - centerZ;
7068         // Normalize direction
7069         double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
7070         dirX *= invDirLength;
7071         dirY *= invDirLength;
7072         dirZ *= invDirLength;
7073         // left = up x direction
7074         double leftX, leftY, leftZ;
7075         leftX = upY * dirZ - upZ * dirY;
7076         leftY = upZ * dirX - upX * dirZ;
7077         leftZ = upX * dirY - upY * dirX;
7078         // normalize left
7079         double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
7080         leftX *= invLeftLength;
7081         leftY *= invLeftLength;
7082         leftZ *= invLeftLength;
7083         // up = direction x left
7084         double upnX = dirY * leftZ - dirZ * leftY;
7085         double upnY = dirZ * leftX - dirX * leftZ;
7086         double upnZ = dirX * leftY - dirY * leftX;
7087 
7088         // calculate right matrix elements
7089         double rm00 = leftX;
7090         double rm01 = upnX;
7091         double rm02 = dirX;
7092         double rm10 = leftY;
7093         double rm11 = upnY;
7094         double rm12 = dirY;
7095         double rm20 = leftZ;
7096         double rm21 = upnZ;
7097         double rm22 = dirZ;
7098         double rm30 = -(leftX * eyeX + leftY * eyeY + leftZ * eyeZ);
7099         double rm31 = -(upnX * eyeX + upnY * eyeY + upnZ * eyeZ);
7100         double rm32 = -(dirX * eyeX + dirY * eyeY + dirZ * eyeZ);
7101 
7102         // perform optimized matrix multiplication
7103         // compute last column first, because others do not depend on it
7104         dest.m30 = m00 * rm30 + m10 * rm31 + m20 * rm32 + m30;
7105         dest.m31 = m01 * rm30 + m11 * rm31 + m21 * rm32 + m31;
7106         dest.m32 = m02 * rm30 + m12 * rm31 + m22 * rm32 + m32;
7107         // introduce temporaries for dependent results
7108         double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
7109         double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
7110         double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
7111         double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
7112         double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
7113         double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
7114         dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
7115         dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
7116         dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
7117         // set the rest of the matrix elements
7118         dest.m00 = nm00;
7119         dest.m01 = nm01;
7120         dest.m02 = nm02;
7121         dest.m10 = nm10;
7122         dest.m11 = nm11;
7123         dest.m12 = nm12;
7124         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
7125 
7126         return dest;
7127     }
7128 
7129     /**
7130      * Apply a "lookat" transformation to this matrix for a right-handed coordinate system, 
7131      * that aligns <code>-z</code> with <code>center - eye</code>.
7132      * <p>
7133      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix,
7134      * then the new matrix will be <code>M * L</code>. So when transforming a
7135      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>,
7136      * the lookat transformation will be applied first!
7137      * <p>
7138      * In order to set the matrix to a lookat transformation without post-multiplying it,
7139      * use {@link #setLookAt(double, double, double, double, double, double, double, double, double) setLookAt()}.
7140      * 
7141      * @see #lookAt(Vector3d, Vector3d, Vector3d)
7142      * @see #setLookAt(double, double, double, double, double, double, double, double, double)
7143      * 
7144      * @param eyeX
7145      *              the x-coordinate of the eye/camera location
7146      * @param eyeY
7147      *              the y-coordinate of the eye/camera location
7148      * @param eyeZ
7149      *              the z-coordinate of the eye/camera location
7150      * @param centerX
7151      *              the x-coordinate of the point to look at
7152      * @param centerY
7153      *              the y-coordinate of the point to look at
7154      * @param centerZ
7155      *              the z-coordinate of the point to look at
7156      * @param upX
7157      *              the x-coordinate of the up vector
7158      * @param upY
7159      *              the y-coordinate of the up vector
7160      * @param upZ
7161      *              the z-coordinate of the up vector
7162      * @return this
7163      */
7164     ref public Matrix4x3d lookAt(double eyeX, double eyeY, double eyeZ,
7165                              double centerX, double centerY, double centerZ,
7166                              double upX, double upY, double upZ) return {
7167         lookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, this);
7168         return this;
7169     }
7170 
7171     /**
7172      * Set this matrix to be a "lookat" transformation for a left-handed coordinate system, that aligns
7173      * <code>+z</code> with <code>center - eye</code>.
7174      * <p>
7175      * In order to not make use of vectors to specify <code>eye</code>, <code>center</code> and <code>up</code> but use primitives,
7176      * like in the GLU function, use {@link #setLookAtLH(double, double, double, double, double, double, double, double, double) setLookAtLH()}
7177      * instead.
7178      * <p>
7179      * In order to apply the lookat transformation to a previous existing transformation,
7180      * use {@link #lookAtLH(Vector3d, Vector3d, Vector3d) lookAt()}.
7181      * 
7182      * @see #setLookAtLH(double, double, double, double, double, double, double, double, double)
7183      * @see #lookAtLH(Vector3d, Vector3d, Vector3d)
7184      * 
7185      * @param eye
7186      *            the position of the camera
7187      * @param center
7188      *            the point in space to look at
7189      * @param up
7190      *            the direction of 'up'
7191      * @return this
7192      */
7193     ref public Matrix4x3d setLookAtLH(Vector3d eye, Vector3d center, Vector3d up) return {
7194         return setLookAtLH(eye.x, eye.y, eye.z, center.x, center.y, center.z, up.x, up.y, up.z);
7195     }
7196 
7197     /**
7198      * Set this matrix to be a "lookat" transformation for a left-handed coordinate system, 
7199      * that aligns <code>+z</code> with <code>center - eye</code>.
7200      * <p>
7201      * In order to apply the lookat transformation to a previous existing transformation,
7202      * use {@link #lookAtLH(double, double, double, double, double, double, double, double, double) lookAtLH}.
7203      * 
7204      * @see #setLookAtLH(Vector3d, Vector3d, Vector3d)
7205      * @see #lookAtLH(double, double, double, double, double, double, double, double, double)
7206      * 
7207      * @param eyeX
7208      *              the x-coordinate of the eye/camera location
7209      * @param eyeY
7210      *              the y-coordinate of the eye/camera location
7211      * @param eyeZ
7212      *              the z-coordinate of the eye/camera location
7213      * @param centerX
7214      *              the x-coordinate of the point to look at
7215      * @param centerY
7216      *              the y-coordinate of the point to look at
7217      * @param centerZ
7218      *              the z-coordinate of the point to look at
7219      * @param upX
7220      *              the x-coordinate of the up vector
7221      * @param upY
7222      *              the y-coordinate of the up vector
7223      * @param upZ
7224      *              the z-coordinate of the up vector
7225      * @return this
7226      */
7227     ref public Matrix4x3d setLookAtLH(double eyeX, double eyeY, double eyeZ,
7228                                   double centerX, double centerY, double centerZ,
7229                                   double upX, double upY, double upZ) return {
7230         // Compute direction from position to lookAt
7231         double dirX, dirY, dirZ;
7232         dirX = centerX - eyeX;
7233         dirY = centerY - eyeY;
7234         dirZ = centerZ - eyeZ;
7235         // Normalize direction
7236         double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
7237         dirX *= invDirLength;
7238         dirY *= invDirLength;
7239         dirZ *= invDirLength;
7240         // left = up x direction
7241         double leftX, leftY, leftZ;
7242         leftX = upY * dirZ - upZ * dirY;
7243         leftY = upZ * dirX - upX * dirZ;
7244         leftZ = upX * dirY - upY * dirX;
7245         // normalize left
7246         double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
7247         leftX *= invLeftLength;
7248         leftY *= invLeftLength;
7249         leftZ *= invLeftLength;
7250         // up = direction x left
7251         double upnX = dirY * leftZ - dirZ * leftY;
7252         double upnY = dirZ * leftX - dirX * leftZ;
7253         double upnZ = dirX * leftY - dirY * leftX;
7254 
7255         m00 = leftX;
7256         m01 = upnX;
7257         m02 = dirX;
7258         m10 = leftY;
7259         m11 = upnY;
7260         m12 = dirY;
7261         m20 = leftZ;
7262         m21 = upnZ;
7263         m22 = dirZ;
7264         m30 = -(leftX * eyeX + leftY * eyeY + leftZ * eyeZ);
7265         m31 = -(upnX * eyeX + upnY * eyeY + upnZ * eyeZ);
7266         m32 = -(dirX * eyeX + dirY * eyeY + dirZ * eyeZ);
7267         properties = PROPERTY_ORTHONORMAL;
7268 
7269         return this;
7270     }
7271 
7272     /**
7273      * Apply a "lookat" transformation to this matrix for a left-handed coordinate system, 
7274      * that aligns <code>+z</code> with <code>center - eye</code> and store the result in <code>dest</code>.
7275      * <p>
7276      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix,
7277      * then the new matrix will be <code>M * L</code>. So when transforming a
7278      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>,
7279      * the lookat transformation will be applied first!
7280      * <p>
7281      * In order to set the matrix to a lookat transformation without post-multiplying it,
7282      * use {@link #setLookAtLH(Vector3d, Vector3d, Vector3d)}.
7283      * 
7284      * @see #lookAtLH(double, double, double, double, double, double, double, double, double)
7285      * 
7286      * @param eye
7287      *            the position of the camera
7288      * @param center
7289      *            the point in space to look at
7290      * @param up
7291      *            the direction of 'up'
7292      * @param dest
7293      *            will hold the result
7294      * @return dest
7295      */
7296     public Matrix4x3d lookAtLH(Vector3d eye, Vector3d center, Vector3d up, ref Matrix4x3d dest) {
7297         return lookAtLH(eye.x, eye.y, eye.z, center.x, center.y, center.z, up.x, up.y, up.z, dest);
7298     }
7299 
7300     /**
7301      * Apply a "lookat" transformation to this matrix for a left-handed coordinate system, 
7302      * that aligns <code>+z</code> with <code>center - eye</code>.
7303      * <p>
7304      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix,
7305      * then the new matrix will be <code>M * L</code>. So when transforming a
7306      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>,
7307      * the lookat transformation will be applied first!
7308      * <p>
7309      * In order to set the matrix to a lookat transformation without post-multiplying it,
7310      * use {@link #setLookAtLH(Vector3d, Vector3d, Vector3d)}.
7311      * 
7312      * @see #lookAtLH(double, double, double, double, double, double, double, double, double)
7313      * 
7314      * @param eye
7315      *            the position of the camera
7316      * @param center
7317      *            the point in space to look at
7318      * @param up
7319      *            the direction of 'up'
7320      * @return this
7321      */
7322     ref public Matrix4x3d lookAtLH(Vector3d eye, Vector3d center, Vector3d up) return {
7323         lookAtLH(eye.x, eye.y, eye.z, center.x, center.y, center.z, up.x, up.y, up.z, this);
7324         return this;
7325     }
7326 
7327     /**
7328      * Apply a "lookat" transformation to this matrix for a left-handed coordinate system, 
7329      * that aligns <code>+z</code> with <code>center - eye</code> and store the result in <code>dest</code>.
7330      * <p>
7331      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix,
7332      * then the new matrix will be <code>M * L</code>. So when transforming a
7333      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>,
7334      * the lookat transformation will be applied first!
7335      * <p>
7336      * In order to set the matrix to a lookat transformation without post-multiplying it,
7337      * use {@link #setLookAtLH(double, double, double, double, double, double, double, double, double) setLookAtLH()}.
7338      * 
7339      * @see #lookAtLH(Vector3d, Vector3d, Vector3d)
7340      * @see #setLookAtLH(double, double, double, double, double, double, double, double, double)
7341      * 
7342      * @param eyeX
7343      *              the x-coordinate of the eye/camera location
7344      * @param eyeY
7345      *              the y-coordinate of the eye/camera location
7346      * @param eyeZ
7347      *              the z-coordinate of the eye/camera location
7348      * @param centerX
7349      *              the x-coordinate of the point to look at
7350      * @param centerY
7351      *              the y-coordinate of the point to look at
7352      * @param centerZ
7353      *              the z-coordinate of the point to look at
7354      * @param upX
7355      *              the x-coordinate of the up vector
7356      * @param upY
7357      *              the y-coordinate of the up vector
7358      * @param upZ
7359      *              the z-coordinate of the up vector
7360      * @param dest
7361      *          will hold the result
7362      * @return dest
7363      */
7364     public Matrix4x3d lookAtLH(double eyeX, double eyeY, double eyeZ,
7365                                double centerX, double centerY, double centerZ,
7366                                double upX, double upY, double upZ, ref Matrix4x3d dest) {
7367         if ((properties & PROPERTY_IDENTITY) != 0)
7368             return dest.setLookAtLH(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);
7369         return lookAtLHGeneric(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, dest);
7370     }
7371     private Matrix4x3d lookAtLHGeneric(double eyeX, double eyeY, double eyeZ,
7372                                        double centerX, double centerY, double centerZ,
7373                                        double upX, double upY, double upZ, ref Matrix4x3d dest) {
7374         // Compute direction from position to lookAt
7375         double dirX, dirY, dirZ;
7376         dirX = centerX - eyeX;
7377         dirY = centerY - eyeY;
7378         dirZ = centerZ - eyeZ;
7379         // Normalize direction
7380         double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
7381         dirX *= invDirLength;
7382         dirY *= invDirLength;
7383         dirZ *= invDirLength;
7384         // left = up x direction
7385         double leftX, leftY, leftZ;
7386         leftX = upY * dirZ - upZ * dirY;
7387         leftY = upZ * dirX - upX * dirZ;
7388         leftZ = upX * dirY - upY * dirX;
7389         // normalize left
7390         double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
7391         leftX *= invLeftLength;
7392         leftY *= invLeftLength;
7393         leftZ *= invLeftLength;
7394         // up = direction x left
7395         double upnX = dirY * leftZ - dirZ * leftY;
7396         double upnY = dirZ * leftX - dirX * leftZ;
7397         double upnZ = dirX * leftY - dirY * leftX;
7398 
7399         // calculate right matrix elements
7400         double rm00 = leftX;
7401         double rm01 = upnX;
7402         double rm02 = dirX;
7403         double rm10 = leftY;
7404         double rm11 = upnY;
7405         double rm12 = dirY;
7406         double rm20 = leftZ;
7407         double rm21 = upnZ;
7408         double rm22 = dirZ;
7409         double rm30 = -(leftX * eyeX + leftY * eyeY + leftZ * eyeZ);
7410         double rm31 = -(upnX * eyeX + upnY * eyeY + upnZ * eyeZ);
7411         double rm32 = -(dirX * eyeX + dirY * eyeY + dirZ * eyeZ);
7412 
7413         // perform optimized matrix multiplication
7414         // compute last column first, because others do not depend on it
7415         dest.m30 = m00 * rm30 + m10 * rm31 + m20 * rm32 + m30;
7416         dest.m31 = m01 * rm30 + m11 * rm31 + m21 * rm32 + m31;
7417         dest.m32 = m02 * rm30 + m12 * rm31 + m22 * rm32 + m32;
7418         // introduce temporaries for dependent results
7419         double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
7420         double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
7421         double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
7422         double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
7423         double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
7424         double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
7425         dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
7426         dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
7427         dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
7428         // set the rest of the matrix elements
7429         dest.m00 = nm00;
7430         dest.m01 = nm01;
7431         dest.m02 = nm02;
7432         dest.m10 = nm10;
7433         dest.m11 = nm11;
7434         dest.m12 = nm12;
7435         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
7436 
7437         return dest;
7438     }
7439 
7440     /**
7441      * Apply a "lookat" transformation to this matrix for a left-handed coordinate system, 
7442      * that aligns <code>+z</code> with <code>center - eye</code>.
7443      * <p>
7444      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix,
7445      * then the new matrix will be <code>M * L</code>. So when transforming a
7446      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>,
7447      * the lookat transformation will be applied first!
7448      * <p>
7449      * In order to set the matrix to a lookat transformation without post-multiplying it,
7450      * use {@link #setLookAtLH(double, double, double, double, double, double, double, double, double) setLookAtLH()}.
7451      * 
7452      * @see #lookAtLH(Vector3d, Vector3d, Vector3d)
7453      * @see #setLookAtLH(double, double, double, double, double, double, double, double, double)
7454      * 
7455      * @param eyeX
7456      *              the x-coordinate of the eye/camera location
7457      * @param eyeY
7458      *              the y-coordinate of the eye/camera location
7459      * @param eyeZ
7460      *              the z-coordinate of the eye/camera location
7461      * @param centerX
7462      *              the x-coordinate of the point to look at
7463      * @param centerY
7464      *              the y-coordinate of the point to look at
7465      * @param centerZ
7466      *              the z-coordinate of the point to look at
7467      * @param upX
7468      *              the x-coordinate of the up vector
7469      * @param upY
7470      *              the y-coordinate of the up vector
7471      * @param upZ
7472      *              the z-coordinate of the up vector
7473      * @return this
7474      */
7475     ref public Matrix4x3d lookAtLH(double eyeX, double eyeY, double eyeZ,
7476                                double centerX, double centerY, double centerZ,
7477                                double upX, double upY, double upZ) return {
7478         lookAtLH(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, this);
7479         return this;
7480     }
7481 
7482     public Vector4d frustumPlane(int which, Vector4d dest) {
7483         switch (which) {
7484         case PLANE_NX:
7485             dest.set(m00, m10, m20, 1.0 + m30).normalize();
7486             break;
7487         case PLANE_PX:
7488             dest.set(-m00, -m10, -m20, 1.0 - m30).normalize();
7489             break;
7490         case PLANE_NY:
7491             dest.set(m01, m11, m21, 1.0 + m31).normalize();
7492             break;
7493         case PLANE_PY:
7494             dest.set(-m01, -m11, -m21, 1.0 - m31).normalize();
7495             break;
7496         case PLANE_NZ:
7497             dest.set(m02, m12, m22, 1.0 + m32).normalize();
7498             break;
7499         case PLANE_PZ:
7500             dest.set(-m02, -m12, -m22, 1.0 - m32).normalize();
7501             break;
7502         default:
7503             // do nothing
7504         }
7505         return dest;
7506     }
7507 
7508     public Vector3d positiveZ(ref Vector3d dir) {
7509         dir.x = m10 * m21 - m11 * m20;
7510         dir.y = m20 * m01 - m21 * m00;
7511         dir.z = m00 * m11 - m01 * m10;
7512         return dir.normalize(dir);
7513     }
7514 
7515     public Vector3d normalizedPositiveZ(ref Vector3d dir) {
7516         dir.x = m02;
7517         dir.y = m12;
7518         dir.z = m22;
7519         return dir;
7520     }
7521 
7522     public Vector3d positiveX(ref Vector3d dir) {
7523         dir.x = m11 * m22 - m12 * m21;
7524         dir.y = m02 * m21 - m01 * m22;
7525         dir.z = m01 * m12 - m02 * m11;
7526         return dir.normalize(dir);
7527     }
7528 
7529     public Vector3d normalizedPositiveX(ref Vector3d dir) {
7530         dir.x = m00;
7531         dir.y = m10;
7532         dir.z = m20;
7533         return dir;
7534     }
7535 
7536     public Vector3d positiveY(ref Vector3d dir) {
7537         dir.x = m12 * m20 - m10 * m22;
7538         dir.y = m00 * m22 - m02 * m20;
7539         dir.z = m02 * m10 - m00 * m12;
7540         return dir.normalize(dir);
7541     }
7542 
7543     public Vector3d normalizedPositiveY(ref Vector3d dir) {
7544         dir.x = m01;
7545         dir.y = m11;
7546         dir.z = m21;
7547         return dir;
7548     }
7549 
7550     public Vector3d origin(Vector3d origin) {
7551         double a = m00 * m11 - m01 * m10;
7552         double b = m00 * m12 - m02 * m10;
7553         double d = m01 * m12 - m02 * m11;
7554         double g = m20 * m31 - m21 * m30;
7555         double h = m20 * m32 - m22 * m30;
7556         double j = m21 * m32 - m22 * m31;
7557         origin.x = -m10 * j + m11 * h - m12 * g;
7558         origin.y =  m00 * j - m01 * h + m02 * g;
7559         origin.z = -m30 * d + m31 * b - m32 * a;
7560         return origin;
7561     }
7562 
7563     /**
7564      * Apply a projection transformation to this matrix that projects onto the plane specified via the general plane equation
7565      * <code>x*a + y*b + z*c + d = 0</code> as if casting a shadow from a given light position/direction <code>light</code>.
7566      * <p>
7567      * If <code>light.w</code> is <code>0.0</code> the light is being treated as a directional light; if it is <code>1.0</code> it is a point light.
7568      * <p>
7569      * If <code>M</code> is <code>this</code> matrix and <code>S</code> the shadow matrix,
7570      * then the new matrix will be <code>M * S</code>. So when transforming a
7571      * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the
7572      * shadow projection will be applied first!
7573      * <p>
7574      * Reference: <a href="ftp://ftp.sgi.com/opengl/contrib/blythe/advanced99/notes/node192.html">ftp.sgi.com</a>
7575      * 
7576      * @param light
7577      *          the light's vector
7578      * @param a
7579      *          the x factor in the plane equation
7580      * @param b
7581      *          the y factor in the plane equation
7582      * @param c
7583      *          the z factor in the plane equation
7584      * @param d
7585      *          the constant in the plane equation
7586      * @return this
7587      */
7588     ref public Matrix4x3d shadow(Vector4d light, double a, double b, double c, double d) return {
7589         shadow(light.x, light.y, light.z, light.w, a, b, c, d, this);
7590         return this;
7591     }
7592 
7593     public Matrix4x3d shadow(Vector4d light, double a, double b, double c, double d, ref Matrix4x3d dest) {
7594         return shadow(light.x, light.y, light.z, light.w, a, b, c, d, dest);
7595     }
7596 
7597     /**
7598      * Apply a projection transformation to this matrix that projects onto the plane specified via the general plane equation
7599      * <code>x*a + y*b + z*c + d = 0</code> as if casting a shadow from a given light position/direction <code>(lightX, lightY, lightZ, lightW)</code>.
7600      * <p>
7601      * If <code>lightW</code> is <code>0.0</code> the light is being treated as a directional light; if it is <code>1.0</code> it is a point light.
7602      * <p>
7603      * If <code>M</code> is <code>this</code> matrix and <code>S</code> the shadow matrix,
7604      * then the new matrix will be <code>M * S</code>. So when transforming a
7605      * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the
7606      * shadow projection will be applied first!
7607      * <p>
7608      * Reference: <a href="ftp://ftp.sgi.com/opengl/contrib/blythe/advanced99/notes/node192.html">ftp.sgi.com</a>
7609      * 
7610      * @param lightX
7611      *          the x-component of the light's vector
7612      * @param lightY
7613      *          the y-component of the light's vector
7614      * @param lightZ
7615      *          the z-component of the light's vector
7616      * @param lightW
7617      *          the w-component of the light's vector
7618      * @param a
7619      *          the x factor in the plane equation
7620      * @param b
7621      *          the y factor in the plane equation
7622      * @param c
7623      *          the z factor in the plane equation
7624      * @param d
7625      *          the constant in the plane equation
7626      * @return this
7627      */
7628     ref public Matrix4x3d shadow(double lightX, double lightY, double lightZ, double lightW, double a, double b, double c, double d) return {
7629         shadow(lightX, lightY, lightZ, lightW, a, b, c, d, this);
7630         return this;
7631     }
7632 
7633     public Matrix4x3d shadow(double lightX, double lightY, double lightZ, double lightW, double a, double b, double c, double d, ref Matrix4x3d dest) {
7634         // normalize plane
7635         double invPlaneLen = Math.invsqrt(a*a + b*b + c*c);
7636         double an = a * invPlaneLen;
7637         double bn = b * invPlaneLen;
7638         double cn = c * invPlaneLen;
7639         double dn = d * invPlaneLen;
7640 
7641         double dot = an * lightX + bn * lightY + cn * lightZ + dn * lightW;
7642 
7643         // compute right matrix elements
7644         double rm00 = dot - an * lightX;
7645         double rm01 = -an * lightY;
7646         double rm02 = -an * lightZ;
7647         double rm03 = -an * lightW;
7648         double rm10 = -bn * lightX;
7649         double rm11 = dot - bn * lightY;
7650         double rm12 = -bn * lightZ;
7651         double rm13 = -bn * lightW;
7652         double rm20 = -cn * lightX;
7653         double rm21 = -cn * lightY;
7654         double rm22 = dot - cn * lightZ;
7655         double rm23 = -cn * lightW;
7656         double rm30 = -dn * lightX;
7657         double rm31 = -dn * lightY;
7658         double rm32 = -dn * lightZ;
7659         double rm33 = dot - dn * lightW;
7660 
7661         // matrix multiplication
7662         double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02 + m30 * rm03;
7663         double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02 + m31 * rm03;
7664         double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02 + m32 * rm03;
7665         double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12 + m30 * rm13;
7666         double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12 + m31 * rm13;
7667         double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12 + m32 * rm13;
7668         double nm20 = m00 * rm20 + m10 * rm21 + m20 * rm22 + m30 * rm23;
7669         double nm21 = m01 * rm20 + m11 * rm21 + m21 * rm22 + m31 * rm23;
7670         double nm22 = m02 * rm20 + m12 * rm21 + m22 * rm22 + m32 * rm23;
7671         dest.m30 = m00 * rm30 + m10 * rm31 + m20 * rm32 + m30 * rm33;
7672         dest.m31 = m01 * rm30 + m11 * rm31 + m21 * rm32 + m31 * rm33;
7673         dest.m32 = m02 * rm30 + m12 * rm31 + m22 * rm32 + m32 * rm33;
7674         dest.m00 = nm00;
7675         dest.m01 = nm01;
7676         dest.m02 = nm02;
7677         dest.m10 = nm10;
7678         dest.m11 = nm11;
7679         dest.m12 = nm12;
7680         dest.m20 = nm20;
7681         dest.m21 = nm21;
7682         dest.m22 = nm22;
7683         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
7684 
7685         return dest;
7686     }
7687 
7688     public Matrix4x3d shadow(Vector4d light, Matrix4x3d planeTransform, ref Matrix4x3d dest) {
7689         // compute plane equation by transforming (y = 0)
7690         double a = planeTransform.m10;
7691         double b = planeTransform.m11;
7692         double c = planeTransform.m12;
7693         double d = -a * planeTransform.m30 - b * planeTransform.m31 - c * planeTransform.m32;
7694         return shadow(light.x, light.y, light.z, light.w, a, b, c, d, dest);
7695     }
7696 
7697     /**
7698      * Apply a projection transformation to this matrix that projects onto the plane with the general plane equation
7699      * <code>y = 0</code> as if casting a shadow from a given light position/direction <code>light</code>.
7700      * <p>
7701      * Before the shadow projection is applied, the plane is transformed via the specified <code>planeTransformation</code>.
7702      * <p>
7703      * If <code>light.w</code> is <code>0.0</code> the light is being treated as a directional light; if it is <code>1.0</code> it is a point light.
7704      * <p>
7705      * If <code>M</code> is <code>this</code> matrix and <code>S</code> the shadow matrix,
7706      * then the new matrix will be <code>M * S</code>. So when transforming a
7707      * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the
7708      * shadow projection will be applied first!
7709      * 
7710      * @param light
7711      *          the light's vector
7712      * @param planeTransform
7713      *          the transformation to transform the implied plane <code>y = 0</code> before applying the projection
7714      * @return this
7715      */
7716     ref public Matrix4x3d shadow(Vector4d light, Matrix4x3d planeTransform) return {
7717         shadow(light, planeTransform, this);
7718         return this;
7719     }
7720 
7721     public Matrix4x3d shadow(double lightX, double lightY, double lightZ, double lightW, Matrix4x3d planeTransform, ref Matrix4x3d dest) {
7722         // compute plane equation by transforming (y = 0)
7723         double a = planeTransform.m10;
7724         double b = planeTransform.m11;
7725         double c = planeTransform.m12;
7726         double d = -a * planeTransform.m30 - b * planeTransform.m31 - c * planeTransform.m32;
7727         return shadow(lightX, lightY, lightZ, lightW, a, b, c, d, dest);
7728     }
7729 
7730     /**
7731      * Apply a projection transformation to this matrix that projects onto the plane with the general plane equation
7732      * <code>y = 0</code> as if casting a shadow from a given light position/direction <code>(lightX, lightY, lightZ, lightW)</code>.
7733      * <p>
7734      * Before the shadow projection is applied, the plane is transformed via the specified <code>planeTransformation</code>.
7735      * <p>
7736      * If <code>lightW</code> is <code>0.0</code> the light is being treated as a directional light; if it is <code>1.0</code> it is a point light.
7737      * <p>
7738      * If <code>M</code> is <code>this</code> matrix and <code>S</code> the shadow matrix,
7739      * then the new matrix will be <code>M * S</code>. So when transforming a
7740      * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the
7741      * shadow projection will be applied first!
7742      * 
7743      * @param lightX
7744      *          the x-component of the light vector
7745      * @param lightY
7746      *          the y-component of the light vector
7747      * @param lightZ
7748      *          the z-component of the light vector
7749      * @param lightW
7750      *          the w-component of the light vector
7751      * @param planeTransform
7752      *          the transformation to transform the implied plane <code>y = 0</code> before applying the projection
7753      * @return this
7754      */
7755     ref public Matrix4x3d shadow(double lightX, double lightY, double lightZ, double lightW, Matrix4x3d planeTransform) return {
7756         shadow(lightX, lightY, lightZ, lightW, planeTransform, this);
7757         return this;
7758     }
7759 
7760     /**
7761      * Set this matrix to a cylindrical billboard transformation that rotates the local +Z axis of a given object with position <code>objPos</code> towards
7762      * a target position at <code>targetPos</code> while constraining a cylindrical rotation around the given <code>up</code> vector.
7763      * <p>
7764      * This method can be used to create the complete model transformation for a given object, including the translation of the object to
7765      * its position <code>objPos</code>.
7766      * 
7767      * @param objPos
7768      *          the position of the object to rotate towards <code>targetPos</code>
7769      * @param targetPos
7770      *          the position of the target (for example the camera) towards which to rotate the object
7771      * @param up
7772      *          the rotation axis (must be {@link Vector3d#normalize() normalized})
7773      * @return this
7774      */
7775     ref public Matrix4x3d billboardCylindrical(Vector3d objPos, Vector3d targetPos, Vector3d up) return {
7776         double dirX = targetPos.x - objPos.x;
7777         double dirY = targetPos.y - objPos.y;
7778         double dirZ = targetPos.z - objPos.z;
7779         // left = up x dir
7780         double leftX = up.y * dirZ - up.z * dirY;
7781         double leftY = up.z * dirX - up.x * dirZ;
7782         double leftZ = up.x * dirY - up.y * dirX;
7783         // normalize left
7784         double invLeftLen = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
7785         leftX *= invLeftLen;
7786         leftY *= invLeftLen;
7787         leftZ *= invLeftLen;
7788         // recompute dir by constraining rotation around 'up'
7789         // dir = left x up
7790         dirX = leftY * up.z - leftZ * up.y;
7791         dirY = leftZ * up.x - leftX * up.z;
7792         dirZ = leftX * up.y - leftY * up.x;
7793         // normalize dir
7794         double invDirLen = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
7795         dirX *= invDirLen;
7796         dirY *= invDirLen;
7797         dirZ *= invDirLen;
7798         // set matrix elements
7799         m00 = leftX;
7800         m01 = leftY;
7801         m02 = leftZ;
7802         m10 = up.x;
7803         m11 = up.y;
7804         m12 = up.z;
7805         m20 = dirX;
7806         m21 = dirY;
7807         m22 = dirZ;
7808         m30 = objPos.x;
7809         m31 = objPos.y;
7810         m32 = objPos.z;
7811         properties = PROPERTY_ORTHONORMAL;
7812         return this;
7813     }
7814 
7815     /**
7816      * Set this matrix to a spherical billboard transformation that rotates the local +Z axis of a given object with position <code>objPos</code> towards
7817      * a target position at <code>targetPos</code>.
7818      * <p>
7819      * This method can be used to create the complete model transformation for a given object, including the translation of the object to
7820      * its position <code>objPos</code>.
7821      * <p>
7822      * If preserving an <i>up</i> vector is not necessary when rotating the +Z axis, then a shortest arc rotation can be obtained 
7823      * using {@link #billboardSpherical(Vector3d, Vector3d)}.
7824      * 
7825      * @see #billboardSpherical(Vector3d, Vector3d)
7826      * 
7827      * @param objPos
7828      *          the position of the object to rotate towards <code>targetPos</code>
7829      * @param targetPos
7830      *          the position of the target (for example the camera) towards which to rotate the object
7831      * @param up
7832      *          the up axis used to orient the object
7833      * @return this
7834      */
7835     ref public Matrix4x3d billboardSpherical(Vector3d objPos, Vector3d targetPos, Vector3d up) return {
7836         double dirX = targetPos.x - objPos.x;
7837         double dirY = targetPos.y - objPos.y;
7838         double dirZ = targetPos.z - objPos.z;
7839         // normalize dir
7840         double invDirLen = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
7841         dirX *= invDirLen;
7842         dirY *= invDirLen;
7843         dirZ *= invDirLen;
7844         // left = up x dir
7845         double leftX = up.y * dirZ - up.z * dirY;
7846         double leftY = up.z * dirX - up.x * dirZ;
7847         double leftZ = up.x * dirY - up.y * dirX;
7848         // normalize left
7849         double invLeftLen = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
7850         leftX *= invLeftLen;
7851         leftY *= invLeftLen;
7852         leftZ *= invLeftLen;
7853         // up = dir x left
7854         double upX = dirY * leftZ - dirZ * leftY;
7855         double upY = dirZ * leftX - dirX * leftZ;
7856         double upZ = dirX * leftY - dirY * leftX;
7857         // set matrix elements
7858         m00 = leftX;
7859         m01 = leftY;
7860         m02 = leftZ;
7861         m10 = upX;
7862         m11 = upY;
7863         m12 = upZ;
7864         m20 = dirX;
7865         m21 = dirY;
7866         m22 = dirZ;
7867         m30 = objPos.x;
7868         m31 = objPos.y;
7869         m32 = objPos.z;
7870         properties = PROPERTY_ORTHONORMAL;
7871         return this;
7872     }
7873 
7874     /**
7875      * Set this matrix to a spherical billboard transformation that rotates the local +Z axis of a given object with position <code>objPos</code> towards
7876      * a target position at <code>targetPos</code> using a shortest arc rotation by not preserving any <i>up</i> vector of the object.
7877      * <p>
7878      * This method can be used to create the complete model transformation for a given object, including the translation of the object to
7879      * its position <code>objPos</code>.
7880      * <p>
7881      * In order to specify an <i>up</i> vector which needs to be maintained when rotating the +Z axis of the object,
7882      * use {@link #billboardSpherical(Vector3d, Vector3d, Vector3d)}.
7883      * 
7884      * @see #billboardSpherical(Vector3d, Vector3d, Vector3d)
7885      * 
7886      * @param objPos
7887      *          the position of the object to rotate towards <code>targetPos</code>
7888      * @param targetPos
7889      *          the position of the target (for example the camera) towards which to rotate the object
7890      * @return this
7891      */
7892     ref public Matrix4x3d billboardSpherical(Vector3d objPos, Vector3d targetPos) return {
7893         double toDirX = targetPos.x - objPos.x;
7894         double toDirY = targetPos.y - objPos.y;
7895         double toDirZ = targetPos.z - objPos.z;
7896         double x = -toDirY;
7897         double y = toDirX;
7898         double w = Math.sqrt(toDirX * toDirX + toDirY * toDirY + toDirZ * toDirZ) + toDirZ;
7899         double invNorm = Math.invsqrt(x * x + y * y + w * w);
7900         x *= invNorm;
7901         y *= invNorm;
7902         w *= invNorm;
7903         double q00 = (x + x) * x;
7904         double q11 = (y + y) * y;
7905         double q01 = (x + x) * y;
7906         double q03 = (x + x) * w;
7907         double q13 = (y + y) * w;
7908         m00 = 1.0 - q11;
7909         m01 = q01;
7910         m02 = -q13;
7911         m10 = q01;
7912         m11 = 1.0 - q00;
7913         m12 = q03;
7914         m20 = q13;
7915         m21 = -q03;
7916         m22 = 1.0 - q11 - q00;
7917         m30 = objPos.x;
7918         m31 = objPos.y;
7919         m32 = objPos.z;
7920         properties = PROPERTY_ORTHONORMAL;
7921         return this;
7922     }
7923 
7924     public int hashCode() {
7925         immutable int prime = 31;
7926         int result = 1;
7927         long temp;
7928         temp = Math.doubleToLongBits(m00);
7929         result = prime * result + cast(int) (temp ^ (temp >>> 32));
7930         temp = Math.doubleToLongBits(m01);
7931         result = prime * result + cast(int) (temp ^ (temp >>> 32));
7932         temp = Math.doubleToLongBits(m02);
7933         result = prime * result + cast(int) (temp ^ (temp >>> 32));
7934         temp = Math.doubleToLongBits(m10);
7935         result = prime * result + cast(int) (temp ^ (temp >>> 32));
7936         temp = Math.doubleToLongBits(m11);
7937         result = prime * result + cast(int) (temp ^ (temp >>> 32));
7938         temp = Math.doubleToLongBits(m12);
7939         result = prime * result + cast(int) (temp ^ (temp >>> 32));
7940         temp = Math.doubleToLongBits(m20);
7941         result = prime * result + cast(int) (temp ^ (temp >>> 32));
7942         temp = Math.doubleToLongBits(m21);
7943         result = prime * result + cast(int) (temp ^ (temp >>> 32));
7944         temp = Math.doubleToLongBits(m22);
7945         result = prime * result + cast(int) (temp ^ (temp >>> 32));
7946         temp = Math.doubleToLongBits(m30);
7947         result = prime * result + cast(int) (temp ^ (temp >>> 32));
7948         temp = Math.doubleToLongBits(m31);
7949         result = prime * result + cast(int) (temp ^ (temp >>> 32));
7950         temp = Math.doubleToLongBits(m32);
7951         result = prime * result + cast(int) (temp ^ (temp >>> 32));
7952         return result;
7953     }
7954 
7955     public bool equals(Matrix4x3d m, double delta) {
7956         if (this == m)
7957             return true;
7958         if (!Math.equals(m00, m.m00, delta))
7959             return false;
7960         if (!Math.equals(m01, m.m01, delta))
7961             return false;
7962         if (!Math.equals(m02, m.m02, delta))
7963             return false;
7964         if (!Math.equals(m10, m.m10, delta))
7965             return false;
7966         if (!Math.equals(m11, m.m11, delta))
7967             return false;
7968         if (!Math.equals(m12, m.m12, delta))
7969             return false;
7970         if (!Math.equals(m20, m.m20, delta))
7971             return false;
7972         if (!Math.equals(m21, m.m21, delta))
7973             return false;
7974         if (!Math.equals(m22, m.m22, delta))
7975             return false;
7976         if (!Math.equals(m30, m.m30, delta))
7977             return false;
7978         if (!Math.equals(m31, m.m31, delta))
7979             return false;
7980         if (!Math.equals(m32, m.m32, delta))
7981             return false;
7982         return true;
7983     }
7984 
7985     public Matrix4x3d pick(double x, double y, double width, double height, int[] viewport, ref Matrix4x3d dest) {
7986         double sx = viewport[2] / width;
7987         double sy = viewport[3] / height;
7988         double tx = (viewport[2] + 2.0 * (viewport[0] - x)) / width;
7989         double ty = (viewport[3] + 2.0 * (viewport[1] - y)) / height;
7990         dest.m30 = m00 * tx + m10 * ty + m30;
7991         dest.m31 = m01 * tx + m11 * ty + m31;
7992         dest.m32 = m02 * tx + m12 * ty + m32;
7993         dest.m00 = m00 * sx;
7994         dest.m01 = m01 * sx;
7995         dest.m02 = m02 * sx;
7996         dest.m10 = m10 * sy;
7997         dest.m11 = m11 * sy;
7998         dest.m12 = m12 * sy;
7999         dest.properties = 0;
8000         return dest;
8001     }
8002 
8003     /**
8004      * Apply a picking transformation to this matrix using the given window coordinates <code>(x, y)</code> as the pick center
8005      * and the given <code>(width, height)</code> as the size of the picking region in window coordinates.
8006      * 
8007      * @param x
8008      *          the x coordinate of the picking region center in window coordinates
8009      * @param y
8010      *          the y coordinate of the picking region center in window coordinates
8011      * @param width
8012      *          the width of the picking region in window coordinates
8013      * @param height
8014      *          the height of the picking region in window coordinates
8015      * @param viewport
8016      *          the viewport described by <code>[x, y, width, height]</code>
8017      * @return this
8018      */
8019     ref public Matrix4x3d pick(double x, double y, double width, double height, int[] viewport) return {
8020         pick(x, y, width, height, viewport, this);
8021         return this;
8022     }
8023 
8024     /**
8025      * Exchange the values of <code>this</code> matrix with the given <code>other</code> matrix.
8026      * 
8027      * @param other
8028      *          the other matrix to exchange the values with
8029      * @return this
8030      */
8031     ref public Matrix4x3d swap(ref Matrix4x3d other) return {
8032         double tmp;
8033         tmp = m00; m00 = other.m00; other.m00 = tmp;
8034         tmp = m01; m01 = other.m01; other.m01 = tmp;
8035         tmp = m02; m02 = other.m02; other.m02 = tmp;
8036         tmp = m10; m10 = other.m10; other.m10 = tmp;
8037         tmp = m11; m11 = other.m11; other.m11 = tmp;
8038         tmp = m12; m12 = other.m12; other.m12 = tmp;
8039         tmp = m20; m20 = other.m20; other.m20 = tmp;
8040         tmp = m21; m21 = other.m21; other.m21 = tmp;
8041         tmp = m22; m22 = other.m22; other.m22 = tmp;
8042         tmp = m30; m30 = other.m30; other.m30 = tmp;
8043         tmp = m31; m31 = other.m31; other.m31 = tmp;
8044         tmp = m32; m32 = other.m32; other.m32 = tmp;
8045         int props = properties;
8046         this.properties = other.properties;
8047         other.properties = props;
8048         return this;
8049     }
8050 
8051     public Matrix4x3d arcball(double radius, double centerX, double centerY, double centerZ, double angleX, double angleY, ref Matrix4x3d dest) {
8052         double m30 = m20 * -radius + this.m30;
8053         double m31 = m21 * -radius + this.m31;
8054         double m32 = m22 * -radius + this.m32;
8055         double sin = Math.sin(angleX);
8056         double cos = Math.cosFromSin(sin, angleX);
8057         double nm10 = m10 * cos + m20 * sin;
8058         double nm11 = m11 * cos + m21 * sin;
8059         double nm12 = m12 * cos + m22 * sin;
8060         double m20 = this.m20 * cos - m10 * sin;
8061         double m21 = this.m21 * cos - m11 * sin;
8062         double m22 = this.m22 * cos - m12 * sin;
8063         sin = Math.sin(angleY);
8064         cos = Math.cosFromSin(sin, angleY);
8065         double nm00 = m00 * cos - m20 * sin;
8066         double nm01 = m01 * cos - m21 * sin;
8067         double nm02 = m02 * cos - m22 * sin;
8068         double nm20 = m00 * sin + m20 * cos;
8069         double nm21 = m01 * sin + m21 * cos;
8070         double nm22 = m02 * sin + m22 * cos;
8071         dest.m30 = -nm00 * centerX - nm10 * centerY - nm20 * centerZ + m30;
8072         dest.m31 = -nm01 * centerX - nm11 * centerY - nm21 * centerZ + m31;
8073         dest.m32 = -nm02 * centerX - nm12 * centerY - nm22 * centerZ + m32;
8074         dest.m20 = nm20;
8075         dest.m21 = nm21;
8076         dest.m22 = nm22;
8077         dest.m10 = nm10;
8078         dest.m11 = nm11;
8079         dest.m12 = nm12;
8080         dest.m00 = nm00;
8081         dest.m01 = nm01;
8082         dest.m02 = nm02;
8083         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
8084         return dest;
8085     }
8086 
8087     public Matrix4x3d arcball(double radius, Vector3d center, double angleX, double angleY, ref Matrix4x3d dest) {
8088         return arcball(radius, center.x, center.y, center.z, angleX, angleY, dest);
8089     }
8090 
8091     /**
8092      * Apply an arcball view transformation to this matrix with the given <code>radius</code> and center <code>(centerX, centerY, centerZ)</code>
8093      * position of the arcball and the specified X and Y rotation angles.
8094      * <p>
8095      * This method is equivalent to calling: <code>translate(0, 0, -radius).rotateX(angleX).rotateY(angleY).translate(-centerX, -centerY, -centerZ)</code>
8096      * 
8097      * @param radius
8098      *          the arcball radius
8099      * @param centerX
8100      *          the x coordinate of the center position of the arcball
8101      * @param centerY
8102      *          the y coordinate of the center position of the arcball
8103      * @param centerZ
8104      *          the z coordinate of the center position of the arcball
8105      * @param angleX
8106      *          the rotation angle around the X axis in radians
8107      * @param angleY
8108      *          the rotation angle around the Y axis in radians
8109      * @return this
8110      */
8111     ref public Matrix4x3d arcball(double radius, double centerX, double centerY, double centerZ, double angleX, double angleY) return {
8112         arcball(radius, centerX, centerY, centerZ, angleX, angleY, this);
8113         return this;
8114     }
8115 
8116     /**
8117      * Apply an arcball view transformation to this matrix with the given <code>radius</code> and <code>center</code>
8118      * position of the arcball and the specified X and Y rotation angles.
8119      * <p>
8120      * This method is equivalent to calling: <code>translate(0, 0, -radius).rotateX(angleX).rotateY(angleY).translate(-center.x, -center.y, -center.z)</code>
8121      * 
8122      * @param radius
8123      *          the arcball radius
8124      * @param center
8125      *          the center position of the arcball
8126      * @param angleX
8127      *          the rotation angle around the X axis in radians
8128      * @param angleY
8129      *          the rotation angle around the Y axis in radians
8130      * @return this
8131      */
8132     ref public Matrix4x3d arcball(double radius, Vector3d center, double angleX, double angleY) return {
8133         arcball(radius, center.x, center.y, center.z, angleX, angleY, this);
8134         return this;
8135     }
8136 
8137     public Matrix4x3d transformAab(double minX, double minY, double minZ, double maxX, double maxY, double maxZ, Vector3d outMin, Vector3d outMax) {
8138         double xax = m00 * minX, xay = m01 * minX, xaz = m02 * minX;
8139         double xbx = m00 * maxX, xby = m01 * maxX, xbz = m02 * maxX;
8140         double yax = m10 * minY, yay = m11 * minY, yaz = m12 * minY;
8141         double ybx = m10 * maxY, yby = m11 * maxY, ybz = m12 * maxY;
8142         double zax = m20 * minZ, zay = m21 * minZ, zaz = m22 * minZ;
8143         double zbx = m20 * maxZ, zby = m21 * maxZ, zbz = m22 * maxZ;
8144         double xminx, xminy, xminz, yminx, yminy, yminz, zminx, zminy, zminz;
8145         double xmaxx, xmaxy, xmaxz, ymaxx, ymaxy, ymaxz, zmaxx, zmaxy, zmaxz;
8146         if (xax < xbx) {
8147             xminx = xax;
8148             xmaxx = xbx;
8149         } else {
8150             xminx = xbx;
8151             xmaxx = xax;
8152         }
8153         if (xay < xby) {
8154             xminy = xay;
8155             xmaxy = xby;
8156         } else {
8157             xminy = xby;
8158             xmaxy = xay;
8159         }
8160         if (xaz < xbz) {
8161             xminz = xaz;
8162             xmaxz = xbz;
8163         } else {
8164             xminz = xbz;
8165             xmaxz = xaz;
8166         }
8167         if (yax < ybx) {
8168             yminx = yax;
8169             ymaxx = ybx;
8170         } else {
8171             yminx = ybx;
8172             ymaxx = yax;
8173         }
8174         if (yay < yby) {
8175             yminy = yay;
8176             ymaxy = yby;
8177         } else {
8178             yminy = yby;
8179             ymaxy = yay;
8180         }
8181         if (yaz < ybz) {
8182             yminz = yaz;
8183             ymaxz = ybz;
8184         } else {
8185             yminz = ybz;
8186             ymaxz = yaz;
8187         }
8188         if (zax < zbx) {
8189             zminx = zax;
8190             zmaxx = zbx;
8191         } else {
8192             zminx = zbx;
8193             zmaxx = zax;
8194         }
8195         if (zay < zby) {
8196             zminy = zay;
8197             zmaxy = zby;
8198         } else {
8199             zminy = zby;
8200             zmaxy = zay;
8201         }
8202         if (zaz < zbz) {
8203             zminz = zaz;
8204             zmaxz = zbz;
8205         } else {
8206             zminz = zbz;
8207             zmaxz = zaz;
8208         }
8209         outMin.x = xminx + yminx + zminx + m30;
8210         outMin.y = xminy + yminy + zminy + m31;
8211         outMin.z = xminz + yminz + zminz + m32;
8212         outMax.x = xmaxx + ymaxx + zmaxx + m30;
8213         outMax.y = xmaxy + ymaxy + zmaxy + m31;
8214         outMax.z = xmaxz + ymaxz + zmaxz + m32;
8215         return this;
8216     }
8217 
8218     public Matrix4x3d transformAab(Vector3d min, Vector3d max, Vector3d outMin, Vector3d outMax) {
8219         return transformAab(min.x, min.y, min.z, max.x, max.y, max.z, outMin, outMax);
8220     }
8221 
8222     /**
8223      * Linearly interpolate <code>this</code> and <code>other</code> using the given interpolation factor <code>t</code>
8224      * and store the result in <code>this</code>.
8225      * <p>
8226      * If <code>t</code> is <code>0.0</code> then the result is <code>this</code>. If the interpolation factor is <code>1.0</code>
8227      * then the result is <code>other</code>.
8228      *
8229      * @param other
8230      *          the other matrix
8231      * @param t
8232      *          the interpolation factor between 0.0 and 1.0
8233      * @return this
8234      */
8235     ref public Matrix4x3d lerp(Matrix4x3d other, double t) return {
8236         lerp(other, t, this);
8237         return this;
8238     }
8239 
8240     public Matrix4x3d lerp(Matrix4x3d other, double t, ref Matrix4x3d dest) {
8241         dest.m00 = Math.fma(other.m00 - m00, t, m00);
8242         dest.m01 = Math.fma(other.m01 - m01, t, m01);
8243         dest.m02 = Math.fma(other.m02 - m02, t, m02);
8244         dest.m10 = Math.fma(other.m10 - m10, t, m10);
8245         dest.m11 = Math.fma(other.m11 - m11, t, m11);
8246         dest.m12 = Math.fma(other.m12 - m12, t, m12);
8247         dest.m20 = Math.fma(other.m20 - m20, t, m20);
8248         dest.m21 = Math.fma(other.m21 - m21, t, m21);
8249         dest.m22 = Math.fma(other.m22 - m22, t, m22);
8250         dest.m30 = Math.fma(other.m30 - m30, t, m30);
8251         dest.m31 = Math.fma(other.m31 - m31, t, m31);
8252         dest.m32 = Math.fma(other.m32 - m32, t, m32);
8253         dest.properties = properties & other.properties;
8254         return dest;
8255     }
8256 
8257     /**
8258      * Apply a model transformation to this matrix for a right-handed coordinate system, 
8259      * that aligns the local <code>+Z</code> axis with <code>dir</code>
8260      * and store the result in <code>dest</code>.
8261      * <p>
8262      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix,
8263      * then the new matrix will be <code>M * L</code>. So when transforming a
8264      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>,
8265      * the lookat transformation will be applied first!
8266      * <p>
8267      * In order to set the matrix to a rotation transformation without post-multiplying it,
8268      * use {@link #rotationTowards(Vector3d, Vector3d) rotationTowards()}.
8269      * <p>
8270      * This method is equivalent to calling: <code>mul(new Matrix4x3d().lookAt(new Vector3d(), new Vector3d(dir).negate(), up).invert(), dest)</code>
8271      * 
8272      * @see #rotateTowards(double, double, double, double, double, double, Matrix4x3d)
8273      * @see #rotationTowards(Vector3d, Vector3d)
8274      * 
8275      * @param dir
8276      *              the direction to rotate towards
8277      * @param up
8278      *              the up vector
8279      * @param dest
8280      *              will hold the result
8281      * @return dest
8282      */
8283     public Matrix4x3d rotateTowards(ref Vector3d dir, Vector3d up, ref Matrix4x3d dest) {
8284         return rotateTowards(dir.x, dir.y, dir.z, up.x, up.y, up.z, dest);
8285     }
8286 
8287     /**
8288      * Apply a model transformation to this matrix for a right-handed coordinate system, 
8289      * that aligns the local <code>+Z</code> axis with <code>dir</code>.
8290      * <p>
8291      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix,
8292      * then the new matrix will be <code>M * L</code>. So when transforming a
8293      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>,
8294      * the lookat transformation will be applied first!
8295      * <p>
8296      * In order to set the matrix to a rotation transformation without post-multiplying it,
8297      * use {@link #rotationTowards(Vector3d, Vector3d) rotationTowards()}.
8298      * <p>
8299      * This method is equivalent to calling: <code>mul(new Matrix4x3d().lookAt(new Vector3d(), new Vector3d(dir).negate(), up).invert())</code>
8300      * 
8301      * @see #rotateTowards(double, double, double, double, double, double)
8302      * @see #rotationTowards(Vector3d, Vector3d)
8303      * 
8304      * @param dir
8305      *              the direction to orient towards
8306      * @param up
8307      *              the up vector
8308      * @return this
8309      */
8310     ref public Matrix4x3d rotateTowards(ref Vector3d dir, Vector3d up) return {
8311         rotateTowards(dir.x, dir.y, dir.z, up.x, up.y, up.z, this);
8312         return this;
8313     }
8314 
8315     /**
8316      * Apply a model transformation to this matrix for a right-handed coordinate system, 
8317      * that aligns the local <code>+Z</code> axis with <code>(dirX, dirY, dirZ)</code>.
8318      * <p>
8319      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix,
8320      * then the new matrix will be <code>M * L</code>. So when transforming a
8321      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>,
8322      * the lookat transformation will be applied first!
8323      * <p>
8324      * In order to set the matrix to a rotation transformation without post-multiplying it,
8325      * use {@link #rotationTowards(double, double, double, double, double, double) rotationTowards()}.
8326      * <p>
8327      * This method is equivalent to calling: <code>mul(new Matrix4x3d().lookAt(0, 0, 0, -dirX, -dirY, -dirZ, upX, upY, upZ).invert())</code>
8328      * 
8329      * @see #rotateTowards(Vector3d, Vector3d)
8330      * @see #rotationTowards(double, double, double, double, double, double)
8331      * 
8332      * @param dirX
8333      *              the x-coordinate of the direction to rotate towards
8334      * @param dirY
8335      *              the y-coordinate of the direction to rotate towards
8336      * @param dirZ
8337      *              the z-coordinate of the direction to rotate towards
8338      * @param upX
8339      *              the x-coordinate of the up vector
8340      * @param upY
8341      *              the y-coordinate of the up vector
8342      * @param upZ
8343      *              the z-coordinate of the up vector
8344      * @return this
8345      */
8346     ref public Matrix4x3d rotateTowards(double dirX, double dirY, double dirZ, double upX, double upY, double upZ) return {
8347         rotateTowards(dirX, dirY, dirZ, upX, upY, upZ, this);
8348         return this;
8349     }
8350 
8351     /**
8352      * Apply a model transformation to this matrix for a right-handed coordinate system, 
8353      * that aligns the local <code>+Z</code> axis with <code>(dirX, dirY, dirZ)</code>
8354      * and store the result in <code>dest</code>.
8355      * <p>
8356      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix,
8357      * then the new matrix will be <code>M * L</code>. So when transforming a
8358      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>,
8359      * the lookat transformation will be applied first!
8360      * <p>
8361      * In order to set the matrix to a rotation transformation without post-multiplying it,
8362      * use {@link #rotationTowards(double, double, double, double, double, double) rotationTowards()}.
8363      * <p>
8364      * This method is equivalent to calling: <code>mul(new Matrix4x3d().lookAt(0, 0, 0, -dirX, -dirY, -dirZ, upX, upY, upZ).invert(), dest)</code>
8365      * 
8366      * @see #rotateTowards(Vector3d, Vector3d)
8367      * @see #rotationTowards(double, double, double, double, double, double)
8368      * 
8369      * @param dirX
8370      *              the x-coordinate of the direction to rotate towards
8371      * @param dirY
8372      *              the y-coordinate of the direction to rotate towards
8373      * @param dirZ
8374      *              the z-coordinate of the direction to rotate towards
8375      * @param upX
8376      *              the x-coordinate of the up vector
8377      * @param upY
8378      *              the y-coordinate of the up vector
8379      * @param upZ
8380      *              the z-coordinate of the up vector
8381      * @param dest
8382      *              will hold the result
8383      * @return dest
8384      */
8385     public Matrix4x3d rotateTowards(double dirX, double dirY, double dirZ, double upX, double upY, double upZ, ref Matrix4x3d dest) {
8386         // Normalize direction
8387         double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
8388         double ndirX = dirX * invDirLength;
8389         double ndirY = dirY * invDirLength;
8390         double ndirZ = dirZ * invDirLength;
8391         // left = up x direction
8392         double leftX, leftY, leftZ;
8393         leftX = upY * ndirZ - upZ * ndirY;
8394         leftY = upZ * ndirX - upX * ndirZ;
8395         leftZ = upX * ndirY - upY * ndirX;
8396         // normalize left
8397         double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
8398         leftX *= invLeftLength;
8399         leftY *= invLeftLength;
8400         leftZ *= invLeftLength;
8401         // up = direction x left
8402         double upnX = ndirY * leftZ - ndirZ * leftY;
8403         double upnY = ndirZ * leftX - ndirX * leftZ;
8404         double upnZ = ndirX * leftY - ndirY * leftX;
8405         double rm00 = leftX;
8406         double rm01 = leftY;
8407         double rm02 = leftZ;
8408         double rm10 = upnX;
8409         double rm11 = upnY;
8410         double rm12 = upnZ;
8411         double rm20 = ndirX;
8412         double rm21 = ndirY;
8413         double rm22 = ndirZ;
8414         dest.m30 = m30;
8415         dest.m31 = m31;
8416         dest.m32 = m32;
8417         double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
8418         double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
8419         double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
8420         double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
8421         double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
8422         double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
8423         dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
8424         dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
8425         dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
8426         dest.m00 = nm00;
8427         dest.m01 = nm01;
8428         dest.m02 = nm02;
8429         dest.m10 = nm10;
8430         dest.m11 = nm11;
8431         dest.m12 = nm12;
8432         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
8433         return dest;
8434     }
8435 
8436     /**
8437      * Set this matrix to a model transformation for a right-handed coordinate system, 
8438      * that aligns the local <code>-z</code> axis with <code>dir</code>.
8439      * <p>
8440      * In order to apply the rotation transformation to a previous existing transformation,
8441      * use {@link #rotateTowards(double, double, double, double, double, double) rotateTowards}.
8442      * <p>
8443      * This method is equivalent to calling: <code>setLookAt(new Vector3d(), new Vector3d(dir).negate(), up).invert()</code>
8444      * 
8445      * @see #rotationTowards(Vector3d, Vector3d)
8446      * @see #rotateTowards(double, double, double, double, double, double)
8447      * 
8448      * @param dir
8449      *              the direction to orient the local -z axis towards
8450      * @param up
8451      *              the up vector
8452      * @return this
8453      */
8454     ref public Matrix4x3d rotationTowards(ref Vector3d dir, Vector3d up) return {
8455         return rotationTowards(dir.x, dir.y, dir.z, up.x, up.y, up.z);
8456     }
8457 
8458     /**
8459      * Set this matrix to a model transformation for a right-handed coordinate system, 
8460      * that aligns the local <code>-z</code> axis with <code>(dirX, dirY, dirZ)</code>.
8461      * <p>
8462      * In order to apply the rotation transformation to a previous existing transformation,
8463      * use {@link #rotateTowards(double, double, double, double, double, double) rotateTowards}.
8464      * <p>
8465      * This method is equivalent to calling: <code>setLookAt(0, 0, 0, -dirX, -dirY, -dirZ, upX, upY, upZ).invert()</code>
8466      * 
8467      * @see #rotateTowards(Vector3d, Vector3d)
8468      * @see #rotationTowards(double, double, double, double, double, double)
8469      * 
8470      * @param dirX
8471      *              the x-coordinate of the direction to rotate towards
8472      * @param dirY
8473      *              the y-coordinate of the direction to rotate towards
8474      * @param dirZ
8475      *              the z-coordinate of the direction to rotate towards
8476      * @param upX
8477      *              the x-coordinate of the up vector
8478      * @param upY
8479      *              the y-coordinate of the up vector
8480      * @param upZ
8481      *              the z-coordinate of the up vector
8482      * @return this
8483      */
8484     ref public Matrix4x3d rotationTowards(double dirX, double dirY, double dirZ, double upX, double upY, double upZ) return {
8485         // Normalize direction
8486         double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
8487         double ndirX = dirX * invDirLength;
8488         double ndirY = dirY * invDirLength;
8489         double ndirZ = dirZ * invDirLength;
8490         // left = up x direction
8491         double leftX, leftY, leftZ;
8492         leftX = upY * ndirZ - upZ * ndirY;
8493         leftY = upZ * ndirX - upX * ndirZ;
8494         leftZ = upX * ndirY - upY * ndirX;
8495         // normalize left
8496         double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
8497         leftX *= invLeftLength;
8498         leftY *= invLeftLength;
8499         leftZ *= invLeftLength;
8500         // up = direction x left
8501         double upnX = ndirY * leftZ - ndirZ * leftY;
8502         double upnY = ndirZ * leftX - ndirX * leftZ;
8503         double upnZ = ndirX * leftY - ndirY * leftX;
8504         this.m00 = leftX;
8505         this.m01 = leftY;
8506         this.m02 = leftZ;
8507         this.m10 = upnX;
8508         this.m11 = upnY;
8509         this.m12 = upnZ;
8510         this.m20 = ndirX;
8511         this.m21 = ndirY;
8512         this.m22 = ndirZ;
8513         this.m30 = 0.0;
8514         this.m31 = 0.0;
8515         this.m32 = 0.0;
8516         properties = PROPERTY_ORTHONORMAL;
8517         return this;
8518     }
8519 
8520     /**
8521      * Set this matrix to a model transformation for a right-handed coordinate system, 
8522      * that translates to the given <code>pos</code> and aligns the local <code>-z</code>
8523      * axis with <code>dir</code>.
8524      * <p>
8525      * This method is equivalent to calling: <code>translation(pos).rotateTowards(dir, up)</code>
8526      * 
8527      * @see #translation(Vector3d)
8528      * @see #rotateTowards(Vector3d, Vector3d)
8529      *
8530      * @param pos
8531      *              the position to translate to
8532      * @param dir
8533      *              the direction to rotate towards
8534      * @param up
8535      *              the up vector
8536      * @return this
8537      */
8538     ref public Matrix4x3d translationRotateTowards(Vector3d pos, ref Vector3d dir, Vector3d up) return {
8539         return translationRotateTowards(pos.x, pos.y, pos.z, dir.x, dir.y, dir.z, up.x, up.y, up.z);
8540     }
8541 
8542     /**
8543      * Set this matrix to a model transformation for a right-handed coordinate system, 
8544      * that translates to the given <code>(posX, posY, posZ)</code> and aligns the local <code>-z</code>
8545      * axis with <code>(dirX, dirY, dirZ)</code>.
8546      * <p>
8547      * This method is equivalent to calling: <code>translation(posX, posY, posZ).rotateTowards(dirX, dirY, dirZ, upX, upY, upZ)</code>
8548      * 
8549      * @see #translation(double, double, double)
8550      * @see #rotateTowards(double, double, double, double, double, double)
8551      * 
8552      * @param posX
8553      *              the x-coordinate of the position to translate to
8554      * @param posY
8555      *              the y-coordinate of the position to translate to
8556      * @param posZ
8557      *              the z-coordinate of the position to translate to
8558      * @param dirX
8559      *              the x-coordinate of the direction to rotate towards
8560      * @param dirY
8561      *              the y-coordinate of the direction to rotate towards
8562      * @param dirZ
8563      *              the z-coordinate of the direction to rotate towards
8564      * @param upX
8565      *              the x-coordinate of the up vector
8566      * @param upY
8567      *              the y-coordinate of the up vector
8568      * @param upZ
8569      *              the z-coordinate of the up vector
8570      * @return this
8571      */
8572     ref public Matrix4x3d translationRotateTowards(double posX, double posY, double posZ, double dirX, double dirY, double dirZ, double upX, double upY, double upZ) return {
8573         // Normalize direction
8574         double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
8575         double ndirX = dirX * invDirLength;
8576         double ndirY = dirY * invDirLength;
8577         double ndirZ = dirZ * invDirLength;
8578         // left = up x direction
8579         double leftX, leftY, leftZ;
8580         leftX = upY * ndirZ - upZ * ndirY;
8581         leftY = upZ * ndirX - upX * ndirZ;
8582         leftZ = upX * ndirY - upY * ndirX;
8583         // normalize left
8584         double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
8585         leftX *= invLeftLength;
8586         leftY *= invLeftLength;
8587         leftZ *= invLeftLength;
8588         // up = direction x left
8589         double upnX = ndirY * leftZ - ndirZ * leftY;
8590         double upnY = ndirZ * leftX - ndirX * leftZ;
8591         double upnZ = ndirX * leftY - ndirY * leftX;
8592         this.m00 = leftX;
8593         this.m01 = leftY;
8594         this.m02 = leftZ;
8595         this.m10 = upnX;
8596         this.m11 = upnY;
8597         this.m12 = upnZ;
8598         this.m20 = ndirX;
8599         this.m21 = ndirY;
8600         this.m22 = ndirZ;
8601         this.m30 = posX;
8602         this.m31 = posY;
8603         this.m32 = posZ;
8604         properties = PROPERTY_ORTHONORMAL;
8605         return this;
8606     }
8607 
8608     public Vector3d getEulerAnglesZYX(ref Vector3d dest) {
8609         dest.x = Math.atan2(m12, m22);
8610         dest.y = Math.atan2(-m02, Math.sqrt(1.0 - m02 * m02));
8611         dest.z = Math.atan2(m01, m00);
8612         return dest;
8613     }
8614 
8615     public Vector3d getEulerAnglesXYZ(ref Vector3d dest) {
8616         dest.x = Math.atan2(-m21, m22);
8617         dest.y = Math.atan2(m20, Math.sqrt(1.0 - m20 * m20));
8618         dest.z = Math.atan2(-m10, m00);
8619         return dest;
8620     }
8621 
8622     /**
8623      * Apply an oblique projection transformation to this matrix with the given values for <code>a</code> and
8624      * <code>b</code>.
8625      * <p>
8626      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the oblique transformation matrix,
8627      * then the new matrix will be <code>M * O</code>. So when transforming a
8628      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
8629      * oblique transformation will be applied first!
8630      * <p>
8631      * The oblique transformation is defined as:
8632      * <pre>
8633      * x' = x + a*z
8634      * y' = y + a*z
8635      * z' = z
8636      * </pre>
8637      * or in matrix form:
8638      * <pre>
8639      * 1 0 a 0
8640      * 0 1 b 0
8641      * 0 0 1 0
8642      * </pre>
8643      * 
8644      * @param a
8645      *            the value for the z factor that applies to x
8646      * @param b
8647      *            the value for the z factor that applies to y
8648      * @return this
8649      */
8650     ref public Matrix4x3d obliqueZ(double a, double b) return {
8651         this.m20 = m00 * a + m10 * b + m20;
8652         this.m21 = m01 * a + m11 * b + m21;
8653         this.m22 = m02 * a + m12 * b + m22;
8654         this.properties = 0;
8655         return this;
8656     }
8657 
8658     /**
8659      * Apply an oblique projection transformation to this matrix with the given values for <code>a</code> and
8660      * <code>b</code> and store the result in <code>dest</code>.
8661      * <p>
8662      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the oblique transformation matrix,
8663      * then the new matrix will be <code>M * O</code>. So when transforming a
8664      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
8665      * oblique transformation will be applied first!
8666      * <p>
8667      * The oblique transformation is defined as:
8668      * <pre>
8669      * x' = x + a*z
8670      * y' = y + a*z
8671      * z' = z
8672      * </pre>
8673      * or in matrix form:
8674      * <pre>
8675      * 1 0 a 0
8676      * 0 1 b 0
8677      * 0 0 1 0
8678      * </pre>
8679      * 
8680      * @param a
8681      *            the value for the z factor that applies to x
8682      * @param b
8683      *            the value for the z factor that applies to y
8684      * @param dest
8685      *            will hold the result
8686      * @return dest
8687      */
8688     public Matrix4x3d obliqueZ(double a, double b, ref Matrix4x3d dest) {
8689         dest.m00 = m00;
8690         dest.m01 = m01;
8691         dest.m02 = m02;
8692         dest.m10 = m10;
8693         dest.m11 = m11;
8694         dest.m12 = m12;
8695         dest.m20 = m00 * a + m10 * b + m20;
8696         dest.m21 = m01 * a + m11 * b + m21;
8697         dest.m22 = m02 * a + m12 * b + m22;
8698         dest.m30 = m30;
8699         dest.m31 = m31;
8700         dest.m32 = m32;
8701         dest.properties = 0;
8702         return dest;
8703     }
8704 
8705     /**
8706      * Multiply <code>this</code> by the matrix
8707      * <pre>
8708      * 1 0 0 0
8709      * 0 0 1 0
8710      * 0 1 0 0
8711      * </pre>
8712      * 
8713      * @return this
8714      */
8715     ref public Matrix4x3d mapXZY() return {
8716         mapXZY(this);
8717         return this;
8718     }
8719     public Matrix4x3d mapXZY(ref Matrix4x3d dest) {
8720         double m10 = this.m10, m11 = this.m11, m12 = this.m12;
8721         return dest._m00(m00)._m01(m01)._m02(m02)._m10(m20)._m11(m21)._m12(m22)._m20(m10)._m21(m11)._m22(m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
8722     }
8723     /**
8724      * Multiply <code>this</code> by the matrix
8725      * <pre>
8726      * 1 0  0 0
8727      * 0 0 -1 0
8728      * 0 1  0 0
8729      * </pre>
8730      * 
8731      * @return this
8732      */
8733     ref public Matrix4x3d mapXZnY() return {
8734         mapXZnY(this);
8735         return this;
8736     }
8737     public Matrix4x3d mapXZnY(ref Matrix4x3d dest) {
8738         double m10 = this.m10, m11 = this.m11, m12 = this.m12;
8739         return dest._m00(m00)._m01(m01)._m02(m02)._m10(m20)._m11(m21)._m12(m22)._m20(-m10)._m21(-m11)._m22(-m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
8740     }
8741     /**
8742      * Multiply <code>this</code> by the matrix
8743      * <pre>
8744      * 1  0  0 0
8745      * 0 -1  0 0
8746      * 0  0 -1 0
8747      * </pre>
8748      * 
8749      * @return this
8750      */
8751     ref public Matrix4x3d mapXnYnZ() return {
8752         mapXnYnZ(this);
8753         return this;
8754     }
8755     public Matrix4x3d mapXnYnZ(ref Matrix4x3d dest) {
8756         return dest._m00(m00)._m01(m01)._m02(m02)._m10(-m10)._m11(-m11)._m12(-m12)._m20(-m20)._m21(-m21)._m22(-m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
8757     }
8758     /**
8759      * Multiply <code>this</code> by the matrix
8760      * <pre>
8761      * 1  0 0 0
8762      * 0  0 1 0
8763      * 0 -1 0 0
8764      * </pre>
8765      * 
8766      * @return this
8767      */
8768     ref public Matrix4x3d mapXnZY() return {
8769         mapXnZY(this);
8770         return this;
8771     }
8772     public Matrix4x3d mapXnZY(ref Matrix4x3d dest) {
8773         double m10 = this.m10, m11 = this.m11, m12 = this.m12;
8774         return dest._m00(m00)._m01(m01)._m02(m02)._m10(-m20)._m11(-m21)._m12(-m22)._m20(m10)._m21(m11)._m22(m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
8775     }
8776     /**
8777      * Multiply <code>this</code> by the matrix
8778      * <pre>
8779      * 1  0  0 0
8780      * 0  0 -1 0
8781      * 0 -1  0 0
8782      * </pre>
8783      * 
8784      * @return this
8785      */
8786     ref public Matrix4x3d mapXnZnY() return {
8787         mapXnZnY(this);
8788         return this;
8789     }
8790     public Matrix4x3d mapXnZnY(ref Matrix4x3d dest) {
8791         double m10 = this.m10, m11 = this.m11, m12 = this.m12;
8792         return dest._m00(m00)._m01(m01)._m02(m02)._m10(-m20)._m11(-m21)._m12(-m22)._m20(-m10)._m21(-m11)._m22(-m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
8793     }
8794     /**
8795      * Multiply <code>this</code> by the matrix
8796      * <pre>
8797      * 0 1 0 0
8798      * 1 0 0 0
8799      * 0 0 1 0
8800      * </pre>
8801      * 
8802      * @return this
8803      */
8804     ref public Matrix4x3d mapYXZ() return {
8805         mapYXZ(this);
8806         return this;
8807     }
8808     public Matrix4x3d mapYXZ(ref Matrix4x3d dest) {
8809         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
8810         return dest._m00(m10)._m01(m11)._m02(m12)._m10(m00)._m11(m01)._m12(m02)._m20(m20)._m21(m21)._m22(m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
8811     }
8812     /**
8813      * Multiply <code>this</code> by the matrix
8814      * <pre>
8815      * 0 1  0 0
8816      * 1 0  0 0
8817      * 0 0 -1 0
8818      * </pre>
8819      * 
8820      * @return this
8821      */
8822     ref public Matrix4x3d mapYXnZ() return {
8823         mapYXnZ(this);
8824         return this;
8825     }
8826     public Matrix4x3d mapYXnZ(ref Matrix4x3d dest) {
8827         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
8828         return dest._m00(m10)._m01(m11)._m02(m12)._m10(m00)._m11(m01)._m12(m02)._m20(-m20)._m21(-m21)._m22(-m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
8829     }
8830     /**
8831      * Multiply <code>this</code> by the matrix
8832      * <pre>
8833      * 0 0 1 0
8834      * 1 0 0 0
8835      * 0 1 0 0
8836      * </pre>
8837      * 
8838      * @return this
8839      */
8840     ref public Matrix4x3d mapYZX() return {
8841         mapYZX(this);
8842         return this;
8843     }
8844     public Matrix4x3d mapYZX(ref Matrix4x3d dest) {
8845         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
8846         return dest._m00(m10)._m01(m11)._m02(m12)._m10(m20)._m11(m21)._m12(m22)._m20(m00)._m21(m01)._m22(m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
8847     }
8848     /**
8849      * Multiply <code>this</code> by the matrix
8850      * <pre>
8851      * 0 0 -1 0
8852      * 1 0  0 0
8853      * 0 1  0 0
8854      * </pre>
8855      * 
8856      * @return this
8857      */
8858     ref public Matrix4x3d mapYZnX() return {
8859         mapYZnX(this);
8860         return this;
8861     }
8862     public Matrix4x3d mapYZnX(ref Matrix4x3d dest) {
8863         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
8864         return dest._m00(m10)._m01(m11)._m02(m12)._m10(m20)._m11(m21)._m12(m22)._m20(-m00)._m21(-m01)._m22(-m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
8865     }
8866     /**
8867      * Multiply <code>this</code> by the matrix
8868      * <pre>
8869      * 0 -1 0 0
8870      * 1  0 0 0
8871      * 0  0 1 0
8872      * </pre>
8873      * 
8874      * @return this
8875      */
8876     ref public Matrix4x3d mapYnXZ() return {
8877         mapYnXZ(this);
8878         return this;
8879     }
8880     public Matrix4x3d mapYnXZ(ref Matrix4x3d dest) {
8881         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
8882         return dest._m00(m10)._m01(m11)._m02(m12)._m10(-m00)._m11(-m01)._m12(-m02)._m20(m20)._m21(m21)._m22(m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
8883     }
8884     /**
8885      * Multiply <code>this</code> by the matrix
8886      * <pre>
8887      * 0 -1  0 0
8888      * 1  0  0 0
8889      * 0  0 -1 0
8890      * </pre>
8891      * 
8892      * @return this
8893      */
8894     ref public Matrix4x3d mapYnXnZ() return {
8895         mapYnXnZ(this);
8896         return this;
8897     }
8898     public Matrix4x3d mapYnXnZ(ref Matrix4x3d dest) {
8899         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
8900         return dest._m00(m10)._m01(m11)._m02(m12)._m10(-m00)._m11(-m01)._m12(-m02)._m20(-m20)._m21(-m21)._m22(-m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
8901     }
8902     /**
8903      * Multiply <code>this</code> by the matrix
8904      * <pre>
8905      * 0  0 1 0
8906      * 1  0 0 0
8907      * 0 -1 0 0
8908      * </pre>
8909      * 
8910      * @return this
8911      */
8912     ref public Matrix4x3d mapYnZX() return {
8913         mapYnZX(this);
8914         return this;
8915     }
8916     public Matrix4x3d mapYnZX(ref Matrix4x3d dest) {
8917         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
8918         return dest._m00(m10)._m01(m11)._m02(m12)._m10(-m20)._m11(-m21)._m12(-m22)._m20(m00)._m21(m01)._m22(m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
8919     }
8920     /**
8921      * Multiply <code>this</code> by the matrix
8922      * <pre>
8923      * 0  0 -1 0
8924      * 1  0  0 0
8925      * 0 -1  0 0
8926      * </pre>
8927      * 
8928      * @return this
8929      */
8930     ref public Matrix4x3d mapYnZnX() return {
8931         mapYnZnX(this);
8932         return this;
8933     }
8934     public Matrix4x3d mapYnZnX(ref Matrix4x3d dest) {
8935         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
8936         return dest._m00(m10)._m01(m11)._m02(m12)._m10(-m20)._m11(-m21)._m12(-m22)._m20(-m00)._m21(-m01)._m22(-m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
8937     }
8938     /**
8939      * Multiply <code>this</code> by the matrix
8940      * <pre>
8941      * 0 1 0 0
8942      * 0 0 1 0
8943      * 1 0 0 0
8944      * </pre>
8945      * 
8946      * @return this
8947      */
8948     ref public Matrix4x3d mapZXY() return {
8949         mapZXY(this);
8950         return this;
8951     }
8952     public Matrix4x3d mapZXY(ref Matrix4x3d dest) {
8953         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
8954         double m10 = this.m10, m11 = this.m11, m12 = this.m12;
8955         return dest._m00(m20)._m01(m21)._m02(m22)._m10(m00)._m11(m01)._m12(m02)._m20(m10)._m21(m11)._m22(m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
8956     }
8957     /**
8958      * Multiply <code>this</code> by the matrix
8959      * <pre>
8960      * 0 1  0 0
8961      * 0 0 -1 0
8962      * 1 0  0 0
8963      * </pre>
8964      * 
8965      * @return this
8966      */
8967     ref public Matrix4x3d mapZXnY() return {
8968         mapZXnY(this);
8969         return this;
8970     }
8971     public Matrix4x3d mapZXnY(ref Matrix4x3d dest) {
8972         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
8973         double m10 = this.m10, m11 = this.m11, m12 = this.m12;
8974         return dest._m00(m20)._m01(m21)._m02(m22)._m10(m00)._m11(m01)._m12(m02)._m20(-m10)._m21(-m11)._m22(-m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
8975     }
8976     /**
8977      * Multiply <code>this</code> by the matrix
8978      * <pre>
8979      * 0 0 1 0
8980      * 0 1 0 0
8981      * 1 0 0 0
8982      * </pre>
8983      * 
8984      * @return this
8985      */
8986     ref public Matrix4x3d mapZYX() return {
8987         mapZYX(this);
8988         return this;
8989     }
8990     public Matrix4x3d mapZYX(ref Matrix4x3d dest) {
8991         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
8992         return dest._m00(m20)._m01(m21)._m02(m22)._m10(m10)._m11(m11)._m12(m12)._m20(m00)._m21(m01)._m22(m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
8993     }
8994     /**
8995      * Multiply <code>this</code> by the matrix
8996      * <pre>
8997      * 0 0 -1 0
8998      * 0 1  0 0
8999      * 1 0  0 0
9000      * </pre>
9001      * 
9002      * @return this
9003      */
9004     ref public Matrix4x3d mapZYnX() return {
9005         mapZYnX(this);
9006         return this;
9007     }
9008     public Matrix4x3d mapZYnX(ref Matrix4x3d dest) {
9009         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9010         return dest._m00(m20)._m01(m21)._m02(m22)._m10(m10)._m11(m11)._m12(m12)._m20(-m00)._m21(-m01)._m22(-m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
9011     }
9012     /**
9013      * Multiply <code>this</code> by the matrix
9014      * <pre>
9015      * 0 -1 0 0
9016      * 0  0 1 0
9017      * 1  0 0 0
9018      * </pre>
9019      * 
9020      * @return this
9021      */
9022     ref public Matrix4x3d mapZnXY() return {
9023         mapZnXY(this);
9024         return this;
9025     }
9026     public Matrix4x3d mapZnXY(ref Matrix4x3d dest) {
9027         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9028         double m10 = this.m10, m11 = this.m11, m12 = this.m12;
9029         return dest._m00(m20)._m01(m21)._m02(m22)._m10(-m00)._m11(-m01)._m12(-m02)._m20(m10)._m21(m11)._m22(m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
9030     }
9031     /**
9032      * Multiply <code>this</code> by the matrix
9033      * <pre>
9034      * 0 -1  0 0
9035      * 0  0 -1 0
9036      * 1  0  0 0
9037      * </pre>
9038      * 
9039      * @return this
9040      */
9041     ref public Matrix4x3d mapZnXnY() return {
9042         mapZnXnY(this);
9043         return this;
9044     }
9045     public Matrix4x3d mapZnXnY(ref Matrix4x3d dest) {
9046         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9047         double m10 = this.m10, m11 = this.m11, m12 = this.m12;
9048         return dest._m00(m20)._m01(m21)._m02(m22)._m10(-m00)._m11(-m01)._m12(-m02)._m20(-m10)._m21(-m11)._m22(-m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
9049     }
9050     /**
9051      * Multiply <code>this</code> by the matrix
9052      * <pre>
9053      * 0  0 1 0
9054      * 0 -1 0 0
9055      * 1  0 0 0
9056      * </pre>
9057      * 
9058      * @return this
9059      */
9060     ref public Matrix4x3d mapZnYX() return {
9061         mapZnYX(this);
9062         return this;
9063     }
9064     public Matrix4x3d mapZnYX(ref Matrix4x3d dest) {
9065         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9066         return dest._m00(m20)._m01(m21)._m02(m22)._m10(-m10)._m11(-m11)._m12(-m12)._m20(m00)._m21(m01)._m22(m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
9067     }
9068     /**
9069      * Multiply <code>this</code> by the matrix
9070      * <pre>
9071      * 0  0 -1 0
9072      * 0 -1  0 0
9073      * 1  0  0 0
9074      * </pre>
9075      * 
9076      * @return this
9077      */
9078     ref public Matrix4x3d mapZnYnX() return {
9079         mapZnYnX(this);
9080         return this;
9081     }
9082     public Matrix4x3d mapZnYnX(ref Matrix4x3d dest) {
9083         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9084         return dest._m00(m20)._m01(m21)._m02(m22)._m10(-m10)._m11(-m11)._m12(-m12)._m20(-m00)._m21(-m01)._m22(-m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
9085     }
9086     /**
9087      * Multiply <code>this</code> by the matrix
9088      * <pre>
9089      * -1 0  0 0
9090      *  0 1  0 0
9091      *  0 0 -1 0
9092      * </pre>
9093      * 
9094      * @return this
9095      */
9096     ref public Matrix4x3d mapnXYnZ() return {
9097         mapnXYnZ(this);
9098         return this;
9099     }
9100     public Matrix4x3d mapnXYnZ(ref Matrix4x3d dest) {
9101         return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(m10)._m11(m11)._m12(m12)._m20(-m20)._m21(-m21)._m22(-m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
9102     }
9103     /**
9104      * Multiply <code>this</code> by the matrix
9105      * <pre>
9106      * -1 0 0 0
9107      *  0 0 1 0
9108      *  0 1 0 0
9109      * </pre>
9110      * 
9111      * @return this
9112      */
9113     ref public Matrix4x3d mapnXZY() return {
9114         mapnXZY(this);
9115         return this;
9116     }
9117     public Matrix4x3d mapnXZY(ref Matrix4x3d dest) {
9118         double m10 = this.m10, m11 = this.m11, m12 = this.m12;
9119         return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(m20)._m11(m21)._m12(m22)._m20(m10)._m21(m11)._m22(m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
9120     }
9121     /**
9122      * Multiply <code>this</code> by the matrix
9123      * <pre>
9124      * -1 0  0 0
9125      *  0 0 -1 0
9126      *  0 1  0 0
9127      * </pre>
9128      * 
9129      * @return this
9130      */
9131     ref public Matrix4x3d mapnXZnY() return {
9132         mapnXZnY(this);
9133         return this;
9134     }
9135     public Matrix4x3d mapnXZnY(ref Matrix4x3d dest) {
9136         double m10 = this.m10, m11 = this.m11, m12 = this.m12;
9137         return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(m20)._m11(m21)._m12(m22)._m20(-m10)._m21(-m11)._m22(-m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
9138     }
9139     /**
9140      * Multiply <code>this</code> by the matrix
9141      * <pre>
9142      * -1  0 0 0
9143      *  0 -1 0 0
9144      *  0  0 1 0
9145      * </pre>
9146      * 
9147      * @return this
9148      */
9149     ref public Matrix4x3d mapnXnYZ() return {
9150         mapnXnYZ(this);
9151         return this;
9152     }
9153     public Matrix4x3d mapnXnYZ(ref Matrix4x3d dest) {
9154         return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(-m10)._m11(-m11)._m12(-m12)._m20(m20)._m21(m21)._m22(m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
9155     }
9156     /**
9157      * Multiply <code>this</code> by the matrix
9158      * <pre>
9159      * -1  0  0 0
9160      *  0 -1  0 0
9161      *  0  0 -1 0
9162      * </pre>
9163      * 
9164      * @return this
9165      */
9166     ref public Matrix4x3d mapnXnYnZ() return {
9167         mapnXnYnZ(this);
9168         return this;
9169     }
9170     public Matrix4x3d mapnXnYnZ(ref Matrix4x3d dest) {
9171         return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(-m10)._m11(-m11)._m12(-m12)._m20(-m20)._m21(-m21)._m22(-m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
9172     }
9173     /**
9174      * Multiply <code>this</code> by the matrix
9175      * <pre>
9176      * -1  0 0 0
9177      *  0  0 1 0
9178      *  0 -1 0 0
9179      * </pre>
9180      * 
9181      * @return this
9182      */
9183     ref public Matrix4x3d mapnXnZY() return {
9184         mapnXnZY(this);
9185         return this;
9186     }
9187     public Matrix4x3d mapnXnZY(ref Matrix4x3d dest) {
9188         double m10 = this.m10, m11 = this.m11, m12 = this.m12;
9189         return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(-m20)._m11(-m21)._m12(-m22)._m20(m10)._m21(m11)._m22(m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
9190     }
9191     /**
9192      * Multiply <code>this</code> by the matrix
9193      * <pre>
9194      * -1  0  0 0
9195      *  0  0 -1 0
9196      *  0 -1  0 0
9197      * </pre>
9198      * 
9199      * @return this
9200      */
9201     ref public Matrix4x3d mapnXnZnY() return {
9202         mapnXnZnY(this);
9203         return this;
9204     }
9205     public Matrix4x3d mapnXnZnY(ref Matrix4x3d dest) {
9206         double m10 = this.m10, m11 = this.m11, m12 = this.m12;
9207         return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(-m20)._m11(-m21)._m12(-m22)._m20(-m10)._m21(-m11)._m22(-m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
9208     }
9209     /**
9210      * Multiply <code>this</code> by the matrix
9211      * <pre>
9212      *  0 1 0 0
9213      * -1 0 0 0
9214      *  0 0 1 0
9215      * </pre>
9216      * 
9217      * @return this
9218      */
9219     ref public Matrix4x3d mapnYXZ() return {
9220         mapnYXZ(this);
9221         return this;
9222     }
9223     public Matrix4x3d mapnYXZ(ref Matrix4x3d dest) {
9224         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9225         return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(m00)._m11(m01)._m12(m02)._m20(m20)._m21(m21)._m22(m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
9226     }
9227     /**
9228      * Multiply <code>this</code> by the matrix
9229      * <pre>
9230      *  0 1  0 0
9231      * -1 0  0 0
9232      *  0 0 -1 0
9233      * </pre>
9234      * 
9235      * @return this
9236      */
9237     ref public Matrix4x3d mapnYXnZ() return {
9238         mapnYXnZ(this);
9239         return this;
9240     }
9241     public Matrix4x3d mapnYXnZ(ref Matrix4x3d dest) {
9242         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9243         return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(m00)._m11(m01)._m12(m02)._m20(-m20)._m21(-m21)._m22(-m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
9244     }
9245     /**
9246      * Multiply <code>this</code> by the matrix
9247      * <pre>
9248      *  0 0 1 0
9249      * -1 0 0 0
9250      *  0 1 0 0
9251      * </pre>
9252      * 
9253      * @return this
9254      */
9255     ref public Matrix4x3d mapnYZX() return {
9256         mapnYZX(this);
9257         return this;
9258     }
9259     public Matrix4x3d mapnYZX(ref Matrix4x3d dest) {
9260         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9261         return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(m20)._m11(m21)._m12(m22)._m20(m00)._m21(m01)._m22(m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
9262     }
9263     /**
9264      * Multiply <code>this</code> by the matrix
9265      * <pre>
9266      *  0 0 -1 0
9267      * -1 0  0 0
9268      *  0 1  0 0
9269      * </pre>
9270      * 
9271      * @return this
9272      */
9273     ref public Matrix4x3d mapnYZnX() return {
9274         mapnYZnX(this);
9275         return this;
9276     }
9277     public Matrix4x3d mapnYZnX(ref Matrix4x3d dest) {
9278         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9279         return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(m20)._m11(m21)._m12(m22)._m20(-m00)._m21(-m01)._m22(-m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
9280     }
9281     /**
9282      * Multiply <code>this</code> by the matrix
9283      * <pre>
9284      *  0 -1 0 0
9285      * -1  0 0 0
9286      *  0  0 1 0
9287      * </pre>
9288      * 
9289      * @return this
9290      */
9291     ref public Matrix4x3d mapnYnXZ() return {
9292         mapnYnXZ(this);
9293         return this;
9294     }
9295     public Matrix4x3d mapnYnXZ(ref Matrix4x3d dest) {
9296         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9297         return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(-m00)._m11(-m01)._m12(-m02)._m20(m20)._m21(m21)._m22(m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
9298     }
9299     /**
9300      * Multiply <code>this</code> by the matrix
9301      * <pre>
9302      *  0 -1  0 0
9303      * -1  0  0 0
9304      *  0  0 -1 0
9305      * </pre>
9306      * 
9307      * @return this
9308      */
9309     ref public Matrix4x3d mapnYnXnZ() return {
9310         mapnYnXnZ(this);
9311         return this;
9312     }
9313     public Matrix4x3d mapnYnXnZ(ref Matrix4x3d dest) {
9314         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9315         return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(-m00)._m11(-m01)._m12(-m02)._m20(-m20)._m21(-m21)._m22(-m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
9316     }
9317     /**
9318      * Multiply <code>this</code> by the matrix
9319      * <pre>
9320      *  0  0 1 0
9321      * -1  0 0 0
9322      *  0 -1 0 0
9323      * </pre>
9324      * 
9325      * @return this
9326      */
9327     ref public Matrix4x3d mapnYnZX() return {
9328         mapnYnZX(this);
9329         return this;
9330     }
9331     public Matrix4x3d mapnYnZX(ref Matrix4x3d dest) {
9332         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9333         return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(-m20)._m11(-m21)._m12(-m22)._m20(m00)._m21(m01)._m22(m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
9334     }
9335     /**
9336      * Multiply <code>this</code> by the matrix
9337      * <pre>
9338      *  0  0 -1 0
9339      * -1  0  0 0
9340      *  0 -1  0 0
9341      * </pre>
9342      * 
9343      * @return this
9344      */
9345     ref public Matrix4x3d mapnYnZnX() return {
9346         mapnYnZnX(this);
9347         return this;
9348     }
9349     public Matrix4x3d mapnYnZnX(ref Matrix4x3d dest) {
9350         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9351         return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(-m20)._m11(-m21)._m12(-m22)._m20(-m00)._m21(-m01)._m22(-m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
9352     }
9353     /**
9354      * Multiply <code>this</code> by the matrix
9355      * <pre>
9356      *  0 1 0 0
9357      *  0 0 1 0
9358      * -1 0 0 0
9359      * </pre>
9360      * 
9361      * @return this
9362      */
9363     ref public Matrix4x3d mapnZXY() return {
9364         mapnZXY(this);
9365         return this;
9366     }
9367     public Matrix4x3d mapnZXY(ref Matrix4x3d dest) {
9368         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9369         double m10 = this.m10, m11 = this.m11, m12 = this.m12;
9370         return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(m00)._m11(m01)._m12(m02)._m20(m10)._m21(m11)._m22(m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
9371     }
9372     /**
9373      * Multiply <code>this</code> by the matrix
9374      * <pre>
9375      *  0 1  0 0
9376      *  0 0 -1 0
9377      * -1 0  0 0
9378      * </pre>
9379      * 
9380      * @return this
9381      */
9382     ref public Matrix4x3d mapnZXnY() return {
9383         mapnZXnY(this);
9384         return this;
9385     }
9386     public Matrix4x3d mapnZXnY(ref Matrix4x3d dest) {
9387         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9388         double m10 = this.m10, m11 = this.m11, m12 = this.m12;
9389         return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(m00)._m11(m01)._m12(m02)._m20(-m10)._m21(-m11)._m22(-m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
9390     }
9391     /**
9392      * Multiply <code>this</code> by the matrix
9393      * <pre>
9394      *  0 0 1 0
9395      *  0 1 0 0
9396      * -1 0 0 0
9397      * </pre>
9398      * 
9399      * @return this
9400      */
9401     ref public Matrix4x3d mapnZYX() return {
9402         mapnZYX(this);
9403         return this;
9404     }
9405     public Matrix4x3d mapnZYX(ref Matrix4x3d dest) {
9406         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9407         return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(m10)._m11(m11)._m12(m12)._m20(m00)._m21(m01)._m22(m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
9408     }
9409     /**
9410      * Multiply <code>this</code> by the matrix
9411      * <pre>
9412      *  0 0 -1 0
9413      *  0 1  0 0
9414      * -1 0  0 0
9415      * </pre>
9416      * 
9417      * @return this
9418      */
9419     ref public Matrix4x3d mapnZYnX() return {
9420         mapnZYnX(this);
9421         return this;
9422     }
9423     public Matrix4x3d mapnZYnX(ref Matrix4x3d dest) {
9424         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9425         return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(m10)._m11(m11)._m12(m12)._m20(-m00)._m21(-m01)._m22(-m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
9426     }
9427     /**
9428      * Multiply <code>this</code> by the matrix
9429      * <pre>
9430      *  0 -1 0 0
9431      *  0  0 1 0
9432      * -1  0 0 0
9433      * </pre>
9434      * 
9435      * @return this
9436      */
9437     ref public Matrix4x3d mapnZnXY() return {
9438         mapnZnXY(this);
9439         return this;
9440     }
9441     public Matrix4x3d mapnZnXY(ref Matrix4x3d dest) {
9442         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9443         double m10 = this.m10, m11 = this.m11, m12 = this.m12;
9444         return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(-m00)._m11(-m01)._m12(-m02)._m20(m10)._m21(m11)._m22(m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
9445     }
9446     /**
9447      * Multiply <code>this</code> by the matrix
9448      * <pre>
9449      *  0 -1  0 0
9450      *  0  0 -1 0
9451      * -1  0  0 0
9452      * </pre>
9453      * 
9454      * @return this
9455      */
9456     ref public Matrix4x3d mapnZnXnY() return {
9457         mapnZnXnY(this);
9458         return this;
9459     }
9460     public Matrix4x3d mapnZnXnY(ref Matrix4x3d dest) {
9461         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9462         double m10 = this.m10, m11 = this.m11, m12 = this.m12;
9463         return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(-m00)._m11(-m01)._m12(-m02)._m20(-m10)._m21(-m11)._m22(-m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
9464     }
9465     /**
9466      * Multiply <code>this</code> by the matrix
9467      * <pre>
9468      *  0  0 1 0
9469      *  0 -1 0 0
9470      * -1  0 0 0
9471      * </pre>
9472      * 
9473      * @return this
9474      */
9475     ref public Matrix4x3d mapnZnYX() return {
9476         mapnZnYX(this);
9477         return this;
9478     }
9479     public Matrix4x3d mapnZnYX(ref Matrix4x3d dest) {
9480         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9481         return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(-m10)._m11(-m11)._m12(-m12)._m20(m00)._m21(m01)._m22(m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
9482     }
9483     /**
9484      * Multiply <code>this</code> by the matrix
9485      * <pre>
9486      *  0  0 -1 0
9487      *  0 -1  0 0
9488      * -1  0  0 0
9489      * </pre>
9490      * 
9491      * @return this
9492      */
9493     ref public Matrix4x3d mapnZnYnX() return {
9494         mapnZnYnX(this);
9495         return this;
9496     }
9497     public Matrix4x3d mapnZnYnX(ref Matrix4x3d dest) {
9498         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9499         return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(-m10)._m11(-m11)._m12(-m12)._m20(-m00)._m21(-m01)._m22(-m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
9500     }
9501 
9502     /**
9503      * Multiply <code>this</code> by the matrix
9504      * <pre>
9505      * -1 0 0 0
9506      *  0 1 0 0
9507      *  0 0 1 0
9508      * </pre>
9509      * 
9510      * @return this
9511      */
9512     ref public Matrix4x3d negateX() return {
9513         return _m00(-m00)._m01(-m01)._m02(-m02)._properties(properties & PROPERTY_ORTHONORMAL);
9514     }
9515     public Matrix4x3d negateX(ref Matrix4x3d dest) {
9516         return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(m10)._m11(m11)._m12(m12)._m20(m20)._m21(m21)._m22(m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
9517     }
9518 
9519     /**
9520      * Multiply <code>this</code> by the matrix
9521      * <pre>
9522      * 1  0 0 0
9523      * 0 -1 0 0
9524      * 0  0 1 0
9525      * </pre>
9526      * 
9527      * @return this
9528      */
9529     ref public Matrix4x3d negateY() return {
9530         return _m10(-m10)._m11(-m11)._m12(-m12)._properties(properties & PROPERTY_ORTHONORMAL);
9531     }
9532     public Matrix4x3d negateY(ref Matrix4x3d dest) {
9533         return dest._m00(m00)._m01(m01)._m02(m02)._m10(-m10)._m11(-m11)._m12(-m12)._m20(m20)._m21(m21)._m22(m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
9534     }
9535 
9536     /**
9537      * Multiply <code>this</code> by the matrix
9538      * <pre>
9539      * 1 0  0 0
9540      * 0 1  0 0
9541      * 0 0 -1 0
9542      * </pre>
9543      * 
9544      * @return this
9545      */
9546     ref public Matrix4x3d negateZ() return {
9547         return _m20(-m20)._m21(-m21)._m22(-m22)._properties(properties & PROPERTY_ORTHONORMAL);
9548     }
9549     public Matrix4x3d negateZ(ref Matrix4x3d dest) {
9550         return dest._m00(m00)._m01(m01)._m02(m02)._m10(m10)._m11(m11)._m12(m12)._m20(-m20)._m21(-m21)._m22(-m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
9551     }
9552 
9553     public bool isFinite() {
9554         return Math.isFinite(m00) && Math.isFinite(m01) && Math.isFinite(m02) &&
9555                Math.isFinite(m10) && Math.isFinite(m11) && Math.isFinite(m12) &&
9556                Math.isFinite(m20) && Math.isFinite(m21) && Math.isFinite(m22) &&
9557                Math.isFinite(m30) && Math.isFinite(m31) && Math.isFinite(m32);
9558     }
9559 }