1 //------------------------------------------------------------------------------
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 //============================================================================
20 //----------------------------------------------------------------------------
21 // mat16fv.cpp : opengl-style float[16] matrix routines.
23 // OPENGL STYLE CAMERA VIEWING MATRIX ROUTINES (PREMULT/ROW VECT, 4x4 MATRIX)
24 // A POINT IN THE WORLD SPACE CAN BE TRANSFORMED TO A PIXEL ON THE CAMERA
25 // VIEWPLANE BY TRANSFORMING WITH THE COMPOSITE MATRIX: C = V*P*M
26 // WHERE V IS THE Viewport XFORM, P IS THE Projection XFORM, AND M IS THE
27 // Modelview XFORM. The associated inverse matrices are also provided.
28 // Matrices are of the following form:
33 //============================================================================
40 float* Copy16fv(float* A, const float* B) // A=B
42 A[0]=B[0]; A[1]=B[1]; A[2]=B[2]; A[3]=B[3];
43 A[4]=B[4]; A[5]=B[5]; A[6]=B[6]; A[7]=B[7];
44 A[8]=B[8]; A[9]=B[9]; A[10]=B[10]; A[11]=B[11];
45 A[12]=B[12]; A[13]=B[13]; A[14]=B[14]; A[15]=B[15];
49 float* Mult16fv(float* C, const float* A, const float* B) // C=A*B
53 tC[0] = A[0]*B[0] + A[4]*B[1] + A[8]*B[2] + A[12]*B[3];
54 tC[1] = A[1]*B[0] + A[5]*B[1] + A[9]*B[2] + A[13]*B[3];
55 tC[2] = A[2]*B[0] + A[6]*B[1] + A[10]*B[2] + A[14]*B[3];
56 tC[3] = A[3]*B[0] + A[7]*B[1] + A[11]*B[2] + A[15]*B[3];
58 tC[4] = A[0]*B[4] + A[4]*B[5] + A[8]*B[6] + A[12]*B[7];
59 tC[5] = A[1]*B[4] + A[5]*B[5] + A[9]*B[6] + A[13]*B[7];
60 tC[6] = A[2]*B[4] + A[6]*B[5] + A[10]*B[6] + A[14]*B[7];
61 tC[7] = A[3]*B[4] + A[7]*B[5] + A[11]*B[6] + A[15]*B[7];
63 tC[8] = A[0]*B[8] + A[4]*B[9] + A[8]*B[10] + A[12]*B[11];
64 tC[9] = A[1]*B[8] + A[5]*B[9] + A[9]*B[10] + A[13]*B[11];
65 tC[10] = A[2]*B[8] + A[6]*B[9] + A[10]*B[10] + A[14]*B[11];
66 tC[11] = A[3]*B[8] + A[7]*B[9] + A[11]*B[10] + A[15]*B[11];
68 tC[12] = A[0]*B[12] + A[4]*B[13] + A[8]*B[14] + A[12]*B[15];
69 tC[13] = A[1]*B[12] + A[5]*B[13] + A[9]*B[14] + A[13]*B[15];
70 tC[14] = A[2]*B[12] + A[6]*B[13] + A[10]*B[14] + A[14]*B[15];
71 tC[15] = A[3]*B[12] + A[7]*B[13] + A[11]*B[14] + A[15]*B[15];
78 float* Mult16fv3fv(float *NewV, const float* M, const float *V)
80 NewV[0] = M[0]*V[0] + M[4]*V[1] + M[8]*V[2];
81 NewV[1] = M[1]*V[0] + M[5]*V[1] + M[9]*V[2];
82 NewV[2] = M[2]*V[0] + M[6]*V[1] + M[10]*V[2];
86 float* Mult16fv3fvPerspDiv(float *NewV, const float* M, const float *V)
88 float W = M[3]*V[0] + M[7]*V[1] + M[11]*V[2] + M[15];
89 NewV[0] = (M[0]*V[0] + M[4]*V[1] + M[8]*V[2] + M[12]) / W;
90 NewV[1] = (M[1]*V[0] + M[5]*V[1] + M[9]*V[2] + M[13]) / W;
91 NewV[2] = (M[2]*V[0] + M[6]*V[1] + M[10]*V[2] + M[14]) / W;
95 float* Mult16fv4fv(float *NewV, const float* M, const float *V)
97 NewV[0] = M[0]*V[0] + M[4]*V[1] + M[8]*V[2] + M[12]*V[3];
98 NewV[1] = M[1]*V[0] + M[5]*V[1] + M[9]*V[2] + M[13]*V[3];
99 NewV[2] = M[2]*V[0] + M[6]*V[1] + M[10]*V[2] + M[14]*V[3];
100 NewV[3] = M[3]*V[0] + M[7]*V[1] + M[11]*V[2] + M[15]*V[3];
104 float* Identity16fv(float* M)
106 M[0]=M[5]=M[10]=M[15]=1;
107 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;
111 float* Transpose16fv(float* M)
113 #define SWAP(a,b,t) (t)=(a);(a)=(b);(b)=(t);
124 float* Rotate16fv(float *M, float DegAng, const float Axis[3])
126 float RadAng = DegAng * 0.0174532f;
127 float ca=(float)cos(RadAng),
128 sa=(float)sin(RadAng);
129 if (Axis[0]==1 && Axis[1]==0 && Axis[2]==0) // ABOUT X-AXIS
131 M[0]=1; M[4]=0; M[8]=0; M[12]=0;
132 M[1]=0; M[5]=ca; M[9]=-sa; M[13]=0;
133 M[2]=0; M[6]=sa; M[10]=ca; M[14]=0;
134 M[3]=0; M[7]=0; M[11]=0; M[15]=1;
136 if (Axis[0]==0 && Axis[1]==1 && Axis[2]==0) // ABOUT Y-AXIS
138 M[0]=ca; M[4]=0; M[8]=sa; M[12]=0;
139 M[1]=0; M[5]=1; M[9]=0; M[13]=0;
140 M[2]=-sa; M[6]=0; M[10]=ca; M[14]=0;
141 M[3]=0; M[7]=0; M[11]=0; M[15]=1;
143 if (Axis[0]==0 && Axis[1]==0 && Axis[2]==1) // ABOUT Z-AXIS
145 M[0]=ca; M[4]=-sa; M[8]=0; M[12]=0;
146 M[1]=sa; M[5]=ca; M[9]=0; M[13]=0;
147 M[2]=0; M[6]=0; M[10]=1; M[14]=0;
148 M[3]=0; M[7]=0; M[11]=0; M[15]=1;
150 else // ARBITRARY AXIS
152 float l = Axis[0]*Axis[0]+Axis[1]*Axis[1]+Axis[2]*Axis[2];
154 x=Axis[0],y=Axis[1],z=Axis[2];
155 if (l > 1.0001f || l < 0.9999f && l!=0)
157 // needs normalization
158 l=1.0f/(float)sqrt(l);
161 float x2=x*x, y2=y*y, z2=z*z;
162 M[0]=x2+ca*(1-x2); M[4]=(x*y)+ca*(-x*y)+sa*(-z); M[8]=(x*z)+ca*(-x*z)+sa*y;
163 M[1]=(x*y)+ca*(-x*y)+sa*z; M[5]=y2+ca*(1-y2); M[9]=(y*z)+ca*(-y*z)+sa*(-x);
164 M[2]=(x*z)+ca*(-x*z)+sa*(-y); M[6]=(y*z)+ca*(-y*z)+sa*x; M[10]=z2+ca*(1-z2);
165 M[12]=M[13]=M[14]=M[3]=M[7]=M[11]=0;
171 float* invRotate16fv(float *M, float DegAng, const float Axis[3])
173 Rotate16fv(M,DegAng,Axis);
178 float* Scale16fv(float* M, float sx, float sy, float sz)
180 M[0]=sx; M[4]=0; M[8]=0; M[12]=0;
181 M[1]=0; M[5]=sy; M[9]=0; M[13]=0;
182 M[2]=0; M[6]=0; M[10]=sz; M[14]=0;
183 M[3]=0; M[7]=0; M[11]=0; M[15]=1;
187 float* invScale16fv(float* M, float sx, float sy, float sz)
189 M[0]=1/sx; M[4]=0; M[8]=0; M[12]=0;
190 M[1]=0; M[5]=1/sy; M[9]=0; M[13]=0;
191 M[2]=0; M[6]=0; M[10]=1/sz; M[14]=0;
192 M[3]=0; M[7]=0; M[11]=0; M[15]=1;
196 float* Translate16fv(float* M, float tx, float ty, float tz)
198 M[0]=1; M[4]=0; M[8]=0; M[12]=tx;
199 M[1]=0; M[5]=1; M[9]=0; M[13]=ty;
200 M[2]=0; M[6]=0; M[10]=1; M[14]=tz;
201 M[3]=0; M[7]=0; M[11]=0; M[15]=1;
205 float* invTranslate16fv(float* M, float tx, float ty, float tz)
207 M[0]=1; M[4]=0; M[8]=0; M[12]=-tx;
208 M[1]=0; M[5]=1; M[9]=0; M[13]=-ty;
209 M[2]=0; M[6]=0; M[10]=1; M[14]=-tz;
210 M[3]=0; M[7]=0; M[11]=0; M[15]=1;
214 float* LookAt(float* M,
216 const float LookAtPt[3],
217 const float ViewUp[3])
219 float X[3], Y[3], Z[3];
220 Subtract3fv(Z,Eye,LookAtPt); Normalize3fv(Z);
221 CrossProd3fv(X,ViewUp,Z); Normalize3fv(X);
222 CrossProd3fv(Y,Z,X); Normalize3fv(Y);
223 M[0]=X[0]; M[4]=X[1]; M[8]=X[2]; M[12]=-DotProd3fv(X,Eye); // TRANS->ROT
224 M[1]=Y[0]; M[5]=Y[1]; M[9]=Y[2]; M[13]=-DotProd3fv(Y,Eye);
225 M[2]=Z[0]; M[6]=Z[1]; M[10]=Z[2]; M[14]=-DotProd3fv(Z,Eye);
226 M[3]=0; M[7]=0; M[11]=0; M[15]=1;
230 float* invLookAt(float* M,
232 const float LookAtPt[3],
233 const float ViewUp[3])
235 float X[3], Y[3], Z[3];
236 Subtract3fv(Z,Eye,LookAtPt); Normalize3fv(Z);
237 CrossProd3fv(X,ViewUp,Z); Normalize3fv(X);
238 CrossProd3fv(Y,Z,X); Normalize3fv(Y);
239 M[0]=X[0]; M[4]=Y[0]; M[8]=Z[0]; M[12]=Eye[0]; // ROT->TRANS
240 M[1]=X[1]; M[5]=Y[1]; M[9]=Z[1]; M[13]=Eye[1];
241 M[2]=X[2]; M[6]=Y[2]; M[10]=Z[2]; M[14]=Eye[2];
242 M[3]=0; M[7]=0; M[11]=0; M[15]=1;
246 float* Frustum16fv(float* M, float l, float r, float b, float t,
249 M[0]=(2*n)/(r-l); M[4]=0; M[8]=(r+l)/(r-l); M[12]=0;
250 M[1]=0; M[5]=(2*n)/(t-b); M[9]=(t+b)/(t-b); M[13]=0;
251 M[2]=0; M[6]=0; M[10]=-(f+n)/(f-n); M[14]=(-2*f*n)/(f-n);
252 M[3]=0; M[7]=0; M[11]=-1; M[15]=0;
256 float* invFrustum16fv(float* M, float l, float r, float b, float t,
259 M[0]=(r-l)/(2*n); M[4]=0; M[8]=0; M[12]=(r+l)/(2*n);
260 M[1]=0; M[5]=(t-b)/(2*n); M[9]=0; M[13]=(t+b)/(2*n);
261 M[2]=0; M[6]=0; M[10]=0; M[14]=-1;
262 M[3]=0; M[7]=0; M[11]=-(f-n)/(2*f*n); M[15]=(f+n)/(2*f*n);
266 float* Perspective(float* M, float Yfov, float Aspect,
267 float Ndist, float Fdist)
269 Yfov *= 0.0174532f; // CONVERT TO RADIANS
270 float wT=(float)tan(Yfov*0.5f)*Ndist, wB=-wT;
271 float wR=wT*Aspect, wL=-wR;
272 Frustum16fv(M,wL,wR,wB,wT,Ndist,Fdist);
276 float* invPerspective(float* M, float Yfov, float Aspect,
277 float Ndist, float Fdist)
279 Yfov *= 0.0174532f; // CONVERT TO RADIANS
280 float wT=(float)tan(Yfov*0.5f)*Ndist, wB=-wT;
281 float wR=wT*Aspect, wL=-wR;
282 invFrustum16fv(M,wL,wR,wB,wT,Ndist,Fdist);
288 const float X[3], const float Y[3], const float Z[3], const float O[3])
290 M[0]=X[0]; M[4]=X[1]; M[8]=X[2]; M[12]=-DotProd3fv(X,O);
291 M[1]=Y[0]; M[5]=Y[1]; M[9]=Y[2]; M[13]=-DotProd3fv(Y,O);
292 M[2]=Z[0]; M[6]=Z[1]; M[10]=Z[2]; M[14]=-DotProd3fv(Z,O);
293 M[3]=0; M[7]=0; M[11]=0; M[15]=1;
297 // THE INVERSE OF Viewing16fv,
298 // THIS TAKES A VIEW MATRIX AND RETURNS VIEWING AXES.
299 // MATRIX ASSUMED TO BE ORTHONORMAL
300 void Viewing2CoordFrame16fv(
301 const float *M, float X[3], float Y[3], float Z[3], float O[3])
303 X[0]=M[0]; X[1]=M[4]; X[2]=M[8]; O[0]=-DotProd3fv(M,M+12);
304 Y[0]=M[1]; Y[1]=M[5]; Y[2]=M[9]; O[1]=-DotProd3fv(M+4,M+12);
305 Z[0]=M[2]; Z[1]=M[6]; Z[2]=M[10]; O[2]=-DotProd3fv(M+8,M+12);
308 float* invViewing16fv(
310 const float X[3], const float Y[3], const float Z[3], const float O[3])
312 M[0]=X[0]; M[4]=Y[0]; M[8]=Z[0]; M[12]=O[0];
313 M[1]=X[1]; M[5]=Y[1]; M[9]=Z[1]; M[13]=O[1];
314 M[2]=X[2]; M[6]=Y[2]; M[10]=Z[2]; M[14]=O[2];
315 M[3]=0; M[7]=0; M[11]=0; M[15]=1;
319 float* Viewport16fv(float* M, int WW, int WH)
321 float WW2=(float)WW*0.5f, WH2=(float)WH*0.5f;
322 M[0]=WW2; M[4]=0; M[8]=0; M[12]=WW2;
323 M[1]=0; M[5]=WH2; M[9]=0; M[13]=WH2;
324 M[2]=0; M[6]=0; M[10]=0.5f; M[14]=0.5f;
325 M[3]=0; M[7]=0; M[11]=0; M[15]=1;
329 float* invViewport16fv(float* M, int WW, int WH)
331 float WW2=2.0f/(float)WW, WH2=2.0f/(float)WH;
332 M[0]=WW2; M[4]=0; M[8]=0; M[12]=-1.0;
333 M[1]=0; M[5]=WH2; M[9]=0; M[13]=-1.0;
334 M[2]=0; M[6]=0; M[10]=2.0; M[14]=-1.0;
335 M[3]=0; M[7]=0; M[11]=0; M[15]=1;
339 //--------------------------------------------------------------------------
340 // Given the coefficient [A B C D] of a plane in the implicit form
341 // Ax+By+Cz+D=0 (see plane.hpp), this routine generates a reflection matrix
342 // that will "reflect" all points/vectors about the given plane.
343 // NOTE: the plane is assumed to be normalized: normal vector (A,B,C) is
344 // normalized (unit-length), and D is the negative distance from the origin
345 // to the plane along the normal.
346 //--------------------------------------------------------------------------
347 float* PlanarReflection16fv(float M[16], const float P[4])
349 float AA=P[0]*P[0], AB=P[0]*P[1], AC=P[0]*P[2], AD=P[0]*P[3],
350 BB=P[1]*P[1], BC=P[1]*P[2], BD=P[1]*P[3],
351 CC=P[2]*P[2], CD=P[2]*P[3];
352 M[0]=1-2*AA; M[4]=-2*AB; M[8]=-2*AC; M[12]=-2*AD;
353 M[1]=-2*AB; M[5]=1-2*BB; M[9]=-2*BC; M[13]=-2*BD;
354 M[2]=-2*AC; M[6]=-2*BC; M[10]=1-2*CC; M[14]=-2*CD;
355 M[3]=0; M[7]=0; M[11]=0; M[15]=1;
359 //--------------------------------------------------------------------------
360 // Returns a matrix that will xform a point from the given object-space
361 // coordinate frame to world space
362 // A composite matrix is formed as follows:
363 // C = Translation * Rotation * Scaling (using column vectors/pre-multiplication)
364 // WorldPt = C * ModelPt
365 // The corresponding inverse Xform is also provided (GetWorld2ObjXform)
366 //--------------------------------------------------------------------------
367 float* Obj2WorldXform16fv(
369 const float X[3], const float Y[3], const float Z[3],
370 const float O[3], float Scale)
372 float sX[3], sY[3], sZ[3]; // CREATE SCALED VERSION OF ROT AXES
373 ScalarMult3fv(sX,X,Scale);
374 ScalarMult3fv(sY,Y,Scale);
375 ScalarMult3fv(sZ,Z,Scale);
376 M[0]=sX[0]; M[4]=sY[0]; M[8]=sZ[0]; M[12]=O[0];
377 M[1]=sX[1]; M[5]=sY[1]; M[9]=sZ[1]; M[13]=O[1];
378 M[2]=sX[2]; M[6]=sY[2]; M[10]=sZ[2]; M[14]=O[2];
379 M[3]=0; M[7]=0; M[11]=0; M[15]=1;
383 float* World2ObjXform16fv(
385 const float X[3], const float Y[3], const float Z[3],
386 const float O[3], float Scale)
388 if (Scale<=0) { printf("Too small scale!\n"); Scale=1; }
389 float invScale = 1/Scale;
390 float sX[3], sY[3], sZ[3];
391 ScalarMult3fv(sX,X,invScale);
392 ScalarMult3fv(sY,Y,invScale);
393 ScalarMult3fv(sZ,Z,invScale);
394 M[0]=sX[0]; M[4]=sX[1]; M[8]=sX[2]; M[12]=-DotProd3fv(O,sX);
395 M[1]=sY[0]; M[5]=sY[1]; M[9]=sY[2]; M[13]=-DotProd3fv(O,sY);
396 M[2]=sZ[0]; M[6]=sZ[1]; M[10]=sZ[2]; M[14]=-DotProd3fv(O,sZ);
397 M[3]=0; M[7]=0; M[11]=0; M[15]=1;
401 // ONLY TRANSLATES, ROTATES, AND SCALES ARE ALLOWED
402 float XformCoordFrame16fv(
403 const float *M, float X[3], float Y[3], float Z[3], float O[3])
405 Set3fv(X, X[0]*M[0] + X[1]*M[4] + X[2]*M[8],
406 X[0]*M[1] + X[1]*M[5] + X[2]*M[9],
407 X[0]*M[2] + X[1]*M[6] + X[2]*M[10] );
408 Set3fv(Y, Y[0]*M[0] + Y[1]*M[4] + Y[2]*M[8],
409 Y[0]*M[1] + Y[1]*M[5] + Y[2]*M[9],
410 Y[0]*M[2] + Y[1]*M[6] + Y[2]*M[10] );
411 Set3fv(Z, Z[0]*M[0] + Z[1]*M[4] + Z[2]*M[8],
412 Z[0]*M[1] + Z[1]*M[5] + Z[2]*M[9],
413 Z[0]*M[2] + Z[1]*M[6] + Z[2]*M[10] );
414 Set3fv(O, O[0]*M[0] + O[1]*M[4] + O[2]*M[8] + M[12],
415 O[0]*M[1] + O[1]*M[5] + O[2]*M[9] + M[13],
416 O[0]*M[2] + O[1]*M[6] + O[2]*M[10] + M[14] );
418 // MUST RENORMALIZE AXES TO FIND THE UNIFORM SCALE
419 float Scale = Length3fv(X);
420 ScalarDiv3fv(X,Scale);
421 ScalarDiv3fv(Y,Scale);
422 ScalarDiv3fv(Z,Scale);
424 // RETURN UNIFORM SCALING OF AXES (how much coordinate frame was scaled)
429 //----------------------------------------------------------------------------
430 // Given a complete definition for a particular view (viewing, projection,
431 // and viewport), returns the COMPOSITE xform matrix that takes a point in the
432 // world space to a screen space (pixel) point. The inverse is also provided.
433 //----------------------------------------------------------------------------
434 float* Screen2WorldXform16fv(
436 const float X[3], const float Y[3], const float Z[3], // VIEWING AXES
437 const float O[3], // VIEWING ORIGIN
438 float l, float r, float b, float t, float n, float f, // PROJECTION
439 int WW, int WH) // VIEWPORT
441 // C = InverseModelview * InverseProjection * InverseViewport
443 invViewing16fv(M,X,Y,Z,O);
444 invFrustum16fv(N,l,r,b,t,n,f);
445 Mult16fv(M,M,N); // M=M*N;
446 invViewport16fv(N,WW,WH);
447 Mult16fv(M,M,N); // M=M*N;
451 float* World2ScreenXform16fv(
453 const float X[3], const float Y[3], const float Z[3], // VIEWING AXES
454 const float O[3], // VIEWING ORIGIN
455 float l, float r, float b, float t, float n, float f, // PROJECTION
456 int WW, int WH) // VIEWPORT
458 // C = Viewport * Projection * Modelview
460 Viewport16fv(M,WW,WH);
461 Frustum16fv(N,l,r,b,t,n,f);
462 Mult16fv(M,M,N); // M=M*N;
463 Viewing16fv(N,X,Y,Z,O);
464 Mult16fv(M,M,N); // M=M*N;
468 void Print16fv(const float* M)
470 printf("\n%f %f %f %f\n",M[0],M[4],M[8],M[12]);
471 printf("%f %f %f %f\n",M[1],M[5],M[9],M[13]);
472 printf("%f %f %f %f\n",M[2],M[6],M[10],M[14]);
473 printf("%f %f %f %f\n\n",M[3],M[7],M[11],M[15]);