1 module matrix_4x3d;
2 
3 import Math = math;
4 import MemUtil = mem_util;
5 
6 import matrix_3d;
7 import matrix_4d;
8 
9 import vector_3d;
10 import vector_4d;
11 
12 import axis_angle_4d;
13 import quaternion_d;
14 
15 /*
16  * The MIT License
17  *
18  * Copyright (c) 2015-2021 Richard Greenlees
19  @$!@$# Translated by jordan4ibanez
20  *
21  * Permission is hereby granted, free of charge, to any person obtaining a copy
22  * of this software and associated documentation files (the "Software"), to deal
23  * in the Software without restriction, including without limitation the rights
24  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25  * copies of the Software, and to permit persons to whom the Software is
26  * furnished to do so, subject to the following conditions:
27  *
28  * The above copyright notice and this permission notice shall be included in
29  * all copies or substantial portions of the Software.
30  *
31  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
37  * THE SOFTWARE.
38  */
39 
40 /**
41  * Contains the definition of an affine 4x3 matrix (4 columns, 3 rows) of doubles, and associated functions to transform
42  * it. The matrix is column-major to match OpenGL's interpretation, and it looks like this:
43  * <p>
44  *      m00  m10  m20  m30<br>
45  *      m01  m11  m21  m31<br>
46  *      m02  m12  m22  m32<br>
47  * 
48  * @author Richard Greenlees
49  * @author Kai Burjack
50  */
51 struct Matrix4x3d {
52 
53     double m00 = 1.0;
54     double m01 = 0.0;
55     double m02 = 0.0;
56 
57     double m10 = 0.0;
58     double m11 = 1.0;
59     double m12 = 0.0;
60 
61     double m20 = 0.0;
62     double m21 = 0.0;
63     double m22 = 1.0;
64 
65     double m30 = 0.0;
66     double m31 = 0.0;
67     double m32 = 0.0;
68 
69     /**
70      * Argument to the first parameter of {@link #frustumPlane(int, Vector4d)}
71      * identifying the plane with equation <code>x=-1</code> when using the identity matrix.  
72      */
73     immutable static int PLANE_NX = 0;
74     /**
75      * Argument to the first parameter of {@link #frustumPlane(int, Vector4d)}
76      * identifying the plane with equation <code>x=1</code> when using the identity matrix.  
77      */
78     immutable static int PLANE_PX = 1;
79     /**
80      * Argument to the first parameter of {@link #frustumPlane(int, Vector4d)}
81      * identifying the plane with equation <code>y=-1</code> when using the identity matrix.  
82      */
83     immutable static int PLANE_NY = 2;
84     /**
85      * Argument to the first parameter of {@link #frustumPlane(int, Vector4d)}
86      * identifying the plane with equation <code>y=1</code> when using the identity matrix.  
87      */
88     immutable static int PLANE_PY = 3;
89     /**
90      * Argument to the first parameter of {@link #frustumPlane(int, Vector4d)}
91      * identifying the plane with equation <code>z=-1</code> when using the identity matrix.  
92      */
93     immutable static int PLANE_NZ = 4;
94     /**
95      * Argument to the first parameter of {@link #frustumPlane(int, Vector4d)}
96      * identifying the plane with equation <code>z=1</code> when using the identity matrix.  
97      */
98     immutable static int PLANE_PZ = 5;
99 
100     /**
101      * Bit returned by {@link #properties()} to indicate that the matrix represents the identity transformation.
102      */
103     immutable static byte PROPERTY_IDENTITY = 1<<2;
104     /**
105      * Bit returned by {@link #properties()} to indicate that the matrix represents a pure translation transformation.
106      */
107     immutable static byte PROPERTY_TRANSLATION = 1<<3;
108     /**
109      * Bit returned by {@link #properties()} to indicate that the left 3x3 submatrix represents an orthogonal
110      * matrix (i.e. orthonormal basis).
111      */
112     immutable static byte PROPERTY_ORTHONORMAL = 1<<4;
113 
114 
115     int properties = PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL;
116 
117     /**
118      * Create a new {@link Matrix4x3d} and make it a copy of the given matrix.
119      * 
120      * @param mat
121      *          the {@link Matrix4x3d} to copy the values from
122      */
123     this(Matrix4x3d mat) {
124         set(mat);
125     }
126 
127 
128     /**
129      * Create a new {@link Matrix4x3d} by setting its left 3x3 submatrix to the values of the given {@link Matrix3d}
130      * and the rest to identity.
131      * 
132      * @param mat
133      *          the {@link Matrix3d}
134      */
135     this(Matrix3d mat) {
136         set(mat);
137     }
138 
139     /**
140      * Create a new 4x4 matrix using the supplied double values.
141      * 
142      * @param m00
143      *          the value of m00
144      * @param m01
145      *          the value of m01
146      * @param m02
147      *          the value of m02
148      * @param m10
149      *          the value of m10
150      * @param m11
151      *          the value of m11
152      * @param m12
153      *          the value of m12
154      * @param m20
155      *          the value of m20
156      * @param m21
157      *          the value of m21
158      * @param m22
159      *          the value of m22
160      * @param m30
161      *          the value of m30
162      * @param m31
163      *          the value of m31
164      * @param m32
165      *          the value of m32
166      */
167     this(double m00, double m01, double m02,
168                       double m10, double m11, double m12, 
169                       double m20, double m21, double m22, 
170                       double m30, double m31, double m32) {
171         this.m00 = m00;
172         this.m01 = m01;
173         this.m02 = m02;
174         this.m10 = m10;
175         this.m11 = m11;
176         this.m12 = m12;
177         this.m20 = m20;
178         this.m21 = m21;
179         this.m22 = m22;
180         this.m30 = m30;
181         this.m31 = m31;
182         this.m32 = m32;
183         determineProperties();
184     }
185 
186     /**
187      * Assume the given properties about this matrix.
188      * <p>
189      * Use one or multiple of 0, {@link Matrix4x3d#PROPERTY_IDENTITY},
190      * {@link Matrix4x3d#PROPERTY_TRANSLATION}, {@link Matrix4x3d#PROPERTY_ORTHONORMAL}.
191      * 
192      * @param properties
193      *          bitset of the properties to assume about this matrix
194      * @return this
195      */
196     ref public Matrix4x3d assume(int properties) return {
197         this.properties = properties;
198         return this;
199     }
200 
201     /**
202      * Compute and set the matrix properties returned by {@link #properties()} based
203      * on the current matrix element values.
204      * 
205      * @return this
206      */
207     ref public Matrix4x3d determineProperties() return {
208         int __properties = 0;
209         if (m00 == 1.0 && m01 == 0.0 && m02 == 0.0 && m10 == 0.0 && m11 == 1.0 && m12 == 0.0
210                 && m20 == 0.0 && m21 == 0.0 && m22 == 1.0) {
211             __properties |= PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL;
212             if (m30 == 0.0 && m31 == 0.0 && m32 == 0.0)
213                 __properties |= PROPERTY_IDENTITY;
214         }
215         /* 
216          * We do not determine orthogonality, since it would require arbitrary epsilons
217          * and is rather expensive (6 dot products) in the worst case.
218          */
219         this.properties = __properties;
220         return this;
221     }
222 
223     public int getproperties() {
224         return properties;
225     }
226 
227     ref Matrix4x3d _properties(int properties) return {
228         this.properties = properties;
229         return this;
230     }
231 
232     /**
233      * Set the value of the matrix element at column 0 and row 0 without updating the properties of the matrix.
234      * 
235      * @param m00
236      *          the new value
237      * @return this
238      */
239     ref Matrix4x3d _m00(double m00) return {
240         this.m00 = m00;
241         return this;
242     }
243     /**
244      * Set the value of the matrix element at column 0 and row 1 without updating the properties of the matrix.
245      * 
246      * @param m01
247      *          the new value
248      * @return this
249      */
250     ref Matrix4x3d _m01(double m01) return {
251         this.m01 = m01;
252         return this;
253     }
254     /**
255      * Set the value of the matrix element at column 0 and row 2 without updating the properties of the matrix.
256      * 
257      * @param m02
258      *          the new value
259      * @return this
260      */
261     ref Matrix4x3d _m02(double m02) return {
262         this.m02 = m02;
263         return this;
264     }
265     /**
266      * Set the value of the matrix element at column 1 and row 0 without updating the properties of the matrix.
267      * 
268      * @param m10
269      *          the new value
270      * @return this
271      */
272     ref Matrix4x3d _m10(double m10) return {
273         this.m10 = m10;
274         return this;
275     }
276     /**
277      * Set the value of the matrix element at column 1 and row 1 without updating the properties of the matrix.
278      * 
279      * @param m11
280      *          the new value
281      * @return this
282      */
283     ref Matrix4x3d _m11(double m11) return {
284         this.m11 = m11;
285         return this;
286     }
287     /**
288      * Set the value of the matrix element at column 1 and row 2 without updating the properties of the matrix.
289      * 
290      * @param m12
291      *          the new value
292      * @return this
293      */
294     ref Matrix4x3d _m12(double m12) return {
295         this.m12 = m12;
296         return this;
297     }
298     /**
299      * Set the value of the matrix element at column 2 and row 0 without updating the properties of the matrix.
300      * 
301      * @param m20
302      *          the new value
303      * @return this
304      */
305     ref Matrix4x3d _m20(double m20) return {
306         this.m20 = m20;
307         return this;
308     }
309     /**
310      * Set the value of the matrix element at column 2 and row 1 without updating the properties of the matrix.
311      * 
312      * @param m21
313      *          the new value
314      * @return this
315      */
316     ref Matrix4x3d _m21(double m21) return {
317         this.m21 = m21;
318         return this;
319     }
320     /**
321      * Set the value of the matrix element at column 2 and row 2 without updating the properties of the matrix.
322      * 
323      * @param m22
324      *          the new value
325      * @return this
326      */
327     ref Matrix4x3d _m22(double m22) return {
328         this.m22 = m22;
329         return this;
330     }
331     /**
332      * Set the value of the matrix element at column 3 and row 0 without updating the properties of the matrix.
333      * 
334      * @param m30
335      *          the new value
336      * @return this
337      */
338     ref Matrix4x3d _m30(double m30) return {
339         this.m30 = m30;
340         return this;
341     }
342     /**
343      * Set the value of the matrix element at column 3 and row 1 without updating the properties of the matrix.
344      * 
345      * @param m31
346      *          the new value
347      * @return this
348      */
349     ref Matrix4x3d _m31(double m31) return {
350         this.m31 = m31;
351         return this;
352     }
353     /**
354      * Set the value of the matrix element at column 3 and row 2 without updating the properties of the matrix.
355      * 
356      * @param m32
357      *          the new value
358      * @return this
359      */
360     ref Matrix4x3d _m32(double m32) return {
361         this.m32 = m32;
362         return this;
363     }
364 
365     /**
366      * Set the value of the matrix element at column 0 and row 0.
367      * 
368      * @param m00
369      *          the new value
370      * @return this
371      */
372     ref public Matrix4x3d setm00(double m00) return {
373         this.m00 = m00;
374         properties &= ~PROPERTY_ORTHONORMAL;
375         if (m00 != 1.0)
376             properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
377         return this;
378     }
379     /**
380      * Set the value of the matrix element at column 0 and row 1.
381      * 
382      * @param m01
383      *          the new value
384      * @return this
385      */
386     ref public Matrix4x3d setm01(double m01) return {
387         this.m01 = m01;
388         properties &= ~PROPERTY_ORTHONORMAL;
389         if (m01 != 0.0)
390             properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
391         return this;
392     }
393     /**
394      * Set the value of the matrix element at column 0 and row 2.
395      * 
396      * @param m02
397      *          the new value
398      * @return this
399      */
400     ref public Matrix4x3d setm02(double m02) return {
401         this.m02 = m02;
402         properties &= ~PROPERTY_ORTHONORMAL;
403         if (m02 != 0.0)
404             properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
405         return this;
406     }
407     /**
408      * Set the value of the matrix element at column 1 and row 0.
409      * 
410      * @param m10
411      *          the new value
412      * @return this
413      */
414     ref public Matrix4x3d setm10(double m10) return {
415         this.m10 = m10;
416         properties &= ~PROPERTY_ORTHONORMAL;
417         if (m10 != 0.0)
418             properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
419         return this;
420     }
421     /**
422      * Set the value of the matrix element at column 1 and row 1.
423      * 
424      * @param m11
425      *          the new value
426      * @return this
427      */
428     ref public Matrix4x3d setm11(double m11) return {
429         this.m11 = m11;
430         properties &= ~PROPERTY_ORTHONORMAL;
431         if (m11 != 1.0)
432             properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
433         return this;
434     }
435     /**
436      * Set the value of the matrix element at column 1 and row 2.
437      * 
438      * @param m12
439      *          the new value
440      * @return this
441      */
442     ref public Matrix4x3d setm12(double m12) return {
443         this.m12 = m12;
444         properties &= ~PROPERTY_ORTHONORMAL;
445         if (m12 != 0.0)
446             properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
447         return this;
448     }
449     /**
450      * Set the value of the matrix element at column 2 and row 0.
451      * 
452      * @param m20
453      *          the new value
454      * @return this
455      */
456     ref public Matrix4x3d setm20(double m20) return {
457         this.m20 = m20;
458         properties &= ~PROPERTY_ORTHONORMAL;
459         if (m20 != 0.0)
460             properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
461         return this;
462     }
463     /**
464      * Set the value of the matrix element at column 2 and row 1.
465      * 
466      * @param m21
467      *          the new value
468      * @return this
469      */
470     ref public Matrix4x3d setm21(double m21) return {
471         this.m21 = m21;
472         properties &= ~PROPERTY_ORTHONORMAL;
473         if (m21 != 0.0)
474             properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
475         return this;
476     }
477     /**
478      * Set the value of the matrix element at column 2 and row 2.
479      * 
480      * @param m22
481      *          the new value
482      * @return this
483      */
484     ref public Matrix4x3d setm22(double m22) return {
485         this.m22 = m22;
486         properties &= ~PROPERTY_ORTHONORMAL;
487         if (m22 != 1.0)
488             properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
489         return this;
490     }
491     /**
492      * Set the value of the matrix element at column 3 and row 0.
493      * 
494      * @param m30
495      *          the new value
496      * @return this
497      */
498     ref public Matrix4x3d setm30(double m30) return {
499         this.m30 = m30;
500         if (m30 != 0.0)
501             properties &= ~PROPERTY_IDENTITY;
502         return this;
503     }
504     /**
505      * Set the value of the matrix element at column 3 and row 1.
506      * 
507      * @param m31
508      *          the new value
509      * @return this
510      */
511     ref public Matrix4x3d setm31(double m31) return {
512         this.m31 = m31;
513         if (m31 != 0.0)
514             properties &= ~PROPERTY_IDENTITY;
515         return this;
516     }
517     /**
518      * Set the value of the matrix element at column 3 and row 2.
519      * 
520      * @param m32
521      *          the new value
522      * @return this
523      */
524     ref public Matrix4x3d setm32(double m32) return {
525         this.m32 = m32;
526         if (m32 != 0.0)
527             properties &= ~PROPERTY_IDENTITY;
528         return this;
529     }
530 
531     /**
532      * Reset this matrix to the identity.
533      * <p>
534      * Please note that if a call to {@link #identity()} is immediately followed by a call to:
535      * {@link #translate(double, double, double) translate}, 
536      * {@link #rotate(double, double, double, double) rotate},
537      * {@link #scale(double, double, double) scale},
538      * {@link #ortho(double, double, double, double, double, double) ortho},
539      * {@link #ortho2D(double, double, double, double) ortho2D},
540      * {@link #lookAt(double, double, double, double, double, double, double, double, double) lookAt},
541      * {@link #lookAlong(double, double, double, double, double, double) lookAlong},
542      * or any of their overloads, then the call to {@link #identity()} can be omitted and the subsequent call replaced with:
543      * {@link #translation(double, double, double) translation},
544      * {@link #rotation(double, double, double, double) rotation},
545      * {@link #scaling(double, double, double) scaling},
546      * {@link #setOrtho(double, double, double, double, double, double) setOrtho},
547      * {@link #setOrtho2D(double, double, double, double) setOrtho2D},
548      * {@link #setLookAt(double, double, double, double, double, double, double, double, double) setLookAt},
549      * {@link #setLookAlong(double, double, double, double, double, double) setLookAlong},
550      * or any of their overloads.
551      * 
552      * @return this
553      */
554     ref public Matrix4x3d identity() return {
555         if ((properties & PROPERTY_IDENTITY) != 0)
556             return this;
557         m00 = 1.0;
558         m01 = 0.0;
559         m02 = 0.0;
560         m10 = 0.0;
561         m11 = 1.0;
562         m12 = 0.0;
563         m20 = 0.0;
564         m21 = 0.0;
565         m22 = 1.0;
566         m30 = 0.0;
567         m31 = 0.0;
568         m32 = 0.0;
569         properties = PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL;
570         return this;
571     }
572 
573     /**
574      * Store the values of the given matrix <code>m</code> into <code>this</code> matrix.
575      * 
576      * @param m
577      *          the matrix to copy the values from
578      * @return this
579      */
580     ref public Matrix4x3d set(Matrix4x3d m) return {
581         m00 = m.m00;
582         m01 = m.m01;
583         m02 = m.m02;
584         m10 = m.m10;
585         m11 = m.m11;
586         m12 = m.m12;
587         m20 = m.m20;
588         m21 = m.m21;
589         m22 = m.m22;
590         m30 = m.m30;
591         m31 = m.m31;
592         m32 = m.m32;
593         properties = m.properties;
594         return this;
595     }
596 
597 
598     /**
599      * Store the values of the upper 4x3 submatrix of <code>m</code> into <code>this</code> matrix.
600      * 
601      * @see Matrix4d#get4x3(Matrix4x3d)
602      * 
603      * @param m
604      *          the matrix to copy the values from
605      * @return this
606      */
607     ref public Matrix4x3d set(Matrix4d m) return {
608         m00 = m.m00;
609         m01 = m.m01;
610         m02 = m.m02;
611         m10 = m.m10;
612         m11 = m.m11;
613         m12 = m.m12;
614         m20 = m.m20;
615         m21 = m.m21;
616         m22 = m.m22;
617         m30 = m.m30;
618         m31 = m.m31;
619         m32 = m.m32;
620         properties = m.properties & (PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
621         return this;
622     }
623 
624     public Matrix4d get(ref Matrix4d dest) {
625         return dest.set4x3(this);
626     }
627 
628     /**
629      * Set the left 3x3 submatrix of this {@link Matrix4x3d} to the given {@link Matrix3d} 
630      * and the rest to identity.
631      * 
632      * @see #Matrix4x3d(Matrix3d)
633      * 
634      * @param mat
635      *          the {@link Matrix3d}
636      * @return this
637      */
638     ref public Matrix4x3d set(Matrix3d mat) return {
639         m00 = mat.m00;
640         m01 = mat.m01;
641         m02 = mat.m02;
642         m10 = mat.m10;
643         m11 = mat.m11;
644         m12 = mat.m12;
645         m20 = mat.m20;
646         m21 = mat.m21;
647         m22 = mat.m22;
648         m30 = 0.0;
649         m31 = 0.0;
650         m32 = 0.0;
651         return determineProperties();
652     }
653 
654 
655     /**
656      * Set the four columns of this matrix to the supplied vectors, respectively.
657      * 
658      * @param col0
659      *          the first column
660      * @param col1
661      *          the second column
662      * @param col2
663      *          the third column
664      * @param col3
665      *          the fourth column
666      * @return this
667      */
668     ref public Matrix4x3d set(Vector3d col0,
669                           Vector3d col1, 
670                           Vector3d col2,
671                           Vector3d col3) return {
672         this.m00 = col0.x;
673         this.m01 = col0.y;
674         this.m02 = col0.z;
675         this.m10 = col1.x;
676         this.m11 = col1.y;
677         this.m12 = col1.z;
678         this.m20 = col2.x;
679         this.m21 = col2.y;
680         this.m22 = col2.z;
681         this.m30 = col3.x;
682         this.m31 = col3.y;
683         this.m32 = col3.z;
684         return determineProperties();
685     }
686 
687     /**
688      * Set the left 3x3 submatrix of this {@link Matrix4x3d} to that of the given {@link Matrix4x3d} 
689      * and don't change the other elements.
690      * 
691      * @param mat
692      *          the {@link Matrix4x3d}
693      * @return this
694      */
695     ref public Matrix4x3d set3x3(Matrix4x3d mat) return {
696         m00 = mat.m00;
697         m01 = mat.m01;
698         m02 = mat.m02;
699         m10 = mat.m10;
700         m11 = mat.m11;
701         m12 = mat.m12;
702         m20 = mat.m20;
703         m21 = mat.m21;
704         m22 = mat.m22;
705         properties &= mat.properties;
706         return this;
707     }
708 
709     /**
710      * Set this matrix to be equivalent to the rotation specified by the given {@link AxisAngle4d}.
711      * 
712      * @param axisAngle
713      *          the {@link AxisAngle4d}
714      * @return this
715      */
716     ref public Matrix4x3d set(AxisAngle4d axisAngle) return {
717         double x = axisAngle.x;
718         double y = axisAngle.y;
719         double z = axisAngle.z;
720         double angle = axisAngle.angle;
721         double invLength = Math.invsqrt(x*x + y*y + z*z);
722         x *= invLength;
723         y *= invLength;
724         z *= invLength;
725         double s = Math.sin(angle);
726         double c = Math.cosFromSin(s, angle);
727         double omc = 1.0 - c;
728         m00 = c + x*x*omc;
729         m11 = c + y*y*omc;
730         m22 = c + z*z*omc;
731         double tmp1 = x*y*omc;
732         double tmp2 = z*s;
733         m10 = tmp1 - tmp2;
734         m01 = tmp1 + tmp2;
735         tmp1 = x*z*omc;
736         tmp2 = y*s;
737         m20 = tmp1 + tmp2;
738         m02 = tmp1 - tmp2;
739         tmp1 = y*z*omc;
740         tmp2 = x*s;
741         m21 = tmp1 - tmp2;
742         m12 = tmp1 + tmp2;
743         m30 = 0.0;
744         m31 = 0.0;
745         m32 = 0.0;
746         properties = PROPERTY_ORTHONORMAL;
747         return this;
748     }
749 
750 
751     /**
752      * Set this matrix to be equivalent to the rotation - and possibly scaling - specified by the given {@link Quaterniond}.
753      * <p>
754      * This method is equivalent to calling: <code>rotation(q)</code>
755      * 
756      * @param q
757      *          the {@link Quaterniond}
758      * @return this
759      */
760     ref public Matrix4x3d set(Quaterniond q) return {
761         return rotation(q);
762     }
763 
764     /**
765      * Multiply this matrix by the supplied <code>right</code> matrix.
766      * <p>
767      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the <code>right</code> matrix,
768      * then the new matrix will be <code>M * R</code>. So when transforming a
769      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
770      * transformation of the right matrix will be applied first!
771      * 
772      * @param right
773      *          the right operand of the multiplication
774      * @return this
775      */
776     ref public Matrix4x3d mul(Matrix4x3d right) return {
777         mul(right, this);
778         return this;
779     }
780 
781     public Matrix4x3d mul(Matrix4x3d right, ref Matrix4x3d dest) {
782         if ((properties & PROPERTY_IDENTITY) != 0)
783             return dest.set(right);
784         else if ((right.properties & PROPERTY_IDENTITY) != 0)
785             return dest.set(this);
786         else if ((properties & PROPERTY_TRANSLATION) != 0)
787             return mulTranslation(right, dest);
788         return mulGeneric(right, dest);
789     }
790     private Matrix4x3d mulGeneric(Matrix4x3d right, ref Matrix4x3d dest) {
791         double __m00 = this.m00, __m01 = this.m01, __m02 = this.m02;
792         double __m10 = this.m10, __m11 = this.m11, __m12 = this.m12;
793         double __m20 = this.m20, __m21 = this.m21, __m22 = this.m22;
794         double rm00 = right.m00, rm01 = right.m01, rm02 = right.m02;
795         double rm10 = right.m10, rm11 = right.m11, rm12 = right.m12;
796         double rm20 = right.m20, rm21 = right.m21, rm22 = right.m22;
797         double rm30 = right.m30, rm31 = right.m31, rm32 = right.m32;
798         return dest
799         ._m00(Math.fma(__m00, rm00, Math.fma(__m10, rm01, __m20 * rm02)))
800         ._m01(Math.fma(__m01, rm00, Math.fma(__m11, rm01, __m21 * rm02)))
801         ._m02(Math.fma(__m02, rm00, Math.fma(__m12, rm01, __m22 * rm02)))
802         ._m10(Math.fma(__m00, rm10, Math.fma(__m10, rm11, __m20 * rm12)))
803         ._m11(Math.fma(__m01, rm10, Math.fma(__m11, rm11, __m21 * rm12)))
804         ._m12(Math.fma(__m02, rm10, Math.fma(__m12, rm11, __m22 * rm12)))
805         ._m20(Math.fma(__m00, rm20, Math.fma(__m10, rm21, __m20 * rm22)))
806         ._m21(Math.fma(__m01, rm20, Math.fma(__m11, rm21, __m21 * rm22)))
807         ._m22(Math.fma(__m02, rm20, Math.fma(__m12, rm21, __m22 * rm22)))
808         ._m30(Math.fma(__m00, rm30, Math.fma(__m10, rm31, Math.fma(__m20, rm32, m30))))
809         ._m31(Math.fma(__m01, rm30, Math.fma(__m11, rm31, Math.fma(__m21, rm32, m31))))
810         ._m32(Math.fma(__m02, rm30, Math.fma(__m12, rm31, Math.fma(__m22, rm32, m32))))
811         ._properties(properties & right.properties & PROPERTY_ORTHONORMAL);
812     }
813 
814 
815     public Matrix4x3d mulTranslation(Matrix4x3d right, ref Matrix4x3d dest) {
816         return dest
817         ._m00(right.m00)
818         ._m01(right.m01)
819         ._m02(right.m02)
820         ._m10(right.m10)
821         ._m11(right.m11)
822         ._m12(right.m12)
823         ._m20(right.m20)
824         ._m21(right.m21)
825         ._m22(right.m22)
826         ._m30(right.m30 + m30)
827         ._m31(right.m31 + m31)
828         ._m32(right.m32 + m32)
829         ._properties(right.properties & PROPERTY_ORTHONORMAL);
830     }
831 
832     /**
833      * Multiply <code>this</code> orthographic projection matrix by the supplied <code>view</code> matrix.
834      * <p>
835      * If <code>M</code> is <code>this</code> matrix and <code>V</code> the <code>view</code> matrix,
836      * then the new matrix will be <code>M * V</code>. So when transforming a
837      * vector <code>v</code> with the new matrix by using <code>M * V * v</code>, the
838      * transformation of the <code>view</code> matrix will be applied first!
839      *
840      * @param view
841      *          the matrix which to multiply <code>this</code> with
842      * @return this
843      */
844     ref public Matrix4x3d mulOrtho(Matrix4x3d view) return {
845         mulOrtho(view, this);
846         return this;
847     }
848 
849     public Matrix4x3d mulOrtho(Matrix4x3d view, ref Matrix4x3d dest) {
850         double nm00 = m00 * view.m00;
851         double nm01 = m11 * view.m01;
852         double nm02 = m22 * view.m02;
853         double nm10 = m00 * view.m10;
854         double nm11 = m11 * view.m11;
855         double nm12 = m22 * view.m12;
856         double nm20 = m00 * view.m20;
857         double nm21 = m11 * view.m21;
858         double nm22 = m22 * view.m22;
859         double nm30 = m00 * view.m30 + m30;
860         double nm31 = m11 * view.m31 + m31;
861         double nm32 = m22 * view.m32 + m32;
862         dest.m00 = nm00;
863         dest.m01 = nm01;
864         dest.m02 = nm02;
865         dest.m10 = nm10;
866         dest.m11 = nm11;
867         dest.m12 = nm12;
868         dest.m20 = nm20;
869         dest.m21 = nm21;
870         dest.m22 = nm22;
871         dest.m30 = nm30;
872         dest.m31 = nm31;
873         dest.m32 = nm32;
874         dest.properties = (this.properties & view.properties & PROPERTY_ORTHONORMAL);
875         return dest;
876     }
877 
878     /**
879      * Multiply <code>this</code> by the 4x3 matrix with the column vectors <code>(rm00, rm01, rm02)</code>,
880      * <code>(rm10, rm11, rm12)</code>, <code>(rm20, rm21, rm22)</code> and <code>(0, 0, 0)</code>.
881      * <p>
882      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the specified matrix,
883      * then the new matrix will be <code>M * R</code>. So when transforming a
884      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
885      * transformation of the <code>R</code> matrix will be applied first!
886      * 
887      * @param rm00
888      *          the value of the m00 element
889      * @param rm01
890      *          the value of the m01 element
891      * @param rm02
892      *          the value of the m02 element
893      * @param rm10
894      *          the value of the m10 element
895      * @param rm11
896      *          the value of the m11 element
897      * @param rm12
898      *          the value of the m12 element
899      * @param rm20
900      *          the value of the m20 element
901      * @param rm21
902      *          the value of the m21 element
903      * @param rm22
904      *          the value of the m22 element
905      * @return this
906      */
907     ref public Matrix4x3d mul3x3(
908             double rm00, double rm01, double rm02,
909             double rm10, double rm11, double rm12,
910             double rm20, double rm21, double rm22) return {
911         mul3x3(rm00, rm01, rm02, rm10, rm11, rm12, rm20, rm21, rm22, this);
912         return this;
913     }
914     public Matrix4x3d mul3x3(
915             double rm00, double rm01, double rm02,
916             double rm10, double rm11, double rm12,
917             double rm20, double rm21, double rm22,
918             ref Matrix4x3d dest) {
919         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
920         double m10 = this.m10, m11 = this.m11, m12 = this.m12;
921         double m20 = this.m20, m21 = this.m21, m22 = this.m22;
922         return dest
923         ._m00(Math.fma(m00, rm00, Math.fma(m10, rm01, m20 * rm02)))
924         ._m01(Math.fma(m01, rm00, Math.fma(m11, rm01, m21 * rm02)))
925         ._m02(Math.fma(m02, rm00, Math.fma(m12, rm01, m22 * rm02)))
926         ._m10(Math.fma(m00, rm10, Math.fma(m10, rm11, m20 * rm12)))
927         ._m11(Math.fma(m01, rm10, Math.fma(m11, rm11, m21 * rm12)))
928         ._m12(Math.fma(m02, rm10, Math.fma(m12, rm11, m22 * rm12)))
929         ._m20(Math.fma(m00, rm20, Math.fma(m10, rm21, m20 * rm22)))
930         ._m21(Math.fma(m01, rm20, Math.fma(m11, rm21, m21 * rm22)))
931         ._m22(Math.fma(m02, rm20, Math.fma(m12, rm21, m22 * rm22)))
932         ._m30(m30)
933         ._m31(m31)
934         ._m32(m32)
935         ._properties(0);
936     }
937 
938     /**
939      * Component-wise add <code>this</code> and <code>other</code>
940      * by first multiplying each component of <code>other</code> by <code>otherFactor</code> and
941      * adding that result to <code>this</code>.
942      * <p>
943      * The matrix <code>other</code> will not be changed.
944      * 
945      * @param other
946      *          the other matrix 
947      * @param otherFactor
948      *          the factor to multiply each of the other matrix's components
949      * @return this
950      */
951     ref public Matrix4x3d fma(Matrix4x3d other, double otherFactor) return {
952         fma(other, otherFactor, this);
953         return this;
954     }
955 
956     public Matrix4x3d fma(Matrix4x3d other, double otherFactor, ref Matrix4x3d dest) {
957         dest
958         ._m00(Math.fma(other.m00, otherFactor, m00))
959         ._m01(Math.fma(other.m01, otherFactor, m01))
960         ._m02(Math.fma(other.m02, otherFactor, m02))
961         ._m10(Math.fma(other.m10, otherFactor, m10))
962         ._m11(Math.fma(other.m11, otherFactor, m11))
963         ._m12(Math.fma(other.m12, otherFactor, m12))
964         ._m20(Math.fma(other.m20, otherFactor, m20))
965         ._m21(Math.fma(other.m21, otherFactor, m21))
966         ._m22(Math.fma(other.m22, otherFactor, m22))
967         ._m30(Math.fma(other.m30, otherFactor, m30))
968         ._m31(Math.fma(other.m31, otherFactor, m31))
969         ._m32(Math.fma(other.m32, otherFactor, m32))
970         ._properties(0);
971         return dest;
972     }
973 
974     /**
975      * Component-wise add <code>this</code> and <code>other</code>.
976      * 
977      * @param other
978      *          the other addend
979      * @return this
980      */
981     ref public Matrix4x3d add(Matrix4x3d other) return {
982         add(other, this);
983         return this;
984     }
985 
986     public Matrix4x3d add(Matrix4x3d other, ref Matrix4x3d dest) {
987         dest.m00 = m00 + other.m00;
988         dest.m01 = m01 + other.m01;
989         dest.m02 = m02 + other.m02;
990         dest.m10 = m10 + other.m10;
991         dest.m11 = m11 + other.m11;
992         dest.m12 = m12 + other.m12;
993         dest.m20 = m20 + other.m20;
994         dest.m21 = m21 + other.m21;
995         dest.m22 = m22 + other.m22;
996         dest.m30 = m30 + other.m30;
997         dest.m31 = m31 + other.m31;
998         dest.m32 = m32 + other.m32;
999         dest.properties = 0;
1000         return dest;
1001     }
1002 
1003 
1004     /**
1005      * Component-wise subtract <code>subtrahend</code> from <code>this</code>.
1006      * 
1007      * @param subtrahend
1008      *          the subtrahend
1009      * @return this
1010      */
1011     ref public Matrix4x3d sub(Matrix4x3d subtrahend) return {
1012         sub(subtrahend, this);
1013         return this;
1014     }
1015 
1016     public Matrix4x3d sub(Matrix4x3d subtrahend, ref Matrix4x3d dest) {
1017         dest.m00 = m00 - subtrahend.m00;
1018         dest.m01 = m01 - subtrahend.m01;
1019         dest.m02 = m02 - subtrahend.m02;
1020         dest.m10 = m10 - subtrahend.m10;
1021         dest.m11 = m11 - subtrahend.m11;
1022         dest.m12 = m12 - subtrahend.m12;
1023         dest.m20 = m20 - subtrahend.m20;
1024         dest.m21 = m21 - subtrahend.m21;
1025         dest.m22 = m22 - subtrahend.m22;
1026         dest.m30 = m30 - subtrahend.m30;
1027         dest.m31 = m31 - subtrahend.m31;
1028         dest.m32 = m32 - subtrahend.m32;
1029         dest.properties = 0;
1030         return dest;
1031     }
1032 
1033     /**
1034      * Component-wise multiply <code>this</code> by <code>other</code>.
1035      * 
1036      * @param other
1037      *          the other matrix
1038      * @return this
1039      */
1040     ref public Matrix4x3d mulComponentWise(Matrix4x3d other) return {
1041         mulComponentWise(other, this);
1042         return this;
1043     }
1044 
1045     public Matrix4x3d mulComponentWise(Matrix4x3d other, ref Matrix4x3d dest) {
1046         dest.m00 = m00 * other.m00;
1047         dest.m01 = m01 * other.m01;
1048         dest.m02 = m02 * other.m02;
1049         dest.m10 = m10 * other.m10;
1050         dest.m11 = m11 * other.m11;
1051         dest.m12 = m12 * other.m12;
1052         dest.m20 = m20 * other.m20;
1053         dest.m21 = m21 * other.m21;
1054         dest.m22 = m22 * other.m22;
1055         dest.m30 = m30 * other.m30;
1056         dest.m31 = m31 * other.m31;
1057         dest.m32 = m32 * other.m32;
1058         dest.properties = 0;
1059         return dest;
1060     }
1061 
1062     /**
1063      * Set the values within this matrix to the supplied double values. The matrix will look like this:<br><br>
1064      *
1065      * m00, m10, m20, m30<br>
1066      * m01, m11, m21, m31<br>
1067      * m02, m12, m22, m32<br>
1068      *
1069      * @param m00
1070      *          the new value of m00
1071      * @param m01
1072      *          the new value of m01
1073      * @param m02
1074      *          the new value of m02
1075      * @param m10
1076      *          the new value of m10
1077      * @param m11
1078      *          the new value of m11
1079      * @param m12
1080      *          the new value of m12
1081      * @param m20
1082      *          the new value of m20
1083      * @param m21
1084      *          the new value of m21
1085      * @param m22
1086      *          the new value of m22
1087      * @param m30
1088      *          the new value of m30
1089      * @param m31
1090      *          the new value of m31
1091      * @param m32
1092      *          the new value of m32
1093      * @return this
1094      */
1095     ref public Matrix4x3d set(double m00, double m01, double m02,
1096                           double m10, double m11, double m12,
1097                           double m20, double m21, double m22, 
1098                           double m30, double m31, double m32) return {
1099         this.m00 = m00;
1100         this.m10 = m10;
1101         this.m20 = m20;
1102         this.m30 = m30;
1103         this.m01 = m01;
1104         this.m11 = m11;
1105         this.m21 = m21;
1106         this.m31 = m31;
1107         this.m02 = m02;
1108         this.m12 = m12;
1109         this.m22 = m22;
1110         this.m32 = m32;
1111         return determineProperties();
1112     }
1113 
1114     /**
1115      * Set the values in the matrix using a double array that contains the matrix elements in column-major order.
1116      * <p>
1117      * The results will look like this:<br><br>
1118      * 
1119      * 0, 3, 6, 9<br>
1120      * 1, 4, 7, 10<br>
1121      * 2, 5, 8, 11<br>
1122      * 
1123      * @see #set(double[])
1124      * 
1125      * @param m
1126      *          the array to read the matrix values from
1127      * @param off
1128      *          the offset into the array
1129      * @return this
1130      */
1131     ref public Matrix4x3d set(double[] m, int off) return {
1132         m00 = m[off+0];
1133         m01 = m[off+1];
1134         m02 = m[off+2];
1135         m10 = m[off+3];
1136         m11 = m[off+4];
1137         m12 = m[off+5];
1138         m20 = m[off+6];
1139         m21 = m[off+7];
1140         m22 = m[off+8];
1141         m30 = m[off+9];
1142         m31 = m[off+10];
1143         m32 = m[off+11];
1144         return determineProperties();
1145     }
1146 
1147     /**
1148      * Set the values in the matrix using a double array that contains the matrix elements in column-major order.
1149      * <p>
1150      * The results will look like this:<br><br>
1151      * 
1152      * 0, 3, 6, 9<br>
1153      * 1, 4, 7, 10<br>
1154      * 2, 5, 8, 11<br>
1155      * 
1156      * @see #set(double[], int)
1157      * 
1158      * @param m
1159      *          the array to read the matrix values from
1160      * @return this
1161      */
1162     ref public Matrix4x3d set(double[] m) return {
1163         return set(m, 0);
1164     }
1165 
1166     /**
1167      * Set the values in the matrix using a float array that contains the matrix elements in column-major order.
1168      * <p>
1169      * The results will look like this:<br><br>
1170      * 
1171      * 0, 3, 6, 9<br>
1172      * 1, 4, 7, 10<br>
1173      * 2, 5, 8, 11<br>
1174      * 
1175      * @see #set(float[])
1176      * 
1177      * @param m
1178      *          the array to read the matrix values from
1179      * @param off
1180      *          the offset into the array
1181      * @return this
1182      */
1183     ref public Matrix4x3d set(float[] m, int off) return {
1184         m00 = m[off+0];
1185         m01 = m[off+1];
1186         m02 = m[off+2];
1187         m10 = m[off+3];
1188         m11 = m[off+4];
1189         m12 = m[off+5];
1190         m20 = m[off+6];
1191         m21 = m[off+7];
1192         m22 = m[off+8];
1193         m30 = m[off+9];
1194         m31 = m[off+10];
1195         m32 = m[off+11];
1196         return determineProperties();
1197     }
1198 
1199     /**
1200      * Set the values in the matrix using a float array that contains the matrix elements in column-major order.
1201      * <p>
1202      * The results will look like this:<br><br>
1203      * 
1204      * 0, 3, 6, 9<br>
1205      * 1, 4, 7, 10<br>
1206      * 2, 5, 8, 11<br>
1207      * 
1208      * @see #set(float[], int)
1209      * 
1210      * @param m
1211      *          the array to read the matrix values from
1212      * @return this
1213      */
1214     ref public Matrix4x3d set(float[] m) return {
1215         return set(m, 0);
1216     }
1217 
1218 
1219 
1220     public double determinant() {
1221         return (m00 * m11 - m01 * m10) * m22
1222              + (m02 * m10 - m00 * m12) * m21
1223              + (m01 * m12 - m02 * m11) * m20;
1224     }
1225 
1226     /**
1227      * Invert this matrix.
1228      * 
1229      * @return this
1230      */
1231     ref public Matrix4x3d invert() return {
1232         invert(this);
1233         return this;
1234     }
1235 
1236     public Matrix4x3d invert(ref Matrix4x3d dest) {
1237         if ((properties & PROPERTY_IDENTITY) != 0)
1238             return dest.identity();
1239         else if ((properties & PROPERTY_ORTHONORMAL) != 0)
1240             return invertOrthonormal(dest);
1241         return invertGeneric(dest);
1242     }
1243     private Matrix4x3d invertGeneric(ref Matrix4x3d dest) {
1244         double m11m00 = m00 * m11, m10m01 = m01 * m10, m10m02 = m02 * m10;
1245         double m12m00 = m00 * m12, m12m01 = m01 * m12, m11m02 = m02 * m11;
1246         double s = 1.0 / ((m11m00 - m10m01) * m22 + (m10m02 - m12m00) * m21 + (m12m01 - m11m02) * m20);
1247         double m10m22 = m10 * m22, m10m21 = m10 * m21, m11m22 = m11 * m22;
1248         double m11m20 = m11 * m20, m12m21 = m12 * m21, m12m20 = m12 * m20;
1249         double m20m02 = m20 * m02, m20m01 = m20 * m01, m21m02 = m21 * m02;
1250         double m21m00 = m21 * m00, m22m01 = m22 * m01, m22m00 = m22 * m00;
1251         double nm00 = (m11m22 - m12m21) * s;
1252         double nm01 = (m21m02 - m22m01) * s;
1253         double nm02 = (m12m01 - m11m02) * s;
1254         double nm10 = (m12m20 - m10m22) * s;
1255         double nm11 = (m22m00 - m20m02) * s;
1256         double nm12 = (m10m02 - m12m00) * s;
1257         double nm20 = (m10m21 - m11m20) * s;
1258         double nm21 = (m20m01 - m21m00) * s;
1259         double nm22 = (m11m00 - m10m01) * s;
1260         double nm30 = (m10m22 * m31 - m10m21 * m32 + m11m20 * m32 - m11m22 * m30 + m12m21 * m30 - m12m20 * m31) * s;
1261         double nm31 = (m20m02 * m31 - m20m01 * m32 + m21m00 * m32 - m21m02 * m30 + m22m01 * m30 - m22m00 * m31) * s;
1262         double nm32 = (m11m02 * m30 - m12m01 * m30 + m12m00 * m31 - m10m02 * m31 + m10m01 * m32 - m11m00 * m32) * s;
1263         dest.m00 = nm00;
1264         dest.m01 = nm01;
1265         dest.m02 = nm02;
1266         dest.m10 = nm10;
1267         dest.m11 = nm11;
1268         dest.m12 = nm12;
1269         dest.m20 = nm20;
1270         dest.m21 = nm21;
1271         dest.m22 = nm22;
1272         dest.m30 = nm30;
1273         dest.m31 = nm31;
1274         dest.m32 = nm32;
1275         dest.properties = 0;
1276         return dest;
1277     }
1278     private Matrix4x3d invertOrthonormal(ref Matrix4x3d dest) {
1279         double nm30 = -(m00 * m30 + m01 * m31 + m02 * m32);
1280         double nm31 = -(m10 * m30 + m11 * m31 + m12 * m32);
1281         double nm32 = -(m20 * m30 + m21 * m31 + m22 * m32);
1282         double m01 = this.m01;
1283         double m02 = this.m02;
1284         double m12 = this.m12;
1285         dest.m00 = m00;
1286         dest.m01 = m10;
1287         dest.m02 = m20;
1288         dest.m10 = m01;
1289         dest.m11 = m11;
1290         dest.m12 = m21;
1291         dest.m20 = m02;
1292         dest.m21 = m12;
1293         dest.m22 = m22;
1294         dest.m30 = nm30;
1295         dest.m31 = nm31;
1296         dest.m32 = nm32;
1297         dest.properties = PROPERTY_ORTHONORMAL;
1298         return dest;
1299     }
1300 
1301     public Matrix4x3d invertOrtho(ref Matrix4x3d dest) {
1302         double invM00 = 1.0 / m00;
1303         double invM11 = 1.0 / m11;
1304         double invM22 = 1.0 / m22;
1305         dest.set(invM00, 0, 0,
1306                  0, invM11, 0,
1307                  0, 0, invM22,
1308                  -m30 * invM00, -m31 * invM11, -m32 * invM22);
1309         dest.properties = 0;
1310         return dest;
1311     }
1312 
1313     /**
1314      * Invert <code>this</code> orthographic projection matrix.
1315      * <p>
1316      * This method can be used to quickly obtain the inverse of an orthographic projection matrix.
1317      * 
1318      * @return this
1319      */
1320     ref public Matrix4x3d invertOrtho() return {
1321         invertOrtho(this);
1322         return this;
1323     }
1324 
1325     /**
1326      * Transpose only the left 3x3 submatrix of this matrix and set the rest of the matrix elements to identity.
1327      * 
1328      * @return this
1329      */
1330     ref public Matrix4x3d transpose3x3() return {
1331         transpose3x3(this);
1332         return this;
1333     }
1334 
1335     public Matrix4x3d transpose3x3(ref Matrix4x3d dest) {
1336         double nm00 = m00;
1337         double nm01 = m10;
1338         double nm02 = m20;
1339         double nm10 = m01;
1340         double nm11 = m11;
1341         double nm12 = m21;
1342         double nm20 = m02;
1343         double nm21 = m12;
1344         double nm22 = m22;
1345         dest.m00 = nm00;
1346         dest.m01 = nm01;
1347         dest.m02 = nm02;
1348         dest.m10 = nm10;
1349         dest.m11 = nm11;
1350         dest.m12 = nm12;
1351         dest.m20 = nm20;
1352         dest.m21 = nm21;
1353         dest.m22 = nm22;
1354         dest.properties = properties;
1355         return dest;
1356     }
1357 
1358     public Matrix3d transpose3x3(Matrix3d dest) {
1359         dest.m00 = (m00);
1360         dest.m01 = (m10);
1361         dest.m02 = (m20);
1362         dest.m10 = (m01);
1363         dest.m11 = (m11);
1364         dest.m12 = (m21);
1365         dest.m20 = (m02);
1366         dest.m21 = (m12);
1367         dest.m22 = (m22);
1368         return dest;
1369     }
1370 
1371     /**
1372      * Set this matrix to be a simple translation matrix.
1373      * <p>
1374      * The resulting matrix can be multiplied against another transformation
1375      * matrix to obtain an additional translation.
1376      * 
1377      * @param x
1378      *          the offset to translate in x
1379      * @param y
1380      *          the offset to translate in y
1381      * @param z
1382      *          the offset to translate in z
1383      * @return this
1384      */
1385     ref public Matrix4x3d translation(double x, double y, double z) return {
1386         if ((properties & PROPERTY_IDENTITY) == 0)
1387             this.identity();
1388         m30 = x;
1389         m31 = y;
1390         m32 = z;
1391         properties = PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL;
1392         return this;
1393     }
1394 
1395 
1396     /**
1397      * Set this matrix to be a simple translation matrix.
1398      * <p>
1399      * The resulting matrix can be multiplied against another transformation
1400      * matrix to obtain an additional translation.
1401      *
1402      * @param offset
1403      *              the offsets in x, y and z to translate
1404      * @return this
1405      */
1406     ref public Matrix4x3d translation(Vector3d offset) return {
1407         return translation(offset.x, offset.y, offset.z);
1408     }
1409 
1410     /**
1411      * Set only the translation components <code>(m30, m31, m32)</code> of this matrix to the given values <code>(x, y, z)</code>.
1412      * <p>
1413      * To build a translation matrix instead, use {@link #translation(double, double, double)}.
1414      * To apply a translation, use {@link #translate(double, double, double)}.
1415      * 
1416      * @see #translation(double, double, double)
1417      * @see #translate(double, double, double)
1418      * 
1419      * @param x
1420      *          the units to translate in x
1421      * @param y
1422      *          the units to translate in y
1423      * @param z
1424      *          the units to translate in z
1425      * @return this
1426      */
1427     ref public Matrix4x3d setTranslation(double x, double y, double z) return {
1428         m30 = x;
1429         m31 = y;
1430         m32 = z;
1431         properties &= ~(PROPERTY_IDENTITY);
1432         return this;
1433     }
1434 
1435     /**
1436      * 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>.
1437      * <p>
1438      * To build a translation matrix instead, use {@link #translation(Vector3d)}.
1439      * To apply a translation, use {@link #translate(Vector3d)}.
1440      * 
1441      * @see #translation(Vector3d)
1442      * @see #translate(Vector3d)
1443      * 
1444      * @param xyz
1445      *          the units to translate in <code>(x, y, z)</code>
1446      * @return this
1447      */
1448     ref public Matrix4x3d setTranslation(Vector3d xyz) return {
1449         return setTranslation(xyz.x, xyz.y, xyz.z);
1450     }
1451 
1452     public Vector3d getTranslation(ref Vector3d dest) {
1453         dest.x = m30;
1454         dest.y = m31;
1455         dest.z = m32;
1456         return dest;
1457     }
1458 
1459     public Vector3d getScale(ref Vector3d dest) {
1460         dest.x = Math.sqrt(m00 * m00 + m01 * m01 + m02 * m02);
1461         dest.y = Math.sqrt(m10 * m10 + m11 * m11 + m12 * m12);
1462         dest.z = Math.sqrt(m20 * m20 + m21 * m21 + m22 * m22);
1463         return dest;
1464     }
1465     
1466     /**
1467      * Get the current values of <code>this</code> matrix and store them into
1468      * <code>dest</code>.
1469      * <p>
1470      * This is the reverse method of {@link #set(Matrix4x3d)} and allows to obtain
1471      * intermediate calculation results when chaining multiple transformations.
1472      * 
1473      * @see #set(Matrix4x3d)
1474      * 
1475      * @param dest
1476      *          the destination matrix
1477      * @return the passed in destination
1478      */
1479     public Matrix4x3d get(ref Matrix4x3d dest) {
1480         return dest.set(this);
1481     }
1482 
1483     public Quaterniond getUnnormalizedRotation(Quaterniond dest) {
1484         return dest.setFromUnnormalized(this);
1485     }
1486 
1487     public Quaterniond getNormalizedRotation(Quaterniond dest) {
1488         return dest.setFromNormalized(this);
1489     }
1490 
1491     public double[] get(double[] arr, int offset) {
1492         arr[offset+0]  = m00;
1493         arr[offset+1]  = m01;
1494         arr[offset+2]  = m02;
1495         arr[offset+3]  = m10;
1496         arr[offset+4]  = m11;
1497         arr[offset+5]  = m12;
1498         arr[offset+6]  = m20;
1499         arr[offset+7]  = m21;
1500         arr[offset+8]  = m22;
1501         arr[offset+9]  = m30;
1502         arr[offset+10] = m31;
1503         arr[offset+11] = m32;
1504         return arr;
1505     }
1506 
1507     public double[] get(double[] arr) {
1508         return get(arr, 0);
1509     }
1510 
1511     public float[] get(float[] arr, int offset) {
1512         arr[offset+0]  = cast(float)m00;
1513         arr[offset+1]  = cast(float)m01;
1514         arr[offset+2]  = cast(float)m02;
1515         arr[offset+3]  = cast(float)m10;
1516         arr[offset+4]  = cast(float)m11;
1517         arr[offset+5]  = cast(float)m12;
1518         arr[offset+6]  = cast(float)m20;
1519         arr[offset+7]  = cast(float)m21;
1520         arr[offset+8]  = cast(float)m22;
1521         arr[offset+9]  = cast(float)m30;
1522         arr[offset+10] = cast(float)m31;
1523         arr[offset+11] = cast(float)m32;
1524         return arr;
1525     }
1526 
1527     public float[] get(float[] arr) {
1528         return get(arr, 0);
1529     }
1530 
1531 
1532     public double[] get4x4(double[] arr, int offset) {
1533         MemUtil.copy4x4(this, arr, offset);
1534         return arr;
1535     }
1536 
1537     public double[] get4x4(double[] arr) {
1538         return get4x4(arr, 0);
1539     }
1540 
1541 
1542     public double[] getTransposed(double[] arr, int offset) {
1543         arr[offset+0]  = m00;
1544         arr[offset+1]  = m10;
1545         arr[offset+2]  = m20;
1546         arr[offset+3]  = m30;
1547         arr[offset+4]  = m01;
1548         arr[offset+5]  = m11;
1549         arr[offset+6]  = m21;
1550         arr[offset+7]  = m31;
1551         arr[offset+8]  = m02;
1552         arr[offset+9]  = m12;
1553         arr[offset+10] = m22;
1554         arr[offset+11] = m32;
1555         return arr;
1556     }
1557 
1558     public double[] getTransposed(double[] arr) {
1559         return getTransposed(arr, 0);
1560     }
1561 
1562     /**
1563      * Set all the values within this matrix to 0.
1564      * 
1565      * @return this
1566      */
1567     ref public Matrix4x3d zero() return {
1568         m00 = 0.0;
1569         m01 = 0.0;
1570         m02 = 0.0;
1571         m10 = 0.0;
1572         m11 = 0.0;
1573         m12 = 0.0;
1574         m20 = 0.0;
1575         m21 = 0.0;
1576         m22 = 0.0;
1577         m30 = 0.0;
1578         m31 = 0.0;
1579         m32 = 0.0;
1580         properties = 0;
1581         return this;
1582     }
1583 
1584     /**
1585      * Set this matrix to be a simple scale matrix, which scales all axes uniformly by the given factor.
1586      * <p>
1587      * The resulting matrix can be multiplied against another transformation
1588      * matrix to obtain an additional scaling.
1589      * <p>
1590      * In order to post-multiply a scaling transformation directly to a
1591      * matrix, use {@link #scale(double) scale()} instead.
1592      * 
1593      * @see #scale(double)
1594      * 
1595      * @param factor
1596      *             the scale factor in x, y and z
1597      * @return this
1598      */
1599     ref public Matrix4x3d scaling(double factor) return {
1600         return scaling(factor, factor, factor);
1601     }
1602 
1603     /**
1604      * Set this matrix to be a simple scale matrix.
1605      * 
1606      * @param x
1607      *          the scale in x
1608      * @param y
1609      *          the scale in y
1610      * @param z
1611      *          the scale in z         
1612      * @return this
1613      */
1614     ref public Matrix4x3d scaling(double x, double y, double z) return {
1615         if ((properties & PROPERTY_IDENTITY) == 0)
1616             this.identity();
1617         m00 = x;
1618         m11 = y;
1619         m22 = z;
1620         bool one = Math.absEqualsOne(x) && Math.absEqualsOne(y) && Math.absEqualsOne(z);
1621         properties = one ? PROPERTY_ORTHONORMAL : 0;
1622         return this;
1623     }
1624 
1625     /**
1626      * Set this matrix to be a simple scale matrix which scales the base axes by
1627      * <code>xyz.x</code>, <code>xyz.y</code> and <code>xyz.z</code>, respectively.
1628      * <p>
1629      * The resulting matrix can be multiplied against another transformation
1630      * matrix to obtain an additional scaling.
1631      * <p>
1632      * In order to post-multiply a scaling transformation directly to a
1633      * matrix use {@link #scale(Vector3d) scale()} instead.
1634      * 
1635      * @see #scale(Vector3d)
1636      * 
1637      * @param xyz
1638      *             the scale in x, y and z, respectively
1639      * @return this
1640      */
1641     ref public Matrix4x3d scaling(Vector3d xyz) return {
1642         return scaling(xyz.x, xyz.y, xyz.z);
1643     }
1644 
1645     /**
1646      * Set this matrix to a rotation matrix which rotates the given radians about a given axis.
1647      * <p>
1648      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1649      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1650      * When used with a left-handed coordinate system, the rotation is clockwise.
1651      * <p>
1652      * From <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">Wikipedia</a>
1653      * 
1654      * @param angle
1655      *          the angle in radians
1656      * @param x
1657      *          the x-coordinate of the axis to rotate about
1658      * @param y
1659      *          the y-coordinate of the axis to rotate about
1660      * @param z
1661      *          the z-coordinate of the axis to rotate about
1662      * @return this
1663      */
1664     ref public Matrix4x3d rotation(double angle, double x, double y, double z) return {
1665         if (y == 0.0 && z == 0.0 && Math.absEqualsOne(x))
1666             rotationX(x * angle);
1667         else if (x == 0.0 && z == 0.0 && Math.absEqualsOne(y))
1668             rotationY(y * angle);
1669         else if (x == 0.0 && y == 0.0 && Math.absEqualsOne(z))
1670             rotationZ(z * angle);
1671         else
1672             rotationInternal(angle, x, y, z);
1673         return this;
1674     }
1675     private Matrix4x3d rotationInternal(double angle, double x, double y, double z) {
1676         double sin = Math.sin(angle);
1677         double cos = Math.cosFromSin(sin, angle);
1678         double C = 1.0 - cos;
1679         double xy = x * y, xz = x * z, yz = y * z;
1680         m00 = cos + x * x * C;
1681         m01 = xy * C + z * sin;
1682         m02 = xz * C - y * sin;
1683         m10 = xy * C - z * sin;
1684         m11 = cos + y * y * C;
1685         m12 = yz * C + x * sin;
1686         m20 = xz * C + y * sin;
1687         m21 = yz * C - x * sin;
1688         m22 = cos + z * z * C;
1689         m30 = 0.0;
1690         m31 = 0.0;
1691         m32 = 0.0;
1692         properties = PROPERTY_ORTHONORMAL;
1693         return this;
1694     }
1695 
1696     /**
1697      * Set this matrix to a rotation transformation about the X axis.
1698      * <p>
1699      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1700      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1701      * When used with a left-handed coordinate system, the rotation is clockwise.
1702      * <p>
1703      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">http://en.wikipedia.org</a>
1704      * 
1705      * @param ang
1706      *            the angle in radians
1707      * @return this
1708      */
1709     ref public Matrix4x3d rotationX(double ang) return {
1710         double sin, cos;
1711         sin = Math.sin(ang);
1712         cos = Math.cosFromSin(sin, ang);
1713         m00 = 1.0;
1714         m01 = 0.0;
1715         m02 = 0.0;
1716         m10 = 0.0;
1717         m11 = cos;
1718         m12 = sin;
1719         m20 = 0.0;
1720         m21 = -sin;
1721         m22 = cos;
1722         m30 = 0.0;
1723         m31 = 0.0;
1724         m32 = 0.0;
1725         properties = PROPERTY_ORTHONORMAL;
1726         return this;
1727     }
1728 
1729     /**
1730      * Set this matrix to a rotation transformation about the Y axis.
1731      * <p>
1732      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1733      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1734      * When used with a left-handed coordinate system, the rotation is clockwise.
1735      * <p>
1736      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">http://en.wikipedia.org</a>
1737      * 
1738      * @param ang
1739      *            the angle in radians
1740      * @return this
1741      */
1742     ref public Matrix4x3d rotationY(double ang) return {
1743         double sin, cos;
1744         sin = Math.sin(ang);
1745         cos = Math.cosFromSin(sin, ang);
1746         m00 = cos;
1747         m01 = 0.0;
1748         m02 = -sin;
1749         m10 = 0.0;
1750         m11 = 1.0;
1751         m12 = 0.0;
1752         m20 = sin;
1753         m21 = 0.0;
1754         m22 = cos;
1755         m30 = 0.0;
1756         m31 = 0.0;
1757         m32 = 0.0;
1758         properties = PROPERTY_ORTHONORMAL;
1759         return this;
1760     }
1761 
1762     /**
1763      * Set this matrix to a rotation transformation about the Z axis.
1764      * <p>
1765      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1766      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1767      * When used with a left-handed coordinate system, the rotation is clockwise.
1768      * <p>
1769      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">http://en.wikipedia.org</a>
1770      * 
1771      * @param ang
1772      *            the angle in radians
1773      * @return this
1774      */
1775     ref public Matrix4x3d rotationZ(double ang) return {
1776         double sin, cos;
1777         sin = Math.sin(ang);
1778         cos = Math.cosFromSin(sin, ang);
1779         m00 = cos;
1780         m01 = sin;
1781         m02 = 0.0;
1782         m10 = -sin;
1783         m11 = cos;
1784         m12 = 0.0;
1785         m20 = 0.0;
1786         m21 = 0.0;
1787         m22 = 1.0;
1788         m30 = 0.0;
1789         m31 = 0.0;
1790         m32 = 0.0;
1791         properties = PROPERTY_ORTHONORMAL;
1792         return this;
1793     }
1794 
1795     /**
1796      * Set this matrix to a rotation of <code>angleX</code> radians about the X axis, followed by a rotation
1797      * of <code>angleY</code> radians about the Y axis and followed by a rotation of <code>angleZ</code> radians about the Z axis.
1798      * <p>
1799      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1800      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1801      * When used with a left-handed coordinate system, the rotation is clockwise.
1802      * <p>
1803      * This method is equivalent to calling: <code>rotationX(angleX).rotateY(angleY).rotateZ(angleZ)</code>
1804      * 
1805      * @param angleX
1806      *            the angle to rotate about X
1807      * @param angleY
1808      *            the angle to rotate about Y
1809      * @param angleZ
1810      *            the angle to rotate about Z
1811      * @return this
1812      */
1813     ref public Matrix4x3d rotationXYZ(double angleX, double angleY, double angleZ) return {
1814         double sinX = Math.sin(angleX);
1815         double cosX = Math.cosFromSin(sinX, angleX);
1816         double sinY = Math.sin(angleY);
1817         double cosY = Math.cosFromSin(sinY, angleY);
1818         double sinZ = Math.sin(angleZ);
1819         double cosZ = Math.cosFromSin(sinZ, angleZ);
1820         double m_sinX = -sinX;
1821         double m_sinY = -sinY;
1822         double m_sinZ = -sinZ;
1823 
1824         // rotateX
1825         double nm11 = cosX;
1826         double nm12 = sinX;
1827         double nm21 = m_sinX;
1828         double nm22 = cosX;
1829         // rotateY
1830         double nm00 = cosY;
1831         double nm01 = nm21 * m_sinY;
1832         double nm02 = nm22 * m_sinY;
1833         m20 = sinY;
1834         m21 = nm21 * cosY;
1835         m22 = nm22 * cosY;
1836         // rotateZ
1837         m00 = nm00 * cosZ;
1838         m01 = nm01 * cosZ + nm11 * sinZ;
1839         m02 = nm02 * cosZ + nm12 * sinZ;
1840         m10 = nm00 * m_sinZ;
1841         m11 = nm01 * m_sinZ + nm11 * cosZ;
1842         m12 = nm02 * m_sinZ + nm12 * cosZ;
1843         // set last column to identity
1844         m30 = 0.0;
1845         m31 = 0.0;
1846         m32 = 0.0;
1847         properties = PROPERTY_ORTHONORMAL;
1848         return this;
1849     }
1850 
1851     /**
1852      * Set this matrix to a rotation of <code>angleZ</code> radians about the Z axis, followed by a rotation
1853      * of <code>angleY</code> radians about the Y axis and followed by a rotation of <code>angleX</code> radians about the X axis.
1854      * <p>
1855      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1856      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1857      * When used with a left-handed coordinate system, the rotation is clockwise.
1858      * <p>
1859      * This method is equivalent to calling: <code>rotationZ(angleZ).rotateY(angleY).rotateX(angleX)</code>
1860      * 
1861      * @param angleZ
1862      *            the angle to rotate about Z
1863      * @param angleY
1864      *            the angle to rotate about Y
1865      * @param angleX
1866      *            the angle to rotate about X
1867      * @return this
1868      */
1869     ref public Matrix4x3d rotationZYX(double angleZ, double angleY, double angleX) return {
1870         double sinX = Math.sin(angleX);
1871         double cosX = Math.cosFromSin(sinX, angleX);
1872         double sinY = Math.sin(angleY);
1873         double cosY = Math.cosFromSin(sinY, angleY);
1874         double sinZ = Math.sin(angleZ);
1875         double cosZ = Math.cosFromSin(sinZ, angleZ);
1876         double m_sinZ = -sinZ;
1877         double m_sinY = -sinY;
1878         double m_sinX = -sinX;
1879 
1880         // rotateZ
1881         double nm00 = cosZ;
1882         double nm01 = sinZ;
1883         double nm10 = m_sinZ;
1884         double nm11 = cosZ;
1885         // rotateY
1886         double nm20 = nm00 * sinY;
1887         double nm21 = nm01 * sinY;
1888         double nm22 = cosY;
1889         m00 = nm00 * cosY;
1890         m01 = nm01 * cosY;
1891         m02 = m_sinY;
1892         // rotateX
1893         m10 = nm10 * cosX + nm20 * sinX;
1894         m11 = nm11 * cosX + nm21 * sinX;
1895         m12 = nm22 * sinX;
1896         m20 = nm10 * m_sinX + nm20 * cosX;
1897         m21 = nm11 * m_sinX + nm21 * cosX;
1898         m22 = nm22 * cosX;
1899         // set last column to identity
1900         m30 = 0.0;
1901         m31 = 0.0;
1902         m32 = 0.0;
1903         properties = PROPERTY_ORTHONORMAL;
1904         return this;
1905     }
1906 
1907     /**
1908      * Set this matrix to a rotation of <code>angleY</code> radians about the Y axis, followed by a rotation
1909      * of <code>angleX</code> radians about the X axis and followed by a rotation of <code>angleZ</code> radians about the Z axis.
1910      * <p>
1911      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1912      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1913      * When used with a left-handed coordinate system, the rotation is clockwise.
1914      * <p>
1915      * This method is equivalent to calling: <code>rotationY(angleY).rotateX(angleX).rotateZ(angleZ)</code>
1916      * 
1917      * @param angleY
1918      *            the angle to rotate about Y
1919      * @param angleX
1920      *            the angle to rotate about X
1921      * @param angleZ
1922      *            the angle to rotate about Z
1923      * @return this
1924      */
1925     ref public Matrix4x3d rotationYXZ(double angleY, double angleX, double angleZ) return {
1926         double sinX = Math.sin(angleX);
1927         double cosX = Math.cosFromSin(sinX, angleX);
1928         double sinY = Math.sin(angleY);
1929         double cosY = Math.cosFromSin(sinY, angleY);
1930         double sinZ = Math.sin(angleZ);
1931         double cosZ = Math.cosFromSin(sinZ, angleZ);
1932         double m_sinY = -sinY;
1933         double m_sinX = -sinX;
1934         double m_sinZ = -sinZ;
1935 
1936         // rotateY
1937         double nm00 = cosY;
1938         double nm02 = m_sinY;
1939         double nm20 = sinY;
1940         double nm22 = cosY;
1941         // rotateX
1942         double nm10 = nm20 * sinX;
1943         double nm11 = cosX;
1944         double nm12 = nm22 * sinX;
1945         m20 = nm20 * cosX;
1946         m21 = m_sinX;
1947         m22 = nm22 * cosX;
1948         // rotateZ
1949         m00 = nm00 * cosZ + nm10 * sinZ;
1950         m01 = nm11 * sinZ;
1951         m02 = nm02 * cosZ + nm12 * sinZ;
1952         m10 = nm00 * m_sinZ + nm10 * cosZ;
1953         m11 = nm11 * cosZ;
1954         m12 = nm02 * m_sinZ + nm12 * cosZ;
1955         // set last column to identity
1956         m30 = 0.0;
1957         m31 = 0.0;
1958         m32 = 0.0;
1959         properties = PROPERTY_ORTHONORMAL;
1960         return this;
1961     }
1962 
1963     /**
1964      * 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
1965      * of <code>angleY</code> radians about the Y axis and followed by a rotation of <code>angleZ</code> radians about the Z axis.
1966      * <p>
1967      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
1968      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
1969      * When used with a left-handed coordinate system, the rotation is clockwise.
1970      * 
1971      * @param angleX
1972      *            the angle to rotate about X
1973      * @param angleY
1974      *            the angle to rotate about Y
1975      * @param angleZ
1976      *            the angle to rotate about Z
1977      * @return this
1978      */
1979     ref public Matrix4x3d setRotationXYZ(double angleX, double angleY, double angleZ) return {
1980         double sinX = Math.sin(angleX);
1981         double cosX = Math.cosFromSin(sinX, angleX);
1982         double sinY = Math.sin(angleY);
1983         double cosY = Math.cosFromSin(sinY, angleY);
1984         double sinZ = Math.sin(angleZ);
1985         double cosZ = Math.cosFromSin(sinZ, angleZ);
1986         double m_sinX = -sinX;
1987         double m_sinY = -sinY;
1988         double m_sinZ = -sinZ;
1989 
1990         // rotateX
1991         double nm11 = cosX;
1992         double nm12 = sinX;
1993         double nm21 = m_sinX;
1994         double nm22 = cosX;
1995         // rotateY
1996         double nm00 = cosY;
1997         double nm01 = nm21 * m_sinY;
1998         double nm02 = nm22 * m_sinY;
1999         m20 = sinY;
2000         m21 = nm21 * cosY;
2001         m22 = nm22 * cosY;
2002         // rotateZ
2003         m00 = nm00 * cosZ;
2004         m01 = nm01 * cosZ + nm11 * sinZ;
2005         m02 = nm02 * cosZ + nm12 * sinZ;
2006         m10 = nm00 * m_sinZ;
2007         m11 = nm01 * m_sinZ + nm11 * cosZ;
2008         m12 = nm02 * m_sinZ + nm12 * cosZ;
2009         properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
2010         return this;
2011     }
2012 
2013     /**
2014      * 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
2015      * of <code>angleY</code> radians about the Y axis and followed by a rotation of <code>angleX</code> radians about the X axis.
2016      * <p>
2017      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2018      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2019      * When used with a left-handed coordinate system, the rotation is clockwise.
2020      * 
2021      * @param angleZ
2022      *            the angle to rotate about Z
2023      * @param angleY
2024      *            the angle to rotate about Y
2025      * @param angleX
2026      *            the angle to rotate about X
2027      * @return this
2028      */
2029     ref public Matrix4x3d setRotationZYX(double angleZ, double angleY, double angleX) return {
2030         double sinX = Math.sin(angleX);
2031         double cosX = Math.cosFromSin(sinX, angleX);
2032         double sinY = Math.sin(angleY);
2033         double cosY = Math.cosFromSin(sinY, angleY);
2034         double sinZ = Math.sin(angleZ);
2035         double cosZ = Math.cosFromSin(sinZ, angleZ);
2036         double m_sinZ = -sinZ;
2037         double m_sinY = -sinY;
2038         double m_sinX = -sinX;
2039 
2040         // rotateZ
2041         double nm00 = cosZ;
2042         double nm01 = sinZ;
2043         double nm10 = m_sinZ;
2044         double nm11 = cosZ;
2045         // rotateY
2046         double nm20 = nm00 * sinY;
2047         double nm21 = nm01 * sinY;
2048         double nm22 = cosY;
2049         m00 = nm00 * cosY;
2050         m01 = nm01 * cosY;
2051         m02 = m_sinY;
2052         // rotateX
2053         m10 = nm10 * cosX + nm20 * sinX;
2054         m11 = nm11 * cosX + nm21 * sinX;
2055         m12 = nm22 * sinX;
2056         m20 = nm10 * m_sinX + nm20 * cosX;
2057         m21 = nm11 * m_sinX + nm21 * cosX;
2058         m22 = nm22 * cosX;
2059         properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
2060         return this;
2061     }
2062 
2063     /**
2064      * 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
2065      * of <code>angleX</code> radians about the X axis and followed by a rotation of <code>angleZ</code> radians about the Z axis.
2066      * <p>
2067      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2068      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2069      * When used with a left-handed coordinate system, the rotation is clockwise.
2070      * 
2071      * @param angleY
2072      *            the angle to rotate about Y
2073      * @param angleX
2074      *            the angle to rotate about X
2075      * @param angleZ
2076      *            the angle to rotate about Z
2077      * @return this
2078      */
2079     ref public Matrix4x3d setRotationYXZ(double angleY, double angleX, double angleZ) return {
2080         double sinX = Math.sin(angleX);
2081         double cosX = Math.cosFromSin(sinX, angleX);
2082         double sinY = Math.sin(angleY);
2083         double cosY = Math.cosFromSin(sinY, angleY);
2084         double sinZ = Math.sin(angleZ);
2085         double cosZ = Math.cosFromSin(sinZ, angleZ);
2086         double m_sinY = -sinY;
2087         double m_sinX = -sinX;
2088         double m_sinZ = -sinZ;
2089 
2090         // rotateY
2091         double nm00 = cosY;
2092         double nm02 = m_sinY;
2093         double nm20 = sinY;
2094         double nm22 = cosY;
2095         // rotateX
2096         double nm10 = nm20 * sinX;
2097         double nm11 = cosX;
2098         double nm12 = nm22 * sinX;
2099         m20 = nm20 * cosX;
2100         m21 = m_sinX;
2101         m22 = nm22 * cosX;
2102         // rotateZ
2103         m00 = nm00 * cosZ + nm10 * sinZ;
2104         m01 = nm11 * sinZ;
2105         m02 = nm02 * cosZ + nm12 * sinZ;
2106         m10 = nm00 * m_sinZ + nm10 * cosZ;
2107         m11 = nm11 * cosZ;
2108         m12 = nm02 * m_sinZ + nm12 * cosZ;
2109         properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
2110         return this;
2111     }
2112 
2113     /**
2114      * Set this matrix to a rotation matrix which rotates the given radians about a given axis.
2115      * <p>
2116      * The axis described by the <code>axis</code> vector needs to be a unit vector.
2117      * <p>
2118      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2119      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2120      * When used with a left-handed coordinate system, the rotation is clockwise.
2121      * 
2122      * @param angle
2123      *          the angle in radians
2124      * @param axis
2125      *          the axis to rotate about
2126      * @return this
2127      */
2128     ref public Matrix4x3d rotation(double angle, Vector3d axis) return {
2129         return rotation(angle, axis.x, axis.y, axis.z);
2130     }
2131 
2132     public Vector4d transform(Vector4d v) {
2133         return v.mul(this);
2134     }
2135 
2136     public Vector4d transform(Vector4d v, Vector4d dest) {
2137         return v.mul(this, dest);
2138     }
2139 
2140     public Vector3d transformPosition(ref Vector3d v) {
2141         v.set(m00 * v.x + m10 * v.y + m20 * v.z + m30,
2142               m01 * v.x + m11 * v.y + m21 * v.z + m31,
2143               m02 * v.x + m12 * v.y + m22 * v.z + m32);
2144         return v;
2145     }
2146 
2147     public Vector3d transformPosition(ref Vector3d v, ref Vector3d dest) {
2148         dest.set(m00 * v.x + m10 * v.y + m20 * v.z + m30,
2149                  m01 * v.x + m11 * v.y + m21 * v.z + m31,
2150                  m02 * v.x + m12 * v.y + m22 * v.z + m32);
2151         return dest;
2152     }
2153 
2154     public Vector3d transformDirection(ref Vector3d v) {
2155         v.set(m00 * v.x + m10 * v.y + m20 * v.z,
2156               m01 * v.x + m11 * v.y + m21 * v.z,
2157               m02 * v.x + m12 * v.y + m22 * v.z);
2158         return v;
2159     }
2160 
2161     public Vector3d transformDirection(ref Vector3d v, ref Vector3d dest) {
2162         dest.set(m00 * v.x + m10 * v.y + m20 * v.z,
2163                  m01 * v.x + m11 * v.y + m21 * v.z,
2164                  m02 * v.x + m12 * v.y + m22 * v.z);
2165         return dest;
2166     }
2167 
2168     /**
2169      * Set the left 3x3 submatrix of this {@link Matrix4x3d} to the given {@link Matrix3d} and don't change the other elements.
2170      * 
2171      * @param mat
2172      *          the 3x3 matrix
2173      * @return this
2174      */
2175     ref public Matrix4x3d set3x3(Matrix3d mat) return {
2176         m00 = mat.m00;
2177         m01 = mat.m01;
2178         m02 = mat.m02;
2179         m10 = mat.m10;
2180         m11 = mat.m11;
2181         m12 = mat.m12;
2182         m20 = mat.m20;
2183         m21 = mat.m21;
2184         m22 = mat.m22;
2185         properties = 0;
2186         return this;
2187     }
2188 
2189 
2190     public Matrix4x3d scale(Vector3d xyz, ref Matrix4x3d dest) {
2191         return scale(xyz.x, xyz.y, xyz.z, dest);
2192     }
2193 
2194     /**
2195      * Apply scaling to this matrix by scaling the base axes by the given <code>xyz.x</code>,
2196      * <code>xyz.y</code> and <code>xyz.z</code> factors, respectively.
2197      * <p>
2198      * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix,
2199      * then the new matrix will be <code>M * S</code>. So when transforming a
2200      * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the
2201      * scaling will be applied first!
2202      * 
2203      * @param xyz
2204      *            the factors of the x, y and z component, respectively
2205      * @return this
2206      */
2207     ref public Matrix4x3d scale(Vector3d xyz) return {
2208         scale(xyz.x, xyz.y, xyz.z, this);
2209         return this;
2210     }
2211 
2212     public Matrix4x3d scale(double x, double y, double z, ref Matrix4x3d dest) {
2213         if ((properties & PROPERTY_IDENTITY) != 0)
2214             return dest.scaling(x, y, z);
2215         return scaleGeneric(x, y, z, dest);
2216     }
2217     private Matrix4x3d scaleGeneric(double x, double y, double z, ref Matrix4x3d dest) {
2218         dest.m00 = m00 * x;
2219         dest.m01 = m01 * x;
2220         dest.m02 = m02 * x;
2221         dest.m10 = m10 * y;
2222         dest.m11 = m11 * y;
2223         dest.m12 = m12 * y;
2224         dest.m20 = m20 * z;
2225         dest.m21 = m21 * z;
2226         dest.m22 = m22 * z;
2227         dest.m30 = m30;
2228         dest.m31 = m31;
2229         dest.m32 = m32;
2230         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
2231         return dest;
2232     }
2233 
2234     /**
2235      * Apply scaling to <code>this</code> matrix by scaling the base axes by the given x,
2236      * y and z factors.
2237      * <p>
2238      * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix,
2239      * then the new matrix will be <code>M * S</code>. So when transforming a
2240      * vector <code>v</code> with the new matrix by using <code>M * S * v</code>
2241      * , the scaling will be applied first!
2242      * 
2243      * @param x
2244      *            the factor of the x component
2245      * @param y
2246      *            the factor of the y component
2247      * @param z
2248      *            the factor of the z component
2249      * @return this
2250      */
2251     ref public Matrix4x3d scale(double x, double y, double z) return {
2252         scale(x, y, z, this);
2253         return this;
2254     }
2255 
2256     public Matrix4x3d scale(double xyz, ref Matrix4x3d dest) {
2257         return scale(xyz, xyz, xyz, dest);
2258     }
2259 
2260     /**
2261      * Apply scaling to this matrix by uniformly scaling all base axes by the given xyz factor.
2262      * <p>
2263      * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix,
2264      * then the new matrix will be <code>M * S</code>. So when transforming a
2265      * vector <code>v</code> with the new matrix by using <code>M * S * v</code>
2266      * , the scaling will be applied first!
2267      * 
2268      * @see #scale(double, double, double)
2269      * 
2270      * @param xyz
2271      *            the factor for all components
2272      * @return this
2273      */
2274     ref public Matrix4x3d scale(double xyz) return {
2275         return scale(xyz, xyz, xyz);
2276     }
2277 
2278     public Matrix4x3d scaleXY(double x, double y, ref Matrix4x3d dest) {
2279         return scale(x, y, 1.0, dest);
2280     }
2281 
2282     /**
2283      * Apply scaling to this matrix by scaling the X axis by <code>x</code> and the Y axis by <code>y</code>.
2284      * <p>
2285      * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix,
2286      * then the new matrix will be <code>M * S</code>. So when transforming a
2287      * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the
2288      * scaling will be applied first!
2289      * 
2290      * @param x
2291      *            the factor of the x component
2292      * @param y
2293      *            the factor of the y component
2294      * @return this
2295      */
2296     ref public Matrix4x3d scaleXY(double x, double y) return {
2297         return scale(x, y, 1.0);
2298     }
2299 
2300     public Matrix4x3d scaleAround(double sx, double sy, double sz, double ox, double oy, double oz, ref Matrix4x3d dest) {
2301         double nm30 = m00 * ox + m10 * oy + m20 * oz + m30;
2302         double nm31 = m01 * ox + m11 * oy + m21 * oz + m31;
2303         double nm32 = m02 * ox + m12 * oy + m22 * oz + m32;
2304         bool one = Math.absEqualsOne(sx) && Math.absEqualsOne(sy) && Math.absEqualsOne(sz);
2305         return dest
2306         ._m00(m00 * sx)
2307         ._m01(m01 * sx)
2308         ._m02(m02 * sx)
2309         ._m10(m10 * sy)
2310         ._m11(m11 * sy)
2311         ._m12(m12 * sy)
2312         ._m20(m20 * sz)
2313         ._m21(m21 * sz)
2314         ._m22(m22 * sz)
2315         ._m30(-dest.m00 * ox - dest.m10 * oy - dest.m20 * oz + nm30)
2316         ._m31(-dest.m01 * ox - dest.m11 * oy - dest.m21 * oz + nm31)
2317         ._m32(-dest.m02 * ox - dest.m12 * oy - dest.m22 * oz + nm32)
2318         ._properties(properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | (one ? 0 : PROPERTY_ORTHONORMAL)));
2319     }
2320 
2321     /**
2322      * Apply scaling to this matrix by scaling the base axes by the given sx,
2323      * sy and sz factors while using <code>(ox, oy, oz)</code> as the scaling origin.
2324      * <p>
2325      * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix,
2326      * then the new matrix will be <code>M * S</code>. So when transforming a
2327      * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the
2328      * scaling will be applied first!
2329      * <p>
2330      * This method is equivalent to calling: <code>translate(ox, oy, oz).scale(sx, sy, sz).translate(-ox, -oy, -oz)</code>
2331      * 
2332      * @param sx
2333      *            the scaling factor of the x component
2334      * @param sy
2335      *            the scaling factor of the y component
2336      * @param sz
2337      *            the scaling factor of the z component
2338      * @param ox
2339      *            the x coordinate of the scaling origin
2340      * @param oy
2341      *            the y coordinate of the scaling origin
2342      * @param oz
2343      *            the z coordinate of the scaling origin
2344      * @return this
2345      */
2346     ref public Matrix4x3d scaleAround(double sx, double sy, double sz, double ox, double oy, double oz) return {
2347         scaleAround(sx, sy, sz, ox, oy, oz, this);
2348         return this;
2349     }
2350 
2351     /**
2352      * Apply scaling to this matrix by scaling all three base axes by the given <code>factor</code>
2353      * while using <code>(ox, oy, oz)</code> as the scaling origin.
2354      * <p>
2355      * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix,
2356      * then the new matrix will be <code>M * S</code>. So when transforming a
2357      * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the
2358      * scaling will be applied first!
2359      * <p>
2360      * This method is equivalent to calling: <code>translate(ox, oy, oz).scale(factor).translate(-ox, -oy, -oz)</code>
2361      * 
2362      * @param factor
2363      *            the scaling factor for all three axes
2364      * @param ox
2365      *            the x coordinate of the scaling origin
2366      * @param oy
2367      *            the y coordinate of the scaling origin
2368      * @param oz
2369      *            the z coordinate of the scaling origin
2370      * @return this
2371      */
2372     ref public Matrix4x3d scaleAround(double factor, double ox, double oy, double oz) return {
2373         scaleAround(factor, factor, factor, ox, oy, oz, this);
2374         return this;
2375     }
2376 
2377     public Matrix4x3d scaleAround(double factor, double ox, double oy, double oz, ref Matrix4x3d dest) {
2378         return scaleAround(factor, factor, factor, ox, oy, oz, dest);
2379     }
2380 
2381     public Matrix4x3d scaleLocal(double x, double y, double z, ref Matrix4x3d dest) {
2382         if ((properties & PROPERTY_IDENTITY) != 0)
2383             return dest.scaling(x, y, z);
2384 
2385         double nm00 = x * m00;
2386         double nm01 = y * m01;
2387         double nm02 = z * m02;
2388         double nm10 = x * m10;
2389         double nm11 = y * m11;
2390         double nm12 = z * m12;
2391         double nm20 = x * m20;
2392         double nm21 = y * m21;
2393         double nm22 = z * m22;
2394         double nm30 = x * m30;
2395         double nm31 = y * m31;
2396         double nm32 = z * m32;
2397         dest.m00 = nm00;
2398         dest.m01 = nm01;
2399         dest.m02 = nm02;
2400         dest.m10 = nm10;
2401         dest.m11 = nm11;
2402         dest.m12 = nm12;
2403         dest.m20 = nm20;
2404         dest.m21 = nm21;
2405         dest.m22 = nm22;
2406         dest.m30 = nm30;
2407         dest.m31 = nm31;
2408         dest.m32 = nm32;
2409         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
2410         return dest;
2411     }
2412 
2413     /**
2414      * Pre-multiply scaling to this matrix by scaling the base axes by the given x,
2415      * y and z factors.
2416      * <p>
2417      * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix,
2418      * then the new matrix will be <code>S * M</code>. So when transforming a
2419      * vector <code>v</code> with the new matrix by using <code>S * M * v</code>, the
2420      * scaling will be applied last!
2421      * 
2422      * @param x
2423      *            the factor of the x component
2424      * @param y
2425      *            the factor of the y component
2426      * @param z
2427      *            the factor of the z component
2428      * @return this
2429      */
2430     ref public Matrix4x3d scaleLocal(double x, double y, double z) return {
2431         scaleLocal(x, y, z, this);
2432         return this;
2433     }
2434 
2435     public Matrix4x3d rotate(double ang, double x, double y, double z, ref Matrix4x3d dest) {
2436         if ((properties & PROPERTY_IDENTITY) != 0)
2437             return dest.rotation(ang, x, y, z);
2438         else if ((properties & PROPERTY_TRANSLATION) != 0)
2439             return rotateTranslation(ang, x, y, z, dest);
2440         return rotateGeneric(ang, x, y, z, dest);
2441     }
2442     private Matrix4x3d rotateGeneric(double ang, double x, double y, double z, ref Matrix4x3d dest) {
2443         if (y == 0.0 && z == 0.0 && Math.absEqualsOne(x))
2444             return rotateX(x * ang, dest);
2445         else if (x == 0.0 && z == 0.0 && Math.absEqualsOne(y))
2446             return rotateY(y * ang, dest);
2447         else if (x == 0.0 && y == 0.0 && Math.absEqualsOne(z))
2448             return rotateZ(z * ang, dest);
2449         return rotateGenericInternal(ang, x, y, z, dest);
2450     }
2451     private Matrix4x3d rotateGenericInternal(double ang, double x, double y, double z, ref Matrix4x3d dest) {
2452         double s = Math.sin(ang);
2453         double c = Math.cosFromSin(s, ang);
2454         double C = 1.0 - c;
2455         double xx = x * x, xy = x * y, xz = x * z;
2456         double yy = y * y, yz = y * z;
2457         double zz = z * z;
2458         double rm00 = xx * C + c;
2459         double rm01 = xy * C + z * s;
2460         double rm02 = xz * C - y * s;
2461         double rm10 = xy * C - z * s;
2462         double rm11 = yy * C + c;
2463         double rm12 = yz * C + x * s;
2464         double rm20 = xz * C + y * s;
2465         double rm21 = yz * C - x * s;
2466         double rm22 = zz * C + c;
2467         // add temporaries for dependent values
2468         double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
2469         double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
2470         double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
2471         double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
2472         double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
2473         double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
2474         // set non-dependent values directly
2475         dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
2476         dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
2477         dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
2478         // set other values
2479         dest.m00 = nm00;
2480         dest.m01 = nm01;
2481         dest.m02 = nm02;
2482         dest.m10 = nm10;
2483         dest.m11 = nm11;
2484         dest.m12 = nm12;
2485         dest.m30 = m30;
2486         dest.m31 = m31;
2487         dest.m32 = m32;
2488         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
2489         return dest;
2490     }
2491 
2492     /**
2493      * Apply rotation to this matrix by rotating the given amount of radians
2494      * about the given axis specified as x, y and z components.
2495      * <p>
2496      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2497      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2498      * When used with a left-handed coordinate system, the rotation is clockwise.
2499      * <p>
2500      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
2501      * then the new matrix will be <code>M * R</code>. So when transforming a
2502      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>
2503      * , the rotation will be applied first!
2504      * <p>
2505      * In order to set the matrix to a rotation matrix without post-multiplying the rotation
2506      * transformation, use {@link #rotation(double, double, double, double) rotation()}.
2507      * 
2508      * @see #rotation(double, double, double, double)
2509      *  
2510      * @param ang
2511      *            the angle is in radians
2512      * @param x
2513      *            the x component of the axis
2514      * @param y
2515      *            the y component of the axis
2516      * @param z
2517      *            the z component of the axis
2518      * @return this
2519      */
2520     ref public Matrix4x3d rotate(double ang, double x, double y, double z) return {
2521         rotate(ang, x, y, z, this);
2522         return this;
2523     }
2524 
2525     /**
2526      * Apply rotation to this matrix, which is assumed to only contain a translation, by rotating the given amount of radians
2527      * about the specified <code>(x, y, z)</code> axis and store the result in <code>dest</code>.
2528      * <p>
2529      * This method assumes <code>this</code> to only contain a translation.
2530      * <p>
2531      * The axis described by the three components needs to be a unit vector.
2532      * <p>
2533      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2534      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2535      * When used with a left-handed coordinate system, the rotation is clockwise.
2536      * <p>
2537      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
2538      * then the new matrix will be <code>M * R</code>. So when transforming a
2539      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
2540      * rotation will be applied first!
2541      * <p>
2542      * In order to set the matrix to a rotation matrix without post-multiplying the rotation
2543      * transformation, use {@link #rotation(double, double, double, double) rotation()}.
2544      * <p>
2545      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a>
2546      * 
2547      * @see #rotation(double, double, double, double)
2548      * 
2549      * @param ang
2550      *            the angle in radians
2551      * @param x
2552      *            the x component of the axis
2553      * @param y
2554      *            the y component of the axis
2555      * @param z
2556      *            the z component of the axis
2557      * @param dest
2558      *            will hold the result
2559      * @return dest
2560      */
2561     public Matrix4x3d rotateTranslation(double ang, double x, double y, double z, ref Matrix4x3d dest) {
2562         double tx = m30, ty = m31, tz = m32;
2563         if (y == 0.0 && z == 0.0 && Math.absEqualsOne(x))
2564             return dest.rotationX(x * ang).setTranslation(tx, ty, tz);
2565         else if (x == 0.0 && z == 0.0 && Math.absEqualsOne(y))
2566             return dest.rotationY(y * ang).setTranslation(tx, ty, tz);
2567         else if (x == 0.0 && y == 0.0 && Math.absEqualsOne(z))
2568             return dest.rotationZ(z * ang).setTranslation(tx, ty, tz);
2569         return rotateTranslationInternal(ang, x, y, z, dest);
2570     }
2571     private Matrix4x3d rotateTranslationInternal(double ang, double x, double y, double z, ref Matrix4x3d dest) {
2572         double s = Math.sin(ang);
2573         double c = Math.cosFromSin(s, ang);
2574         double C = 1.0 - c;
2575         double xx = x * x, xy = x * y, xz = x * z;
2576         double yy = y * y, yz = y * z;
2577         double zz = z * z;
2578         double rm00 = xx * C + c;
2579         double rm01 = xy * C + z * s;
2580         double rm02 = xz * C - y * s;
2581         double rm10 = xy * C - z * s;
2582         double rm11 = yy * C + c;
2583         double rm12 = yz * C + x * s;
2584         double rm20 = xz * C + y * s;
2585         double rm21 = yz * C - x * s;
2586         double rm22 = zz * C + c;
2587         dest.m20 = rm20;
2588         dest.m21 = rm21;
2589         dest.m22 = rm22;
2590         dest.m00 = rm00;
2591         dest.m01 = rm01;
2592         dest.m02 = rm02;
2593         dest.m10 = rm10;
2594         dest.m11 = rm11;
2595         dest.m12 = rm12;
2596         dest.m30 = m30;
2597         dest.m31 = m31;
2598         dest.m32 = m32;
2599         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
2600         return dest;
2601     }
2602 
2603     /**
2604      * Apply the rotation transformation of the given {@link Quaterniond} to this matrix while using <code>(ox, oy, oz)</code> as the rotation origin.
2605      * <p>
2606      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2607      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2608      * When used with a left-handed coordinate system, the rotation is clockwise.
2609      * <p>
2610      * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion,
2611      * then the new matrix will be <code>M * Q</code>. So when transforming a
2612      * vector <code>v</code> with the new matrix by using <code>M * Q * v</code>,
2613      * the quaternion rotation will be applied first!
2614      * <p>
2615      * This method is equivalent to calling: <code>translate(ox, oy, oz).rotate(quat).translate(-ox, -oy, -oz)</code>
2616      * <p>
2617      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a>
2618      * 
2619      * @param quat
2620      *          the {@link Quaterniond}
2621      * @param ox
2622      *          the x coordinate of the rotation origin
2623      * @param oy
2624      *          the y coordinate of the rotation origin
2625      * @param oz
2626      *          the z coordinate of the rotation origin
2627      * @return this
2628      */
2629     ref public Matrix4x3d rotateAround(Quaterniond quat, double ox, double oy, double oz) return {
2630         rotateAround(quat, ox, oy, oz, this);
2631         return this;
2632     }
2633 
2634     private Matrix4x3d rotateAroundAffine(Quaterniond quat, double ox, double oy, double oz, ref Matrix4x3d dest) {
2635         double w2 = quat.w * quat.w, x2 = quat.x * quat.x;
2636         double y2 = quat.y * quat.y, z2 = quat.z * quat.z;
2637         double zw = quat.z * quat.w, dzw = zw + zw, xy = quat.x * quat.y, dxy = xy + xy;
2638         double xz = quat.x * quat.z, dxz = xz + xz, yw = quat.y * quat.w, dyw = yw + yw;
2639         double yz = quat.y * quat.z, dyz = yz + yz, xw = quat.x * quat.w, dxw = xw + xw;
2640         double rm00 = w2 + x2 - z2 - y2;
2641         double rm01 = dxy + dzw;
2642         double rm02 = dxz - dyw;
2643         double rm10 = dxy - dzw;
2644         double rm11 = y2 - z2 + w2 - x2;
2645         double rm12 = dyz + dxw;
2646         double rm20 = dyw + dxz;
2647         double rm21 = dyz - dxw;
2648         double rm22 = z2 - y2 - x2 + w2;
2649         double tm30 = m00 * ox + m10 * oy + m20 * oz + m30;
2650         double tm31 = m01 * ox + m11 * oy + m21 * oz + m31;
2651         double tm32 = m02 * ox + m12 * oy + m22 * oz + m32;
2652         double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
2653         double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
2654         double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
2655         double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
2656         double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
2657         double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
2658         dest
2659         ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22)
2660         ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22)
2661         ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22)
2662         ._m00(nm00)
2663         ._m01(nm01)
2664         ._m02(nm02)
2665         ._m10(nm10)
2666         ._m11(nm11)
2667         ._m12(nm12)
2668         ._m30(-nm00 * ox - nm10 * oy - m20 * oz + tm30)
2669         ._m31(-nm01 * ox - nm11 * oy - m21 * oz + tm31)
2670         ._m32(-nm02 * ox - nm12 * oy - m22 * oz + tm32)
2671         ._properties(properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
2672         return dest;
2673     }
2674 
2675     public Matrix4x3d rotateAround(Quaterniond quat, double ox, double oy, double oz, ref Matrix4x3d dest) {
2676         if ((properties & PROPERTY_IDENTITY) != 0)
2677             return rotationAround(quat, ox, oy, oz);
2678         return rotateAroundAffine(quat, ox, oy, oz, dest);
2679     }
2680 
2681     /**
2682      * 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.
2683      * <p>
2684      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2685      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2686      * When used with a left-handed coordinate system, the rotation is clockwise.
2687      * <p>
2688      * This method is equivalent to calling: <code>translation(ox, oy, oz).rotate(quat).translate(-ox, -oy, -oz)</code>
2689      * <p>
2690      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a>
2691      * 
2692      * @param quat
2693      *          the {@link Quaterniond}
2694      * @param ox
2695      *          the x coordinate of the rotation origin
2696      * @param oy
2697      *          the y coordinate of the rotation origin
2698      * @param oz
2699      *          the z coordinate of the rotation origin
2700      * @return this
2701      */
2702     ref public Matrix4x3d rotationAround(Quaterniond quat, double ox, double oy, double oz) return {
2703         double w2 = quat.w * quat.w, x2 = quat.x * quat.x;
2704         double y2 = quat.y * quat.y, z2 = quat.z * quat.z;
2705         double zw = quat.z * quat.w, dzw = zw + zw, xy = quat.x * quat.y, dxy = xy + xy;
2706         double xz = quat.x * quat.z, dxz = xz + xz, yw = quat.y * quat.w, dyw = yw + yw;
2707         double yz = quat.y * quat.z, dyz = yz + yz, xw = quat.x * quat.w, dxw = xw + xw;
2708         this._m20(dyw + dxz);
2709         this._m21(dyz - dxw);
2710         this._m22(z2 - y2 - x2 + w2);
2711         this._m00(w2 + x2 - z2 - y2);
2712         this._m01(dxy + dzw);
2713         this._m02(dxz - dyw);
2714         this._m10(dxy - dzw);
2715         this._m11(y2 - z2 + w2 - x2);
2716         this._m12(dyz + dxw);
2717         this._m30(-m00 * ox - m10 * oy - m20 * oz + ox);
2718         this._m31(-m01 * ox - m11 * oy - m21 * oz + oy);
2719         this._m32(-m02 * ox - m12 * oy - m22 * oz + oz);
2720         this.properties = PROPERTY_ORTHONORMAL;
2721         return this;
2722     }
2723 
2724     /**
2725      * Pre-multiply a rotation to this matrix by rotating the given amount of radians
2726      * about the specified <code>(x, y, z)</code> axis and store the result in <code>dest</code>.
2727      * <p>
2728      * The axis described by the three components needs to be a unit vector.
2729      * <p>
2730      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2731      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2732      * When used with a left-handed coordinate system, the rotation is clockwise.
2733      * <p>
2734      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
2735      * then the new matrix will be <code>R * M</code>. So when transforming a
2736      * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the
2737      * rotation will be applied last!
2738      * <p>
2739      * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
2740      * transformation, use {@link #rotation(double, double, double, double) rotation()}.
2741      * <p>
2742      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a>
2743      * 
2744      * @see #rotation(double, double, double, double)
2745      * 
2746      * @param ang
2747      *            the angle in radians
2748      * @param x
2749      *            the x component of the axis
2750      * @param y
2751      *            the y component of the axis
2752      * @param z
2753      *            the z component of the axis
2754      * @param dest
2755      *            will hold the result
2756      * @return dest
2757      */
2758     public Matrix4x3d rotateLocal(double ang, double x, double y, double z, ref Matrix4x3d dest) {
2759         if (y == 0.0 && z == 0.0 && Math.absEqualsOne(x))
2760             return rotateLocalX(x * ang, dest);
2761         else if (x == 0.0 && z == 0.0 && Math.absEqualsOne(y))
2762             return rotateLocalY(y * ang, dest);
2763         else if (x == 0.0 && y == 0.0 && Math.absEqualsOne(z))
2764             return rotateLocalZ(z * ang, dest);
2765         return rotateLocalInternal(ang, x, y, z, dest);
2766     }
2767     private Matrix4x3d rotateLocalInternal(double ang, double x, double y, double z, ref Matrix4x3d dest) {
2768         double s = Math.sin(ang);
2769         double c = Math.cosFromSin(s, ang);
2770         double C = 1.0 - c;
2771         double xx = x * x, xy = x * y, xz = x * z;
2772         double yy = y * y, yz = y * z;
2773         double zz = z * z;
2774         double lm00 = xx * C + c;
2775         double lm01 = xy * C + z * s;
2776         double lm02 = xz * C - y * s;
2777         double lm10 = xy * C - z * s;
2778         double lm11 = yy * C + c;
2779         double lm12 = yz * C + x * s;
2780         double lm20 = xz * C + y * s;
2781         double lm21 = yz * C - x * s;
2782         double lm22 = zz * C + c;
2783         double nm00 = lm00 * m00 + lm10 * m01 + lm20 * m02;
2784         double nm01 = lm01 * m00 + lm11 * m01 + lm21 * m02;
2785         double nm02 = lm02 * m00 + lm12 * m01 + lm22 * m02;
2786         double nm10 = lm00 * m10 + lm10 * m11 + lm20 * m12;
2787         double nm11 = lm01 * m10 + lm11 * m11 + lm21 * m12;
2788         double nm12 = lm02 * m10 + lm12 * m11 + lm22 * m12;
2789         double nm20 = lm00 * m20 + lm10 * m21 + lm20 * m22;
2790         double nm21 = lm01 * m20 + lm11 * m21 + lm21 * m22;
2791         double nm22 = lm02 * m20 + lm12 * m21 + lm22 * m22;
2792         double nm30 = lm00 * m30 + lm10 * m31 + lm20 * m32;
2793         double nm31 = lm01 * m30 + lm11 * m31 + lm21 * m32;
2794         double nm32 = lm02 * m30 + lm12 * m31 + lm22 * m32;
2795         dest.m00 = nm00;
2796         dest.m01 = nm01;
2797         dest.m02 = nm02;
2798         dest.m10 = nm10;
2799         dest.m11 = nm11;
2800         dest.m12 = nm12;
2801         dest.m20 = nm20;
2802         dest.m21 = nm21;
2803         dest.m22 = nm22;
2804         dest.m30 = nm30;
2805         dest.m31 = nm31;
2806         dest.m32 = nm32;
2807         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
2808         return dest;
2809     }
2810 
2811     /**
2812      * Pre-multiply a rotation to this matrix by rotating the given amount of radians
2813      * about the specified <code>(x, y, z)</code> axis.
2814      * <p>
2815      * The axis described by the three components needs to be a unit vector.
2816      * <p>
2817      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2818      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2819      * When used with a left-handed coordinate system, the rotation is clockwise.
2820      * <p>
2821      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
2822      * then the new matrix will be <code>R * M</code>. So when transforming a
2823      * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the
2824      * rotation will be applied last!
2825      * <p>
2826      * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
2827      * transformation, use {@link #rotation(double, double, double, double) rotation()}.
2828      * <p>
2829      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a>
2830      * 
2831      * @see #rotation(double, double, double, double)
2832      * 
2833      * @param ang
2834      *            the angle in radians
2835      * @param x
2836      *            the x component of the axis
2837      * @param y
2838      *            the y component of the axis
2839      * @param z
2840      *            the z component of the axis
2841      * @return this
2842      */
2843     ref public Matrix4x3d rotateLocal(double ang, double x, double y, double z) return {
2844         rotateLocal(ang, x, y, z, this);
2845         return this;
2846     }
2847 
2848     /**
2849      * Pre-multiply a rotation around the X axis to this matrix by rotating the given amount of radians
2850      * about the X axis and store the result in <code>dest</code>.
2851      * <p>
2852      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2853      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2854      * When used with a left-handed coordinate system, the rotation is clockwise.
2855      * <p>
2856      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
2857      * then the new matrix will be <code>R * M</code>. So when transforming a
2858      * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the
2859      * rotation will be applied last!
2860      * <p>
2861      * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
2862      * transformation, use {@link #rotationX(double) rotationX()}.
2863      * <p>
2864      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a>
2865      * 
2866      * @see #rotationX(double)
2867      * 
2868      * @param ang
2869      *            the angle in radians to rotate about the X axis
2870      * @param dest
2871      *            will hold the result
2872      * @return dest
2873      */
2874     public Matrix4x3d rotateLocalX(double ang, ref Matrix4x3d dest) {
2875         double sin = Math.sin(ang);
2876         double cos = Math.cosFromSin(sin, ang);
2877         double nm01 = cos * m01 - sin * m02;
2878         double nm02 = sin * m01 + cos * m02;
2879         double nm11 = cos * m11 - sin * m12;
2880         double nm12 = sin * m11 + cos * m12;
2881         double nm21 = cos * m21 - sin * m22;
2882         double nm22 = sin * m21 + cos * m22;
2883         double nm31 = cos * m31 - sin * m32;
2884         double nm32 = sin * m31 + cos * m32;
2885         dest.m00 = m00;
2886         dest.m01 = nm01;
2887         dest.m02 = nm02;
2888         dest.m10 = m10;
2889         dest.m11 = nm11;
2890         dest.m12 = nm12;
2891         dest.m20 = m20;
2892         dest.m21 = nm21;
2893         dest.m22 = nm22;
2894         dest.m30 = m30;
2895         dest.m31 = nm31;
2896         dest.m32 = nm32;
2897         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
2898         return dest;
2899     }
2900 
2901     /**
2902      * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the X axis.
2903      * <p>
2904      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2905      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2906      * When used with a left-handed coordinate system, the rotation is clockwise.
2907      * <p>
2908      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
2909      * then the new matrix will be <code>R * M</code>. So when transforming a
2910      * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the
2911      * rotation will be applied last!
2912      * <p>
2913      * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
2914      * transformation, use {@link #rotationX(double) rotationX()}.
2915      * <p>
2916      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a>
2917      * 
2918      * @see #rotationX(double)
2919      * 
2920      * @param ang
2921      *            the angle in radians to rotate about the X axis
2922      * @return this
2923      */
2924     ref public Matrix4x3d rotateLocalX(double ang) return {
2925         rotateLocalX(ang, this);
2926         return this;
2927     }
2928 
2929     /**
2930      * Pre-multiply a rotation around the Y axis to this matrix by rotating the given amount of radians
2931      * about the Y axis and store the result in <code>dest</code>.
2932      * <p>
2933      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2934      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2935      * When used with a left-handed coordinate system, the rotation is clockwise.
2936      * <p>
2937      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
2938      * then the new matrix will be <code>R * M</code>. So when transforming a
2939      * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the
2940      * rotation will be applied last!
2941      * <p>
2942      * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
2943      * transformation, use {@link #rotationY(double) rotationY()}.
2944      * <p>
2945      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a>
2946      * 
2947      * @see #rotationY(double)
2948      * 
2949      * @param ang
2950      *            the angle in radians to rotate about the Y axis
2951      * @param dest
2952      *            will hold the result
2953      * @return dest
2954      */
2955     public Matrix4x3d rotateLocalY(double ang, ref Matrix4x3d dest) {
2956         double sin = Math.sin(ang);
2957         double cos = Math.cosFromSin(sin, ang);
2958         double nm00 =  cos * m00 + sin * m02;
2959         double nm02 = -sin * m00 + cos * m02;
2960         double nm10 =  cos * m10 + sin * m12;
2961         double nm12 = -sin * m10 + cos * m12;
2962         double nm20 =  cos * m20 + sin * m22;
2963         double nm22 = -sin * m20 + cos * m22;
2964         double nm30 =  cos * m30 + sin * m32;
2965         double nm32 = -sin * m30 + cos * m32;
2966         dest.m00 = nm00;
2967         dest.m01 = m01;
2968         dest.m02 = nm02;
2969         dest.m10 = nm10;
2970         dest.m11 = m11;
2971         dest.m12 = nm12;
2972         dest.m20 = nm20;
2973         dest.m21 = m21;
2974         dest.m22 = nm22;
2975         dest.m30 = nm30;
2976         dest.m31 = m31;
2977         dest.m32 = nm32;
2978         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
2979         return dest;
2980     }
2981 
2982     /**
2983      * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the Y axis.
2984      * <p>
2985      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
2986      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
2987      * When used with a left-handed coordinate system, the rotation is clockwise.
2988      * <p>
2989      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
2990      * then the new matrix will be <code>R * M</code>. So when transforming a
2991      * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the
2992      * rotation will be applied last!
2993      * <p>
2994      * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
2995      * transformation, use {@link #rotationY(double) rotationY()}.
2996      * <p>
2997      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a>
2998      * 
2999      * @see #rotationY(double)
3000      * 
3001      * @param ang
3002      *            the angle in radians to rotate about the Y axis
3003      * @return this
3004      */
3005     ref public Matrix4x3d rotateLocalY(double ang) return {
3006         rotateLocalY(ang, this);
3007         return this;
3008     }
3009 
3010     /**
3011      * Pre-multiply a rotation around the Z axis to this matrix by rotating the given amount of radians
3012      * about the Z axis and store the result in <code>dest</code>.
3013      * <p>
3014      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
3015      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
3016      * When used with a left-handed coordinate system, the rotation is clockwise.
3017      * <p>
3018      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
3019      * then the new matrix will be <code>R * M</code>. So when transforming a
3020      * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the
3021      * rotation will be applied last!
3022      * <p>
3023      * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
3024      * transformation, use {@link #rotationZ(double) rotationZ()}.
3025      * <p>
3026      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a>
3027      * 
3028      * @see #rotationZ(double)
3029      * 
3030      * @param ang
3031      *            the angle in radians to rotate about the Z axis
3032      * @param dest
3033      *            will hold the result
3034      * @return dest
3035      */
3036     public Matrix4x3d rotateLocalZ(double ang, ref Matrix4x3d dest) {
3037         double sin = Math.sin(ang);
3038         double cos = Math.cosFromSin(sin, ang);
3039         double nm00 = cos * m00 - sin * m01;
3040         double nm01 = sin * m00 + cos * m01;
3041         double nm10 = cos * m10 - sin * m11;
3042         double nm11 = sin * m10 + cos * m11;
3043         double nm20 = cos * m20 - sin * m21;
3044         double nm21 = sin * m20 + cos * m21;
3045         double nm30 = cos * m30 - sin * m31;
3046         double nm31 = sin * m30 + cos * m31;
3047         dest.m00 = nm00;
3048         dest.m01 = nm01;
3049         dest.m02 = m02;
3050         dest.m10 = nm10;
3051         dest.m11 = nm11;
3052         dest.m12 = m12;
3053         dest.m20 = nm20;
3054         dest.m21 = nm21;
3055         dest.m22 = m22;
3056         dest.m30 = nm30;
3057         dest.m31 = nm31;
3058         dest.m32 = m32;
3059         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
3060         return dest;
3061     }
3062 
3063     /**
3064      * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the Z axis.
3065      * <p>
3066      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
3067      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
3068      * When used with a left-handed coordinate system, the rotation is clockwise.
3069      * <p>
3070      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
3071      * then the new matrix will be <code>R * M</code>. So when transforming a
3072      * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the
3073      * rotation will be applied last!
3074      * <p>
3075      * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
3076      * transformation, use {@link #rotationZ(double) rotationY()}.
3077      * <p>
3078      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle">http://en.wikipedia.org</a>
3079      * 
3080      * @see #rotationY(double)
3081      * 
3082      * @param ang
3083      *            the angle in radians to rotate about the Z axis
3084      * @return this
3085      */
3086     ref public Matrix4x3d rotateLocalZ(double ang) return {
3087         rotateLocalZ(ang, this);
3088         return this;
3089     }
3090 
3091     /**
3092      * Apply a translation to this matrix by translating by the given number of
3093      * units in x, y and z.
3094      * <p>
3095      * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation
3096      * matrix, then the new matrix will be <code>M * T</code>. So when
3097      * transforming a vector <code>v</code> with the new matrix by using
3098      * <code>M * T * v</code>, the translation will be applied first!
3099      * <p>
3100      * In order to set the matrix to a translation transformation without post-multiplying
3101      * it, use {@link #translation(Vector3d)}.
3102      * 
3103      * @see #translation(Vector3d)
3104      * 
3105      * @param offset
3106      *          the number of units in x, y and z by which to translate
3107      * @return this
3108      */
3109     ref public Matrix4x3d translate(Vector3d offset) return {
3110         return translate(offset.x, offset.y, offset.z);
3111     }
3112 
3113     /**
3114      * Apply a translation to this matrix by translating by the given number of
3115      * units in x, y and z and store the result in <code>dest</code>.
3116      * <p>
3117      * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation
3118      * matrix, then the new matrix will be <code>M * T</code>. So when
3119      * transforming a vector <code>v</code> with the new matrix by using
3120      * <code>M * T * v</code>, the translation will be applied first!
3121      * <p>
3122      * In order to set the matrix to a translation transformation without post-multiplying
3123      * it, use {@link #translation(Vector3d)}.
3124      * 
3125      * @see #translation(Vector3d)
3126      * 
3127      * @param offset
3128      *          the number of units in x, y and z by which to translate
3129      * @param dest
3130      *          will hold the result
3131      * @return dest
3132      */
3133     public Matrix4x3d translate(Vector3d offset, ref Matrix4x3d dest) {
3134         return translate(offset.x, offset.y, offset.z, dest);
3135     }
3136 
3137     /**
3138      * Apply a translation to this matrix by translating by the given number of
3139      * units in x, y and z and store the result in <code>dest</code>.
3140      * <p>
3141      * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation
3142      * matrix, then the new matrix will be <code>M * T</code>. So when
3143      * transforming a vector <code>v</code> with the new matrix by using
3144      * <code>M * T * v</code>, the translation will be applied first!
3145      * <p>
3146      * In order to set the matrix to a translation transformation without post-multiplying
3147      * it, use {@link #translation(double, double, double)}.
3148      * 
3149      * @see #translation(double, double, double)
3150      * 
3151      * @param x
3152      *          the offset to translate in x
3153      * @param y
3154      *          the offset to translate in y
3155      * @param z
3156      *          the offset to translate in z
3157      * @param dest
3158      *          will hold the result
3159      * @return dest
3160      */
3161     public Matrix4x3d translate(double x, double y, double z, ref Matrix4x3d dest) {
3162         if ((properties & PROPERTY_IDENTITY) != 0)
3163             return dest.translation(x, y, z);
3164         return translateGeneric(x, y, z, dest);
3165     }
3166     private Matrix4x3d translateGeneric(double x, double y, double z, ref Matrix4x3d dest) {
3167         dest.m00 = m00;
3168         dest.m01 = m01;
3169         dest.m02 = m02;
3170         dest.m10 = m10;
3171         dest.m11 = m11;
3172         dest.m12 = m12;
3173         dest.m20 = m20;
3174         dest.m21 = m21;
3175         dest.m22 = m22;
3176         dest.m30 = m00 * x + m10 * y + m20 * z + m30;
3177         dest.m31 = m01 * x + m11 * y + m21 * z + m31;
3178         dest.m32 = m02 * x + m12 * y + m22 * z + m32;
3179         dest.properties = properties & ~(PROPERTY_IDENTITY);
3180         return dest;
3181     }
3182 
3183     /**
3184      * Apply a translation to this matrix by translating by the given number of
3185      * units in x, y and z.
3186      * <p>
3187      * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation
3188      * matrix, then the new matrix will be <code>M * T</code>. So when
3189      * transforming a vector <code>v</code> with the new matrix by using
3190      * <code>M * T * v</code>, the translation will be applied first!
3191      * <p>
3192      * In order to set the matrix to a translation transformation without post-multiplying
3193      * it, use {@link #translation(double, double, double)}.
3194      * 
3195      * @see #translation(double, double, double)
3196      * 
3197      * @param x
3198      *          the offset to translate in x
3199      * @param y
3200      *          the offset to translate in y
3201      * @param z
3202      *          the offset to translate in z
3203      * @return this
3204      */
3205     ref public Matrix4x3d translate(double x, double y, double z) return {
3206         if ((properties & PROPERTY_IDENTITY) != 0)
3207             return translation(x, y, z);
3208         Matrix4x3d c = this;
3209         c.m30 = c.m00 * x + c.m10 * y + c.m20 * z + c.m30;
3210         c.m31 = c.m01 * x + c.m11 * y + c.m21 * z + c.m31;
3211         c.m32 = c.m02 * x + c.m12 * y + c.m22 * z + c.m32;
3212         c.properties &= ~(PROPERTY_IDENTITY);
3213         return this;
3214     }
3215 
3216 
3217     /**
3218      * Pre-multiply a translation to this matrix by translating by the given number of
3219      * units in x, y and z.
3220      * <p>
3221      * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation
3222      * matrix, then the new matrix will be <code>T * M</code>. So when
3223      * transforming a vector <code>v</code> with the new matrix by using
3224      * <code>T * M * v</code>, the translation will be applied last!
3225      * <p>
3226      * In order to set the matrix to a translation transformation without pre-multiplying
3227      * it, use {@link #translation(Vector3d)}.
3228      * 
3229      * @see #translation(Vector3d)
3230      * 
3231      * @param offset
3232      *          the number of units in x, y and z by which to translate
3233      * @return this
3234      */
3235     ref public Matrix4x3d translateLocal(Vector3d offset) return {
3236         return translateLocal(offset.x, offset.y, offset.z);
3237     }
3238 
3239     /**
3240      * Pre-multiply a translation to this matrix by translating by the given number of
3241      * units in x, y and z and store the result in <code>dest</code>.
3242      * <p>
3243      * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation
3244      * matrix, then the new matrix will be <code>T * M</code>. So when
3245      * transforming a vector <code>v</code> with the new matrix by using
3246      * <code>T * M * v</code>, the translation will be applied last!
3247      * <p>
3248      * In order to set the matrix to a translation transformation without pre-multiplying
3249      * it, use {@link #translation(Vector3d)}.
3250      * 
3251      * @see #translation(Vector3d)
3252      * 
3253      * @param offset
3254      *          the number of units in x, y and z by which to translate
3255      * @param dest
3256      *          will hold the result
3257      * @return dest
3258      */
3259     public Matrix4x3d translateLocal(Vector3d offset, ref Matrix4x3d dest) {
3260         return translateLocal(offset.x, offset.y, offset.z, dest);
3261     }
3262 
3263     /**
3264      * Pre-multiply a translation to this matrix by translating by the given number of
3265      * units in x, y and z and store the result in <code>dest</code>.
3266      * <p>
3267      * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation
3268      * matrix, then the new matrix will be <code>T * M</code>. So when
3269      * transforming a vector <code>v</code> with the new matrix by using
3270      * <code>T * M * v</code>, the translation will be applied last!
3271      * <p>
3272      * In order to set the matrix to a translation transformation without pre-multiplying
3273      * it, use {@link #translation(double, double, double)}.
3274      * 
3275      * @see #translation(double, double, double)
3276      * 
3277      * @param x
3278      *          the offset to translate in x
3279      * @param y
3280      *          the offset to translate in y
3281      * @param z
3282      *          the offset to translate in z
3283      * @param dest
3284      *          will hold the result
3285      * @return dest
3286      */
3287     public Matrix4x3d translateLocal(double x, double y, double z, ref Matrix4x3d dest) {
3288         dest.m00 = m00;
3289         dest.m01 = m01;
3290         dest.m02 = m02;
3291         dest.m10 = m10;
3292         dest.m11 = m11;
3293         dest.m12 = m12;
3294         dest.m20 = m20;
3295         dest.m21 = m21;
3296         dest.m22 = m22;
3297         dest.m30 = m30 + x;
3298         dest.m31 = m31 + y;
3299         dest.m32 = m32 + z;
3300         dest.properties = properties & ~(PROPERTY_IDENTITY);
3301         return dest;
3302     }
3303 
3304     /**
3305      * Pre-multiply a translation to this matrix by translating by the given number of
3306      * units in x, y and z.
3307      * <p>
3308      * If <code>M</code> is <code>this</code> matrix and <code>T</code> the translation
3309      * matrix, then the new matrix will be <code>T * M</code>. So when
3310      * transforming a vector <code>v</code> with the new matrix by using
3311      * <code>T * M * v</code>, the translation will be applied last!
3312      * <p>
3313      * In order to set the matrix to a translation transformation without pre-multiplying
3314      * it, use {@link #translation(double, double, double)}.
3315      * 
3316      * @see #translation(double, double, double)
3317      * 
3318      * @param x
3319      *          the offset to translate in x
3320      * @param y
3321      *          the offset to translate in y
3322      * @param z
3323      *          the offset to translate in z
3324      * @return this
3325      */
3326     ref public Matrix4x3d translateLocal(double x, double y, double z) return {
3327         translateLocal(x, y, z, this);
3328         return this;
3329     }
3330 
3331     public Matrix4x3d rotateX(double ang, ref Matrix4x3d dest) {
3332         if ((properties & PROPERTY_IDENTITY) != 0)
3333             return dest.rotationX(ang);
3334         else if ((properties & PROPERTY_TRANSLATION) != 0) {
3335             double x = m30, y = m31, z = m32;
3336             return dest.rotationX(ang).setTranslation(x, y, z);
3337         }
3338         return rotateXInternal(ang, dest);
3339     }
3340     private Matrix4x3d rotateXInternal(double ang, ref Matrix4x3d dest) {
3341         double sin, cos;
3342         sin = Math.sin(ang);
3343         cos = Math.cosFromSin(sin, ang);
3344         double rm11 = cos;
3345         double rm12 = sin;
3346         double rm21 = -sin;
3347         double rm22 = cos;
3348 
3349         // add temporaries for dependent values
3350         double nm10 = m10 * rm11 + m20 * rm12;
3351         double nm11 = m11 * rm11 + m21 * rm12;
3352         double nm12 = m12 * rm11 + m22 * rm12;
3353         // set non-dependent values directly
3354         dest.m20 = m10 * rm21 + m20 * rm22;
3355         dest.m21 = m11 * rm21 + m21 * rm22;
3356         dest.m22 = m12 * rm21 + m22 * rm22;
3357         // set other values
3358         dest.m10 = nm10;
3359         dest.m11 = nm11;
3360         dest.m12 = nm12;
3361         dest.m00 = m00;
3362         dest.m01 = m01;
3363         dest.m02 = m02;
3364         dest.m30 = m30;
3365         dest.m31 = m31;
3366         dest.m32 = m32;
3367         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
3368         return dest;
3369     }
3370 
3371     /**
3372      * Apply rotation about the X axis to this matrix by rotating the given amount of radians.
3373      * <p>
3374      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
3375      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
3376      * When used with a left-handed coordinate system, the rotation is clockwise.
3377      * <p>
3378      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
3379      * then the new matrix will be <code>M * R</code>. So when transforming a
3380      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
3381      * rotation will be applied first!
3382      * <p>
3383      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">http://en.wikipedia.org</a>
3384      * 
3385      * @param ang
3386      *            the angle in radians
3387      * @return this
3388      */
3389     ref public Matrix4x3d rotateX(double ang) return {
3390         rotateX(ang, this);
3391         return this;
3392     }
3393 
3394     public Matrix4x3d rotateY(double ang, ref Matrix4x3d dest) {
3395         if ((properties & PROPERTY_IDENTITY) != 0)
3396             return dest.rotationY(ang);
3397         else if ((properties & PROPERTY_TRANSLATION) != 0) {
3398             double x = m30, y = m31, z = m32;
3399             return dest.rotationY(ang).setTranslation(x, y, z);
3400         }
3401         return rotateYInternal(ang, dest);
3402     }
3403     private Matrix4x3d rotateYInternal(double ang, ref Matrix4x3d dest) {
3404         double sin, cos;
3405         sin = Math.sin(ang);
3406         cos = Math.cosFromSin(sin, ang);
3407         double rm00 = cos;
3408         double rm02 = -sin;
3409         double rm20 = sin;
3410         double rm22 = cos;
3411 
3412         // add temporaries for dependent values
3413         double nm00 = m00 * rm00 + m20 * rm02;
3414         double nm01 = m01 * rm00 + m21 * rm02;
3415         double nm02 = m02 * rm00 + m22 * rm02;
3416         // set non-dependent values directly
3417         dest.m20 = m00 * rm20 + m20 * rm22;
3418         dest.m21 = m01 * rm20 + m21 * rm22;
3419         dest.m22 = m02 * rm20 + m22 * rm22;
3420         // set other values
3421         dest.m00 = nm00;
3422         dest.m01 = nm01;
3423         dest.m02 = nm02;
3424         dest.m10 = m10;
3425         dest.m11 = m11;
3426         dest.m12 = m12;
3427         dest.m30 = m30;
3428         dest.m31 = m31;
3429         dest.m32 = m32;
3430         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
3431         return dest;
3432     }
3433 
3434     /**
3435      * Apply rotation about the Y axis to this matrix by rotating the given amount of radians.
3436      * <p>
3437      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
3438      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
3439      * When used with a left-handed coordinate system, the rotation is clockwise.
3440      * <p>
3441      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
3442      * then the new matrix will be <code>M * R</code>. So when transforming a
3443      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
3444      * rotation will be applied first!
3445      * <p>
3446      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">http://en.wikipedia.org</a>
3447      * 
3448      * @param ang
3449      *            the angle in radians
3450      * @return this
3451      */
3452     ref public Matrix4x3d rotateY(double ang) return {
3453         rotateY(ang, this);
3454         return this;
3455     }
3456 
3457     public Matrix4x3d rotateZ(double ang, ref Matrix4x3d dest) {
3458         if ((properties & PROPERTY_IDENTITY) != 0)
3459             return dest.rotationZ(ang);
3460         else if ((properties & PROPERTY_TRANSLATION) != 0) {
3461             double x = m30, y = m31, z = m32;
3462             return dest.rotationZ(ang).setTranslation(x, y, z);
3463         }
3464         return rotateZInternal(ang, dest);
3465     }
3466     private Matrix4x3d rotateZInternal(double ang, ref Matrix4x3d dest) {
3467         double sin, cos;
3468         sin = Math.sin(ang);
3469         cos = Math.cosFromSin(sin, ang);
3470         double rm00 = cos;
3471         double rm01 = sin;
3472         double rm10 = -sin;
3473         double rm11 = cos;
3474 
3475         // add temporaries for dependent values
3476         double nm00 = m00 * rm00 + m10 * rm01;
3477         double nm01 = m01 * rm00 + m11 * rm01;
3478         double nm02 = m02 * rm00 + m12 * rm01;
3479         // set non-dependent values directly
3480         dest.m10 = m00 * rm10 + m10 * rm11;
3481         dest.m11 = m01 * rm10 + m11 * rm11;
3482         dest.m12 = m02 * rm10 + m12 * rm11;
3483         // set other values
3484         dest.m00 = nm00;
3485         dest.m01 = nm01;
3486         dest.m02 = nm02;
3487         dest.m20 = m20;
3488         dest.m21 = m21;
3489         dest.m22 = m22;
3490         dest.m30 = m30;
3491         dest.m31 = m31;
3492         dest.m32 = m32;
3493         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
3494         return dest;
3495     }
3496 
3497     /**
3498      * Apply rotation about the Z axis to this matrix by rotating the given amount of radians.
3499      * <p>
3500      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
3501      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
3502      * When used with a left-handed coordinate system, the rotation is clockwise.
3503      * <p>
3504      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
3505      * then the new matrix will be <code>M * R</code>. So when transforming a
3506      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
3507      * rotation will be applied first!
3508      * <p>
3509      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">http://en.wikipedia.org</a>
3510      * 
3511      * @param ang
3512      *            the angle in radians
3513      * @return this
3514      */
3515     ref public Matrix4x3d rotateZ(double ang) return {
3516         rotateZ(ang, this);
3517         return this;
3518     }
3519 
3520     /**
3521      * 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
3522      * followed by a rotation of <code>angles.z</code> radians about the Z axis.
3523      * <p>
3524      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
3525      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
3526      * When used with a left-handed coordinate system, the rotation is clockwise.
3527      * <p>
3528      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
3529      * then the new matrix will be <code>M * R</code>. So when transforming a
3530      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
3531      * rotation will be applied first!
3532      * <p>
3533      * This method is equivalent to calling: <code>rotateX(angles.x).rotateY(angles.y).rotateZ(angles.z)</code>
3534      * 
3535      * @param angles
3536      *            the Euler angles
3537      * @return this
3538      */
3539     ref public Matrix4x3d rotateXYZ(Vector3d angles) return {
3540         return rotateXYZ(angles.x, angles.y, angles.z);
3541     }
3542 
3543     /**
3544      * 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
3545      * followed by a rotation of <code>angleZ</code> radians about the Z axis.
3546      * <p>
3547      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
3548      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
3549      * When used with a left-handed coordinate system, the rotation is clockwise.
3550      * <p>
3551      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
3552      * then the new matrix will be <code>M * R</code>. So when transforming a
3553      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
3554      * rotation will be applied first!
3555      * <p>
3556      * This method is equivalent to calling: <code>rotateX(angleX).rotateY(angleY).rotateZ(angleZ)</code>
3557      * 
3558      * @param angleX
3559      *            the angle to rotate about X
3560      * @param angleY
3561      *            the angle to rotate about Y
3562      * @param angleZ
3563      *            the angle to rotate about Z
3564      * @return this
3565      */
3566     ref public Matrix4x3d rotateXYZ(double angleX, double angleY, double angleZ) return {
3567         rotateXYZ(angleX, angleY, angleZ, this);
3568         return this;
3569     }
3570 
3571     public Matrix4x3d rotateXYZ(double angleX, double angleY, double angleZ, ref Matrix4x3d dest) {
3572         if ((properties & PROPERTY_IDENTITY) != 0)
3573             return dest.rotationXYZ(angleX, angleY, angleZ);
3574         else if ((properties & PROPERTY_TRANSLATION) != 0) {
3575             double tx = m30, ty = m31, tz = m32;
3576             return dest.rotationXYZ(angleX, angleY, angleZ).setTranslation(tx, ty, tz);
3577         }
3578         return rotateXYZInternal(angleX, angleY, angleZ, dest);
3579     }
3580     private Matrix4x3d rotateXYZInternal(double angleX, double angleY, double angleZ, ref Matrix4x3d dest) {
3581         double sinX = Math.sin(angleX);
3582         double cosX = Math.cosFromSin(sinX, angleX);
3583         double sinY = Math.sin(angleY);
3584         double cosY = Math.cosFromSin(sinY, angleY);
3585         double sinZ = Math.sin(angleZ);
3586         double cosZ = Math.cosFromSin(sinZ, angleZ);
3587         double m_sinX = -sinX;
3588         double m_sinY = -sinY;
3589         double m_sinZ = -sinZ;
3590 
3591         // rotateX
3592         double nm10 = m10 * cosX + m20 * sinX;
3593         double nm11 = m11 * cosX + m21 * sinX;
3594         double nm12 = m12 * cosX + m22 * sinX;
3595         double nm20 = m10 * m_sinX + m20 * cosX;
3596         double nm21 = m11 * m_sinX + m21 * cosX;
3597         double nm22 = m12 * m_sinX + m22 * cosX;
3598         // rotateY
3599         double nm00 = m00 * cosY + nm20 * m_sinY;
3600         double nm01 = m01 * cosY + nm21 * m_sinY;
3601         double nm02 = m02 * cosY + nm22 * m_sinY;
3602         dest.m20 = m00 * sinY + nm20 * cosY;
3603         dest.m21 = m01 * sinY + nm21 * cosY;
3604         dest.m22 = m02 * sinY + nm22 * cosY;
3605         // rotateZ
3606         dest.m00 = nm00 * cosZ + nm10 * sinZ;
3607         dest.m01 = nm01 * cosZ + nm11 * sinZ;
3608         dest.m02 = nm02 * cosZ + nm12 * sinZ;
3609         dest.m10 = nm00 * m_sinZ + nm10 * cosZ;
3610         dest.m11 = nm01 * m_sinZ + nm11 * cosZ;
3611         dest.m12 = nm02 * m_sinZ + nm12 * cosZ;
3612         // copy last column from 'this'
3613         dest.m30 = m30;
3614         dest.m31 = m31;
3615         dest.m32 = m32;
3616         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
3617         return dest;
3618     }
3619 
3620     /**
3621      * 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
3622      * followed by a rotation of <code>angles.x</code> radians about the X axis.
3623      * <p>
3624      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
3625      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
3626      * When used with a left-handed coordinate system, the rotation is clockwise.
3627      * <p>
3628      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
3629      * then the new matrix will be <code>M * R</code>. So when transforming a
3630      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
3631      * rotation will be applied first!
3632      * <p>
3633      * This method is equivalent to calling: <code>rotateZ(angles.z).rotateY(angles.y).rotateX(angles.x)</code>
3634      * 
3635      * @param angles
3636      *            the Euler angles
3637      * @return this
3638      */
3639     ref public Matrix4x3d rotateZYX(Vector3d angles) return {
3640         return rotateZYX(angles.z, angles.y, angles.x);
3641     }
3642 
3643     /**
3644      * 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
3645      * followed by a rotation of <code>angleX</code> radians about the X axis.
3646      * <p>
3647      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
3648      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
3649      * When used with a left-handed coordinate system, the rotation is clockwise.
3650      * <p>
3651      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
3652      * then the new matrix will be <code>M * R</code>. So when transforming a
3653      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
3654      * rotation will be applied first!
3655      * <p>
3656      * This method is equivalent to calling: <code>rotateZ(angleZ).rotateY(angleY).rotateX(angleX)</code>
3657      * 
3658      * @param angleZ
3659      *            the angle to rotate about Z
3660      * @param angleY
3661      *            the angle to rotate about Y
3662      * @param angleX
3663      *            the angle to rotate about X
3664      * @return this
3665      */
3666     ref public Matrix4x3d rotateZYX(double angleZ, double angleY, double angleX) return {
3667         rotateZYX(angleZ, angleY, angleX, this);
3668         return this;
3669     }
3670 
3671     public Matrix4x3d rotateZYX(double angleZ, double angleY, double angleX, ref Matrix4x3d dest) {
3672         if ((properties & PROPERTY_IDENTITY) != 0)
3673             return dest.rotationZYX(angleZ, angleY, angleX);
3674         else if ((properties & PROPERTY_TRANSLATION) != 0) {
3675             double tx = m30, ty = m31, tz = m32;
3676             return dest.rotationZYX(angleZ, angleY, angleX).setTranslation(tx, ty, tz);
3677         }
3678         return rotateZYXInternal(angleZ, angleY, angleX, dest);
3679     }
3680     private Matrix4x3d rotateZYXInternal(double angleZ, double angleY, double angleX, ref Matrix4x3d dest) {
3681         double sinX = Math.sin(angleX);
3682         double cosX = Math.cosFromSin(sinX, angleX);
3683         double sinY = Math.sin(angleY);
3684         double cosY = Math.cosFromSin(sinY, angleY);
3685         double sinZ = Math.sin(angleZ);
3686         double cosZ = Math.cosFromSin(sinZ, angleZ);
3687         double m_sinZ = -sinZ;
3688         double m_sinY = -sinY;
3689         double m_sinX = -sinX;
3690 
3691         // rotateZ
3692         double nm00 = m00 * cosZ + m10 * sinZ;
3693         double nm01 = m01 * cosZ + m11 * sinZ;
3694         double nm02 = m02 * cosZ + m12 * sinZ;
3695         double nm10 = m00 * m_sinZ + m10 * cosZ;
3696         double nm11 = m01 * m_sinZ + m11 * cosZ;
3697         double nm12 = m02 * m_sinZ + m12 * cosZ;
3698         // rotateY
3699         double nm20 = nm00 * sinY + m20 * cosY;
3700         double nm21 = nm01 * sinY + m21 * cosY;
3701         double nm22 = nm02 * sinY + m22 * cosY;
3702         dest.m00 = nm00 * cosY + m20 * m_sinY;
3703         dest.m01 = nm01 * cosY + m21 * m_sinY;
3704         dest.m02 = nm02 * cosY + m22 * m_sinY;
3705         // rotateX
3706         dest.m10 = nm10 * cosX + nm20 * sinX;
3707         dest.m11 = nm11 * cosX + nm21 * sinX;
3708         dest.m12 = nm12 * cosX + nm22 * sinX;
3709         dest.m20 = nm10 * m_sinX + nm20 * cosX;
3710         dest.m21 = nm11 * m_sinX + nm21 * cosX;
3711         dest.m22 = nm12 * m_sinX + nm22 * cosX;
3712         // copy last column from 'this'
3713         dest.m30 = m30;
3714         dest.m31 = m31;
3715         dest.m32 = m32;
3716         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
3717         return dest;
3718     }
3719 
3720     /**
3721      * 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
3722      * followed by a rotation of <code>angles.z</code> radians about the Z axis.
3723      * <p>
3724      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
3725      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
3726      * When used with a left-handed coordinate system, the rotation is clockwise.
3727      * <p>
3728      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
3729      * then the new matrix will be <code>M * R</code>. So when transforming a
3730      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
3731      * rotation will be applied first!
3732      * <p>
3733      * This method is equivalent to calling: <code>rotateY(angles.y).rotateX(angles.x).rotateZ(angles.z)</code>
3734      * 
3735      * @param angles
3736      *            the Euler angles
3737      * @return this
3738      */
3739     ref public Matrix4x3d rotateYXZ(Vector3d angles) return {
3740         return rotateYXZ(angles.y, angles.x, angles.z);
3741     }
3742 
3743     /**
3744      * 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
3745      * followed by a rotation of <code>angleZ</code> radians about the Z axis.
3746      * <p>
3747      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
3748      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
3749      * When used with a left-handed coordinate system, the rotation is clockwise.
3750      * <p>
3751      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix,
3752      * then the new matrix will be <code>M * R</code>. So when transforming a
3753      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
3754      * rotation will be applied first!
3755      * <p>
3756      * This method is equivalent to calling: <code>rotateY(angleY).rotateX(angleX).rotateZ(angleZ)</code>
3757      * 
3758      * @param angleY
3759      *            the angle to rotate about Y
3760      * @param angleX
3761      *            the angle to rotate about X
3762      * @param angleZ
3763      *            the angle to rotate about Z
3764      * @return this
3765      */
3766     ref public Matrix4x3d rotateYXZ(double angleY, double angleX, double angleZ) return {
3767         rotateYXZ(angleY, angleX, angleZ, this);
3768         return this;
3769     }
3770 
3771     public Matrix4x3d rotateYXZ(double angleY, double angleX, double angleZ, ref Matrix4x3d dest) {
3772         if ((properties & PROPERTY_IDENTITY) != 0)
3773             return dest.rotationYXZ(angleY, angleX, angleZ);
3774         else if ((properties & PROPERTY_TRANSLATION) != 0) {
3775             double tx = m30, ty = m31, tz = m32;
3776             return dest.rotationYXZ(angleY, angleX, angleZ).setTranslation(tx, ty, tz);
3777         }
3778         return rotateYXZInternal(angleY, angleX, angleZ, dest);
3779     }
3780     private Matrix4x3d rotateYXZInternal(double angleY, double angleX, double angleZ, ref Matrix4x3d dest) {
3781         double sinX = Math.sin(angleX);
3782         double cosX = Math.cosFromSin(sinX, angleX);
3783         double sinY = Math.sin(angleY);
3784         double cosY = Math.cosFromSin(sinY, angleY);
3785         double sinZ = Math.sin(angleZ);
3786         double cosZ = Math.cosFromSin(sinZ, angleZ);
3787         double m_sinY = -sinY;
3788         double m_sinX = -sinX;
3789         double m_sinZ = -sinZ;
3790 
3791         // rotateY
3792         double nm20 = m00 * sinY + m20 * cosY;
3793         double nm21 = m01 * sinY + m21 * cosY;
3794         double nm22 = m02 * sinY + m22 * cosY;
3795         double nm00 = m00 * cosY + m20 * m_sinY;
3796         double nm01 = m01 * cosY + m21 * m_sinY;
3797         double nm02 = m02 * cosY + m22 * m_sinY;
3798         // rotateX
3799         double nm10 = m10 * cosX + nm20 * sinX;
3800         double nm11 = m11 * cosX + nm21 * sinX;
3801         double nm12 = m12 * cosX + nm22 * sinX;
3802         dest.m20 = m10 * m_sinX + nm20 * cosX;
3803         dest.m21 = m11 * m_sinX + nm21 * cosX;
3804         dest.m22 = m12 * m_sinX + nm22 * cosX;
3805         // rotateZ
3806         dest.m00 = nm00 * cosZ + nm10 * sinZ;
3807         dest.m01 = nm01 * cosZ + nm11 * sinZ;
3808         dest.m02 = nm02 * cosZ + nm12 * sinZ;
3809         dest.m10 = nm00 * m_sinZ + nm10 * cosZ;
3810         dest.m11 = nm01 * m_sinZ + nm11 * cosZ;
3811         dest.m12 = nm02 * m_sinZ + nm12 * cosZ;
3812         // copy last column from 'this'
3813         dest.m30 = m30;
3814         dest.m31 = m31;
3815         dest.m32 = m32;
3816         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
3817         return dest;
3818     }
3819 
3820 
3821     /**
3822      * Set this matrix to a rotation transformation using the given {@link AxisAngle4d}.
3823      * <p>
3824      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
3825      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
3826      * When used with a left-handed coordinate system, the rotation is clockwise.
3827      * <p>
3828      * The resulting matrix can be multiplied against another transformation
3829      * matrix to obtain an additional rotation.
3830      * <p>
3831      * In order to apply the rotation transformation to an existing transformation,
3832      * use {@link #rotate(AxisAngle4d) rotate()} instead.
3833      * <p>
3834      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Axis_and_angle">http://en.wikipedia.org</a>
3835      *
3836      * @see #rotate(AxisAngle4d)
3837      * 
3838      * @param angleAxis
3839      *          the {@link AxisAngle4d} (needs to be {@link AxisAngle4d#normalize() normalized})
3840      * @return this
3841      */
3842     ref public Matrix4x3d rotation(AxisAngle4d angleAxis) return {
3843         return rotation(angleAxis.angle, angleAxis.x, angleAxis.y, angleAxis.z);
3844     }
3845 
3846     /**
3847      * Set this matrix to the rotation - and possibly scaling - transformation of the given {@link Quaterniond}.
3848      * <p>
3849      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
3850      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
3851      * When used with a left-handed coordinate system, the rotation is clockwise.
3852      * <p>
3853      * The resulting matrix can be multiplied against another transformation
3854      * matrix to obtain an additional rotation.
3855      * <p>
3856      * In order to apply the rotation transformation to an existing transformation,
3857      * use {@link #rotate(Quaterniond) rotate()} instead.
3858      * <p>
3859      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a>
3860      * 
3861      * @see #rotate(Quaterniond)
3862      * 
3863      * @param quat
3864      *          the {@link Quaterniond}
3865      * @return this
3866      */
3867     ref public Matrix4x3d rotation(Quaterniond quat) return {
3868         double w2 = quat.w * quat.w;
3869         double x2 = quat.x * quat.x;
3870         double y2 = quat.y * quat.y;
3871         double z2 = quat.z * quat.z;
3872         double zw = quat.z * quat.w, dzw = zw + zw;
3873         double xy = quat.x * quat.y, dxy = xy + xy;
3874         double xz = quat.x * quat.z, dxz = xz + xz;
3875         double yw = quat.y * quat.w, dyw = yw + yw;
3876         double yz = quat.y * quat.z, dyz = yz + yz;
3877         double xw = quat.x * quat.w, dxw = xw + xw;
3878         _m00(w2 + x2 - z2 - y2);
3879         _m01(dxy + dzw);
3880         _m02(dxz - dyw);
3881         _m10(dxy - dzw);
3882         _m11(y2 - z2 + w2 - x2);
3883         _m12(dyz + dxw);
3884         _m20(dyw + dxz);
3885         _m21(dyz - dxw);
3886         _m22(z2 - y2 - x2 + w2);
3887         _m30(0.0);
3888         _m31(0.0);
3889         _m32(0.0);
3890         properties = PROPERTY_ORTHONORMAL;
3891         return this;
3892     }
3893 
3894 
3895     /**
3896      * 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>,
3897      * <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
3898      * which scales the three axes x, y and z by <code>(sx, sy, sz)</code>.
3899      * <p>
3900      * When transforming a vector by the resulting matrix the scaling transformation will be applied first, then the rotation and
3901      * at last the translation.
3902      * <p>
3903      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
3904      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
3905      * When used with a left-handed coordinate system, the rotation is clockwise.
3906      * <p>
3907      * This method is equivalent to calling: <code>translation(tx, ty, tz).rotate(quat).scale(sx, sy, sz)</code>
3908      * 
3909      * @see #translation(double, double, double)
3910      * @see #rotate(Quaterniond)
3911      * @see #scale(double, double, double)
3912      * 
3913      * @param tx
3914      *          the number of units by which to translate the x-component
3915      * @param ty
3916      *          the number of units by which to translate the y-component
3917      * @param tz
3918      *          the number of units by which to translate the z-component
3919      * @param qx
3920      *          the x-coordinate of the vector part of the quaternion
3921      * @param qy
3922      *          the y-coordinate of the vector part of the quaternion
3923      * @param qz
3924      *          the z-coordinate of the vector part of the quaternion
3925      * @param qw
3926      *          the scalar part of the quaternion
3927      * @param sx
3928      *          the scaling factor for the x-axis
3929      * @param sy
3930      *          the scaling factor for the y-axis
3931      * @param sz
3932      *          the scaling factor for the z-axis
3933      * @return this
3934      */
3935     ref public Matrix4x3d translationRotateScale(double tx, double ty, double tz, 
3936                                            double qx, double qy, double qz, double qw, 
3937                                            double sx, double sy, double sz) return {
3938         double dqx = qx + qx, dqy = qy + qy, dqz = qz + qz;
3939         double q00 = dqx * qx;
3940         double q11 = dqy * qy;
3941         double q22 = dqz * qz;
3942         double q01 = dqx * qy;
3943         double q02 = dqx * qz;
3944         double q03 = dqx * qw;
3945         double q12 = dqy * qz;
3946         double q13 = dqy * qw;
3947         double q23 = dqz * qw;
3948         m00 = sx - (q11 + q22) * sx;
3949         m01 = (q01 + q23) * sx;
3950         m02 = (q02 - q13) * sx;
3951         m10 = (q01 - q23) * sy;
3952         m11 = sy - (q22 + q00) * sy;
3953         m12 = (q12 + q03) * sy;
3954         m20 = (q02 + q13) * sz;
3955         m21 = (q12 - q03) * sz;
3956         m22 = sz - (q11 + q00) * sz;
3957         m30 = tx;
3958         m31 = ty;
3959         m32 = tz;
3960         properties = 0;
3961         return this;
3962     }
3963 
3964     /**
3965      * Set <code>this</code> matrix to <code>T * R * S</code>, where <code>T</code> is the given <code>translation</code>,
3966      * <code>R</code> is a rotation transformation specified by the given quaternion, and <code>S</code> is a scaling transformation
3967      * which scales the axes by <code>scale</code>.
3968      * <p>
3969      * When transforming a vector by the resulting matrix the scaling transformation will be applied first, then the rotation and
3970      * at last the translation.
3971      * <p>
3972      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
3973      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
3974      * When used with a left-handed coordinate system, the rotation is clockwise.
3975      * <p>
3976      * This method is equivalent to calling: <code>translation(translation).rotate(quat).scale(scale)</code>
3977      * 
3978      * @see #translation(Vector3d)
3979      * @see #rotate(Quaterniond)
3980      * 
3981      * @param translation
3982      *          the translation
3983      * @param quat
3984      *          the quaternion representing a rotation
3985      * @param scale
3986      *          the scaling factors
3987      * @return this
3988      */
3989     ref public Matrix4x3d translationRotateScale(Vector3d translation, 
3990                                            Quaterniond quat, 
3991                                            Vector3d scale) return {
3992         return translationRotateScale(translation.x, translation.y, translation.z, quat.x, quat.y, quat.z, 
3993         quat.w, scale.x, scale.y, scale.z);
3994     }
3995 
3996     /**
3997      * 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>,
3998      * <code>R</code> is a rotation transformation specified by the quaternion <code>(qx, qy, qz, qw)</code>, <code>S</code> is a scaling transformation
3999      * which scales the three axes x, y and z by <code>(sx, sy, sz)</code>.
4000      * <p>
4001      * 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
4002      * at last the translation.
4003      * <p>
4004      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
4005      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
4006      * When used with a left-handed coordinate system, the rotation is clockwise.
4007      * <p>
4008      * This method is equivalent to calling: <code>translation(tx, ty, tz).rotate(quat).scale(sx, sy, sz).mul(m)</code>
4009      * 
4010      * @see #translation(double, double, double)
4011      * @see #rotate(Quaterniond)
4012      * @see #scale(double, double, double)
4013      * @see #mul(Matrix4x3d)
4014      * 
4015      * @param tx
4016      *          the number of units by which to translate the x-component
4017      * @param ty
4018      *          the number of units by which to translate the y-component
4019      * @param tz
4020      *          the number of units by which to translate the z-component
4021      * @param qx
4022      *          the x-coordinate of the vector part of the quaternion
4023      * @param qy
4024      *          the y-coordinate of the vector part of the quaternion
4025      * @param qz
4026      *          the z-coordinate of the vector part of the quaternion
4027      * @param qw
4028      *          the scalar part of the quaternion
4029      * @param sx
4030      *          the scaling factor for the x-axis
4031      * @param sy
4032      *          the scaling factor for the y-axis
4033      * @param sz
4034      *          the scaling factor for the z-axis
4035      * @param m
4036      *          the matrix to multiply by
4037      * @return this
4038      */
4039     ref public Matrix4x3d translationRotateScaleMul(
4040             double tx, double ty, double tz, 
4041             double qx, double qy, double qz, double qw, 
4042             double sx, double sy, double sz,
4043             Matrix4x3d m) return {
4044         double dqx = qx + qx;
4045         double dqy = qy + qy;
4046         double dqz = qz + qz;
4047         double q00 = dqx * qx;
4048         double q11 = dqy * qy;
4049         double q22 = dqz * qz;
4050         double q01 = dqx * qy;
4051         double q02 = dqx * qz;
4052         double q03 = dqx * qw;
4053         double q12 = dqy * qz;
4054         double q13 = dqy * qw;
4055         double q23 = dqz * qw;
4056         double nm00 = sx - (q11 + q22) * sx;
4057         double nm01 = (q01 + q23) * sx;
4058         double nm02 = (q02 - q13) * sx;
4059         double nm10 = (q01 - q23) * sy;
4060         double nm11 = sy - (q22 + q00) * sy;
4061         double nm12 = (q12 + q03) * sy;
4062         double nm20 = (q02 + q13) * sz;
4063         double nm21 = (q12 - q03) * sz;
4064         double nm22 = sz - (q11 + q00) * sz;
4065         double __m00 = nm00 * m.m00 + nm10 * m.m01 + nm20 * m.m02;
4066         double __m01 = nm01 * m.m00 + nm11 * m.m01 + nm21 * m.m02;
4067         m02 = nm02 * m.m00 + nm12 * m.m01 + nm22 * m.m02;
4068         this.m00 = __m00;
4069         this.m01 = __m01;
4070         double __m10 = nm00 * m.m10 + nm10 * m.m11 + nm20 * m.m12;
4071         double __m11 = nm01 * m.m10 + nm11 * m.m11 + nm21 * m.m12;
4072         m12 = nm02 * m.m10 + nm12 * m.m11 + nm22 * m.m12;
4073         this.m10 = __m10;
4074         this.m11 = __m11;
4075         double __m20 = nm00 * m.m20 + nm10 * m.m21 + nm20 * m.m22;
4076         double __m21 = nm01 * m.m20 + nm11 * m.m21 + nm21 * m.m22;
4077         m22 = nm02 * m.m20 + nm12 * m.m21 + nm22 * m.m22;
4078         this.m20 = __m20;
4079         this.m21 = __m21;
4080         double __m30 = nm00 * m.m30 + nm10 * m.m31 + nm20 * m.m32 + tx;
4081         double __m31 = nm01 * m.m30 + nm11 * m.m31 + nm21 * m.m32 + ty;
4082         m32 = nm02 * m.m30 + nm12 * m.m31 + nm22 * m.m32 + tz;
4083         this.m30 = __m30;
4084         this.m31 = __m31;
4085         properties = 0;
4086         return this;
4087     }
4088 
4089     /**
4090      * Set <code>this</code> matrix to <code>T * R * S * M</code>, where <code>T</code> is the given <code>translation</code>,
4091      * <code>R</code> is a rotation transformation specified by the given quaternion, <code>S</code> is a scaling transformation
4092      * which scales the axes by <code>scale</code>.
4093      * <p>
4094      * 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
4095      * at last the translation.
4096      * <p>
4097      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
4098      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
4099      * When used with a left-handed coordinate system, the rotation is clockwise.
4100      * <p>
4101      * This method is equivalent to calling: <code>translation(translation).rotate(quat).scale(scale).mul(m)</code>
4102      * 
4103      * @see #translation(Vector3d)
4104      * @see #rotate(Quaterniond)
4105      * @see #mul(Matrix4x3d)
4106      * 
4107      * @param translation
4108      *          the translation
4109      * @param quat
4110      *          the quaternion representing a rotation
4111      * @param scale
4112      *          the scaling factors
4113      * @param m
4114      *          the matrix to multiply by
4115      * @return this
4116      */
4117     ref public Matrix4x3d translationRotateScaleMul(Vector3d translation, Quaterniond quat, Vector3d scale, Matrix4x3d m) return {
4118         return translationRotateScaleMul(translation.x, translation.y, translation.z, quat.x, quat.y, quat.z
4119         , quat.w, scale.x, scale.y, scale.z, m);
4120     }
4121 
4122     /**
4123      * 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
4124      * <code>R</code> is a rotation transformation specified by the given quaternion.
4125      * <p>
4126      * When transforming a vector by the resulting matrix the rotation transformation will be applied first and then the translation.
4127      * <p>
4128      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
4129      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
4130      * When used with a left-handed coordinate system, the rotation is clockwise.
4131      * <p>
4132      * This method is equivalent to calling: <code>translation(tx, ty, tz).rotate(quat)</code>
4133      * 
4134      * @see #translation(double, double, double)
4135      * @see #rotate(Quaterniond)
4136      * 
4137      * @param tx
4138      *          the number of units by which to translate the x-component
4139      * @param ty
4140      *          the number of units by which to translate the y-component
4141      * @param tz
4142      *          the number of units by which to translate the z-component
4143      * @param quat
4144      *          the quaternion representing a rotation
4145      * @return this
4146      */
4147     ref public Matrix4x3d translationRotate(double tx, double ty, double tz, Quaterniond quat) return {
4148         double dqx = quat.x + quat.x, dqy = quat.y + quat.y, dqz = quat.z + quat.z;
4149         double q00 = dqx * quat.x;
4150         double q11 = dqy * quat.y;
4151         double q22 = dqz * quat.z;
4152         double q01 = dqx * quat.y;
4153         double q02 = dqx * quat.z;
4154         double q03 = dqx * quat.w;
4155         double q12 = dqy * quat.z;
4156         double q13 = dqy * quat.w;
4157         double q23 = dqz * quat.w;
4158         m00 = 1.0 - (q11 + q22);
4159         m01 = q01 + q23;
4160         m02 = q02 - q13;
4161         m10 = q01 - q23;
4162         m11 = 1.0 - (q22 + q00);
4163         m12 = q12 + q03;
4164         m20 = q02 + q13;
4165         m21 = q12 - q03;
4166         m22 = 1.0 - (q11 + q00);
4167         m30 = tx;
4168         m31 = ty;
4169         m32 = tz;
4170         properties = PROPERTY_ORTHONORMAL;
4171         return this;
4172     }
4173 
4174     /**
4175      * 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
4176      * <code>R</code> is a rotation - and possibly scaling - transformation specified by the quaternion <code>(qx, qy, qz, qw)</code>.
4177      * <p>
4178      * When transforming a vector by the resulting matrix the rotation - and possibly scaling - transformation will be applied first and then the translation.
4179      * <p>
4180      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
4181      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
4182      * When used with a left-handed coordinate system, the rotation is clockwise.
4183      * <p>
4184      * This method is equivalent to calling: <code>translation(tx, ty, tz).rotate(quat)</code>
4185      * 
4186      * @see #translation(double, double, double)
4187      * @see #rotate(Quaterniond)
4188      * 
4189      * @param tx
4190      *          the number of units by which to translate the x-component
4191      * @param ty
4192      *          the number of units by which to translate the y-component
4193      * @param tz
4194      *          the number of units by which to translate the z-component
4195      * @param qx
4196      *          the x-coordinate of the vector part of the quaternion
4197      * @param qy
4198      *          the y-coordinate of the vector part of the quaternion
4199      * @param qz
4200      *          the z-coordinate of the vector part of the quaternion
4201      * @param qw
4202      *          the scalar part of the quaternion
4203      * @return this
4204      */
4205     ref public Matrix4x3d translationRotate(double tx, double ty, double tz, double qx, double qy, double qz, double qw) return {
4206         double w2 = qw * qw;
4207         double x2 = qx * qx;
4208         double y2 = qy * qy;
4209         double z2 = qz * qz;
4210         double zw = qz * qw;
4211         double xy = qx * qy;
4212         double xz = qx * qz;
4213         double yw = qy * qw;
4214         double yz = qy * qz;
4215         double xw = qx * qw;
4216         this.m00 = w2 + x2 - z2 - y2;
4217         this.m01 = xy + zw + zw + xy;
4218         this.m02 = xz - yw + xz - yw;
4219         this.m10 = -zw + xy - zw + xy;
4220         this.m11 = y2 - z2 + w2 - x2;
4221         this.m12 = yz + yz + xw + xw;
4222         this.m20 = yw + xz + xz + yw;
4223         this.m21 = yz + yz - xw - xw;
4224         this.m22 = z2 - y2 - x2 + w2;
4225         this.m30 = tx;
4226         this.m31 = ty;
4227         this.m32 = tz;
4228         this.properties = PROPERTY_ORTHONORMAL;
4229         return this;
4230     }
4231 
4232     /**
4233      * Set <code>this</code> matrix to <code>T * R</code>, where <code>T</code> is the given <code>translation</code> and
4234      * <code>R</code> is a rotation transformation specified by the given quaternion.
4235      * <p>
4236      * When transforming a vector by the resulting matrix the scaling transformation will be applied first, then the rotation and
4237      * at last the translation.
4238      * <p>
4239      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
4240      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
4241      * When used with a left-handed coordinate system, the rotation is clockwise.
4242      * <p>
4243      * This method is equivalent to calling: <code>translation(translation).rotate(quat)</code>
4244      * 
4245      * @see #translation(Vector3d)
4246      * @see #rotate(Quaterniond)
4247      * 
4248      * @param translation
4249      *          the translation
4250      * @param quat
4251      *          the quaternion representing a rotation
4252      * @return this
4253      */
4254     ref public Matrix4x3d translationRotate(Vector3d translation, 
4255                                         Quaterniond quat) return {
4256         return translationRotate(translation.x, translation.y, translation.z, quat.x, quat.y, quat.z, quat.w);
4257     }
4258 
4259     /**
4260      * 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>,
4261      * <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>
4262      * <p>
4263      * 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
4264      * at last the translation.
4265      * <p>
4266      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
4267      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
4268      * When used with a left-handed coordinate system, the rotation is clockwise.
4269      * <p>
4270      * This method is equivalent to calling: <code>translation(tx, ty, tz).rotate(quat).mul(mat)</code>
4271      * 
4272      * @see #translation(double, double, double)
4273      * @see #rotate(Quaternionfc)
4274      * @see #mul(Matrix4x3d)
4275      * 
4276      * @param tx
4277      *          the number of units by which to translate the x-component
4278      * @param ty
4279      *          the number of units by which to translate the y-component
4280      * @param tz
4281      *          the number of units by which to translate the z-component
4282      * @param qx
4283      *          the x-coordinate of the vector part of the quaternion
4284      * @param qy
4285      *          the y-coordinate of the vector part of the quaternion
4286      * @param qz
4287      *          the z-coordinate of the vector part of the quaternion
4288      * @param qw
4289      *          the scalar part of the quaternion
4290      * @param mat
4291      *          the matrix to multiply with
4292      * @return this
4293      */
4294     ref public Matrix4x3d translationRotateMul(double tx, double ty, double tz, double qx, double qy, double qz, double qw, Matrix4x3d mat) return {
4295         double w2 = qw * qw;
4296         double x2 = qx * qx;
4297         double y2 = qy * qy;
4298         double z2 = qz * qz;
4299         double zw = qz * qw;
4300         double xy = qx * qy;
4301         double xz = qx * qz;
4302         double yw = qy * qw;
4303         double yz = qy * qz;
4304         double xw = qx * qw;
4305         double nm00 = w2 + x2 - z2 - y2;
4306         double nm01 = xy + zw + zw + xy;
4307         double nm02 = xz - yw + xz - yw;
4308         double nm10 = -zw + xy - zw + xy;
4309         double nm11 = y2 - z2 + w2 - x2;
4310         double nm12 = yz + yz + xw + xw;
4311         double nm20 = yw + xz + xz + yw;
4312         double nm21 = yz + yz - xw - xw;
4313         double nm22 = z2 - y2 - x2 + w2;
4314         m00 = nm00 * mat.m00 + nm10 * mat.m01 + nm20 * mat.m02;
4315         m01 = nm01 * mat.m00 + nm11 * mat.m01 + nm21 * mat.m02;
4316         m02 = nm02 * mat.m00 + nm12 * mat.m01 + nm22 * mat.m02;
4317         m10 = nm00 * mat.m10 + nm10 * mat.m11 + nm20 * mat.m12;
4318         m11 = nm01 * mat.m10 + nm11 * mat.m11 + nm21 * mat.m12;
4319         m12 = nm02 * mat.m10 + nm12 * mat.m11 + nm22 * mat.m12;
4320         m20 = nm00 * mat.m20 + nm10 * mat.m21 + nm20 * mat.m22;
4321         m21 = nm01 * mat.m20 + nm11 * mat.m21 + nm21 * mat.m22;
4322         m22 = nm02 * mat.m20 + nm12 * mat.m21 + nm22 * mat.m22;
4323         m30 = nm00 * mat.m30 + nm10 * mat.m31 + nm20 * mat.m32 + tx;
4324         m31 = nm01 * mat.m30 + nm11 * mat.m31 + nm21 * mat.m32 + ty;
4325         m32 = nm02 * mat.m30 + nm12 * mat.m31 + nm22 * mat.m32 + tz;
4326         this.properties = 0;
4327         return this;
4328     }
4329 
4330     /**
4331      * 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
4332      * <code>R</code> is a rotation transformation specified by the quaternion <code>(qx, qy, qz, qw)</code>.
4333      * <p>
4334      * This method is equivalent to calling: <code>translationRotate(...).invert()</code>
4335      * 
4336      * @see #translationRotate(double, double, double, double, double, double, double)
4337      * @see #invert()
4338      * 
4339      * @param tx
4340      *          the number of units by which to translate the x-component
4341      * @param ty
4342      *          the number of units by which to translate the y-component
4343      * @param tz
4344      *          the number of units by which to translate the z-component
4345      * @param qx
4346      *          the x-coordinate of the vector part of the quaternion
4347      * @param qy
4348      *          the y-coordinate of the vector part of the quaternion
4349      * @param qz
4350      *          the z-coordinate of the vector part of the quaternion
4351      * @param qw
4352      *          the scalar part of the quaternion
4353      * @return this
4354      */
4355     ref public Matrix4x3d translationRotateInvert(double tx, double ty, double tz, double qx, double qy, double qz, 
4356     double qw) return {
4357         double nqx = -qx, nqy = -qy, nqz = -qz;
4358         double dqx = nqx + nqx;
4359         double dqy = nqy + nqy;
4360         double dqz = nqz + nqz;
4361         double q00 = dqx * nqx;
4362         double q11 = dqy * nqy;
4363         double q22 = dqz * nqz;
4364         double q01 = dqx * nqy;
4365         double q02 = dqx * nqz;
4366         double q03 = dqx * qw;
4367         double q12 = dqy * nqz;
4368         double q13 = dqy * qw;
4369         double q23 = dqz * qw;
4370         return this
4371         ._m00(1.0 - q11 - q22)
4372         ._m01(q01 + q23)
4373         ._m02(q02 - q13)
4374         ._m10(q01 - q23)
4375         ._m11(1.0 - q22 - q00)
4376         ._m12(q12 + q03)
4377         ._m20(q02 + q13)
4378         ._m21(q12 - q03)
4379         ._m22(1.0 - q11 - q00)
4380         ._m30(-m00 * tx - m10 * ty - m20 * tz)
4381         ._m31(-m01 * tx - m11 * ty - m21 * tz)
4382         ._m32(-m02 * tx - m12 * ty - m22 * tz)
4383         ._properties(PROPERTY_ORTHONORMAL);
4384     }
4385 
4386     /**
4387      * Set <code>this</code> matrix to <code>(T * R)<sup>-1</sup></code>, where <code>T</code> is the given <code>translation</code> and
4388      * <code>R</code> is a rotation transformation specified by the given quaternion.
4389      * <p>
4390      * This method is equivalent to calling: <code>translationRotate(...).invert()</code>
4391      * 
4392      * @see #translationRotate(Vector3d, Quaterniond)
4393      * @see #invert()
4394      * 
4395      * @param translation
4396      *          the translation
4397      * @param quat
4398      *          the quaternion representing a rotation
4399      * @return this
4400      */
4401     ref public Matrix4x3d translationRotateInvert(Vector3d translation, 
4402                                               Quaterniond quat) return {
4403         return translationRotateInvert(translation.x, translation.y, translation.z, quat.x, quat.y, quat.z,
4404          quat.w);
4405     }
4406 
4407     /**
4408      * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniond} to this matrix and store
4409      * the result in <code>dest</code>.
4410      * <p>
4411      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
4412      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
4413      * When used with a left-handed coordinate system, the rotation is clockwise.
4414      * <p>
4415      * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion,
4416      * then the new matrix will be <code>M * Q</code>. So when transforming a
4417      * vector <code>v</code> with the new matrix by using <code>M * Q * v</code>,
4418      * the quaternion rotation will be applied first!
4419      * <p>
4420      * In order to set the matrix to a rotation transformation without post-multiplying,
4421      * use {@link #rotation(Quaterniond)}.
4422      * <p>
4423      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a>
4424      * 
4425      * @see #rotation(Quaterniond)
4426      * 
4427      * @param quat
4428      *          the {@link Quaterniond}
4429      * @param dest
4430      *          will hold the result
4431      * @return dest
4432      */
4433     public Matrix4x3d rotate(Quaterniond quat, ref Matrix4x3d dest) {
4434         if ((properties & PROPERTY_IDENTITY) != 0)
4435             return dest.rotation(quat);
4436         else if ((properties & PROPERTY_TRANSLATION) != 0)
4437             return rotateTranslation(quat, dest);
4438         return rotateGeneric(quat, dest);
4439     }
4440     private Matrix4x3d rotateGeneric(Quaterniond quat, ref Matrix4x3d dest) {
4441         double w2 = quat.w * quat.w, x2 = quat.x * quat.x;
4442         double y2 = quat.y * quat.y, z2 = quat.z * quat.z;
4443         double zw = quat.z * quat.w, dzw = zw + zw, xy = quat.x * quat.y, dxy = xy + xy;
4444         double xz = quat.x * quat.z, dxz = xz + xz, yw = quat.y * quat.w, dyw = yw + yw;
4445         double yz = quat.y * quat.z, dyz = yz + yz, xw = quat.x * quat.w, dxw = xw + xw;
4446         double rm00 = w2 + x2 - z2 - y2;
4447         double rm01 = dxy + dzw;
4448         double rm02 = dxz - dyw;
4449         double rm10 = dxy - dzw;
4450         double rm11 = y2 - z2 + w2 - x2;
4451         double rm12 = dyz + dxw;
4452         double rm20 = dyw + dxz;
4453         double rm21 = dyz - dxw;
4454         double rm22 = z2 - y2 - x2 + w2;
4455         double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
4456         double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
4457         double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
4458         double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
4459         double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
4460         double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
4461         dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
4462         dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
4463         dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
4464         dest.m00 = nm00;
4465         dest.m01 = nm01;
4466         dest.m02 = nm02;
4467         dest.m10 = nm10;
4468         dest.m11 = nm11;
4469         dest.m12 = nm12;
4470         dest.m30 = m30;
4471         dest.m31 = m31;
4472         dest.m32 = m32;
4473         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
4474         return dest;
4475     }
4476 
4477 
4478     /**
4479      * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniond} to this matrix.
4480      * <p>
4481      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
4482      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
4483      * When used with a left-handed coordinate system, the rotation is clockwise.
4484      * <p>
4485      * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion,
4486      * then the new matrix will be <code>M * Q</code>. So when transforming a
4487      * vector <code>v</code> with the new matrix by using <code>M * Q * v</code>,
4488      * the quaternion rotation will be applied first!
4489      * <p>
4490      * In order to set the matrix to a rotation transformation without post-multiplying,
4491      * use {@link #rotation(Quaterniond)}.
4492      * <p>
4493      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a>
4494      * 
4495      * @see #rotation(Quaterniond)
4496      * 
4497      * @param quat
4498      *          the {@link Quaterniond}
4499      * @return this
4500      */
4501     ref public Matrix4x3d rotate(Quaterniond quat) return {
4502         rotate(quat, this);
4503         return this;
4504     }
4505 
4506 
4507     /**
4508      * 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
4509      * the result in <code>dest</code>.
4510      * <p>
4511      * This method assumes <code>this</code> to only contain a translation.
4512      * <p>
4513      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
4514      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
4515      * When used with a left-handed coordinate system, the rotation is clockwise.
4516      * <p>
4517      * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion,
4518      * then the new matrix will be <code>M * Q</code>. So when transforming a
4519      * vector <code>v</code> with the new matrix by using <code>M * Q * v</code>,
4520      * the quaternion rotation will be applied first!
4521      * <p>
4522      * In order to set the matrix to a rotation transformation without post-multiplying,
4523      * use {@link #rotation(Quaterniond)}.
4524      * <p>
4525      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a>
4526      * 
4527      * @see #rotation(Quaterniond)
4528      * 
4529      * @param quat
4530      *          the {@link Quaterniond}
4531      * @param dest
4532      *          will hold the result
4533      * @return dest
4534      */
4535     public Matrix4x3d rotateTranslation(Quaterniond quat, ref Matrix4x3d dest) {
4536         double w2 = quat.w * quat.w, x2 = quat.x * quat.x;
4537         double y2 = quat.y * quat.y, z2 = quat.z * quat.z;
4538         double zw = quat.z * quat.w, dzw = zw + zw, xy = quat.x * quat.y, dxy = xy + xy;
4539         double xz = quat.x * quat.z, dxz = xz + xz, yw = quat.y * quat.w, dyw = yw + yw;
4540         double yz = quat.y * quat.z, dyz = yz + yz, xw = quat.x * quat.w, dxw = xw + xw;
4541         double rm00 = w2 + x2 - z2 - y2;
4542         double rm01 = dxy + dzw;
4543         double rm02 = dxz - dyw;
4544         double rm10 = dxy - dzw;
4545         double rm11 = y2 - z2 + w2 - x2;
4546         double rm12 = dyz + dxw;
4547         double rm20 = dyw + dxz;
4548         double rm21 = dyz - dxw;
4549         double rm22 = z2 - y2 - x2 + w2;
4550         dest.m20 = rm20;
4551         dest.m21 = rm21;
4552         dest.m22 = rm22;
4553         dest.m00 = rm00;
4554         dest.m01 = rm01;
4555         dest.m02 = rm02;
4556         dest.m10 = rm10;
4557         dest.m11 = rm11;
4558         dest.m12 = rm12;
4559         dest.m30 = m30;
4560         dest.m31 = m31;
4561         dest.m32 = m32;
4562         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
4563         return dest;
4564     }
4565 
4566 
4567     /**
4568      * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaterniond} to this matrix and store
4569      * the result in <code>dest</code>.
4570      * <p>
4571      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
4572      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
4573      * When used with a left-handed coordinate system, the rotation is clockwise.
4574      * <p>
4575      * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion,
4576      * then the new matrix will be <code>Q * M</code>. So when transforming a
4577      * vector <code>v</code> with the new matrix by using <code>Q * M * v</code>,
4578      * the quaternion rotation will be applied last!
4579      * <p>
4580      * In order to set the matrix to a rotation transformation without pre-multiplying,
4581      * use {@link #rotation(Quaterniond)}.
4582      * <p>
4583      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a>
4584      * 
4585      * @see #rotation(Quaterniond)
4586      * 
4587      * @param quat
4588      *          the {@link Quaterniond}
4589      * @param dest
4590      *          will hold the result
4591      * @return dest
4592      */
4593     public Matrix4x3d rotateLocal(Quaterniond quat, ref Matrix4x3d dest) {
4594         double w2 = quat.w * quat.w, x2 = quat.x * quat.x;
4595         double y2 = quat.y * quat.y, z2 = quat.z * quat.z;
4596         double zw = quat.z * quat.w, dzw = zw + zw, xy = quat.x * quat.y, dxy = xy + xy;
4597         double xz = quat.x * quat.z, dxz = xz + xz, yw = quat.y * quat.w, dyw = yw + yw;
4598         double yz = quat.y * quat.z, dyz = yz + yz, xw = quat.x * quat.w, dxw = xw + xw;
4599         double lm00 = w2 + x2 - z2 - y2;
4600         double lm01 = dxy + dzw;
4601         double lm02 = dxz - dyw;
4602         double lm10 = dxy - dzw;
4603         double lm11 = y2 - z2 + w2 - x2;
4604         double lm12 = dyz + dxw;
4605         double lm20 = dyw + dxz;
4606         double lm21 = dyz - dxw;
4607         double lm22 = z2 - y2 - x2 + w2;
4608         double nm00 = lm00 * m00 + lm10 * m01 + lm20 * m02;
4609         double nm01 = lm01 * m00 + lm11 * m01 + lm21 * m02;
4610         double nm02 = lm02 * m00 + lm12 * m01 + lm22 * m02;
4611         double nm10 = lm00 * m10 + lm10 * m11 + lm20 * m12;
4612         double nm11 = lm01 * m10 + lm11 * m11 + lm21 * m12;
4613         double nm12 = lm02 * m10 + lm12 * m11 + lm22 * m12;
4614         double nm20 = lm00 * m20 + lm10 * m21 + lm20 * m22;
4615         double nm21 = lm01 * m20 + lm11 * m21 + lm21 * m22;
4616         double nm22 = lm02 * m20 + lm12 * m21 + lm22 * m22;
4617         double nm30 = lm00 * m30 + lm10 * m31 + lm20 * m32;
4618         double nm31 = lm01 * m30 + lm11 * m31 + lm21 * m32;
4619         double nm32 = lm02 * m30 + lm12 * m31 + lm22 * m32;
4620         dest.m00 = nm00;
4621         dest.m01 = nm01;
4622         dest.m02 = nm02;
4623         dest.m10 = nm10;
4624         dest.m11 = nm11;
4625         dest.m12 = nm12;
4626         dest.m20 = nm20;
4627         dest.m21 = nm21;
4628         dest.m22 = nm22;
4629         dest.m30 = nm30;
4630         dest.m31 = nm31;
4631         dest.m32 = nm32;
4632         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
4633         return dest;
4634     }
4635 
4636     /**
4637      * Pre-multiply the rotation transformation of the given {@link Quaterniond} to this matrix.
4638      * <p>
4639      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
4640      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
4641      * When used with a left-handed coordinate system, the rotation is clockwise.
4642      * <p>
4643      * If <code>M</code> is <code>this</code> matrix and <code>Q</code> the rotation matrix obtained from the given quaternion,
4644      * then the new matrix will be <code>Q * M</code>. So when transforming a
4645      * vector <code>v</code> with the new matrix by using <code>Q * M * v</code>,
4646      * the quaternion rotation will be applied last!
4647      * <p>
4648      * In order to set the matrix to a rotation transformation without pre-multiplying,
4649      * use {@link #rotation(Quaterniond)}.
4650      * <p>
4651      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion">http://en.wikipedia.org</a>
4652      * 
4653      * @see #rotation(Quaterniond)
4654      * 
4655      * @param quat
4656      *          the {@link Quaterniond}
4657      * @return this
4658      */
4659     ref public Matrix4x3d rotateLocal(Quaterniond quat) return {
4660         rotateLocal(quat, this);
4661         return this;
4662     }
4663 
4664     /**
4665      * Apply a rotation transformation, rotating about the given {@link AxisAngle4d}, to this matrix.
4666      * <p>
4667      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
4668      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
4669      * When used with a left-handed coordinate system, the rotation is clockwise.
4670      * <p>
4671      * If <code>M</code> is <code>this</code> matrix and <code>A</code> the rotation matrix obtained from the given {@link AxisAngle4d},
4672      * then the new matrix will be <code>M * A</code>. So when transforming a
4673      * vector <code>v</code> with the new matrix by using <code>M * A * v</code>,
4674      * the {@link AxisAngle4d} rotation will be applied first!
4675      * <p>
4676      * In order to set the matrix to a rotation transformation without post-multiplying,
4677      * use {@link #rotation(AxisAngle4d)}.
4678      * <p>
4679      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Axis_and_angle">http://en.wikipedia.org</a>
4680      * 
4681      * @see #rotate(double, double, double, double)
4682      * @see #rotation(AxisAngle4d)
4683      * 
4684      * @param axisAngle
4685      *          the {@link AxisAngle4d} (needs to be {@link AxisAngle4d#normalize() normalized})
4686      * @return this
4687      */
4688     ref public Matrix4x3d rotate(AxisAngle4d axisAngle) return {
4689         return rotate(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z);
4690     }
4691 
4692     /**
4693      * Apply a rotation transformation, rotating about the given {@link AxisAngle4d} and store the result in <code>dest</code>.
4694      * <p>
4695      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
4696      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
4697      * When used with a left-handed coordinate system, the rotation is clockwise.
4698      * <p>
4699      * If <code>M</code> is <code>this</code> matrix and <code>A</code> the rotation matrix obtained from the given {@link AxisAngle4d},
4700      * then the new matrix will be <code>M * A</code>. So when transforming a
4701      * vector <code>v</code> with the new matrix by using <code>M * A * v</code>,
4702      * the {@link AxisAngle4d} rotation will be applied first!
4703      * <p>
4704      * In order to set the matrix to a rotation transformation without post-multiplying,
4705      * use {@link #rotation(AxisAngle4d)}.
4706      * <p>
4707      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Axis_and_angle">http://en.wikipedia.org</a>
4708      * 
4709      * @see #rotate(double, double, double, double)
4710      * @see #rotation(AxisAngle4d)
4711      * 
4712      * @param axisAngle
4713      *          the {@link AxisAngle4d} (needs to be {@link AxisAngle4d#normalize() normalized})
4714      * @param dest
4715      *          will hold the result
4716      * @return dest
4717      */
4718     public Matrix4x3d rotate(AxisAngle4d axisAngle, ref Matrix4x3d dest) {
4719         return rotate(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z, dest);
4720     }
4721 
4722     /**
4723      * Apply a rotation transformation, rotating the given radians about the specified axis, to this matrix.
4724      * <p>
4725      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
4726      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
4727      * When used with a left-handed coordinate system, the rotation is clockwise.
4728      * <p>
4729      * If <code>M</code> is <code>this</code> matrix and <code>A</code> the rotation matrix obtained from the given angle and axis,
4730      * then the new matrix will be <code>M * A</code>. So when transforming a
4731      * vector <code>v</code> with the new matrix by using <code>M * A * v</code>,
4732      * the axis-angle rotation will be applied first!
4733      * <p>
4734      * In order to set the matrix to a rotation transformation without post-multiplying,
4735      * use {@link #rotation(double, Vector3d)}.
4736      * <p>
4737      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Axis_and_angle">http://en.wikipedia.org</a>
4738      * 
4739      * @see #rotate(double, double, double, double)
4740      * @see #rotation(double, Vector3d)
4741      * 
4742      * @param angle
4743      *          the angle in radians
4744      * @param axis
4745      *          the rotation axis (needs to be {@link Vector3d#normalize() normalized})
4746      * @return this
4747      */
4748     ref public Matrix4x3d rotate(double angle, Vector3d axis) return {
4749         return rotate(angle, axis.x, axis.y, axis.z);
4750     }
4751 
4752     /**
4753      * Apply a rotation transformation, rotating the given radians about the specified axis and store the result in <code>dest</code>.
4754      * <p>
4755      * When used with a right-handed coordinate system, the produced rotation will rotate a vector 
4756      * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
4757      * When used with a left-handed coordinate system, the rotation is clockwise.
4758      * <p>
4759      * If <code>M</code> is <code>this</code> matrix and <code>A</code> the rotation matrix obtained from the given angle and axis,
4760      * then the new matrix will be <code>M * A</code>. So when transforming a
4761      * vector <code>v</code> with the new matrix by using <code>M * A * v</code>,
4762      * the axis-angle rotation will be applied first!
4763      * <p>
4764      * In order to set the matrix to a rotation transformation without post-multiplying,
4765      * use {@link #rotation(double, Vector3d)}.
4766      * <p>
4767      * Reference: <a href="http://en.wikipedia.org/wiki/Rotation_matrix#Axis_and_angle">http://en.wikipedia.org</a>
4768      * 
4769      * @see #rotate(double, double, double, double)
4770      * @see #rotation(double, Vector3d)
4771      * 
4772      * @param angle
4773      *          the angle in radians
4774      * @param axis
4775      *          the rotation axis (needs to be {@link Vector3d#normalize() normalized})
4776      * @param dest
4777      *          will hold the result
4778      * @return dest
4779      */
4780     public Matrix4x3d rotate(double angle, Vector3d axis, ref Matrix4x3d dest) {
4781         return rotate(angle, axis.x, axis.y, axis.z, dest);
4782     }
4783 
4784 
4785     public Vector4d getRow(int row, Vector4d dest) {
4786         switch (row) {
4787         case 0:
4788             dest.x = m00;
4789             dest.y = m10;
4790             dest.z = m20;
4791             dest.w = m30;
4792             break;
4793         case 1:
4794             dest.x = m01;
4795             dest.y = m11;
4796             dest.z = m21;
4797             dest.w = m31;
4798             break;
4799         case 2:
4800             dest.x = m02;
4801             dest.y = m12;
4802             dest.z = m22;
4803             dest.w = m32;
4804             break;
4805         default: {}
4806         }
4807         return dest;
4808     }
4809 
4810     /**
4811      * Set the row at the given <code>row</code> index, starting with <code>0</code>.
4812      * 
4813      * @param row
4814      *          the row index in <code>[0..2]</code>
4815      * @param src
4816      *          the row components to set
4817      * @return this
4818      * @throws IndexOutOfBoundsException if <code>row</code> is not in <code>[0..2]</code>
4819      */
4820     ref public Matrix4x3d setRow(int row, Vector4d src) return {
4821         switch (row) {
4822         case 0:
4823             this.m00 = src.x;
4824             this.m10 = src.y;
4825             this.m20 = src.z;
4826             this.m30 = src.w;
4827             break;
4828         case 1:
4829             this.m01 = src.x;
4830             this.m11 = src.y;
4831             this.m21 = src.z;
4832             this.m31 = src.w;
4833             break;
4834         case 2:
4835             this.m02 = src.x;
4836             this.m12 = src.y;
4837             this.m22 = src.z;
4838             this.m32 = src.w;
4839             break;
4840         default: {}
4841         }
4842         properties = 0;
4843         return this;
4844     }
4845 
4846     public Vector3d getColumn(int column, ref Vector3d dest) {
4847         switch (column) {
4848         case 0:
4849             dest.x = m00;
4850             dest.y = m01;
4851             dest.z = m02;
4852             break;
4853         case 1:
4854             dest.x = m10;
4855             dest.y = m11;
4856             dest.z = m12;
4857             break;
4858         case 2:
4859             dest.x = m20;
4860             dest.y = m21;
4861             dest.z = m22;
4862             break;
4863         case 3:
4864             dest.x = m30;
4865             dest.y = m31;
4866             dest.z = m32;
4867             break;
4868         default: {}
4869         }
4870         return dest;
4871     }
4872 
4873     /**
4874      * Set the column at the given <code>column</code> index, starting with <code>0</code>.
4875      * 
4876      * @param column
4877      *          the column index in <code>[0..3]</code>
4878      * @param src
4879      *          the column components to set
4880      * @return this
4881      * @throws IndexOutOfBoundsException if <code>column</code> is not in <code>[0..3]</code>
4882      */
4883     ref public Matrix4x3d setColumn(int column, Vector3d src) return {
4884         switch (column) {
4885         case 0:
4886             this.m00 = src.x;
4887             this.m01 = src.y;
4888             this.m02 = src.z;
4889             break;
4890         case 1:
4891             this.m10 = src.x;
4892             this.m11 = src.y;
4893             this.m12 = src.z;
4894             break;
4895         case 2:
4896             this.m20 = src.x;
4897             this.m21 = src.y;
4898             this.m22 = src.z;
4899             break;
4900         case 3:
4901             this.m30 = src.x;
4902             this.m31 = src.y;
4903             this.m32 = src.z;
4904             break;
4905         default: {}
4906         }
4907         properties = 0;
4908         return this;
4909     }
4910 
4911     /**
4912      * Compute a normal matrix from the left 3x3 submatrix of <code>this</code>
4913      * and store it into the left 3x3 submatrix of <code>this</code>.
4914      * All other values of <code>this</code> will be set to {@link #identity() identity}.
4915      * <p>
4916      * The normal matrix of <code>m</code> is the transpose of the inverse of <code>m</code>.
4917      * <p>
4918      * Please note that, if <code>this</code> is an orthogonal matrix or a matrix whose columns are orthogonal vectors, 
4919      * then this method <i>need not</i> be invoked, since in that case <code>this</code> itself is its normal matrix.
4920      * In that case, use {@link #set3x3(Matrix4x3d)} to set a given Matrix4x3d to only the left 3x3 submatrix
4921      * of this matrix.
4922      * 
4923      * @see #set3x3(Matrix4x3d)
4924      * 
4925      * @return this
4926      */
4927     ref public Matrix4x3d normal() return {
4928         normal(this);
4929         return this;
4930     }
4931 
4932     /**
4933      * Compute a normal matrix from the left 3x3 submatrix of <code>this</code>
4934      * and store it into the left 3x3 submatrix of <code>dest</code>.
4935      * All other values of <code>dest</code> will be set to {@link #identity() identity}.
4936      * <p>
4937      * The normal matrix of <code>m</code> is the transpose of the inverse of <code>m</code>.
4938      * <p>
4939      * Please note that, if <code>this</code> is an orthogonal matrix or a matrix whose columns are orthogonal vectors, 
4940      * then this method <i>need not</i> be invoked, since in that case <code>this</code> itself is its normal matrix.
4941      * In that case, use {@link #set3x3(Matrix4x3d)} to set a given Matrix4x3d to only the left 3x3 submatrix
4942      * of a given matrix.
4943      * 
4944      * @see #set3x3(Matrix4x3d)
4945      * 
4946      * @param dest
4947      *             will hold the result
4948      * @return dest
4949      */
4950     public Matrix4x3d normal(ref Matrix4x3d dest) {
4951         if ((properties & PROPERTY_IDENTITY) != 0)
4952             return dest.identity();
4953         else if ((properties & PROPERTY_ORTHONORMAL) != 0)
4954             return normalOrthonormal(dest);
4955         return normalGeneric(dest);
4956     }
4957     private Matrix4x3d normalOrthonormal(ref Matrix4x3d dest) {
4958         if (dest != this)
4959             dest.set(this);
4960         return dest._properties(PROPERTY_ORTHONORMAL);
4961     }
4962     private Matrix4x3d normalGeneric(ref Matrix4x3d dest) {
4963         double m00m11 = m00 * m11;
4964         double m01m10 = m01 * m10;
4965         double m02m10 = m02 * m10;
4966         double m00m12 = m00 * m12;
4967         double m01m12 = m01 * m12;
4968         double m02m11 = m02 * m11;
4969         double det = (m00m11 - m01m10) * m22 + (m02m10 - m00m12) * m21 + (m01m12 - m02m11) * m20;
4970         double s = 1.0 / det;
4971         /* Invert and transpose in one go */
4972         double nm00 = (m11 * m22 - m21 * m12) * s;
4973         double nm01 = (m20 * m12 - m10 * m22) * s;
4974         double nm02 = (m10 * m21 - m20 * m11) * s;
4975         double nm10 = (m21 * m02 - m01 * m22) * s;
4976         double nm11 = (m00 * m22 - m20 * m02) * s;
4977         double nm12 = (m20 * m01 - m00 * m21) * s;
4978         double nm20 = (m01m12 - m02m11) * s;
4979         double nm21 = (m02m10 - m00m12) * s;
4980         double nm22 = (m00m11 - m01m10) * s;
4981         dest.m00 = nm00;
4982         dest.m01 = nm01;
4983         dest.m02 = nm02;
4984         dest.m10 = nm10;
4985         dest.m11 = nm11;
4986         dest.m12 = nm12;
4987         dest.m20 = nm20;
4988         dest.m21 = nm21;
4989         dest.m22 = nm22;
4990         dest.m30 = 0.0;
4991         dest.m31 = 0.0;
4992         dest.m32 = 0.0;
4993         dest.properties = properties & ~PROPERTY_TRANSLATION;
4994         return dest;
4995     }
4996 
4997     public Matrix3d normal(Matrix3d dest) {
4998         if ((properties & PROPERTY_ORTHONORMAL) != 0)
4999             return normalOrthonormal(dest);
5000         return normalGeneric(dest);
5001     }
5002     private Matrix3d normalOrthonormal(Matrix3d dest) {
5003         return dest.set(this);
5004     }
5005     private Matrix3d normalGeneric(Matrix3d dest) {
5006         double m00m11 = m00 * m11;
5007         double m01m10 = m01 * m10;
5008         double m02m10 = m02 * m10;
5009         double m00m12 = m00 * m12;
5010         double m01m12 = m01 * m12;
5011         double m02m11 = m02 * m11;
5012         double det = (m00m11 - m01m10) * m22 + (m02m10 - m00m12) * m21 + (m01m12 - m02m11) * m20;
5013         double s = 1.0 / det;
5014         /* Invert and transpose in one go */
5015         dest.m00 = ((m11 * m22 - m21 * m12) * s);
5016         dest.m01 = ((m20 * m12 - m10 * m22) * s);
5017         dest.m02 = ((m10 * m21 - m20 * m11) * s);
5018         dest.m10 = ((m21 * m02 - m01 * m22) * s);
5019         dest.m11 = ((m00 * m22 - m20 * m02) * s);
5020         dest.m12 = ((m20 * m01 - m00 * m21) * s);
5021         dest.m20 = ((m01m12 - m02m11) * s);
5022         dest.m21 = ((m02m10 - m00m12) * s);
5023         dest.m22 = ((m00m11 - m01m10) * s);
5024         return dest;
5025     }
5026 
5027     /**
5028      * Compute the cofactor matrix of the left 3x3 submatrix of <code>this</code>.
5029      * <p>
5030      * The cofactor matrix can be used instead of {@link #normal()} to transform normals
5031      * when the orientation of the normals with respect to the surface should be preserved.
5032      * 
5033      * @return this
5034      */
5035     ref public Matrix4x3d cofactor3x3() return {
5036         cofactor3x3(this);
5037         return this;
5038     }
5039 
5040     /**
5041      * Compute the cofactor matrix of the left 3x3 submatrix of <code>this</code>
5042      * and store it into <code>dest</code>.
5043      * <p>
5044      * The cofactor matrix can be used instead of {@link #normal(Matrix3d)} to transform normals
5045      * when the orientation of the normals with respect to the surface should be preserved.
5046      * 
5047      * @param dest
5048      *             will hold the result
5049      * @return dest
5050      */
5051     public Matrix3d cofactor3x3(Matrix3d dest) {
5052         dest.m00 = m11 * m22 - m21 * m12;
5053         dest.m01 = m20 * m12 - m10 * m22;
5054         dest.m02 = m10 * m21 - m20 * m11;
5055         dest.m10 = m21 * m02 - m01 * m22;
5056         dest.m11 = m00 * m22 - m20 * m02;
5057         dest.m12 = m20 * m01 - m00 * m21;
5058         dest.m20 = m01 * m12 - m02 * m11;
5059         dest.m21 = m02 * m10 - m00 * m12;
5060         dest.m22 = m00 * m11 - m01 * m10;
5061         return dest;
5062     }
5063 
5064     /**
5065      * Compute the cofactor matrix of the left 3x3 submatrix of <code>this</code>
5066      * and store it into <code>dest</code>.
5067      * All other values of <code>dest</code> will be set to {@link #identity() identity}.
5068      * <p>
5069      * The cofactor matrix can be used instead of {@link #normal(Matrix4x3d)} to transform normals
5070      * when the orientation of the normals with respect to the surface should be preserved.
5071      * 
5072      * @param dest
5073      *             will hold the result
5074      * @return dest
5075      */
5076     public Matrix4x3d cofactor3x3(ref Matrix4x3d dest) {
5077         double nm00 = m11 * m22 - m21 * m12;
5078         double nm01 = m20 * m12 - m10 * m22;
5079         double nm02 = m10 * m21 - m20 * m11;
5080         double nm10 = m21 * m02 - m01 * m22;
5081         double nm11 = m00 * m22 - m20 * m02;
5082         double nm12 = m20 * m01 - m00 * m21;
5083         double nm20 = m01 * m12 - m11 * m02;
5084         double nm21 = m02 * m10 - m12 * m00;
5085         double nm22 = m00 * m11 - m10 * m01;
5086         dest.m00 = nm00;
5087         dest.m01 = nm01;
5088         dest.m02 = nm02;
5089         dest.m10 = nm10;
5090         dest.m11 = nm11;
5091         dest.m12 = nm12;
5092         dest.m20 = nm20;
5093         dest.m21 = nm21;
5094         dest.m22 = nm22;
5095         dest.m30 = 0.0;
5096         dest.m31 = 0.0;
5097         dest.m32 = 0.0;
5098         dest.properties = properties & ~PROPERTY_TRANSLATION;
5099         return dest;
5100     }
5101 
5102     /**
5103      * Normalize the left 3x3 submatrix of this matrix.
5104      * <p>
5105      * The resulting matrix will map unit vectors to unit vectors, though a pair of orthogonal input unit
5106      * vectors need not be mapped to a pair of orthogonal output vectors if the original matrix was not orthogonal itself
5107      * (i.e. had <i>skewing</i>).
5108      * 
5109      * @return this
5110      */
5111     ref public Matrix4x3d normalize3x3() return {
5112         normalize3x3(this);
5113         return this;
5114     }
5115 
5116     public Matrix4x3d normalize3x3(ref Matrix4x3d dest) {
5117         double invXlen = Math.invsqrt(m00 * m00 + m01 * m01 + m02 * m02);
5118         double invYlen = Math.invsqrt(m10 * m10 + m11 * m11 + m12 * m12);
5119         double invZlen = Math.invsqrt(m20 * m20 + m21 * m21 + m22 * m22);
5120         dest.m00 = m00 * invXlen; dest.m01 = m01 * invXlen; dest.m02 = m02 * invXlen;
5121         dest.m10 = m10 * invYlen; dest.m11 = m11 * invYlen; dest.m12 = m12 * invYlen;
5122         dest.m20 = m20 * invZlen; dest.m21 = m21 * invZlen; dest.m22 = m22 * invZlen;
5123         return dest;
5124     }
5125 
5126     public Matrix3d normalize3x3(Matrix3d dest) {
5127         double invXlen = Math.invsqrt(m00 * m00 + m01 * m01 + m02 * m02);
5128         double invYlen = Math.invsqrt(m10 * m10 + m11 * m11 + m12 * m12);
5129         double invZlen = Math.invsqrt(m20 * m20 + m21 * m21 + m22 * m22);
5130         dest.m00 = (m00 * invXlen); dest.m01 = (m01 * invXlen); dest.m02 = (m02 * invXlen);
5131         dest.m10 = (m10 * invYlen); dest.m11 = (m11 * invYlen); dest.m12 = (m12 * invYlen);
5132         dest.m20 = (m20 * invZlen); dest.m21 = (m21 * invZlen); dest.m22 = (m22 * invZlen);
5133         return dest;
5134     }
5135 
5136     public Matrix4x3d reflect(double a, double b, double c, double d, ref Matrix4x3d dest) {
5137         if ((properties & PROPERTY_IDENTITY) != 0)
5138             return dest.reflection(a, b, c, d);
5139 
5140         double da = a + a, db = b + b, dc = c + c, dd = d + d;
5141         double rm00 = 1.0 - da * a;
5142         double rm01 = -da * b;
5143         double rm02 = -da * c;
5144         double rm10 = -db * a;
5145         double rm11 = 1.0 - db * b;
5146         double rm12 = -db * c;
5147         double rm20 = -dc * a;
5148         double rm21 = -dc * b;
5149         double rm22 = 1.0 - dc * c;
5150         double rm30 = -dd * a;
5151         double rm31 = -dd * b;
5152         double rm32 = -dd * c;
5153 
5154         // matrix multiplication
5155         dest.m30 = m00 * rm30 + m10 * rm31 + m20 * rm32 + m30;
5156         dest.m31 = m01 * rm30 + m11 * rm31 + m21 * rm32 + m31;
5157         dest.m32 = m02 * rm30 + m12 * rm31 + m22 * rm32 + m32;
5158         double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
5159         double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
5160         double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
5161         double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
5162         double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
5163         double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
5164         dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
5165         dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
5166         dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
5167         dest.m00 = nm00;
5168         dest.m01 = nm01;
5169         dest.m02 = nm02;
5170         dest.m10 = nm10;
5171         dest.m11 = nm11;
5172         dest.m12 = nm12;
5173         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
5174 
5175         return dest;
5176     }
5177 
5178     /**
5179      * Apply a mirror/reflection transformation to this matrix that reflects about the given plane
5180      * specified via the equation <code>x*a + y*b + z*c + d = 0</code>.
5181      * <p>
5182      * The vector <code>(a, b, c)</code> must be a unit vector.
5183      * <p>
5184      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the reflection matrix,
5185      * then the new matrix will be <code>M * R</code>. So when transforming a
5186      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
5187      * reflection will be applied first!
5188      * <p>
5189      * Reference: <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/bb281733(v=vs.85).aspx">msdn.microsoft.com</a>
5190      * 
5191      * @param a
5192      *          the x factor in the plane equation
5193      * @param b
5194      *          the y factor in the plane equation
5195      * @param c
5196      *          the z factor in the plane equation
5197      * @param d
5198      *          the constant in the plane equation
5199      * @return this
5200      */
5201     ref public Matrix4x3d reflect(double a, double b, double c, double d) return {
5202         reflect(a, b, c, d, this);
5203         return this;
5204     }
5205 
5206     /**
5207      * Apply a mirror/reflection transformation to this matrix that reflects about the given plane
5208      * specified via the plane normal and a point on the plane.
5209      * <p>
5210      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the reflection matrix,
5211      * then the new matrix will be <code>M * R</code>. So when transforming a
5212      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
5213      * reflection will be applied first!
5214      * 
5215      * @param nx
5216      *          the x-coordinate of the plane normal
5217      * @param ny
5218      *          the y-coordinate of the plane normal
5219      * @param nz
5220      *          the z-coordinate of the plane normal
5221      * @param px
5222      *          the x-coordinate of a point on the plane
5223      * @param py
5224      *          the y-coordinate of a point on the plane
5225      * @param pz
5226      *          the z-coordinate of a point on the plane
5227      * @return this
5228      */
5229     ref public Matrix4x3d reflect(double nx, double ny, double nz, double px, double py, double pz) return {
5230         reflect(nx, ny, nz, px, py, pz, this);
5231         return this;
5232     }
5233 
5234     public Matrix4x3d reflect(double nx, double ny, double nz, double px, double py, double pz, ref Matrix4x3d dest) {
5235         double invLength = Math.invsqrt(nx * nx + ny * ny + nz * nz);
5236         double nnx = nx * invLength;
5237         double nny = ny * invLength;
5238         double nnz = nz * invLength;
5239         /* See: http://mathworld.wolfram.com/Plane.html */
5240         return reflect(nnx, nny, nnz, -nnx * px - nny * py - nnz * pz, dest);
5241     }
5242 
5243     /**
5244      * Apply a mirror/reflection transformation to this matrix that reflects about the given plane
5245      * specified via the plane normal and a point on the plane.
5246      * <p>
5247      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the reflection matrix,
5248      * then the new matrix will be <code>M * R</code>. So when transforming a
5249      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
5250      * reflection will be applied first!
5251      * 
5252      * @param normal
5253      *          the plane normal
5254      * @param point
5255      *          a point on the plane
5256      * @return this
5257      */
5258     ref public Matrix4x3d reflect(Vector3d normal, Vector3d point) return {
5259         return reflect(normal.x, normal.y, normal.z, point.x, point.y, point.z);
5260     }
5261 
5262     /**
5263      * Apply a mirror/reflection transformation to this matrix that reflects about a plane
5264      * specified via the plane orientation and a point on the plane.
5265      * <p>
5266      * This method can be used to build a reflection transformation based on the orientation of a mirror object in the scene.
5267      * It is assumed that the default mirror plane's normal is <code>(0, 0, 1)</code>. So, if the given {@link Quaterniond} is
5268      * the identity (does not apply any additional rotation), the reflection plane will be <code>z=0</code>, offset by the given <code>point</code>.
5269      * <p>
5270      * If <code>M</code> is <code>this</code> matrix and <code>R</code> the reflection matrix,
5271      * then the new matrix will be <code>M * R</code>. So when transforming a
5272      * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the
5273      * reflection will be applied first!
5274      * 
5275      * @param orientation
5276      *          the plane orientation relative to an implied normal vector of <code>(0, 0, 1)</code>
5277      * @param point
5278      *          a point on the plane
5279      * @return this
5280      */
5281     ref public Matrix4x3d reflect(Quaterniond orientation, Vector3d point) return {
5282         reflect(orientation, point, this);
5283         return this;
5284     }
5285 
5286     public Matrix4x3d reflect(Quaterniond orientation, Vector3d point, ref Matrix4x3d dest) {
5287         double num1 = orientation.x + orientation.x;
5288         double num2 = orientation.y + orientation.y;
5289         double num3 = orientation.z + orientation.z;
5290         double normalX = orientation.x * num3 + orientation.w * num2;
5291         double normalY = orientation.y * num3 - orientation.w * num1;
5292         double normalZ = 1.0 - (orientation.x * num1 + orientation.y * num2);
5293         return reflect(normalX, normalY, normalZ, point.x, point.y, point.z, dest);
5294     }
5295 
5296     public Matrix4x3d reflect(Vector3d normal, Vector3d point, ref Matrix4x3d dest) {
5297         return reflect(normal.x, normal.y, normal.z, point.x, point.y, point.z, dest);
5298     }
5299 
5300     /**
5301      * Set this matrix to a mirror/reflection transformation that reflects about the given plane
5302      * specified via the equation <code>x*a + y*b + z*c + d = 0</code>.
5303      * <p>
5304      * The vector <code>(a, b, c)</code> must be a unit vector.
5305      * <p>
5306      * Reference: <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/bb281733(v=vs.85).aspx">msdn.microsoft.com</a>
5307      * 
5308      * @param a
5309      *          the x factor in the plane equation
5310      * @param b
5311      *          the y factor in the plane equation
5312      * @param c
5313      *          the z factor in the plane equation
5314      * @param d
5315      *          the constant in the plane equation
5316      * @return this
5317      */
5318     ref public Matrix4x3d reflection(double a, double b, double c, double d) return {
5319         double da = a + a, db = b + b, dc = c + c, dd = d + d;
5320         m00 = 1.0 - da * a;
5321         m01 = -da * b;
5322         m02 = -da * c;
5323         m10 = -db * a;
5324         m11 = 1.0 - db * b;
5325         m12 = -db * c;
5326         m20 = -dc * a;
5327         m21 = -dc * b;
5328         m22 = 1.0 - dc * c;
5329         m30 = -dd * a;
5330         m31 = -dd * b;
5331         m32 = -dd * c;
5332         properties = PROPERTY_ORTHONORMAL;
5333         return this;
5334     }
5335 
5336     /**
5337      * Set this matrix to a mirror/reflection transformation that reflects about the given plane
5338      * specified via the plane normal and a point on the plane.
5339      * 
5340      * @param nx
5341      *          the x-coordinate of the plane normal
5342      * @param ny
5343      *          the y-coordinate of the plane normal
5344      * @param nz
5345      *          the z-coordinate of the plane normal
5346      * @param px
5347      *          the x-coordinate of a point on the plane
5348      * @param py
5349      *          the y-coordinate of a point on the plane
5350      * @param pz
5351      *          the z-coordinate of a point on the plane
5352      * @return this
5353      */
5354     ref public Matrix4x3d reflection(double nx, double ny, double nz, double px, double py, double pz) return {
5355         double invLength = Math.invsqrt(nx * nx + ny * ny + nz * nz);
5356         double nnx = nx * invLength;
5357         double nny = ny * invLength;
5358         double nnz = nz * invLength;
5359         /* See: http://mathworld.wolfram.com/Plane.html */
5360         return reflection(nnx, nny, nnz, -nnx * px - nny * py - nnz * pz);
5361     }
5362 
5363     /**
5364      * Set this matrix to a mirror/reflection transformation that reflects about the given plane
5365      * specified via the plane normal and a point on the plane.
5366      * 
5367      * @param normal
5368      *          the plane normal
5369      * @param point
5370      *          a point on the plane
5371      * @return this
5372      */
5373     ref public Matrix4x3d reflection(Vector3d normal, Vector3d point) return {
5374         return reflection(normal.x, normal.y, normal.z, point.x, point.y, point.z);
5375     }
5376 
5377     /**
5378      * Set this matrix to a mirror/reflection transformation that reflects about a plane
5379      * specified via the plane orientation and a point on the plane.
5380      * <p>
5381      * This method can be used to build a reflection transformation based on the orientation of a mirror object in the scene.
5382      * It is assumed that the default mirror plane's normal is <code>(0, 0, 1)</code>. So, if the given {@link Quaterniond} is
5383      * the identity (does not apply any additional rotation), the reflection plane will be <code>z=0</code>, offset by the given <code>point</code>.
5384      * 
5385      * @param orientation
5386      *          the plane orientation
5387      * @param point
5388      *          a point on the plane
5389      * @return this
5390      */
5391     ref public Matrix4x3d reflection(Quaterniond orientation, Vector3d point) return {
5392         double num1 = orientation.x + orientation.x;
5393         double num2 = orientation.y + orientation.y;
5394         double num3 = orientation.z + orientation.z;
5395         double normalX = orientation.x * num3 + orientation.w * num2;
5396         double normalY = orientation.y * num3 - orientation.w * num1;
5397         double normalZ = 1.0 - (orientation.x * num1 + orientation.y * num2);
5398         return reflection(normalX, normalY, normalZ, point.x, point.y, point.z);
5399     }
5400 
5401     /**
5402      * Apply an orthographic projection transformation for a right-handed coordinate system
5403      * using the given NDC z range to this matrix and store the result in <code>dest</code>.
5404      * <p>
5405      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
5406      * then the new matrix will be <code>M * O</code>. So when transforming a
5407      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
5408      * orthographic projection transformation will be applied first!
5409      * <p>
5410      * In order to set the matrix to an orthographic projection without post-multiplying it,
5411      * use {@link #setOrtho(double, double, double, double, double, double, bool) setOrtho()}.
5412      * <p>
5413      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
5414      * 
5415      * @see #setOrtho(double, double, double, double, double, double, bool)
5416      * 
5417      * @param left
5418      *            the distance from the center to the left frustum edge
5419      * @param right
5420      *            the distance from the center to the right frustum edge
5421      * @param bottom
5422      *            the distance from the center to the bottom frustum edge
5423      * @param top
5424      *            the distance from the center to the top frustum edge
5425      * @param zNear
5426      *            near clipping plane distance
5427      * @param zFar
5428      *            far clipping plane distance
5429      * @param zZeroToOne
5430      *            whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code>
5431      *            or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code>
5432      * @param dest
5433      *            will hold the result
5434      * @return dest
5435      */
5436     public Matrix4x3d ortho(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne, ref Matrix4x3d dest) {
5437         // calculate right matrix elements
5438         double rm00 = 2.0 / (right - left);
5439         double rm11 = 2.0 / (top - bottom);
5440         double rm22 = (zZeroToOne ? 1.0 : 2.0) / (zNear - zFar);
5441         double rm30 = (left + right) / (left - right);
5442         double rm31 = (top + bottom) / (bottom - top);
5443         double rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
5444 
5445         // perform optimized multiplication
5446         // compute the last column first, because other columns do not depend on it
5447         dest.m30 = m00 * rm30 + m10 * rm31 + m20 * rm32 + m30;
5448         dest.m31 = m01 * rm30 + m11 * rm31 + m21 * rm32 + m31;
5449         dest.m32 = m02 * rm30 + m12 * rm31 + m22 * rm32 + m32;
5450         dest.m00 = m00 * rm00;
5451         dest.m01 = m01 * rm00;
5452         dest.m02 = m02 * rm00;
5453         dest.m10 = m10 * rm11;
5454         dest.m11 = m11 * rm11;
5455         dest.m12 = m12 * rm11;
5456         dest.m20 = m20 * rm22;
5457         dest.m21 = m21 * rm22;
5458         dest.m22 = m22 * rm22;
5459         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
5460 
5461         return dest;
5462     }
5463 
5464     /**
5465      * Apply an orthographic projection transformation for a right-handed coordinate system
5466      * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>.
5467      * <p>
5468      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
5469      * then the new matrix will be <code>M * O</code>. So when transforming a
5470      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
5471      * orthographic projection transformation will be applied first!
5472      * <p>
5473      * In order to set the matrix to an orthographic projection without post-multiplying it,
5474      * use {@link #setOrtho(double, double, double, double, double, double) setOrtho()}.
5475      * <p>
5476      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
5477      * 
5478      * @see #setOrtho(double, double, double, double, double, double)
5479      * 
5480      * @param left
5481      *            the distance from the center to the left frustum edge
5482      * @param right
5483      *            the distance from the center to the right frustum edge
5484      * @param bottom
5485      *            the distance from the center to the bottom frustum edge
5486      * @param top
5487      *            the distance from the center to the top frustum edge
5488      * @param zNear
5489      *            near clipping plane distance
5490      * @param zFar
5491      *            far clipping plane distance
5492      * @param dest
5493      *            will hold the result
5494      * @return dest
5495      */
5496     public Matrix4x3d ortho(double left, double right, double bottom, double top, double zNear, double zFar, ref Matrix4x3d dest) {
5497         return ortho(left, right, bottom, top, zNear, zFar, false, dest);
5498     }
5499 
5500     /**
5501      * Apply an orthographic projection transformation for a right-handed coordinate system
5502      * using the given NDC z range to this matrix.
5503      * <p>
5504      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
5505      * then the new matrix will be <code>M * O</code>. So when transforming a
5506      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
5507      * orthographic projection transformation will be applied first!
5508      * <p>
5509      * In order to set the matrix to an orthographic projection without post-multiplying it,
5510      * use {@link #setOrtho(double, double, double, double, double, double, bool) setOrtho()}.
5511      * <p>
5512      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
5513      * 
5514      * @see #setOrtho(double, double, double, double, double, double, bool)
5515      * 
5516      * @param left
5517      *            the distance from the center to the left frustum edge
5518      * @param right
5519      *            the distance from the center to the right frustum edge
5520      * @param bottom
5521      *            the distance from the center to the bottom frustum edge
5522      * @param top
5523      *            the distance from the center to the top frustum edge
5524      * @param zNear
5525      *            near clipping plane distance
5526      * @param zFar
5527      *            far clipping plane distance
5528      * @param zZeroToOne
5529      *            whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code>
5530      *            or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code>
5531      * @return this
5532      */
5533     ref public Matrix4x3d ortho(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne) return {
5534         ortho(left, right, bottom, top, zNear, zFar, zZeroToOne, this);
5535         return this;
5536     }
5537 
5538     /**
5539      * Apply an orthographic projection transformation for a right-handed coordinate system
5540      * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix.
5541      * <p>
5542      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
5543      * then the new matrix will be <code>M * O</code>. So when transforming a
5544      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
5545      * orthographic projection transformation will be applied first!
5546      * <p>
5547      * In order to set the matrix to an orthographic projection without post-multiplying it,
5548      * use {@link #setOrtho(double, double, double, double, double, double) setOrtho()}.
5549      * <p>
5550      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
5551      * 
5552      * @see #setOrtho(double, double, double, double, double, double)
5553      * 
5554      * @param left
5555      *            the distance from the center to the left frustum edge
5556      * @param right
5557      *            the distance from the center to the right frustum edge
5558      * @param bottom
5559      *            the distance from the center to the bottom frustum edge
5560      * @param top
5561      *            the distance from the center to the top frustum edge
5562      * @param zNear
5563      *            near clipping plane distance
5564      * @param zFar
5565      *            far clipping plane distance
5566      * @return this
5567      */
5568     ref public Matrix4x3d ortho(double left, double right, double bottom, double top, double zNear, double zFar) return {
5569         return ortho(left, right, bottom, top, zNear, zFar, false);
5570     }
5571 
5572     /**
5573      * Apply an orthographic projection transformation for a left-handed coordiante system
5574      * using the given NDC z range to this matrix and store the result in <code>dest</code>.
5575      * <p>
5576      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
5577      * then the new matrix will be <code>M * O</code>. So when transforming a
5578      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
5579      * orthographic projection transformation will be applied first!
5580      * <p>
5581      * In order to set the matrix to an orthographic projection without post-multiplying it,
5582      * use {@link #setOrthoLH(double, double, double, double, double, double, bool) setOrthoLH()}.
5583      * <p>
5584      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
5585      * 
5586      * @see #setOrthoLH(double, double, double, double, double, double, bool)
5587      * 
5588      * @param left
5589      *            the distance from the center to the left frustum edge
5590      * @param right
5591      *            the distance from the center to the right frustum edge
5592      * @param bottom
5593      *            the distance from the center to the bottom frustum edge
5594      * @param top
5595      *            the distance from the center to the top frustum edge
5596      * @param zNear
5597      *            near clipping plane distance
5598      * @param zFar
5599      *            far clipping plane distance
5600      * @param zZeroToOne
5601      *            whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code>
5602      *            or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code>
5603      * @param dest
5604      *            will hold the result
5605      * @return dest
5606      */
5607     public Matrix4x3d orthoLH(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne, ref Matrix4x3d dest) {
5608         // calculate right matrix elements
5609         double rm00 = 2.0 / (right - left);
5610         double rm11 = 2.0 / (top - bottom);
5611         double rm22 = (zZeroToOne ? 1.0 : 2.0) / (zFar - zNear);
5612         double rm30 = (left + right) / (left - right);
5613         double rm31 = (top + bottom) / (bottom - top);
5614         double rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
5615 
5616         // perform optimized multiplication
5617         // compute the last column first, because other columns do not depend on it
5618         dest.m30 = m00 * rm30 + m10 * rm31 + m20 * rm32 + m30;
5619         dest.m31 = m01 * rm30 + m11 * rm31 + m21 * rm32 + m31;
5620         dest.m32 = m02 * rm30 + m12 * rm31 + m22 * rm32 + m32;
5621         dest.m00 = m00 * rm00;
5622         dest.m01 = m01 * rm00;
5623         dest.m02 = m02 * rm00;
5624         dest.m10 = m10 * rm11;
5625         dest.m11 = m11 * rm11;
5626         dest.m12 = m12 * rm11;
5627         dest.m20 = m20 * rm22;
5628         dest.m21 = m21 * rm22;
5629         dest.m22 = m22 * rm22;
5630         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
5631 
5632         return dest;
5633     }
5634 
5635     /**
5636      * Apply an orthographic projection transformation for a left-handed coordiante system
5637      * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>.
5638      * <p>
5639      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
5640      * then the new matrix will be <code>M * O</code>. So when transforming a
5641      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
5642      * orthographic projection transformation will be applied first!
5643      * <p>
5644      * In order to set the matrix to an orthographic projection without post-multiplying it,
5645      * use {@link #setOrthoLH(double, double, double, double, double, double) setOrthoLH()}.
5646      * <p>
5647      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
5648      * 
5649      * @see #setOrthoLH(double, double, double, double, double, double)
5650      * 
5651      * @param left
5652      *            the distance from the center to the left frustum edge
5653      * @param right
5654      *            the distance from the center to the right frustum edge
5655      * @param bottom
5656      *            the distance from the center to the bottom frustum edge
5657      * @param top
5658      *            the distance from the center to the top frustum edge
5659      * @param zNear
5660      *            near clipping plane distance
5661      * @param zFar
5662      *            far clipping plane distance
5663      * @param dest
5664      *            will hold the result
5665      * @return dest
5666      */
5667     public Matrix4x3d orthoLH(double left, double right, double bottom, double top, double zNear, double zFar, ref Matrix4x3d dest) {
5668         return orthoLH(left, right, bottom, top, zNear, zFar, false, dest);
5669     }
5670 
5671     /**
5672      * Apply an orthographic projection transformation for a left-handed coordiante system
5673      * using the given NDC z range to this matrix.
5674      * <p>
5675      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
5676      * then the new matrix will be <code>M * O</code>. So when transforming a
5677      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
5678      * orthographic projection transformation will be applied first!
5679      * <p>
5680      * In order to set the matrix to an orthographic projection without post-multiplying it,
5681      * use {@link #setOrthoLH(double, double, double, double, double, double, bool) setOrthoLH()}.
5682      * <p>
5683      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
5684      * 
5685      * @see #setOrthoLH(double, double, double, double, double, double, bool)
5686      * 
5687      * @param left
5688      *            the distance from the center to the left frustum edge
5689      * @param right
5690      *            the distance from the center to the right frustum edge
5691      * @param bottom
5692      *            the distance from the center to the bottom frustum edge
5693      * @param top
5694      *            the distance from the center to the top frustum edge
5695      * @param zNear
5696      *            near clipping plane distance
5697      * @param zFar
5698      *            far clipping plane distance
5699      * @param zZeroToOne
5700      *            whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code>
5701      *            or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code>
5702      * @return this
5703      */
5704     ref public Matrix4x3d orthoLH(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne) return {
5705         orthoLH(left, right, bottom, top, zNear, zFar, zZeroToOne, this);
5706         return this;
5707     }
5708 
5709     /**
5710      * Apply an orthographic projection transformation for a left-handed coordiante system
5711      * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix.
5712      * <p>
5713      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
5714      * then the new matrix will be <code>M * O</code>. So when transforming a
5715      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
5716      * orthographic projection transformation will be applied first!
5717      * <p>
5718      * In order to set the matrix to an orthographic projection without post-multiplying it,
5719      * use {@link #setOrthoLH(double, double, double, double, double, double) setOrthoLH()}.
5720      * <p>
5721      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
5722      * 
5723      * @see #setOrthoLH(double, double, double, double, double, double)
5724      * 
5725      * @param left
5726      *            the distance from the center to the left frustum edge
5727      * @param right
5728      *            the distance from the center to the right frustum edge
5729      * @param bottom
5730      *            the distance from the center to the bottom frustum edge
5731      * @param top
5732      *            the distance from the center to the top frustum edge
5733      * @param zNear
5734      *            near clipping plane distance
5735      * @param zFar
5736      *            far clipping plane distance
5737      * @return this
5738      */
5739     ref public Matrix4x3d orthoLH(double left, double right, double bottom, double top, double zNear, double zFar) return {
5740         return orthoLH(left, right, bottom, top, zNear, zFar, false);
5741     }
5742 
5743     /**
5744      * Set this matrix to be an orthographic projection transformation for a right-handed coordinate system
5745      * using the given NDC z range.
5746      * <p>
5747      * In order to apply the orthographic projection to an already existing transformation,
5748      * use {@link #ortho(double, double, double, double, double, double, bool) ortho()}.
5749      * <p>
5750      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
5751      * 
5752      * @see #ortho(double, double, double, double, double, double, bool)
5753      * 
5754      * @param left
5755      *            the distance from the center to the left frustum edge
5756      * @param right
5757      *            the distance from the center to the right frustum edge
5758      * @param bottom
5759      *            the distance from the center to the bottom frustum edge
5760      * @param top
5761      *            the distance from the center to the top frustum edge
5762      * @param zNear
5763      *            near clipping plane distance
5764      * @param zFar
5765      *            far clipping plane distance
5766      * @param zZeroToOne
5767      *            whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code>
5768      *            or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code>
5769      * @return this
5770      */
5771     ref public Matrix4x3d setOrtho(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne) return {
5772         m00 = 2.0 / (right - left);
5773         m01 = 0.0;
5774         m02 = 0.0;
5775         m10 = 0.0;
5776         m11 = 2.0 / (top - bottom);
5777         m12 = 0.0;
5778         m20 = 0.0;
5779         m21 = 0.0;
5780         m22 = (zZeroToOne ? 1.0 : 2.0) / (zNear - zFar);
5781         m30 = (right + left) / (left - right);
5782         m31 = (top + bottom) / (bottom - top);
5783         m32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
5784         properties = 0;
5785         return this;
5786     }
5787 
5788     /**
5789      * Set this matrix to be an orthographic projection transformation for a right-handed coordinate system
5790      * using OpenGL's NDC z range of <code>[-1..+1]</code>.
5791      * <p>
5792      * In order to apply the orthographic projection to an already existing transformation,
5793      * use {@link #ortho(double, double, double, double, double, double) ortho()}.
5794      * <p>
5795      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
5796      * 
5797      * @see #ortho(double, double, double, double, double, double)
5798      * 
5799      * @param left
5800      *            the distance from the center to the left frustum edge
5801      * @param right
5802      *            the distance from the center to the right frustum edge
5803      * @param bottom
5804      *            the distance from the center to the bottom frustum edge
5805      * @param top
5806      *            the distance from the center to the top frustum edge
5807      * @param zNear
5808      *            near clipping plane distance
5809      * @param zFar
5810      *            far clipping plane distance
5811      * @return this
5812      */
5813     ref public Matrix4x3d setOrtho(double left, double right, double bottom, double top, double zNear, double zFar) return {
5814         return setOrtho(left, right, bottom, top, zNear, zFar, false);
5815     }
5816 
5817     /**
5818      * Set this matrix to be an orthographic projection transformation for a left-handed coordinate system
5819      * using the given NDC z range.
5820      * <p>
5821      * In order to apply the orthographic projection to an already existing transformation,
5822      * use {@link #orthoLH(double, double, double, double, double, double, bool) orthoLH()}.
5823      * <p>
5824      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
5825      * 
5826      * @see #orthoLH(double, double, double, double, double, double, bool)
5827      * 
5828      * @param left
5829      *            the distance from the center to the left frustum edge
5830      * @param right
5831      *            the distance from the center to the right frustum edge
5832      * @param bottom
5833      *            the distance from the center to the bottom frustum edge
5834      * @param top
5835      *            the distance from the center to the top frustum edge
5836      * @param zNear
5837      *            near clipping plane distance
5838      * @param zFar
5839      *            far clipping plane distance
5840      * @param zZeroToOne
5841      *            whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code>
5842      *            or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code>
5843      * @return this
5844      */
5845     ref public Matrix4x3d setOrthoLH(double left, double right, double bottom, double top, double zNear, double zFar, bool zZeroToOne) return {
5846         m00 = 2.0 / (right - left);
5847         m01 = 0.0;
5848         m02 = 0.0;
5849         m10 = 0.0;
5850         m11 = 2.0 / (top - bottom);
5851         m12 = 0.0;
5852         m20 = 0.0;
5853         m21 = 0.0;
5854         m22 = (zZeroToOne ? 1.0 : 2.0) / (zFar - zNear);
5855         m30 = (right + left) / (left - right);
5856         m31 = (top + bottom) / (bottom - top);
5857         m32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
5858         properties = 0;
5859         return this;
5860     }
5861 
5862     /**
5863      * Set this matrix to be an orthographic projection transformation for a left-handed coordinate system
5864      * using OpenGL's NDC z range of <code>[-1..+1]</code>.
5865      * <p>
5866      * In order to apply the orthographic projection to an already existing transformation,
5867      * use {@link #orthoLH(double, double, double, double, double, double) orthoLH()}.
5868      * <p>
5869      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
5870      * 
5871      * @see #orthoLH(double, double, double, double, double, double)
5872      * 
5873      * @param left
5874      *            the distance from the center to the left frustum edge
5875      * @param right
5876      *            the distance from the center to the right frustum edge
5877      * @param bottom
5878      *            the distance from the center to the bottom frustum edge
5879      * @param top
5880      *            the distance from the center to the top frustum edge
5881      * @param zNear
5882      *            near clipping plane distance
5883      * @param zFar
5884      *            far clipping plane distance
5885      * @return this
5886      */
5887     ref public Matrix4x3d setOrthoLH(double left, double right, double bottom, double top, double zNear, double zFar) return {
5888         return setOrthoLH(left, right, bottom, top, zNear, zFar, false);
5889     }
5890 
5891     /**
5892      * Apply a symmetric orthographic projection transformation for a right-handed coordinate system
5893      * using the given NDC z range to this matrix and store the result in <code>dest</code>.
5894      * <p>
5895      * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double, bool, Matrix4x3d) ortho()} with
5896      * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>.
5897      * <p>
5898      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
5899      * then the new matrix will be <code>M * O</code>. So when transforming a
5900      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
5901      * orthographic projection transformation will be applied first!
5902      * <p>
5903      * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
5904      * use {@link #setOrthoSymmetric(double, double, double, double, bool) setOrthoSymmetric()}.
5905      * <p>
5906      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
5907      * 
5908      * @see #setOrthoSymmetric(double, double, double, double, bool)
5909      * 
5910      * @param width
5911      *            the distance between the right and left frustum edges
5912      * @param height
5913      *            the distance between the top and bottom frustum edges
5914      * @param zNear
5915      *            near clipping plane distance
5916      * @param zFar
5917      *            far clipping plane distance
5918      * @param dest
5919      *            will hold the result
5920      * @param zZeroToOne
5921      *            whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code>
5922      *            or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code>
5923      * @return dest
5924      */
5925     public Matrix4x3d orthoSymmetric(double width, double height, double zNear, double zFar, bool zZeroToOne, ref Matrix4x3d dest) {
5926         // calculate right matrix elements
5927         double rm00 = 2.0 / width;
5928         double rm11 = 2.0 / height;
5929         double rm22 = (zZeroToOne ? 1.0 : 2.0) / (zNear - zFar);
5930         double rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
5931 
5932         // perform optimized multiplication
5933         // compute the last column first, because other columns do not depend on it
5934         dest.m30 = m20 * rm32 + m30;
5935         dest.m31 = m21 * rm32 + m31;
5936         dest.m32 = m22 * rm32 + m32;
5937         dest.m00 = m00 * rm00;
5938         dest.m01 = m01 * rm00;
5939         dest.m02 = m02 * rm00;
5940         dest.m10 = m10 * rm11;
5941         dest.m11 = m11 * rm11;
5942         dest.m12 = m12 * rm11;
5943         dest.m20 = m20 * rm22;
5944         dest.m21 = m21 * rm22;
5945         dest.m22 = m22 * rm22;
5946         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
5947 
5948         return dest;
5949     }
5950 
5951     /**
5952      * Apply a symmetric orthographic projection transformation for a right-handed coordinate system
5953      * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>.
5954      * <p>
5955      * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double, Matrix4x3d) ortho()} with
5956      * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>.
5957      * <p>
5958      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
5959      * then the new matrix will be <code>M * O</code>. So when transforming a
5960      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
5961      * orthographic projection transformation will be applied first!
5962      * <p>
5963      * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
5964      * use {@link #setOrthoSymmetric(double, double, double, double) setOrthoSymmetric()}.
5965      * <p>
5966      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
5967      * 
5968      * @see #setOrthoSymmetric(double, double, double, double)
5969      * 
5970      * @param width
5971      *            the distance between the right and left frustum edges
5972      * @param height
5973      *            the distance between the top and bottom frustum edges
5974      * @param zNear
5975      *            near clipping plane distance
5976      * @param zFar
5977      *            far clipping plane distance
5978      * @param dest
5979      *            will hold the result
5980      * @return dest
5981      */
5982     public Matrix4x3d orthoSymmetric(double width, double height, double zNear, double zFar, ref Matrix4x3d dest) {
5983         return orthoSymmetric(width, height, zNear, zFar, false, dest);
5984     }
5985 
5986     /**
5987      * Apply a symmetric orthographic projection transformation for a right-handed coordinate system
5988      * using the given NDC z range to this matrix.
5989      * <p>
5990      * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double, bool) ortho()} with
5991      * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>.
5992      * <p>
5993      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
5994      * then the new matrix will be <code>M * O</code>. So when transforming a
5995      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
5996      * orthographic projection transformation will be applied first!
5997      * <p>
5998      * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
5999      * use {@link #setOrthoSymmetric(double, double, double, double, bool) setOrthoSymmetric()}.
6000      * <p>
6001      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
6002      * 
6003      * @see #setOrthoSymmetric(double, double, double, double, bool)
6004      * 
6005      * @param width
6006      *            the distance between the right and left frustum edges
6007      * @param height
6008      *            the distance between the top and bottom frustum edges
6009      * @param zNear
6010      *            near clipping plane distance
6011      * @param zFar
6012      *            far clipping plane distance
6013      * @param zZeroToOne
6014      *            whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code>
6015      *            or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code>
6016      * @return this
6017      */
6018     ref public Matrix4x3d orthoSymmetric(double width, double height, double zNear, double zFar, bool zZeroToOne) return {
6019         orthoSymmetric(width, height, zNear, zFar, zZeroToOne, this);
6020         return this;
6021     }
6022 
6023     /**
6024      * Apply a symmetric orthographic projection transformation for a right-handed coordinate system
6025      * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix.
6026      * <p>
6027      * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double) ortho()} with
6028      * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>.
6029      * <p>
6030      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
6031      * then the new matrix will be <code>M * O</code>. So when transforming a
6032      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
6033      * orthographic projection transformation will be applied first!
6034      * <p>
6035      * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
6036      * use {@link #setOrthoSymmetric(double, double, double, double) setOrthoSymmetric()}.
6037      * <p>
6038      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
6039      * 
6040      * @see #setOrthoSymmetric(double, double, double, double)
6041      * 
6042      * @param width
6043      *            the distance between the right and left frustum edges
6044      * @param height
6045      *            the distance between the top and bottom frustum edges
6046      * @param zNear
6047      *            near clipping plane distance
6048      * @param zFar
6049      *            far clipping plane distance
6050      * @return this
6051      */
6052     ref public Matrix4x3d orthoSymmetric(double width, double height, double zNear, double zFar) return {
6053         orthoSymmetric(width, height, zNear, zFar, false, this);
6054         return this;
6055     }
6056 
6057     /**
6058      * Apply a symmetric orthographic projection transformation for a left-handed coordinate system
6059      * using the given NDC z range to this matrix and store the result in <code>dest</code>.
6060      * <p>
6061      * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double, bool, Matrix4x3d) orthoLH()} with
6062      * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>.
6063      * <p>
6064      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
6065      * then the new matrix will be <code>M * O</code>. So when transforming a
6066      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
6067      * orthographic projection transformation will be applied first!
6068      * <p>
6069      * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
6070      * use {@link #setOrthoSymmetricLH(double, double, double, double, bool) setOrthoSymmetricLH()}.
6071      * <p>
6072      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
6073      * 
6074      * @see #setOrthoSymmetricLH(double, double, double, double, bool)
6075      * 
6076      * @param width
6077      *            the distance between the right and left frustum edges
6078      * @param height
6079      *            the distance between the top and bottom frustum edges
6080      * @param zNear
6081      *            near clipping plane distance
6082      * @param zFar
6083      *            far clipping plane distance
6084      * @param dest
6085      *            will hold the result
6086      * @param zZeroToOne
6087      *            whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code>
6088      *            or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code>
6089      * @return dest
6090      */
6091     public Matrix4x3d orthoSymmetricLH(double width, double height, double zNear, double zFar, bool zZeroToOne, ref Matrix4x3d dest) {
6092         // calculate right matrix elements
6093         double rm00 = 2.0 / width;
6094         double rm11 = 2.0 / height;
6095         double rm22 = (zZeroToOne ? 1.0 : 2.0) / (zFar - zNear);
6096         double rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
6097 
6098         // perform optimized multiplication
6099         // compute the last column first, because other columns do not depend on it
6100         dest.m30 = m20 * rm32 + m30;
6101         dest.m31 = m21 * rm32 + m31;
6102         dest.m32 = m22 * rm32 + m32;
6103         dest.m00 = m00 * rm00;
6104         dest.m01 = m01 * rm00;
6105         dest.m02 = m02 * rm00;
6106         dest.m10 = m10 * rm11;
6107         dest.m11 = m11 * rm11;
6108         dest.m12 = m12 * rm11;
6109         dest.m20 = m20 * rm22;
6110         dest.m21 = m21 * rm22;
6111         dest.m22 = m22 * rm22;
6112         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
6113 
6114         return dest;
6115     }
6116 
6117     /**
6118      * Apply a symmetric orthographic projection transformation for a left-handed coordinate system
6119      * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix and store the result in <code>dest</code>.
6120      * <p>
6121      * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double, Matrix4x3d) orthoLH()} with
6122      * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>.
6123      * <p>
6124      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
6125      * then the new matrix will be <code>M * O</code>. So when transforming a
6126      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
6127      * orthographic projection transformation will be applied first!
6128      * <p>
6129      * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
6130      * use {@link #setOrthoSymmetricLH(double, double, double, double) setOrthoSymmetricLH()}.
6131      * <p>
6132      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
6133      * 
6134      * @see #setOrthoSymmetricLH(double, double, double, double)
6135      * 
6136      * @param width
6137      *            the distance between the right and left frustum edges
6138      * @param height
6139      *            the distance between the top and bottom frustum edges
6140      * @param zNear
6141      *            near clipping plane distance
6142      * @param zFar
6143      *            far clipping plane distance
6144      * @param dest
6145      *            will hold the result
6146      * @return dest
6147      */
6148     public Matrix4x3d orthoSymmetricLH(double width, double height, double zNear, double zFar, ref Matrix4x3d dest) {
6149         return orthoSymmetricLH(width, height, zNear, zFar, false, dest);
6150     }
6151 
6152     /**
6153      * Apply a symmetric orthographic projection transformation for a left-handed coordinate system
6154      * using the given NDC z range to this matrix.
6155      * <p>
6156      * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double, bool) orthoLH()} with
6157      * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>.
6158      * <p>
6159      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
6160      * then the new matrix will be <code>M * O</code>. So when transforming a
6161      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
6162      * orthographic projection transformation will be applied first!
6163      * <p>
6164      * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
6165      * use {@link #setOrthoSymmetricLH(double, double, double, double, bool) setOrthoSymmetricLH()}.
6166      * <p>
6167      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
6168      * 
6169      * @see #setOrthoSymmetricLH(double, double, double, double, bool)
6170      * 
6171      * @param width
6172      *            the distance between the right and left frustum edges
6173      * @param height
6174      *            the distance between the top and bottom frustum edges
6175      * @param zNear
6176      *            near clipping plane distance
6177      * @param zFar
6178      *            far clipping plane distance
6179      * @param zZeroToOne
6180      *            whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code>
6181      *            or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code>
6182      * @return this
6183      */
6184     ref public Matrix4x3d orthoSymmetricLH(double width, double height, double zNear, double zFar, bool zZeroToOne) return {
6185         orthoSymmetricLH(width, height, zNear, zFar, zZeroToOne, this);
6186         return this;
6187     }
6188 
6189     /**
6190      * Apply a symmetric orthographic projection transformation for a left-handed coordinate system
6191      * using OpenGL's NDC z range of <code>[-1..+1]</code> to this matrix.
6192      * <p>
6193      * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double) orthoLH()} with
6194      * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>.
6195      * <p>
6196      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
6197      * then the new matrix will be <code>M * O</code>. So when transforming a
6198      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
6199      * orthographic projection transformation will be applied first!
6200      * <p>
6201      * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
6202      * use {@link #setOrthoSymmetricLH(double, double, double, double) setOrthoSymmetricLH()}.
6203      * <p>
6204      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
6205      * 
6206      * @see #setOrthoSymmetricLH(double, double, double, double)
6207      * 
6208      * @param width
6209      *            the distance between the right and left frustum edges
6210      * @param height
6211      *            the distance between the top and bottom frustum edges
6212      * @param zNear
6213      *            near clipping plane distance
6214      * @param zFar
6215      *            far clipping plane distance
6216      * @return this
6217      */
6218     ref public Matrix4x3d orthoSymmetricLH(double width, double height, double zNear, double zFar) return {
6219         orthoSymmetricLH(width, height, zNear, zFar, false, this);
6220         return this;
6221     }
6222 
6223     /**
6224      * Set this matrix to be a symmetric orthographic projection transformation for a right-handed coordinate system
6225      * using the given NDC z range.
6226      * <p>
6227      * This method is equivalent to calling {@link #setOrtho(double, double, double, double, double, double, bool) setOrtho()} with
6228      * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>.
6229      * <p>
6230      * In order to apply the symmetric orthographic projection to an already existing transformation,
6231      * use {@link #orthoSymmetric(double, double, double, double, bool) orthoSymmetric()}.
6232      * <p>
6233      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
6234      * 
6235      * @see #orthoSymmetric(double, double, double, double, bool)
6236      * 
6237      * @param width
6238      *            the distance between the right and left frustum edges
6239      * @param height
6240      *            the distance between the top and bottom frustum edges
6241      * @param zNear
6242      *            near clipping plane distance
6243      * @param zFar
6244      *            far clipping plane distance
6245      * @param zZeroToOne
6246      *            whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code>
6247      *            or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code>
6248      * @return this
6249      */
6250     ref public Matrix4x3d setOrthoSymmetric(double width, double height, double zNear, double zFar, bool zZeroToOne) return {
6251         m00 = 2.0 / width;
6252         m01 = 0.0;
6253         m02 = 0.0;
6254         m10 = 0.0;
6255         m11 = 2.0 / height;
6256         m12 = 0.0;
6257         m20 = 0.0;
6258         m21 = 0.0;
6259         m22 = (zZeroToOne ? 1.0 : 2.0) / (zNear - zFar);
6260         m30 = 0.0;
6261         m31 = 0.0;
6262         m32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
6263         properties = 0;
6264         return this;
6265     }
6266 
6267     /**
6268      * Set this matrix to be a symmetric orthographic projection transformation for a right-handed coordinate system
6269      * using OpenGL's NDC z range of <code>[-1..+1]</code>.
6270      * <p>
6271      * This method is equivalent to calling {@link #setOrtho(double, double, double, double, double, double) setOrtho()} with
6272      * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>.
6273      * <p>
6274      * In order to apply the symmetric orthographic projection to an already existing transformation,
6275      * use {@link #orthoSymmetric(double, double, double, double) orthoSymmetric()}.
6276      * <p>
6277      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
6278      * 
6279      * @see #orthoSymmetric(double, double, double, double)
6280      * 
6281      * @param width
6282      *            the distance between the right and left frustum edges
6283      * @param height
6284      *            the distance between the top and bottom frustum edges
6285      * @param zNear
6286      *            near clipping plane distance
6287      * @param zFar
6288      *            far clipping plane distance
6289      * @return this
6290      */
6291     ref public Matrix4x3d setOrthoSymmetric(double width, double height, double zNear, double zFar) return {
6292         return setOrthoSymmetric(width, height, zNear, zFar, false);
6293     }
6294 
6295     /**
6296      * Set this matrix to be a symmetric orthographic projection transformation for a left-handed coordinate system using the given NDC z range.
6297      * <p>
6298      * This method is equivalent to calling {@link #setOrtho(double, double, double, double, double, double, bool) setOrtho()} with
6299      * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>.
6300      * <p>
6301      * In order to apply the symmetric orthographic projection to an already existing transformation,
6302      * use {@link #orthoSymmetricLH(double, double, double, double, bool) orthoSymmetricLH()}.
6303      * <p>
6304      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
6305      * 
6306      * @see #orthoSymmetricLH(double, double, double, double, bool)
6307      * 
6308      * @param width
6309      *            the distance between the right and left frustum edges
6310      * @param height
6311      *            the distance between the top and bottom frustum edges
6312      * @param zNear
6313      *            near clipping plane distance
6314      * @param zFar
6315      *            far clipping plane distance
6316      * @param zZeroToOne
6317      *            whether to use Vulkan's and Direct3D's NDC z range of <code>[0..+1]</code> when <code>true</code>
6318      *            or whether to use OpenGL's NDC z range of <code>[-1..+1]</code> when <code>false</code>
6319      * @return this
6320      */
6321     ref public Matrix4x3d setOrthoSymmetricLH(double width, double height, double zNear, double zFar, bool zZeroToOne) return {
6322         m00 = 2.0 / width;
6323         m01 = 0.0;
6324         m02 = 0.0;
6325         m10 = 0.0;
6326         m11 = 2.0 / height;
6327         m12 = 0.0;
6328         m20 = 0.0;
6329         m21 = 0.0;
6330         m22 = (zZeroToOne ? 1.0 : 2.0) / (zFar - zNear);
6331         m30 = 0.0;
6332         m31 = 0.0;
6333         m32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
6334         properties = 0;
6335         return this;
6336     }
6337 
6338     /**
6339      * Set this matrix to be a symmetric orthographic projection transformation for a left-handed coordinate system
6340      * using OpenGL's NDC z range of <code>[-1..+1]</code>.
6341      * <p>
6342      * This method is equivalent to calling {@link #setOrthoLH(double, double, double, double, double, double) setOrthoLH()} with
6343      * <code>left=-width/2</code>, <code>right=+width/2</code>, <code>bottom=-height/2</code> and <code>top=+height/2</code>.
6344      * <p>
6345      * In order to apply the symmetric orthographic projection to an already existing transformation,
6346      * use {@link #orthoSymmetricLH(double, double, double, double) orthoSymmetricLH()}.
6347      * <p>
6348      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
6349      * 
6350      * @see #orthoSymmetricLH(double, double, double, double)
6351      * 
6352      * @param width
6353      *            the distance between the right and left frustum edges
6354      * @param height
6355      *            the distance between the top and bottom frustum edges
6356      * @param zNear
6357      *            near clipping plane distance
6358      * @param zFar
6359      *            far clipping plane distance
6360      * @return this
6361      */
6362     ref public Matrix4x3d setOrthoSymmetricLH(double width, double height, double zNear, double zFar) return {
6363         return setOrthoSymmetricLH(width, height, zNear, zFar, false);
6364     }
6365 
6366     /**
6367      * Apply an orthographic projection transformation for a right-handed coordinate system
6368      * to this matrix and store the result in <code>dest</code>.
6369      * <p>
6370      * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double, Matrix4x3d) ortho()} with
6371      * <code>zNear=-1</code> and <code>zFar=+1</code>.
6372      * <p>
6373      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
6374      * then the new matrix will be <code>M * O</code>. So when transforming a
6375      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
6376      * orthographic projection transformation will be applied first!
6377      * <p>
6378      * In order to set the matrix to an orthographic projection without post-multiplying it,
6379      * use {@link #setOrtho2D(double, double, double, double) setOrtho()}.
6380      * <p>
6381      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
6382      * 
6383      * @see #ortho(double, double, double, double, double, double, Matrix4x3d)
6384      * @see #setOrtho2D(double, double, double, double)
6385      * 
6386      * @param left
6387      *            the distance from the center to the left frustum edge
6388      * @param right
6389      *            the distance from the center to the right frustum edge
6390      * @param bottom
6391      *            the distance from the center to the bottom frustum edge
6392      * @param top
6393      *            the distance from the center to the top frustum edge
6394      * @param dest
6395      *            will hold the result
6396      * @return dest
6397      */
6398     public Matrix4x3d ortho2D(double left, double right, double bottom, double top, ref Matrix4x3d dest) {
6399         // calculate right matrix elements
6400         double rm00 = 2.0 / (right - left);
6401         double rm11 = 2.0 / (top - bottom);
6402         double rm30 = -(right + left) / (right - left);
6403         double rm31 = -(top + bottom) / (top - bottom);
6404 
6405         // perform optimized multiplication
6406         // compute the last column first, because other columns do not depend on it
6407         dest.m30 = m00 * rm30 + m10 * rm31 + m30;
6408         dest.m31 = m01 * rm30 + m11 * rm31 + m31;
6409         dest.m32 = m02 * rm30 + m12 * rm31 + m32;
6410         dest.m00 = m00 * rm00;
6411         dest.m01 = m01 * rm00;
6412         dest.m02 = m02 * rm00;
6413         dest.m10 = m10 * rm11;
6414         dest.m11 = m11 * rm11;
6415         dest.m12 = m12 * rm11;
6416         dest.m20 = -m20;
6417         dest.m21 = -m21;
6418         dest.m22 = -m22;
6419         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
6420 
6421         return dest;
6422     }
6423 
6424     /**
6425      * Apply an orthographic projection transformation for a right-handed coordinate system to this matrix.
6426      * <p>
6427      * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double) ortho()} with
6428      * <code>zNear=-1</code> and <code>zFar=+1</code>.
6429      * <p>
6430      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
6431      * then the new matrix will be <code>M * O</code>. So when transforming a
6432      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
6433      * orthographic projection transformation will be applied first!
6434      * <p>
6435      * In order to set the matrix to an orthographic projection without post-multiplying it,
6436      * use {@link #setOrtho2D(double, double, double, double) setOrtho2D()}.
6437      * <p>
6438      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
6439      * 
6440      * @see #ortho(double, double, double, double, double, double)
6441      * @see #setOrtho2D(double, double, double, double)
6442      * 
6443      * @param left
6444      *            the distance from the center to the left frustum edge
6445      * @param right
6446      *            the distance from the center to the right frustum edge
6447      * @param bottom
6448      *            the distance from the center to the bottom frustum edge
6449      * @param top
6450      *            the distance from the center to the top frustum edge
6451      * @return this
6452      */
6453     ref public Matrix4x3d ortho2D(double left, double right, double bottom, double top) return {
6454         ortho2D(left, right, bottom, top, this);
6455         return this;
6456     }
6457 
6458     /**
6459      * Apply an orthographic projection transformation for a left-handed coordinate system to this matrix and store the result in <code>dest</code>.
6460      * <p>
6461      * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double, Matrix4x3d) orthoLH()} with
6462      * <code>zNear=-1</code> and <code>zFar=+1</code>.
6463      * <p>
6464      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
6465      * then the new matrix will be <code>M * O</code>. So when transforming a
6466      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
6467      * orthographic projection transformation will be applied first!
6468      * <p>
6469      * In order to set the matrix to an orthographic projection without post-multiplying it,
6470      * use {@link #setOrtho2DLH(double, double, double, double) setOrthoLH()}.
6471      * <p>
6472      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
6473      * 
6474      * @see #orthoLH(double, double, double, double, double, double, Matrix4x3d)
6475      * @see #setOrtho2DLH(double, double, double, double)
6476      * 
6477      * @param left
6478      *            the distance from the center to the left frustum edge
6479      * @param right
6480      *            the distance from the center to the right frustum edge
6481      * @param bottom
6482      *            the distance from the center to the bottom frustum edge
6483      * @param top
6484      *            the distance from the center to the top frustum edge
6485      * @param dest
6486      *            will hold the result
6487      * @return dest
6488      */
6489     public Matrix4x3d ortho2DLH(double left, double right, double bottom, double top, ref Matrix4x3d dest) {
6490         // calculate right matrix elements
6491         double rm00 = 2.0 / (right - left);
6492         double rm11 = 2.0 / (top - bottom);
6493         double rm30 = -(right + left) / (right - left);
6494         double rm31 = -(top + bottom) / (top - bottom);
6495 
6496         // perform optimized multiplication
6497         // compute the last column first, because other columns do not depend on it
6498         dest.m30 = m00 * rm30 + m10 * rm31 + m30;
6499         dest.m31 = m01 * rm30 + m11 * rm31 + m31;
6500         dest.m32 = m02 * rm30 + m12 * rm31 + m32;
6501         dest.m00 = m00 * rm00;
6502         dest.m01 = m01 * rm00;
6503         dest.m02 = m02 * rm00;
6504         dest.m10 = m10 * rm11;
6505         dest.m11 = m11 * rm11;
6506         dest.m12 = m12 * rm11;
6507         dest.m20 = m20;
6508         dest.m21 = m21;
6509         dest.m22 = m22;
6510         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
6511 
6512         return dest;
6513     }
6514 
6515     /**
6516      * Apply an orthographic projection transformation for a left-handed coordinate system to this matrix.
6517      * <p>
6518      * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double) orthoLH()} with
6519      * <code>zNear=-1</code> and <code>zFar=+1</code>.
6520      * <p>
6521      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the orthographic projection matrix,
6522      * then the new matrix will be <code>M * O</code>. So when transforming a
6523      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
6524      * orthographic projection transformation will be applied first!
6525      * <p>
6526      * In order to set the matrix to an orthographic projection without post-multiplying it,
6527      * use {@link #setOrtho2DLH(double, double, double, double) setOrtho2DLH()}.
6528      * <p>
6529      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
6530      * 
6531      * @see #orthoLH(double, double, double, double, double, double)
6532      * @see #setOrtho2DLH(double, double, double, double)
6533      * 
6534      * @param left
6535      *            the distance from the center to the left frustum edge
6536      * @param right
6537      *            the distance from the center to the right frustum edge
6538      * @param bottom
6539      *            the distance from the center to the bottom frustum edge
6540      * @param top
6541      *            the distance from the center to the top frustum edge
6542      * @return this
6543      */
6544     ref public Matrix4x3d ortho2DLH(double left, double right, double bottom, double top) return {
6545         ortho2DLH(left, right, bottom, top, this);
6546         return this;
6547     }
6548 
6549     /**
6550      * Set this matrix to be an orthographic projection transformation for a right-handed coordinate system.
6551      * <p>
6552      * This method is equivalent to calling {@link #setOrtho(double, double, double, double, double, double) setOrtho()} with
6553      * <code>zNear=-1</code> and <code>zFar=+1</code>.
6554      * <p>
6555      * In order to apply the orthographic projection to an already existing transformation,
6556      * use {@link #ortho2D(double, double, double, double) ortho2D()}.
6557      * <p>
6558      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
6559      * 
6560      * @see #setOrtho(double, double, double, double, double, double)
6561      * @see #ortho2D(double, double, double, double)
6562      * 
6563      * @param left
6564      *            the distance from the center to the left frustum edge
6565      * @param right
6566      *            the distance from the center to the right frustum edge
6567      * @param bottom
6568      *            the distance from the center to the bottom frustum edge
6569      * @param top
6570      *            the distance from the center to the top frustum edge
6571      * @return this
6572      */
6573     ref public Matrix4x3d setOrtho2D(double left, double right, double bottom, double top) return {
6574         m00 = 2.0 / (right - left);
6575         m01 = 0.0;
6576         m02 = 0.0;
6577         m10 = 0.0;
6578         m11 = 2.0 / (top - bottom);
6579         m12 = 0.0;
6580         m20 = 0.0;
6581         m21 = 0.0;
6582         m22 = -1.0;
6583         m30 = -(right + left) / (right - left);
6584         m31 = -(top + bottom) / (top - bottom);
6585         m32 = 0.0;
6586         properties = 0;
6587         return this;
6588     }
6589 
6590     /**
6591      * Set this matrix to be an orthographic projection transformation for a left-handed coordinate system.
6592      * <p>
6593      * This method is equivalent to calling {@link #setOrtho(double, double, double, double, double, double) setOrthoLH()} with
6594      * <code>zNear=-1</code> and <code>zFar=+1</code>.
6595      * <p>
6596      * In order to apply the orthographic projection to an already existing transformation,
6597      * use {@link #ortho2DLH(double, double, double, double) ortho2DLH()}.
6598      * <p>
6599      * Reference: <a href="http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho">http://www.songho.ca</a>
6600      * 
6601      * @see #setOrthoLH(double, double, double, double, double, double)
6602      * @see #ortho2DLH(double, double, double, double)
6603      * 
6604      * @param left
6605      *            the distance from the center to the left frustum edge
6606      * @param right
6607      *            the distance from the center to the right frustum edge
6608      * @param bottom
6609      *            the distance from the center to the bottom frustum edge
6610      * @param top
6611      *            the distance from the center to the top frustum edge
6612      * @return this
6613      */
6614     ref public Matrix4x3d setOrtho2DLH(double left, double right, double bottom, double top) return {
6615         m00 = 2.0 / (right - left);
6616         m01 = 0.0;
6617         m02 = 0.0;
6618         m10 = 0.0;
6619         m11 = 2.0 / (top - bottom);
6620         m12 = 0.0;
6621         m20 = 0.0;
6622         m21 = 0.0;
6623         m22 = 1.0;
6624         m30 = -(right + left) / (right - left);
6625         m31 = -(top + bottom) / (top - bottom);
6626         m32 = 0.0;
6627         properties = 0;
6628         return this;
6629     }
6630 
6631     /**
6632      * Apply a rotation transformation to this matrix to make <code>-z</code> point along <code>dir</code>. 
6633      * <p>
6634      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookalong rotation matrix,
6635      * then the new matrix will be <code>M * L</code>. So when transforming a
6636      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, the
6637      * lookalong rotation transformation will be applied first!
6638      * <p>
6639      * This is equivalent to calling
6640      * {@link #lookAt(Vector3d, Vector3d, Vector3d) lookAt}
6641      * with <code>eye = (0, 0, 0)</code> and <code>center = dir</code>.
6642      * <p>
6643      * In order to set the matrix to a lookalong transformation without post-multiplying it,
6644      * use {@link #setLookAlong(Vector3d, Vector3d) setLookAlong()}.
6645      * 
6646      * @see #lookAlong(double, double, double, double, double, double)
6647      * @see #lookAt(Vector3d, Vector3d, Vector3d)
6648      * @see #setLookAlong(Vector3d, Vector3d)
6649      * 
6650      * @param dir
6651      *            the direction in space to look along
6652      * @param up
6653      *            the direction of 'up'
6654      * @return this
6655      */
6656     ref public Matrix4x3d lookAlong(ref Vector3d dir, Vector3d up) return {
6657         lookAlong(dir.x, dir.y, dir.z, up.x, up.y, up.z, this);
6658         return this;
6659     }
6660 
6661     /**
6662      * Apply a rotation transformation to this matrix to make <code>-z</code> point along <code>dir</code>
6663      * and store the result in <code>dest</code>. 
6664      * <p>
6665      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookalong rotation matrix,
6666      * then the new matrix will be <code>M * L</code>. So when transforming a
6667      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, the
6668      * lookalong rotation transformation will be applied first!
6669      * <p>
6670      * This is equivalent to calling
6671      * {@link #lookAt(Vector3d, Vector3d, Vector3d) lookAt}
6672      * with <code>eye = (0, 0, 0)</code> and <code>center = dir</code>.
6673      * <p>
6674      * In order to set the matrix to a lookalong transformation without post-multiplying it,
6675      * use {@link #setLookAlong(Vector3d, Vector3d) setLookAlong()}.
6676      * 
6677      * @see #lookAlong(double, double, double, double, double, double)
6678      * @see #lookAt(Vector3d, Vector3d, Vector3d)
6679      * @see #setLookAlong(Vector3d, Vector3d)
6680      * 
6681      * @param dir
6682      *            the direction in space to look along
6683      * @param up
6684      *            the direction of 'up'
6685      * @param dest
6686      *            will hold the result
6687      * @return dest
6688      */
6689     public Matrix4x3d lookAlong(ref Vector3d dir, Vector3d up, ref Matrix4x3d dest) {
6690         return lookAlong(dir.x, dir.y, dir.z, up.x, up.y, up.z, dest);
6691     }
6692 
6693     /**
6694      * Apply a rotation transformation to this matrix to make <code>-z</code> point along <code>dir</code>
6695      * and store the result in <code>dest</code>. 
6696      * <p>
6697      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookalong rotation matrix,
6698      * then the new matrix will be <code>M * L</code>. So when transforming a
6699      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, the
6700      * lookalong rotation transformation will be applied first!
6701      * <p>
6702      * This is equivalent to calling
6703      * {@link #lookAt(double, double, double, double, double, double, double, double, double) lookAt()}
6704      * with <code>eye = (0, 0, 0)</code> and <code>center = dir</code>.
6705      * <p>
6706      * In order to set the matrix to a lookalong transformation without post-multiplying it,
6707      * use {@link #setLookAlong(double, double, double, double, double, double) setLookAlong()}
6708      * 
6709      * @see #lookAt(double, double, double, double, double, double, double, double, double)
6710      * @see #setLookAlong(double, double, double, double, double, double)
6711      * 
6712      * @param dirX
6713      *              the x-coordinate of the direction to look along
6714      * @param dirY
6715      *              the y-coordinate of the direction to look along
6716      * @param dirZ
6717      *              the z-coordinate of the direction to look along
6718      * @param upX
6719      *              the x-coordinate of the up vector
6720      * @param upY
6721      *              the y-coordinate of the up vector
6722      * @param upZ
6723      *              the z-coordinate of the up vector
6724      * @param dest
6725      *              will hold the result
6726      * @return dest
6727      */
6728     public Matrix4x3d lookAlong(double dirX, double dirY, double dirZ,
6729                                 double upX, double upY, double upZ, ref Matrix4x3d dest) {
6730         if ((properties & PROPERTY_IDENTITY) != 0)
6731             return setLookAlong(dirX, dirY, dirZ, upX, upY, upZ);
6732 
6733         // Normalize direction
6734         double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
6735         dirX *= -invDirLength;
6736         dirY *= -invDirLength;
6737         dirZ *= -invDirLength;
6738         // left = up x direction
6739         double leftX, leftY, leftZ;
6740         leftX = upY * dirZ - upZ * dirY;
6741         leftY = upZ * dirX - upX * dirZ;
6742         leftZ = upX * dirY - upY * dirX;
6743         // normalize left
6744         double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
6745         leftX *= invLeftLength;
6746         leftY *= invLeftLength;
6747         leftZ *= invLeftLength;
6748         // up = direction x left
6749         double upnX = dirY * leftZ - dirZ * leftY;
6750         double upnY = dirZ * leftX - dirX * leftZ;
6751         double upnZ = dirX * leftY - dirY * leftX;
6752 
6753         // calculate right matrix elements
6754         double rm00 = leftX;
6755         double rm01 = upnX;
6756         double rm02 = dirX;
6757         double rm10 = leftY;
6758         double rm11 = upnY;
6759         double rm12 = dirY;
6760         double rm20 = leftZ;
6761         double rm21 = upnZ;
6762         double rm22 = dirZ;
6763 
6764         // perform optimized matrix multiplication
6765         // introduce temporaries for dependent results
6766         double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
6767         double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
6768         double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
6769         double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
6770         double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
6771         double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
6772         dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
6773         dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
6774         dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
6775         // set the rest of the matrix elements
6776         dest.m00 = nm00;
6777         dest.m01 = nm01;
6778         dest.m02 = nm02;
6779         dest.m10 = nm10;
6780         dest.m11 = nm11;
6781         dest.m12 = nm12;
6782         dest.m30 = m30;
6783         dest.m31 = m31;
6784         dest.m32 = m32;
6785         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
6786 
6787         return dest;
6788     }
6789 
6790     /**
6791      * Apply a rotation transformation to this matrix to make <code>-z</code> point along <code>dir</code>. 
6792      * <p>
6793      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookalong rotation matrix,
6794      * then the new matrix will be <code>M * L</code>. So when transforming a
6795      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>, the
6796      * lookalong rotation transformation will be applied first!
6797      * <p>
6798      * This is equivalent to calling
6799      * {@link #lookAt(double, double, double, double, double, double, double, double, double) lookAt()}
6800      * with <code>eye = (0, 0, 0)</code> and <code>center = dir</code>.
6801      * <p>
6802      * In order to set the matrix to a lookalong transformation without post-multiplying it,
6803      * use {@link #setLookAlong(double, double, double, double, double, double) setLookAlong()}
6804      * 
6805      * @see #lookAt(double, double, double, double, double, double, double, double, double)
6806      * @see #setLookAlong(double, double, double, double, double, double)
6807      * 
6808      * @param dirX
6809      *              the x-coordinate of the direction to look along
6810      * @param dirY
6811      *              the y-coordinate of the direction to look along
6812      * @param dirZ
6813      *              the z-coordinate of the direction to look along
6814      * @param upX
6815      *              the x-coordinate of the up vector
6816      * @param upY
6817      *              the y-coordinate of the up vector
6818      * @param upZ
6819      *              the z-coordinate of the up vector
6820      * @return this
6821      */
6822     ref public Matrix4x3d lookAlong(double dirX, double dirY, double dirZ,
6823                                 double upX, double upY, double upZ) return {
6824         lookAlong(dirX, dirY, dirZ, upX, upY, upZ, this);
6825         return this;
6826     }
6827 
6828     /**
6829      * Set this matrix to a rotation transformation to make <code>-z</code>
6830      * point along <code>dir</code>.
6831      * <p>
6832      * This is equivalent to calling
6833      * {@link #setLookAt(Vector3d, Vector3d, Vector3d) setLookAt()} 
6834      * with <code>eye = (0, 0, 0)</code> and <code>center = dir</code>.
6835      * <p>
6836      * In order to apply the lookalong transformation to any previous existing transformation,
6837      * use {@link #lookAlong(Vector3d, Vector3d)}.
6838      * 
6839      * @see #setLookAlong(Vector3d, Vector3d)
6840      * @see #lookAlong(Vector3d, Vector3d)
6841      * 
6842      * @param dir
6843      *            the direction in space to look along
6844      * @param up
6845      *            the direction of 'up'
6846      * @return this
6847      */
6848     ref public Matrix4x3d setLookAlong(ref Vector3d dir, Vector3d up) return {
6849         return setLookAlong(dir.x, dir.y, dir.z, up.x, up.y, up.z);
6850     }
6851 
6852     /**
6853      * Set this matrix to a rotation transformation to make <code>-z</code>
6854      * point along <code>dir</code>.
6855      * <p>
6856      * This is equivalent to calling
6857      * {@link #setLookAt(double, double, double, double, double, double, double, double, double)
6858      * setLookAt()} with <code>eye = (0, 0, 0)</code> and <code>center = dir</code>.
6859      * <p>
6860      * In order to apply the lookalong transformation to any previous existing transformation,
6861      * use {@link #lookAlong(double, double, double, double, double, double) lookAlong()}
6862      * 
6863      * @see #setLookAlong(double, double, double, double, double, double)
6864      * @see #lookAlong(double, double, double, double, double, double)
6865      * 
6866      * @param dirX
6867      *              the x-coordinate of the direction to look along
6868      * @param dirY
6869      *              the y-coordinate of the direction to look along
6870      * @param dirZ
6871      *              the z-coordinate of the direction to look along
6872      * @param upX
6873      *              the x-coordinate of the up vector
6874      * @param upY
6875      *              the y-coordinate of the up vector
6876      * @param upZ
6877      *              the z-coordinate of the up vector
6878      * @return this
6879      */
6880     ref public Matrix4x3d setLookAlong(double dirX, double dirY, double dirZ,
6881                                    double upX, double upY, double upZ) return {
6882         // Normalize direction
6883         double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
6884         dirX *= -invDirLength;
6885         dirY *= -invDirLength;
6886         dirZ *= -invDirLength;
6887         // left = up x direction
6888         double leftX, leftY, leftZ;
6889         leftX = upY * dirZ - upZ * dirY;
6890         leftY = upZ * dirX - upX * dirZ;
6891         leftZ = upX * dirY - upY * dirX;
6892         // normalize left
6893         double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
6894         leftX *= invLeftLength;
6895         leftY *= invLeftLength;
6896         leftZ *= invLeftLength;
6897         // up = direction x left
6898         double upnX = dirY * leftZ - dirZ * leftY;
6899         double upnY = dirZ * leftX - dirX * leftZ;
6900         double upnZ = dirX * leftY - dirY * leftX;
6901 
6902         m00 = leftX;
6903         m01 = upnX;
6904         m02 = dirX;
6905         m10 = leftY;
6906         m11 = upnY;
6907         m12 = dirY;
6908         m20 = leftZ;
6909         m21 = upnZ;
6910         m22 = dirZ;
6911         m30 = 0.0;
6912         m31 = 0.0;
6913         m32 = 0.0;
6914         properties = PROPERTY_ORTHONORMAL;
6915 
6916         return this;
6917     }
6918 
6919     /**
6920      * Set this matrix to be a "lookat" transformation for a right-handed coordinate system, that aligns
6921      * <code>-z</code> with <code>center - eye</code>.
6922      * <p>
6923      * In order to not make use of vectors to specify <code>eye</code>, <code>center</code> and <code>up</code> but use primitives,
6924      * like in the GLU function, use {@link #setLookAt(double, double, double, double, double, double, double, double, double) setLookAt()}
6925      * instead.
6926      * <p>
6927      * In order to apply the lookat transformation to a previous existing transformation,
6928      * use {@link #lookAt(Vector3d, Vector3d, Vector3d) lookAt()}.
6929      * 
6930      * @see #setLookAt(double, double, double, double, double, double, double, double, double)
6931      * @see #lookAt(Vector3d, Vector3d, Vector3d)
6932      * 
6933      * @param eye
6934      *            the position of the camera
6935      * @param center
6936      *            the point in space to look at
6937      * @param up
6938      *            the direction of 'up'
6939      * @return this
6940      */
6941     ref public Matrix4x3d setLookAt(Vector3d eye, Vector3d center, Vector3d up) return {
6942         return setLookAt(eye.x, eye.y, eye.z, center.x, center.y, center.z, up.x, up.y, up.z);
6943     }
6944 
6945     /**
6946      * Set this matrix to be a "lookat" transformation for a right-handed coordinate system, 
6947      * that aligns <code>-z</code> with <code>center - eye</code>.
6948      * <p>
6949      * In order to apply the lookat transformation to a previous existing transformation,
6950      * use {@link #lookAt(double, double, double, double, double, double, double, double, double) lookAt}.
6951      * 
6952      * @see #setLookAt(Vector3d, Vector3d, Vector3d)
6953      * @see #lookAt(double, double, double, double, double, double, double, double, double)
6954      * 
6955      * @param eyeX
6956      *              the x-coordinate of the eye/camera location
6957      * @param eyeY
6958      *              the y-coordinate of the eye/camera location
6959      * @param eyeZ
6960      *              the z-coordinate of the eye/camera location
6961      * @param centerX
6962      *              the x-coordinate of the point to look at
6963      * @param centerY
6964      *              the y-coordinate of the point to look at
6965      * @param centerZ
6966      *              the z-coordinate of the point to look at
6967      * @param upX
6968      *              the x-coordinate of the up vector
6969      * @param upY
6970      *              the y-coordinate of the up vector
6971      * @param upZ
6972      *              the z-coordinate of the up vector
6973      * @return this
6974      */
6975     ref public Matrix4x3d setLookAt(double eyeX, double eyeY, double eyeZ,
6976                                 double centerX, double centerY, double centerZ,
6977                                 double upX, double upY, double upZ) return {
6978         // Compute direction from position to lookAt
6979         double dirX, dirY, dirZ;
6980         dirX = eyeX - centerX;
6981         dirY = eyeY - centerY;
6982         dirZ = eyeZ - centerZ;
6983         // Normalize direction
6984         double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
6985         dirX *= invDirLength;
6986         dirY *= invDirLength;
6987         dirZ *= invDirLength;
6988         // left = up x direction
6989         double leftX, leftY, leftZ;
6990         leftX = upY * dirZ - upZ * dirY;
6991         leftY = upZ * dirX - upX * dirZ;
6992         leftZ = upX * dirY - upY * dirX;
6993         // normalize left
6994         double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
6995         leftX *= invLeftLength;
6996         leftY *= invLeftLength;
6997         leftZ *= invLeftLength;
6998         // up = direction x left
6999         double upnX = dirY * leftZ - dirZ * leftY;
7000         double upnY = dirZ * leftX - dirX * leftZ;
7001         double upnZ = dirX * leftY - dirY * leftX;
7002 
7003         m00 = leftX;
7004         m01 = upnX;
7005         m02 = dirX;
7006         m10 = leftY;
7007         m11 = upnY;
7008         m12 = dirY;
7009         m20 = leftZ;
7010         m21 = upnZ;
7011         m22 = dirZ;
7012         m30 = -(leftX * eyeX + leftY * eyeY + leftZ * eyeZ);
7013         m31 = -(upnX * eyeX + upnY * eyeY + upnZ * eyeZ);
7014         m32 = -(dirX * eyeX + dirY * eyeY + dirZ * eyeZ);
7015         properties = PROPERTY_ORTHONORMAL;
7016 
7017         return this;
7018     }
7019 
7020     /**
7021      * Apply a "lookat" transformation to this matrix for a right-handed coordinate system, 
7022      * that aligns <code>-z</code> with <code>center - eye</code> and store the result in <code>dest</code>.
7023      * <p>
7024      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix,
7025      * then the new matrix will be <code>M * L</code>. So when transforming a
7026      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>,
7027      * the lookat transformation will be applied first!
7028      * <p>
7029      * In order to set the matrix to a lookat transformation without post-multiplying it,
7030      * use {@link #setLookAt(Vector3d, Vector3d, Vector3d)}.
7031      * 
7032      * @see #lookAt(double, double, double, double, double, double, double, double, double)
7033      * @see #setLookAlong(Vector3d, Vector3d)
7034      * 
7035      * @param eye
7036      *            the position of the camera
7037      * @param center
7038      *            the point in space to look at
7039      * @param up
7040      *            the direction of 'up'
7041      * @param dest
7042      *            will hold the result
7043      * @return dest
7044      */
7045     public Matrix4x3d lookAt(Vector3d eye, Vector3d center, Vector3d up, ref Matrix4x3d dest) {
7046         return lookAt(eye.x, eye.y, eye.z, center.x, center.y, center.z, up.x, up.y, up.z, dest);
7047     }
7048 
7049     /**
7050      * Apply a "lookat" transformation to this matrix for a right-handed coordinate system, 
7051      * that aligns <code>-z</code> with <code>center - eye</code>.
7052      * <p>
7053      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix,
7054      * then the new matrix will be <code>M * L</code>. So when transforming a
7055      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>,
7056      * the lookat transformation will be applied first!
7057      * <p>
7058      * In order to set the matrix to a lookat transformation without post-multiplying it,
7059      * use {@link #setLookAt(Vector3d, Vector3d, Vector3d)}.
7060      * 
7061      * @see #lookAt(double, double, double, double, double, double, double, double, double)
7062      * @see #setLookAlong(Vector3d, Vector3d)
7063      * 
7064      * @param eye
7065      *            the position of the camera
7066      * @param center
7067      *            the point in space to look at
7068      * @param up
7069      *            the direction of 'up'
7070      * @return this
7071      */
7072     ref public Matrix4x3d lookAt(Vector3d eye, Vector3d center, Vector3d up) return {
7073         lookAt(eye.x, eye.y, eye.z, center.x, center.y, center.z, up.x, up.y, up.z, this);
7074         return this;
7075     }
7076 
7077     /**
7078      * Apply a "lookat" transformation to this matrix for a right-handed coordinate system, 
7079      * that aligns <code>-z</code> with <code>center - eye</code> and store the result in <code>dest</code>.
7080      * <p>
7081      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix,
7082      * then the new matrix will be <code>M * L</code>. So when transforming a
7083      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>,
7084      * the lookat transformation will be applied first!
7085      * <p>
7086      * In order to set the matrix to a lookat transformation without post-multiplying it,
7087      * use {@link #setLookAt(double, double, double, double, double, double, double, double, double) setLookAt()}.
7088      * 
7089      * @see #lookAt(Vector3d, Vector3d, Vector3d)
7090      * @see #setLookAt(double, double, double, double, double, double, double, double, double)
7091      * 
7092      * @param eyeX
7093      *              the x-coordinate of the eye/camera location
7094      * @param eyeY
7095      *              the y-coordinate of the eye/camera location
7096      * @param eyeZ
7097      *              the z-coordinate of the eye/camera location
7098      * @param centerX
7099      *              the x-coordinate of the point to look at
7100      * @param centerY
7101      *              the y-coordinate of the point to look at
7102      * @param centerZ
7103      *              the z-coordinate of the point to look at
7104      * @param upX
7105      *              the x-coordinate of the up vector
7106      * @param upY
7107      *              the y-coordinate of the up vector
7108      * @param upZ
7109      *              the z-coordinate of the up vector
7110      * @param dest
7111      *          will hold the result
7112      * @return dest
7113      */
7114     public Matrix4x3d lookAt(double eyeX, double eyeY, double eyeZ,
7115                              double centerX, double centerY, double centerZ,
7116                              double upX, double upY, double upZ, ref Matrix4x3d dest) {
7117         if ((properties & PROPERTY_IDENTITY) != 0)
7118             return dest.setLookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);
7119         return lookAtGeneric(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, dest);
7120     }
7121     private Matrix4x3d lookAtGeneric(double eyeX, double eyeY, double eyeZ,
7122                                      double centerX, double centerY, double centerZ,
7123                                      double upX, double upY, double upZ, ref Matrix4x3d dest) {
7124         // Compute direction from position to lookAt
7125         double dirX, dirY, dirZ;
7126         dirX = eyeX - centerX;
7127         dirY = eyeY - centerY;
7128         dirZ = eyeZ - centerZ;
7129         // Normalize direction
7130         double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
7131         dirX *= invDirLength;
7132         dirY *= invDirLength;
7133         dirZ *= invDirLength;
7134         // left = up x direction
7135         double leftX, leftY, leftZ;
7136         leftX = upY * dirZ - upZ * dirY;
7137         leftY = upZ * dirX - upX * dirZ;
7138         leftZ = upX * dirY - upY * dirX;
7139         // normalize left
7140         double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
7141         leftX *= invLeftLength;
7142         leftY *= invLeftLength;
7143         leftZ *= invLeftLength;
7144         // up = direction x left
7145         double upnX = dirY * leftZ - dirZ * leftY;
7146         double upnY = dirZ * leftX - dirX * leftZ;
7147         double upnZ = dirX * leftY - dirY * leftX;
7148 
7149         // calculate right matrix elements
7150         double rm00 = leftX;
7151         double rm01 = upnX;
7152         double rm02 = dirX;
7153         double rm10 = leftY;
7154         double rm11 = upnY;
7155         double rm12 = dirY;
7156         double rm20 = leftZ;
7157         double rm21 = upnZ;
7158         double rm22 = dirZ;
7159         double rm30 = -(leftX * eyeX + leftY * eyeY + leftZ * eyeZ);
7160         double rm31 = -(upnX * eyeX + upnY * eyeY + upnZ * eyeZ);
7161         double rm32 = -(dirX * eyeX + dirY * eyeY + dirZ * eyeZ);
7162 
7163         // perform optimized matrix multiplication
7164         // compute last column first, because others do not depend on it
7165         dest.m30 = m00 * rm30 + m10 * rm31 + m20 * rm32 + m30;
7166         dest.m31 = m01 * rm30 + m11 * rm31 + m21 * rm32 + m31;
7167         dest.m32 = m02 * rm30 + m12 * rm31 + m22 * rm32 + m32;
7168         // introduce temporaries for dependent results
7169         double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
7170         double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
7171         double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
7172         double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
7173         double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
7174         double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
7175         dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
7176         dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
7177         dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
7178         // set the rest of the matrix elements
7179         dest.m00 = nm00;
7180         dest.m01 = nm01;
7181         dest.m02 = nm02;
7182         dest.m10 = nm10;
7183         dest.m11 = nm11;
7184         dest.m12 = nm12;
7185         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
7186 
7187         return dest;
7188     }
7189 
7190     /**
7191      * Apply a "lookat" transformation to this matrix for a right-handed coordinate system, 
7192      * that aligns <code>-z</code> with <code>center - eye</code>.
7193      * <p>
7194      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix,
7195      * then the new matrix will be <code>M * L</code>. So when transforming a
7196      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>,
7197      * the lookat transformation will be applied first!
7198      * <p>
7199      * In order to set the matrix to a lookat transformation without post-multiplying it,
7200      * use {@link #setLookAt(double, double, double, double, double, double, double, double, double) setLookAt()}.
7201      * 
7202      * @see #lookAt(Vector3d, Vector3d, Vector3d)
7203      * @see #setLookAt(double, double, double, double, double, double, double, double, double)
7204      * 
7205      * @param eyeX
7206      *              the x-coordinate of the eye/camera location
7207      * @param eyeY
7208      *              the y-coordinate of the eye/camera location
7209      * @param eyeZ
7210      *              the z-coordinate of the eye/camera location
7211      * @param centerX
7212      *              the x-coordinate of the point to look at
7213      * @param centerY
7214      *              the y-coordinate of the point to look at
7215      * @param centerZ
7216      *              the z-coordinate of the point to look at
7217      * @param upX
7218      *              the x-coordinate of the up vector
7219      * @param upY
7220      *              the y-coordinate of the up vector
7221      * @param upZ
7222      *              the z-coordinate of the up vector
7223      * @return this
7224      */
7225     ref public Matrix4x3d lookAt(double eyeX, double eyeY, double eyeZ,
7226                              double centerX, double centerY, double centerZ,
7227                              double upX, double upY, double upZ) return {
7228         lookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, this);
7229         return this;
7230     }
7231 
7232     /**
7233      * Set this matrix to be a "lookat" transformation for a left-handed coordinate system, that aligns
7234      * <code>+z</code> with <code>center - eye</code>.
7235      * <p>
7236      * In order to not make use of vectors to specify <code>eye</code>, <code>center</code> and <code>up</code> but use primitives,
7237      * like in the GLU function, use {@link #setLookAtLH(double, double, double, double, double, double, double, double, double) setLookAtLH()}
7238      * instead.
7239      * <p>
7240      * In order to apply the lookat transformation to a previous existing transformation,
7241      * use {@link #lookAtLH(Vector3d, Vector3d, Vector3d) lookAt()}.
7242      * 
7243      * @see #setLookAtLH(double, double, double, double, double, double, double, double, double)
7244      * @see #lookAtLH(Vector3d, Vector3d, Vector3d)
7245      * 
7246      * @param eye
7247      *            the position of the camera
7248      * @param center
7249      *            the point in space to look at
7250      * @param up
7251      *            the direction of 'up'
7252      * @return this
7253      */
7254     ref public Matrix4x3d setLookAtLH(Vector3d eye, Vector3d center, Vector3d up) return {
7255         return setLookAtLH(eye.x, eye.y, eye.z, center.x, center.y, center.z, up.x, up.y, up.z);
7256     }
7257 
7258     /**
7259      * Set this matrix to be a "lookat" transformation for a left-handed coordinate system, 
7260      * that aligns <code>+z</code> with <code>center - eye</code>.
7261      * <p>
7262      * In order to apply the lookat transformation to a previous existing transformation,
7263      * use {@link #lookAtLH(double, double, double, double, double, double, double, double, double) lookAtLH}.
7264      * 
7265      * @see #setLookAtLH(Vector3d, Vector3d, Vector3d)
7266      * @see #lookAtLH(double, double, double, double, double, double, double, double, double)
7267      * 
7268      * @param eyeX
7269      *              the x-coordinate of the eye/camera location
7270      * @param eyeY
7271      *              the y-coordinate of the eye/camera location
7272      * @param eyeZ
7273      *              the z-coordinate of the eye/camera location
7274      * @param centerX
7275      *              the x-coordinate of the point to look at
7276      * @param centerY
7277      *              the y-coordinate of the point to look at
7278      * @param centerZ
7279      *              the z-coordinate of the point to look at
7280      * @param upX
7281      *              the x-coordinate of the up vector
7282      * @param upY
7283      *              the y-coordinate of the up vector
7284      * @param upZ
7285      *              the z-coordinate of the up vector
7286      * @return this
7287      */
7288     ref public Matrix4x3d setLookAtLH(double eyeX, double eyeY, double eyeZ,
7289                                   double centerX, double centerY, double centerZ,
7290                                   double upX, double upY, double upZ) return {
7291         // Compute direction from position to lookAt
7292         double dirX, dirY, dirZ;
7293         dirX = centerX - eyeX;
7294         dirY = centerY - eyeY;
7295         dirZ = centerZ - eyeZ;
7296         // Normalize direction
7297         double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
7298         dirX *= invDirLength;
7299         dirY *= invDirLength;
7300         dirZ *= invDirLength;
7301         // left = up x direction
7302         double leftX, leftY, leftZ;
7303         leftX = upY * dirZ - upZ * dirY;
7304         leftY = upZ * dirX - upX * dirZ;
7305         leftZ = upX * dirY - upY * dirX;
7306         // normalize left
7307         double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
7308         leftX *= invLeftLength;
7309         leftY *= invLeftLength;
7310         leftZ *= invLeftLength;
7311         // up = direction x left
7312         double upnX = dirY * leftZ - dirZ * leftY;
7313         double upnY = dirZ * leftX - dirX * leftZ;
7314         double upnZ = dirX * leftY - dirY * leftX;
7315 
7316         m00 = leftX;
7317         m01 = upnX;
7318         m02 = dirX;
7319         m10 = leftY;
7320         m11 = upnY;
7321         m12 = dirY;
7322         m20 = leftZ;
7323         m21 = upnZ;
7324         m22 = dirZ;
7325         m30 = -(leftX * eyeX + leftY * eyeY + leftZ * eyeZ);
7326         m31 = -(upnX * eyeX + upnY * eyeY + upnZ * eyeZ);
7327         m32 = -(dirX * eyeX + dirY * eyeY + dirZ * eyeZ);
7328         properties = PROPERTY_ORTHONORMAL;
7329 
7330         return this;
7331     }
7332 
7333     /**
7334      * Apply a "lookat" transformation to this matrix for a left-handed coordinate system, 
7335      * that aligns <code>+z</code> with <code>center - eye</code> and store the result in <code>dest</code>.
7336      * <p>
7337      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix,
7338      * then the new matrix will be <code>M * L</code>. So when transforming a
7339      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>,
7340      * the lookat transformation will be applied first!
7341      * <p>
7342      * In order to set the matrix to a lookat transformation without post-multiplying it,
7343      * use {@link #setLookAtLH(Vector3d, Vector3d, Vector3d)}.
7344      * 
7345      * @see #lookAtLH(double, double, double, double, double, double, double, double, double)
7346      * 
7347      * @param eye
7348      *            the position of the camera
7349      * @param center
7350      *            the point in space to look at
7351      * @param up
7352      *            the direction of 'up'
7353      * @param dest
7354      *            will hold the result
7355      * @return dest
7356      */
7357     public Matrix4x3d lookAtLH(Vector3d eye, Vector3d center, Vector3d up, ref Matrix4x3d dest) {
7358         return lookAtLH(eye.x, eye.y, eye.z, center.x, center.y, center.z, up.x, up.y, up.z, dest);
7359     }
7360 
7361     /**
7362      * Apply a "lookat" transformation to this matrix for a left-handed coordinate system, 
7363      * that aligns <code>+z</code> with <code>center - eye</code>.
7364      * <p>
7365      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix,
7366      * then the new matrix will be <code>M * L</code>. So when transforming a
7367      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>,
7368      * the lookat transformation will be applied first!
7369      * <p>
7370      * In order to set the matrix to a lookat transformation without post-multiplying it,
7371      * use {@link #setLookAtLH(Vector3d, Vector3d, Vector3d)}.
7372      * 
7373      * @see #lookAtLH(double, double, double, double, double, double, double, double, double)
7374      * 
7375      * @param eye
7376      *            the position of the camera
7377      * @param center
7378      *            the point in space to look at
7379      * @param up
7380      *            the direction of 'up'
7381      * @return this
7382      */
7383     ref public Matrix4x3d lookAtLH(Vector3d eye, Vector3d center, Vector3d up) return {
7384         lookAtLH(eye.x, eye.y, eye.z, center.x, center.y, center.z, up.x, up.y, up.z, this);
7385         return this;
7386     }
7387 
7388     /**
7389      * Apply a "lookat" transformation to this matrix for a left-handed coordinate system, 
7390      * that aligns <code>+z</code> with <code>center - eye</code> and store the result in <code>dest</code>.
7391      * <p>
7392      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix,
7393      * then the new matrix will be <code>M * L</code>. So when transforming a
7394      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>,
7395      * the lookat transformation will be applied first!
7396      * <p>
7397      * In order to set the matrix to a lookat transformation without post-multiplying it,
7398      * use {@link #setLookAtLH(double, double, double, double, double, double, double, double, double) setLookAtLH()}.
7399      * 
7400      * @see #lookAtLH(Vector3d, Vector3d, Vector3d)
7401      * @see #setLookAtLH(double, double, double, double, double, double, double, double, double)
7402      * 
7403      * @param eyeX
7404      *              the x-coordinate of the eye/camera location
7405      * @param eyeY
7406      *              the y-coordinate of the eye/camera location
7407      * @param eyeZ
7408      *              the z-coordinate of the eye/camera location
7409      * @param centerX
7410      *              the x-coordinate of the point to look at
7411      * @param centerY
7412      *              the y-coordinate of the point to look at
7413      * @param centerZ
7414      *              the z-coordinate of the point to look at
7415      * @param upX
7416      *              the x-coordinate of the up vector
7417      * @param upY
7418      *              the y-coordinate of the up vector
7419      * @param upZ
7420      *              the z-coordinate of the up vector
7421      * @param dest
7422      *          will hold the result
7423      * @return dest
7424      */
7425     public Matrix4x3d lookAtLH(double eyeX, double eyeY, double eyeZ,
7426                                double centerX, double centerY, double centerZ,
7427                                double upX, double upY, double upZ, ref Matrix4x3d dest) {
7428         if ((properties & PROPERTY_IDENTITY) != 0)
7429             return dest.setLookAtLH(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);
7430         return lookAtLHGeneric(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, dest);
7431     }
7432     private Matrix4x3d lookAtLHGeneric(double eyeX, double eyeY, double eyeZ,
7433                                        double centerX, double centerY, double centerZ,
7434                                        double upX, double upY, double upZ, ref Matrix4x3d dest) {
7435         // Compute direction from position to lookAt
7436         double dirX, dirY, dirZ;
7437         dirX = centerX - eyeX;
7438         dirY = centerY - eyeY;
7439         dirZ = centerZ - eyeZ;
7440         // Normalize direction
7441         double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
7442         dirX *= invDirLength;
7443         dirY *= invDirLength;
7444         dirZ *= invDirLength;
7445         // left = up x direction
7446         double leftX, leftY, leftZ;
7447         leftX = upY * dirZ - upZ * dirY;
7448         leftY = upZ * dirX - upX * dirZ;
7449         leftZ = upX * dirY - upY * dirX;
7450         // normalize left
7451         double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
7452         leftX *= invLeftLength;
7453         leftY *= invLeftLength;
7454         leftZ *= invLeftLength;
7455         // up = direction x left
7456         double upnX = dirY * leftZ - dirZ * leftY;
7457         double upnY = dirZ * leftX - dirX * leftZ;
7458         double upnZ = dirX * leftY - dirY * leftX;
7459 
7460         // calculate right matrix elements
7461         double rm00 = leftX;
7462         double rm01 = upnX;
7463         double rm02 = dirX;
7464         double rm10 = leftY;
7465         double rm11 = upnY;
7466         double rm12 = dirY;
7467         double rm20 = leftZ;
7468         double rm21 = upnZ;
7469         double rm22 = dirZ;
7470         double rm30 = -(leftX * eyeX + leftY * eyeY + leftZ * eyeZ);
7471         double rm31 = -(upnX * eyeX + upnY * eyeY + upnZ * eyeZ);
7472         double rm32 = -(dirX * eyeX + dirY * eyeY + dirZ * eyeZ);
7473 
7474         // perform optimized matrix multiplication
7475         // compute last column first, because others do not depend on it
7476         dest.m30 = m00 * rm30 + m10 * rm31 + m20 * rm32 + m30;
7477         dest.m31 = m01 * rm30 + m11 * rm31 + m21 * rm32 + m31;
7478         dest.m32 = m02 * rm30 + m12 * rm31 + m22 * rm32 + m32;
7479         // introduce temporaries for dependent results
7480         double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
7481         double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
7482         double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
7483         double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
7484         double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
7485         double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
7486         dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
7487         dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
7488         dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
7489         // set the rest of the matrix elements
7490         dest.m00 = nm00;
7491         dest.m01 = nm01;
7492         dest.m02 = nm02;
7493         dest.m10 = nm10;
7494         dest.m11 = nm11;
7495         dest.m12 = nm12;
7496         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
7497 
7498         return dest;
7499     }
7500 
7501     /**
7502      * Apply a "lookat" transformation to this matrix for a left-handed coordinate system, 
7503      * that aligns <code>+z</code> with <code>center - eye</code>.
7504      * <p>
7505      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix,
7506      * then the new matrix will be <code>M * L</code>. So when transforming a
7507      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>,
7508      * the lookat transformation will be applied first!
7509      * <p>
7510      * In order to set the matrix to a lookat transformation without post-multiplying it,
7511      * use {@link #setLookAtLH(double, double, double, double, double, double, double, double, double) setLookAtLH()}.
7512      * 
7513      * @see #lookAtLH(Vector3d, Vector3d, Vector3d)
7514      * @see #setLookAtLH(double, double, double, double, double, double, double, double, double)
7515      * 
7516      * @param eyeX
7517      *              the x-coordinate of the eye/camera location
7518      * @param eyeY
7519      *              the y-coordinate of the eye/camera location
7520      * @param eyeZ
7521      *              the z-coordinate of the eye/camera location
7522      * @param centerX
7523      *              the x-coordinate of the point to look at
7524      * @param centerY
7525      *              the y-coordinate of the point to look at
7526      * @param centerZ
7527      *              the z-coordinate of the point to look at
7528      * @param upX
7529      *              the x-coordinate of the up vector
7530      * @param upY
7531      *              the y-coordinate of the up vector
7532      * @param upZ
7533      *              the z-coordinate of the up vector
7534      * @return this
7535      */
7536     ref public Matrix4x3d lookAtLH(double eyeX, double eyeY, double eyeZ,
7537                                double centerX, double centerY, double centerZ,
7538                                double upX, double upY, double upZ) return {
7539         lookAtLH(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, this);
7540         return this;
7541     }
7542 
7543     public Vector4d frustumPlane(int which, Vector4d dest) {
7544         switch (which) {
7545         case PLANE_NX:
7546             dest.set(m00, m10, m20, 1.0 + m30).normalize();
7547             break;
7548         case PLANE_PX:
7549             dest.set(-m00, -m10, -m20, 1.0 - m30).normalize();
7550             break;
7551         case PLANE_NY:
7552             dest.set(m01, m11, m21, 1.0 + m31).normalize();
7553             break;
7554         case PLANE_PY:
7555             dest.set(-m01, -m11, -m21, 1.0 - m31).normalize();
7556             break;
7557         case PLANE_NZ:
7558             dest.set(m02, m12, m22, 1.0 + m32).normalize();
7559             break;
7560         case PLANE_PZ:
7561             dest.set(-m02, -m12, -m22, 1.0 - m32).normalize();
7562             break;
7563         default:
7564             // do nothing
7565         }
7566         return dest;
7567     }
7568 
7569     public Vector3d positiveZ(ref Vector3d dir) {
7570         dir.x = m10 * m21 - m11 * m20;
7571         dir.y = m20 * m01 - m21 * m00;
7572         dir.z = m00 * m11 - m01 * m10;
7573         return dir.normalize(dir);
7574     }
7575 
7576     public Vector3d normalizedPositiveZ(ref Vector3d dir) {
7577         dir.x = m02;
7578         dir.y = m12;
7579         dir.z = m22;
7580         return dir;
7581     }
7582 
7583     public Vector3d positiveX(ref Vector3d dir) {
7584         dir.x = m11 * m22 - m12 * m21;
7585         dir.y = m02 * m21 - m01 * m22;
7586         dir.z = m01 * m12 - m02 * m11;
7587         return dir.normalize(dir);
7588     }
7589 
7590     public Vector3d normalizedPositiveX(ref Vector3d dir) {
7591         dir.x = m00;
7592         dir.y = m10;
7593         dir.z = m20;
7594         return dir;
7595     }
7596 
7597     public Vector3d positiveY(ref Vector3d dir) {
7598         dir.x = m12 * m20 - m10 * m22;
7599         dir.y = m00 * m22 - m02 * m20;
7600         dir.z = m02 * m10 - m00 * m12;
7601         return dir.normalize(dir);
7602     }
7603 
7604     public Vector3d normalizedPositiveY(ref Vector3d dir) {
7605         dir.x = m01;
7606         dir.y = m11;
7607         dir.z = m21;
7608         return dir;
7609     }
7610 
7611     public Vector3d origin(Vector3d origin) {
7612         double a = m00 * m11 - m01 * m10;
7613         double b = m00 * m12 - m02 * m10;
7614         double d = m01 * m12 - m02 * m11;
7615         double g = m20 * m31 - m21 * m30;
7616         double h = m20 * m32 - m22 * m30;
7617         double j = m21 * m32 - m22 * m31;
7618         origin.x = -m10 * j + m11 * h - m12 * g;
7619         origin.y =  m00 * j - m01 * h + m02 * g;
7620         origin.z = -m30 * d + m31 * b - m32 * a;
7621         return origin;
7622     }
7623 
7624     /**
7625      * Apply a projection transformation to this matrix that projects onto the plane specified via the general plane equation
7626      * <code>x*a + y*b + z*c + d = 0</code> as if casting a shadow from a given light position/direction <code>light</code>.
7627      * <p>
7628      * 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.
7629      * <p>
7630      * If <code>M</code> is <code>this</code> matrix and <code>S</code> the shadow matrix,
7631      * then the new matrix will be <code>M * S</code>. So when transforming a
7632      * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the
7633      * shadow projection will be applied first!
7634      * <p>
7635      * Reference: <a href="ftp://ftp.sgi.com/opengl/contrib/blythe/advanced99/notes/node192.html">ftp.sgi.com</a>
7636      * 
7637      * @param light
7638      *          the light's vector
7639      * @param a
7640      *          the x factor in the plane equation
7641      * @param b
7642      *          the y factor in the plane equation
7643      * @param c
7644      *          the z factor in the plane equation
7645      * @param d
7646      *          the constant in the plane equation
7647      * @return this
7648      */
7649     ref public Matrix4x3d shadow(Vector4d light, double a, double b, double c, double d) return {
7650         shadow(light.x, light.y, light.z, light.w, a, b, c, d, this);
7651         return this;
7652     }
7653 
7654     public Matrix4x3d shadow(Vector4d light, double a, double b, double c, double d, ref Matrix4x3d dest) {
7655         return shadow(light.x, light.y, light.z, light.w, a, b, c, d, dest);
7656     }
7657 
7658     /**
7659      * Apply a projection transformation to this matrix that projects onto the plane specified via the general plane equation
7660      * <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>.
7661      * <p>
7662      * 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.
7663      * <p>
7664      * If <code>M</code> is <code>this</code> matrix and <code>S</code> the shadow matrix,
7665      * then the new matrix will be <code>M * S</code>. So when transforming a
7666      * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the
7667      * shadow projection will be applied first!
7668      * <p>
7669      * Reference: <a href="ftp://ftp.sgi.com/opengl/contrib/blythe/advanced99/notes/node192.html">ftp.sgi.com</a>
7670      * 
7671      * @param lightX
7672      *          the x-component of the light's vector
7673      * @param lightY
7674      *          the y-component of the light's vector
7675      * @param lightZ
7676      *          the z-component of the light's vector
7677      * @param lightW
7678      *          the w-component of the light's vector
7679      * @param a
7680      *          the x factor in the plane equation
7681      * @param b
7682      *          the y factor in the plane equation
7683      * @param c
7684      *          the z factor in the plane equation
7685      * @param d
7686      *          the constant in the plane equation
7687      * @return this
7688      */
7689     ref public Matrix4x3d shadow(double lightX, double lightY, double lightZ, double lightW, double a, double b, double c, double d) return {
7690         shadow(lightX, lightY, lightZ, lightW, a, b, c, d, this);
7691         return this;
7692     }
7693 
7694     public Matrix4x3d shadow(double lightX, double lightY, double lightZ, double lightW, double a, double b, double c, double d, ref Matrix4x3d dest) {
7695         // normalize plane
7696         double invPlaneLen = Math.invsqrt(a*a + b*b + c*c);
7697         double an = a * invPlaneLen;
7698         double bn = b * invPlaneLen;
7699         double cn = c * invPlaneLen;
7700         double dn = d * invPlaneLen;
7701 
7702         double dot = an * lightX + bn * lightY + cn * lightZ + dn * lightW;
7703 
7704         // compute right matrix elements
7705         double rm00 = dot - an * lightX;
7706         double rm01 = -an * lightY;
7707         double rm02 = -an * lightZ;
7708         double rm03 = -an * lightW;
7709         double rm10 = -bn * lightX;
7710         double rm11 = dot - bn * lightY;
7711         double rm12 = -bn * lightZ;
7712         double rm13 = -bn * lightW;
7713         double rm20 = -cn * lightX;
7714         double rm21 = -cn * lightY;
7715         double rm22 = dot - cn * lightZ;
7716         double rm23 = -cn * lightW;
7717         double rm30 = -dn * lightX;
7718         double rm31 = -dn * lightY;
7719         double rm32 = -dn * lightZ;
7720         double rm33 = dot - dn * lightW;
7721 
7722         // matrix multiplication
7723         double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02 + m30 * rm03;
7724         double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02 + m31 * rm03;
7725         double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02 + m32 * rm03;
7726         double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12 + m30 * rm13;
7727         double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12 + m31 * rm13;
7728         double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12 + m32 * rm13;
7729         double nm20 = m00 * rm20 + m10 * rm21 + m20 * rm22 + m30 * rm23;
7730         double nm21 = m01 * rm20 + m11 * rm21 + m21 * rm22 + m31 * rm23;
7731         double nm22 = m02 * rm20 + m12 * rm21 + m22 * rm22 + m32 * rm23;
7732         dest.m30 = m00 * rm30 + m10 * rm31 + m20 * rm32 + m30 * rm33;
7733         dest.m31 = m01 * rm30 + m11 * rm31 + m21 * rm32 + m31 * rm33;
7734         dest.m32 = m02 * rm30 + m12 * rm31 + m22 * rm32 + m32 * rm33;
7735         dest.m00 = nm00;
7736         dest.m01 = nm01;
7737         dest.m02 = nm02;
7738         dest.m10 = nm10;
7739         dest.m11 = nm11;
7740         dest.m12 = nm12;
7741         dest.m20 = nm20;
7742         dest.m21 = nm21;
7743         dest.m22 = nm22;
7744         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
7745 
7746         return dest;
7747     }
7748 
7749     public Matrix4x3d shadow(Vector4d light, Matrix4x3d planeTransform, ref Matrix4x3d dest) {
7750         // compute plane equation by transforming (y = 0)
7751         double a = planeTransform.m10;
7752         double b = planeTransform.m11;
7753         double c = planeTransform.m12;
7754         double d = -a * planeTransform.m30 - b * planeTransform.m31 - c * planeTransform.m32;
7755         return shadow(light.x, light.y, light.z, light.w, a, b, c, d, dest);
7756     }
7757 
7758     /**
7759      * Apply a projection transformation to this matrix that projects onto the plane with the general plane equation
7760      * <code>y = 0</code> as if casting a shadow from a given light position/direction <code>light</code>.
7761      * <p>
7762      * Before the shadow projection is applied, the plane is transformed via the specified <code>planeTransformation</code>.
7763      * <p>
7764      * 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.
7765      * <p>
7766      * If <code>M</code> is <code>this</code> matrix and <code>S</code> the shadow matrix,
7767      * then the new matrix will be <code>M * S</code>. So when transforming a
7768      * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the
7769      * shadow projection will be applied first!
7770      * 
7771      * @param light
7772      *          the light's vector
7773      * @param planeTransform
7774      *          the transformation to transform the implied plane <code>y = 0</code> before applying the projection
7775      * @return this
7776      */
7777     ref public Matrix4x3d shadow(Vector4d light, Matrix4x3d planeTransform) return {
7778         shadow(light, planeTransform, this);
7779         return this;
7780     }
7781 
7782     public Matrix4x3d shadow(double lightX, double lightY, double lightZ, double lightW, Matrix4x3d planeTransform, ref Matrix4x3d dest) {
7783         // compute plane equation by transforming (y = 0)
7784         double a = planeTransform.m10;
7785         double b = planeTransform.m11;
7786         double c = planeTransform.m12;
7787         double d = -a * planeTransform.m30 - b * planeTransform.m31 - c * planeTransform.m32;
7788         return shadow(lightX, lightY, lightZ, lightW, a, b, c, d, dest);
7789     }
7790 
7791     /**
7792      * Apply a projection transformation to this matrix that projects onto the plane with the general plane equation
7793      * <code>y = 0</code> as if casting a shadow from a given light position/direction <code>(lightX, lightY, lightZ, lightW)</code>.
7794      * <p>
7795      * Before the shadow projection is applied, the plane is transformed via the specified <code>planeTransformation</code>.
7796      * <p>
7797      * 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.
7798      * <p>
7799      * If <code>M</code> is <code>this</code> matrix and <code>S</code> the shadow matrix,
7800      * then the new matrix will be <code>M * S</code>. So when transforming a
7801      * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the
7802      * shadow projection will be applied first!
7803      * 
7804      * @param lightX
7805      *          the x-component of the light vector
7806      * @param lightY
7807      *          the y-component of the light vector
7808      * @param lightZ
7809      *          the z-component of the light vector
7810      * @param lightW
7811      *          the w-component of the light vector
7812      * @param planeTransform
7813      *          the transformation to transform the implied plane <code>y = 0</code> before applying the projection
7814      * @return this
7815      */
7816     ref public Matrix4x3d shadow(double lightX, double lightY, double lightZ, double lightW, Matrix4x3d planeTransform) return {
7817         shadow(lightX, lightY, lightZ, lightW, planeTransform, this);
7818         return this;
7819     }
7820 
7821     /**
7822      * Set this matrix to a cylindrical billboard transformation that rotates the local +Z axis of a given object with position <code>objPos</code> towards
7823      * a target position at <code>targetPos</code> while constraining a cylindrical rotation around the given <code>up</code> vector.
7824      * <p>
7825      * This method can be used to create the complete model transformation for a given object, including the translation of the object to
7826      * its position <code>objPos</code>.
7827      * 
7828      * @param objPos
7829      *          the position of the object to rotate towards <code>targetPos</code>
7830      * @param targetPos
7831      *          the position of the target (for example the camera) towards which to rotate the object
7832      * @param up
7833      *          the rotation axis (must be {@link Vector3d#normalize() normalized})
7834      * @return this
7835      */
7836     ref public Matrix4x3d billboardCylindrical(Vector3d objPos, Vector3d targetPos, Vector3d up) return {
7837         double dirX = targetPos.x - objPos.x;
7838         double dirY = targetPos.y - objPos.y;
7839         double dirZ = targetPos.z - objPos.z;
7840         // left = up x dir
7841         double leftX = up.y * dirZ - up.z * dirY;
7842         double leftY = up.z * dirX - up.x * dirZ;
7843         double leftZ = up.x * dirY - up.y * dirX;
7844         // normalize left
7845         double invLeftLen = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
7846         leftX *= invLeftLen;
7847         leftY *= invLeftLen;
7848         leftZ *= invLeftLen;
7849         // recompute dir by constraining rotation around 'up'
7850         // dir = left x up
7851         dirX = leftY * up.z - leftZ * up.y;
7852         dirY = leftZ * up.x - leftX * up.z;
7853         dirZ = leftX * up.y - leftY * up.x;
7854         // normalize dir
7855         double invDirLen = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
7856         dirX *= invDirLen;
7857         dirY *= invDirLen;
7858         dirZ *= invDirLen;
7859         // set matrix elements
7860         m00 = leftX;
7861         m01 = leftY;
7862         m02 = leftZ;
7863         m10 = up.x;
7864         m11 = up.y;
7865         m12 = up.z;
7866         m20 = dirX;
7867         m21 = dirY;
7868         m22 = dirZ;
7869         m30 = objPos.x;
7870         m31 = objPos.y;
7871         m32 = objPos.z;
7872         properties = PROPERTY_ORTHONORMAL;
7873         return this;
7874     }
7875 
7876     /**
7877      * Set this matrix to a spherical billboard transformation that rotates the local +Z axis of a given object with position <code>objPos</code> towards
7878      * a target position at <code>targetPos</code>.
7879      * <p>
7880      * This method can be used to create the complete model transformation for a given object, including the translation of the object to
7881      * its position <code>objPos</code>.
7882      * <p>
7883      * If preserving an <i>up</i> vector is not necessary when rotating the +Z axis, then a shortest arc rotation can be obtained 
7884      * using {@link #billboardSpherical(Vector3d, Vector3d)}.
7885      * 
7886      * @see #billboardSpherical(Vector3d, Vector3d)
7887      * 
7888      * @param objPos
7889      *          the position of the object to rotate towards <code>targetPos</code>
7890      * @param targetPos
7891      *          the position of the target (for example the camera) towards which to rotate the object
7892      * @param up
7893      *          the up axis used to orient the object
7894      * @return this
7895      */
7896     ref public Matrix4x3d billboardSpherical(Vector3d objPos, Vector3d targetPos, Vector3d up) return {
7897         double dirX = targetPos.x - objPos.x;
7898         double dirY = targetPos.y - objPos.y;
7899         double dirZ = targetPos.z - objPos.z;
7900         // normalize dir
7901         double invDirLen = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
7902         dirX *= invDirLen;
7903         dirY *= invDirLen;
7904         dirZ *= invDirLen;
7905         // left = up x dir
7906         double leftX = up.y * dirZ - up.z * dirY;
7907         double leftY = up.z * dirX - up.x * dirZ;
7908         double leftZ = up.x * dirY - up.y * dirX;
7909         // normalize left
7910         double invLeftLen = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
7911         leftX *= invLeftLen;
7912         leftY *= invLeftLen;
7913         leftZ *= invLeftLen;
7914         // up = dir x left
7915         double upX = dirY * leftZ - dirZ * leftY;
7916         double upY = dirZ * leftX - dirX * leftZ;
7917         double upZ = dirX * leftY - dirY * leftX;
7918         // set matrix elements
7919         m00 = leftX;
7920         m01 = leftY;
7921         m02 = leftZ;
7922         m10 = upX;
7923         m11 = upY;
7924         m12 = upZ;
7925         m20 = dirX;
7926         m21 = dirY;
7927         m22 = dirZ;
7928         m30 = objPos.x;
7929         m31 = objPos.y;
7930         m32 = objPos.z;
7931         properties = PROPERTY_ORTHONORMAL;
7932         return this;
7933     }
7934 
7935     /**
7936      * Set this matrix to a spherical billboard transformation that rotates the local +Z axis of a given object with position <code>objPos</code> towards
7937      * a target position at <code>targetPos</code> using a shortest arc rotation by not preserving any <i>up</i> vector of the object.
7938      * <p>
7939      * This method can be used to create the complete model transformation for a given object, including the translation of the object to
7940      * its position <code>objPos</code>.
7941      * <p>
7942      * In order to specify an <i>up</i> vector which needs to be maintained when rotating the +Z axis of the object,
7943      * use {@link #billboardSpherical(Vector3d, Vector3d, Vector3d)}.
7944      * 
7945      * @see #billboardSpherical(Vector3d, Vector3d, Vector3d)
7946      * 
7947      * @param objPos
7948      *          the position of the object to rotate towards <code>targetPos</code>
7949      * @param targetPos
7950      *          the position of the target (for example the camera) towards which to rotate the object
7951      * @return this
7952      */
7953     ref public Matrix4x3d billboardSpherical(Vector3d objPos, Vector3d targetPos) return {
7954         double toDirX = targetPos.x - objPos.x;
7955         double toDirY = targetPos.y - objPos.y;
7956         double toDirZ = targetPos.z - objPos.z;
7957         double x = -toDirY;
7958         double y = toDirX;
7959         double w = Math.sqrt(toDirX * toDirX + toDirY * toDirY + toDirZ * toDirZ) + toDirZ;
7960         double invNorm = Math.invsqrt(x * x + y * y + w * w);
7961         x *= invNorm;
7962         y *= invNorm;
7963         w *= invNorm;
7964         double q00 = (x + x) * x;
7965         double q11 = (y + y) * y;
7966         double q01 = (x + x) * y;
7967         double q03 = (x + x) * w;
7968         double q13 = (y + y) * w;
7969         m00 = 1.0 - q11;
7970         m01 = q01;
7971         m02 = -q13;
7972         m10 = q01;
7973         m11 = 1.0 - q00;
7974         m12 = q03;
7975         m20 = q13;
7976         m21 = -q03;
7977         m22 = 1.0 - q11 - q00;
7978         m30 = objPos.x;
7979         m31 = objPos.y;
7980         m32 = objPos.z;
7981         properties = PROPERTY_ORTHONORMAL;
7982         return this;
7983     }
7984 
7985     public int hashCode() {
7986         immutable int prime = 31;
7987         int result = 1;
7988         long temp;
7989         temp = Math.doubleToLongBits(m00);
7990         result = prime * result + cast(int) (temp ^ (temp >>> 32));
7991         temp = Math.doubleToLongBits(m01);
7992         result = prime * result + cast(int) (temp ^ (temp >>> 32));
7993         temp = Math.doubleToLongBits(m02);
7994         result = prime * result + cast(int) (temp ^ (temp >>> 32));
7995         temp = Math.doubleToLongBits(m10);
7996         result = prime * result + cast(int) (temp ^ (temp >>> 32));
7997         temp = Math.doubleToLongBits(m11);
7998         result = prime * result + cast(int) (temp ^ (temp >>> 32));
7999         temp = Math.doubleToLongBits(m12);
8000         result = prime * result + cast(int) (temp ^ (temp >>> 32));
8001         temp = Math.doubleToLongBits(m20);
8002         result = prime * result + cast(int) (temp ^ (temp >>> 32));
8003         temp = Math.doubleToLongBits(m21);
8004         result = prime * result + cast(int) (temp ^ (temp >>> 32));
8005         temp = Math.doubleToLongBits(m22);
8006         result = prime * result + cast(int) (temp ^ (temp >>> 32));
8007         temp = Math.doubleToLongBits(m30);
8008         result = prime * result + cast(int) (temp ^ (temp >>> 32));
8009         temp = Math.doubleToLongBits(m31);
8010         result = prime * result + cast(int) (temp ^ (temp >>> 32));
8011         temp = Math.doubleToLongBits(m32);
8012         result = prime * result + cast(int) (temp ^ (temp >>> 32));
8013         return result;
8014     }
8015 
8016     public bool equals(Matrix4x3d m, double delta) {
8017         if (this == m)
8018             return true;
8019         if (!Math.equals(m00, m.m00, delta))
8020             return false;
8021         if (!Math.equals(m01, m.m01, delta))
8022             return false;
8023         if (!Math.equals(m02, m.m02, delta))
8024             return false;
8025         if (!Math.equals(m10, m.m10, delta))
8026             return false;
8027         if (!Math.equals(m11, m.m11, delta))
8028             return false;
8029         if (!Math.equals(m12, m.m12, delta))
8030             return false;
8031         if (!Math.equals(m20, m.m20, delta))
8032             return false;
8033         if (!Math.equals(m21, m.m21, delta))
8034             return false;
8035         if (!Math.equals(m22, m.m22, delta))
8036             return false;
8037         if (!Math.equals(m30, m.m30, delta))
8038             return false;
8039         if (!Math.equals(m31, m.m31, delta))
8040             return false;
8041         if (!Math.equals(m32, m.m32, delta))
8042             return false;
8043         return true;
8044     }
8045 
8046     public Matrix4x3d pick(double x, double y, double width, double height, int[] viewport, ref Matrix4x3d dest) {
8047         double sx = viewport[2] / width;
8048         double sy = viewport[3] / height;
8049         double tx = (viewport[2] + 2.0 * (viewport[0] - x)) / width;
8050         double ty = (viewport[3] + 2.0 * (viewport[1] - y)) / height;
8051         dest.m30 = m00 * tx + m10 * ty + m30;
8052         dest.m31 = m01 * tx + m11 * ty + m31;
8053         dest.m32 = m02 * tx + m12 * ty + m32;
8054         dest.m00 = m00 * sx;
8055         dest.m01 = m01 * sx;
8056         dest.m02 = m02 * sx;
8057         dest.m10 = m10 * sy;
8058         dest.m11 = m11 * sy;
8059         dest.m12 = m12 * sy;
8060         dest.properties = 0;
8061         return dest;
8062     }
8063 
8064     /**
8065      * Apply a picking transformation to this matrix using the given window coordinates <code>(x, y)</code> as the pick center
8066      * and the given <code>(width, height)</code> as the size of the picking region in window coordinates.
8067      * 
8068      * @param x
8069      *          the x coordinate of the picking region center in window coordinates
8070      * @param y
8071      *          the y coordinate of the picking region center in window coordinates
8072      * @param width
8073      *          the width of the picking region in window coordinates
8074      * @param height
8075      *          the height of the picking region in window coordinates
8076      * @param viewport
8077      *          the viewport described by <code>[x, y, width, height]</code>
8078      * @return this
8079      */
8080     ref public Matrix4x3d pick(double x, double y, double width, double height, int[] viewport) return {
8081         pick(x, y, width, height, viewport, this);
8082         return this;
8083     }
8084 
8085     /**
8086      * Exchange the values of <code>this</code> matrix with the given <code>other</code> matrix.
8087      * 
8088      * @param other
8089      *          the other matrix to exchange the values with
8090      * @return this
8091      */
8092     ref public Matrix4x3d swap(ref Matrix4x3d other) return {
8093         double tmp;
8094         tmp = m00; m00 = other.m00; other.m00 = tmp;
8095         tmp = m01; m01 = other.m01; other.m01 = tmp;
8096         tmp = m02; m02 = other.m02; other.m02 = tmp;
8097         tmp = m10; m10 = other.m10; other.m10 = tmp;
8098         tmp = m11; m11 = other.m11; other.m11 = tmp;
8099         tmp = m12; m12 = other.m12; other.m12 = tmp;
8100         tmp = m20; m20 = other.m20; other.m20 = tmp;
8101         tmp = m21; m21 = other.m21; other.m21 = tmp;
8102         tmp = m22; m22 = other.m22; other.m22 = tmp;
8103         tmp = m30; m30 = other.m30; other.m30 = tmp;
8104         tmp = m31; m31 = other.m31; other.m31 = tmp;
8105         tmp = m32; m32 = other.m32; other.m32 = tmp;
8106         int props = properties;
8107         this.properties = other.properties;
8108         other.properties = props;
8109         return this;
8110     }
8111 
8112     public Matrix4x3d arcball(double radius, double centerX, double centerY, double centerZ, double angleX, double angleY, ref Matrix4x3d dest) {
8113         double m30 = m20 * -radius + this.m30;
8114         double m31 = m21 * -radius + this.m31;
8115         double m32 = m22 * -radius + this.m32;
8116         double sin = Math.sin(angleX);
8117         double cos = Math.cosFromSin(sin, angleX);
8118         double nm10 = m10 * cos + m20 * sin;
8119         double nm11 = m11 * cos + m21 * sin;
8120         double nm12 = m12 * cos + m22 * sin;
8121         double m20 = this.m20 * cos - m10 * sin;
8122         double m21 = this.m21 * cos - m11 * sin;
8123         double m22 = this.m22 * cos - m12 * sin;
8124         sin = Math.sin(angleY);
8125         cos = Math.cosFromSin(sin, angleY);
8126         double nm00 = m00 * cos - m20 * sin;
8127         double nm01 = m01 * cos - m21 * sin;
8128         double nm02 = m02 * cos - m22 * sin;
8129         double nm20 = m00 * sin + m20 * cos;
8130         double nm21 = m01 * sin + m21 * cos;
8131         double nm22 = m02 * sin + m22 * cos;
8132         dest.m30 = -nm00 * centerX - nm10 * centerY - nm20 * centerZ + m30;
8133         dest.m31 = -nm01 * centerX - nm11 * centerY - nm21 * centerZ + m31;
8134         dest.m32 = -nm02 * centerX - nm12 * centerY - nm22 * centerZ + m32;
8135         dest.m20 = nm20;
8136         dest.m21 = nm21;
8137         dest.m22 = nm22;
8138         dest.m10 = nm10;
8139         dest.m11 = nm11;
8140         dest.m12 = nm12;
8141         dest.m00 = nm00;
8142         dest.m01 = nm01;
8143         dest.m02 = nm02;
8144         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
8145         return dest;
8146     }
8147 
8148     public Matrix4x3d arcball(double radius, Vector3d center, double angleX, double angleY, ref Matrix4x3d dest) {
8149         return arcball(radius, center.x, center.y, center.z, angleX, angleY, dest);
8150     }
8151 
8152     /**
8153      * Apply an arcball view transformation to this matrix with the given <code>radius</code> and center <code>(centerX, centerY, centerZ)</code>
8154      * position of the arcball and the specified X and Y rotation angles.
8155      * <p>
8156      * This method is equivalent to calling: <code>translate(0, 0, -radius).rotateX(angleX).rotateY(angleY).translate(-centerX, -centerY, -centerZ)</code>
8157      * 
8158      * @param radius
8159      *          the arcball radius
8160      * @param centerX
8161      *          the x coordinate of the center position of the arcball
8162      * @param centerY
8163      *          the y coordinate of the center position of the arcball
8164      * @param centerZ
8165      *          the z coordinate of the center position of the arcball
8166      * @param angleX
8167      *          the rotation angle around the X axis in radians
8168      * @param angleY
8169      *          the rotation angle around the Y axis in radians
8170      * @return this
8171      */
8172     ref public Matrix4x3d arcball(double radius, double centerX, double centerY, double centerZ, double angleX, double angleY) return {
8173         arcball(radius, centerX, centerY, centerZ, angleX, angleY, this);
8174         return this;
8175     }
8176 
8177     /**
8178      * Apply an arcball view transformation to this matrix with the given <code>radius</code> and <code>center</code>
8179      * position of the arcball and the specified X and Y rotation angles.
8180      * <p>
8181      * This method is equivalent to calling: <code>translate(0, 0, -radius).rotateX(angleX).rotateY(angleY).translate(-center.x, -center.y, -center.z)</code>
8182      * 
8183      * @param radius
8184      *          the arcball radius
8185      * @param center
8186      *          the center position of the arcball
8187      * @param angleX
8188      *          the rotation angle around the X axis in radians
8189      * @param angleY
8190      *          the rotation angle around the Y axis in radians
8191      * @return this
8192      */
8193     ref public Matrix4x3d arcball(double radius, Vector3d center, double angleX, double angleY) return {
8194         arcball(radius, center.x, center.y, center.z, angleX, angleY, this);
8195         return this;
8196     }
8197 
8198     public Matrix4x3d transformAab(double minX, double minY, double minZ, double maxX, double maxY, double maxZ, Vector3d outMin, Vector3d outMax) {
8199         double xax = m00 * minX, xay = m01 * minX, xaz = m02 * minX;
8200         double xbx = m00 * maxX, xby = m01 * maxX, xbz = m02 * maxX;
8201         double yax = m10 * minY, yay = m11 * minY, yaz = m12 * minY;
8202         double ybx = m10 * maxY, yby = m11 * maxY, ybz = m12 * maxY;
8203         double zax = m20 * minZ, zay = m21 * minZ, zaz = m22 * minZ;
8204         double zbx = m20 * maxZ, zby = m21 * maxZ, zbz = m22 * maxZ;
8205         double xminx, xminy, xminz, yminx, yminy, yminz, zminx, zminy, zminz;
8206         double xmaxx, xmaxy, xmaxz, ymaxx, ymaxy, ymaxz, zmaxx, zmaxy, zmaxz;
8207         if (xax < xbx) {
8208             xminx = xax;
8209             xmaxx = xbx;
8210         } else {
8211             xminx = xbx;
8212             xmaxx = xax;
8213         }
8214         if (xay < xby) {
8215             xminy = xay;
8216             xmaxy = xby;
8217         } else {
8218             xminy = xby;
8219             xmaxy = xay;
8220         }
8221         if (xaz < xbz) {
8222             xminz = xaz;
8223             xmaxz = xbz;
8224         } else {
8225             xminz = xbz;
8226             xmaxz = xaz;
8227         }
8228         if (yax < ybx) {
8229             yminx = yax;
8230             ymaxx = ybx;
8231         } else {
8232             yminx = ybx;
8233             ymaxx = yax;
8234         }
8235         if (yay < yby) {
8236             yminy = yay;
8237             ymaxy = yby;
8238         } else {
8239             yminy = yby;
8240             ymaxy = yay;
8241         }
8242         if (yaz < ybz) {
8243             yminz = yaz;
8244             ymaxz = ybz;
8245         } else {
8246             yminz = ybz;
8247             ymaxz = yaz;
8248         }
8249         if (zax < zbx) {
8250             zminx = zax;
8251             zmaxx = zbx;
8252         } else {
8253             zminx = zbx;
8254             zmaxx = zax;
8255         }
8256         if (zay < zby) {
8257             zminy = zay;
8258             zmaxy = zby;
8259         } else {
8260             zminy = zby;
8261             zmaxy = zay;
8262         }
8263         if (zaz < zbz) {
8264             zminz = zaz;
8265             zmaxz = zbz;
8266         } else {
8267             zminz = zbz;
8268             zmaxz = zaz;
8269         }
8270         outMin.x = xminx + yminx + zminx + m30;
8271         outMin.y = xminy + yminy + zminy + m31;
8272         outMin.z = xminz + yminz + zminz + m32;
8273         outMax.x = xmaxx + ymaxx + zmaxx + m30;
8274         outMax.y = xmaxy + ymaxy + zmaxy + m31;
8275         outMax.z = xmaxz + ymaxz + zmaxz + m32;
8276         return this;
8277     }
8278 
8279     public Matrix4x3d transformAab(Vector3d min, Vector3d max, Vector3d outMin, Vector3d outMax) {
8280         return transformAab(min.x, min.y, min.z, max.x, max.y, max.z, outMin, outMax);
8281     }
8282 
8283     /**
8284      * Linearly interpolate <code>this</code> and <code>other</code> using the given interpolation factor <code>t</code>
8285      * and store the result in <code>this</code>.
8286      * <p>
8287      * 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>
8288      * then the result is <code>other</code>.
8289      *
8290      * @param other
8291      *          the other matrix
8292      * @param t
8293      *          the interpolation factor between 0.0 and 1.0
8294      * @return this
8295      */
8296     ref public Matrix4x3d lerp(Matrix4x3d other, double t) return {
8297         lerp(other, t, this);
8298         return this;
8299     }
8300 
8301     public Matrix4x3d lerp(Matrix4x3d other, double t, ref Matrix4x3d dest) {
8302         dest.m00 = Math.fma(other.m00 - m00, t, m00);
8303         dest.m01 = Math.fma(other.m01 - m01, t, m01);
8304         dest.m02 = Math.fma(other.m02 - m02, t, m02);
8305         dest.m10 = Math.fma(other.m10 - m10, t, m10);
8306         dest.m11 = Math.fma(other.m11 - m11, t, m11);
8307         dest.m12 = Math.fma(other.m12 - m12, t, m12);
8308         dest.m20 = Math.fma(other.m20 - m20, t, m20);
8309         dest.m21 = Math.fma(other.m21 - m21, t, m21);
8310         dest.m22 = Math.fma(other.m22 - m22, t, m22);
8311         dest.m30 = Math.fma(other.m30 - m30, t, m30);
8312         dest.m31 = Math.fma(other.m31 - m31, t, m31);
8313         dest.m32 = Math.fma(other.m32 - m32, t, m32);
8314         dest.properties = properties & other.properties;
8315         return dest;
8316     }
8317 
8318     /**
8319      * Apply a model transformation to this matrix for a right-handed coordinate system, 
8320      * that aligns the local <code>+Z</code> axis with <code>dir</code>
8321      * and store the result in <code>dest</code>.
8322      * <p>
8323      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix,
8324      * then the new matrix will be <code>M * L</code>. So when transforming a
8325      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>,
8326      * the lookat transformation will be applied first!
8327      * <p>
8328      * In order to set the matrix to a rotation transformation without post-multiplying it,
8329      * use {@link #rotationTowards(Vector3d, Vector3d) rotationTowards()}.
8330      * <p>
8331      * This method is equivalent to calling: <code>mul(new Matrix4x3d().lookAt(new Vector3d(), new Vector3d(dir).negate(), up).invert(), dest)</code>
8332      * 
8333      * @see #rotateTowards(double, double, double, double, double, double, Matrix4x3d)
8334      * @see #rotationTowards(Vector3d, Vector3d)
8335      * 
8336      * @param dir
8337      *              the direction to rotate towards
8338      * @param up
8339      *              the up vector
8340      * @param dest
8341      *              will hold the result
8342      * @return dest
8343      */
8344     public Matrix4x3d rotateTowards(ref Vector3d dir, Vector3d up, ref Matrix4x3d dest) {
8345         return rotateTowards(dir.x, dir.y, dir.z, up.x, up.y, up.z, dest);
8346     }
8347 
8348     /**
8349      * Apply a model transformation to this matrix for a right-handed coordinate system, 
8350      * that aligns the local <code>+Z</code> axis with <code>dir</code>.
8351      * <p>
8352      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix,
8353      * then the new matrix will be <code>M * L</code>. So when transforming a
8354      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>,
8355      * the lookat transformation will be applied first!
8356      * <p>
8357      * In order to set the matrix to a rotation transformation without post-multiplying it,
8358      * use {@link #rotationTowards(Vector3d, Vector3d) rotationTowards()}.
8359      * <p>
8360      * This method is equivalent to calling: <code>mul(new Matrix4x3d().lookAt(new Vector3d(), new Vector3d(dir).negate(), up).invert())</code>
8361      * 
8362      * @see #rotateTowards(double, double, double, double, double, double)
8363      * @see #rotationTowards(Vector3d, Vector3d)
8364      * 
8365      * @param dir
8366      *              the direction to orient towards
8367      * @param up
8368      *              the up vector
8369      * @return this
8370      */
8371     ref public Matrix4x3d rotateTowards(ref Vector3d dir, Vector3d up) return {
8372         rotateTowards(dir.x, dir.y, dir.z, up.x, up.y, up.z, this);
8373         return this;
8374     }
8375 
8376     /**
8377      * Apply a model transformation to this matrix for a right-handed coordinate system, 
8378      * that aligns the local <code>+Z</code> axis with <code>(dirX, dirY, dirZ)</code>.
8379      * <p>
8380      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix,
8381      * then the new matrix will be <code>M * L</code>. So when transforming a
8382      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>,
8383      * the lookat transformation will be applied first!
8384      * <p>
8385      * In order to set the matrix to a rotation transformation without post-multiplying it,
8386      * use {@link #rotationTowards(double, double, double, double, double, double) rotationTowards()}.
8387      * <p>
8388      * This method is equivalent to calling: <code>mul(new Matrix4x3d().lookAt(0, 0, 0, -dirX, -dirY, -dirZ, upX, upY, upZ).invert())</code>
8389      * 
8390      * @see #rotateTowards(Vector3d, Vector3d)
8391      * @see #rotationTowards(double, double, double, double, double, double)
8392      * 
8393      * @param dirX
8394      *              the x-coordinate of the direction to rotate towards
8395      * @param dirY
8396      *              the y-coordinate of the direction to rotate towards
8397      * @param dirZ
8398      *              the z-coordinate of the direction to rotate towards
8399      * @param upX
8400      *              the x-coordinate of the up vector
8401      * @param upY
8402      *              the y-coordinate of the up vector
8403      * @param upZ
8404      *              the z-coordinate of the up vector
8405      * @return this
8406      */
8407     ref public Matrix4x3d rotateTowards(double dirX, double dirY, double dirZ, double upX, double upY, double upZ) return {
8408         rotateTowards(dirX, dirY, dirZ, upX, upY, upZ, this);
8409         return this;
8410     }
8411 
8412     /**
8413      * Apply a model transformation to this matrix for a right-handed coordinate system, 
8414      * that aligns the local <code>+Z</code> axis with <code>(dirX, dirY, dirZ)</code>
8415      * and store the result in <code>dest</code>.
8416      * <p>
8417      * If <code>M</code> is <code>this</code> matrix and <code>L</code> the lookat matrix,
8418      * then the new matrix will be <code>M * L</code>. So when transforming a
8419      * vector <code>v</code> with the new matrix by using <code>M * L * v</code>,
8420      * the lookat transformation will be applied first!
8421      * <p>
8422      * In order to set the matrix to a rotation transformation without post-multiplying it,
8423      * use {@link #rotationTowards(double, double, double, double, double, double) rotationTowards()}.
8424      * <p>
8425      * This method is equivalent to calling: <code>mul(new Matrix4x3d().lookAt(0, 0, 0, -dirX, -dirY, -dirZ, upX, upY, upZ).invert(), dest)</code>
8426      * 
8427      * @see #rotateTowards(Vector3d, Vector3d)
8428      * @see #rotationTowards(double, double, double, double, double, double)
8429      * 
8430      * @param dirX
8431      *              the x-coordinate of the direction to rotate towards
8432      * @param dirY
8433      *              the y-coordinate of the direction to rotate towards
8434      * @param dirZ
8435      *              the z-coordinate of the direction to rotate towards
8436      * @param upX
8437      *              the x-coordinate of the up vector
8438      * @param upY
8439      *              the y-coordinate of the up vector
8440      * @param upZ
8441      *              the z-coordinate of the up vector
8442      * @param dest
8443      *              will hold the result
8444      * @return dest
8445      */
8446     public Matrix4x3d rotateTowards(double dirX, double dirY, double dirZ, double upX, double upY, double upZ, ref Matrix4x3d dest) {
8447         // Normalize direction
8448         double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
8449         double ndirX = dirX * invDirLength;
8450         double ndirY = dirY * invDirLength;
8451         double ndirZ = dirZ * invDirLength;
8452         // left = up x direction
8453         double leftX, leftY, leftZ;
8454         leftX = upY * ndirZ - upZ * ndirY;
8455         leftY = upZ * ndirX - upX * ndirZ;
8456         leftZ = upX * ndirY - upY * ndirX;
8457         // normalize left
8458         double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
8459         leftX *= invLeftLength;
8460         leftY *= invLeftLength;
8461         leftZ *= invLeftLength;
8462         // up = direction x left
8463         double upnX = ndirY * leftZ - ndirZ * leftY;
8464         double upnY = ndirZ * leftX - ndirX * leftZ;
8465         double upnZ = ndirX * leftY - ndirY * leftX;
8466         double rm00 = leftX;
8467         double rm01 = leftY;
8468         double rm02 = leftZ;
8469         double rm10 = upnX;
8470         double rm11 = upnY;
8471         double rm12 = upnZ;
8472         double rm20 = ndirX;
8473         double rm21 = ndirY;
8474         double rm22 = ndirZ;
8475         dest.m30 = m30;
8476         dest.m31 = m31;
8477         dest.m32 = m32;
8478         double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
8479         double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
8480         double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
8481         double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
8482         double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
8483         double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
8484         dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
8485         dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
8486         dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
8487         dest.m00 = nm00;
8488         dest.m01 = nm01;
8489         dest.m02 = nm02;
8490         dest.m10 = nm10;
8491         dest.m11 = nm11;
8492         dest.m12 = nm12;
8493         dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
8494         return dest;
8495     }
8496 
8497     /**
8498      * Set this matrix to a model transformation for a right-handed coordinate system, 
8499      * that aligns the local <code>-z</code> axis with <code>dir</code>.
8500      * <p>
8501      * In order to apply the rotation transformation to a previous existing transformation,
8502      * use {@link #rotateTowards(double, double, double, double, double, double) rotateTowards}.
8503      * <p>
8504      * This method is equivalent to calling: <code>setLookAt(new Vector3d(), new Vector3d(dir).negate(), up).invert()</code>
8505      * 
8506      * @see #rotationTowards(Vector3d, Vector3d)
8507      * @see #rotateTowards(double, double, double, double, double, double)
8508      * 
8509      * @param dir
8510      *              the direction to orient the local -z axis towards
8511      * @param up
8512      *              the up vector
8513      * @return this
8514      */
8515     ref public Matrix4x3d rotationTowards(ref Vector3d dir, Vector3d up) return {
8516         return rotationTowards(dir.x, dir.y, dir.z, up.x, up.y, up.z);
8517     }
8518 
8519     /**
8520      * Set this matrix to a model transformation for a right-handed coordinate system, 
8521      * that aligns the local <code>-z</code> axis with <code>(dirX, dirY, dirZ)</code>.
8522      * <p>
8523      * In order to apply the rotation transformation to a previous existing transformation,
8524      * use {@link #rotateTowards(double, double, double, double, double, double) rotateTowards}.
8525      * <p>
8526      * This method is equivalent to calling: <code>setLookAt(0, 0, 0, -dirX, -dirY, -dirZ, upX, upY, upZ).invert()</code>
8527      * 
8528      * @see #rotateTowards(Vector3d, Vector3d)
8529      * @see #rotationTowards(double, double, double, double, double, double)
8530      * 
8531      * @param dirX
8532      *              the x-coordinate of the direction to rotate towards
8533      * @param dirY
8534      *              the y-coordinate of the direction to rotate towards
8535      * @param dirZ
8536      *              the z-coordinate of the direction to rotate towards
8537      * @param upX
8538      *              the x-coordinate of the up vector
8539      * @param upY
8540      *              the y-coordinate of the up vector
8541      * @param upZ
8542      *              the z-coordinate of the up vector
8543      * @return this
8544      */
8545     ref public Matrix4x3d rotationTowards(double dirX, double dirY, double dirZ, double upX, double upY, double upZ) return {
8546         // Normalize direction
8547         double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
8548         double ndirX = dirX * invDirLength;
8549         double ndirY = dirY * invDirLength;
8550         double ndirZ = dirZ * invDirLength;
8551         // left = up x direction
8552         double leftX, leftY, leftZ;
8553         leftX = upY * ndirZ - upZ * ndirY;
8554         leftY = upZ * ndirX - upX * ndirZ;
8555         leftZ = upX * ndirY - upY * ndirX;
8556         // normalize left
8557         double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
8558         leftX *= invLeftLength;
8559         leftY *= invLeftLength;
8560         leftZ *= invLeftLength;
8561         // up = direction x left
8562         double upnX = ndirY * leftZ - ndirZ * leftY;
8563         double upnY = ndirZ * leftX - ndirX * leftZ;
8564         double upnZ = ndirX * leftY - ndirY * leftX;
8565         this.m00 = leftX;
8566         this.m01 = leftY;
8567         this.m02 = leftZ;
8568         this.m10 = upnX;
8569         this.m11 = upnY;
8570         this.m12 = upnZ;
8571         this.m20 = ndirX;
8572         this.m21 = ndirY;
8573         this.m22 = ndirZ;
8574         this.m30 = 0.0;
8575         this.m31 = 0.0;
8576         this.m32 = 0.0;
8577         properties = PROPERTY_ORTHONORMAL;
8578         return this;
8579     }
8580 
8581     /**
8582      * Set this matrix to a model transformation for a right-handed coordinate system, 
8583      * that translates to the given <code>pos</code> and aligns the local <code>-z</code>
8584      * axis with <code>dir</code>.
8585      * <p>
8586      * This method is equivalent to calling: <code>translation(pos).rotateTowards(dir, up)</code>
8587      * 
8588      * @see #translation(Vector3d)
8589      * @see #rotateTowards(Vector3d, Vector3d)
8590      *
8591      * @param pos
8592      *              the position to translate to
8593      * @param dir
8594      *              the direction to rotate towards
8595      * @param up
8596      *              the up vector
8597      * @return this
8598      */
8599     ref public Matrix4x3d translationRotateTowards(Vector3d pos, ref Vector3d dir, Vector3d up) return {
8600         return translationRotateTowards(pos.x, pos.y, pos.z, dir.x, dir.y, dir.z, up.x, up.y, up.z);
8601     }
8602 
8603     /**
8604      * Set this matrix to a model transformation for a right-handed coordinate system, 
8605      * that translates to the given <code>(posX, posY, posZ)</code> and aligns the local <code>-z</code>
8606      * axis with <code>(dirX, dirY, dirZ)</code>.
8607      * <p>
8608      * This method is equivalent to calling: <code>translation(posX, posY, posZ).rotateTowards(dirX, dirY, dirZ, upX, upY, upZ)</code>
8609      * 
8610      * @see #translation(double, double, double)
8611      * @see #rotateTowards(double, double, double, double, double, double)
8612      * 
8613      * @param posX
8614      *              the x-coordinate of the position to translate to
8615      * @param posY
8616      *              the y-coordinate of the position to translate to
8617      * @param posZ
8618      *              the z-coordinate of the position to translate to
8619      * @param dirX
8620      *              the x-coordinate of the direction to rotate towards
8621      * @param dirY
8622      *              the y-coordinate of the direction to rotate towards
8623      * @param dirZ
8624      *              the z-coordinate of the direction to rotate towards
8625      * @param upX
8626      *              the x-coordinate of the up vector
8627      * @param upY
8628      *              the y-coordinate of the up vector
8629      * @param upZ
8630      *              the z-coordinate of the up vector
8631      * @return this
8632      */
8633     ref public Matrix4x3d translationRotateTowards(double posX, double posY, double posZ, double dirX, double dirY, double dirZ, double upX, double upY, double upZ) return {
8634         // Normalize direction
8635         double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
8636         double ndirX = dirX * invDirLength;
8637         double ndirY = dirY * invDirLength;
8638         double ndirZ = dirZ * invDirLength;
8639         // left = up x direction
8640         double leftX, leftY, leftZ;
8641         leftX = upY * ndirZ - upZ * ndirY;
8642         leftY = upZ * ndirX - upX * ndirZ;
8643         leftZ = upX * ndirY - upY * ndirX;
8644         // normalize left
8645         double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
8646         leftX *= invLeftLength;
8647         leftY *= invLeftLength;
8648         leftZ *= invLeftLength;
8649         // up = direction x left
8650         double upnX = ndirY * leftZ - ndirZ * leftY;
8651         double upnY = ndirZ * leftX - ndirX * leftZ;
8652         double upnZ = ndirX * leftY - ndirY * leftX;
8653         this.m00 = leftX;
8654         this.m01 = leftY;
8655         this.m02 = leftZ;
8656         this.m10 = upnX;
8657         this.m11 = upnY;
8658         this.m12 = upnZ;
8659         this.m20 = ndirX;
8660         this.m21 = ndirY;
8661         this.m22 = ndirZ;
8662         this.m30 = posX;
8663         this.m31 = posY;
8664         this.m32 = posZ;
8665         properties = PROPERTY_ORTHONORMAL;
8666         return this;
8667     }
8668 
8669     public Vector3d getEulerAnglesZYX(ref Vector3d dest) {
8670         dest.x = Math.atan2(m12, m22);
8671         dest.y = Math.atan2(-m02, Math.sqrt(1.0 - m02 * m02));
8672         dest.z = Math.atan2(m01, m00);
8673         return dest;
8674     }
8675 
8676     public Vector3d getEulerAnglesXYZ(ref Vector3d dest) {
8677         dest.x = Math.atan2(-m21, m22);
8678         dest.y = Math.atan2(m20, Math.sqrt(1.0 - m20 * m20));
8679         dest.z = Math.atan2(-m10, m00);
8680         return dest;
8681     }
8682 
8683     /**
8684      * Apply an oblique projection transformation to this matrix with the given values for <code>a</code> and
8685      * <code>b</code>.
8686      * <p>
8687      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the oblique transformation matrix,
8688      * then the new matrix will be <code>M * O</code>. So when transforming a
8689      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
8690      * oblique transformation will be applied first!
8691      * <p>
8692      * The oblique transformation is defined as:
8693      * <pre>
8694      * x' = x + a*z
8695      * y' = y + a*z
8696      * z' = z
8697      * </pre>
8698      * or in matrix form:
8699      * <pre>
8700      * 1 0 a 0
8701      * 0 1 b 0
8702      * 0 0 1 0
8703      * </pre>
8704      * 
8705      * @param a
8706      *            the value for the z factor that applies to x
8707      * @param b
8708      *            the value for the z factor that applies to y
8709      * @return this
8710      */
8711     ref public Matrix4x3d obliqueZ(double a, double b) return {
8712         this.m20 = m00 * a + m10 * b + m20;
8713         this.m21 = m01 * a + m11 * b + m21;
8714         this.m22 = m02 * a + m12 * b + m22;
8715         this.properties = 0;
8716         return this;
8717     }
8718 
8719     /**
8720      * Apply an oblique projection transformation to this matrix with the given values for <code>a</code> and
8721      * <code>b</code> and store the result in <code>dest</code>.
8722      * <p>
8723      * If <code>M</code> is <code>this</code> matrix and <code>O</code> the oblique transformation matrix,
8724      * then the new matrix will be <code>M * O</code>. So when transforming a
8725      * vector <code>v</code> with the new matrix by using <code>M * O * v</code>, the
8726      * oblique transformation will be applied first!
8727      * <p>
8728      * The oblique transformation is defined as:
8729      * <pre>
8730      * x' = x + a*z
8731      * y' = y + a*z
8732      * z' = z
8733      * </pre>
8734      * or in matrix form:
8735      * <pre>
8736      * 1 0 a 0
8737      * 0 1 b 0
8738      * 0 0 1 0
8739      * </pre>
8740      * 
8741      * @param a
8742      *            the value for the z factor that applies to x
8743      * @param b
8744      *            the value for the z factor that applies to y
8745      * @param dest
8746      *            will hold the result
8747      * @return dest
8748      */
8749     public Matrix4x3d obliqueZ(double a, double b, ref Matrix4x3d dest) {
8750         dest.m00 = m00;
8751         dest.m01 = m01;
8752         dest.m02 = m02;
8753         dest.m10 = m10;
8754         dest.m11 = m11;
8755         dest.m12 = m12;
8756         dest.m20 = m00 * a + m10 * b + m20;
8757         dest.m21 = m01 * a + m11 * b + m21;
8758         dest.m22 = m02 * a + m12 * b + m22;
8759         dest.m30 = m30;
8760         dest.m31 = m31;
8761         dest.m32 = m32;
8762         dest.properties = 0;
8763         return dest;
8764     }
8765 
8766     /**
8767      * Multiply <code>this</code> by the matrix
8768      * <pre>
8769      * 1 0 0 0
8770      * 0 0 1 0
8771      * 0 1 0 0
8772      * </pre>
8773      * 
8774      * @return this
8775      */
8776     ref public Matrix4x3d mapXZY() return {
8777         mapXZY(this);
8778         return this;
8779     }
8780     public Matrix4x3d mapXZY(ref Matrix4x3d dest) {
8781         double m10 = this.m10, m11 = this.m11, m12 = this.m12;
8782         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);
8783     }
8784     /**
8785      * Multiply <code>this</code> by the matrix
8786      * <pre>
8787      * 1 0  0 0
8788      * 0 0 -1 0
8789      * 0 1  0 0
8790      * </pre>
8791      * 
8792      * @return this
8793      */
8794     ref public Matrix4x3d mapXZnY() return {
8795         mapXZnY(this);
8796         return this;
8797     }
8798     public Matrix4x3d mapXZnY(ref Matrix4x3d dest) {
8799         double m10 = this.m10, m11 = this.m11, m12 = this.m12;
8800         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);
8801     }
8802     /**
8803      * Multiply <code>this</code> by the matrix
8804      * <pre>
8805      * 1  0  0 0
8806      * 0 -1  0 0
8807      * 0  0 -1 0
8808      * </pre>
8809      * 
8810      * @return this
8811      */
8812     ref public Matrix4x3d mapXnYnZ() return {
8813         mapXnYnZ(this);
8814         return this;
8815     }
8816     public Matrix4x3d mapXnYnZ(ref Matrix4x3d dest) {
8817         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);
8818     }
8819     /**
8820      * Multiply <code>this</code> by the matrix
8821      * <pre>
8822      * 1  0 0 0
8823      * 0  0 1 0
8824      * 0 -1 0 0
8825      * </pre>
8826      * 
8827      * @return this
8828      */
8829     ref public Matrix4x3d mapXnZY() return {
8830         mapXnZY(this);
8831         return this;
8832     }
8833     public Matrix4x3d mapXnZY(ref Matrix4x3d dest) {
8834         double m10 = this.m10, m11 = this.m11, m12 = this.m12;
8835         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);
8836     }
8837     /**
8838      * Multiply <code>this</code> by the matrix
8839      * <pre>
8840      * 1  0  0 0
8841      * 0  0 -1 0
8842      * 0 -1  0 0
8843      * </pre>
8844      * 
8845      * @return this
8846      */
8847     ref public Matrix4x3d mapXnZnY() return {
8848         mapXnZnY(this);
8849         return this;
8850     }
8851     public Matrix4x3d mapXnZnY(ref Matrix4x3d dest) {
8852         double m10 = this.m10, m11 = this.m11, m12 = this.m12;
8853         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);
8854     }
8855     /**
8856      * Multiply <code>this</code> by the matrix
8857      * <pre>
8858      * 0 1 0 0
8859      * 1 0 0 0
8860      * 0 0 1 0
8861      * </pre>
8862      * 
8863      * @return this
8864      */
8865     ref public Matrix4x3d mapYXZ() return {
8866         mapYXZ(this);
8867         return this;
8868     }
8869     public Matrix4x3d mapYXZ(ref Matrix4x3d dest) {
8870         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
8871         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);
8872     }
8873     /**
8874      * Multiply <code>this</code> by the matrix
8875      * <pre>
8876      * 0 1  0 0
8877      * 1 0  0 0
8878      * 0 0 -1 0
8879      * </pre>
8880      * 
8881      * @return this
8882      */
8883     ref public Matrix4x3d mapYXnZ() return {
8884         mapYXnZ(this);
8885         return this;
8886     }
8887     public Matrix4x3d mapYXnZ(ref Matrix4x3d dest) {
8888         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
8889         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);
8890     }
8891     /**
8892      * Multiply <code>this</code> by the matrix
8893      * <pre>
8894      * 0 0 1 0
8895      * 1 0 0 0
8896      * 0 1 0 0
8897      * </pre>
8898      * 
8899      * @return this
8900      */
8901     ref public Matrix4x3d mapYZX() return {
8902         mapYZX(this);
8903         return this;
8904     }
8905     public Matrix4x3d mapYZX(ref Matrix4x3d dest) {
8906         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
8907         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);
8908     }
8909     /**
8910      * Multiply <code>this</code> by the matrix
8911      * <pre>
8912      * 0 0 -1 0
8913      * 1 0  0 0
8914      * 0 1  0 0
8915      * </pre>
8916      * 
8917      * @return this
8918      */
8919     ref public Matrix4x3d mapYZnX() return {
8920         mapYZnX(this);
8921         return this;
8922     }
8923     public Matrix4x3d mapYZnX(ref Matrix4x3d dest) {
8924         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
8925         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);
8926     }
8927     /**
8928      * Multiply <code>this</code> by the matrix
8929      * <pre>
8930      * 0 -1 0 0
8931      * 1  0 0 0
8932      * 0  0 1 0
8933      * </pre>
8934      * 
8935      * @return this
8936      */
8937     ref public Matrix4x3d mapYnXZ() return {
8938         mapYnXZ(this);
8939         return this;
8940     }
8941     public Matrix4x3d mapYnXZ(ref Matrix4x3d dest) {
8942         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
8943         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);
8944     }
8945     /**
8946      * Multiply <code>this</code> by the matrix
8947      * <pre>
8948      * 0 -1  0 0
8949      * 1  0  0 0
8950      * 0  0 -1 0
8951      * </pre>
8952      * 
8953      * @return this
8954      */
8955     ref public Matrix4x3d mapYnXnZ() return {
8956         mapYnXnZ(this);
8957         return this;
8958     }
8959     public Matrix4x3d mapYnXnZ(ref Matrix4x3d dest) {
8960         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
8961         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);
8962     }
8963     /**
8964      * Multiply <code>this</code> by the matrix
8965      * <pre>
8966      * 0  0 1 0
8967      * 1  0 0 0
8968      * 0 -1 0 0
8969      * </pre>
8970      * 
8971      * @return this
8972      */
8973     ref public Matrix4x3d mapYnZX() return {
8974         mapYnZX(this);
8975         return this;
8976     }
8977     public Matrix4x3d mapYnZX(ref Matrix4x3d dest) {
8978         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
8979         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);
8980     }
8981     /**
8982      * Multiply <code>this</code> by the matrix
8983      * <pre>
8984      * 0  0 -1 0
8985      * 1  0  0 0
8986      * 0 -1  0 0
8987      * </pre>
8988      * 
8989      * @return this
8990      */
8991     ref public Matrix4x3d mapYnZnX() return {
8992         mapYnZnX(this);
8993         return this;
8994     }
8995     public Matrix4x3d mapYnZnX(ref Matrix4x3d dest) {
8996         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
8997         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);
8998     }
8999     /**
9000      * Multiply <code>this</code> by the matrix
9001      * <pre>
9002      * 0 1 0 0
9003      * 0 0 1 0
9004      * 1 0 0 0
9005      * </pre>
9006      * 
9007      * @return this
9008      */
9009     ref public Matrix4x3d mapZXY() return {
9010         mapZXY(this);
9011         return this;
9012     }
9013     public Matrix4x3d mapZXY(ref Matrix4x3d dest) {
9014         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9015         double m10 = this.m10, m11 = this.m11, m12 = this.m12;
9016         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);
9017     }
9018     /**
9019      * Multiply <code>this</code> by the matrix
9020      * <pre>
9021      * 0 1  0 0
9022      * 0 0 -1 0
9023      * 1 0  0 0
9024      * </pre>
9025      * 
9026      * @return this
9027      */
9028     ref public Matrix4x3d mapZXnY() return {
9029         mapZXnY(this);
9030         return this;
9031     }
9032     public Matrix4x3d mapZXnY(ref Matrix4x3d dest) {
9033         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9034         double m10 = this.m10, m11 = this.m11, m12 = this.m12;
9035         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);
9036     }
9037     /**
9038      * Multiply <code>this</code> by the matrix
9039      * <pre>
9040      * 0 0 1 0
9041      * 0 1 0 0
9042      * 1 0 0 0
9043      * </pre>
9044      * 
9045      * @return this
9046      */
9047     ref public Matrix4x3d mapZYX() return {
9048         mapZYX(this);
9049         return this;
9050     }
9051     public Matrix4x3d mapZYX(ref Matrix4x3d dest) {
9052         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9053         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);
9054     }
9055     /**
9056      * Multiply <code>this</code> by the matrix
9057      * <pre>
9058      * 0 0 -1 0
9059      * 0 1  0 0
9060      * 1 0  0 0
9061      * </pre>
9062      * 
9063      * @return this
9064      */
9065     ref public Matrix4x3d mapZYnX() return {
9066         mapZYnX(this);
9067         return this;
9068     }
9069     public Matrix4x3d mapZYnX(ref Matrix4x3d dest) {
9070         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9071         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);
9072     }
9073     /**
9074      * Multiply <code>this</code> by the matrix
9075      * <pre>
9076      * 0 -1 0 0
9077      * 0  0 1 0
9078      * 1  0 0 0
9079      * </pre>
9080      * 
9081      * @return this
9082      */
9083     ref public Matrix4x3d mapZnXY() return {
9084         mapZnXY(this);
9085         return this;
9086     }
9087     public Matrix4x3d mapZnXY(ref Matrix4x3d dest) {
9088         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9089         double m10 = this.m10, m11 = this.m11, m12 = this.m12;
9090         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);
9091     }
9092     /**
9093      * Multiply <code>this</code> by the matrix
9094      * <pre>
9095      * 0 -1  0 0
9096      * 0  0 -1 0
9097      * 1  0  0 0
9098      * </pre>
9099      * 
9100      * @return this
9101      */
9102     ref public Matrix4x3d mapZnXnY() return {
9103         mapZnXnY(this);
9104         return this;
9105     }
9106     public Matrix4x3d mapZnXnY(ref Matrix4x3d dest) {
9107         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9108         double m10 = this.m10, m11 = this.m11, m12 = this.m12;
9109         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);
9110     }
9111     /**
9112      * Multiply <code>this</code> by the matrix
9113      * <pre>
9114      * 0  0 1 0
9115      * 0 -1 0 0
9116      * 1  0 0 0
9117      * </pre>
9118      * 
9119      * @return this
9120      */
9121     ref public Matrix4x3d mapZnYX() return {
9122         mapZnYX(this);
9123         return this;
9124     }
9125     public Matrix4x3d mapZnYX(ref Matrix4x3d dest) {
9126         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9127         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);
9128     }
9129     /**
9130      * Multiply <code>this</code> by the matrix
9131      * <pre>
9132      * 0  0 -1 0
9133      * 0 -1  0 0
9134      * 1  0  0 0
9135      * </pre>
9136      * 
9137      * @return this
9138      */
9139     ref public Matrix4x3d mapZnYnX() return {
9140         mapZnYnX(this);
9141         return this;
9142     }
9143     public Matrix4x3d mapZnYnX(ref Matrix4x3d dest) {
9144         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9145         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);
9146     }
9147     /**
9148      * Multiply <code>this</code> by the matrix
9149      * <pre>
9150      * -1 0  0 0
9151      *  0 1  0 0
9152      *  0 0 -1 0
9153      * </pre>
9154      * 
9155      * @return this
9156      */
9157     ref public Matrix4x3d mapnXYnZ() return {
9158         mapnXYnZ(this);
9159         return this;
9160     }
9161     public Matrix4x3d mapnXYnZ(ref Matrix4x3d dest) {
9162         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);
9163     }
9164     /**
9165      * Multiply <code>this</code> by the matrix
9166      * <pre>
9167      * -1 0 0 0
9168      *  0 0 1 0
9169      *  0 1 0 0
9170      * </pre>
9171      * 
9172      * @return this
9173      */
9174     ref public Matrix4x3d mapnXZY() return {
9175         mapnXZY(this);
9176         return this;
9177     }
9178     public Matrix4x3d mapnXZY(ref Matrix4x3d dest) {
9179         double m10 = this.m10, m11 = this.m11, m12 = this.m12;
9180         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);
9181     }
9182     /**
9183      * Multiply <code>this</code> by the matrix
9184      * <pre>
9185      * -1 0  0 0
9186      *  0 0 -1 0
9187      *  0 1  0 0
9188      * </pre>
9189      * 
9190      * @return this
9191      */
9192     ref public Matrix4x3d mapnXZnY() return {
9193         mapnXZnY(this);
9194         return this;
9195     }
9196     public Matrix4x3d mapnXZnY(ref Matrix4x3d dest) {
9197         double m10 = this.m10, m11 = this.m11, m12 = this.m12;
9198         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);
9199     }
9200     /**
9201      * Multiply <code>this</code> by the matrix
9202      * <pre>
9203      * -1  0 0 0
9204      *  0 -1 0 0
9205      *  0  0 1 0
9206      * </pre>
9207      * 
9208      * @return this
9209      */
9210     ref public Matrix4x3d mapnXnYZ() return {
9211         mapnXnYZ(this);
9212         return this;
9213     }
9214     public Matrix4x3d mapnXnYZ(ref Matrix4x3d dest) {
9215         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);
9216     }
9217     /**
9218      * Multiply <code>this</code> by the matrix
9219      * <pre>
9220      * -1  0  0 0
9221      *  0 -1  0 0
9222      *  0  0 -1 0
9223      * </pre>
9224      * 
9225      * @return this
9226      */
9227     ref public Matrix4x3d mapnXnYnZ() return {
9228         mapnXnYnZ(this);
9229         return this;
9230     }
9231     public Matrix4x3d mapnXnYnZ(ref Matrix4x3d dest) {
9232         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);
9233     }
9234     /**
9235      * Multiply <code>this</code> by the matrix
9236      * <pre>
9237      * -1  0 0 0
9238      *  0  0 1 0
9239      *  0 -1 0 0
9240      * </pre>
9241      * 
9242      * @return this
9243      */
9244     ref public Matrix4x3d mapnXnZY() return {
9245         mapnXnZY(this);
9246         return this;
9247     }
9248     public Matrix4x3d mapnXnZY(ref Matrix4x3d dest) {
9249         double m10 = this.m10, m11 = this.m11, m12 = this.m12;
9250         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);
9251     }
9252     /**
9253      * Multiply <code>this</code> by the matrix
9254      * <pre>
9255      * -1  0  0 0
9256      *  0  0 -1 0
9257      *  0 -1  0 0
9258      * </pre>
9259      * 
9260      * @return this
9261      */
9262     ref public Matrix4x3d mapnXnZnY() return {
9263         mapnXnZnY(this);
9264         return this;
9265     }
9266     public Matrix4x3d mapnXnZnY(ref Matrix4x3d dest) {
9267         double m10 = this.m10, m11 = this.m11, m12 = this.m12;
9268         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);
9269     }
9270     /**
9271      * Multiply <code>this</code> by the matrix
9272      * <pre>
9273      *  0 1 0 0
9274      * -1 0 0 0
9275      *  0 0 1 0
9276      * </pre>
9277      * 
9278      * @return this
9279      */
9280     ref public Matrix4x3d mapnYXZ() return {
9281         mapnYXZ(this);
9282         return this;
9283     }
9284     public Matrix4x3d mapnYXZ(ref Matrix4x3d dest) {
9285         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9286         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);
9287     }
9288     /**
9289      * Multiply <code>this</code> by the matrix
9290      * <pre>
9291      *  0 1  0 0
9292      * -1 0  0 0
9293      *  0 0 -1 0
9294      * </pre>
9295      * 
9296      * @return this
9297      */
9298     ref public Matrix4x3d mapnYXnZ() return {
9299         mapnYXnZ(this);
9300         return this;
9301     }
9302     public Matrix4x3d mapnYXnZ(ref Matrix4x3d dest) {
9303         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9304         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);
9305     }
9306     /**
9307      * Multiply <code>this</code> by the matrix
9308      * <pre>
9309      *  0 0 1 0
9310      * -1 0 0 0
9311      *  0 1 0 0
9312      * </pre>
9313      * 
9314      * @return this
9315      */
9316     ref public Matrix4x3d mapnYZX() return {
9317         mapnYZX(this);
9318         return this;
9319     }
9320     public Matrix4x3d mapnYZX(ref Matrix4x3d dest) {
9321         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9322         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);
9323     }
9324     /**
9325      * Multiply <code>this</code> by the matrix
9326      * <pre>
9327      *  0 0 -1 0
9328      * -1 0  0 0
9329      *  0 1  0 0
9330      * </pre>
9331      * 
9332      * @return this
9333      */
9334     ref public Matrix4x3d mapnYZnX() return {
9335         mapnYZnX(this);
9336         return this;
9337     }
9338     public Matrix4x3d mapnYZnX(ref Matrix4x3d dest) {
9339         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9340         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);
9341     }
9342     /**
9343      * Multiply <code>this</code> by the matrix
9344      * <pre>
9345      *  0 -1 0 0
9346      * -1  0 0 0
9347      *  0  0 1 0
9348      * </pre>
9349      * 
9350      * @return this
9351      */
9352     ref public Matrix4x3d mapnYnXZ() return {
9353         mapnYnXZ(this);
9354         return this;
9355     }
9356     public Matrix4x3d mapnYnXZ(ref Matrix4x3d dest) {
9357         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9358         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);
9359     }
9360     /**
9361      * Multiply <code>this</code> by the matrix
9362      * <pre>
9363      *  0 -1  0 0
9364      * -1  0  0 0
9365      *  0  0 -1 0
9366      * </pre>
9367      * 
9368      * @return this
9369      */
9370     ref public Matrix4x3d mapnYnXnZ() return {
9371         mapnYnXnZ(this);
9372         return this;
9373     }
9374     public Matrix4x3d mapnYnXnZ(ref Matrix4x3d dest) {
9375         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9376         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);
9377     }
9378     /**
9379      * Multiply <code>this</code> by the matrix
9380      * <pre>
9381      *  0  0 1 0
9382      * -1  0 0 0
9383      *  0 -1 0 0
9384      * </pre>
9385      * 
9386      * @return this
9387      */
9388     ref public Matrix4x3d mapnYnZX() return {
9389         mapnYnZX(this);
9390         return this;
9391     }
9392     public Matrix4x3d mapnYnZX(ref Matrix4x3d dest) {
9393         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9394         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);
9395     }
9396     /**
9397      * Multiply <code>this</code> by the matrix
9398      * <pre>
9399      *  0  0 -1 0
9400      * -1  0  0 0
9401      *  0 -1  0 0
9402      * </pre>
9403      * 
9404      * @return this
9405      */
9406     ref public Matrix4x3d mapnYnZnX() return {
9407         mapnYnZnX(this);
9408         return this;
9409     }
9410     public Matrix4x3d mapnYnZnX(ref Matrix4x3d dest) {
9411         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9412         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);
9413     }
9414     /**
9415      * Multiply <code>this</code> by the matrix
9416      * <pre>
9417      *  0 1 0 0
9418      *  0 0 1 0
9419      * -1 0 0 0
9420      * </pre>
9421      * 
9422      * @return this
9423      */
9424     ref public Matrix4x3d mapnZXY() return {
9425         mapnZXY(this);
9426         return this;
9427     }
9428     public Matrix4x3d mapnZXY(ref Matrix4x3d dest) {
9429         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9430         double m10 = this.m10, m11 = this.m11, m12 = this.m12;
9431         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);
9432     }
9433     /**
9434      * Multiply <code>this</code> by the matrix
9435      * <pre>
9436      *  0 1  0 0
9437      *  0 0 -1 0
9438      * -1 0  0 0
9439      * </pre>
9440      * 
9441      * @return this
9442      */
9443     ref public Matrix4x3d mapnZXnY() return {
9444         mapnZXnY(this);
9445         return this;
9446     }
9447     public Matrix4x3d mapnZXnY(ref Matrix4x3d dest) {
9448         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9449         double m10 = this.m10, m11 = this.m11, m12 = this.m12;
9450         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);
9451     }
9452     /**
9453      * Multiply <code>this</code> by the matrix
9454      * <pre>
9455      *  0 0 1 0
9456      *  0 1 0 0
9457      * -1 0 0 0
9458      * </pre>
9459      * 
9460      * @return this
9461      */
9462     ref public Matrix4x3d mapnZYX() return {
9463         mapnZYX(this);
9464         return this;
9465     }
9466     public Matrix4x3d mapnZYX(ref Matrix4x3d dest) {
9467         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9468         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);
9469     }
9470     /**
9471      * Multiply <code>this</code> by the matrix
9472      * <pre>
9473      *  0 0 -1 0
9474      *  0 1  0 0
9475      * -1 0  0 0
9476      * </pre>
9477      * 
9478      * @return this
9479      */
9480     ref public Matrix4x3d mapnZYnX() return {
9481         mapnZYnX(this);
9482         return this;
9483     }
9484     public Matrix4x3d mapnZYnX(ref Matrix4x3d dest) {
9485         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9486         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);
9487     }
9488     /**
9489      * Multiply <code>this</code> by the matrix
9490      * <pre>
9491      *  0 -1 0 0
9492      *  0  0 1 0
9493      * -1  0 0 0
9494      * </pre>
9495      * 
9496      * @return this
9497      */
9498     ref public Matrix4x3d mapnZnXY() return {
9499         mapnZnXY(this);
9500         return this;
9501     }
9502     public Matrix4x3d mapnZnXY(ref Matrix4x3d dest) {
9503         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9504         double m10 = this.m10, m11 = this.m11, m12 = this.m12;
9505         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);
9506     }
9507     /**
9508      * Multiply <code>this</code> by the matrix
9509      * <pre>
9510      *  0 -1  0 0
9511      *  0  0 -1 0
9512      * -1  0  0 0
9513      * </pre>
9514      * 
9515      * @return this
9516      */
9517     ref public Matrix4x3d mapnZnXnY() return {
9518         mapnZnXnY(this);
9519         return this;
9520     }
9521     public Matrix4x3d mapnZnXnY(ref Matrix4x3d dest) {
9522         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9523         double m10 = this.m10, m11 = this.m11, m12 = this.m12;
9524         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);
9525     }
9526     /**
9527      * Multiply <code>this</code> by the matrix
9528      * <pre>
9529      *  0  0 1 0
9530      *  0 -1 0 0
9531      * -1  0 0 0
9532      * </pre>
9533      * 
9534      * @return this
9535      */
9536     ref public Matrix4x3d mapnZnYX() return {
9537         mapnZnYX(this);
9538         return this;
9539     }
9540     public Matrix4x3d mapnZnYX(ref Matrix4x3d dest) {
9541         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9542         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);
9543     }
9544     /**
9545      * Multiply <code>this</code> by the matrix
9546      * <pre>
9547      *  0  0 -1 0
9548      *  0 -1  0 0
9549      * -1  0  0 0
9550      * </pre>
9551      * 
9552      * @return this
9553      */
9554     ref public Matrix4x3d mapnZnYnX() return {
9555         mapnZnYnX(this);
9556         return this;
9557     }
9558     public Matrix4x3d mapnZnYnX(ref Matrix4x3d dest) {
9559         double m00 = this.m00, m01 = this.m01, m02 = this.m02;
9560         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);
9561     }
9562 
9563     /**
9564      * Multiply <code>this</code> by the matrix
9565      * <pre>
9566      * -1 0 0 0
9567      *  0 1 0 0
9568      *  0 0 1 0
9569      * </pre>
9570      * 
9571      * @return this
9572      */
9573     ref public Matrix4x3d negateX() return {
9574         return _m00(-m00)._m01(-m01)._m02(-m02)._properties(properties & PROPERTY_ORTHONORMAL);
9575     }
9576     public Matrix4x3d negateX(ref Matrix4x3d dest) {
9577         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);
9578     }
9579 
9580     /**
9581      * Multiply <code>this</code> by the matrix
9582      * <pre>
9583      * 1  0 0 0
9584      * 0 -1 0 0
9585      * 0  0 1 0
9586      * </pre>
9587      * 
9588      * @return this
9589      */
9590     ref public Matrix4x3d negateY() return {
9591         return _m10(-m10)._m11(-m11)._m12(-m12)._properties(properties & PROPERTY_ORTHONORMAL);
9592     }
9593     public Matrix4x3d negateY(ref Matrix4x3d dest) {
9594         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);
9595     }
9596 
9597     /**
9598      * Multiply <code>this</code> by the matrix
9599      * <pre>
9600      * 1 0  0 0
9601      * 0 1  0 0
9602      * 0 0 -1 0
9603      * </pre>
9604      * 
9605      * @return this
9606      */
9607     ref public Matrix4x3d negateZ() return {
9608         return _m20(-m20)._m21(-m21)._m22(-m22)._properties(properties & PROPERTY_ORTHONORMAL);
9609     }
9610     public Matrix4x3d negateZ(ref Matrix4x3d dest) {
9611         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);
9612     }
9613 
9614     public bool isFinite() {
9615         return Math.isFinite(m00) && Math.isFinite(m01) && Math.isFinite(m02) &&
9616                Math.isFinite(m10) && Math.isFinite(m11) && Math.isFinite(m12) &&
9617                Math.isFinite(m20) && Math.isFinite(m21) && Math.isFinite(m22) &&
9618                Math.isFinite(m30) && Math.isFinite(m31) && Math.isFinite(m32);
9619     }
9620 }