1 //------------------------------------------------------------------------------
2 // File : mat44impl.hpp
3 //------------------------------------------------------------------------------
4 // GLVU : Copyright 1997 - 2002
5 // The University of North Carolina at Chapel Hill
6 //------------------------------------------------------------------------------
7 // Permission to use, copy, modify, distribute and sell this software and its
8 // documentation for any purpose is hereby granted without fee, provided that
9 // the above copyright notice appear in all copies and that both that copyright
10 // notice and this permission notice appear in supporting documentation.
11 // Binaries may be compiled with this software without any royalties or
14 // The University of North Carolina at Chapel Hill makes no representations
15 // about the suitability of this software for any purpose. It is provided
16 // "as is" without express or implied warranty.
18 //============================================================================
19 // mat44.hpp : 4x4 OpenGL-style matrix template.
20 // This is the template implementation file. It is included by mat44.hpp.
21 //============================================================================
23 //---------------------------------------------------------------------------
25 //---------------------------------------------------------------------------
33 Mat44<Type>::Mat44(const Type *N)
35 M[0]=N[0]; M[4]=N[4]; M[8]=N[8]; M[12]=N[12];
36 M[1]=N[1]; M[5]=N[5]; M[9]=N[9]; M[13]=N[13];
37 M[2]=N[2]; M[6]=N[6]; M[10]=N[10]; M[14]=N[14];
38 M[3]=N[3]; M[7]=N[7]; M[11]=N[11]; M[15]=N[15];
42 Mat44<Type>::Mat44(Type M0, Type M4, Type M8, Type M12,
43 Type M1, Type M5, Type M9, Type M13,
44 Type M2, Type M6, Type M10, Type M14,
45 Type M3, Type M7, Type M11, Type M15)
47 M[0]=M0; M[4]=M4; M[8]=M8; M[12]=M12;
48 M[1]=M1; M[5]=M5; M[9]=M9; M[13]=M13;
49 M[2]=M2; M[6]=M6; M[10]=M10; M[14]=M14;
50 M[3]=M3; M[7]=M7; M[11]=M11; M[15]=M15;
53 //---------------------------------------------------------------------------
54 // MATRIX/MATRIX AND MATRIX/VECTOR OPERATORS
55 //---------------------------------------------------------------------------
57 Mat44<Type>& Mat44<Type>::operator = (const Mat44& A) // ASSIGNMENT (=)
59 M[0]=A.M[0]; M[4]=A.M[4]; M[8]=A.M[8]; M[12]=A.M[12];
60 M[1]=A.M[1]; M[5]=A.M[5]; M[9]=A.M[9]; M[13]=A.M[13];
61 M[2]=A.M[2]; M[6]=A.M[6]; M[10]=A.M[10]; M[14]=A.M[14];
62 M[3]=A.M[3]; M[7]=A.M[7]; M[11]=A.M[11]; M[15]=A.M[15];
67 Mat44<Type>& Mat44<Type>::operator = (const Type* a) {
68 for (int i=0;i<16;i++) {
75 Mat44<Type> Mat44<Type>::operator * (const Mat44& A) const // MULTIPLICATION (*)
77 Mat44<Type> NewM( M[0]*A.M[0] + M[4]*A.M[1] + M[8]*A.M[2] + M[12]*A.M[3], // ROW 1
78 M[0]*A.M[4] + M[4]*A.M[5] + M[8]*A.M[6] + M[12]*A.M[7],
79 M[0]*A.M[8] + M[4]*A.M[9] + M[8]*A.M[10] + M[12]*A.M[11],
80 M[0]*A.M[12] + M[4]*A.M[13] + M[8]*A.M[14] + M[12]*A.M[15],
82 M[1]*A.M[0] + M[5]*A.M[1] + M[9]*A.M[2] + M[13]*A.M[3], // ROW 2
83 M[1]*A.M[4] + M[5]*A.M[5] + M[9]*A.M[6] + M[13]*A.M[7],
84 M[1]*A.M[8] + M[5]*A.M[9] + M[9]*A.M[10] + M[13]*A.M[11],
85 M[1]*A.M[12] + M[5]*A.M[13] + M[9]*A.M[14] + M[13]*A.M[15],
87 M[2]*A.M[0] + M[6]*A.M[1] + M[10]*A.M[2] + M[14]*A.M[3], // ROW 3
88 M[2]*A.M[4] + M[6]*A.M[5] + M[10]*A.M[6] + M[14]*A.M[7],
89 M[2]*A.M[8] + M[6]*A.M[9] + M[10]*A.M[10] + M[14]*A.M[11],
90 M[2]*A.M[12] + M[6]*A.M[13] + M[10]*A.M[14] + M[14]*A.M[15],
92 M[3]*A.M[0] + M[7]*A.M[1] + M[11]*A.M[2] + M[15]*A.M[3], // ROW 4
93 M[3]*A.M[4] + M[7]*A.M[5] + M[11]*A.M[6] + M[15]*A.M[7],
94 M[3]*A.M[8] + M[7]*A.M[9] + M[11]*A.M[10] + M[15]*A.M[11],
95 M[3]*A.M[12] + M[7]*A.M[13] + M[11]*A.M[14] + M[15]*A.M[15] );
100 Vec3<Type> Mat44<Type>::operator * (const Vec3<Type>& V) const // MAT-VECTOR MULTIPLICATION (*) W/ PERSP DIV
102 Type W = M[3]*V.x + M[7]*V.y + M[11]*V.z + M[15];
103 Vec3<Type> NewV( (M[0]*V.x + M[4]*V.y + M[8]*V.z + M[12]) / W,
104 (M[1]*V.x + M[5]*V.y + M[9]*V.z + M[13]) / W,
105 (M[2]*V.x + M[6]*V.y + M[10]*V.z + M[14]) / W );
110 // MAT-VECTOR MULTIPLICATION _WITHOUT_ PERSP DIV
111 // For transforming normals or other pure vectors.
112 // Assumes matrix is affine, i.e. bottom row is 0,0,0,1
114 Vec3<Type> Mat44<Type>::multNormal(const Vec3<Type>& N) const
116 Vec3<Type> NewN( (M[0]*N.x + M[4]*N.y + M[8]*N.z ),
117 (M[1]*N.x + M[5]*N.y + M[9]*N.z ),
118 (M[2]*N.x + M[6]*N.y + M[10]*N.z) );
122 // MAT-POINT MULTIPLICATION _WITHOUT_ PERSP DIV
123 // (for transforming points in space)
124 // Assumes matrix is affine, i.e. bottom row is 0,0,0,1
126 Vec3<Type> Mat44<Type>::multPoint(const Vec3<Type>& P) const
128 Vec3<Type> NewP( (M[0]*P.x + M[4]*P.y + M[8]*P.z + M[12]),
129 (M[1]*P.x + M[5]*P.y + M[9]*P.z + M[13]),
130 (M[2]*P.x + M[6]*P.y + M[10]*P.z + M[14]) );
136 Vec4<Type> Mat44<Type>::operator * (const Vec4<Type>& V) const // MAT-VECTOR MULTIPLICATION (*)
139 NewV.x = M[0]*V.x + M[4]*V.y + M[8]*V.z + M[12]*V.w;
140 NewV.y = M[1]*V.x + M[5]*V.y + M[9]*V.z + M[13]*V.w;
141 NewV.z = M[2]*V.x + M[6]*V.y + M[10]*V.z + M[14]*V.w;
142 NewV.w = M[3]*V.x + M[7]*V.y + M[11]*V.z + M[15]*V.w;
148 Mat44<Type> Mat44<Type>::operator * (Type a) const // SCALAR POST-MULTIPLICATION
150 Mat44<Type> NewM( M[0] * a, M[1] * a, M[2] * a, M[3] * a,
151 M[4] * a, M[5] * a, M[6] * a, M[7] * a,
152 M[8] * a, M[9] * a, M[10] * a, M[11] * a,
153 M[12] * a, M[13] * a, M[14] * a, M[15] * a);
158 Mat44<Type>& Mat44<Type>::operator *= (Type a) // SCALAR ACCUMULATE POST-MULTIPLICATION
160 for (int i = 0; i < 16; i++)
169 Mat44<Type>::operator const Type*() const
175 Mat44<Type>::operator Type*()
181 Type& Mat44<Type>::operator()(int col, int row)
187 const Type& Mat44<Type>::operator()(int col, int row) const
193 void Mat44<Type>::Set(const Type* a)
195 for (int i=0;i<16;i++) {
202 void Mat44<Type>::Set(Type M0, Type M4, Type M8, Type M12,
203 Type M1, Type M5, Type M9, Type M13,
204 Type M2, Type M6, Type M10, Type M14,
205 Type M3, Type M7, Type M11, Type M15)
207 M[0]=M0; M[4]=M4; M[8]=M8; M[12]=M12;
208 M[1]=M1; M[5]=M5; M[9]=M9; M[13]=M13;
209 M[2]=M2; M[6]=M6; M[10]=M10; M[14]=M14;
210 M[3]=M3; M[7]=M7; M[11]=M11; M[15]=M15;
214 //---------------------------------------------------------------------------
215 // Standard Matrix Operations
216 //---------------------------------------------------------------------------
218 void Mat44<Type>::Identity()
220 M[0]=M[5]=M[10]=M[15]=1;
221 M[1]=M[2]=M[3]=M[4]=M[6]=M[7]=M[8]=M[9]=M[11]=M[12]=M[13]=M[14]=0;
225 void Mat44<Type>::Transpose()
235 //---------------------------------------------------------------------------
236 // Standard Matrix Affine Transformations
237 //---------------------------------------------------------------------------
238 template <class Type>
239 void Mat44<Type>::Translate(Type Tx, Type Ty, Type Tz)
241 M[0]=1; M[4]=0; M[8]=0; M[12]=Tx;
242 M[1]=0; M[5]=1; M[9]=0; M[13]=Ty;
243 M[2]=0; M[6]=0; M[10]=1; M[14]=Tz;
244 M[3]=0; M[7]=0; M[11]=0; M[15]=1;
248 void Mat44<Type>::Translate(const Vec3<Type>& T)
250 M[0]=1; M[4]=0; M[8]=0; M[12]=T.x;
251 M[1]=0; M[5]=1; M[9]=0; M[13]=T.y;
252 M[2]=0; M[6]=0; M[10]=1; M[14]=T.z;
253 M[3]=0; M[7]=0; M[11]=0; M[15]=1;
257 void Mat44<Type>::invTranslate(Type Tx, Type Ty, Type Tz)
259 M[0]=1; M[4]=0; M[8]=0; M[12]=-Tx;
260 M[1]=0; M[5]=1; M[9]=0; M[13]=-Ty;
261 M[2]=0; M[6]=0; M[10]=1; M[14]=-Tz;
262 M[3]=0; M[7]=0; M[11]=0; M[15]=1;
266 void Mat44<Type>::invTranslate(const Vec3<Type>& T)
268 M[0]=1; M[4]=0; M[8]=0; M[12]=-T.x;
269 M[1]=0; M[5]=1; M[9]=0; M[13]=-T.y;
270 M[2]=0; M[6]=0; M[10]=1; M[14]=-T.z;
271 M[3]=0; M[7]=0; M[11]=0; M[15]=1;
275 void Mat44<Type>::Scale(Type Sx, Type Sy, Type Sz)
277 M[0]=Sx; M[4]=0; M[8]=0; M[12]=0;
278 M[1]=0; M[5]=Sy; M[9]=0; M[13]=0;
279 M[2]=0; M[6]=0; M[10]=Sz; M[14]=0;
280 M[3]=0; M[7]=0; M[11]=0; M[15]=1;
284 void Mat44<Type>::Scale(const Vec3<Type>& S)
286 M[0]=S.x; M[4]=0; M[8]=0; M[12]=0;
287 M[1]=0; M[5]=S.y; M[9]=0; M[13]=0;
288 M[2]=0; M[6]=0; M[10]=S.z; M[14]=0;
289 M[3]=0; M[7]=0; M[11]=0; M[15]=1;
293 void Mat44<Type>::invScale(Type Sx, Type Sy, Type Sz)
295 M[0]=1/Sx; M[4]=0; M[8]=0; M[12]=0;
296 M[1]=0; M[5]=1/Sy; M[9]=0; M[13]=0;
297 M[2]=0; M[6]=0; M[10]=1/Sz; M[14]=0;
298 M[3]=0; M[7]=0; M[11]=0; M[15]=1;
302 void Mat44<Type>::invScale(const Vec3<Type>& S)
304 M[0]=1/S.x; M[4]=0; M[8]=0; M[12]=0;
305 M[1]=0; M[5]=1/S.y; M[9]=0; M[13]=0;
306 M[2]=0; M[6]=0; M[10]=1/S.z; M[14]=0;
307 M[3]=0; M[7]=0; M[11]=0; M[15]=1;
311 void Mat44<Type>::Rotate(Type DegAng, const Vec3<Type>& Axis)
313 Type RadAng = DegAng*Mat44TORADS;
314 Type ca=(Type)cos(RadAng),
315 sa=(Type)sin(RadAng);
316 if (Axis.x==1 && Axis.y==0 && Axis.z==0) // ABOUT X-AXIS
318 M[0]=1; M[4]=0; M[8]=0; M[12]=0;
319 M[1]=0; M[5]=ca; M[9]=-sa; M[13]=0;
320 M[2]=0; M[6]=sa; M[10]=ca; M[14]=0;
321 M[3]=0; M[7]=0; M[11]=0; M[15]=1;
323 else if (Axis.x==0 && Axis.y==1 && Axis.z==0) // ABOUT Y-AXIS
325 M[0]=ca; M[4]=0; M[8]=sa; M[12]=0;
326 M[1]=0; M[5]=1; M[9]=0; M[13]=0;
327 M[2]=-sa; M[6]=0; M[10]=ca; M[14]=0;
328 M[3]=0; M[7]=0; M[11]=0; M[15]=1;
330 else if (Axis.x==0 && Axis.y==0 && Axis.z==1) // ABOUT Z-AXIS
332 M[0]=ca; M[4]=-sa; M[8]=0; M[12]=0;
333 M[1]=sa; M[5]=ca; M[9]=0; M[13]=0;
334 M[2]=0; M[6]=0; M[10]=1; M[14]=0;
335 M[3]=0; M[7]=0; M[11]=0; M[15]=1;
337 else // ARBITRARY AXIS
339 Type l = Axis.LengthSqr();
341 x=Axis.x, y=Axis.y, z=Axis.z;
342 if (l > Type(1.0001) || l < Type(0.9999) && l!=0)
344 // needs normalization
348 Type x2=x*x, y2=y*y, z2=z*z;
349 M[0]=x2+ca*(1-x2); M[4]=(x*y)+ca*(-x*y)+sa*(-z); M[8]=(x*z)+ca*(-x*z)+sa*y;
350 M[1]=(x*y)+ca*(-x*y)+sa*z; M[5]=y2+ca*(1-y2); M[9]=(y*z)+ca*(-y*z)+sa*(-x);
351 M[2]=(x*z)+ca*(-x*z)+sa*(-y); M[6]=(y*z)+ca*(-y*z)+sa*x; M[10]=z2+ca*(1-z2);
352 M[12]=M[13]=M[14]=M[3]=M[7]=M[11]=0;
358 void Mat44<Type>::invRotate(Type DegAng, const Vec3<Type>& Axis)
365 inline Type Mat44<Type>::Trace() const
367 return M[0] + M[5] + M[10] + M[15];
370 //---------------------------------------------------------------------------
371 // Same as glFrustum() : Perspective transformation matrix defined by a
372 // truncated pyramid viewing frustum that starts at the origin (eye)
373 // going in the -Z axis direction (viewer looks down -Z)
374 // with the four pyramid sides passing through the sides of a window
375 // defined through x=l, x=r, y=b, y=t on the viewplane at z=-n.
376 // The top and bottom of the pyramid are truncated by the near and far
377 // planes at z=-n and z=-f. A 4-vector (x,y,z,w) inside this frustum
378 // transformed by this matrix will have x,y,z values in the range
379 // [-w,w]. Homogeneous clipping is applied to restrict (x,y,z) to
380 // this range. Later, a perspective divide by w will result in an NDC
381 // coordinate 3-vector of the form (x/w,y/w,z/w,w/w)=(x',y',z',1) where
382 // x', y', and z' all are in the range [-1,1]. Perspectively divided z'
383 // will be in [-1,1] with -1 being the near plane and +1 being the far.
384 //---------------------------------------------------------------------------
386 void Mat44<Type>::Frustum(Type l, Type r, Type b, Type t, Type n, Type f)
388 M[0]=(2*n)/(r-l); M[4]=0; M[8]=(r+l)/(r-l); M[12]=0;
389 M[1]=0; M[5]=(2*n)/(t-b); M[9]=(t+b)/(t-b); M[13]=0;
390 M[2]=0; M[6]=0; M[10]=-(f+n)/(f-n); M[14]=(-2*f*n)/(f-n);
391 M[3]=0; M[7]=0; M[11]=-1; M[15]=0;
395 void Mat44<Type>::invFrustum(Type l, Type r, Type b, Type t, Type n, Type f)
397 M[0]=(r-l)/(2*n); M[4]=0; M[8]=0; M[12]=(r+l)/(2*n);
398 M[1]=0; M[5]=(t-b)/(2*n); M[9]=0; M[13]=(t+b)/(2*n);
399 M[2]=0; M[6]=0; M[10]=0; M[14]=-1;
400 M[3]=0; M[7]=0; M[11]=-(f-n)/(2*f*n); M[15]=(f+n)/(2*f*n);
403 //---------------------------------------------------------------------------
404 // Same as gluPerspective : calls Frustum()
405 //---------------------------------------------------------------------------
407 void Mat44<Type>::Perspective(Type Yfov, Type Aspect, Type Ndist, Type Fdist)
409 Yfov *= 0.0174532f; // CONVERT TO RADIANS
410 Type wT=tanf(Yfov*0.5f)*Ndist, wB=-wT;
411 Type wR=wT*Aspect, wL=-wR;
412 Frustum(wL,wR,wB,wT,Ndist,Fdist);
416 void Mat44<Type>::invPerspective(Type Yfov, Type Aspect, Type Ndist, Type Fdist)
418 Yfov *= 0.0174532f; // CONVERT TO RADIANS
419 Type wT=tanf(Yfov*0.5f)*Ndist, wB=-wT;
420 Type wR=wT*Aspect, wL=-wR;
421 invFrustum(wL,wR,wB,wT,Ndist,Fdist);
424 //---------------------------------------------------------------------------
425 // OpenGL VIEWPORT XFORM MATRIX : given Window width and height in pixels
426 // Transforms the x,y,z NDC values in [-1,1] to (x',y') pixel values and
427 // normalized z' in [0,1] (near and far respectively).
428 //---------------------------------------------------------------------------
430 void Mat44<Type>::Viewport(int WW, int WH)
432 Type WW2=(Type)WW*0.5f, WH2=(Type)WH*0.5f;
433 M[0]=WW2; M[4]=0; M[8]=0; M[12]=WW2;
434 M[1]=0; M[5]=WH2; M[9]=0; M[13]=WH2;
435 M[2]=0; M[6]=0; M[10]=0.5; M[14]=0.5;
436 M[3]=0; M[7]=0; M[11]=0; M[15]=1;
440 void Mat44<Type>::invViewport(int WW, int WH)
442 Type WW2=2.0f/(Type)WW, WH2=2.0f/(Type)WH;
443 M[0]=WW2; M[4]=0; M[8]=0; M[12]=-1.0;
444 M[1]=0; M[5]=WH2; M[9]=0; M[13]=-1.0;
445 M[2]=0; M[6]=0; M[10]=2.0; M[14]=-1.0;
446 M[3]=0; M[7]=0; M[11]=0; M[15]=1;
449 //---------------------------------------------------------------------------
450 // Same as gluLookAt()
451 //---------------------------------------------------------------------------
453 void Mat44<Type>::LookAt(const Vec3<Type>& Eye,
454 const Vec3<Type>& LookAtPt,
455 const Vec3<Type>& ViewUp)
457 Vec3<Type> Z = Eye-LookAtPt; Z.Normalize(); // CALC CAM AXES ("/" IS CROSS-PROD)
458 Vec3<Type> X = ViewUp/Z; X.Normalize();
459 Vec3<Type> Y = Z/X; Y.Normalize();
460 Vec3<Type> Tr = -Eye;
461 M[0]=X.x; M[4]=X.y; M[8]=X.z; M[12]=X*Tr; // TRANS->ROT
462 M[1]=Y.x; M[5]=Y.y; M[9]=Y.z; M[13]=Y*Tr;
463 M[2]=Z.x; M[6]=Z.y; M[10]=Z.z; M[14]=Z*Tr;
464 M[3]=0; M[7]=0; M[11]=0; M[15]=1;
468 void Mat44<Type>::invLookAt(const Vec3<Type>& Eye,
469 const Vec3<Type>& LookAtPt,
470 const Vec3<Type>& ViewUp)
472 Vec3<Type> Z = Eye-LookAtPt; Z.Normalize(); // CALC CAM AXES ("/" IS CROSS-PROD)
473 Vec3<Type> X = ViewUp/Z; X.Normalize();
474 Vec3<Type> Y = Z/X; Y.Normalize();
475 M[0]=X.x; M[4]=Y.x; M[8]=Z.x; M[12]=Eye.x; // ROT->TRANS
476 M[1]=X.y; M[5]=Y.y; M[9]=Z.y; M[13]=Eye.y;
477 M[2]=X.z; M[6]=Y.z; M[10]=Z.z; M[14]=Eye.z;
478 M[3]=0; M[7]=0; M[11]=0; M[15]=1;
481 //---------------------------------------------------------------------------
482 // VIEWPORT TRANFORMATION MATRIX : given Window width and height in pixels
483 // FROM "JIM BLINN'S CORNER" JULY '91. This function transforms an
484 // 4-vector in homogeneous space of the form (x,y,z,w) where
485 // -w<=x,y,z<=w into (x',y',z',1) where (x',y') is the vectors
486 // projected pixel location in ([0,WW-1],[0,WH-1]) and z' is the
487 // normalized depth value mapped into [0,1]; 0 is the near plane
488 // and 1 is the far plane. Mat44VIEWPORT_TOL is introduced to have correct
489 // mappings. (-1,-1,?,?) in NDC refers to the bottom-left of the
490 // viewplane window and (0,0,?,?) in screen space refers to the
491 // bottom-left pixel.
492 //---------------------------------------------------------------------------
494 void Mat44<Type>::Viewport2(int WW, int WH)
496 Type WW2=(WW-Mat44VIEWPORT_TOL)*0.5f, WH2=(WH-Mat44VIEWPORT_TOL)*0.5f;
497 M[0]=WW2; M[4]=0; M[8]=0; M[12]=WW2;
498 M[1]=0; M[5]=WH2; M[9]=0; M[13]=WH2;
499 M[2]=0; M[6]=0; M[10]=0.5; M[14]=0.5;
500 M[3]=0; M[7]=0; M[11]=0; M[15]=1;
504 void Mat44<Type>::invViewport2(int WW, int WH)
506 Type WW2=2.0f/(WW-Mat44VIEWPORT_TOL), WH2=2.0f/(WH-Mat44VIEWPORT_TOL);
507 M[0]=WW2; M[4]=0; M[8]=0; M[12]=-1.0;
508 M[1]=0; M[5]=WH2; M[9]=0; M[13]=-1.0;
509 M[2]=0; M[6]=0; M[10]=2.0; M[14]=-1.0;
510 M[3]=0; M[7]=0; M[11]=0; M[15]=1;
513 //---------------------------------------------------------------------------
514 // Handy matrix printing routine.
515 //---------------------------------------------------------------------------
517 void Mat44<Type>::Print() const
519 printf("\n%f %f %f %f\n",M[0],M[4],M[8],M[12]);
520 printf("%f %f %f %f\n",M[1],M[5],M[9],M[13]);
521 printf("%f %f %f %f\n",M[2],M[6],M[10],M[14]);
522 printf("%f %f %f %f\n\n",M[3],M[7],M[11],M[15]);
525 //---------------------------------------------------------------------------
526 // Copy contents of matrix into matrix array.
527 //---------------------------------------------------------------------------
529 void Mat44<Type>::CopyInto(Type *Mat) const
531 Mat[0]=M[0]; Mat[4]=M[4]; Mat[8]=M[8]; Mat[12]=M[12];
532 Mat[1]=M[1]; Mat[5]=M[5]; Mat[9]=M[9]; Mat[13]=M[13];
533 Mat[2]=M[2]; Mat[6]=M[6]; Mat[10]=M[10]; Mat[14]=M[14];
534 Mat[3]=M[3]; Mat[7]=M[7]; Mat[11]=M[11]; Mat[15]=M[15];