1 /*
2  * The 3D Studio File Format Library
3  * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
4  * All rights reserved.
5  *
6  * This program is  free  software;  you can redistribute it and/or modify it
7  * under the terms of the  GNU Lesser General Public License  as published by
8  * the  Free Software Foundation;  either version 2.1 of the License,  or (at
9  * your option) any later version.
10  *
11  * This  program  is  distributed in  the  hope that it will  be useful,  but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13  * or  FITNESS FOR A  PARTICULAR PURPOSE.  See the  GNU Lesser General Public
14  * License for more details.
15  *
16  * You should  have received  a copy of the GNU Lesser General Public License
17  * along with  this program;  if not, write to the  Free Software Foundation,
18  * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  *
20  * $Id: matrix.c,v 1.14 2007/06/20 17:04:08 jeh Exp $
21  */
22 #include <lib3ds/matrix.h>
23 #include <lib3ds/quat.h>
24 #include <lib3ds/vector.h>
25 #include <string.h>
26 #include <math.h>
27 
28 
29 /*!
30  * \defgroup matrix Matrix Mathematics
31  */
32 
33 
34 /*!
35 * \typedef Lib3dsMatrix
36 * \ingroup matrix
37 */
38 
39 
40 /*!
41  * Clear a matrix to all zeros.
42  *
43  * \param m Matrix to be cleared.
44  *
45  * \ingroup matrix
46  */
47 void
lib3ds_matrix_zero(Lib3dsMatrix m)48 lib3ds_matrix_zero(Lib3dsMatrix m)
49 {
50   int i,j;
51 
52   for (i=0; i<4; i++) {
53     for (j=0; j<4; j++) m[i][j]=0.0f;
54   }
55 }
56 
57 
58 /*!
59  * Set a matrix to identity.
60  *
61  * \param m Matrix to be set.
62  *
63  * \ingroup matrix
64  */
65 void
lib3ds_matrix_identity(Lib3dsMatrix m)66 lib3ds_matrix_identity(Lib3dsMatrix m)
67 {
68   int i,j;
69 
70   for (i=0; i<4; i++) {
71     for (j=0; j<4; j++) m[i][j]=0.0;
72   }
73   for (i=0; i<4; i++) m[i][i]=1.0;
74 }
75 
76 
77 /*!
78  * Copy a matrix.
79  *
80  * \ingroup matrix
81  */
82 void
lib3ds_matrix_copy(Lib3dsMatrix dest,Lib3dsMatrix src)83 lib3ds_matrix_copy(Lib3dsMatrix dest, Lib3dsMatrix src)
84 {
85   memcpy(dest, src, sizeof(Lib3dsMatrix));
86 }
87 
88 
89 /*!
90  * Negate a matrix -- all elements negated.
91  *
92  * \ingroup matrix
93  */
94 void
lib3ds_matrix_neg(Lib3dsMatrix m)95 lib3ds_matrix_neg(Lib3dsMatrix m)
96 {
97   int i,j;
98 
99   for (j=0; j<4; j++) {
100     for (i=0; i<4; i++) {
101       m[j][i]=-m[j][i];
102     }
103   }
104 }
105 
106 
107 /*!
108  * Set all matrix elements to their absolute value.
109  *
110  * \ingroup matrix
111  */
112 void
lib3ds_matrix_abs(Lib3dsMatrix m)113 lib3ds_matrix_abs(Lib3dsMatrix m)
114 {
115   int i,j;
116 
117   for (j=0; j<4; j++) {
118     for (i=0; i<4; i++) {
119       m[j][i]=(Lib3dsFloat)fabs(m[j][i]);
120     }
121   }
122 }
123 
124 
125 /*!
126  * Transpose a matrix in place.
127  *
128  * \ingroup matrix
129  */
130 void
lib3ds_matrix_transpose(Lib3dsMatrix m)131 lib3ds_matrix_transpose(Lib3dsMatrix m)
132 {
133   int i,j;
134   Lib3dsFloat swp;
135 
136   for (j=0; j<4; j++) {
137     for (i=j+1; i<4; i++) {
138       swp=m[j][i];
139       m[j][i]=m[i][j];
140       m[i][j]=swp;
141     }
142   }
143 }
144 
145 
146 /*!
147  * Add two matrices.
148  *
149  * \ingroup matrix
150  */
151 void
_lib3ds_matrix_add(Lib3dsMatrix m,Lib3dsMatrix a,Lib3dsMatrix b)152 _lib3ds_matrix_add(Lib3dsMatrix m, Lib3dsMatrix a, Lib3dsMatrix b)
153 {
154   int i,j;
155 
156   for (j=0; j<4; j++) {
157     for (i=0; i<4; i++) {
158       m[j][i]=a[j][i]+b[j][i];
159     }
160   }
161 }
162 
163 
164 /*!
165  * Subtract two matrices.
166  *
167  * \param m Result.
168  * \param a Addend.
169  * \param b Minuend.
170  *
171  * \ingroup matrix
172  */
173 void
_lib3ds_matrix_sub(Lib3dsMatrix m,Lib3dsMatrix a,Lib3dsMatrix b)174 _lib3ds_matrix_sub(Lib3dsMatrix m, Lib3dsMatrix a, Lib3dsMatrix b)
175 {
176   int i,j;
177 
178   for (j=0; j<4; j++) {
179     for (i=0; i<4; i++) {
180       m[j][i]=a[j][i]-b[j][i];
181     }
182   }
183 }
184 
185 
186 /*!
187  * Multiplies a matrix by a second one (m = m * n).
188  *
189  * \ingroup matrix
190  */
191 void
lib3ds_matrix_mult(Lib3dsMatrix m,Lib3dsMatrix n)192 lib3ds_matrix_mult(Lib3dsMatrix m, Lib3dsMatrix n)
193 {
194   Lib3dsMatrix tmp;
195   int i,j,k;
196   Lib3dsFloat ab;
197 
198   memcpy(tmp, m, sizeof(Lib3dsMatrix));
199   for (j=0; j<4; j++) {
200     for (i=0; i<4; i++) {
201       ab=0.0f;
202       for (k=0; k<4; k++) ab+=tmp[k][i]*n[j][k];
203       m[j][i]=ab;
204     }
205   }
206 }
207 
208 
209 /*!
210  * Multiply a matrix by a scalar.
211  *
212  * \param m Matrix to be set.
213  * \param k Scalar.
214  *
215  * \ingroup matrix
216  */
217 void
lib3ds_matrix_scalar(Lib3dsMatrix m,Lib3dsFloat k)218 lib3ds_matrix_scalar(Lib3dsMatrix m, Lib3dsFloat k)
219 {
220   int i,j;
221 
222   for (j=0; j<4; j++) {
223     for (i=0; i<4; i++) {
224       m[j][i]*=k;
225     }
226   }
227 }
228 
229 
230 static Lib3dsFloat
det2x2(Lib3dsFloat a,Lib3dsFloat b,Lib3dsFloat c,Lib3dsFloat d)231 det2x2(
232   Lib3dsFloat a, Lib3dsFloat b,
233   Lib3dsFloat c, Lib3dsFloat d)
234 {
235   return((a)*(d)-(b)*(c));
236 }
237 
238 
239 static Lib3dsFloat
det3x3(Lib3dsFloat a1,Lib3dsFloat a2,Lib3dsFloat a3,Lib3dsFloat b1,Lib3dsFloat b2,Lib3dsFloat b3,Lib3dsFloat c1,Lib3dsFloat c2,Lib3dsFloat c3)240 det3x3(
241   Lib3dsFloat a1, Lib3dsFloat a2, Lib3dsFloat a3,
242   Lib3dsFloat b1, Lib3dsFloat b2, Lib3dsFloat b3,
243   Lib3dsFloat c1, Lib3dsFloat c2, Lib3dsFloat c3)
244 {
245   return(
246     a1*det2x2(b2,b3,c2,c3)-
247     b1*det2x2(a2,a3,c2,c3)+
248     c1*det2x2(a2,a3,b2,b3)
249   );
250 }
251 
252 
253 /*!
254  * Find determinant of a matrix.
255  *
256  * \ingroup matrix
257  */
258 Lib3dsFloat
lib3ds_matrix_det(Lib3dsMatrix m)259 lib3ds_matrix_det(Lib3dsMatrix m)
260 {
261   Lib3dsFloat a1,a2,a3,a4,b1,b2,b3,b4,c1,c2,c3,c4,d1,d2,d3,d4;
262 
263   a1 = m[0][0];
264   b1 = m[1][0];
265   c1 = m[2][0];
266   d1 = m[3][0];
267   a2 = m[0][1];
268   b2 = m[1][1];
269   c2 = m[2][1];
270   d2 = m[3][1];
271   a3 = m[0][2];
272   b3 = m[1][2];
273   c3 = m[2][2];
274   d3 = m[3][2];
275   a4 = m[0][3];
276   b4 = m[1][3];
277   c4 = m[2][3];
278   d4 = m[3][3];
279   return(
280     a1 * det3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4)-
281     b1 * det3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4)+
282     c1 * det3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4)-
283     d1 * det3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4)
284   );
285 }
286 
287 
288 /*!
289  * Find the adjoint of a matrix.
290  *
291  * \ingroup matrix
292  */
293 void
lib3ds_matrix_adjoint(Lib3dsMatrix m)294 lib3ds_matrix_adjoint(Lib3dsMatrix m)
295 {
296   Lib3dsFloat a1,a2,a3,a4,b1,b2,b3,b4,c1,c2,c3,c4,d1,d2,d3,d4;
297 
298   a1 = m[0][0];
299   b1 = m[1][0];
300   c1 = m[2][0];
301   d1 = m[3][0];
302   a2 = m[0][1];
303   b2 = m[1][1];
304   c2 = m[2][1];
305   d2 = m[3][1];
306   a3 = m[0][2];
307   b3 = m[1][2];
308   c3 = m[2][2];
309   d3 = m[3][2];
310   a4 = m[0][3];
311   b4 = m[1][3];
312   c4 = m[2][3];
313   d4 = m[3][3];
314   m[0][0]=  det3x3 (b2, b3, b4, c2, c3, c4, d2, d3, d4);
315   m[0][1]= -det3x3 (a2, a3, a4, c2, c3, c4, d2, d3, d4);
316   m[0][2]=  det3x3 (a2, a3, a4, b2, b3, b4, d2, d3, d4);
317   m[0][3]= -det3x3 (a2, a3, a4, b2, b3, b4, c2, c3, c4);
318   m[1][0]= -det3x3 (b1, b3, b4, c1, c3, c4, d1, d3, d4);
319   m[1][1]=  det3x3 (a1, a3, a4, c1, c3, c4, d1, d3, d4);
320   m[1][2]= -det3x3 (a1, a3, a4, b1, b3, b4, d1, d3, d4);
321   m[1][3]=  det3x3 (a1, a3, a4, b1, b3, b4, c1, c3, c4);
322   m[2][0]=  det3x3 (b1, b2, b4, c1, c2, c4, d1, d2, d4);
323   m[2][1]= -det3x3 (a1, a2, a4, c1, c2, c4, d1, d2, d4);
324   m[2][2]=  det3x3 (a1, a2, a4, b1, b2, b4, d1, d2, d4);
325   m[2][3]= -det3x3 (a1, a2, a4, b1, b2, b4, c1, c2, c4);
326   m[3][0]= -det3x3 (b1, b2, b3, c1, c2, c3, d1, d2, d3);
327   m[3][1]=  det3x3 (a1, a2, a3, c1, c2, c3, d1, d2, d3);
328   m[3][2]= -det3x3 (a1, a2, a3, b1, b2, b3, d1, d2, d3);
329   m[3][3]=  det3x3 (a1, a2, a3, b1, b2, b3, c1, c2, c3);
330 }
331 
332 
333 /*!
334  * Invert a matrix in place.
335  *
336  * \param m Matrix to invert.
337  *
338  * \return LIB3DS_TRUE on success, LIB3DS_FALSE on failure.
339  * \ingroup matrix
340  *
341  * GGemsII, K.Wu, Fast Matrix Inversion
342  */
343 Lib3dsBool
lib3ds_matrix_inv(Lib3dsMatrix m)344 lib3ds_matrix_inv(Lib3dsMatrix m)
345 {
346   int i,j,k;
347   int pvt_i[4], pvt_j[4];            /* Locations of pivot elements */
348   Lib3dsFloat pvt_val;               /* Value of current pivot element */
349   Lib3dsFloat hold;                  /* Temporary storage */
350   Lib3dsFloat determinat;
351 
352   determinat = 1.0f;
353   for (k=0; k<4; k++)  {
354     /* Locate k'th pivot element */
355     pvt_val=m[k][k];            /* Initialize for search */
356     pvt_i[k]=k;
357     pvt_j[k]=k;
358     for (i=k; i<4; i++) {
359       for (j=k; j<4; j++) {
360         if (fabs(m[i][j]) > fabs(pvt_val)) {
361           pvt_i[k]=i;
362           pvt_j[k]=j;
363           pvt_val=m[i][j];
364         }
365       }
366     }
367 
368     /* Product of pivots, gives determinant when finished */
369     determinat*=pvt_val;
370     if (fabs(determinat)<LIB3DS_EPSILON) {
371       return(LIB3DS_FALSE);  /* Matrix is singular (zero determinant) */
372     }
373 
374     /* "Interchange" rows (with sign change stuff) */
375     i=pvt_i[k];
376     if (i!=k) {               /* If rows are different */
377       for (j=0; j<4; j++) {
378         hold=-m[k][j];
379         m[k][j]=m[i][j];
380         m[i][j]=hold;
381       }
382     }
383 
384     /* "Interchange" columns */
385     j=pvt_j[k];
386     if (j!=k) {              /* If columns are different */
387       for (i=0; i<4; i++) {
388         hold=-m[i][k];
389         m[i][k]=m[i][j];
390         m[i][j]=hold;
391       }
392     }
393 
394     /* Divide column by minus pivot value */
395     for (i=0; i<4; i++) {
396       if (i!=k) m[i][k]/=( -pvt_val) ;
397     }
398 
399     /* Reduce the matrix */
400     for (i=0; i<4; i++) {
401       hold = m[i][k];
402       for (j=0; j<4; j++) {
403         if (i!=k && j!=k) m[i][j]+=hold*m[k][j];
404       }
405     }
406 
407     /* Divide row by pivot */
408     for (j=0; j<4; j++) {
409       if (j!=k) m[k][j]/=pvt_val;
410     }
411 
412     /* Replace pivot by reciprocal (at last we can touch it). */
413     m[k][k] = 1.0f/pvt_val;
414   }
415 
416   /* That was most of the work, one final pass of row/column interchange */
417   /* to finish */
418   for (k=4-2; k>=0; k--) { /* Don't need to work with 1 by 1 corner*/
419     i=pvt_j[k];            /* Rows to swap correspond to pivot COLUMN */
420     if (i!=k) {            /* If rows are different */
421       for(j=0; j<4; j++) {
422         hold = m[k][j];
423         m[k][j]=-m[i][j];
424         m[i][j]=hold;
425       }
426     }
427 
428     j=pvt_i[k];           /* Columns to swap correspond to pivot ROW */
429     if (j!=k)             /* If columns are different */
430     for (i=0; i<4; i++) {
431       hold=m[i][k];
432       m[i][k]=-m[i][j];
433       m[i][j]=hold;
434     }
435   }
436   return(LIB3DS_TRUE);
437 }
438 
439 
440 /*!
441  * Apply a translation to a matrix.
442  *
443  * \ingroup matrix
444  */
445 void
lib3ds_matrix_translate_xyz(Lib3dsMatrix m,Lib3dsFloat x,Lib3dsFloat y,Lib3dsFloat z)446 lib3ds_matrix_translate_xyz(Lib3dsMatrix m, Lib3dsFloat x, Lib3dsFloat y, Lib3dsFloat z)
447 {
448   int i;
449 
450   for (i=0; i<3; i++) {
451     m[3][i]+= m[0][i]*x + m[1][i]*y + m[2][i]*z;
452   }
453 }
454 
455 
456 /*!
457  * Apply a translation to a matrix.
458  *
459  * \ingroup matrix
460  */
461 void
lib3ds_matrix_translate(Lib3dsMatrix m,Lib3dsVector t)462 lib3ds_matrix_translate(Lib3dsMatrix m, Lib3dsVector t)
463 {
464   int i;
465 
466   for (i=0; i<3; i++) {
467     m[3][i]+= m[0][i]*t[0] + m[1][i]*t[1] + m[2][i]*t[2];
468   }
469 }
470 
471 
472 /*!
473  * Apply scale factors to a matrix.
474  *
475  * \ingroup matrix
476  */
477 void
lib3ds_matrix_scale_xyz(Lib3dsMatrix m,Lib3dsFloat x,Lib3dsFloat y,Lib3dsFloat z)478 lib3ds_matrix_scale_xyz(Lib3dsMatrix m, Lib3dsFloat x, Lib3dsFloat y, Lib3dsFloat z)
479 {
480   int i;
481 
482   for (i=0; i<4; i++) {
483     m[0][i]*=x;
484     m[1][i]*=y;
485     m[2][i]*=z;
486   }
487 }
488 
489 
490 /*!
491  * Apply scale factors to a matrix.
492  *
493  * \ingroup matrix
494  */
495 void
lib3ds_matrix_scale(Lib3dsMatrix m,Lib3dsVector s)496 lib3ds_matrix_scale(Lib3dsMatrix m, Lib3dsVector s)
497 {
498   int i;
499 
500   for (i=0; i<4; i++) {
501     m[0][i]*=s[0];
502     m[1][i]*=s[1];
503     m[2][i]*=s[2];
504   }
505 }
506 
507 
508 /*!
509  * Apply a rotation about the x axis to a matrix.
510  *
511  * \ingroup matrix
512  */
513 void
lib3ds_matrix_rotate_x(Lib3dsMatrix m,Lib3dsFloat phi)514 lib3ds_matrix_rotate_x(Lib3dsMatrix m, Lib3dsFloat phi)
515 {
516   Lib3dsFloat SinPhi,CosPhi;
517   Lib3dsFloat a1[4],a2[4];
518 
519   SinPhi=(Lib3dsFloat)sin(phi);
520   CosPhi=(Lib3dsFloat)cos(phi);
521   memcpy(a1,m[1],4*sizeof(Lib3dsFloat));
522   memcpy(a2,m[2],4*sizeof(Lib3dsFloat));
523   m[1][0]=CosPhi*a1[0]+SinPhi*a2[0];
524   m[1][1]=CosPhi*a1[1]+SinPhi*a2[1];
525   m[1][2]=CosPhi*a1[2]+SinPhi*a2[2];
526   m[1][3]=CosPhi*a1[3]+SinPhi*a2[3];
527   m[2][0]=-SinPhi*a1[0]+CosPhi*a2[0];
528   m[2][1]=-SinPhi*a1[1]+CosPhi*a2[1];
529   m[2][2]=-SinPhi*a1[2]+CosPhi*a2[2];
530   m[2][3]=-SinPhi*a1[3]+CosPhi*a2[3];
531 }
532 
533 
534 /*!
535  * Apply a rotation about the y axis to a matrix.
536  *
537  * \ingroup matrix
538  */
539 void
lib3ds_matrix_rotate_y(Lib3dsMatrix m,Lib3dsFloat phi)540 lib3ds_matrix_rotate_y(Lib3dsMatrix m, Lib3dsFloat phi)
541 {
542   Lib3dsFloat SinPhi,CosPhi;
543   Lib3dsFloat a0[4],a2[4];
544 
545   SinPhi=(Lib3dsFloat)sin(phi);
546   CosPhi=(Lib3dsFloat)cos(phi);
547   memcpy(a0,m[0],4*sizeof(Lib3dsFloat));
548   memcpy(a2,m[2],4*sizeof(Lib3dsFloat));
549   m[0][0]=CosPhi*a0[0]-SinPhi*a2[0];
550   m[0][1]=CosPhi*a0[1]-SinPhi*a2[1];
551   m[0][2]=CosPhi*a0[2]-SinPhi*a2[2];
552   m[0][3]=CosPhi*a0[3]-SinPhi*a2[3];
553   m[2][0]=SinPhi*a0[0]+CosPhi*a2[0];
554   m[2][1]=SinPhi*a0[1]+CosPhi*a2[1];
555   m[2][2]=SinPhi*a0[2]+CosPhi*a2[2];
556   m[2][3]=SinPhi*a0[3]+CosPhi*a2[3];
557 }
558 
559 
560 /*!
561  * Apply a rotation about the z axis to a matrix.
562  *
563  * \ingroup matrix
564  */
565 void
lib3ds_matrix_rotate_z(Lib3dsMatrix m,Lib3dsFloat phi)566 lib3ds_matrix_rotate_z(Lib3dsMatrix m, Lib3dsFloat phi)
567 {
568   Lib3dsFloat SinPhi,CosPhi;
569   Lib3dsFloat a0[4],a1[4];
570 
571   SinPhi=(Lib3dsFloat)sin(phi);
572   CosPhi=(Lib3dsFloat)cos(phi);
573   memcpy(a0,m[0],4*sizeof(Lib3dsFloat));
574   memcpy(a1,m[1],4*sizeof(Lib3dsFloat));
575   m[0][0]=CosPhi*a0[0]+SinPhi*a1[0];
576   m[0][1]=CosPhi*a0[1]+SinPhi*a1[1];
577   m[0][2]=CosPhi*a0[2]+SinPhi*a1[2];
578   m[0][3]=CosPhi*a0[3]+SinPhi*a1[3];
579   m[1][0]=-SinPhi*a0[0]+CosPhi*a1[0];
580   m[1][1]=-SinPhi*a0[1]+CosPhi*a1[1];
581   m[1][2]=-SinPhi*a0[2]+CosPhi*a1[2];
582   m[1][3]=-SinPhi*a0[3]+CosPhi*a1[3];
583 }
584 
585 
586 /*!
587  * Apply a rotation about an arbitrary axis to a matrix.
588  *
589  * \ingroup matrix
590  */
591 void
lib3ds_matrix_rotate(Lib3dsMatrix m,Lib3dsQuat q)592 lib3ds_matrix_rotate(Lib3dsMatrix m, Lib3dsQuat q)
593 {
594   Lib3dsFloat s,xs,ys,zs,wx,wy,wz,xx,xy,xz,yy,yz,zz,l;
595   Lib3dsMatrix R;
596 
597   l=q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3];
598   if (fabs(l)<LIB3DS_EPSILON) {
599     s=1.0f;
600   }
601   else {
602     s=2.0f/l;
603   }
604 
605   xs = q[0] * s;   ys = q[1] * s;  zs = q[2] * s;
606   wx = q[3] * xs;  wy = q[3] * ys; wz = q[3] * zs;
607   xx = q[0] * xs;  xy = q[0] * ys; xz = q[0] * zs;
608   yy = q[1] * ys;  yz = q[1] * zs; zz = q[2] * zs;
609 
610   R[0][0]=1.0f - (yy +zz);
611   R[1][0]=xy - wz;
612   R[2][0]=xz + wy;
613   R[0][1]=xy + wz;
614   R[1][1]=1.0f - (xx +zz);
615   R[2][1]=yz - wx;
616   R[0][2]=xz - wy;
617   R[1][2]=yz + wx;
618   R[2][2]=1.0f - (xx + yy);
619   R[3][0]=R[3][1]=R[3][2]=R[0][3]=R[1][3]=R[2][3]=0.0f;
620   R[3][3]=1.0f;
621 
622   lib3ds_matrix_mult(m,R);
623 }
624 
625 
626 /*!
627  * Apply a rotation about an arbitrary axis to a matrix.
628  *
629  * \ingroup matrix
630  */
631 void
lib3ds_matrix_rotate_axis(Lib3dsMatrix m,Lib3dsVector axis,Lib3dsFloat angle)632 lib3ds_matrix_rotate_axis(Lib3dsMatrix m, Lib3dsVector axis, Lib3dsFloat angle)
633 {
634   Lib3dsQuat q;
635 
636   lib3ds_quat_axis_angle(q,axis,angle);
637   lib3ds_matrix_rotate(m,q);
638 }
639 
640 
641 /*!
642  * Compute a camera matrix based on position, target and roll.
643  *
644  * Generates a translate/rotate matrix that maps world coordinates
645  * to camera coordinates.  Resulting matrix does not include perspective
646  * transform.
647  *
648  * \param matrix Destination matrix.
649  * \param pos Camera position
650  * \param tgt Camera target
651  * \param roll Roll angle
652  *
653  * \ingroup matrix
654  */
655 void
lib3ds_matrix_camera(Lib3dsMatrix matrix,Lib3dsVector pos,Lib3dsVector tgt,Lib3dsFloat roll)656 lib3ds_matrix_camera(Lib3dsMatrix matrix, Lib3dsVector pos,
657   Lib3dsVector tgt, Lib3dsFloat roll)
658 {
659   Lib3dsMatrix M;
660   Lib3dsVector x, y, z;
661 
662   lib3ds_vector_sub(y, tgt, pos);
663   lib3ds_vector_normalize(y);
664 
665   if (y[0] != 0. || y[1] != 0) {
666     z[0] = 0;
667     z[1] = 0;
668     z[2] = 1.0;
669   }
670   else {	/* Special case:  looking straight up or down z axis */
671     z[0] = -1.0;
672     z[1] = 0;
673     z[2] = 0;
674   }
675 
676   lib3ds_vector_cross(x, y, z);
677   lib3ds_vector_cross(z, x, y);
678   lib3ds_vector_normalize(x);
679   lib3ds_vector_normalize(z);
680 
681   lib3ds_matrix_identity(M);
682   M[0][0] = x[0];
683   M[1][0] = x[1];
684   M[2][0] = x[2];
685   M[0][1] = y[0];
686   M[1][1] = y[1];
687   M[2][1] = y[2];
688   M[0][2] = z[0];
689   M[1][2] = z[1];
690   M[2][2] = z[2];
691 
692   lib3ds_matrix_identity(matrix);
693   lib3ds_matrix_rotate_y(matrix, roll);
694   lib3ds_matrix_mult(matrix, M);
695   lib3ds_matrix_translate_xyz(matrix, -pos[0],-pos[1],-pos[2]);
696 }
697 
698 
699 /*!
700  * \ingroup matrix
701  */
702 void
lib3ds_matrix_dump(Lib3dsMatrix matrix)703 lib3ds_matrix_dump(Lib3dsMatrix matrix)
704 {
705   int i,j;
706 
707   for (i=0; i<4; ++i) {
708     for (j=0; j<4; ++j) {
709       printf("%f ", matrix[j][i]);
710     }
711     printf("\n");
712   }
713 }
714 
715 
716 
717 
718 
719