source: GTP/trunk/App/Demos/Vis/FriendlyCulling/src/Matrix4x4.cpp @ 2920

Revision 2920, 15.4 KB checked in by mattausch, 16 years ago (diff)
Line 
1#include "Matrix4x4.h"
2#include "Vector3.h"
3
4// standard headers
5#include "AxisAlignedBox3.h"
6#include <iomanip>
7
8using namespace std;
9
10namespace CHCDemoEngine
11{
12
13Matrix4x4::Matrix4x4()
14{}
15
16
17Matrix4x4::Matrix4x4(const Vector3 &a, const Vector3 &b, const Vector3 &c)
18{
19        // first index is column [x], the second is row [y]
20        x[0][0] = a.x;
21        x[1][0] = b.x;
22        x[2][0] = c.x;
23        x[3][0] = 0.0f;
24
25        x[0][1] = a.y;
26        x[1][1] = b.y;
27        x[2][1] = c.y;
28        x[3][1] = 0.0f;
29
30        x[0][2] = a.z;
31        x[1][2] = b.z;
32        x[2][2] = c.z;
33        x[3][2] = 0.0f;
34
35        x[0][3] = 0.0f;
36        x[1][3] = 0.0f;
37        x[2][3] = 0.0f;
38        x[3][3] = 1.0f;
39}
40
41
42void Matrix4x4::SetColumns(const Vector3 &a, const Vector3 &b, const Vector3 &c)
43{
44        // first index is column [x], the second is row [y]
45        x[0][0] = a.x;
46        x[1][0] = a.y;
47        x[2][0] = a.z;
48        x[3][0] = 0.0f;
49
50        x[0][1] = b.x;
51        x[1][1] = b.y;
52        x[2][1] = b.z;
53        x[3][1] = 0.0f;
54
55        x[0][2] = c.x;
56        x[1][2] = c.y;
57        x[2][2] = c.z;
58        x[3][2] = 0.0f;
59
60        x[0][3] = 0.0f;
61        x[1][3] = 0.0f;
62        x[2][3] = 0.0f;
63        x[3][3] = 1.0f;
64}
65
66// full constructor
67Matrix4x4::Matrix4x4(float x11, float x12, float x13, float x14,
68                                         float x21, float x22, float x23, float x24,
69                                         float x31, float x32, float x33, float x34,
70                                         float x41, float x42, float x43, float x44)
71{
72        // first index is column [x], the second is row [y]
73        x[0][0] = x11;
74        x[1][0] = x12;
75        x[2][0] = x13;
76        x[3][0] = x14;
77
78        x[0][1] = x21;
79        x[1][1] = x22;
80        x[2][1] = x23;
81        x[3][1] = x24;
82
83        x[0][2] = x31;
84        x[1][2] = x32;
85        x[2][2] = x33;
86        x[3][2] = x34;
87
88        x[0][3] = x41;
89        x[1][3] = x42;
90        x[2][3] = x43;
91        x[3][3] = x44;
92}
93
94
95float Matrix4x4::Det3x3() const
96{
97        return (x[0][0]*x[1][1]*x[2][2] + \
98                x[1][0]*x[2][1]*x[0][2] + \
99                x[2][0]*x[0][1]*x[1][2] - \
100                x[2][0]*x[1][1]*x[0][2] - \
101                x[0][0]*x[2][1]*x[1][2] - \
102                x[1][0]*x[0][1]*x[2][2]);
103}
104
105
106
107// inverse matrix computation gauss_jacobiho method .. from N.R. in C
108// if matrix is regular = computatation successfull = returns 0
109// in case of singular matrix returns 1
110int Matrix4x4::Invert()
111{
112        int indxc[4],indxr[4],ipiv[4];
113        int i,icol,irow,j,k,l,ll,n;
114        float big,dum,pivinv,temp;
115        // satisfy the compiler
116        icol = irow = 0;
117
118        // the size of the matrix
119        n = 4;
120
121        for ( j = 0 ; j < n ; j++) /* zero pivots */
122                ipiv[j] = 0;
123
124        for ( i = 0; i < n; i++)
125        {
126                big = 0.0;
127                for (j = 0 ; j < n ; j++)
128                        if (ipiv[j] != 1)
129                                for ( k = 0 ; k<n ; k++)
130                                {
131                                        if (ipiv[k] == 0)
132                                        {
133                                                if (fabs(x[k][j]) >= big)
134                                                {
135                                                        big = fabs(x[k][j]);
136                                                        irow = j;
137                                                        icol = k;
138                                                }
139                                        }
140                                        else
141                                                if (ipiv[k] > 1)
142                                                        return 1; /* singular matrix */
143                                }
144                                ++(ipiv[icol]);
145                                if (irow != icol)
146                                {
147                                        for ( l = 0 ; l<n ; l++)
148                                        {
149                                                temp = x[l][icol];
150                                                x[l][icol] = x[l][irow];
151                                                x[l][irow] = temp;
152                                        }
153                                }
154                                indxr[i] = irow;
155                                indxc[i] = icol;
156                                if (x[icol][icol] == 0.0)
157                                        return 1; /* singular matrix */
158
159                                pivinv = 1.0f / x[icol][icol];
160                                x[icol][icol] = 1.0f ;
161                                for ( l = 0 ; l<n ; l++)
162                                        x[l][icol] = x[l][icol] * pivinv ;
163
164                                for (ll = 0 ; ll < n ; ll++)
165                                        if (ll != icol)
166                                        {
167                                                dum = x[icol][ll];
168                                                x[icol][ll] = 0.0;
169                                                for ( l = 0 ; l<n ; l++)
170                                                        x[l][ll] = x[l][ll] - x[l][icol] * dum ;
171                                        }
172        }
173        for ( l = n; l--; )
174        {
175                if (indxr[l] != indxc[l])
176                        for ( k = 0; k<n ; k++)
177                        {
178                                temp = x[indxr[l]][k];
179                                x[indxr[l]][k] = x[indxc[l]][k];
180                                x[indxc[l]][k] = temp;
181                        }
182        }
183
184        return 0 ; // matrix is regular .. inversion has been succesfull
185}
186
187
188// Invert the given matrix using the above inversion routine.
189Matrix4x4 Invert(const Matrix4x4& M)
190{
191        Matrix4x4 InvertMe = M;
192        InvertMe.Invert();
193        return InvertMe;
194}
195
196
197// Transpose the matrix.
198void Matrix4x4::Transpose()
199{
200        for (int i = 0; i < 4; i++)
201                for (int j = i; j < 4; j++)
202                        if (i != j) {
203                                float temp = x[i][j];
204                                x[i][j] = x[j][i];
205                                x[j][i] = temp;
206                        }
207}
208
209
210// Transpose the given matrix using the transpose routine above.
211Matrix4x4 Transpose(const Matrix4x4& M)
212{
213        Matrix4x4 TransposeMe = M;
214        TransposeMe.Transpose();
215        return TransposeMe;
216}
217
218
219// Construct an identity matrix.
220Matrix4x4 IdentityMatrix()
221{
222        Matrix4x4 M;
223
224        for (int i = 0; i < 4; i++)
225                for (int j = 0; j < 4; j++)
226                        M.x[i][j] = (i == j) ? 1.0f : 0.0f;
227        return M;
228}
229
230
231// Construct a zero matrix.
232Matrix4x4 ZeroMatrix()
233{
234        Matrix4x4 M;
235        for (int i = 0; i < 4; i++)
236                for (int j = 0; j < 4; j++)
237                        M.x[i][j] = 0;
238        return M;
239}
240
241// Construct a translation matrix given the location to translate to.
242Matrix4x4
243TranslationMatrix(const Vector3& Location)
244{
245        Matrix4x4 M = IdentityMatrix();
246        M.x[3][0] = Location.x;
247        M.x[3][1] = Location.y;
248        M.x[3][2] = Location.z;
249        return M;
250}
251
252// Construct a rotation matrix.  Rotates Angle radians about the
253// X axis.
254Matrix4x4
255RotationXMatrix(float Angle)
256{
257        Matrix4x4 M = IdentityMatrix();
258        float Cosine = cos(Angle);
259        float Sine = sin(Angle);
260        M.x[1][1] = Cosine;
261        M.x[2][1] = -Sine;
262        M.x[1][2] = Sine;
263        M.x[2][2] = Cosine;
264        return M;
265}
266
267// Construct a rotation matrix.  Rotates Angle radians about the
268// Y axis.
269Matrix4x4 RotationYMatrix(float angle)
270{
271        Matrix4x4 m = IdentityMatrix();
272
273        float cosine = cos(angle);
274        float sine = sin(angle);
275
276        m.x[0][0] = cosine;
277        m.x[2][0] = -sine;
278        m.x[0][2] = sine;
279        m.x[2][2] = cosine;
280
281        return m;
282}
283
284
285// Construct a rotation matrix.  Rotates Angle radians about the
286// Z axis.
287Matrix4x4 RotationZMatrix(float angle)
288{
289        Matrix4x4 m = IdentityMatrix();
290
291        float cosine = cos(angle);
292        float sine = sin(angle);
293       
294        m.x[0][0] = cosine;
295        m.x[1][0] = -sine;
296        m.x[0][1] = sine;
297        m.x[1][1] = cosine;
298
299        return m;
300}
301
302
303// Construct a yaw-pitch-roll rotation matrix.  Rotate Yaw
304// radians about the XY axis, rotate Pitch radians in the
305// plane defined by the Yaw rotation, and rotate Roll radians
306// about the axis defined by the previous two angles.
307Matrix4x4 RotationYPRMatrix(float Yaw, float Pitch, float Roll)
308{
309        Matrix4x4 M;
310        float ch = cos(Yaw);
311        float sh = sin(Yaw);
312        float cp = cos(Pitch);
313        float sp = sin(Pitch);
314        float cr = cos(Roll);
315        float sr = sin(Roll);
316
317        M.x[0][0] = ch * cr + sh * sp * sr;
318        M.x[1][0] = -ch * sr + sh * sp * cr;
319        M.x[2][0] = sh * cp;
320        M.x[0][1] = sr * cp;
321        M.x[1][1] = cr * cp;
322        M.x[2][1] = -sp;
323        M.x[0][2] = -sh * cr - ch * sp * sr;
324        M.x[1][2] = sr * sh + ch * sp * cr;
325        M.x[2][2] = ch * cp;
326        for (int i = 0; i < 4; i++)
327                M.x[3][i] = M.x[i][3] = 0;
328        M.x[3][3] = 1;
329
330        return M;
331}
332
333// Construct a rotation of a given angle about a given axis.
334// Derived from Eric Haines's SPD (Standard Procedural
335// Database).
336Matrix4x4 RotationAxisMatrix(const Vector3& axis, float angle)
337{
338        Matrix4x4 M;
339
340        float cosine = cos(angle);
341        float sine = sin(angle);
342        float one_minus_cosine = 1 - cosine;
343
344        M.x[0][0] = axis.x * axis.x + (1.0f - axis.x * axis.x) * cosine;
345        M.x[0][1] = axis.x * axis.y * one_minus_cosine + axis.z * sine;
346        M.x[0][2] = axis.x * axis.z * one_minus_cosine - axis.y * sine;
347        M.x[0][3] = 0;
348
349        M.x[1][0] = axis.x * axis.y * one_minus_cosine - axis.z * sine;
350        M.x[1][1] = axis.y * axis.y + (1.0f - axis.y * axis.y) * cosine;
351        M.x[1][2] = axis.y * axis.z * one_minus_cosine + axis.x * sine;
352        M.x[1][3] = 0;
353
354        M.x[2][0] = axis.x * axis.z * one_minus_cosine + axis.y * sine;
355        M.x[2][1] = axis.y * axis.z * one_minus_cosine - axis.x * sine;
356        M.x[2][2] = axis.z * axis.z + (1.0f - axis.z * axis.z) * cosine;
357        M.x[2][3] = 0;
358
359        M.x[3][0] = 0;
360        M.x[3][1] = 0;
361        M.x[3][2] = 0;
362        M.x[3][3] = 1;
363
364        return M;
365}
366
367
368// Constructs the rotation matrix that rotates 'vec1' to 'vec2'
369Matrix4x4 RotationVectorsMatrix(const Vector3 &vecStart, const Vector3 &vecTo)
370{
371        Vector3 vec = CrossProd(vecStart, vecTo);
372
373        if (Magnitude(vec) > Limits::Small) {
374                // vector exist, compute angle
375                float angle = acos(DotProd(vecStart, vecTo));
376                // normalize for sure
377                vec.Normalize();
378                return RotationAxisMatrix(vec, angle);
379        }
380
381        // opposite or colinear vectors
382        Matrix4x4 ret = IdentityMatrix();
383        if (DotProd(vecStart, vecTo) < 0.0f)
384                ret *= -1.0f; // opposite vectors
385
386        return ret;
387}
388
389
390// Construct a scale matrix given the X, Y, and Z parameters
391// to scale by.  To scale uniformly, let X==Y==Z.
392Matrix4x4 ScaleMatrix(float X, float Y, float Z)
393{
394        Matrix4x4 M = IdentityMatrix();
395
396        M.x[0][0] = X;
397        M.x[1][1] = Y;
398        M.x[2][2] = Z;
399
400        return M;
401}
402
403
404// Construct a rotation matrix that makes the x, y, z axes
405// correspond to the vectors given.
406Matrix4x4 GenRotation(const Vector3 &x, const Vector3 &y, const Vector3 &z)
407{
408        Matrix4x4 M = IdentityMatrix();
409
410        //  x  y
411        M.x[0][0] = x.x;
412        M.x[1][0] = x.y;
413        M.x[2][0] = x.z;
414
415        M.x[0][1] = y.x;
416        M.x[1][1] = y.y;
417        M.x[2][1] = y.z;
418
419        M.x[0][2] = z.x;
420        M.x[1][2] = z.y;
421        M.x[2][2] = z.z;
422
423        return M;
424}
425
426// Construct a quadric matrix.  After Foley et al. pp. 528-529.
427Matrix4x4
428QuadricMatrix(float a, float b, float c, float d, float e,
429                          float f, float g, float h, float j, float k)
430{
431        Matrix4x4 M;
432
433        M.x[0][0] = a;  M.x[0][1] = d;  M.x[0][2] = f;  M.x[0][3] = g;
434        M.x[1][0] = d;  M.x[1][1] = b;  M.x[1][2] = e;  M.x[1][3] = h;
435        M.x[2][0] = f;  M.x[2][1] = e;  M.x[2][2] = c;  M.x[2][3] = j;
436        M.x[3][0] = g;  M.x[3][1] = h;  M.x[3][2] = j;  M.x[3][3] = k;
437
438        return M;
439}
440
441// Construct various "mirror" matrices, which flip coordinate
442// signs in the various axes specified.
443Matrix4x4
444MirrorX()
445{
446        Matrix4x4 M = IdentityMatrix();
447        M.x[0][0] = -1;
448        return M;
449}
450
451Matrix4x4
452MirrorY()
453{
454        Matrix4x4 M = IdentityMatrix();
455        M.x[1][1] = -1;
456        return M;
457}
458
459Matrix4x4
460MirrorZ()
461{
462        Matrix4x4 M = IdentityMatrix();
463        M.x[2][2] = -1;
464        return M;
465}
466
467Matrix4x4
468RotationOnly(const Matrix4x4& x)
469{
470        Matrix4x4 M = x;
471        M.x[3][0] = M.x[3][1] = M.x[3][2] = 0;
472        return M;
473}
474
475// Add corresponding elements of the two matrices.
476Matrix4x4&
477Matrix4x4::operator+= (const Matrix4x4& A)
478{
479        for (int i = 0; i < 4; i++)
480                for (int j = 0; j < 4; j++)
481                        x[i][j] += A.x[i][j];
482        return *this;
483}
484
485// Subtract corresponding elements of the matrices.
486Matrix4x4&
487Matrix4x4::operator-= (const Matrix4x4& A)
488{
489        for (int i = 0; i < 4; i++)
490                for (int j = 0; j < 4; j++)
491                        x[i][j] -= A.x[i][j];
492        return *this;
493}
494
495// Scale each element of the matrix by A.
496Matrix4x4&
497Matrix4x4::operator*= (float A)
498{
499        for (int i = 0; i < 4; i++)
500                for (int j = 0; j < 4; j++)
501                        x[i][j] *= A;
502        return *this;
503}
504
505// Multiply two matrices.
506Matrix4x4&
507Matrix4x4::operator*= (const Matrix4x4& A)
508{
509        Matrix4x4 ret = *this;
510
511        for (int i = 0; i < 4; i++)
512                for (int j = 0; j < 4; j++) {
513                        float subt = 0;
514                        for (int k = 0; k < 4; k++)
515                                subt += ret.x[i][k] * A.x[k][j];
516                        x[i][j] = subt;
517                }
518                return *this;
519}
520
521// Add corresponding elements of the matrices.
522Matrix4x4
523operator+ (const Matrix4x4& A, const Matrix4x4& B)
524{
525        Matrix4x4 ret;
526
527        for (int i = 0; i < 4; i++)
528                for (int j = 0; j < 4; j++)
529                        ret.x[i][j] = A.x[i][j] + B.x[i][j];
530        return ret;
531}
532
533// Subtract corresponding elements of the matrices.
534Matrix4x4
535operator- (const Matrix4x4& A, const Matrix4x4& B)
536{
537        Matrix4x4 ret;
538
539        for (int i = 0; i < 4; i++)
540                for (int j = 0; j < 4; j++)
541                        ret.x[i][j] = A.x[i][j] - B.x[i][j];
542        return ret;
543}
544
545// Multiply matrices.
546Matrix4x4
547operator* (const Matrix4x4& A, const Matrix4x4& B)
548{
549        Matrix4x4 ret;
550
551        for (int i = 0; i < 4; i++)
552                for (int j = 0; j < 4; j++) {
553                        float subt = 0;
554                        for (int k = 0; k < 4; k++)
555                                subt += A.x[i][k] * B.x[k][j];
556                        ret.x[i][j] = subt;
557                }
558                return ret;
559}
560
561// Transform a vector by a matrix.
562Vector3
563operator* (const Matrix4x4& M, const Vector3& v)
564{
565        Vector3 ret;
566        float denom;
567
568        ret.x = v.x * M.x[0][0] + v.y * M.x[1][0] + v.z * M.x[2][0] + M.x[3][0];
569        ret.y = v.x * M.x[0][1] + v.y * M.x[1][1] + v.z * M.x[2][1] + M.x[3][1];
570        ret.z = v.x * M.x[0][2] + v.y * M.x[1][2] + v.z * M.x[2][2] + M.x[3][2];
571        denom = M.x[0][3] + M.x[1][3] + M.x[2][3] + M.x[3][3];
572        if (denom != 1.0)
573                ret /= denom;
574        return ret;
575}
576
577// Apply the rotation portion of a matrix to a vector.
578Vector3
579RotateOnly(const Matrix4x4& M, const Vector3& v)
580{
581        Vector3 ret;
582        float denom;
583
584        ret.x = v.x * M.x[0][0] + v.y * M.x[1][0] + v.z * M.x[2][0];
585        ret.y = v.x * M.x[0][1] + v.y * M.x[1][1] + v.z * M.x[2][1];
586        ret.z = v.x * M.x[0][2] + v.y * M.x[1][2] + v.z * M.x[2][2];
587        denom = M.x[0][3] + M.x[1][3] + M.x[2][3] + M.x[3][3];
588        if (denom != 1.0)
589                ret /= denom;
590        return ret;
591}
592
593// Scale each element of the matrix by B.
594Matrix4x4
595operator* (const Matrix4x4& A, float B)
596{
597        Matrix4x4 ret;
598
599        for (int i = 0; i < 4; i++)
600                for (int j = 0; j < 4; j++)
601                        ret.x[i][j] = A.x[i][j] * B;
602        return ret;
603}
604
605// Overloaded << for C++-style output.
606ostream&
607operator<< (ostream& s, const Matrix4x4& M)
608{
609        for (int i = 0; i < 4; i++) { // y
610                for (int j = 0; j < 4; j++) { // x
611                        //  x  y
612                        s << setprecision(4) << setw(10) << M.x[j][i];
613                }
614                s << '\n';
615        }
616        return s;
617}
618
619
620Vector3 PlaneRotate(const Matrix4x4& tform, const Vector3& p)
621{
622        // I sure hope that matrix is invertible...
623        Matrix4x4 use = Transpose(Invert(tform));
624
625        return RotateOnly(use, p);
626}
627
628// Transform a normal
629Vector3 TransformNormal(const Matrix4x4& tform, const Vector3& n)
630{
631        Matrix4x4 use = NormalTransformMatrix(tform);
632
633        return RotateOnly(use, n);
634}
635
636Matrix4x4
637NormalTransformMatrix(const Matrix4x4 &tform)
638{
639        Matrix4x4 m = tform;
640        // for normal translation vector must be zero!
641        m.x[3][0] = m.x[3][1] = m.x[3][2] = 0.0;
642        // I sure hope that matrix is invertible...
643        return Transpose(Invert(m));
644}
645
646
647Vector3 GetTranslation(const Matrix4x4 &M)
648{
649        return Vector3(M.x[3][0], M.x[3][1], M.x[3][2]);
650}
651
652
653Matrix4x4 GetFittingProjectionMatrix(const AxisAlignedBox3 &box)
654{
655        Matrix4x4 m;
656
657        m.x[0][0] = 2.0f / (box.Max()[0] - box.Min()[0]);
658        m.x[0][1] = .0f;
659        m.x[0][2] = .0f;
660        m.x[0][3] = .0f;
661
662        m.x[1][0] = .0f;
663        m.x[1][1] = 2.0f / (box.Max()[1] - box.Min()[1]);
664        m.x[1][2] = .0f;
665        m.x[1][3] = .0f;
666
667        m.x[2][0] = .0f;
668        m.x[2][1] = .0f;
669        m.x[2][2] = 2.0f / (box.Max()[2] - box.Min()[2]);
670        m.x[2][3] = .0f;
671
672        m.x[3][0] = -(box.Max()[0] + box.Min()[0]) / (box.Max()[0] - box.Min()[0]);
673        m.x[3][1] = -(box.Max()[1] + box.Min()[1]) / (box.Max()[1] - box.Min()[1]);
674        m.x[3][2] = -(box.Max()[2] + box.Min()[2]) / (box.Max()[2] - box.Min()[2]);
675        m.x[3][3] = 1.0f;
676
677        return m;
678}
679
680
681//output is initialized with the same result as glFrustum
682Matrix4x4 GetFrustum(float left, float right,
683                                         float bottom, float top,
684                                         float near, float far)
685{
686        Matrix4x4 m;
687
688        const float xDif = 1.0f / (right - left);
689        const float yDif = 1.0f / (top - bottom);
690        const float zDif = 1.0f / (near - far);
691
692        m.x[0][0] = 2.0f * near * xDif;
693        m.x[0][1] = .0f;
694        m.x[0][2] = .0f;
695        m.x[0][3] = .0f;
696
697        m.x[1][0] = .0f;
698        m.x[1][1] = 2.0f * near * yDif;
699        m.x[1][2] = .0f;
700        m.x[1][3] = .0f;
701
702        m.x[2][0] = (right + left) * xDif;
703        m.x[2][1] = (top + bottom)* yDif;
704        m.x[2][2] = (far + near) * zDif;
705        m.x[2][3] = -1.0f;
706
707        m.x[3][0] = .0f;
708        m.x[3][1] = .0f;
709        m.x[3][2] = 2.0f * near * far * zDif;
710        m.x[3][3] = .0f;
711
712        return m;
713}
714
715
716Matrix4x4 LookAt(const Vector3 &pos, const Vector3 &dir, const Vector3& up)
717{
718        const Vector3 nDir = Normalize(dir);
719       
720        Vector3 nUp = Normalize(up);
721
722        Vector3 nRight = Normalize(CrossProd(nDir, nUp));
723        nUp = Normalize(CrossProd(nRight, nDir));
724
725        Matrix4x4 m;
726        Matrix4x4(nRight, nUp, -nDir);
727
728        m.x[3][0] = -DotProd(nRight, pos);
729        m.x[3][1] = -DotProd(nUp, pos);
730        m.x[3][2] = DotProd(nDir, pos);
731
732        return m;
733}
734
735}
Note: See TracBrowser for help on using the repository browser.