3 * simple math for blender code
5 * sort of cleaned up mar-01 nzc
9 * ***** BEGIN GPL LICENSE BLOCK *****
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software Foundation,
23 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
26 * All rights reserved.
28 * The Original Code is: all of this file.
30 * Contributor(s): none yet.
32 * ***** END GPL LICENSE BLOCK *****
35 /* ************************ FUNKTIES **************************** */
38 #include <sys/types.h>
46 #if defined(__sun__) || defined( __sun ) || defined (__sparc) || defined (__sparc__)
50 #if !defined(__sgi) && !defined(WIN32)
56 #include "BLI_arithb.h"
57 #include "BLI_memarena.h"
59 /* A few small defines. Keep'em local! */
60 #define SMALL_NUMBER 1.e-8
61 #define ABS(x) ((x) < 0 ? -(x) : (x))
62 #define SWAP(type, a, b) { type sw_ap; sw_ap=(a); (a)=(b); (b)=sw_ap; }
63 #define CLAMP(a, b, c) if((a)<(b)) (a)=(b); else if((a)>(c)) (a)=(c)
66 #if defined(WIN32) || defined(__APPLE__)
68 #define M_PI 3.14159265358979323846
69 #define M_SQRT2 1.41421356237309504880
71 #endif /* defined(WIN32) || defined(__APPLE__) */
74 float saacos(float fac)
76 if(fac<= -1.0f) return (float)M_PI;
77 else if(fac>=1.0f) return 0.0;
78 else return (float)acos(fac);
81 float saasin(float fac)
83 if(fac<= -1.0f) return (float)-M_PI/2.0f;
84 else if(fac>=1.0f) return (float)M_PI/2.0f;
85 else return (float)asin(fac);
88 float sasqrt(float fac)
90 if(fac<=0.0) return 0.0;
91 return (float)sqrt(fac);
94 float Normalize(float *n)
98 d= n[0]*n[0]+n[1]*n[1]+n[2]*n[2];
99 /* A larger value causes normalize errors in a scaled down models with camera xtreme close */
113 void Crossf(float *c, float *a, float *b)
115 c[0] = a[1] * b[2] - a[2] * b[1];
116 c[1] = a[2] * b[0] - a[0] * b[2];
117 c[2] = a[0] * b[1] - a[1] * b[0];
120 /* Inpf returns the dot product, also called the scalar product and inner product */
121 float Inpf( float *v1, float *v2)
123 return v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2];
126 /* Project v1 on v2 */
127 void Projf(float *c, float *v1, float *v2)
130 mul = Inpf(v1, v2) / Inpf(v2, v2);
137 void Mat3Transp(float mat[][3])
142 mat[0][1] = mat[1][0] ;
145 mat[0][2] = mat[2][0] ;
148 mat[1][2] = mat[2][1] ;
152 void Mat4Transp(float mat[][4])
157 mat[0][1] = mat[1][0] ;
160 mat[0][2] = mat[2][0] ;
163 mat[0][3] = mat[3][0] ;
167 mat[1][2] = mat[2][1] ;
170 mat[1][3] = mat[3][1] ;
174 mat[2][3] = mat[3][2] ;
181 * computes the inverse of mat and puts it in inverse. Returns
182 * TRUE on success (i.e. can always find a pivot) and FALSE on failure.
183 * Uses Gaussian Elimination with partial (maximal column) pivoting.
188 int Mat4Invert(float inverse[][4], float mat[][4])
196 /* Set inverse to identity */
203 /* Copy original matrix so we don't mess it up */
204 for(i = 0; i < 4; i++)
205 for(j = 0; j <4; j++)
206 tempmat[i][j] = mat[i][j];
208 for(i = 0; i < 4; i++) {
209 /* Look for row with max pivot */
210 max = ABS(tempmat[i][i]);
212 for(j = i + 1; j < 4; j++) {
213 if(ABS(tempmat[j][i]) > max) {
214 max = ABS(tempmat[j][i]);
218 /* Swap rows if necessary */
220 for( k = 0; k < 4; k++) {
221 SWAP(float, tempmat[i][k], tempmat[maxj][k]);
222 SWAP(float, inverse[i][k], inverse[maxj][k]);
226 temp = tempmat[i][i];
228 return 0; /* No non-zero pivot */
229 for(k = 0; k < 4; k++) {
230 tempmat[i][k] = (float)(tempmat[i][k]/temp);
231 inverse[i][k] = (float)(inverse[i][k]/temp);
233 for(j = 0; j < 4; j++) {
235 temp = tempmat[j][i];
236 for(k = 0; k < 4; k++) {
237 tempmat[j][k] -= (float)(tempmat[i][k]*temp);
238 inverse[j][k] -= (float)(inverse[i][k]*temp);
246 void Mat4InvertSimp(float inverse[][4], float mat[][4])
248 /* only for Matrices that have a rotation */
249 /* based at GG IV pag 205 */
252 scale= mat[0][0]*mat[0][0] + mat[1][0]*mat[1][0] + mat[2][0]*mat[2][0];
253 if(scale==0.0) return;
257 /* transpose and scale */
258 inverse[0][0]= scale*mat[0][0];
259 inverse[1][0]= scale*mat[0][1];
260 inverse[2][0]= scale*mat[0][2];
261 inverse[0][1]= scale*mat[1][0];
262 inverse[1][1]= scale*mat[1][1];
263 inverse[2][1]= scale*mat[1][2];
264 inverse[0][2]= scale*mat[2][0];
265 inverse[1][2]= scale*mat[2][1];
266 inverse[2][2]= scale*mat[2][2];
268 inverse[3][0]= -(inverse[0][0]*mat[3][0] + inverse[1][0]*mat[3][1] + inverse[2][0]*mat[3][2]);
269 inverse[3][1]= -(inverse[0][1]*mat[3][0] + inverse[1][1]*mat[3][1] + inverse[2][1]*mat[3][2]);
270 inverse[3][2]= -(inverse[0][2]*mat[3][0] + inverse[1][2]*mat[3][1] + inverse[2][2]*mat[3][2]);
272 inverse[0][3]= inverse[1][3]= inverse[2][3]= 0.0;
276 /* struct Matrix4; */
279 /* this seems to be unused.. */
281 void Mat4Inv(float *m1, float *m2)
284 /* This gets me into trouble: */
285 float mat1[3][3], mat2[3][3];
287 /* void Mat3Inv(); */
288 /* void Mat3CpyMat4(); */
289 /* void Mat4CpyMat3(); */
291 Mat3CpyMat4((float*)mat2,m2);
292 Mat3Inv((float*)mat1, (float*) mat2);
293 Mat4CpyMat3(m1, mat1);
299 float Det2x2(float a,float b,float c,float d)
307 float Det3x3(float a1, float a2, float a3,
308 float b1, float b2, float b3,
309 float c1, float c2, float c3 )
313 ans = a1 * Det2x2( b2, b3, c2, c3 )
314 - b1 * Det2x2( a2, a3, c2, c3 )
315 + c1 * Det2x2( a2, a3, b2, b3 );
320 float Det4x4(float m[][4])
323 float a1,a2,a3,a4,b1,b2,b3,b4,c1,c2,c3,c4,d1,d2,d3,d4;
345 ans = a1 * Det3x3( b2, b3, b4, c2, c3, c4, d2, d3, d4)
346 - b1 * Det3x3( a2, a3, a4, c2, c3, c4, d2, d3, d4)
347 + c1 * Det3x3( a2, a3, a4, b2, b3, b4, d2, d3, d4)
348 - d1 * Det3x3( a2, a3, a4, b2, b3, b4, c2, c3, c4);
354 void Mat4Adj(float out[][4], float in[][4]) /* out = ADJ(in) */
356 float a1, a2, a3, a4, b1, b2, b3, b4;
357 float c1, c2, c3, c4, d1, d2, d3, d4;
380 out[0][0] = Det3x3( b2, b3, b4, c2, c3, c4, d2, d3, d4);
381 out[1][0] = - Det3x3( a2, a3, a4, c2, c3, c4, d2, d3, d4);
382 out[2][0] = Det3x3( a2, a3, a4, b2, b3, b4, d2, d3, d4);
383 out[3][0] = - Det3x3( a2, a3, a4, b2, b3, b4, c2, c3, c4);
385 out[0][1] = - Det3x3( b1, b3, b4, c1, c3, c4, d1, d3, d4);
386 out[1][1] = Det3x3( a1, a3, a4, c1, c3, c4, d1, d3, d4);
387 out[2][1] = - Det3x3( a1, a3, a4, b1, b3, b4, d1, d3, d4);
388 out[3][1] = Det3x3( a1, a3, a4, b1, b3, b4, c1, c3, c4);
390 out[0][2] = Det3x3( b1, b2, b4, c1, c2, c4, d1, d2, d4);
391 out[1][2] = - Det3x3( a1, a2, a4, c1, c2, c4, d1, d2, d4);
392 out[2][2] = Det3x3( a1, a2, a4, b1, b2, b4, d1, d2, d4);
393 out[3][2] = - Det3x3( a1, a2, a4, b1, b2, b4, c1, c2, c4);
395 out[0][3] = - Det3x3( b1, b2, b3, c1, c2, c3, d1, d2, d3);
396 out[1][3] = Det3x3( a1, a2, a3, c1, c2, c3, d1, d2, d3);
397 out[2][3] = - Det3x3( a1, a2, a3, b1, b2, b3, d1, d2, d3);
398 out[3][3] = Det3x3( a1, a2, a3, b1, b2, b3, c1, c2, c3);
401 void Mat4InvGG(float out[][4], float in[][4]) /* from Graphic Gems I, out= INV(in) */
406 /* calculate the adjoint matrix */
412 if ( fabs( det ) < SMALL_NUMBER) {
416 /* scale the adjoint matrix to get the inverse */
420 out[i][j] = out[i][j] / det;
422 /* the last factor is not always 1. For that reason an extra division should be implemented? */
426 void Mat3Inv(float m1[][3], float m2[][3])
434 /* then determinant old matrix! */
435 det= m2[0][0]* (m2[1][1]*m2[2][2] - m2[1][2]*m2[2][1])
436 -m2[1][0]* (m2[0][1]*m2[2][2] - m2[0][2]*m2[2][1])
437 +m2[2][0]* (m2[0][1]*m2[1][2] - m2[0][2]*m2[1][1]);
448 void Mat3Adj(float m1[][3], float m[][3])
450 m1[0][0]=m[1][1]*m[2][2]-m[1][2]*m[2][1];
451 m1[0][1]= -m[0][1]*m[2][2]+m[0][2]*m[2][1];
452 m1[0][2]=m[0][1]*m[1][2]-m[0][2]*m[1][1];
454 m1[1][0]= -m[1][0]*m[2][2]+m[1][2]*m[2][0];
455 m1[1][1]=m[0][0]*m[2][2]-m[0][2]*m[2][0];
456 m1[1][2]= -m[0][0]*m[1][2]+m[0][2]*m[1][0];
458 m1[2][0]=m[1][0]*m[2][1]-m[1][1]*m[2][0];
459 m1[2][1]= -m[0][0]*m[2][1]+m[0][1]*m[2][0];
460 m1[2][2]=m[0][0]*m[1][1]-m[0][1]*m[1][0];
463 void Mat4MulMat4(float m1[][4], float m2[][4], float m3[][4])
465 /* matrix product: m1[j][k] = m2[j][i].m3[i][k] */
467 m1[0][0] = m2[0][0]*m3[0][0] + m2[0][1]*m3[1][0] + m2[0][2]*m3[2][0] + m2[0][3]*m3[3][0];
468 m1[0][1] = m2[0][0]*m3[0][1] + m2[0][1]*m3[1][1] + m2[0][2]*m3[2][1] + m2[0][3]*m3[3][1];
469 m1[0][2] = m2[0][0]*m3[0][2] + m2[0][1]*m3[1][2] + m2[0][2]*m3[2][2] + m2[0][3]*m3[3][2];
470 m1[0][3] = m2[0][0]*m3[0][3] + m2[0][1]*m3[1][3] + m2[0][2]*m3[2][3] + m2[0][3]*m3[3][3];
472 m1[1][0] = m2[1][0]*m3[0][0] + m2[1][1]*m3[1][0] + m2[1][2]*m3[2][0] + m2[1][3]*m3[3][0];
473 m1[1][1] = m2[1][0]*m3[0][1] + m2[1][1]*m3[1][1] + m2[1][2]*m3[2][1] + m2[1][3]*m3[3][1];
474 m1[1][2] = m2[1][0]*m3[0][2] + m2[1][1]*m3[1][2] + m2[1][2]*m3[2][2] + m2[1][3]*m3[3][2];
475 m1[1][3] = m2[1][0]*m3[0][3] + m2[1][1]*m3[1][3] + m2[1][2]*m3[2][3] + m2[1][3]*m3[3][3];
477 m1[2][0] = m2[2][0]*m3[0][0] + m2[2][1]*m3[1][0] + m2[2][2]*m3[2][0] + m2[2][3]*m3[3][0];
478 m1[2][1] = m2[2][0]*m3[0][1] + m2[2][1]*m3[1][1] + m2[2][2]*m3[2][1] + m2[2][3]*m3[3][1];
479 m1[2][2] = m2[2][0]*m3[0][2] + m2[2][1]*m3[1][2] + m2[2][2]*m3[2][2] + m2[2][3]*m3[3][2];
480 m1[2][3] = m2[2][0]*m3[0][3] + m2[2][1]*m3[1][3] + m2[2][2]*m3[2][3] + m2[2][3]*m3[3][3];
482 m1[3][0] = m2[3][0]*m3[0][0] + m2[3][1]*m3[1][0] + m2[3][2]*m3[2][0] + m2[3][3]*m3[3][0];
483 m1[3][1] = m2[3][0]*m3[0][1] + m2[3][1]*m3[1][1] + m2[3][2]*m3[2][1] + m2[3][3]*m3[3][1];
484 m1[3][2] = m2[3][0]*m3[0][2] + m2[3][1]*m3[1][2] + m2[3][2]*m3[2][2] + m2[3][3]*m3[3][2];
485 m1[3][3] = m2[3][0]*m3[0][3] + m2[3][1]*m3[1][3] + m2[3][2]*m3[2][3] + m2[3][3]*m3[3][3];
489 void subMat4MulMat4(float *m1, float *m2, float *m3)
492 m1[0]= m2[0]*m3[0] + m2[1]*m3[4] + m2[2]*m3[8];
493 m1[1]= m2[0]*m3[1] + m2[1]*m3[5] + m2[2]*m3[9];
494 m1[2]= m2[0]*m3[2] + m2[1]*m3[6] + m2[2]*m3[10];
495 m1[3]= m2[0]*m3[3] + m2[1]*m3[7] + m2[2]*m3[11] + m2[3];
498 m1[0]= m2[0]*m3[0] + m2[1]*m3[4] + m2[2]*m3[8];
499 m1[1]= m2[0]*m3[1] + m2[1]*m3[5] + m2[2]*m3[9];
500 m1[2]= m2[0]*m3[2] + m2[1]*m3[6] + m2[2]*m3[10];
501 m1[3]= m2[0]*m3[3] + m2[1]*m3[7] + m2[2]*m3[11] + m2[3];
504 m1[0]= m2[0]*m3[0] + m2[1]*m3[4] + m2[2]*m3[8];
505 m1[1]= m2[0]*m3[1] + m2[1]*m3[5] + m2[2]*m3[9];
506 m1[2]= m2[0]*m3[2] + m2[1]*m3[6] + m2[2]*m3[10];
507 m1[3]= m2[0]*m3[3] + m2[1]*m3[7] + m2[2]*m3[11] + m2[3];
512 void Mat3MulMat3(float m1[][3], float m3[][3], float m2[][3])
514 void Mat3MulMat3(float *m1, float *m3, float *m2)
517 /* m1[i][j] = m2[i][k]*m3[k][j], args are flipped! */
519 m1[0][0]= m2[0][0]*m3[0][0] + m2[0][1]*m3[1][0] + m2[0][2]*m3[2][0];
520 m1[0][1]= m2[0][0]*m3[0][1] + m2[0][1]*m3[1][1] + m2[0][2]*m3[2][1];
521 m1[0][2]= m2[0][0]*m3[0][2] + m2[0][1]*m3[1][2] + m2[0][2]*m3[2][2];
523 m1[1][0]= m2[1][0]*m3[0][0] + m2[1][1]*m3[1][0] + m2[1][2]*m3[2][0];
524 m1[1][1]= m2[1][0]*m3[0][1] + m2[1][1]*m3[1][1] + m2[1][2]*m3[2][1];
525 m1[1][2]= m2[1][0]*m3[0][2] + m2[1][1]*m3[1][2] + m2[1][2]*m3[2][2];
527 m1[2][0]= m2[2][0]*m3[0][0] + m2[2][1]*m3[1][0] + m2[2][2]*m3[2][0];
528 m1[2][1]= m2[2][0]*m3[0][1] + m2[2][1]*m3[1][1] + m2[2][2]*m3[2][1];
529 m1[2][2]= m2[2][0]*m3[0][2] + m2[2][1]*m3[1][2] + m2[2][2]*m3[2][2];
531 m1[0]= m2[0]*m3[0] + m2[1]*m3[3] + m2[2]*m3[6];
532 m1[1]= m2[0]*m3[1] + m2[1]*m3[4] + m2[2]*m3[7];
533 m1[2]= m2[0]*m3[2] + m2[1]*m3[5] + m2[2]*m3[8];
536 m1[0]= m2[0]*m3[0] + m2[1]*m3[3] + m2[2]*m3[6];
537 m1[1]= m2[0]*m3[1] + m2[1]*m3[4] + m2[2]*m3[7];
538 m1[2]= m2[0]*m3[2] + m2[1]*m3[5] + m2[2]*m3[8];
541 m1[0]= m2[0]*m3[0] + m2[1]*m3[3] + m2[2]*m3[6];
542 m1[1]= m2[0]*m3[1] + m2[1]*m3[4] + m2[2]*m3[7];
543 m1[2]= m2[0]*m3[2] + m2[1]*m3[5] + m2[2]*m3[8];
545 } /* end of void Mat3MulMat3(float m1[][3], float m3[][3], float m2[][3]) */
547 void Mat4MulMat43(float (*m1)[4], float (*m3)[4], float (*m2)[3])
549 m1[0][0]= m2[0][0]*m3[0][0] + m2[0][1]*m3[1][0] + m2[0][2]*m3[2][0];
550 m1[0][1]= m2[0][0]*m3[0][1] + m2[0][1]*m3[1][1] + m2[0][2]*m3[2][1];
551 m1[0][2]= m2[0][0]*m3[0][2] + m2[0][1]*m3[1][2] + m2[0][2]*m3[2][2];
552 m1[1][0]= m2[1][0]*m3[0][0] + m2[1][1]*m3[1][0] + m2[1][2]*m3[2][0];
553 m1[1][1]= m2[1][0]*m3[0][1] + m2[1][1]*m3[1][1] + m2[1][2]*m3[2][1];
554 m1[1][2]= m2[1][0]*m3[0][2] + m2[1][1]*m3[1][2] + m2[1][2]*m3[2][2];
555 m1[2][0]= m2[2][0]*m3[0][0] + m2[2][1]*m3[1][0] + m2[2][2]*m3[2][0];
556 m1[2][1]= m2[2][0]*m3[0][1] + m2[2][1]*m3[1][1] + m2[2][2]*m3[2][1];
557 m1[2][2]= m2[2][0]*m3[0][2] + m2[2][1]*m3[1][2] + m2[2][2]*m3[2][2];
559 /* m1 = m2 * m3, ignore the elements on the 4th row/column of m3*/
560 void Mat3IsMat3MulMat4(float m1[][3], float m2[][3], float m3[][4])
562 /* m1[i][j] = m2[i][k] * m3[k][j] */
563 m1[0][0] = m2[0][0] * m3[0][0] + m2[0][1] * m3[1][0] +m2[0][2] * m3[2][0];
564 m1[0][1] = m2[0][0] * m3[0][1] + m2[0][1] * m3[1][1] +m2[0][2] * m3[2][1];
565 m1[0][2] = m2[0][0] * m3[0][2] + m2[0][1] * m3[1][2] +m2[0][2] * m3[2][2];
567 m1[1][0] = m2[1][0] * m3[0][0] + m2[1][1] * m3[1][0] +m2[1][2] * m3[2][0];
568 m1[1][1] = m2[1][0] * m3[0][1] + m2[1][1] * m3[1][1] +m2[1][2] * m3[2][1];
569 m1[1][2] = m2[1][0] * m3[0][2] + m2[1][1] * m3[1][2] +m2[1][2] * m3[2][2];
571 m1[2][0] = m2[2][0] * m3[0][0] + m2[2][1] * m3[1][0] +m2[2][2] * m3[2][0];
572 m1[2][1] = m2[2][0] * m3[0][1] + m2[2][1] * m3[1][1] +m2[2][2] * m3[2][1];
573 m1[2][2] = m2[2][0] * m3[0][2] + m2[2][1] * m3[1][2] +m2[2][2] * m3[2][2];
578 void Mat4MulMat34(float (*m1)[4], float (*m3)[3], float (*m2)[4])
580 m1[0][0]= m2[0][0]*m3[0][0] + m2[0][1]*m3[1][0] + m2[0][2]*m3[2][0];
581 m1[0][1]= m2[0][0]*m3[0][1] + m2[0][1]*m3[1][1] + m2[0][2]*m3[2][1];
582 m1[0][2]= m2[0][0]*m3[0][2] + m2[0][1]*m3[1][2] + m2[0][2]*m3[2][2];
583 m1[1][0]= m2[1][0]*m3[0][0] + m2[1][1]*m3[1][0] + m2[1][2]*m3[2][0];
584 m1[1][1]= m2[1][0]*m3[0][1] + m2[1][1]*m3[1][1] + m2[1][2]*m3[2][1];
585 m1[1][2]= m2[1][0]*m3[0][2] + m2[1][1]*m3[1][2] + m2[1][2]*m3[2][2];
586 m1[2][0]= m2[2][0]*m3[0][0] + m2[2][1]*m3[1][0] + m2[2][2]*m3[2][0];
587 m1[2][1]= m2[2][0]*m3[0][1] + m2[2][1]*m3[1][1] + m2[2][2]*m3[2][1];
588 m1[2][2]= m2[2][0]*m3[0][2] + m2[2][1]*m3[1][2] + m2[2][2]*m3[2][2];
591 void Mat4CpyMat4(float m1[][4], float m2[][4])
593 memcpy(m1, m2, 4*4*sizeof(float));
596 void Mat4SwapMat4(float *m1, float *m2)
610 typedef float Mat3Row[3];
611 typedef float Mat4Row[4];
614 void Mat3CpyMat4(float *m1p, float *m2p)
616 void Mat3CpyMat4(float m1[][3], float m2[][4])
621 Mat3Row *m1= (Mat3Row *)m1p;
622 Mat4Row *m2= (Mat4Row *)m2p;
623 for ( i = 0; i++; i < 3) {
624 for (j = 0; j++; j < 3) {
625 m1p[3*i + j] = m2p[4*i + j];
642 /* Butched. See .h for comment */
643 /* void Mat4CpyMat3(float m1[][4], float m2[][3]) */
645 void Mat4CpyMat3(float* m1, float *m2)
648 for (i = 0; i < 3; i++) {
649 m1[(4*i)] = m2[(3*i)];
650 m1[(4*i) + 1]= m2[(3*i) + 1];
651 m1[(4*i) + 2]= m2[(3*i) + 2];
656 m1[12]=m1[13]= m1[14]= 0.0;
661 void Mat4CpyMat3(float m1[][4], float m2[][3]) /* no clear */
675 /* Reevan's Bugfix */
689 void Mat3CpyMat3(float m1[][3], float m2[][3])
691 /* destination comes first: */
692 memcpy(&m1[0], &m2[0], 9*sizeof(float));
695 void Mat3MulSerie(float answ[][3],
696 float m1[][3], float m2[][3], float m3[][3],
697 float m4[][3], float m5[][3], float m6[][3],
698 float m7[][3], float m8[][3])
702 if(m1==0 || m2==0) return;
705 Mat3MulMat3(answ, m2, m1);
707 Mat3MulMat3(temp, m3, answ);
709 Mat3MulMat3(answ, m4, temp);
711 Mat3MulMat3(temp, m5, answ);
713 Mat3MulMat3(answ, m6, temp);
715 Mat3MulMat3(temp, m7, answ);
717 Mat3MulMat3(answ, m8, temp);
719 else Mat3CpyMat3(answ, temp);
722 else Mat3CpyMat3(answ, temp);
725 else Mat3CpyMat3(answ, temp);
729 void Mat4MulSerie(float answ[][4], float m1[][4],
730 float m2[][4], float m3[][4], float m4[][4],
731 float m5[][4], float m6[][4], float m7[][4],
736 if(m1==0 || m2==0) return;
738 Mat4MulMat4(answ, m2, m1);
740 Mat4MulMat4(temp, m3, answ);
742 Mat4MulMat4(answ, m4, temp);
744 Mat4MulMat4(temp, m5, answ);
746 Mat4MulMat4(answ, m6, temp);
748 Mat4MulMat4(temp, m7, answ);
750 Mat4MulMat4(answ, m8, temp);
752 else Mat4CpyMat4(answ, temp);
755 else Mat4CpyMat4(answ, temp);
758 else Mat4CpyMat4(answ, temp);
762 void Mat3BlendMat3(float out[][3], float dst[][3], float src[][3], float srcweight)
764 float squat[4], dquat[4], fquat[4];
765 float ssize[3], dsize[3], fsize[4];
766 float rmat[3][3], smat[3][3];
768 Mat3ToQuat(dst, dquat);
769 Mat3ToSize(dst, dsize);
771 Mat3ToQuat(src, squat);
772 Mat3ToSize(src, ssize);
775 QuatInterpol(fquat, dquat, squat, srcweight);
776 VecLerpf(fsize, dsize, ssize, srcweight);
778 /* compose new matrix */
779 QuatToMat3(fquat, rmat);
780 SizeToMat3(fsize, smat);
781 Mat3MulMat3(out, rmat, smat);
784 void Mat4BlendMat4(float out[][4], float dst[][4], float src[][4], float srcweight)
786 float squat[4], dquat[4], fquat[4];
787 float ssize[3], dsize[3], fsize[4];
788 float sloc[3], dloc[3], floc[3];
790 Mat4ToQuat(dst, dquat);
791 Mat4ToSize(dst, dsize);
792 VecCopyf(dloc, dst[3]);
794 Mat4ToQuat(src, squat);
795 Mat4ToSize(src, ssize);
796 VecCopyf(sloc, src[3]);
799 VecLerpf(floc, dloc, sloc, srcweight);
800 QuatInterpol(fquat, dquat, squat, srcweight);
801 VecLerpf(fsize, dsize, ssize, srcweight);
803 /* compose new matrix */
804 LocQuatSizeToMat4(out, floc, fquat, fsize);
807 void Mat4Clr(float *m)
809 memset(m, 0, 4*4*sizeof(float));
812 void Mat3Clr(float *m)
814 memset(m, 0, 3*3*sizeof(float));
817 void Mat4One(float m[][4])
820 m[0][0]= m[1][1]= m[2][2]= m[3][3]= 1.0;
821 m[0][1]= m[0][2]= m[0][3]= 0.0;
822 m[1][0]= m[1][2]= m[1][3]= 0.0;
823 m[2][0]= m[2][1]= m[2][3]= 0.0;
824 m[3][0]= m[3][1]= m[3][2]= 0.0;
827 void Mat3One(float m[][3])
830 m[0][0]= m[1][1]= m[2][2]= 1.0;
831 m[0][1]= m[0][2]= 0.0;
832 m[1][0]= m[1][2]= 0.0;
833 m[2][0]= m[2][1]= 0.0;
836 void Mat4MulVec( float mat[][4], int *vec)
842 vec[0]=(int)(x*mat[0][0] + y*mat[1][0] + mat[2][0]*vec[2] + mat[3][0]);
843 vec[1]=(int)(x*mat[0][1] + y*mat[1][1] + mat[2][1]*vec[2] + mat[3][1]);
844 vec[2]=(int)(x*mat[0][2] + y*mat[1][2] + mat[2][2]*vec[2] + mat[3][2]);
847 void Mat4MulVecfl( float mat[][4], float *vec)
853 vec[0]=x*mat[0][0] + y*mat[1][0] + mat[2][0]*vec[2] + mat[3][0];
854 vec[1]=x*mat[0][1] + y*mat[1][1] + mat[2][1]*vec[2] + mat[3][1];
855 vec[2]=x*mat[0][2] + y*mat[1][2] + mat[2][2]*vec[2] + mat[3][2];
858 void VecMat4MulVecfl(float *in, float mat[][4], float *vec)
864 in[0]= x*mat[0][0] + y*mat[1][0] + mat[2][0]*vec[2] + mat[3][0];
865 in[1]= x*mat[0][1] + y*mat[1][1] + mat[2][1]*vec[2] + mat[3][1];
866 in[2]= x*mat[0][2] + y*mat[1][2] + mat[2][2]*vec[2] + mat[3][2];
869 void Mat4Mul3Vecfl( float mat[][4], float *vec)
875 vec[0]= x*mat[0][0] + y*mat[1][0] + mat[2][0]*vec[2];
876 vec[1]= x*mat[0][1] + y*mat[1][1] + mat[2][1]*vec[2];
877 vec[2]= x*mat[0][2] + y*mat[1][2] + mat[2][2]*vec[2];
880 void Mat4MulVec3Project(float mat[][4], float *vec)
884 w = vec[0]*mat[0][3] + vec[1]*mat[1][3] + vec[2]*mat[2][3] + mat[3][3];
885 Mat4MulVecfl(mat, vec);
892 void Mat4MulVec4fl( float mat[][4], float *vec)
899 vec[0]=x*mat[0][0] + y*mat[1][0] + z*mat[2][0] + mat[3][0]*vec[3];
900 vec[1]=x*mat[0][1] + y*mat[1][1] + z*mat[2][1] + mat[3][1]*vec[3];
901 vec[2]=x*mat[0][2] + y*mat[1][2] + z*mat[2][2] + mat[3][2]*vec[3];
902 vec[3]=x*mat[0][3] + y*mat[1][3] + z*mat[2][3] + mat[3][3]*vec[3];
905 void Mat3MulVec( float mat[][3], int *vec)
911 vec[0]= (int)(x*mat[0][0] + y*mat[1][0] + mat[2][0]*vec[2]);
912 vec[1]= (int)(x*mat[0][1] + y*mat[1][1] + mat[2][1]*vec[2]);
913 vec[2]= (int)(x*mat[0][2] + y*mat[1][2] + mat[2][2]*vec[2]);
916 void Mat3MulVecfl( float mat[][3], float *vec)
922 vec[0]= x*mat[0][0] + y*mat[1][0] + mat[2][0]*vec[2];
923 vec[1]= x*mat[0][1] + y*mat[1][1] + mat[2][1]*vec[2];
924 vec[2]= x*mat[0][2] + y*mat[1][2] + mat[2][2]*vec[2];
927 void Mat3MulVecd( float mat[][3], double *vec)
933 vec[0]= x*mat[0][0] + y*mat[1][0] + mat[2][0]*vec[2];
934 vec[1]= x*mat[0][1] + y*mat[1][1] + mat[2][1]*vec[2];
935 vec[2]= x*mat[0][2] + y*mat[1][2] + mat[2][2]*vec[2];
938 void Mat3TransMulVecfl( float mat[][3], float *vec)
944 vec[0]= x*mat[0][0] + y*mat[0][1] + mat[0][2]*vec[2];
945 vec[1]= x*mat[1][0] + y*mat[1][1] + mat[1][2]*vec[2];
946 vec[2]= x*mat[2][0] + y*mat[2][1] + mat[2][2]*vec[2];
949 void Mat3MulFloat(float *m, float f)
953 for(i=0;i<9;i++) m[i]*=f;
956 void Mat4MulFloat(float *m, float f)
960 for(i=0;i<16;i++) m[i]*=f; /* count to 12: without vector component */
964 void Mat4MulFloat3(float *m, float f) /* only scale component */
976 void Mat3AddMat3(float m1[][3], float m2[][3], float m3[][3])
982 m1[i][j]= m2[i][j] + m3[i][j];
985 void Mat4AddMat4(float m1[][4], float m2[][4], float m3[][4])
991 m1[i][j]= m2[i][j] + m3[i][j];
994 void VecStar(float mat[][3], float *vec)
997 mat[0][0]= mat[1][1]= mat[2][2]= 0.0;
1007 short EenheidsMat(float mat[][3])
1010 if(mat[0][0]==1.0 && mat[0][1]==0.0 && mat[0][2]==0.0)
1011 if(mat[1][0]==0.0 && mat[1][1]==1.0 && mat[1][2]==0.0)
1012 if(mat[2][0]==0.0 && mat[2][1]==0.0 && mat[2][2]==1.0)
1018 int FloatCompare( float *v1, float *v2, float limit)
1021 if( fabs(v1[0]-v2[0])<limit ) {
1022 if( fabs(v1[1]-v2[1])<limit ) {
1023 if( fabs(v1[2]-v2[2])<limit ) return 1;
1029 int FloatCompare4( float *v1, float *v2, float limit)
1032 if( fabs(v1[0]-v2[0])<limit ) {
1033 if( fabs(v1[1]-v2[1])<limit ) {
1034 if( fabs(v1[2]-v2[2])<limit ) {
1035 if( fabs(v1[3]-v2[3])<limit ) return 1;
1042 float FloatLerpf( float target, float origin, float fac)
1044 return (fac*target) + (1.0f-fac)*origin;
1047 void printvecf( char *str, float v[3])
1049 printf("%s: %.3f %.3f %.3f\n", str, v[0], v[1], v[2]);
1053 void printquat( char *str, float q[4])
1055 printf("%s: %.3f %.3f %.3f %.3f\n", str, q[0], q[1], q[2], q[3]);
1059 void printvec4f( char *str, float v[4])
1061 printf("%s\n", str);
1062 printf("%f %f %f %f\n",v[0],v[1],v[2], v[3]);
1067 void printmatrix4( char *str, float m[][4])
1069 printf("%s\n", str);
1070 printf("%f %f %f %f\n",m[0][0],m[1][0],m[2][0],m[3][0]);
1071 printf("%f %f %f %f\n",m[0][1],m[1][1],m[2][1],m[3][1]);
1072 printf("%f %f %f %f\n",m[0][2],m[1][2],m[2][2],m[3][2]);
1073 printf("%f %f %f %f\n",m[0][3],m[1][3],m[2][3],m[3][3]);
1078 void printmatrix3( char *str, float m[][3])
1080 printf("%s\n", str);
1081 printf("%f %f %f\n",m[0][0],m[1][0],m[2][0]);
1082 printf("%f %f %f\n",m[0][1],m[1][1],m[2][1]);
1083 printf("%f %f %f\n",m[0][2],m[1][2],m[2][2]);
1088 /* **************** QUATERNIONS ********** */
1091 void QuatMul(float *q, float *q1, float *q2)
1095 t0= q1[0]*q2[0]-q1[1]*q2[1]-q1[2]*q2[2]-q1[3]*q2[3];
1096 t1= q1[0]*q2[1]+q1[1]*q2[0]+q1[2]*q2[3]-q1[3]*q2[2];
1097 t2= q1[0]*q2[2]+q1[2]*q2[0]+q1[3]*q2[1]-q1[1]*q2[3];
1098 q[3]= q1[0]*q2[3]+q1[3]*q2[0]+q1[1]*q2[2]-q1[2]*q2[1];
1104 /* Assumes a unit quaternion */
1105 void QuatMulVecf(float *q, float *v)
1109 t0= -q[1]*v[0]-q[2]*v[1]-q[3]*v[2];
1110 t1= q[0]*v[0]+q[2]*v[2]-q[3]*v[1];
1111 t2= q[0]*v[1]+q[3]*v[0]-q[1]*v[2];
1112 v[2]= q[0]*v[2]+q[1]*v[1]-q[2]*v[0];
1116 t1= t0*-q[1]+v[0]*q[0]-v[1]*q[3]+v[2]*q[2];
1117 t2= t0*-q[2]+v[1]*q[0]-v[2]*q[1]+v[0]*q[3];
1118 v[2]= t0*-q[3]+v[2]*q[0]-v[0]*q[2]+v[1]*q[1];
1123 void QuatConj(float *q)
1130 float QuatDot(float *q1, float *q2)
1132 return q1[0]*q2[0] + q1[1]*q2[1] + q1[2]*q2[2] + q1[3]*q2[3];
1135 void QuatInv(float *q)
1137 float f = QuatDot(q, q);
1143 QuatMulf(q, 1.0f/f);
1147 void QuatMulf(float *q, float f)
1155 void QuatSub(float *q, float *q1, float *q2)
1162 /* angular mult factor */
1163 void QuatMulFac(float *q, float fac)
1165 float angle= fac*saacos(q[0]); /* quat[0]= cos(0.5*angle), but now the 0.5 and 2.0 rule out */
1167 float co= (float)cos(angle);
1168 float si= (float)sin(angle);
1177 void QuatToMat3( float *q, float m[][3])
1179 double q0, q1, q2, q3, qda,qdb,qdc,qaa,qab,qac,qbb,qbc,qcc;
1196 m[0][0]= (float)(1.0-qbb-qcc);
1197 m[0][1]= (float)(qdc+qab);
1198 m[0][2]= (float)(-qdb+qac);
1200 m[1][0]= (float)(-qdc+qab);
1201 m[1][1]= (float)(1.0-qaa-qcc);
1202 m[1][2]= (float)(qda+qbc);
1204 m[2][0]= (float)(qdb+qac);
1205 m[2][1]= (float)(-qda+qbc);
1206 m[2][2]= (float)(1.0-qaa-qbb);
1210 void QuatToMat4( float *q, float m[][4])
1212 double q0, q1, q2, q3, qda,qdb,qdc,qaa,qab,qac,qbb,qbc,qcc;
1229 m[0][0]= (float)(1.0-qbb-qcc);
1230 m[0][1]= (float)(qdc+qab);
1231 m[0][2]= (float)(-qdb+qac);
1234 m[1][0]= (float)(-qdc+qab);
1235 m[1][1]= (float)(1.0-qaa-qcc);
1236 m[1][2]= (float)(qda+qbc);
1239 m[2][0]= (float)(qdb+qac);
1240 m[2][1]= (float)(-qda+qbc);
1241 m[2][2]= (float)(1.0-qaa-qbb);
1244 m[3][0]= m[3][1]= m[3][2]= 0.0f;
1248 void Mat3ToQuat(float wmat[][3], float *q)
1253 /* work on a copy */
1254 Mat3CpyMat3(mat, wmat);
1255 Mat3Ortho(mat); /* this is needed AND a NormalQuat in the end */
1257 tr= 0.25*(1.0+mat[0][0]+mat[1][1]+mat[2][2]);
1259 if(tr>FLT_EPSILON) {
1263 q[1]= (float)((mat[1][2]-mat[2][1])*s);
1264 q[2]= (float)((mat[2][0]-mat[0][2])*s);
1265 q[3]= (float)((mat[0][1]-mat[1][0])*s);
1268 if(mat[0][0] > mat[1][1] && mat[0][0] > mat[2][2]) {
1269 s= 2.0*sqrtf(1.0 + mat[0][0] - mat[1][1] - mat[2][2]);
1270 q[1]= (float)(0.25*s);
1273 q[0]= (float)((mat[2][1] - mat[1][2])*s);
1274 q[2]= (float)((mat[1][0] + mat[0][1])*s);
1275 q[3]= (float)((mat[2][0] + mat[0][2])*s);
1277 else if(mat[1][1] > mat[2][2]) {
1278 s= 2.0*sqrtf(1.0 + mat[1][1] - mat[0][0] - mat[2][2]);
1279 q[2]= (float)(0.25*s);
1282 q[0]= (float)((mat[2][0] - mat[0][2])*s);
1283 q[1]= (float)((mat[1][0] + mat[0][1])*s);
1284 q[3]= (float)((mat[2][1] + mat[1][2])*s);
1287 s= 2.0*sqrtf(1.0 + mat[2][2] - mat[0][0] - mat[1][1]);
1288 q[3]= (float)(0.25*s);
1291 q[0]= (float)((mat[1][0] - mat[0][1])*s);
1292 q[1]= (float)((mat[2][0] + mat[0][2])*s);
1293 q[2]= (float)((mat[2][1] + mat[1][2])*s);
1299 void Mat3ToQuat_is_ok( float wmat[][3], float *q)
1301 float mat[3][3], matr[3][3], matn[3][3], q1[4], q2[4], angle, si, co, nor[3];
1303 /* work on a copy */
1304 Mat3CpyMat3(mat, wmat);
1307 /* rotate z-axis of matrix to z-axis */
1309 nor[0] = mat[2][1]; /* cross product with (0,0,1) */
1310 nor[1] = -mat[2][0];
1315 angle= 0.5f*saacos(co);
1317 co= (float)cos(angle);
1318 si= (float)sin(angle);
1320 q1[1]= -nor[0]*si; /* negative here, but why? */
1324 /* rotate back x-axis from mat, using inverse q1 */
1325 QuatToMat3(q1, matr);
1326 Mat3Inv(matn, matr);
1327 Mat3MulVecfl(matn, mat[0]);
1329 /* and align x-axes */
1330 angle= (float)(0.5*atan2(mat[0][1], mat[0][0]));
1332 co= (float)cos(angle);
1333 si= (float)sin(angle);
1343 void Mat4ToQuat( float m[][4], float *q)
1347 Mat3CpyMat4(mat, m);
1352 void QuatOne(float *q)
1354 q[0]= q[2]= q[3]= 0.0;
1358 void NormalQuat(float *q)
1362 len= (float)sqrt(q[0]*q[0]+q[1]*q[1]+q[2]*q[2]+q[3]*q[3]);
1370 q[0]= q[2]= q[3]= 0.0f;
1374 void RotationBetweenVectorsToQuat(float *q, float v1[3], float v2[3])
1379 Crossf(axis, v1, v2);
1381 angle = NormalizedVecAngle2(v1, v2);
1383 AxisAngleToQuat(q, axis, angle);
1386 void AxisAngleToQuat(float *q, float *axis, float angle)
1391 VecCopyf(nor, axis);
1395 si = (float)sin(angle);
1396 q[0] = (float)cos(angle);
1402 void vectoquat(float *vec, short axis, short upflag, float *q)
1404 float q2[4], nor[3], *fp, mat[3][3], angle, si, co, x2, y2, z2, len1;
1406 /* first rotate to axis */
1408 x2= vec[0] ; y2= vec[1] ; z2= vec[2];
1412 x2= -vec[0] ; y2= -vec[1] ; z2= -vec[2];
1416 q[1]=q[2]=q[3]= 0.0;
1418 len1= (float)sqrt(x2*x2+y2*y2+z2*z2);
1419 if(len1 == 0.0) return;
1421 /* nasty! I need a good routine for this...
1422 * problem is a rotation of an Y axis to the negative Y-axis for example.
1425 if(axis==0) { /* x-axis */
1430 if(fabs(y2)+fabs(z2)<0.0001)
1435 else if(axis==1) { /* y-axis */
1440 if(fabs(x2)+fabs(z2)<0.0001)
1450 if(fabs(x2)+fabs(y2)<0.0001)
1459 angle= 0.5f*saacos(co);
1460 si= (float)sin(angle);
1461 q[0]= (float)cos(angle);
1471 if(upflag==1) angle= (float)(0.5*atan2(fp[2], fp[1]));
1472 else angle= (float)(-0.5*atan2(fp[1], fp[2]));
1475 if(upflag==0) angle= (float)(-0.5*atan2(fp[2], fp[0]));
1476 else angle= (float)(0.5*atan2(fp[0], fp[2]));
1479 if(upflag==0) angle= (float)(0.5*atan2(-fp[1], -fp[0]));
1480 else angle= (float)(-0.5*atan2(-fp[0], -fp[1]));
1483 co= (float)cos(angle);
1484 si= (float)(sin(angle)/len1);
1494 void VecUpMat3old( float *vec, float mat[][3], short axis)
1497 short cox = 0, coy = 0, coz = 0;
1499 /* using different up's is not useful, infact there is no real 'up'!
1507 cox= 0; coy= 1; coz= 2; /* Y up Z tr */
1510 cox= 1; coy= 2; coz= 0; /* Z up X tr */
1513 cox= 2; coy= 0; coz= 1; /* X up Y tr */
1516 cox= 0; coy= 2; coz= 1; /* */
1519 cox= 1; coy= 0; coz= 2; /* */
1522 cox= 2; coy= 1; coz= 0; /* Y up X tr */
1525 mat[coz][0]= vec[0];
1526 mat[coz][1]= vec[1];
1527 mat[coz][2]= vec[2];
1528 Normalize((float *)mat[coz]);
1530 inp= mat[coz][0]*up[0] + mat[coz][1]*up[1] + mat[coz][2]*up[2];
1531 mat[coy][0]= up[0] - inp*mat[coz][0];
1532 mat[coy][1]= up[1] - inp*mat[coz][1];
1533 mat[coy][2]= up[2] - inp*mat[coz][2];
1535 Normalize((float *)mat[coy]);
1537 Crossf(mat[cox], mat[coy], mat[coz]);
1541 void VecUpMat3(float *vec, float mat[][3], short axis)
1544 short cox = 0, coy = 0, coz = 0;
1546 /* using different up's is not useful, infact there is no real 'up'!
1550 cox= 0; coy= 1; coz= 2; /* Y up Z tr */
1553 cox= 1; coy= 2; coz= 0; /* Z up X tr */
1556 cox= 2; coy= 0; coz= 1; /* X up Y tr */
1559 cox= 0; coy= 1; coz= 2; /* Y op -Z tr */
1565 cox= 1; coy= 0; coz= 2; /* */
1568 cox= 2; coy= 1; coz= 0; /* Y up X tr */
1571 mat[coz][0]= vec[0];
1572 mat[coz][1]= vec[1];
1573 mat[coz][2]= vec[2];
1574 Normalize((float *)mat[coz]);
1577 mat[coy][0]= - inp*mat[coz][0];
1578 mat[coy][1]= - inp*mat[coz][1];
1579 mat[coy][2]= 1.0f - inp*mat[coz][2];
1581 Normalize((float *)mat[coy]);
1583 Crossf(mat[cox], mat[coy], mat[coz]);
1587 /* A & M Watt, Advanced animation and rendering techniques, 1992 ACM press */
1588 void QuatInterpolW(float *, float *, float *, float );
1590 void QuatInterpolW(float *result, float *quat1, float *quat2, float t)
1592 float omega, cosom, sinom, sc1, sc2;
1594 cosom = quat1[0]*quat2[0] + quat1[1]*quat2[1] + quat1[2]*quat2[2] + quat1[3]*quat2[3] ;
1596 /* rotate around shortest angle */
1597 if ((1.0 + cosom) > 0.0001) {
1599 if ((1.0 - cosom) > 0.0001) {
1600 omega = acos(cosom);
1602 sc1 = sin((1.0 - t) * omega) / sinom;
1603 sc2 = sin(t * omega) / sinom;
1609 result[0] = sc1*quat1[0] + sc2*quat2[0];
1610 result[1] = sc1*quat1[1] + sc2*quat2[1];
1611 result[2] = sc1*quat1[2] + sc2*quat2[2];
1612 result[3] = sc1*quat1[3] + sc2*quat2[3];
1615 result[0] = quat2[3];
1616 result[1] = -quat2[2];
1617 result[2] = quat2[1];
1618 result[3] = -quat2[0];
1620 sc1 = sin((1.0 - t)*M_PI_2);
1621 sc2 = sin(t*M_PI_2);
1623 result[0] = sc1*quat1[0] + sc2*result[0];
1624 result[1] = sc1*quat1[1] + sc2*result[1];
1625 result[2] = sc1*quat1[2] + sc2*result[2];
1626 result[3] = sc1*quat1[3] + sc2*result[3];
1630 void QuatInterpol(float *result, float *quat1, float *quat2, float t)
1632 float quat[4], omega, cosom, sinom, sc1, sc2;
1634 cosom = quat1[0]*quat2[0] + quat1[1]*quat2[1] + quat1[2]*quat2[2] + quat1[3]*quat2[3] ;
1636 /* rotate around shortest angle */
1651 if ((1.0 - cosom) > 0.0001) {
1652 omega = acos(cosom);
1654 sc1 = sin((1 - t) * omega) / sinom;
1655 sc2 = sin(t * omega) / sinom;
1661 result[0] = sc1 * quat[0] + sc2 * quat2[0];
1662 result[1] = sc1 * quat[1] + sc2 * quat2[1];
1663 result[2] = sc1 * quat[2] + sc2 * quat2[2];
1664 result[3] = sc1 * quat[3] + sc2 * quat2[3];
1667 void QuatAdd(float *result, float *quat1, float *quat2, float t)
1669 result[0]= quat1[0] + t*quat2[0];
1670 result[1]= quat1[1] + t*quat2[1];
1671 result[2]= quat1[2] + t*quat2[2];
1672 result[3]= quat1[3] + t*quat2[3];
1675 void QuatCopy(float *q1, float *q2)
1683 /* **************** DUAL QUATERNIONS ************** */
1686 Conversion routines between (regular quaternion, translation) and
1689 Version 1.0.0, February 7th, 2007
1691 Copyright (C) 2006-2007 University of Dublin, Trinity College, All Rights
1694 This software is provided 'as-is', without any express or implied
1695 warranty. In no event will the author(s) be held liable for any damages
1696 arising from the use of this software.
1698 Permission is granted to anyone to use this software for any purpose,
1699 including commercial applications, and to alter it and redistribute it
1700 freely, subject to the following restrictions:
1702 1. The origin of this software must not be misrepresented; you must not
1703 claim that you wrote the original software. If you use this software
1704 in a product, an acknowledgment in the product documentation would be
1705 appreciated but is not required.
1706 2. Altered source versions must be plainly marked as such, and must not be
1707 misrepresented as being the original software.
1708 3. This notice may not be removed or altered from any source distribution.
1710 Author: Ladislav Kavan, kavanl@cs.tcd.ie
1712 Changes for Blender:
1713 - renaming, style changes and optimizations
1714 - added support for scaling
1717 void Mat4ToDQuat(float basemat[][4], float mat[][4], DualQuat *dq)
1719 float *t, *q, dscale[3], scale[3], basequat[4];
1720 float baseRS[4][4], baseinv[4][4], baseR[4][4], baseRinv[4][4];
1721 float R[4][4], S[4][4];
1723 /* split scaling and rotation, there is probably a faster way to do
1724 this, it's done like this now to correctly get negative scaling */
1725 Mat4MulMat4(baseRS, basemat, mat);
1726 Mat4ToSize(baseRS, scale);
1728 VecCopyf(dscale, scale);
1729 dscale[0] -= 1.0f; dscale[1] -= 1.0f; dscale[2] -= 1.0f;
1731 if((Det4x4(mat) < 0.0f) || VecLength(dscale) > 1e-4) {
1732 /* extract R and S */
1733 Mat4ToQuat(baseRS, basequat);
1734 QuatToMat4(basequat, baseR);
1735 VecCopyf(baseR[3], baseRS[3]);
1737 Mat4Invert(baseinv, basemat);
1738 Mat4MulMat4(R, baseinv, baseR);
1740 Mat4Invert(baseRinv, baseR);
1741 Mat4MulMat4(S, baseRS, baseRinv);
1743 /* set scaling part */
1744 Mat4MulSerie(dq->scale, basemat, S, baseinv, 0, 0, 0, 0, 0);
1745 dq->scale_weight= 1.0f;
1748 /* matrix does not contain scaling */
1749 Mat4CpyMat4(R, mat);
1750 dq->scale_weight= 0.0f;
1754 Mat4ToQuat(R, dq->quat);
1759 dq->trans[0]= -0.5f*( t[0]*q[1] + t[1]*q[2] + t[2]*q[3]);
1760 dq->trans[1]= 0.5f*( t[0]*q[0] + t[1]*q[3] - t[2]*q[2]);
1761 dq->trans[2]= 0.5f*(-t[0]*q[3] + t[1]*q[0] + t[2]*q[1]);
1762 dq->trans[3]= 0.5f*( t[0]*q[2] - t[1]*q[1] + t[2]*q[0]);
1765 void DQuatToMat4(DualQuat *dq, float mat[][4])
1767 float len, *t, q0[4];
1769 /* regular quaternion */
1770 QuatCopy(q0, dq->quat);
1773 len= sqrt(QuatDot(q0, q0));
1775 QuatMulf(q0, 1.0f/len);
1778 QuatToMat4(q0, mat);
1782 mat[3][0]= 2.0*(-t[0]*q0[1] + t[1]*q0[0] - t[2]*q0[3] + t[3]*q0[2]);
1783 mat[3][1]= 2.0*(-t[0]*q0[2] + t[1]*q0[3] + t[2]*q0[0] - t[3]*q0[1]);
1784 mat[3][2]= 2.0*(-t[0]*q0[3] - t[1]*q0[2] + t[2]*q0[1] + t[3]*q0[0]);
1786 /* note: this does not handle scaling */
1789 void DQuatAddWeighted(DualQuat *dqsum, DualQuat *dq, float weight)
1793 /* make sure we interpolate quats in the right direction */
1794 if (QuatDot(dq->quat, dqsum->quat) < 0) {
1799 /* interpolate rotation and translation */
1800 dqsum->quat[0] += weight*dq->quat[0];
1801 dqsum->quat[1] += weight*dq->quat[1];
1802 dqsum->quat[2] += weight*dq->quat[2];
1803 dqsum->quat[3] += weight*dq->quat[3];
1805 dqsum->trans[0] += weight*dq->trans[0];
1806 dqsum->trans[1] += weight*dq->trans[1];
1807 dqsum->trans[2] += weight*dq->trans[2];
1808 dqsum->trans[3] += weight*dq->trans[3];
1810 /* interpolate scale - but only if needed */
1811 if (dq->scale_weight) {
1814 if(flipped) /* we don't want negative weights for scaling */
1817 Mat4CpyMat4(wmat, dq->scale);
1818 Mat4MulFloat((float*)wmat, weight);
1819 Mat4AddMat4(dqsum->scale, dqsum->scale, wmat);
1820 dqsum->scale_weight += weight;
1824 void DQuatNormalize(DualQuat *dq, float totweight)
1826 float scale= 1.0f/totweight;
1828 QuatMulf(dq->quat, scale);
1829 QuatMulf(dq->trans, scale);
1831 if(dq->scale_weight) {
1832 float addweight= totweight - dq->scale_weight;
1835 dq->scale[0][0] += addweight;
1836 dq->scale[1][1] += addweight;
1837 dq->scale[2][2] += addweight;
1838 dq->scale[3][3] += addweight;
1841 Mat4MulFloat((float*)dq->scale, scale);
1842 dq->scale_weight= 1.0f;
1846 void DQuatMulVecfl(DualQuat *dq, float *co, float mat[][3])
1848 float M[3][3], t[3], scalemat[3][3], len2;
1849 float w= dq->quat[0], x= dq->quat[1], y= dq->quat[2], z= dq->quat[3];
1850 float t0= dq->trans[0], t1= dq->trans[1], t2= dq->trans[2], t3= dq->trans[3];
1852 /* rotation matrix */
1853 M[0][0]= w*w + x*x - y*y - z*z;
1854 M[1][0]= 2*(x*y - w*z);
1855 M[2][0]= 2*(x*z + w*y);
1857 M[0][1]= 2*(x*y + w*z);
1858 M[1][1]= w*w + y*y - x*x - z*z;
1859 M[2][1]= 2*(y*z - w*x);
1861 M[0][2]= 2*(x*z - w*y);
1862 M[1][2]= 2*(y*z + w*x);
1863 M[2][2]= w*w + z*z - x*x - y*y;
1865 len2= QuatDot(dq->quat, dq->quat);
1870 t[0]= 2*(-t0*x + w*t1 - t2*z + y*t3);
1871 t[1]= 2*(-t0*y + t1*z - x*t3 + w*t2);
1872 t[2]= 2*(-t0*z + x*t2 + w*t3 - t1*y);
1875 if(dq->scale_weight)
1876 Mat4MulVecfl(dq->scale, co);
1878 /* apply rotation and translation */
1879 Mat3MulVecfl(M, co);
1880 co[0]= (co[0] + t[0])*len2;
1881 co[1]= (co[1] + t[1])*len2;
1882 co[2]= (co[2] + t[2])*len2;
1884 /* compute crazyspace correction mat */
1886 if(dq->scale_weight) {
1887 Mat3CpyMat4(scalemat, dq->scale);
1888 Mat3MulMat3(mat, M, scalemat);
1891 Mat3CpyMat3(mat, M);
1892 Mat3MulFloat((float*)mat, len2);
1896 void DQuatCpyDQuat(DualQuat *dq1, DualQuat *dq2)
1898 memcpy(dq1, dq2, sizeof(DualQuat));
1901 /* **************** VIEW / PROJECTION ******************************** */
1905 float left, float right,
1906 float bottom, float top,
1907 float nearClip, float farClip,
1910 float Xdelta, Ydelta, Zdelta;
1912 Xdelta = right - left;
1913 Ydelta = top - bottom;
1914 Zdelta = farClip - nearClip;
1915 if (Xdelta == 0.0 || Ydelta == 0.0 || Zdelta == 0.0) {
1919 matrix[0][0] = 2.0f/Xdelta;
1920 matrix[3][0] = -(right + left)/Xdelta;
1921 matrix[1][1] = 2.0f/Ydelta;
1922 matrix[3][1] = -(top + bottom)/Ydelta;
1923 matrix[2][2] = -2.0f/Zdelta; /* note: negate Z */
1924 matrix[3][2] = -(farClip + nearClip)/Zdelta;
1928 float left, float right,
1929 float bottom, float top,
1930 float nearClip, float farClip,
1933 float Xdelta, Ydelta, Zdelta;
1935 Xdelta = right - left;
1936 Ydelta = top - bottom;
1937 Zdelta = farClip - nearClip;
1939 if (Xdelta == 0.0 || Ydelta == 0.0 || Zdelta == 0.0) {
1942 mat[0][0] = nearClip * 2.0f/Xdelta;
1943 mat[1][1] = nearClip * 2.0f/Ydelta;
1944 mat[2][0] = (right + left)/Xdelta; /* note: negate Z */
1945 mat[2][1] = (top + bottom)/Ydelta;
1946 mat[2][2] = -(farClip + nearClip)/Zdelta;
1948 mat[3][2] = (-2.0f * nearClip * farClip)/Zdelta;
1949 mat[0][1] = mat[0][2] = mat[0][3] =
1950 mat[1][0] = mat[1][2] = mat[1][3] =
1951 mat[3][0] = mat[3][1] = mat[3][3] = 0.0;
1955 void i_translate(float Tx, float Ty, float Tz, float mat[][4])
1957 mat[3][0] += (Tx*mat[0][0] + Ty*mat[1][0] + Tz*mat[2][0]);
1958 mat[3][1] += (Tx*mat[0][1] + Ty*mat[1][1] + Tz*mat[2][1]);
1959 mat[3][2] += (Tx*mat[0][2] + Ty*mat[1][2] + Tz*mat[2][2]);
1962 void i_multmatrix( float icand[][4], float Vm[][4])
1967 for(row=0 ; row<4 ; row++)
1968 for(col=0 ; col<4 ; col++)
1969 temp[row][col] = icand[row][0] * Vm[0][col]
1970 + icand[row][1] * Vm[1][col]
1971 + icand[row][2] * Vm[2][col]
1972 + icand[row][3] * Vm[3][col];
1973 Mat4CpyMat4(Vm, temp);
1976 void i_rotate(float angle, char axis, float mat[][4])
1982 for(col=0; col<4 ; col++) /* init temp to zero matrix */
1985 angle = (float)(angle*(3.1415926535/180.0));
1986 cosine = (float)cos(angle);
1987 sine = (float)sin(angle);
1991 for(col=0 ; col<4 ; col++)
1992 temp[col] = cosine*mat[1][col] + sine*mat[2][col];
1993 for(col=0 ; col<4 ; col++) {
1994 mat[2][col] = - sine*mat[1][col] + cosine*mat[2][col];
1995 mat[1][col] = temp[col];
2001 for(col=0 ; col<4 ; col++)
2002 temp[col] = cosine*mat[0][col] - sine*mat[2][col];
2003 for(col=0 ; col<4 ; col++) {
2004 mat[2][col] = sine*mat[0][col] + cosine*mat[2][col];
2005 mat[0][col] = temp[col];
2011 for(col=0 ; col<4 ; col++)
2012 temp[col] = cosine*mat[0][col] + sine*mat[1][col];
2013 for(col=0 ; col<4 ; col++) {
2014 mat[1][col] = - sine*mat[0][col] + cosine*mat[1][col];
2015 mat[0][col] = temp[col];
2021 void i_polarview(float dist, float azimuth, float incidence, float twist, float Vm[][4])
2026 i_translate(0.0, 0.0, -dist, Vm);
2027 i_rotate(-twist,'z', Vm);
2028 i_rotate(-incidence,'x', Vm);
2029 i_rotate(-azimuth,'z', Vm);
2032 void i_lookat(float vx, float vy, float vz, float px, float py, float pz, float twist, float mat[][4])
2034 float sine, cosine, hyp, hyp1, dx, dy, dz;
2040 i_rotate(-twist,'z', mat);
2045 hyp = dx * dx + dz * dz; /* hyp squared */
2046 hyp1 = (float)sqrt(dy*dy + hyp);
2047 hyp = (float)sqrt(hyp); /* the real hyp */
2049 if (hyp1 != 0.0) { /* rotate X */
2056 mat1[1][1] = cosine;
2059 mat1[2][2] = cosine;
2061 i_multmatrix(mat1, mat);
2063 mat1[1][1] = mat1[2][2] = 1.0f; /* be careful here to reinit */
2064 mat1[1][2] = mat1[2][1] = 0.0; /* those modified by the last */
2067 if (hyp != 0.0f) { /* rotate Y */
2074 mat1[0][0] = cosine;
2077 mat1[2][2] = cosine;
2079 i_multmatrix(mat1, mat);
2080 i_translate(-vx,-vy,-vz, mat); /* translate viewpoint to origin */
2087 /* ************************************************ */
2089 void Mat3Ortho(float mat[][3])
2096 void Mat4Ortho(float mat[][4])
2100 len= Normalize(mat[0]);
2101 if(len!=0.0) mat[0][3]/= len;
2102 len= Normalize(mat[1]);
2103 if(len!=0.0) mat[1][3]/= len;
2104 len= Normalize(mat[2]);
2105 if(len!=0.0) mat[2][3]/= len;
2108 void VecCopyf(float *v1, float *v2)
2115 int VecLen( int *v1, int *v2)
2119 x=(float)(v1[0]-v2[0]);
2120 y=(float)(v1[1]-v2[1]);
2121 z=(float)(v1[2]-v2[2]);
2122 return (int)floor(sqrt(x*x+y*y+z*z));
2125 float VecLenf( float *v1, float *v2)
2132 return (float)sqrt(x*x+y*y+z*z);
2135 float VecLength(float *v)
2137 return (float) sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
2140 void VecAddf(float *v, float *v1, float *v2)
2147 void VecSubf(float *v, float *v1, float *v2)
2154 void VecLerpf(float *target, float *a, float *b, float t)
2158 target[0]= s*a[0] + t*b[0];
2159 target[1]= s*a[1] + t*b[1];
2160 target[2]= s*a[2] + t*b[2];
2163 void Vec2Lerpf(float *target, float *a, float *b, float t)
2167 target[0]= s*a[0] + t*b[0];
2168 target[1]= s*a[1] + t*b[1];
2171 void VecMidf(float *v, float *v1, float *v2)
2173 v[0]= 0.5f*(v1[0]+ v2[0]);
2174 v[1]= 0.5f*(v1[1]+ v2[1]);
2175 v[2]= 0.5f*(v1[2]+ v2[2]);
2178 void VecMulf(float *v1, float f)
2186 void VecOrthoBasisf(float *v, float *v1, float *v2)
2188 float f = sqrt(v[0]*v[0] + v[1]*v[1]);
2192 v1[0] = 0.0f; v1[1] = 1.0f; v1[2] = 0.0f;
2194 v2[0] = 1.0f; v2[1] = v2[2] = 0.0f;
2197 v2[0] = -1.0f; v2[1] = v2[2] = 0.0f;
2210 int VecLenCompare(float *v1, float *v2, float limit)
2218 return ((x*x + y*y + z*z) < (limit*limit));
2221 int VecCompare( float *v1, float *v2, float limit)
2223 if( fabs(v1[0]-v2[0])<limit )
2224 if( fabs(v1[1]-v2[1])<limit )
2225 if( fabs(v1[2]-v2[2])<limit ) return 1;
2229 int VecEqual(float *v1, float *v2)
2231 return ((v1[0]==v2[0]) && (v1[1]==v2[1]) && (v1[2]==v2[2]));
2234 int VecIsNull(float *v)
2236 return (v[0] == 0 && v[1] == 0 && v[2] == 0);
2239 void CalcNormShort( short *v1, short *v2, short *v3, float *n) /* is also cross product */
2243 n1[0]= (float)(v1[0]-v2[0]);
2244 n2[0]= (float)(v2[0]-v3[0]);
2245 n1[1]= (float)(v1[1]-v2[1]);
2246 n2[1]= (float)(v2[1]-v3[1]);
2247 n1[2]= (float)(v1[2]-v2[2]);
2248 n2[2]= (float)(v2[2]-v3[2]);
2249 n[0]= n1[1]*n2[2]-n1[2]*n2[1];
2250 n[1]= n1[2]*n2[0]-n1[0]*n2[2];
2251 n[2]= n1[0]*n2[1]-n1[1]*n2[0];
2255 void CalcNormLong( int* v1, int*v2, int*v3, float *n)
2259 n1[0]= (float)(v1[0]-v2[0]);
2260 n2[0]= (float)(v2[0]-v3[0]);
2261 n1[1]= (float)(v1[1]-v2[1]);
2262 n2[1]= (float)(v2[1]-v3[1]);
2263 n1[2]= (float)(v1[2]-v2[2]);
2264 n2[2]= (float)(v2[2]-v3[2]);
2265 n[0]= n1[1]*n2[2]-n1[2]*n2[1];
2266 n[1]= n1[2]*n2[0]-n1[0]*n2[2];
2267 n[2]= n1[0]*n2[1]-n1[1]*n2[0];
2271 float CalcNormFloat( float *v1, float *v2, float *v3, float *n)
2281 n[0]= n1[1]*n2[2]-n1[2]*n2[1];
2282 n[1]= n1[2]*n2[0]-n1[0]*n2[2];
2283 n[2]= n1[0]*n2[1]-n1[1]*n2[0];
2284 return Normalize(n);
2287 float CalcNormFloat4( float *v1, float *v2, float *v3, float *v4, float *n)
2300 n[0]= n1[1]*n2[2]-n1[2]*n2[1];
2301 n[1]= n1[2]*n2[0]-n1[0]*n2[2];
2302 n[2]= n1[0]*n2[1]-n1[1]*n2[0];
2304 return Normalize(n);
2308 void CalcCent3f(float *cent, float *v1, float *v2, float *v3)
2311 cent[0]= 0.33333f*(v1[0]+v2[0]+v3[0]);
2312 cent[1]= 0.33333f*(v1[1]+v2[1]+v3[1]);
2313 cent[2]= 0.33333f*(v1[2]+v2[2]+v3[2]);
2316 void CalcCent4f(float *cent, float *v1, float *v2, float *v3, float *v4)
2319 cent[0]= 0.25f*(v1[0]+v2[0]+v3[0]+v4[0]);
2320 cent[1]= 0.25f*(v1[1]+v2[1]+v3[1]+v4[1]);
2321 cent[2]= 0.25f*(v1[2]+v2[2]+v3[2]+v4[2]);
2324 float Sqrt3f(float f)
2326 if(f==0.0) return 0;
2327 if(f<0) return (float)(-exp(log(-f)/3));
2328 else return (float)(exp(log(f)/3));
2331 double Sqrt3d(double d)
2333 if(d==0.0) return 0;
2334 if(d<0) return -exp(log(-d)/3);
2335 else return exp(log(d)/3);
2338 void NormalShortToFloat(float *out, short *in)
2340 out[0] = in[0] / 32767.0;
2341 out[1] = in[1] / 32767.0;
2342 out[2] = in[2] / 32767.0;
2345 void NormalFloatToShort(short *out, float *in)
2347 out[0] = (short)(in[0] * 32767.0);
2348 out[1] = (short)(in[1] * 32767.0);
2349 out[2] = (short)(in[2] * 32767.0);
2352 /* distance v1 to line v2-v3 */
2353 /* using Hesse formula, NO LINE PIECE! */
2354 float DistVL2Dfl( float *v1, float *v2, float *v3) {
2359 deler= (float)sqrt(a[0]*a[0]+a[1]*a[1]);
2360 if(deler== 0.0f) return 0;
2362 return (float)(fabs((v1[0]-v2[0])*a[0]+(v1[1]-v2[1])*a[1])/deler);
2366 /* distance v1 to line-piece v2-v3 */
2367 float PdistVL2Dfl( float *v1, float *v2, float *v3)
2369 float labda, rc[2], pt[2], len;
2373 len= rc[0]*rc[0]+ rc[1]*rc[1];
2377 return (float)(sqrt(rc[0]*rc[0]+ rc[1]*rc[1]));
2380 labda= ( rc[0]*(v1[0]-v2[0]) + rc[1]*(v1[1]-v2[1]) )/len;
2385 else if(labda>=1.0) {
2390 pt[0]= labda*rc[0]+v2[0];
2391 pt[1]= labda*rc[1]+v2[1];
2396 return (float)sqrt(rc[0]*rc[0]+ rc[1]*rc[1]);
2399 float AreaF2Dfl( float *v1, float *v2, float *v3)
2401 return (float)(0.5*fabs( (v1[0]-v2[0])*(v2[1]-v3[1]) + (v1[1]-v2[1])*(v3[0]-v2[0]) ));
2405 float AreaQ3Dfl( float *v1, float *v2, float *v3, float *v4) /* only convex Quadrilaterals */
2407 float len, vec1[3], vec2[3], n[3];
2409 VecSubf(vec1, v2, v1);
2410 VecSubf(vec2, v4, v1);
2411 Crossf(n, vec1, vec2);
2414 VecSubf(vec1, v4, v3);
2415 VecSubf(vec2, v2, v3);
2416 Crossf(n, vec1, vec2);
2422 float AreaT3Dfl( float *v1, float *v2, float *v3) /* Triangles */
2424 float len, vec1[3], vec2[3], n[3];
2426 VecSubf(vec1, v3, v2);
2427 VecSubf(vec2, v1, v2);
2428 Crossf(n, vec1, vec2);
2434 #define MAX2(x,y) ( (x)>(y) ? (x) : (y) )
2435 #define MAX3(x,y,z) MAX2( MAX2((x),(y)) , (z) )
2438 float AreaPoly3Dfl(int nr, float *verts, float *normal)
2440 float x, y, z, area, max;
2444 /* first: find dominant axis: 0==X, 1==Y, 2==Z */
2445 x= (float)fabs(normal[0]);
2446 y= (float)fabs(normal[1]);
2447 z= (float)fabs(normal[2]);
2448 max = MAX3(x, y, z);
2455 /* The Trapezium Area Rule */
2456 prev= verts+3*(nr-1);
2459 for(a=0; a<nr; a++) {
2460 area+= (cur[px]-prev[px])*(cur[py]+prev[py]);
2465 return (float)fabs(0.5*area/max);
2468 /* intersect Line-Line, shorts */
2469 short IsectLL2Ds(short *v1, short *v2, short *v3, short *v4)
2473 0: no intersection of segments
2474 1: exact intersection of segments
2475 2: cross-intersection of segments
2477 float div, labda, mu;
2479 div= (v2[0]-v1[0])*(v4[1]-v3[1])-(v2[1]-v1[1])*(v4[0]-v3[0]);
2480 if(div==0.0) return -1;
2482 labda= ((float)(v1[1]-v3[1])*(v4[0]-v3[0])-(v1[0]-v3[0])*(v4[1]-v3[1]))/div;
2484 mu= ((float)(v1[1]-v3[1])*(v2[0]-v1[0])-(v1[0]-v3[0])*(v2[1]-v1[1]))/div;
2486 if(labda>=0.0 && labda<=1.0 && mu>=0.0 && mu<=1.0) {
2487 if(labda==0.0 || labda==1.0 || mu==0.0 || mu==1.0) return 1;
2493 /* intersect Line-Line, floats */
2494 short IsectLL2Df(float *v1, float *v2, float *v3, float *v4)
2498 0: no intersection of segments
2499 1: exact intersection of segments
2500 2: cross-intersection of segments
2502 float div, labda, mu;
2504 div= (v2[0]-v1[0])*(v4[1]-v3[1])-(v2[1]-v1[1])*(v4[0]-v3[0]);
2505 if(div==0.0) return -1;
2507 labda= ((float)(v1[1]-v3[1])*(v4[0]-v3[0])-(v1[0]-v3[0])*(v4[1]-v3[1]))/div;
2509 mu= ((float)(v1[1]-v3[1])*(v2[0]-v1[0])-(v1[0]-v3[0])*(v2[1]-v1[1]))/div;
2511 if(labda>=0.0 && labda<=1.0 && mu>=0.0 && mu<=1.0) {
2512 if(labda==0.0 || labda==1.0 || mu==0.0 || mu==1.0) return 1;
2523 static short IsectLLPt2Df(float x0,float y0,float x1,float y1,
2524 float x2,float y2,float x3,float y3, float *xi,float *yi)
2528 this function computes the intersection of the sent lines
2529 and returns the intersection point, note that the function assumes
2530 the lines intersect. the function can handle vertical as well
2531 as horizontal lines. note the function isn't very clever, it simply
2532 applies the math, but we don't need speed since this is a
2535 float c1,c2, // constants of linear equations
2536 det_inv, // the inverse of the determinant of the coefficient
2537 m1,m2; // the slopes of each line
2539 compute slopes, note the cludge for infinity, however, this will
2542 if ( fabs( x1-x0 ) > 0.000001 )
2543 m1 = ( y1-y0 ) / ( x1-x0 );
2545 return -1; /*m1 = ( float ) 1e+10;*/ // close enough to infinity
2547 if ( fabs( x3-x2 ) > 0.000001 )
2548 m2 = ( y3-y2 ) / ( x3-x2 );
2550 return -1; /*m2 = ( float ) 1e+10;*/ // close enough to infinity
2552 if (fabs(m1-m2) < 0.000001)
2553 return -1; /* paralelle lines */
2555 // compute constants
2560 // compute the inverse of the determinate
2562 det_inv = 1.0f / ( -m1 + m2 );
2564 // use Kramers rule to compute xi and yi
2566 *xi= ( ( -c2 + c1 ) *det_inv );
2567 *yi= ( ( m2*c1 - m1*c2 ) *det_inv );
2570 } // end Intersect_Lines
2572 #define SIDE_OF_LINE(pa,pb,pp) ((pa[0]-pp[0])*(pb[1]-pp[1]))-((pb[0]-pp[0])*(pa[1]-pp[1]))
2574 int IsectPT2Df(float pt[2], float v1[2], float v2[2], float v3[2])
2576 if (SIDE_OF_LINE(v1,v2,pt)>=0.0) {
2577 if (SIDE_OF_LINE(v2,v3,pt)>=0.0) {
2578 if (SIDE_OF_LINE(v3,v1,pt)>=0.0) {
2583 if (! (SIDE_OF_LINE(v2,v3,pt)>=0.0) ) {
2584 if (! (SIDE_OF_LINE(v3,v1,pt)>=0.0)) {
2592 /* point in quad - only convex quads */
2593 int IsectPQ2Df(float pt[2], float v1[2], float v2[2], float v3[2], float v4[2])
2595 if (SIDE_OF_LINE(v1,v2,pt)>=0.0) {
2596 if (SIDE_OF_LINE(v2,v3,pt)>=0.0) {
2597 if (SIDE_OF_LINE(v3,v4,pt)>=0.0) {
2598 if (SIDE_OF_LINE(v4,v1,pt)>=0.0) {
2604 if (! (SIDE_OF_LINE(v2,v3,pt)>=0.0) ) {
2605 if (! (SIDE_OF_LINE(v3,v4,pt)>=0.0)) {
2606 if (! (SIDE_OF_LINE(v4,v1,pt)>=0.0)) {
2623 void MinMax3(float *min, float *max, float *vec)
2625 if(min[0]>vec[0]) min[0]= vec[0];
2626 if(min[1]>vec[1]) min[1]= vec[1];
2627 if(min[2]>vec[2]) min[2]= vec[2];
2629 if(max[0]<vec[0]) max[0]= vec[0];
2630 if(max[1]<vec[1]) max[1]= vec[1];
2631 if(max[2]<vec[2]) max[2]= vec[2];
2634 static float TriSignedArea(float *v1, float *v2, float *v3, int i, int j)
2636 return 0.5f*((v1[i]-v2[i])*(v2[j]-v3[j]) + (v1[j]-v2[j])*(v3[i]-v2[i]));
2639 static int BarycentricWeights(float *v1, float *v2, float *v3, float *co, float *n, float *w)
2641 float xn, yn, zn, a1, a2, a3, asum;
2644 /* find best projection of face XY, XZ or YZ: barycentric weights of
2645 the 2d projected coords are the same and faster to compute */
2649 if(zn>=xn && zn>=yn) {i= 0; j= 1;}
2650 else if(yn>=xn && yn>=zn) {i= 0; j= 2;}
2653 a1= TriSignedArea(v2, v3, co, i, j);
2654 a2= TriSignedArea(v3, v1, co, i, j);
2655 a3= TriSignedArea(v1, v2, co, i, j);
2659 if (fabs(asum) < FLT_EPSILON) {
2660 /* zero area triangle */
2661 w[0]= w[1]= w[2]= 1.0f/3.0f;
2673 void InterpWeightsQ3Dfl(float *v1, float *v2, float *v3, float *v4, float *co, float *w)
2677 w[0]= w[1]= w[2]= w[3]= 0.0f;
2679 /* first check for exact match */
2680 if(VecEqual(co, v1))
2682 else if(VecEqual(co, v2))
2684 else if(VecEqual(co, v3))
2686 else if(v4 && VecEqual(co, v4))
2689 /* otherwise compute barycentric interpolation weights */
2690 float n1[3], n2[3], n[3];
2693 VecSubf(n1, v1, v3);
2695 VecSubf(n2, v2, v4);
2698 VecSubf(n2, v2, v3);
2702 /* OpenGL seems to split this way, so we do too */
2704 degenerate= BarycentricWeights(v1, v2, v4, co, n, w);
2705 SWAP(float, w[2], w[3]);
2707 if(degenerate || (w[0] < 0.0f)) {
2708 /* if w[1] is negative, co is on the other side of the v1-v3 edge,
2709 so we interpolate using the other triangle */
2710 degenerate= BarycentricWeights(v2, v3, v4, co, n, w2);
2721 BarycentricWeights(v1, v2, v3, co, n, w);
2725 /* Mean value weights - smooth interpolation weights for polygons with
2726 * more than 3 vertices */
2727 static float MeanValueHalfTan(float *v1, float *v2, float *v3)
2729 float d2[3], d3[3], cross[3], area, dot, len;
2731 VecSubf(d2, v2, v1);
2732 VecSubf(d3, v3, v1);
2733 Crossf(cross, d2, d3);
2735 area= VecLength(cross);
2737 len= VecLength(d2)*VecLength(d3);
2742 return (len - dot)/area;
2745 void MeanValueWeights(float v[][3], int n, float *co, float *w)
2747 float totweight, t1, t2, len, *vmid, *vprev, *vnext;
2752 for(i=0; i<n; i++) {
2754 vprev= (i == 0)? v[n-1]: v[i-1];
2755 vnext= (i == n-1)? v[0]: v[i+1];
2757 t1= MeanValueHalfTan(co, vprev, vmid);
2758 t2= MeanValueHalfTan(co, vmid, vnext);
2760 len= VecLenf(co, vmid);
2765 if(totweight != 0.0f)
2771 /* ************ EULER *************** */
2773 void EulToMat3( float *eul, float mat[][3])
2775 double ci, cj, ch, si, sj, sh, cc, cs, sc, ss;
2788 mat[0][0] = (float)(cj*ch);
2789 mat[1][0] = (float)(sj*sc-cs);
2790 mat[2][0] = (float)(sj*cc+ss);
2791 mat[0][1] = (float)(cj*sh);
2792 mat[1][1] = (float)(sj*ss+cc);
2793 mat[2][1] = (float)(sj*cs-sc);
2794 mat[0][2] = (float)-sj;
2795 mat[1][2] = (float)(cj*si);
2796 mat[2][2] = (float)(cj*ci);
2800 void EulToMat4( float *eul,float mat[][4])
2802 double ci, cj, ch, si, sj, sh, cc, cs, sc, ss;
2815 mat[0][0] = (float)(cj*ch);
2816 mat[1][0] = (float)(sj*sc-cs);
2817 mat[2][0] = (float)(sj*cc+ss);
2818 mat[0][1] = (float)(cj*sh);
2819 mat[1][1] = (float)(sj*ss+cc);
2820 mat[2][1] = (float)(sj*cs-sc);
2821 mat[0][2] = (float)-sj;
2822 mat[1][2] = (float)(cj*si);
2823 mat[2][2] = (float)(cj*ci);
2826 mat[3][0]= mat[3][1]= mat[3][2]= mat[0][3]= mat[1][3]= mat[2][3]= 0.0f;
2830 /* returns two euler calculation methods, so we can pick the best */
2831 static void mat3_to_eul2(float tmat[][3], float *eul1, float *eul2)
2833 float cy, quat[4], mat[3][3];
2835 Mat3ToQuat(tmat, quat);
2836 QuatToMat3(quat, mat);
2837 Mat3CpyMat3(mat, tmat);
2840 cy = (float)sqrt(mat[0][0]*mat[0][0] + mat[0][1]*mat[0][1]);
2842 if (cy > 16.0*FLT_EPSILON) {
2844 eul1[0] = (float)atan2(mat[1][2], mat[2][2]);
2845 eul1[1] = (float)atan2(-mat[0][2], cy);
2846 eul1[2] = (float)atan2(mat[0][1], mat[0][0]);
2848 eul2[0] = (float)atan2(-mat[1][2], -mat[2][2]);
2849 eul2[1] = (float)atan2(-mat[0][2], -cy);
2850 eul2[2] = (float)atan2(-mat[0][1], -mat[0][0]);
2853 eul1[0] = (float)atan2(-mat[2][1], mat[1][1]);
2854 eul1[1] = (float)atan2(-mat[0][2], cy);
2857 VecCopyf(eul2, eul1);
2861 void Mat3ToEul(float tmat[][3], float *eul)
2863 float eul1[3], eul2[3];
2865 mat3_to_eul2(tmat, eul1, eul2);
2867 /* return best, which is just the one with lowest values it in */
2868 if( fabs(eul1[0])+fabs(eul1[1])+fabs(eul1[2]) > fabs(eul2[0])+fabs(eul2[1])+fabs(eul2[2])) {
2869 VecCopyf(eul, eul2);
2872 VecCopyf(eul, eul1);
2876 void Mat4ToEul(float tmat[][4], float *eul)
2878 float tempMat[3][3];
2880 Mat3CpyMat4 (tempMat, tmat);
2882 Mat3ToEul(tempMat, eul);
2885 void QuatToEul( float *quat, float *eul)
2889 QuatToMat3(quat, mat);
2890 Mat3ToEul(mat, eul);
2894 void EulToQuat( float *eul, float *quat)
2896 float ti, tj, th, ci, cj, ch, si, sj, sh, cc, cs, sc, ss;
2898 ti = eul[0]*0.5f; tj = eul[1]*0.5f; th = eul[2]*0.5f;
2899 ci = (float)cos(ti); cj = (float)cos(tj); ch = (float)cos(th);
2900 si = (float)sin(ti); sj = (float)sin(tj); sh = (float)sin(th);
2901 cc = ci*ch; cs = ci*sh; sc = si*ch; ss = si*sh;
2903 quat[0] = cj*cc + sj*ss;
2904 quat[1] = cj*sc - sj*cs;
2905 quat[2] = cj*ss + sj*cc;
2906 quat[3] = cj*cs - sj*sc;
2909 void VecRotToMat3( float *vec, float phi, float mat[][3])
2911 /* rotation of phi radials around vec */
2912 float vx, vx2, vy, vy2, vz, vz2, co, si;
2920 co= (float)cos(phi);
2921 si= (float)sin(phi);
2923 mat[0][0]= vx2+co*(1.0f-vx2);
2924 mat[0][1]= vx*vy*(1.0f-co)+vz*si;
2925 mat[0][2]= vz*vx*(1.0f-co)-vy*si;
2926 mat[1][0]= vx*vy*(1.0f-co)-vz*si;
2927 mat[1][1]= vy2+co*(1.0f-vy2);
2928 mat[1][2]= vy*vz*(1.0f-co)+vx*si;
2929 mat[2][0]= vz*vx*(1.0f-co)+vy*si;
2930 mat[2][1]= vy*vz*(1.0f-co)-vx*si;
2931 mat[2][2]= vz2+co*(1.0f-vz2);
2935 void VecRotToMat4( float *vec, float phi, float mat[][4])
2939 VecRotToMat3(vec, phi, tmat);
2941 Mat4CpyMat3(mat, tmat);
2944 void VecRotToQuat( float *vec, float phi, float *quat)
2946 /* rotation of phi radials around vec */
2953 if( Normalize(quat+1) == 0.0) {
2957 quat[0]= (float)cos( phi/2.0 );
2958 si= (float)sin( phi/2.0 );
2965 /* Return the angle in degrees between vecs 1-2 and 2-3 in degrees
2966 If v1 is a shoulder, v2 is the elbow and v3 is the hand,
2967 this would return the angle at the elbow */
2968 float VecAngle3(float *v1, float *v2, float *v3)
2970 float vec1[3], vec2[3];
2972 VecSubf(vec1, v2, v1);
2973 VecSubf(vec2, v2, v3);
2977 return NormalizedVecAngle2(vec1, vec2) * 180.0/M_PI;
2980 float VecAngle3_2D(float *v1, float *v2, float *v3)
2982 float vec1[2], vec2[2];
2984 vec1[0] = v2[0]-v1[0];
2985 vec1[1] = v2[1]-v1[1];
2987 vec2[0] = v2[0]-v3[0];
2988 vec2[1] = v2[1]-v3[1];
2993 return NormalizedVecAngle2_2D(vec1, vec2) * 180.0/M_PI;
2996 /* Return the shortest angle in degrees between the 2 vectors */
2997 float VecAngle2(float *v1, float *v2)
2999 float vec1[3], vec2[3];
3006 return NormalizedVecAngle2(vec1, vec2)* 180.0/M_PI;
3009 float NormalizedVecAngle2(float *v1, float *v2)
3011 /* this is the same as acos(Inpf(v1, v2)), but more accurate */
3012 if (Inpf(v1, v2) < 0.0f) {
3019 return (float)M_PI - 2.0f*saasin(VecLenf(vec, v1)/2.0f);
3022 return 2.0f*saasin(VecLenf(v2, v1)/2.0);
3025 float NormalizedVecAngle2_2D(float *v1, float *v2)
3027 /* this is the same as acos(Inpf(v1, v2)), but more accurate */
3028 if (Inp2f(v1, v2) < 0.0f) {
3034 return (float)M_PI - 2.0f*saasin(Vec2Lenf(vec, v1)/2.0f);
3037 return 2.0f*saasin(Vec2Lenf(v2, v1)/2.0);
3040 void euler_rot(float *beul, float ang, char axis)
3042 float eul[3], mat1[3][3], mat2[3][3], totmat[3][3];
3044 eul[0]= eul[1]= eul[2]= 0.0;
3045 if(axis=='x') eul[0]= ang;
3046 else if(axis=='y') eul[1]= ang;
3049 EulToMat3(eul, mat1);
3050 EulToMat3(beul, mat2);
3052 Mat3MulMat3(totmat, mat2, mat1);
3054 Mat3ToEul(totmat, beul);
3058 /* exported to transform.c */
3059 void compatible_eul(float *eul, float *oldrot)
3063 /* correct differences of about 360 degrees first */
3065 dx= eul[0] - oldrot[0];
3066 dy= eul[1] - oldrot[1];
3067 dz= eul[2] - oldrot[2];
3069 while( fabs(dx) > 5.1) {
3070 if(dx > 0.0) eul[0] -= 2.0*M_PI; else eul[0]+= 2.0*M_PI;
3071 dx= eul[0] - oldrot[0];
3073 while( fabs(dy) > 5.1) {
3074 if(dy > 0.0) eul[1] -= 2.0*M_PI; else eul[1]+= 2.0*M_PI;
3075 dy= eul[1] - oldrot[1];
3077 while( fabs(dz) > 5.1 ) {
3078 if(dz > 0.0) eul[2] -= 2.0*M_PI; else eul[2]+= 2.0*M_PI;
3079 dz= eul[2] - oldrot[2];
3082 /* is 1 of the axis rotations larger than 180 degrees and the other small? NO ELSE IF!! */
3083 if( fabs(dx) > 3.2 && fabs(dy)<1.6 && fabs(dz)<1.6 ) {
3084 if(dx > 0.0) eul[0] -= 2.0*M_PI; else eul[0]+= 2.0*M_PI;
3086 if( fabs(dy) > 3.2 && fabs(dz)<1.6 && fabs(dx)<1.6 ) {
3087 if(dy > 0.0) eul[1] -= 2.0*M_PI; else eul[1]+= 2.0*M_PI;
3089 if( fabs(dz) > 3.2 && fabs(dx)<1.6 && fabs(dy)<1.6 ) {
3090 if(dz > 0.0) eul[2] -= 2.0*M_PI; else eul[2]+= 2.0*M_PI;
3093 /* the method below was there from ancient days... but why! probably because the code sucks :)
3097 dx= eul[0] - oldrot[0];
3098 dy= eul[1] - oldrot[1];
3099 dz= eul[2] - oldrot[2];
3101 /* special case, tested for x-z */
3103 if( (fabs(dx) > 3.1 && fabs(dz) > 1.5 ) || ( fabs(dx) > 1.5 && fabs(dz) > 3.1 ) ) {
3104 if(dx > 0.0) eul[0] -= M_PI; else eul[0]+= M_PI;
3105 if(eul[1] > 0.0) eul[1]= M_PI - eul[1]; else eul[1]= -M_PI - eul[1];
3106 if(dz > 0.0) eul[2] -= M_PI; else eul[2]+= M_PI;
3109 else if( (fabs(dx) > 3.1 && fabs(dy) > 1.5 ) || ( fabs(dx) > 1.5 && fabs(dy) > 3.1 ) ) {
3110 if(dx > 0.0) eul[0] -= M_PI; else eul[0]+= M_PI;
3111 if(dy > 0.0) eul[1] -= M_PI; else eul[1]+= M_PI;
3112 if(eul[2] > 0.0) eul[2]= M_PI - eul[2]; else eul[2]= -M_PI - eul[2];
3114 else if( (fabs(dy) > 3.1 && fabs(dz) > 1.5 ) || ( fabs(dy) > 1.5 && fabs(dz) > 3.1 ) ) {
3115 if(eul[0] > 0.0) eul[0]= M_PI - eul[0]; else eul[0]= -M_PI - eul[0];
3116 if(dy > 0.0) eul[1] -= M_PI; else eul[1]+= M_PI;
3117 if(dz > 0.0) eul[2] -= M_PI; else eul[2]+= M_PI;
3122 /* uses 2 methods to retrieve eulers, and picks the closest */
3123 void Mat3ToCompatibleEul(float mat[][3], float *eul, float *oldrot)
3125 float eul1[3], eul2[3];
3128 mat3_to_eul2(mat, eul1, eul2);
3130 compatible_eul(eul1, oldrot);
3131 compatible_eul(eul2, oldrot);
3133 d1= fabs(eul1[0]-oldrot[0]) + fabs(eul1[1]-oldrot[1]) + fabs(eul1[2]-oldrot[2]);
3134 d2= fabs(eul2[0]-oldrot[0]) + fabs(eul2[1]-oldrot[1]) + fabs(eul2[2]-oldrot[2]);
3136 /* return best, which is just the one with lowest difference */
3138 VecCopyf(eul, eul2);
3141 VecCopyf(eul, eul1);
3146 /* ******************************************** */
3148 void SizeToMat3( float *size, float mat[][3])
3161 void SizeToMat4( float *size, float mat[][4])
3165 SizeToMat3(size, tmat);
3167 Mat4CpyMat3(mat, tmat);
3170 void Mat3ToSize( float mat[][3], float *size)
3172 size[0]= VecLength(mat[0]);
3173 size[1]= VecLength(mat[1]);
3174 size[2]= VecLength(mat[2]);
3177 void Mat4ToSize( float mat[][4], float *size)
3179 size[0]= VecLength(mat[0]);
3180 size[1]= VecLength(mat[1]);
3181 size[2]= VecLength(mat[2]);
3184 /* this gets the average scale of a matrix, only use when your scaling
3185 * data that has no idea of scale axis, examples are bone-envelope-radius
3186 * and curve radius */
3187 float Mat3ToScalef(float mat[][3])
3189 /* unit length vector */
3190 float unit_vec[3] = {0.577350269189626, 0.577350269189626, 0.577350269189626};
3191 Mat3MulVecfl(mat, unit_vec);
3192 return VecLength(unit_vec);
3195 float Mat4ToScalef(float mat[][4])
3198 Mat3CpyMat4(tmat, mat);
3199 return Mat3ToScalef(tmat);
3203 /* ************* SPECIALS ******************* */
3205 void triatoquat( float *v1, float *v2, float *v3, float *quat)
3207 /* imaginary x-axis, y-axis triangle is being rotated */
3208 float vec[3], q1[4], q2[4], n[3], si, co, angle, mat[3][3], imat[3][3];
3210 /* move z-axis to face-normal */
3211 CalcNormFloat(v1, v2, v3, vec);
3218 if(n[0]==0.0 && n[1]==0.0) n[0]= 1.0;
3220 angle= -0.5f*saacos(vec[2]);
3221 co= (float)cos(angle);
3222 si= (float)sin(angle);
3228 /* rotate back line v1-v2 */
3229 QuatToMat3(q1, mat);
3231 VecSubf(vec, v2, v1);
3232 Mat3MulVecfl(imat, vec);
3234 /* what angle has this line with x-axis? */
3238 angle= (float)(0.5*atan2(vec[1], vec[0]));
3239 co= (float)cos(angle);
3240 si= (float)sin(angle);
3246 QuatMul(quat, q1, q2);
3249 void MinMaxRGB(short c[])
3251 if(c[0]>255) c[0]=255;
3252 else if(c[0]<0) c[0]=0;
3253 if(c[1]>255) c[1]=255;
3254 else if(c[1]<0) c[1]=0;
3255 if(c[2]>255) c[2]=255;
3256 else if(c[2]<0) c[2]=0;
3259 float Vec2Lenf(float *v1, float *v2)
3265 return (float)sqrt(x*x+y*y);
3268 float Vec2Length(float *v)
3270 return (float)sqrt(v[0]*v[0] + v[1]*v[1]);
3273 void Vec2Mulf(float *v1, float f)
3279 void Vec2Addf(float *v, float *v1, float *v2)
3285 void Vec2Subf(float *v, float *v1, float *v2)
3291 void Vec2Copyf(float *v1, float *v2)
3297 float Inp2f(float *v1, float *v2)
3299 return v1[0]*v2[0]+v1[1]*v2[1];
3302 float Normalize2(float *n)
3306 d= n[0]*n[0]+n[1]*n[1];
3320 void hsv_to_rgb(float h, float s, float v, float *r, float *g, float *b)
3340 t = v*(1.0f-(s*(1.0f-f)));
3377 void rgb_to_yuv(float r, float g, float b, float *ly, float *lu, float *lv)
3380 y= 0.299*r + 0.587*g + 0.114*b;
3381 u=-0.147*r - 0.289*g + 0.436*b;
3382 v= 0.615*r - 0.515*g - 0.100*b;
3389 void yuv_to_rgb(float y, float u, float v, float *lr, float *lg, float *lb)
3393 g=y-0.394*u - 0.581*v;
3401 void rgb_to_ycc(float r, float g, float b, float *ly, float *lcb, float *lcr)
3411 y=(0.257*sr)+(0.504*sg)+(0.098*sb)+16.0;
3412 cb=(-0.148*sr)-(0.291*sg)+(0.439*sb)+128.0;
3413 cr=(0.439*sr)-(0.368*sg)-(0.071*sb)+128.0;
3420 void ycc_to_rgb(float y, float cb, float cr, float *lr, float *lg, float *lb)
3424 r=1.164*(y-16)+1.596*(cr-128);
3425 g=1.164*(y-16)-0.813*(cr-128)-0.392*(cb-128);
3426 b=1.164*(y-16)+2.017*(cb-128);
3433 void hex_to_rgb(char *hexcol, float *r, float *g, float *b)
3435 unsigned int ri, gi, bi;
3437 if (hexcol[0] == '#') hexcol++;
3439 if (sscanf(hexcol, "%02x%02x%02x", &ri, &gi, &bi)) {
3446 void rgb_to_hsv(float r, float g, float b, float *lh, float *ls, float *lv)
3449 float cmax, cmin, cdelta;
3454 cmax = (g>cmax ? g:cmax);
3455 cmin = (g<cmin ? g:cmin);
3456 cmax = (b>cmax ? b:cmax);
3457 cmin = (b<cmin ? b:cmin);
3459 v = cmax; /* value */
3461 s = (cmax - cmin)/cmax;
3470 rc = (cmax-r)/cdelta;
3471 gc = (cmax-g)/cdelta;
3472 bc = (cmax-b)/cdelta;
3487 if( *lh < 0.0) *lh= 0.0;
3491 /*http://brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html */
3493 void xyz_to_rgb(float xc, float yc, float zc, float *r, float *g, float *b, int colorspace)
3495 switch (colorspace) {
3497 *r = (3.50570 * xc) + (-1.73964 * yc) + (-0.544011 * zc);
3498 *g = (-1.06906 * xc) + (1.97781 * yc) + (0.0351720 * zc);
3499 *b = (0.0563117 * xc) + (-0.196994 * yc) + (1.05005 * zc);
3502 *r = (3.240476 * xc) + (-1.537150 * yc) + (-0.498535 * zc);
3503 *g = (-0.969256 * xc) + (1.875992 * yc) + (0.041556 * zc);
3504 *b = (0.055648 * xc) + (-0.204043 * yc) + (1.057311 * zc);