/src/gpac/src/utils/math.c
Line | Count | Source |
1 | | /* |
2 | | * GPAC - Multimedia Framework C SDK |
3 | | * |
4 | | * Authors: Jean Le Feuvre |
5 | | * Copyright (c) Telecom ParisTech 2000-2023 |
6 | | * All rights reserved |
7 | | * |
8 | | * This file is part of GPAC / common tools sub-project |
9 | | * |
10 | | * GPAC is free software; you can redistribute it and/or modify |
11 | | * it under the terms of the GNU Lesser General Public License as published by |
12 | | * the Free Software Foundation; either version 2, or (at your option) |
13 | | * any later version. |
14 | | * |
15 | | * GPAC is distributed in the hope that it will be useful, |
16 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 | | * GNU Lesser General Public License for more details. |
19 | | * |
20 | | * You should have received a copy of the GNU Lesser General Public |
21 | | * License along with this library; see the file COPYING. If not, write to |
22 | | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
23 | | * |
24 | | * |
25 | | * fixed-point trigo routines taken from freetype |
26 | | * Copyright 1996-2001, 2002, 2004 by |
27 | | * David Turner, Robert Wilhelm, and Werner Lemberg. |
28 | | * License: FTL or GPL |
29 | | * |
30 | | */ |
31 | | |
32 | | #include <gpac/maths.h> |
33 | | |
34 | | #if !defined(GPAC_DISABLE_EVG) || !defined(GPAC_DISABLE_3D) || !defined(GPAC_DISABLE_VRML) || !defined(GPAC_DISABLE_SVG) |
35 | | #define DISABLE_MATHS |
36 | | #endif |
37 | | |
38 | | |
39 | | GF_EXPORT |
40 | | u32 gf_get_bit_size(u32 MaxVal) |
41 | 416 | { |
42 | 416 | u32 k=0; |
43 | 1.24k | while (MaxVal > (((u32)1<<k)-1) ) { |
44 | 832 | if (k==31) { |
45 | 0 | return 32; |
46 | 0 | } |
47 | 832 | k+=1; |
48 | 832 | } |
49 | 416 | return k; |
50 | 416 | } |
51 | | |
52 | | /*adds @rc2 to @rc1 - the new @rc1 contains the old @rc1 and @rc2*/ |
53 | | GF_EXPORT |
54 | | void gf_irect_union(GF_IRect *rc1, GF_IRect *rc2) |
55 | 0 | { |
56 | 0 | if (!rc1->width || !rc1->height) { |
57 | 0 | *rc1=*rc2; |
58 | 0 | return; |
59 | 0 | } |
60 | | |
61 | 0 | if (rc2->x < rc1->x) { |
62 | 0 | rc1->width += rc1->x - rc2->x; |
63 | 0 | rc1->x = rc2->x; |
64 | 0 | } |
65 | 0 | if (rc2->x + rc2->width > rc1->x+rc1->width) rc1->width = rc2->x + rc2->width - rc1->x; |
66 | 0 | if (rc2->y > rc1->y) { |
67 | 0 | rc1->height += rc2->y - rc1->y; |
68 | 0 | rc1->y = rc2->y; |
69 | 0 | } |
70 | 0 | if (rc2->y - rc2->height < rc1->y - rc1->height) rc1->height = rc1->y - rc2->y + rc2->height; |
71 | 0 | } |
72 | | |
73 | | #ifdef DISABLE_MATHS |
74 | | |
75 | | #ifdef GPAC_FIXED_POINT |
76 | | |
77 | | #ifndef __GNUC__ |
78 | | #pragma message("Compiling with fixed-point arithmetic") |
79 | | #endif |
80 | | |
81 | | #if defined(__SYMBIAN32__) && !defined(__SERIES60_3X__) |
82 | | typedef long long fix_s64; |
83 | | #else |
84 | | typedef s64 fix_s64; |
85 | | #endif |
86 | | |
87 | | |
88 | | /* the following is 0.2715717684432231 * 2^30 */ |
89 | | #define GF_TRIG_COSCALE 0x11616E8EUL |
90 | | |
91 | | /* this table was generated for degrees */ |
92 | | #define GF_TRIG_MAX_ITERS 23 |
93 | | |
94 | | static const Fixed gf_trig_arctan_table[24] = |
95 | | { |
96 | | 4157273L, 2949120L, 1740967L, 919879L, 466945L, 234379L, 117304L, |
97 | | 58666L, 29335L, 14668L, 7334L, 3667L, 1833L, 917L, 458L, 229L, 115L, |
98 | | 57L, 29L, 14L, 7L, 4L, 2L, 1L |
99 | | }; |
100 | | |
101 | | /* the Cordic shrink factor, multiplied by 2^32 */ |
102 | | #define GF_TRIG_SCALE 1166391785 /* 0x4585BA38UL */ |
103 | | |
104 | | #define GF_ANGLE_PI (180<<16) |
105 | | #define GF_ANGLE_PI2 (90<<16) |
106 | | #define GF_ANGLE_2PI (360<<16) |
107 | | |
108 | | #define GF_PAD_FLOOR( x, n ) ( (x) & ~((n)-1) ) |
109 | | #define GF_PAD_ROUND( x, n ) GF_PAD_FLOOR( (x) + ((n)/2), n ) |
110 | | #define GF_PAD_CEIL( x, n ) GF_PAD_FLOOR( (x) + ((n)-1), n ) |
111 | | |
112 | | static GFINLINE s32 gf_trig_prenorm(GF_Point2D *vec) |
113 | | { |
114 | | Fixed x, y, z; |
115 | | s32 shift; |
116 | | x = vec->x; |
117 | | y = vec->y; |
118 | | z = ( ( x >= 0 ) ? x : - x ) | ( (y >= 0) ? y : -y ); |
119 | | shift = 0; |
120 | | if ( z < ( 1L << 27 ) ) { |
121 | | do { |
122 | | shift++; |
123 | | z <<= 1; |
124 | | } |
125 | | while ( z < ( 1L << 27 ) ); |
126 | | |
127 | | vec->x = x << shift; |
128 | | vec->y = y << shift; |
129 | | } |
130 | | else if ( z > ( 1L << 28 ) ) { |
131 | | do { |
132 | | shift++; |
133 | | z >>= 1; |
134 | | } while ( z > ( 1L << 28 ) ); |
135 | | |
136 | | vec->x = x >> shift; |
137 | | vec->y = y >> shift; |
138 | | shift = -shift; |
139 | | } |
140 | | return shift; |
141 | | } |
142 | | |
143 | | #define ANGLE_RAD_TO_DEG(_th) ((s32) ( (((fix_s64)_th)*5729582)/100000)) |
144 | | #define ANGLE_DEG_TO_RAD(_th) ((s32) ( (((fix_s64)_th)*100000)/5729582)) |
145 | | |
146 | | static GFINLINE void gf_trig_pseudo_polarize(GF_Point2D *vec) |
147 | | { |
148 | | Fixed theta; |
149 | | Fixed yi, i; |
150 | | Fixed x, y; |
151 | | const Fixed *arctanptr; |
152 | | |
153 | | x = vec->x; |
154 | | y = vec->y; |
155 | | |
156 | | /* Get the vector into the right half plane */ |
157 | | theta = 0; |
158 | | if ( x < 0 ) { |
159 | | x = -x; |
160 | | y = -y; |
161 | | theta = 2 * GF_ANGLE_PI2; |
162 | | } |
163 | | |
164 | | if ( y > 0 ) |
165 | | theta = - theta; |
166 | | |
167 | | arctanptr = gf_trig_arctan_table; |
168 | | |
169 | | if ( y < 0 ) { |
170 | | /* Rotate positive */ |
171 | | yi = y + ( x << 1 ); |
172 | | x = x - ( y << 1 ); |
173 | | y = yi; |
174 | | theta -= *arctanptr++; /* Subtract angle */ |
175 | | } else { |
176 | | /* Rotate negative */ |
177 | | yi = y - ( x << 1 ); |
178 | | x = x + ( y << 1 ); |
179 | | y = yi; |
180 | | theta += *arctanptr++; /* Add angle */ |
181 | | } |
182 | | |
183 | | i = 0; |
184 | | do { |
185 | | if ( y < 0 ) { |
186 | | /* Rotate positive */ |
187 | | yi = y + ( x >> i ); |
188 | | x = x - ( y >> i ); |
189 | | y = yi; |
190 | | theta -= *arctanptr++; |
191 | | } else { |
192 | | /* Rotate negative */ |
193 | | yi = y - ( x >> i ); |
194 | | x = x + ( y >> i ); |
195 | | y = yi; |
196 | | theta += *arctanptr++; |
197 | | } |
198 | | } |
199 | | while ( ++i < GF_TRIG_MAX_ITERS ); |
200 | | |
201 | | /* round theta */ |
202 | | if ( theta >= 0 ) |
203 | | theta = GF_PAD_ROUND( theta, 32 ); |
204 | | else |
205 | | theta = - GF_PAD_ROUND( -theta, 32 ); |
206 | | |
207 | | vec->x = x; |
208 | | vec->y = ANGLE_DEG_TO_RAD(theta); |
209 | | } |
210 | | |
211 | | GF_EXPORT |
212 | | Fixed gf_atan2(Fixed dy, Fixed dx) |
213 | | { |
214 | | GF_Point2D v; |
215 | | if ( dx == 0 && dy == 0 ) return 0; |
216 | | v.x = dx; |
217 | | v.y = dy; |
218 | | gf_trig_prenorm( &v ); |
219 | | gf_trig_pseudo_polarize( &v ); |
220 | | return v.y; |
221 | | } |
222 | | |
223 | | /*define one of these to enable IntelGPP support and link to gpp_WMMX40_d.lib (debug) or gpp_WMMX40_r.lib (release) |
224 | | this is not configured by default for lack of real perf increase.*/ |
225 | | #if defined(GPAC_USE_IGPP_HP) || defined(GPAC_USE_IGPP) |
226 | | # pragma message("Using IntelGPP math library") |
227 | | #ifdef _DEBUG |
228 | | # pragma comment(lib, "gpp_WMMX40_d") |
229 | | #else |
230 | | # pragma comment(lib, "gpp_WMMX40_r") |
231 | | #endif |
232 | | |
233 | | #include <gpp.h> |
234 | | |
235 | | GF_EXPORT |
236 | | Fixed gf_invfix(Fixed a) |
237 | | { |
238 | | Fixed res; |
239 | | if (!a) return (s32)0x7FFFFFFFL; |
240 | | gppInv_16_32s(a, &res); |
241 | | return res; |
242 | | } |
243 | | GF_EXPORT |
244 | | Fixed gf_divfix(Fixed a, Fixed b) |
245 | | { |
246 | | Fixed res; |
247 | | if (!a) return 0; |
248 | | else if (!b) return (a<0) ? -(s32)0x7FFFFFFFL : (s32)0x7FFFFFFFL; |
249 | | else if (a==FIX_ONE) gppInv_16_32s(b, &res); |
250 | | else gppDiv_16_32s(a, b, &res); |
251 | | return res; |
252 | | } |
253 | | |
254 | | GF_EXPORT |
255 | | Fixed gf_mulfix(Fixed a, Fixed b) |
256 | | { |
257 | | Fixed res; |
258 | | if (!a || !b) return 0; |
259 | | else if (b == FIX_ONE) return a; |
260 | | else gppMul_16_32s(a, b, &res); |
261 | | return res; |
262 | | } |
263 | | |
264 | | GF_EXPORT |
265 | | Fixed gf_sqrt(Fixed x) |
266 | | { |
267 | | Fixed res; |
268 | | #ifdef GPAC_USE_IGPP_HP |
269 | | gppSqrtHP_16_32s(x, &res); |
270 | | #else |
271 | | gppSqrtLP_16_32s(x, &res); |
272 | | #endif |
273 | | return res; |
274 | | } |
275 | | |
276 | | GF_EXPORT |
277 | | Fixed gf_cos(Fixed angle) |
278 | | { |
279 | | Fixed res; |
280 | | #ifdef GPAC_USE_IGPP_HP |
281 | | gppCosHP_16_32s(angle, &res); |
282 | | #else |
283 | | gppCosLP_16_32s(angle, &res); |
284 | | #endif |
285 | | return res; |
286 | | } |
287 | | |
288 | | GF_EXPORT |
289 | | Fixed gf_sin(Fixed angle) |
290 | | { |
291 | | Fixed res; |
292 | | #ifdef GPAC_USE_IGPP_HP |
293 | | gppSinHP_16_32s (angle, &res); |
294 | | #else |
295 | | gppSinLP_16_32s (angle, &res); |
296 | | #endif |
297 | | return res; |
298 | | } |
299 | | |
300 | | |
301 | | GF_EXPORT |
302 | | Fixed gf_tan(Fixed angle) |
303 | | { |
304 | | Fixed cosa, sina; |
305 | | #ifdef GPAC_USE_IGPP_HP |
306 | | gppSinCosHP_16_32s(angle, &sina, &cosa); |
307 | | #else |
308 | | gppSinCosLP_16_32s(angle, &sina, &cosa); |
309 | | #endif |
310 | | if (!cosa) return (sina<0) ? -GF_PI2 : GF_PI2; |
311 | | return gf_divfix(sina, cosa); |
312 | | } |
313 | | |
314 | | GF_EXPORT |
315 | | GF_Point2D gf_v2d_from_polar(Fixed length, Fixed angle) |
316 | | { |
317 | | GF_Point2D vec; |
318 | | Fixed cosa, sina; |
319 | | #ifdef GPAC_USE_IGPP_HP |
320 | | gppSinCosHP_16_32s(angle, &sina, &cosa); |
321 | | #else |
322 | | gppSinCosLP_16_32s(angle, &sina, &cosa); |
323 | | #endif |
324 | | vec.x = gf_mulfix(length, cosa); |
325 | | vec.y = gf_mulfix(length, sina); |
326 | | return vec; |
327 | | } |
328 | | |
329 | | GF_EXPORT |
330 | | Fixed gf_v2d_len(GF_Point2D *vec) |
331 | | { |
332 | | Fixed a, b, res; |
333 | | if (!vec->x) return ABS(vec->y); |
334 | | if (!vec->y) return ABS(vec->x); |
335 | | gppSquare_16_32s(vec->x, &a); |
336 | | gppSquare_16_32s(vec->y, &b); |
337 | | #ifdef GPAC_USE_IGPP_HP |
338 | | gppSqrtHP_16_32s(a+b, &res); |
339 | | #else |
340 | | gppSqrtLP_16_32s(a+b, &res); |
341 | | #endif |
342 | | return res; |
343 | | } |
344 | | |
345 | | #else |
346 | | |
347 | | GF_EXPORT |
348 | | Fixed gf_invfix(Fixed a) |
349 | | { |
350 | | if (!a) return (s32)0x7FFFFFFFL; |
351 | | return gf_divfix(FIX_ONE, a); |
352 | | } |
353 | | |
354 | | GF_EXPORT |
355 | | Fixed gf_divfix(Fixed a, Fixed b) |
356 | | { |
357 | | s32 s; |
358 | | u32 q; |
359 | | if (!a) return 0; |
360 | | s = 1; |
361 | | if ( a < 0 ) { |
362 | | a = -a; |
363 | | s = -1; |
364 | | } |
365 | | if ( b < 0 ) { |
366 | | b = -b; |
367 | | s = -s; |
368 | | } |
369 | | |
370 | | if ( b == 0 ) |
371 | | /* check for division by 0 */ |
372 | | q = 0x7FFFFFFFL; |
373 | | else { |
374 | | /* compute result directly */ |
375 | | q = (u32)( ( ( (fix_s64)a << 16 ) + ( b >> 1 ) ) / b ); |
376 | | } |
377 | | return ( s < 0 ? -(s32)q : (s32)q ); |
378 | | } |
379 | | |
380 | | GF_EXPORT |
381 | | Fixed gf_mulfix(Fixed a, Fixed b) |
382 | | { |
383 | | Fixed s; |
384 | | u32 ua, ub; |
385 | | if ( !a || (b == 0x10000L)) return a; |
386 | | if (!b) return 0; |
387 | | |
388 | | s = a; |
389 | | a = ABS(a); |
390 | | s ^= b; |
391 | | b = ABS(b); |
392 | | |
393 | | ua = (u32)a; |
394 | | ub = (u32)b; |
395 | | |
396 | | if ((ua <= 2048) && (ub <= 1048576L)) { |
397 | | ua = ( ua * ub + 0x8000L ) >> 16; |
398 | | } else { |
399 | | u32 al = ua & 0xFFFFL; |
400 | | ua = ( ua >> 16 ) * ub + al * ( ub >> 16 ) + ( ( al * ( ub & 0xFFFFL ) + 0x8000L ) >> 16 ); |
401 | | } |
402 | | if (ua & 0x80000000) s=-s; |
403 | | return ( s < 0 ? -(Fixed)(s32)ua : (Fixed)ua ); |
404 | | } |
405 | | |
406 | | |
407 | | GF_EXPORT |
408 | | Fixed gf_sqrt(Fixed x) |
409 | | { |
410 | | u32 root, rem_hi, rem_lo, test_div; |
411 | | s32 count; |
412 | | root = 0; |
413 | | if ( x > 0 ) { |
414 | | rem_hi = 0; |
415 | | rem_lo = x; |
416 | | count = 24; |
417 | | do { |
418 | | rem_hi = ( rem_hi << 2 ) | ( rem_lo >> 30 ); |
419 | | rem_lo <<= 2; |
420 | | root <<= 1; |
421 | | test_div = ( root << 1 ) + 1; |
422 | | |
423 | | if ( rem_hi >= test_div ) { |
424 | | rem_hi -= test_div; |
425 | | root += 1; |
426 | | } |
427 | | } while ( --count ); |
428 | | } |
429 | | |
430 | | return (Fixed) root; |
431 | | } |
432 | | |
433 | | |
434 | | /* multiply a given value by the CORDIC shrink factor */ |
435 | | static Fixed gf_trig_downscale(Fixed val) |
436 | | { |
437 | | Fixed s; |
438 | | fix_s64 v; |
439 | | s = val; |
440 | | val = ( val >= 0 ) ? val : -val; |
441 | | #ifdef _MSC_VER |
442 | | v = ( val * (fix_s64)GF_TRIG_SCALE ) + 0x100000000; |
443 | | #else |
444 | | v = ( val * (fix_s64)GF_TRIG_SCALE ) + 0x100000000ULL; |
445 | | #endif |
446 | | val = (Fixed)( v >> 32 ); |
447 | | return ( s >= 0 ) ? val : -val; |
448 | | } |
449 | | |
450 | | static void gf_trig_pseudo_rotate(GF_Point2D* vec, Fixed theta) |
451 | | { |
452 | | s32 i; |
453 | | Fixed x, y, xtemp; |
454 | | const Fixed *arctanptr; |
455 | | |
456 | | /*trig funcs are in degrees*/ |
457 | | theta = ANGLE_RAD_TO_DEG(theta); |
458 | | |
459 | | x = vec->x; |
460 | | y = vec->y; |
461 | | |
462 | | /* Get angle between -90 and 90 degrees */ |
463 | | while ( theta <= -GF_ANGLE_PI2 ) { |
464 | | x = -x; |
465 | | y = -y; |
466 | | theta += GF_ANGLE_PI; |
467 | | } |
468 | | |
469 | | while ( theta > GF_ANGLE_PI2 ) { |
470 | | x = -x; |
471 | | y = -y; |
472 | | theta -= GF_ANGLE_PI; |
473 | | } |
474 | | |
475 | | /* Initial pseudorotation, with left shift */ |
476 | | arctanptr = gf_trig_arctan_table; |
477 | | if ( theta < 0 ) { |
478 | | xtemp = x + ( y << 1 ); |
479 | | y = y - ( x << 1 ); |
480 | | x = xtemp; |
481 | | theta += *arctanptr++; |
482 | | } else { |
483 | | xtemp = x - ( y << 1 ); |
484 | | y = y + ( x << 1 ); |
485 | | x = xtemp; |
486 | | theta -= *arctanptr++; |
487 | | } |
488 | | /* Subsequent pseudorotations, with right shifts */ |
489 | | i = 0; |
490 | | do { |
491 | | if ( theta < 0 ) { |
492 | | xtemp = x + ( y >> i ); |
493 | | y = y - ( x >> i ); |
494 | | x = xtemp; |
495 | | theta += *arctanptr++; |
496 | | } else { |
497 | | xtemp = x - ( y >> i ); |
498 | | y = y + ( x >> i ); |
499 | | x = xtemp; |
500 | | theta -= *arctanptr++; |
501 | | } |
502 | | } while ( ++i < GF_TRIG_MAX_ITERS ); |
503 | | |
504 | | vec->x = x; |
505 | | vec->y = y; |
506 | | } |
507 | | |
508 | | /* these macros return 0 for positive numbers, and -1 for negative ones */ |
509 | | #define GF_SIGN_LONG( x ) ( (x) >> ( 32 - 1 ) ) |
510 | | #define GF_SIGN_INT( x ) ( (x) >> ( 32 - 1 ) ) |
511 | | #define GF_SIGN_INT32( x ) ( (x) >> 31 ) |
512 | | #define GF_SIGN_INT16( x ) ( (x) >> 15 ) |
513 | | |
514 | | static void gf_v2d_rotate(GF_Point2D *vec, Fixed angle) |
515 | | { |
516 | | s32 shift; |
517 | | GF_Point2D v; |
518 | | |
519 | | v.x = vec->x; |
520 | | v.y = vec->y; |
521 | | |
522 | | if ( angle && ( v.x != 0 || v.y != 0 ) ) { |
523 | | shift = gf_trig_prenorm( &v ); |
524 | | gf_trig_pseudo_rotate( &v, angle ); |
525 | | v.x = gf_trig_downscale( v.x ); |
526 | | v.y = gf_trig_downscale( v.y ); |
527 | | |
528 | | if ( shift > 0 ) { |
529 | | s32 half = 1L << ( shift - 1 ); |
530 | | |
531 | | vec->x = ( v.x + half + GF_SIGN_LONG( v.x ) ) >> shift; |
532 | | vec->y = ( v.y + half + GF_SIGN_LONG( v.y ) ) >> shift; |
533 | | } else { |
534 | | shift = -shift; |
535 | | vec->x = v.x << shift; |
536 | | vec->y = v.y << shift; |
537 | | } |
538 | | } |
539 | | } |
540 | | |
541 | | GF_EXPORT |
542 | | Fixed gf_v2d_len(GF_Point2D *vec) |
543 | | { |
544 | | s32 shift; |
545 | | GF_Point2D v; |
546 | | v = *vec; |
547 | | |
548 | | /* handle trivial cases */ |
549 | | if ( v.x == 0 ) { |
550 | | return ( v.y >= 0 ) ? v.y : -v.y; |
551 | | } else if ( v.y == 0 ) { |
552 | | return ( v.x >= 0 ) ? v.x : -v.x; |
553 | | } |
554 | | |
555 | | /* general case */ |
556 | | shift = gf_trig_prenorm( &v ); |
557 | | gf_trig_pseudo_polarize( &v ); |
558 | | v.x = gf_trig_downscale( v.x ); |
559 | | if ( shift > 0 ) |
560 | | return ( v.x + ( 1 << ( shift - 1 ) ) ) >> shift; |
561 | | |
562 | | return v.x << -shift; |
563 | | } |
564 | | |
565 | | |
566 | | GF_EXPORT |
567 | | void gf_v2d_polarize(GF_Point2D *vec, Fixed *length, Fixed *angle) |
568 | | { |
569 | | s32 shift; |
570 | | GF_Point2D v; |
571 | | v = *vec; |
572 | | if ( v.x == 0 && v.y == 0 ) |
573 | | return; |
574 | | |
575 | | shift = gf_trig_prenorm( &v ); |
576 | | gf_trig_pseudo_polarize( &v ); |
577 | | v.x = gf_trig_downscale( v.x ); |
578 | | *length = ( shift >= 0 ) ? ( v.x >> shift ) : ( v.x << -shift ); |
579 | | *angle = v.y; |
580 | | } |
581 | | |
582 | | GF_EXPORT |
583 | | GF_Point2D gf_v2d_from_polar(Fixed length, Fixed angle) |
584 | | { |
585 | | GF_Point2D vec; |
586 | | vec.x = length; |
587 | | vec.y = 0; |
588 | | gf_v2d_rotate(&vec, angle); |
589 | | return vec; |
590 | | } |
591 | | |
592 | | GF_EXPORT |
593 | | Fixed gf_cos(Fixed angle) |
594 | | { |
595 | | GF_Point2D v; |
596 | | v.x = GF_TRIG_COSCALE >> 2; |
597 | | v.y = 0; |
598 | | gf_trig_pseudo_rotate( &v, angle ); |
599 | | return v.x / ( 1 << 12 ); |
600 | | } |
601 | | GF_EXPORT |
602 | | Fixed gf_sin(Fixed angle) |
603 | | { |
604 | | return gf_cos( GF_PI2 - angle ); |
605 | | } |
606 | | GF_EXPORT |
607 | | Fixed gf_tan(Fixed angle) |
608 | | { |
609 | | GF_Point2D v; |
610 | | v.x = GF_TRIG_COSCALE >> 2; |
611 | | v.y = 0; |
612 | | gf_trig_pseudo_rotate( &v, angle ); |
613 | | return gf_divfix( v.y, v.x ); |
614 | | } |
615 | | |
616 | | #endif |
617 | | |
618 | | /*common parts*/ |
619 | | GF_EXPORT |
620 | | Fixed gf_muldiv(Fixed a, Fixed b, Fixed c) |
621 | | { |
622 | | s32 s, d; |
623 | | if (!b || !a) return 0; |
624 | | s = 1; |
625 | | if ( a < 0 ) { |
626 | | a = -a; |
627 | | s = -1; |
628 | | } |
629 | | if ( b < 0 ) { |
630 | | b = -b; |
631 | | s = -s; |
632 | | } |
633 | | if ( c < 0 ) { |
634 | | c = -c; |
635 | | s = -s; |
636 | | } |
637 | | |
638 | | d = (s32)( c > 0 ? ( (fix_s64)a * b + ( c >> 1 ) ) / c : 0x7FFFFFFFL); |
639 | | return (Fixed) (( s > 0 ) ? d : -d); |
640 | | } |
641 | | |
642 | | |
643 | | GF_EXPORT |
644 | | Fixed gf_ceil(Fixed a) |
645 | | { |
646 | | return (a >= 0) ? (a + 0xFFFFL) & ~0xFFFFL : -((-a + 0xFFFFL) & ~0xFFFFL); |
647 | | } |
648 | | |
649 | | GF_EXPORT |
650 | | Fixed gf_floor(Fixed a) |
651 | | { |
652 | | return (a >= 0) ? (a & ~0xFFFFL) : -((-a) & ~0xFFFFL); |
653 | | } |
654 | | |
655 | | |
656 | | /*FIXME*/ |
657 | | GF_EXPORT |
658 | | Fixed gf_acos(Fixed angle) |
659 | | { |
660 | | return FLT2FIX( (Float) acos(FIX2FLT(angle))); |
661 | | } |
662 | | |
663 | | /*FIXME*/ |
664 | | GF_EXPORT |
665 | | Fixed gf_asin(Fixed angle) |
666 | | { |
667 | | return FLT2FIX( (Float) asin(FIX2FLT(angle))); |
668 | | } |
669 | | |
670 | | |
671 | | #else |
672 | | |
673 | | |
674 | | GF_EXPORT |
675 | | GF_Point2D gf_v2d_from_polar(Fixed length, Fixed angle) |
676 | 0 | { |
677 | 0 | GF_Point2D vec; |
678 | 0 | vec.x = length*(Float) cos(angle); |
679 | 0 | vec.y = length*(Float) sin(angle); |
680 | 0 | return vec; |
681 | 0 | } |
682 | | |
683 | | GF_EXPORT |
684 | | Fixed gf_v2d_len(GF_Point2D *vec) |
685 | 0 | { |
686 | 0 | if (!vec->x) return ABS(vec->y); |
687 | 0 | if (!vec->y) return ABS(vec->x); |
688 | 0 | return (Fixed) sqrt(vec->x*vec->x + vec->y*vec->y); |
689 | 0 | } |
690 | | |
691 | | /* |
692 | | |
693 | | Fixed gf_cos(_a) { return (Float) cos(_a); } |
694 | | Fixed gf_sin(_a) { return (Float) sin(_a); } |
695 | | Fixed gf_tan(_a) { return (Float) tan(_a); } |
696 | | Fixed gf_atan2(_y, _x) { return (Float) atan2(_y, _x); } |
697 | | Fixed gf_sqrt(_x) { return (Float) sqrt(_x); } |
698 | | Fixed gf_ceil(_a) { return (Float) ceil(_a); } |
699 | | Fixed gf_floor(_a) { return (Float) floor(_a); } |
700 | | Fixed gf_acos(_a) { return (Float) acos(_a); } |
701 | | Fixed gf_asin(_a) { return (Float) asin(_a); } |
702 | | |
703 | | */ |
704 | | |
705 | | #endif |
706 | | |
707 | | GF_EXPORT |
708 | | Fixed gf_v2d_distance(GF_Point2D *a, GF_Point2D *b) |
709 | 0 | { |
710 | 0 | GF_Point2D d; |
711 | 0 | d.x = a->x - b->x; |
712 | 0 | d.y = a->y - b->y; |
713 | 0 | return gf_v2d_len(&d); |
714 | 0 | } |
715 | | |
716 | | GF_EXPORT |
717 | | Fixed gf_angle_diff(Fixed angle1, Fixed angle2) |
718 | 0 | { |
719 | 0 | Fixed delta = angle2 - angle1; |
720 | | #ifdef GPAC_FIXED_POINT |
721 | | delta %= GF_2PI; |
722 | | if (delta < 0) delta += GF_2PI; |
723 | | if (delta > GF_PI) delta -= GF_2PI; |
724 | | #else |
725 | 0 | while (delta < 0) delta += GF_2PI; |
726 | 0 | while (delta > GF_PI) delta -= GF_2PI; |
727 | 0 | #endif |
728 | 0 | return delta; |
729 | 0 | } |
730 | | |
731 | | |
732 | | |
733 | | /* |
734 | | 2D MATRIX TOOLS |
735 | | */ |
736 | | |
737 | | //sanity checker |
738 | | #if 0 |
739 | | void do_check_mx(GF_Matrix2D *_this) |
740 | | { |
741 | | if ( |
742 | | (ABS(_this->m[0])>1000000) |
743 | | || (ABS(_this->m[1])>100000) |
744 | | || (ABS(_this->m[2])>100000) |
745 | | || (ABS(_this->m[3])>100000) |
746 | | || (ABS(_this->m[4])>100000) |
747 | | || (ABS(_this->m[5])>100000) |
748 | | ) { |
749 | | exit(120); |
750 | | } |
751 | | } |
752 | | #define CHECK_MATRIX do_check_mx(_this); |
753 | | #else |
754 | | #define CHECK_MATRIX |
755 | | #endif |
756 | | |
757 | | GF_EXPORT |
758 | | void gf_mx2d_add_matrix(GF_Matrix2D *_this, GF_Matrix2D *from) |
759 | 0 | { |
760 | 0 | GF_Matrix2D bck; |
761 | 0 | if (!_this || !from) return; |
762 | | |
763 | 0 | if (gf_mx2d_is_identity(*from)) return; |
764 | 0 | else if (gf_mx2d_is_identity(*_this)) { |
765 | 0 | gf_mx2d_copy(*_this, *from); |
766 | 0 | return; |
767 | 0 | } |
768 | 0 | gf_mx2d_copy(bck, *_this); |
769 | 0 | _this->m[0] = gf_mulfix(from->m[0], bck.m[0]) + gf_mulfix(from->m[1], bck.m[3]); |
770 | 0 | _this->m[1] = gf_mulfix(from->m[0], bck.m[1]) + gf_mulfix(from->m[1], bck.m[4]); |
771 | 0 | _this->m[2] = gf_mulfix(from->m[0], bck.m[2]) + gf_mulfix(from->m[1], bck.m[5]) + from->m[2]; |
772 | 0 | _this->m[3] = gf_mulfix(from->m[3], bck.m[0]) + gf_mulfix(from->m[4], bck.m[3]); |
773 | 0 | _this->m[4] = gf_mulfix(from->m[3], bck.m[1]) + gf_mulfix(from->m[4], bck.m[4]); |
774 | 0 | _this->m[5] = gf_mulfix(from->m[3], bck.m[2]) + gf_mulfix(from->m[4], bck.m[5]) + from->m[5]; |
775 | |
|
776 | 0 | CHECK_MATRIX |
777 | 0 | } |
778 | | |
779 | | |
780 | | GF_EXPORT |
781 | | void gf_mx2d_pre_multiply(GF_Matrix2D *_this, GF_Matrix2D *with) |
782 | 0 | { |
783 | 0 | GF_Matrix2D bck; |
784 | 0 | if (!_this || !with) return; |
785 | | |
786 | 0 | if (gf_mx2d_is_identity(*with)) return; |
787 | 0 | else if (gf_mx2d_is_identity(*_this)) { |
788 | 0 | gf_mx2d_copy(*_this, *with); |
789 | 0 | return; |
790 | 0 | } |
791 | 0 | gf_mx2d_copy(bck, *_this); |
792 | 0 | _this->m[0] = gf_mulfix(bck.m[0], with->m[0]) + gf_mulfix(bck.m[1], with->m[3]); |
793 | 0 | _this->m[1] = gf_mulfix(bck.m[0], with->m[1]) + gf_mulfix(bck.m[1], with->m[4]); |
794 | 0 | _this->m[2] = gf_mulfix(bck.m[0], with->m[2]) + gf_mulfix(bck.m[1], with->m[5]) + bck.m[2]; |
795 | 0 | _this->m[3] = gf_mulfix(bck.m[3], with->m[0]) + gf_mulfix(bck.m[4], with->m[3]); |
796 | 0 | _this->m[4] = gf_mulfix(bck.m[3], with->m[1]) + gf_mulfix(bck.m[4], with->m[4]); |
797 | 0 | _this->m[5] = gf_mulfix(bck.m[3], with->m[2]) + gf_mulfix(bck.m[4], with->m[5]) + bck.m[5]; |
798 | |
|
799 | 0 | CHECK_MATRIX |
800 | 0 | } |
801 | | |
802 | | |
803 | | GF_EXPORT |
804 | | void gf_mx2d_add_translation(GF_Matrix2D *_this, Fixed cx, Fixed cy) |
805 | 0 | { |
806 | 0 | GF_Matrix2D tmp; |
807 | 0 | if (!_this || (!cx && !cy) ) return; |
808 | 0 | gf_mx2d_init(tmp); |
809 | 0 | tmp.m[2] = cx; |
810 | 0 | tmp.m[5] = cy; |
811 | 0 | gf_mx2d_add_matrix(_this, &tmp); |
812 | |
|
813 | 0 | CHECK_MATRIX |
814 | 0 | } |
815 | | |
816 | | |
817 | | GF_EXPORT |
818 | | void gf_mx2d_add_rotation(GF_Matrix2D *_this, Fixed cx, Fixed cy, Fixed angle) |
819 | 0 | { |
820 | 0 | GF_Matrix2D tmp; |
821 | 0 | if (!_this) return; |
822 | 0 | gf_mx2d_init(tmp); |
823 | |
|
824 | 0 | gf_mx2d_add_translation(_this, -cx, -cy); |
825 | |
|
826 | 0 | tmp.m[0] = gf_cos(angle); |
827 | 0 | tmp.m[4] = tmp.m[0]; |
828 | 0 | tmp.m[3] = gf_sin(angle); |
829 | 0 | tmp.m[1] = -1 * tmp.m[3]; |
830 | 0 | gf_mx2d_add_matrix(_this, &tmp); |
831 | 0 | gf_mx2d_add_translation(_this, cx, cy); |
832 | |
|
833 | 0 | CHECK_MATRIX |
834 | 0 | } |
835 | | |
836 | | GF_EXPORT |
837 | | void gf_mx2d_add_scale(GF_Matrix2D *_this, Fixed scale_x, Fixed scale_y) |
838 | 0 | { |
839 | 0 | GF_Matrix2D tmp; |
840 | 0 | if (!_this || ((scale_x==FIX_ONE) && (scale_y==FIX_ONE)) ) return; |
841 | 0 | gf_mx2d_init(tmp); |
842 | 0 | tmp.m[0] = scale_x; |
843 | 0 | tmp.m[4] = scale_y; |
844 | 0 | gf_mx2d_add_matrix(_this, &tmp); |
845 | |
|
846 | 0 | CHECK_MATRIX |
847 | 0 | } |
848 | | |
849 | | GF_EXPORT |
850 | | void gf_mx2d_add_scale_at(GF_Matrix2D *_this, Fixed scale_x, Fixed scale_y, Fixed cx, Fixed cy, Fixed angle) |
851 | 0 | { |
852 | 0 | GF_Matrix2D tmp; |
853 | 0 | if (!_this) return; |
854 | 0 | gf_mx2d_init(tmp); |
855 | 0 | if (angle) { |
856 | 0 | gf_mx2d_add_rotation(_this, cx, cy, -angle); |
857 | 0 | } |
858 | 0 | tmp.m[0] = scale_x; |
859 | 0 | tmp.m[4] = scale_y; |
860 | 0 | gf_mx2d_add_matrix(_this, &tmp); |
861 | 0 | if (angle) gf_mx2d_add_rotation(_this, cx, cy, angle); |
862 | |
|
863 | 0 | CHECK_MATRIX |
864 | 0 | } |
865 | | |
866 | | GF_EXPORT |
867 | | void gf_mx2d_add_skew(GF_Matrix2D *_this, Fixed skew_x, Fixed skew_y) |
868 | 0 | { |
869 | 0 | GF_Matrix2D tmp; |
870 | 0 | if (!_this || (!skew_x && !skew_y) ) return; |
871 | 0 | gf_mx2d_init(tmp); |
872 | 0 | tmp.m[1] = skew_x; |
873 | 0 | tmp.m[3] = skew_y; |
874 | 0 | gf_mx2d_add_matrix(_this, &tmp); |
875 | |
|
876 | 0 | CHECK_MATRIX |
877 | 0 | } |
878 | | |
879 | | GF_EXPORT |
880 | | void gf_mx2d_add_skew_x(GF_Matrix2D *_this, Fixed angle) |
881 | 0 | { |
882 | 0 | GF_Matrix2D tmp; |
883 | 0 | if (!_this) return; |
884 | 0 | gf_mx2d_init(tmp); |
885 | 0 | tmp.m[1] = gf_tan(angle); |
886 | 0 | tmp.m[3] = 0; |
887 | 0 | gf_mx2d_add_matrix(_this, &tmp); |
888 | |
|
889 | 0 | CHECK_MATRIX |
890 | 0 | } |
891 | | |
892 | | GF_EXPORT |
893 | | void gf_mx2d_add_skew_y(GF_Matrix2D *_this, Fixed angle) |
894 | 0 | { |
895 | 0 | GF_Matrix2D tmp; |
896 | 0 | if (!_this) return; |
897 | 0 | gf_mx2d_init(tmp); |
898 | 0 | tmp.m[1] = 0; |
899 | 0 | tmp.m[3] = gf_tan(angle); |
900 | 0 | gf_mx2d_add_matrix(_this, &tmp); |
901 | |
|
902 | 0 | CHECK_MATRIX |
903 | 0 | } |
904 | | |
905 | | |
906 | | GF_EXPORT |
907 | | void gf_mx2d_inverse(GF_Matrix2D *_this) |
908 | 0 | { |
909 | | #ifdef GPAC_FIXED_POINT |
910 | | Float _det, _max; |
911 | | s32 sign, scale; |
912 | | #endif |
913 | 0 | Fixed det; |
914 | 0 | GF_Matrix2D tmp; |
915 | 0 | if(!_this) return; |
916 | 0 | if (gf_mx2d_is_identity(*_this)) return; |
917 | | |
918 | | #ifdef GPAC_FIXED_POINT |
919 | | /*we must compute the determinent as a float to avoid fixed-point overflow*/ |
920 | | _det = FIX2FLT(_this->m[0])*FIX2FLT(_this->m[4]) - FIX2FLT(_this->m[1])*FIX2FLT(_this->m[3]); |
921 | | if (!_det) { |
922 | | gf_mx2d_init(*_this); |
923 | | return; |
924 | | } |
925 | | sign = _det<0 ? -1 : 1; |
926 | | _det *= sign; |
927 | | scale = 1; |
928 | | _max = FIX2FLT(FIX_MAX); |
929 | | while (_det / scale > _max) { |
930 | | scale *= 10; |
931 | | } |
932 | | det = sign * FLT2FIX(_det/scale); |
933 | | #else |
934 | 0 | det = gf_mulfix(_this->m[0], _this->m[4]) - gf_mulfix(_this->m[1], _this->m[3]); |
935 | 0 | if (!det) { |
936 | 0 | gf_mx2d_init(*_this); |
937 | 0 | return; |
938 | 0 | } |
939 | 0 | #endif |
940 | | |
941 | 0 | tmp.m[0] = gf_divfix(_this->m[4], det); |
942 | 0 | tmp.m[1] = -1 * gf_divfix(_this->m[1], det); |
943 | 0 | tmp.m[2] = gf_mulfix(gf_divfix(_this->m[1], det), _this->m[5]) - gf_mulfix(gf_divfix(_this->m[4], det), _this->m[2]); |
944 | |
|
945 | 0 | tmp.m[3] = -1 * gf_divfix(_this->m[3], det); |
946 | 0 | tmp.m[4] = gf_divfix(_this->m[0], det); |
947 | 0 | tmp.m[5] = gf_mulfix( gf_divfix(_this->m[3], det), _this->m[2]) - gf_mulfix( gf_divfix(_this->m[5], det), _this->m[0]); |
948 | |
|
949 | | #ifdef GPAC_FIXED_POINT |
950 | | if (scale>1) { |
951 | | tmp.m[0] /= scale; |
952 | | tmp.m[1] /= scale; |
953 | | tmp.m[2] /= scale; |
954 | | tmp.m[3] /= scale; |
955 | | tmp.m[4] /= scale; |
956 | | tmp.m[5] /= scale; |
957 | | } |
958 | | #endif |
959 | |
|
960 | 0 | gf_mx2d_copy(*_this, tmp); |
961 | |
|
962 | 0 | CHECK_MATRIX |
963 | 0 | } |
964 | | |
965 | | #endif |
966 | | |
967 | | GF_EXPORT |
968 | | Bool gf_mx2d_decompose(GF_Matrix2D *mx, GF_Point2D *scale, Fixed *rotate, GF_Point2D *translate) |
969 | 7.24k | { |
970 | 7.24k | Fixed det, angle; |
971 | 7.24k | Fixed tmp[6]; |
972 | 7.24k | if(!mx) return GF_FALSE; |
973 | | |
974 | 7.24k | memcpy(tmp, mx->m, sizeof(Fixed)*6); |
975 | 7.24k | translate->x = tmp[2]; |
976 | 7.24k | translate->y = tmp[5]; |
977 | | |
978 | | /*check ac+bd=0*/ |
979 | 7.24k | det = gf_mulfix(tmp[0], tmp[3]) + gf_mulfix(tmp[1], tmp[4]); |
980 | 7.24k | if (ABS(det) > FIX_EPSILON) { |
981 | 3.57k | scale->x = scale->y = 0; |
982 | 3.57k | *rotate = 0; |
983 | 3.57k | return GF_FALSE; |
984 | 3.57k | } |
985 | 3.67k | angle = gf_atan2(tmp[3], tmp[4]); |
986 | 3.67k | if (angle < FIX_EPSILON) { |
987 | 2.25k | scale->x = tmp[0]; |
988 | 2.25k | scale->y = tmp[4]; |
989 | 2.25k | } else { |
990 | 1.42k | det = gf_cos(angle); |
991 | 1.42k | scale->x = gf_divfix(tmp[0], det); |
992 | 1.42k | scale->y = gf_divfix(tmp[4], det); |
993 | 1.42k | } |
994 | 3.67k | *rotate = angle; |
995 | 3.67k | return GF_TRUE; |
996 | 7.24k | } |
997 | | |
998 | | #ifdef DISABLE_MATHS |
999 | | |
1000 | | GF_EXPORT |
1001 | | void gf_mx2d_apply_coords(GF_Matrix2D *_this, Fixed *x, Fixed *y) |
1002 | 0 | { |
1003 | 0 | Fixed _x, _y; |
1004 | 0 | if (!_this || !x || !y) return; |
1005 | 0 | _x = gf_mulfix(*x, _this->m[0]) + gf_mulfix(*y, _this->m[1]) + _this->m[2]; |
1006 | 0 | _y = gf_mulfix(*x, _this->m[3]) + gf_mulfix(*y, _this->m[4]) + _this->m[5]; |
1007 | 0 | *x = _x; |
1008 | 0 | *y = _y; |
1009 | 0 | } |
1010 | | |
1011 | | GF_EXPORT |
1012 | | void gf_mx2d_apply_point(GF_Matrix2D *_this, GF_Point2D *pt) |
1013 | 0 | { |
1014 | 0 | gf_mx2d_apply_coords(_this, &pt->x, &pt->y); |
1015 | 0 | } |
1016 | | |
1017 | | GF_EXPORT |
1018 | | void gf_mx2d_apply_rect(GF_Matrix2D *_this, GF_Rect *rc) |
1019 | 0 | { |
1020 | |
|
1021 | 0 | GF_Point2D c1, c2, c3, c4; |
1022 | 0 | c1.x = c2.x = rc->x; |
1023 | 0 | c3.x = c4.x = rc->x + rc->width; |
1024 | 0 | c1.y = c3.y = rc->y; |
1025 | 0 | c2.y = c4.y = rc->y - rc->height; |
1026 | 0 | gf_mx2d_apply_point(_this, &c1); |
1027 | 0 | gf_mx2d_apply_point(_this, &c2); |
1028 | 0 | gf_mx2d_apply_point(_this, &c3); |
1029 | 0 | gf_mx2d_apply_point(_this, &c4); |
1030 | 0 | rc->x = MIN(c1.x, MIN(c2.x, MIN(c3.x, c4.x))); |
1031 | 0 | rc->width = MAX(c1.x, MAX(c2.x, MAX(c3.x, c4.x))) - rc->x; |
1032 | 0 | rc->height = MIN(c1.y, MIN(c2.y, MIN(c3.y, c4.y))); |
1033 | 0 | rc->y = MAX(c1.y, MAX(c2.y, MAX(c3.y, c4.y))); |
1034 | 0 | rc->height = rc->y - rc->height; |
1035 | | // gf_assert(rc->height>=0); |
1036 | | // gf_assert(rc->width>=0); |
1037 | 0 | } |
1038 | | |
1039 | | /* |
1040 | | RECTANGLE TOOLS |
1041 | | */ |
1042 | | |
1043 | | /*transform rect to smallest covering integer pixels rect - this is needed to make sure clearing |
1044 | | of screen is correctly handled, otherwise we have troubles with bitmap hardware blitting (always integer)*/ |
1045 | | GF_EXPORT |
1046 | | GF_IRect gf_rect_pixelize(GF_Rect *r) |
1047 | 0 | { |
1048 | 0 | GF_IRect rc; |
1049 | 0 | rc.x = FIX2INT(gf_floor(r->x)); |
1050 | 0 | rc.y = FIX2INT(gf_ceil(r->y)); |
1051 | 0 | rc.width = FIX2INT(gf_ceil(r->x + r->width)) - rc.x; |
1052 | 0 | rc.height = rc.y - FIX2INT(gf_floor(r->y - r->height)); |
1053 | 0 | return rc; |
1054 | 0 | } |
1055 | | |
1056 | | #endif |
1057 | | |
1058 | | /*adds @rc2 to @rc1 - the new @rc1 contains the old @rc1 and @rc2*/ |
1059 | | GF_EXPORT |
1060 | | void gf_rect_union(GF_Rect *rc1, GF_Rect *rc2) |
1061 | 0 | { |
1062 | 0 | if (!rc1->width || !rc1->height) { |
1063 | 0 | *rc1=*rc2; |
1064 | 0 | return; |
1065 | 0 | } |
1066 | 0 | if (!rc2->width || !rc2->height) return; |
1067 | 0 | if (rc2->x < rc1->x) { |
1068 | 0 | rc1->width += rc1->x - rc2->x; |
1069 | 0 | rc1->x = rc2->x; |
1070 | 0 | } |
1071 | 0 | if (rc2->x + rc2->width > rc1->x+rc1->width) rc1->width = rc2->x + rc2->width - rc1->x; |
1072 | 0 | if (rc2->y > rc1->y) { |
1073 | 0 | rc1->height += rc2->y - rc1->y; |
1074 | 0 | rc1->y = rc2->y; |
1075 | 0 | } |
1076 | 0 | if (rc2->y - rc2->height < rc1->y - rc1->height) rc1->height = rc1->y - rc2->y + rc2->height; |
1077 | 0 | } |
1078 | | |
1079 | | #ifdef DISABLE_MATHS |
1080 | | |
1081 | | GF_EXPORT |
1082 | | GF_Rect gf_rect_center(Fixed w, Fixed h) |
1083 | 0 | { |
1084 | 0 | GF_Rect rc; |
1085 | 0 | rc.x=-w/2; |
1086 | 0 | rc.y=h/2; |
1087 | 0 | rc.width=w; |
1088 | 0 | rc.height=h; |
1089 | 0 | return rc; |
1090 | 0 | } |
1091 | | #endif |
1092 | | |
1093 | | GF_EXPORT |
1094 | | Bool gf_rect_overlaps(GF_Rect rc1, GF_Rect rc2) |
1095 | 0 | { |
1096 | 0 | if (! rc2.height || !rc2.width || !rc1.height || !rc1.width) return GF_FALSE; |
1097 | 0 | if (rc2.x+rc2.width<=rc1.x) return GF_FALSE; |
1098 | 0 | if (rc2.x>=rc1.x+rc1.width) return GF_FALSE; |
1099 | 0 | if (rc2.y-rc2.height>=rc1.y) return GF_FALSE; |
1100 | 0 | if (rc2.y<=rc1.y-rc1.height) return GF_FALSE; |
1101 | 0 | return GF_TRUE; |
1102 | 0 | } |
1103 | | |
1104 | | GF_EXPORT |
1105 | | Bool gf_rect_equal(GF_Rect *rc1, GF_Rect *rc2) |
1106 | 0 | { |
1107 | 0 | if ( (rc1->x == rc2->x) && (rc1->y == rc2->y) && (rc1->width == rc2->width) && (rc1->height == rc2->height) ) |
1108 | 0 | return GF_TRUE; |
1109 | 0 | return GF_FALSE; |
1110 | 0 | } |
1111 | | |
1112 | | GF_EXPORT |
1113 | | void gf_rect_intersect(GF_Rect *rc1, GF_Rect *rc2) |
1114 | 0 | { |
1115 | 0 | if (! gf_rect_overlaps(*rc1, *rc2)) { |
1116 | 0 | rc1->width = rc1->height = 0; |
1117 | 0 | return; |
1118 | 0 | } |
1119 | 0 | if (rc2->x > rc1->x) { |
1120 | 0 | rc1->width -= rc2->x - rc1->x; |
1121 | 0 | rc1->x = rc2->x; |
1122 | 0 | } |
1123 | 0 | if (rc2->x + rc2->width < rc1->x + rc1->width) { |
1124 | 0 | rc1->width = rc2->width + rc2->x - rc1->x; |
1125 | 0 | } |
1126 | 0 | if (rc2->y < rc1->y) { |
1127 | 0 | rc1->height -= rc1->y - rc2->y; |
1128 | 0 | rc1->y = rc2->y; |
1129 | 0 | } |
1130 | 0 | if (rc2->y - rc2->height > rc1->y - rc1->height) { |
1131 | 0 | rc1->height = rc1->y - rc2->y + rc2->height; |
1132 | 0 | } |
1133 | 0 | } |
1134 | | |
1135 | | |
1136 | | #ifdef DISABLE_MATHS |
1137 | | |
1138 | | #ifdef GPAC_FIXED_POINT |
1139 | | |
1140 | | /* check if dimension is larger than FIX_ONE*/ |
1141 | | #define IS_HIGH_DIM(_v) ((_v > FIX_ONE) || (_v < (s32)0xFFFF0000)) |
1142 | | /* check if any vector dimension is larger than FIX_ONE*/ |
1143 | | #define VEC_HIGH_MAG(_v) (IS_HIGH_DIM(_v->x) || IS_HIGH_DIM(_v->y) || IS_HIGH_DIM(_v->z) ) |
1144 | | |
1145 | | //#define FLOAT_COMPUTE |
1146 | | |
1147 | | GF_EXPORT |
1148 | | Fixed gf_vec_len_p(GF_Vec *v) |
1149 | | { |
1150 | | /*commented out atm - weird results (not enough precision?)...*/ |
1151 | | //#if defined(GPAC_USE_IGPP_HP) || defined (GPAC_USE_IGPP) |
1152 | | #if 0 |
1153 | | Fixed res; |
1154 | | gppVec3DLength_16_32s((GPP_VEC3D *) v, &res); |
1155 | | return res; |
1156 | | #elif defined(FLOAT_COMPUTE) |
1157 | | return FLT2FIX( sqrt( FIX2FLT(v->x) * FIX2FLT(v->x) + FIX2FLT(v->y)*FIX2FLT(v->y) + FIX2FLT(v->z)*FIX2FLT(v->z) ) ); |
1158 | | #else |
1159 | | |
1160 | | /*high-magnitude vector, use low precision on frac part to avoid overflow*/ |
1161 | | if (VEC_HIGH_MAG(v)) { |
1162 | | GF_Vec _v = *v; |
1163 | | _v.x>>=8; |
1164 | | _v.y>>=8; |
1165 | | _v.z>>=8; |
1166 | | return gf_sqrt( gf_mulfix(_v.x, _v.x) + gf_mulfix(_v.y, _v.y) + gf_mulfix(_v.z, _v.z) ) << 8; |
1167 | | } |
1168 | | /*low-res vector*/ |
1169 | | return gf_sqrt( gf_mulfix(v->x, v->x) + gf_mulfix(v->y, v->y) + gf_mulfix(v->z, v->z) ); |
1170 | | #endif |
1171 | | } |
1172 | | |
1173 | | GF_EXPORT |
1174 | | Fixed gf_vec_len(GF_Vec v) |
1175 | | { |
1176 | | return gf_vec_len_p(&v); |
1177 | | |
1178 | | } |
1179 | | GF_EXPORT |
1180 | | Fixed gf_vec_lensq_p(GF_Vec *v) |
1181 | | { |
1182 | | /*commented out atm - weird results (not enough precision?)...*/ |
1183 | | //#if defined(GPAC_USE_IGPP_HP) || defined (GPAC_USE_IGPP) |
1184 | | #if 0 |
1185 | | Fixed res; |
1186 | | gppVec3DLengthSq_16_32s((GPP_VEC3D *) v, &res); |
1187 | | return res; |
1188 | | #elif defined(FLOAT_COMPUTE) |
1189 | | return FLT2FIX( FIX2FLT(v->x) * FIX2FLT(v->x) + FIX2FLT(v->y)*FIX2FLT(v->y) + FIX2FLT(v->z)*FIX2FLT(v->z) ); |
1190 | | #else |
1191 | | |
1192 | | /*high-magnitude vector, use low precision on frac part to avoid overflow*/ |
1193 | | if (VEC_HIGH_MAG(v)) { |
1194 | | GF_Vec _v = *v; |
1195 | | _v.x>>=8; |
1196 | | _v.y>>=8; |
1197 | | _v.z>>=8; |
1198 | | return ( gf_mulfix(_v.x, _v.x) + gf_mulfix(_v.y, _v.y) + gf_mulfix(_v.z, _v.z) ) << 16; |
1199 | | } |
1200 | | return gf_mulfix(v->x, v->x) + gf_mulfix(v->y, v->y) + gf_mulfix(v->z, v->z); |
1201 | | |
1202 | | #endif |
1203 | | } |
1204 | | |
1205 | | GF_EXPORT |
1206 | | Fixed gf_vec_lensq(GF_Vec v) |
1207 | | { |
1208 | | return gf_vec_lensq_p(&v); |
1209 | | |
1210 | | } |
1211 | | |
1212 | | GF_EXPORT |
1213 | | Fixed gf_vec_dot_p(GF_Vec *v1, GF_Vec *v2) |
1214 | | { |
1215 | | /*commented out atm - weird results (not enough precision?)...*/ |
1216 | | //#if defined(GPAC_USE_IGPP_HP) || defined (GPAC_USE_IGPP) |
1217 | | #if 0 |
1218 | | Fixed res; |
1219 | | gppVec3DDot_16_32s((GPP_VEC3D *) v1, (GPP_VEC3D *) v2, &res); |
1220 | | return res; |
1221 | | #elif defined(FLOAT_COMPUTE) |
1222 | | Float fr = FIX2FLT(v1->x)*FIX2FLT(v2->x) + FIX2FLT(v1->y)*FIX2FLT(v2->y) + FIX2FLT(v1->z)*FIX2FLT(v2->z); |
1223 | | return FLT2FIX(fr); |
1224 | | #else |
1225 | | /*both high-magnitude vectors, use low precision on frac part to avoid overflow |
1226 | | if only one is, the dot product should still be in proper range*/ |
1227 | | if (0&&VEC_HIGH_MAG(v1) && VEC_HIGH_MAG(v2)) { |
1228 | | GF_Vec _v1 = *v1; |
1229 | | GF_Vec _v2 = *v2; |
1230 | | _v1.x>>=4; |
1231 | | _v1.y>>=4; |
1232 | | _v1.z>>=4; |
1233 | | _v2.x>>=4; |
1234 | | _v2.y>>=4; |
1235 | | _v2.z>>=4; |
1236 | | return ( gf_mulfix(_v1.x, _v2.x) + gf_mulfix(_v1.y, _v2.y) + gf_mulfix(_v1.z, _v2.z) ) << 8; |
1237 | | } |
1238 | | return gf_mulfix(v1->x, v2->x) + gf_mulfix(v1->y, v2->y) + gf_mulfix(v1->z, v2->z); |
1239 | | |
1240 | | #endif |
1241 | | } |
1242 | | Fixed gf_vec_dot(GF_Vec v1, GF_Vec v2) |
1243 | | { |
1244 | | return gf_vec_dot_p(&v1, &v2); |
1245 | | |
1246 | | } |
1247 | | |
1248 | | GF_EXPORT |
1249 | | void gf_vec_norm(GF_Vec *v) |
1250 | | { |
1251 | | /*commented out atm - weird results (not enough precision?)...*/ |
1252 | | //#if defined(GPAC_USE_IGPP_HP) || defined (GPAC_USE_IGPP) |
1253 | | #if 0 |
1254 | | gppVec3DNormalize_16_32s((GPP_VEC3D *) &v); |
1255 | | #else |
1256 | | Fixed __res = gf_vec_len(*v); |
1257 | | v->x = gf_divfix(v->x, __res); |
1258 | | v->y = gf_divfix(v->y, __res); |
1259 | | v->z = gf_divfix(v->z, __res); |
1260 | | #endif |
1261 | | } |
1262 | | |
1263 | | GF_EXPORT |
1264 | | GF_Vec gf_vec_scale_p(GF_Vec *v, Fixed f) |
1265 | | { |
1266 | | GF_Vec res; |
1267 | | res.x = gf_mulfix(v->x, f); |
1268 | | res.y = gf_mulfix(v->y, f); |
1269 | | res.z = gf_mulfix(v->z, f); |
1270 | | return res; |
1271 | | } |
1272 | | |
1273 | | GF_EXPORT |
1274 | | GF_Vec gf_vec_scale(GF_Vec v, Fixed f) |
1275 | | { |
1276 | | GF_Vec res; |
1277 | | res.x = gf_mulfix(v.x, f); |
1278 | | res.y = gf_mulfix(v.y, f); |
1279 | | res.z = gf_mulfix(v.z, f); |
1280 | | return res; |
1281 | | } |
1282 | | |
1283 | | GF_EXPORT |
1284 | | GF_Vec gf_vec_cross_p(GF_Vec *v1, GF_Vec *v2) |
1285 | | { |
1286 | | GF_Vec res; |
1287 | | /*commented out atm - weird results (not enough precision?)...*/ |
1288 | | //#if defined(GPAC_USE_IGPP_HP) || defined (GPAC_USE_IGPP) |
1289 | | #if 0 |
1290 | | gppVec3DCross_16_32s((GPP_VEC3D *) v1, (GPP_VEC3D *) v2, (GPP_VEC3D *) &res); |
1291 | | return res; |
1292 | | #elif defined(FLOAT_COMPUTE) |
1293 | | res.x = FLT2FIX( FIX2FLT(v1->y)*FIX2FLT(v2->z) - FIX2FLT(v2->y)*FIX2FLT(v1->z)); |
1294 | | res.y = FLT2FIX( FIX2FLT(v2->x)*FIX2FLT(v1->z) - FIX2FLT(v1->x)*FIX2FLT(v2->z)); |
1295 | | res.z = FLT2FIX( FIX2FLT(v1->x)*FIX2FLT(v2->y) - FIX2FLT(v2->x)*FIX2FLT(v1->y)); |
1296 | | return res; |
1297 | | #else |
1298 | | |
1299 | | /*both high-magnitude vectors, use low precision on frac part to avoid overflow |
1300 | | if only one is, the cross product should still be in proper range*/ |
1301 | | if (VEC_HIGH_MAG(v1) && VEC_HIGH_MAG(v2)) { |
1302 | | GF_Vec _v1 = *v1; |
1303 | | GF_Vec _v2 = *v2; |
1304 | | _v1.x>>=8; |
1305 | | _v1.y>>=8; |
1306 | | _v1.z>>=8; |
1307 | | _v2.x>>=8; |
1308 | | _v2.y>>=8; |
1309 | | _v2.z>>=8; |
1310 | | res.x = gf_mulfix(_v1.y, _v2.z) - gf_mulfix(_v2.y, _v1.z); |
1311 | | res.y = gf_mulfix(_v2.x, _v1.z) - gf_mulfix(_v1.x, _v2.z); |
1312 | | res.z = gf_mulfix(_v1.x, _v2.y) - gf_mulfix(_v2.x, _v1.y); |
1313 | | res.x<<=16; |
1314 | | res.y<<=16; |
1315 | | res.z<<=16; |
1316 | | return res; |
1317 | | } |
1318 | | res.x = gf_mulfix(v1->y, v2->z) - gf_mulfix(v2->y, v1->z); |
1319 | | res.y = gf_mulfix(v2->x, v1->z) - gf_mulfix(v1->x, v2->z); |
1320 | | res.z = gf_mulfix(v1->x, v2->y) - gf_mulfix(v2->x, v1->y); |
1321 | | |
1322 | | #endif |
1323 | | return res; |
1324 | | } |
1325 | | |
1326 | | GF_EXPORT |
1327 | | GF_Vec gf_vec_cross(GF_Vec v1, GF_Vec v2) |
1328 | | { |
1329 | | return gf_vec_cross_p(&v1, &v2); |
1330 | | |
1331 | | } |
1332 | | #else |
1333 | | |
1334 | | GF_EXPORT |
1335 | 0 | Fixed gf_vec_len_p(GF_Vec *v) { |
1336 | 0 | return gf_sqrt(v->x*v->x + v->y*v->y + v->z*v->z); |
1337 | 0 | } |
1338 | | GF_EXPORT |
1339 | 0 | Fixed gf_vec_len(GF_Vec v) { |
1340 | 0 | return gf_vec_len_p(&v); |
1341 | 0 | } |
1342 | | GF_EXPORT |
1343 | 0 | Fixed gf_vec_lensq_p(GF_Vec *v) { |
1344 | 0 | return v->x*v->x + v->y*v->y + v->z*v->z; |
1345 | 0 | } |
1346 | | GF_EXPORT |
1347 | 0 | Fixed gf_vec_lensq(GF_Vec v) { |
1348 | 0 | return gf_vec_lensq_p(&v); |
1349 | 0 | } |
1350 | | GF_EXPORT |
1351 | 0 | Fixed gf_vec_dot_p(GF_Vec *v1, GF_Vec *v2) { |
1352 | 0 | return v1->x*v2->x + v1->y*v2->y + v1->z*v2->z; |
1353 | 0 | } |
1354 | | GF_EXPORT |
1355 | 0 | Fixed gf_vec_dot(GF_Vec v1, GF_Vec v2) { |
1356 | 0 | return gf_vec_dot_p(&v1, &v2); |
1357 | 0 | } |
1358 | | GF_EXPORT |
1359 | | void gf_vec_norm(GF_Vec *v) |
1360 | 0 | { |
1361 | 0 | Fixed __res = gf_vec_len(*v); |
1362 | 0 | if (!__res ) return; |
1363 | 0 | if (__res == FIX_ONE) return; |
1364 | 0 | __res = 1.0f/__res; |
1365 | 0 | v->x *= __res; |
1366 | 0 | v->y *= __res; |
1367 | 0 | v->z *= __res; |
1368 | 0 | } |
1369 | | |
1370 | | GF_EXPORT |
1371 | | GF_Vec gf_vec_scale_p(GF_Vec *v, Fixed f) |
1372 | 0 | { |
1373 | 0 | GF_Vec res; |
1374 | 0 | res.x = v->x * f; |
1375 | 0 | res.y = v->y * f; |
1376 | 0 | res.z = v->z * f; |
1377 | 0 | return res; |
1378 | 0 | } |
1379 | | |
1380 | | GF_EXPORT |
1381 | | GF_Vec gf_vec_scale(GF_Vec v, Fixed f) |
1382 | 0 | { |
1383 | 0 | GF_Vec res = v; |
1384 | 0 | res.x *= f; |
1385 | 0 | res.y *= f; |
1386 | 0 | res.z *= f; |
1387 | 0 | return res; |
1388 | 0 | } |
1389 | | |
1390 | | GF_EXPORT |
1391 | | GF_Vec gf_vec_cross_p(GF_Vec *v1, GF_Vec *v2) |
1392 | 0 | { |
1393 | 0 | GF_Vec res; |
1394 | 0 | res.x = v1->y*v2->z - v2->y*v1->z; |
1395 | 0 | res.y = v2->x*v1->z - v1->x*v2->z; |
1396 | 0 | res.z = v1->x*v2->y - v2->x*v1->y; |
1397 | 0 | return res; |
1398 | 0 | } |
1399 | | |
1400 | | GF_EXPORT |
1401 | | GF_Vec gf_vec_cross(GF_Vec v1, GF_Vec v2) |
1402 | 0 | { |
1403 | 0 | return gf_vec_cross_p(&v1, &v2); |
1404 | 0 | } |
1405 | | #endif |
1406 | | |
1407 | | |
1408 | | GF_EXPORT |
1409 | | void gf_mx2d_from_mx(GF_Matrix2D *mat2D, GF_Matrix *mat) |
1410 | 0 | { |
1411 | 0 | gf_mx2d_init(*mat2D); |
1412 | 0 | mat2D->m[0] = mat->m[0]; |
1413 | 0 | mat2D->m[1] = mat->m[4]; |
1414 | 0 | mat2D->m[2] = mat->m[12]; |
1415 | 0 | mat2D->m[3] = mat->m[1]; |
1416 | 0 | mat2D->m[4] = mat->m[5]; |
1417 | 0 | mat2D->m[5] = mat->m[13]; |
1418 | 0 | } |
1419 | | |
1420 | | GF_EXPORT |
1421 | | void gf_mx_apply_rect(GF_Matrix *mat, GF_Rect *rc) |
1422 | 0 | { |
1423 | 0 | GF_Matrix2D mat2D; |
1424 | 0 | gf_mx2d_from_mx(&mat2D, mat); |
1425 | 0 | gf_mx2d_apply_rect(&mat2D, rc); |
1426 | 0 | } |
1427 | | |
1428 | | GF_EXPORT |
1429 | | void gf_mx_add_matrix(GF_Matrix *mat, GF_Matrix *mul) |
1430 | 0 | { |
1431 | 0 | GF_Matrix tmp; |
1432 | 0 | gf_mx_init(tmp); |
1433 | |
|
1434 | 0 | tmp.m[0] = gf_mulfix(mat->m[0],mul->m[0]) + gf_mulfix(mat->m[4],mul->m[1]) + gf_mulfix(mat->m[8],mul->m[2]); |
1435 | 0 | tmp.m[4] = gf_mulfix(mat->m[0],mul->m[4]) + gf_mulfix(mat->m[4],mul->m[5]) + gf_mulfix(mat->m[8],mul->m[6]); |
1436 | 0 | tmp.m[8] = gf_mulfix(mat->m[0],mul->m[8]) + gf_mulfix(mat->m[4],mul->m[9]) + gf_mulfix(mat->m[8],mul->m[10]); |
1437 | 0 | tmp.m[12]= gf_mulfix(mat->m[0],mul->m[12]) + gf_mulfix(mat->m[4],mul->m[13]) + gf_mulfix(mat->m[8],mul->m[14]) + mat->m[12]; |
1438 | 0 | tmp.m[1] = gf_mulfix(mat->m[1],mul->m[0]) + gf_mulfix(mat->m[5],mul->m[1]) + gf_mulfix(mat->m[9],mul->m[2]); |
1439 | 0 | tmp.m[5] = gf_mulfix(mat->m[1],mul->m[4]) + gf_mulfix(mat->m[5],mul->m[5]) + gf_mulfix(mat->m[9],mul->m[6]); |
1440 | 0 | tmp.m[9] = gf_mulfix(mat->m[1],mul->m[8]) + gf_mulfix(mat->m[5],mul->m[9]) + gf_mulfix(mat->m[9],mul->m[10]); |
1441 | 0 | tmp.m[13]= gf_mulfix(mat->m[1],mul->m[12]) + gf_mulfix(mat->m[5],mul->m[13]) + gf_mulfix(mat->m[9],mul->m[14]) + mat->m[13]; |
1442 | 0 | tmp.m[2] = gf_mulfix(mat->m[2],mul->m[0]) + gf_mulfix(mat->m[6],mul->m[1]) + gf_mulfix(mat->m[10],mul->m[2]); |
1443 | 0 | tmp.m[6] = gf_mulfix(mat->m[2],mul->m[4]) + gf_mulfix(mat->m[6],mul->m[5]) + gf_mulfix(mat->m[10],mul->m[6]); |
1444 | 0 | tmp.m[10]= gf_mulfix(mat->m[2],mul->m[8]) + gf_mulfix(mat->m[6],mul->m[9]) + gf_mulfix(mat->m[10],mul->m[10]); |
1445 | 0 | tmp.m[14]= gf_mulfix(mat->m[2],mul->m[12]) + gf_mulfix(mat->m[6],mul->m[13]) + gf_mulfix(mat->m[10],mul->m[14]) + mat->m[14]; |
1446 | 0 | memcpy(mat->m, tmp.m, sizeof(Fixed)*16); |
1447 | 0 | } |
1448 | | |
1449 | | GF_EXPORT |
1450 | | void gf_mx_add_matrix_2d(GF_Matrix *mat, GF_Matrix2D *mat2D) |
1451 | 0 | { |
1452 | 0 | GF_Matrix tmp; |
1453 | 0 | gf_mx_init(tmp); |
1454 | |
|
1455 | 0 | tmp.m[0] = gf_mulfix(mat->m[0],mat2D->m[0]) + gf_mulfix(mat->m[4],mat2D->m[3]); |
1456 | 0 | tmp.m[4] = gf_mulfix(mat->m[0],mat2D->m[1]) + gf_mulfix(mat->m[4],mat2D->m[4]); |
1457 | 0 | tmp.m[8] = mat->m[8]; |
1458 | 0 | tmp.m[12]= gf_mulfix(mat->m[0],mat2D->m[2]) + gf_mulfix(mat->m[4],mat2D->m[5]) + mat->m[12]; |
1459 | 0 | tmp.m[1] = gf_mulfix(mat->m[1],mat2D->m[0]) + gf_mulfix(mat->m[5],mat2D->m[3]); |
1460 | 0 | tmp.m[5] = gf_mulfix(mat->m[1],mat2D->m[1]) + gf_mulfix(mat->m[5],mat2D->m[4]); |
1461 | 0 | tmp.m[9] = mat->m[9]; |
1462 | 0 | tmp.m[13]= gf_mulfix(mat->m[1],mat2D->m[2]) + gf_mulfix(mat->m[5],mat2D->m[5]) + mat->m[13]; |
1463 | 0 | tmp.m[2] = gf_mulfix(mat->m[2],mat2D->m[0]) + gf_mulfix(mat->m[6],mat2D->m[3]); |
1464 | 0 | tmp.m[6] = gf_mulfix(mat->m[2],mat2D->m[1]) + gf_mulfix(mat->m[6],mat2D->m[4]); |
1465 | 0 | tmp.m[10]= mat->m[10]; |
1466 | 0 | tmp.m[14]= gf_mulfix(mat->m[2],mat2D->m[2]) + gf_mulfix(mat->m[6],mat2D->m[5]) + mat->m[14]; |
1467 | 0 | memcpy(mat->m, tmp.m, sizeof(Fixed)*16); |
1468 | 0 | } |
1469 | | |
1470 | | |
1471 | | |
1472 | | GF_EXPORT |
1473 | | void gf_mx_add_translation(GF_Matrix *mat, Fixed tx, Fixed ty, Fixed tz) |
1474 | 0 | { |
1475 | 0 | Fixed tmp[3]; |
1476 | 0 | u32 i; |
1477 | 0 | tmp[0] = mat->m[12]; |
1478 | 0 | tmp[1] = mat->m[13]; |
1479 | 0 | tmp[2] = mat->m[14]; |
1480 | 0 | for (i=0; i<3; i++) |
1481 | 0 | tmp[i] += (gf_mulfix(tx,mat->m[i]) + gf_mulfix(ty,mat->m[i+4]) + gf_mulfix(tz, mat->m[i + 8])); |
1482 | 0 | mat->m[12] = tmp[0]; |
1483 | 0 | mat->m[13] = tmp[1]; |
1484 | 0 | mat->m[14] = tmp[2]; |
1485 | 0 | } |
1486 | | |
1487 | | GF_EXPORT |
1488 | | void gf_mx_add_scale(GF_Matrix *mat, Fixed sx, Fixed sy, Fixed sz) |
1489 | 0 | { |
1490 | 0 | Fixed tmp[3]; |
1491 | 0 | u32 i, j; |
1492 | |
|
1493 | 0 | tmp[0] = sx; |
1494 | 0 | tmp[1] = sy; |
1495 | 0 | tmp[2] = sz; |
1496 | |
|
1497 | 0 | for (i=0; i<3; i++) { |
1498 | 0 | for (j=0; j<3; j++) { |
1499 | 0 | mat->m[i*4 + j] = gf_mulfix(mat->m[j+4 * i], tmp[i]); |
1500 | 0 | } |
1501 | 0 | } |
1502 | 0 | } |
1503 | | |
1504 | | GF_EXPORT |
1505 | | void gf_mx_add_rotation(GF_Matrix *mat, Fixed angle, Fixed x, Fixed y, Fixed z) |
1506 | 0 | { |
1507 | 0 | GF_Matrix tmp; |
1508 | 0 | Fixed xx, yy, zz, xy, xz, yz; |
1509 | 0 | Fixed nor = gf_sqrt(gf_mulfix(x,x) + gf_mulfix(y,y) + gf_mulfix(z,z)); |
1510 | 0 | Fixed cos_a = gf_cos(angle); |
1511 | 0 | Fixed sin_a = gf_sin(angle); |
1512 | 0 | Fixed icos_a = FIX_ONE - cos_a; |
1513 | |
|
1514 | 0 | if (nor && (nor!=FIX_ONE)) { |
1515 | 0 | x = gf_divfix(x, nor); |
1516 | 0 | y = gf_divfix(y, nor); |
1517 | 0 | z = gf_divfix(z, nor); |
1518 | 0 | } |
1519 | 0 | xx = gf_mulfix(x,x); |
1520 | 0 | yy = gf_mulfix(y,y); |
1521 | 0 | zz = gf_mulfix(z,z); |
1522 | 0 | xy = gf_mulfix(x,y); |
1523 | 0 | xz = gf_mulfix(x,z); |
1524 | 0 | yz = gf_mulfix(y,z); |
1525 | 0 | gf_mx_init(tmp); |
1526 | 0 | tmp.m[0] = gf_mulfix(icos_a,xx) + cos_a; |
1527 | 0 | tmp.m[1] = gf_mulfix(xy,icos_a) + gf_mulfix(z,sin_a); |
1528 | 0 | tmp.m[2] = gf_mulfix(xz,icos_a) - gf_mulfix(y,sin_a); |
1529 | |
|
1530 | 0 | tmp.m[4] = gf_mulfix(xy,icos_a) - gf_mulfix(z,sin_a); |
1531 | 0 | tmp.m[5] = gf_mulfix(icos_a,yy) + cos_a; |
1532 | 0 | tmp.m[6] = gf_mulfix(yz,icos_a) + gf_mulfix(x,sin_a); |
1533 | |
|
1534 | 0 | tmp.m[8] = gf_mulfix(xz,icos_a) + gf_mulfix(y,sin_a); |
1535 | 0 | tmp.m[9] = gf_mulfix(yz,icos_a) - gf_mulfix(x,sin_a); |
1536 | 0 | tmp.m[10]= gf_mulfix(icos_a,zz) + cos_a; |
1537 | |
|
1538 | 0 | gf_mx_add_matrix(mat, &tmp); |
1539 | 0 | } |
1540 | | |
1541 | | GF_EXPORT |
1542 | | void gf_mx_from_mx2d(GF_Matrix *mat, GF_Matrix2D *mat2D) |
1543 | 0 | { |
1544 | 0 | gf_mx_init(*mat); |
1545 | 0 | mat->m[0] = mat2D->m[0]; |
1546 | 0 | mat->m[4] = mat2D->m[1]; |
1547 | 0 | mat->m[12] = mat2D->m[2]; |
1548 | 0 | mat->m[1] = mat2D->m[3]; |
1549 | 0 | mat->m[5] = mat2D->m[4]; |
1550 | 0 | mat->m[13] = mat2D->m[5]; |
1551 | 0 | } |
1552 | | |
1553 | | GF_EXPORT |
1554 | | Bool gf_mx_equal(GF_Matrix *mx1, GF_Matrix *mx2) |
1555 | 0 | { |
1556 | 0 | if (mx1->m[0] != mx2->m[0]) return GF_FALSE; |
1557 | 0 | if (mx1->m[1] != mx2->m[1]) return GF_FALSE; |
1558 | 0 | if (mx1->m[2] != mx2->m[2]) return GF_FALSE; |
1559 | 0 | if (mx1->m[4] != mx2->m[4]) return GF_FALSE; |
1560 | 0 | if (mx1->m[5] != mx2->m[5]) return GF_FALSE; |
1561 | 0 | if (mx1->m[6] != mx2->m[6]) return GF_FALSE; |
1562 | 0 | if (mx1->m[8] != mx2->m[8]) return GF_FALSE; |
1563 | 0 | if (mx1->m[9] != mx2->m[9]) return GF_FALSE; |
1564 | 0 | if (mx1->m[10] != mx2->m[10]) return GF_FALSE; |
1565 | 0 | if (mx1->m[12] != mx2->m[12]) return GF_FALSE; |
1566 | 0 | if (mx1->m[13] != mx2->m[13]) return GF_FALSE; |
1567 | 0 | if (mx1->m[14] != mx2->m[14]) return GF_FALSE; |
1568 | 0 | return GF_TRUE; |
1569 | 0 | } |
1570 | | |
1571 | | |
1572 | | GF_EXPORT |
1573 | | void gf_mx_inverse(GF_Matrix *mx) |
1574 | 0 | { |
1575 | | #ifdef GPAC_FIXED_POINT |
1576 | | Float _det, _max; |
1577 | | s32 sign, scale; |
1578 | | #endif |
1579 | 0 | Fixed det; |
1580 | 0 | GF_Matrix rev; |
1581 | 0 | gf_mx_init(rev); |
1582 | |
|
1583 | 0 | gf_assert(! ((mx->m[3] != 0) || (mx->m[7] != 0) || (mx->m[11] != 0) || (mx->m[15] != FIX_ONE)) ); |
1584 | | |
1585 | |
|
1586 | | #ifdef GPAC_FIXED_POINT |
1587 | | /*we must compute the determinent as a float to avoid fixed-point overflow*/ |
1588 | | _det = FIX2FLT(mx->m[0])*FIX2FLT(mx->m[5])*FIX2FLT(mx->m[10]); |
1589 | | _det += FIX2FLT(mx->m[1])*FIX2FLT(mx->m[6])*FIX2FLT(mx->m[8]); |
1590 | | _det += FIX2FLT(mx->m[2])*FIX2FLT(mx->m[4])*FIX2FLT(mx->m[9]); |
1591 | | _det -= FIX2FLT(mx->m[2])*FIX2FLT(mx->m[5])*FIX2FLT(mx->m[8]); |
1592 | | _det -= FIX2FLT(mx->m[1])*FIX2FLT(mx->m[4])*FIX2FLT(mx->m[10]); |
1593 | | _det -= FIX2FLT(mx->m[0])*FIX2FLT(mx->m[6])*FIX2FLT(mx->m[9]); |
1594 | | |
1595 | | if (!_det) { |
1596 | | gf_mx2d_init(*mx); |
1597 | | return; |
1598 | | } |
1599 | | sign = _det<0 ? -1 : 1; |
1600 | | _det *= sign; |
1601 | | scale = 1; |
1602 | | _max = FIX2FLT(FIX_MAX); |
1603 | | while (_det / scale > _max) { |
1604 | | scale *= 10; |
1605 | | } |
1606 | | det = sign * FLT2FIX(_det/scale); |
1607 | | #else |
1608 | 0 | det = gf_mulfix(gf_mulfix(mx->m[0], mx->m[5]) , mx->m[10]); |
1609 | 0 | det += gf_mulfix(gf_mulfix(mx->m[1], mx->m[6]) , mx->m[8]); |
1610 | 0 | det += gf_mulfix(gf_mulfix(mx->m[2], mx->m[4]) , mx->m[9]); |
1611 | 0 | det -= gf_mulfix(gf_mulfix(mx->m[2], mx->m[5]) , mx->m[8]); |
1612 | 0 | det -= gf_mulfix(gf_mulfix(mx->m[1], mx->m[4]) , mx->m[10]); |
1613 | 0 | det -= gf_mulfix(gf_mulfix(mx->m[0], mx->m[6]) , mx->m[9]); |
1614 | 0 | if (!det) { |
1615 | 0 | gf_mx_init(*mx); |
1616 | 0 | return; |
1617 | 0 | } |
1618 | 0 | #endif |
1619 | | |
1620 | | |
1621 | | /* Calculate inverse(A) = adj(A) / det(A) */ |
1622 | 0 | rev.m[0] = gf_muldiv(mx->m[5], mx->m[10], det) - gf_muldiv(mx->m[6], mx->m[9], det); |
1623 | 0 | rev.m[4] = -gf_muldiv(mx->m[4], mx->m[10], det) + gf_muldiv(mx->m[6], mx->m[8], det); |
1624 | 0 | rev.m[8] = gf_muldiv(mx->m[4], mx->m[9], det) - gf_muldiv(mx->m[5], mx->m[8], det); |
1625 | 0 | rev.m[1] = -gf_muldiv(mx->m[1], mx->m[10], det) + gf_muldiv(mx->m[2], mx->m[9], det); |
1626 | 0 | rev.m[5] = gf_muldiv(mx->m[0], mx->m[10], det) - gf_muldiv(mx->m[2], mx->m[8], det); |
1627 | 0 | rev.m[9] = -gf_muldiv(mx->m[0], mx->m[9], det) + gf_muldiv(mx->m[1], mx->m[8], det); |
1628 | 0 | rev.m[2] = gf_muldiv(mx->m[1], mx->m[6], det) - gf_muldiv(mx->m[2], mx->m[5], det); |
1629 | 0 | rev.m[6] = -gf_muldiv(mx->m[0], mx->m[6], det) + gf_muldiv(mx->m[2], mx->m[4], det); |
1630 | 0 | rev.m[10] = gf_muldiv(mx->m[0], mx->m[5], det) - gf_muldiv(mx->m[1], mx->m[4], det); |
1631 | |
|
1632 | | #ifdef GPAC_FIXED_POINT |
1633 | | if (scale>1) { |
1634 | | rev.m[0] /= scale; |
1635 | | rev.m[4] /= scale; |
1636 | | rev.m[8] /= scale; |
1637 | | rev.m[1] /= scale; |
1638 | | rev.m[5] /= scale; |
1639 | | rev.m[9] /= scale; |
1640 | | rev.m[2] /= scale; |
1641 | | rev.m[6] /= scale; |
1642 | | rev.m[10] /= scale; |
1643 | | } |
1644 | | #endif |
1645 | | |
1646 | | /* do translation part*/ |
1647 | 0 | rev.m[12] = -( gf_mulfix(mx->m[12], rev.m[0]) + gf_mulfix(mx->m[13], rev.m[4]) + gf_mulfix(mx->m[14], rev.m[8]) ); |
1648 | 0 | rev.m[13] = -( gf_mulfix(mx->m[12], rev.m[1]) + gf_mulfix(mx->m[13], rev.m[5]) + gf_mulfix(mx->m[14], rev.m[9]) ); |
1649 | 0 | rev.m[14] = -( gf_mulfix(mx->m[12], rev.m[2]) + gf_mulfix(mx->m[13], rev.m[6]) + gf_mulfix(mx->m[14], rev.m[10]) ); |
1650 | 0 | gf_mx_copy(*mx, rev); |
1651 | 0 | } |
1652 | | |
1653 | | GF_EXPORT |
1654 | | void gf_mx_transpose(GF_Matrix *mx) |
1655 | 0 | { |
1656 | 0 | GF_Matrix rev; |
1657 | 0 | int i,j; |
1658 | |
|
1659 | 0 | gf_mx_init(rev); |
1660 | 0 | for (i=0; i<4 ; i++) { |
1661 | 0 | for(j=0; j<4; j++) { |
1662 | 0 | rev.m[i*4+j] = mx->m[j*4+i]; |
1663 | 0 | } |
1664 | 0 | } |
1665 | | |
1666 | |
|
1667 | 0 | gf_mx_copy(*mx, rev); |
1668 | 0 | } |
1669 | | |
1670 | | |
1671 | | |
1672 | | |
1673 | | GF_EXPORT |
1674 | | void gf_mx_apply_vec(GF_Matrix *mx, GF_Vec *pt) |
1675 | 0 | { |
1676 | 0 | GF_Vec res; |
1677 | 0 | res.x = gf_mulfix(pt->x, mx->m[0]) + gf_mulfix(pt->y, mx->m[4]) + gf_mulfix(pt->z, mx->m[8]) + mx->m[12]; |
1678 | 0 | res.y = gf_mulfix(pt->x, mx->m[1]) + gf_mulfix(pt->y, mx->m[5]) + gf_mulfix(pt->z, mx->m[9]) + mx->m[13]; |
1679 | 0 | res.z = gf_mulfix(pt->x, mx->m[2]) + gf_mulfix(pt->y, mx->m[6]) + gf_mulfix(pt->z, mx->m[10]) + mx->m[14]; |
1680 | 0 | *pt = res; |
1681 | 0 | } |
1682 | | |
1683 | | GF_EXPORT |
1684 | | void gf_mx_ortho(GF_Matrix *mx, Fixed left, Fixed right, Fixed bottom, Fixed top, Fixed z_near, Fixed z_far) |
1685 | 0 | { |
1686 | 0 | gf_mx_init(*mx); |
1687 | 0 | mx->m[0] = gf_divfix(2*FIX_ONE, right-left); |
1688 | 0 | mx->m[5] = gf_divfix(2*FIX_ONE, top-bottom); |
1689 | 0 | mx->m[10] = gf_divfix(-2*FIX_ONE, z_far-z_near); |
1690 | 0 | mx->m[12] = gf_divfix(right+left, right-left); |
1691 | 0 | mx->m[13] = gf_divfix(top+bottom, top-bottom); |
1692 | 0 | mx->m[14] = gf_divfix(z_far+z_near, z_far-z_near); |
1693 | 0 | mx->m[15] = FIX_ONE; |
1694 | 0 | } |
1695 | | |
1696 | | GF_EXPORT |
1697 | | void gf_mx_ortho_reverse_z(GF_Matrix *mx, Fixed left, Fixed right, Fixed bottom, Fixed top, Fixed z_near, Fixed z_far) |
1698 | 0 | { |
1699 | 0 | gf_mx_init(*mx); |
1700 | 0 | mx->m[0] = gf_divfix(2*FIX_ONE, right-left); |
1701 | 0 | mx->m[5] = gf_divfix(2*FIX_ONE, top-bottom); |
1702 | 0 | mx->m[10] = gf_divfix(-FIX_ONE, z_far-z_near); |
1703 | 0 | mx->m[12] = gf_divfix(right+left, right-left); |
1704 | 0 | mx->m[13] = gf_divfix(top+bottom, top-bottom); |
1705 | 0 | mx->m[14] = -gf_divfix(z_near, z_far-z_near); |
1706 | 0 | mx->m[15] = FIX_ONE; |
1707 | 0 | } |
1708 | | GF_EXPORT |
1709 | | void gf_mx_perspective(GF_Matrix *mx, Fixed fieldOfView, Fixed aspectRatio, Fixed z_near, Fixed z_far) |
1710 | 0 | { |
1711 | 0 | Fixed f = gf_divfix(gf_cos(fieldOfView/2), gf_sin(fieldOfView/2)); |
1712 | 0 | gf_mx_init(*mx); |
1713 | 0 | mx->m[0] = gf_divfix(f, aspectRatio); |
1714 | 0 | mx->m[5] = f; |
1715 | 0 | mx->m[10] = gf_divfix(z_far+z_near, z_near-z_far); |
1716 | |
|
1717 | 0 | mx->m[11] = -FIX_ONE; |
1718 | 0 | mx->m[14] = 2*gf_muldiv(z_near, z_far, z_near-z_far); |
1719 | |
|
1720 | 0 | mx->m[15] = 0; |
1721 | 0 | } |
1722 | | |
1723 | | GF_EXPORT |
1724 | | void gf_mx_perspective_reverse_z(GF_Matrix *mx, Fixed fieldOfView, Fixed aspectRatio, Fixed z_near, Fixed z_far) |
1725 | 0 | { |
1726 | 0 | Fixed f = gf_divfix(gf_cos(fieldOfView/2), gf_sin(fieldOfView/2)); |
1727 | 0 | gf_mx_init(*mx); |
1728 | 0 | mx->m[0] = gf_divfix(f, aspectRatio); |
1729 | 0 | mx->m[5] = f; |
1730 | | //see http://dev.theomader.com/depth-precision/ |
1731 | 0 | #if 1 |
1732 | 0 | mx->m[10] = -gf_divfix(z_far, z_near-z_far) - FIX_ONE; |
1733 | 0 | mx->m[11] = -FIX_ONE; |
1734 | 0 | mx->m[14] = - gf_muldiv(z_near, z_far, z_near-z_far); |
1735 | | #else |
1736 | | mx->m[10] = 0; |
1737 | | mx->m[11] = - FIX_ONE; |
1738 | | mx->m[14] = z_near; |
1739 | | #endif |
1740 | |
|
1741 | 0 | mx->m[15] = 0; |
1742 | 0 | } |
1743 | | GF_EXPORT |
1744 | | void gf_mx_lookat(GF_Matrix *mx, GF_Vec eye, GF_Vec center, GF_Vec upVector) |
1745 | 0 | { |
1746 | 0 | GF_Vec f, s, u; |
1747 | |
|
1748 | 0 | gf_vec_diff(f, center, eye); |
1749 | 0 | gf_vec_norm(&f); |
1750 | 0 | gf_vec_norm(&upVector); |
1751 | |
|
1752 | 0 | s = gf_vec_cross(f, upVector); |
1753 | 0 | u = gf_vec_cross(s, f); |
1754 | 0 | gf_mx_init(*mx); |
1755 | |
|
1756 | 0 | mx->m[0] = s.x; |
1757 | 0 | mx->m[1] = u.x; |
1758 | 0 | mx->m[2] = -f.x; |
1759 | 0 | mx->m[4] = s.y; |
1760 | 0 | mx->m[5] = u.y; |
1761 | 0 | mx->m[6] = -f.y; |
1762 | 0 | mx->m[8] = s.z; |
1763 | 0 | mx->m[9] = u.z; |
1764 | 0 | mx->m[10] = -f.z; |
1765 | |
|
1766 | 0 | gf_mx_add_translation(mx, -eye.x, -eye.y, -eye.z); |
1767 | 0 | } |
1768 | | |
1769 | | GF_Vec4 gf_quat_from_matrix(GF_Matrix *mx); |
1770 | | |
1771 | | GF_EXPORT |
1772 | | void gf_mx_get_yaw_pitch_roll(GF_Matrix *mx, Fixed *yaw, Fixed *pitch, Fixed *roll) |
1773 | 0 | { |
1774 | 0 | Fixed locmat[16]; |
1775 | 0 | gf_assert(mx->m[15]); |
1776 | 0 | memcpy(locmat, mx->m, sizeof(Fixed)*16); |
1777 | 0 | *pitch = (Float) atan(locmat[4]/locmat[0]); |
1778 | 0 | *yaw = (Float) atan(-locmat[8]/gf_sqrt(pow(locmat[9],2) + pow(locmat[10],2))); |
1779 | 0 | *roll = (Float) atan(locmat[9]/locmat[10]); |
1780 | 0 | } |
1781 | | |
1782 | | GF_EXPORT |
1783 | | void gf_mx_decompose(GF_Matrix *mx, GF_Vec *translate, GF_Vec *scale, GF_Vec4 *rotate, GF_Vec *shear) |
1784 | 0 | { |
1785 | 0 | u32 i, j; |
1786 | 0 | GF_Vec4 quat; |
1787 | 0 | Fixed locmat[16]; |
1788 | 0 | GF_Matrix tmp; |
1789 | 0 | GF_Vec row0, row1, row2; |
1790 | 0 | Fixed shear_xy, shear_xz, shear_yz; |
1791 | 0 | gf_assert(mx->m[15]); |
1792 | |
|
1793 | 0 | memcpy(locmat, mx->m, sizeof(Fixed)*16); |
1794 | | /*no perspective*/ |
1795 | 0 | locmat[3] = locmat[7] = locmat[11] = 0; |
1796 | | /*normalize*/ |
1797 | 0 | for (i=0; i<4; i++) { |
1798 | 0 | for (j=0; j<4; j++) { |
1799 | 0 | locmat[4*i+j] = gf_divfix(locmat[4*i+j], locmat[15]); |
1800 | 0 | } |
1801 | 0 | } |
1802 | 0 | translate->x = locmat[12]; |
1803 | 0 | translate->y = locmat[13]; |
1804 | 0 | translate->z = locmat[14]; |
1805 | 0 | locmat[12] = locmat[13] = locmat[14] = 0; |
1806 | 0 | row0.x = locmat[0]; |
1807 | 0 | row0.y = locmat[1]; |
1808 | 0 | row0.z = locmat[2]; |
1809 | 0 | row1.x = locmat[4]; |
1810 | 0 | row1.y = locmat[5]; |
1811 | 0 | row1.z = locmat[6]; |
1812 | 0 | row2.x = locmat[8]; |
1813 | 0 | row2.y = locmat[9]; |
1814 | 0 | row2.z = locmat[10]; |
1815 | |
|
1816 | 0 | scale->x = gf_vec_len(row0); |
1817 | 0 | gf_vec_norm(&row0); |
1818 | 0 | shear_xy = gf_vec_dot(row0, row1); |
1819 | 0 | row1.x -= gf_mulfix(row0.x, shear_xy); |
1820 | 0 | row1.y -= gf_mulfix(row0.y, shear_xy); |
1821 | 0 | row1.z -= gf_mulfix(row0.z, shear_xy); |
1822 | |
|
1823 | 0 | scale->y = gf_vec_len(row1); |
1824 | 0 | gf_vec_norm(&row1); |
1825 | 0 | shear->x = gf_divfix(shear_xy, scale->y); |
1826 | |
|
1827 | 0 | shear_xz = gf_vec_dot(row0, row2); |
1828 | 0 | row2.x -= gf_mulfix(row0.x, shear_xz); |
1829 | 0 | row2.y -= gf_mulfix(row0.y, shear_xz); |
1830 | 0 | row2.z -= gf_mulfix(row0.z, shear_xz); |
1831 | 0 | shear_yz = gf_vec_dot(row1, row2); |
1832 | 0 | row2.x -= gf_mulfix(row1.x, shear_yz); |
1833 | 0 | row2.y -= gf_mulfix(row1.y, shear_yz); |
1834 | 0 | row2.z -= gf_mulfix(row1.z, shear_yz); |
1835 | |
|
1836 | 0 | scale->z = gf_vec_len(row2); |
1837 | 0 | gf_vec_norm(&row2); |
1838 | 0 | shear->y = gf_divfix(shear_xz, scale->z); |
1839 | 0 | shear->z = gf_divfix(shear_yz, scale->z); |
1840 | |
|
1841 | 0 | locmat[0] = row0.x; |
1842 | 0 | locmat[4] = row1.x; |
1843 | 0 | locmat[8] = row2.x; |
1844 | 0 | locmat[1] = row0.y; |
1845 | 0 | locmat[5] = row1.y; |
1846 | 0 | locmat[9] = row2.y; |
1847 | 0 | locmat[2] = row0.z; |
1848 | 0 | locmat[6] = row1.z; |
1849 | 0 | locmat[10] = row2.z; |
1850 | |
|
1851 | 0 | memcpy(tmp.m, locmat, sizeof(Fixed)*16); |
1852 | 0 | quat = gf_quat_from_matrix(&tmp); |
1853 | 0 | *rotate = gf_quat_to_rotation(&quat); |
1854 | 0 | } |
1855 | | |
1856 | | GF_EXPORT |
1857 | | void gf_mx_apply_bbox_sphere(GF_Matrix *mx, GF_BBox *box) |
1858 | 0 | { |
1859 | 0 | Fixed var; |
1860 | 0 | gf_mx_apply_vec(mx, &box->min_edge); |
1861 | 0 | gf_mx_apply_vec(mx, &box->max_edge); |
1862 | |
|
1863 | 0 | if (box->min_edge.x > box->max_edge.x) |
1864 | 0 | { |
1865 | 0 | var = box->min_edge.x; |
1866 | 0 | box->min_edge.x = box->max_edge.x; |
1867 | 0 | box->max_edge.x = var; |
1868 | 0 | } |
1869 | 0 | if (box->min_edge.y > box->max_edge.y) |
1870 | 0 | { |
1871 | 0 | var = box->min_edge.y; |
1872 | 0 | box->min_edge.y = box->max_edge.y; |
1873 | 0 | box->max_edge.y = var; |
1874 | 0 | } |
1875 | 0 | if (box->min_edge.z > box->max_edge.z) |
1876 | 0 | { |
1877 | 0 | var = box->min_edge.z; |
1878 | 0 | box->min_edge.z = box->max_edge.z; |
1879 | 0 | box->max_edge.z = var; |
1880 | 0 | } |
1881 | 0 | gf_bbox_refresh(box); |
1882 | 0 | } |
1883 | | |
1884 | | GF_EXPORT |
1885 | | void gf_mx_apply_bbox(GF_Matrix *mx, GF_BBox *box) |
1886 | 0 | { |
1887 | 0 | u32 i; |
1888 | 0 | GF_Vec v[8]; |
1889 | 0 | v[0] = box->min_edge; |
1890 | 0 | v[1] = box->min_edge; |
1891 | 0 | v[1].x = box->max_edge.x; |
1892 | 0 | v[2] = box->min_edge; |
1893 | 0 | v[2].y = box->max_edge.y; |
1894 | 0 | v[3] = box->min_edge; |
1895 | 0 | v[3].z = box->max_edge.z; |
1896 | |
|
1897 | 0 | v[4] = box->max_edge; |
1898 | 0 | v[5] = box->max_edge; |
1899 | 0 | v[5].x = box->min_edge.x; |
1900 | 0 | v[6] = box->max_edge; |
1901 | 0 | v[6].y = box->min_edge.y; |
1902 | 0 | v[7] = box->max_edge; |
1903 | 0 | v[7].z = box->min_edge.z; |
1904 | |
|
1905 | 0 | box->max_edge.x = box->max_edge.y = box->max_edge.z = -FIX_MAX; |
1906 | 0 | box->min_edge.x = box->min_edge.y = box->min_edge.z = FIX_MAX; |
1907 | 0 | for (i=0; i<8; i++) { |
1908 | 0 | gf_mx_apply_vec(mx, &v[i]); |
1909 | 0 | if (box->min_edge.x > v[i].x) box->min_edge.x = v[i].x; |
1910 | 0 | if (box->min_edge.y > v[i].y) box->min_edge.y = v[i].y; |
1911 | 0 | if (box->min_edge.z > v[i].z) box->min_edge.z = v[i].z; |
1912 | 0 | if (box->max_edge.x < v[i].x) box->max_edge.x = v[i].x; |
1913 | 0 | if (box->max_edge.y < v[i].y) box->max_edge.y = v[i].y; |
1914 | 0 | if (box->max_edge.z < v[i].z) box->max_edge.z = v[i].z; |
1915 | 0 | } |
1916 | 0 | gf_bbox_refresh(box); |
1917 | 0 | } |
1918 | | |
1919 | | GF_EXPORT |
1920 | | void gf_mx_apply_bbox_4x4(GF_Matrix *mx, GF_BBox *box) |
1921 | 0 | { |
1922 | 0 | u32 i; |
1923 | 0 | GF_Vec v[8]; |
1924 | 0 | v[0] = box->min_edge; |
1925 | 0 | v[1] = box->min_edge; |
1926 | 0 | v[1].x = box->max_edge.x; |
1927 | 0 | v[2] = box->min_edge; |
1928 | 0 | v[2].y = box->max_edge.y; |
1929 | 0 | v[3] = box->min_edge; |
1930 | 0 | v[3].z = box->max_edge.z; |
1931 | |
|
1932 | 0 | v[4] = box->max_edge; |
1933 | 0 | v[5] = box->max_edge; |
1934 | 0 | v[5].x = box->min_edge.x; |
1935 | 0 | v[6] = box->max_edge; |
1936 | 0 | v[6].y = box->min_edge.y; |
1937 | 0 | v[7] = box->max_edge; |
1938 | 0 | v[7].z = box->min_edge.z; |
1939 | |
|
1940 | 0 | box->max_edge.x = box->max_edge.y = box->max_edge.z = -FIX_MAX; |
1941 | 0 | box->min_edge.x = box->min_edge.y = box->min_edge.z = FIX_MAX; |
1942 | 0 | for (i=0; i<8; i++) { |
1943 | 0 | GF_Vec4 vec; |
1944 | 0 | vec.x = v[i].x; |
1945 | 0 | vec.y = v[i].y; |
1946 | 0 | vec.z = v[i].z; |
1947 | 0 | vec.q = FIX_ONE; |
1948 | 0 | gf_mx_apply_vec_4x4(mx, &vec); |
1949 | 0 | if (!vec.q) continue; |
1950 | 0 | vec.q = gf_divfix(FIX_ONE, vec.q); |
1951 | 0 | vec.x = gf_mulfix(vec.x, vec.q); |
1952 | 0 | vec.y = gf_mulfix(vec.y, vec.q); |
1953 | 0 | vec.z = gf_mulfix(vec.z, vec.q); |
1954 | |
|
1955 | 0 | if (box->min_edge.x > vec.x) box->min_edge.x = vec.x; |
1956 | 0 | if (box->min_edge.y > vec.y) box->min_edge.y = vec.y; |
1957 | 0 | if (box->min_edge.z > vec.z) box->min_edge.z = vec.z; |
1958 | 0 | if (box->max_edge.x < vec.x) box->max_edge.x = vec.x; |
1959 | 0 | if (box->max_edge.y < vec.y) box->max_edge.y = vec.y; |
1960 | 0 | if (box->max_edge.z < vec.z) box->max_edge.z = vec.z; |
1961 | 0 | } |
1962 | 0 | gf_bbox_refresh(box); |
1963 | 0 | } |
1964 | | |
1965 | | |
1966 | | // Apply the rotation portion of a matrix to a vector. |
1967 | | GF_EXPORT |
1968 | | void gf_mx_rotate_vector(GF_Matrix *mx, GF_Vec *pt) |
1969 | 0 | { |
1970 | 0 | GF_Vec res; |
1971 | 0 | Fixed den; |
1972 | 0 | res.x = gf_mulfix(pt->x, mx->m[0]) + gf_mulfix(pt->y, mx->m[4]) + gf_mulfix(pt->z, mx->m[8]); |
1973 | 0 | res.y = gf_mulfix(pt->x, mx->m[1]) + gf_mulfix(pt->y, mx->m[5]) + gf_mulfix(pt->z, mx->m[9]); |
1974 | 0 | res.z = gf_mulfix(pt->x, mx->m[2]) + gf_mulfix(pt->y, mx->m[6]) + gf_mulfix(pt->z, mx->m[10]); |
1975 | 0 | den = gf_mulfix(pt->x, mx->m[3]) + gf_mulfix(pt->y, mx->m[7]) + gf_mulfix(pt->z, mx->m[11]) + mx->m[15]; |
1976 | 0 | if (den == 0) return; |
1977 | 0 | res.x = gf_divfix(res.x, den); |
1978 | 0 | res.y = gf_divfix(res.y, den); |
1979 | 0 | res.z = gf_divfix(res.z, den); |
1980 | 0 | *pt = res; |
1981 | 0 | } |
1982 | | |
1983 | | GF_EXPORT |
1984 | | void gf_mx_rotation_matrix_from_vectors(GF_Matrix *mx, GF_Vec x, GF_Vec y, GF_Vec z) |
1985 | 0 | { |
1986 | 0 | mx->m[0] = x.x; |
1987 | 0 | mx->m[1] = y.x; |
1988 | 0 | mx->m[2] = z.x; |
1989 | 0 | mx->m[3] = 0; |
1990 | 0 | mx->m[4] = x.y; |
1991 | 0 | mx->m[5] = y.y; |
1992 | 0 | mx->m[6] = z.y; |
1993 | 0 | mx->m[7] = 0; |
1994 | 0 | mx->m[8] = x.z; |
1995 | 0 | mx->m[9] = y.z; |
1996 | 0 | mx->m[10] = z.z; |
1997 | 0 | mx->m[11] = 0; |
1998 | 0 | mx->m[12] = 0; |
1999 | 0 | mx->m[13] = 0; |
2000 | 0 | mx->m[14] = 0; |
2001 | 0 | mx->m[15] = FIX_ONE; |
2002 | 0 | } |
2003 | | |
2004 | | |
2005 | | /*we should only need a full matrix product for frustrum setup*/ |
2006 | | GF_EXPORT |
2007 | | void gf_mx_add_matrix_4x4(GF_Matrix *mat, GF_Matrix *mul) |
2008 | 0 | { |
2009 | 0 | GF_Matrix tmp; |
2010 | 0 | gf_mx_init(tmp); |
2011 | 0 | tmp.m[0] = gf_mulfix(mat->m[0],mul->m[0]) + gf_mulfix(mat->m[4],mul->m[1]) + gf_mulfix(mat->m[8],mul->m[2]) + gf_mulfix(mat->m[12],mul->m[3]); |
2012 | 0 | tmp.m[1] = gf_mulfix(mat->m[1],mul->m[0]) + gf_mulfix(mat->m[5],mul->m[1]) + gf_mulfix(mat->m[9],mul->m[2]) + gf_mulfix(mat->m[13],mul->m[3]); |
2013 | 0 | tmp.m[2] = gf_mulfix(mat->m[2],mul->m[0]) + gf_mulfix(mat->m[6],mul->m[1]) + gf_mulfix(mat->m[10],mul->m[2]) + gf_mulfix(mat->m[14],mul->m[3]); |
2014 | 0 | tmp.m[3] = gf_mulfix(mat->m[3],mul->m[0]) + gf_mulfix(mat->m[7],mul->m[1]) + gf_mulfix(mat->m[11],mul->m[2]) + gf_mulfix(mat->m[15],mul->m[3]); |
2015 | 0 | tmp.m[4] = gf_mulfix(mat->m[0],mul->m[4]) + gf_mulfix(mat->m[4],mul->m[5]) + gf_mulfix(mat->m[8],mul->m[6]) + gf_mulfix(mat->m[12],mul->m[7]); |
2016 | 0 | tmp.m[5] = gf_mulfix(mat->m[1],mul->m[4]) + gf_mulfix(mat->m[5],mul->m[5]) + gf_mulfix(mat->m[9],mul->m[6]) + gf_mulfix(mat->m[13],mul->m[7]); |
2017 | 0 | tmp.m[6] = gf_mulfix(mat->m[2],mul->m[4]) + gf_mulfix(mat->m[6],mul->m[5]) + gf_mulfix(mat->m[10],mul->m[6]) + gf_mulfix(mat->m[14],mul->m[7]); |
2018 | 0 | tmp.m[7] = gf_mulfix(mat->m[3],mul->m[4]) + gf_mulfix(mat->m[7],mul->m[5]) + gf_mulfix(mat->m[11],mul->m[6]) + gf_mulfix(mat->m[15],mul->m[7]); |
2019 | 0 | tmp.m[8] = gf_mulfix(mat->m[0],mul->m[8]) + gf_mulfix(mat->m[4],mul->m[9]) + gf_mulfix(mat->m[8],mul->m[10]) + gf_mulfix(mat->m[12],mul->m[11]); |
2020 | 0 | tmp.m[9] = gf_mulfix(mat->m[1],mul->m[8]) + gf_mulfix(mat->m[5],mul->m[9]) + gf_mulfix(mat->m[9],mul->m[10]) + gf_mulfix(mat->m[13],mul->m[11]); |
2021 | 0 | tmp.m[10] = gf_mulfix(mat->m[2],mul->m[8]) + gf_mulfix(mat->m[6],mul->m[9]) + gf_mulfix(mat->m[10],mul->m[10]) + gf_mulfix(mat->m[14],mul->m[11]); |
2022 | 0 | tmp.m[11] = gf_mulfix(mat->m[3],mul->m[8]) + gf_mulfix(mat->m[7],mul->m[9]) + gf_mulfix(mat->m[11],mul->m[10]) + gf_mulfix(mat->m[15],mul->m[11]); |
2023 | 0 | tmp.m[12] = gf_mulfix(mat->m[0],mul->m[12]) + gf_mulfix(mat->m[4],mul->m[13]) + gf_mulfix(mat->m[8],mul->m[14]) + gf_mulfix(mat->m[12],mul->m[15]); |
2024 | 0 | tmp.m[13] = gf_mulfix(mat->m[1],mul->m[12]) + gf_mulfix(mat->m[5],mul->m[13]) + gf_mulfix(mat->m[9],mul->m[14]) + gf_mulfix(mat->m[13],mul->m[15]); |
2025 | 0 | tmp.m[14] = gf_mulfix(mat->m[2],mul->m[12]) + gf_mulfix(mat->m[6],mul->m[13]) + gf_mulfix(mat->m[10],mul->m[14]) + gf_mulfix(mat->m[14],mul->m[15]); |
2026 | 0 | tmp.m[15] = gf_mulfix(mat->m[3],mul->m[12]) + gf_mulfix(mat->m[7],mul->m[13]) + gf_mulfix(mat->m[11],mul->m[14]) + gf_mulfix(mat->m[15],mul->m[15]); |
2027 | 0 | memcpy(mat->m, tmp.m, sizeof(Fixed)*16); |
2028 | 0 | } |
2029 | | |
2030 | | |
2031 | | GF_EXPORT |
2032 | | void gf_mx_apply_vec_4x4(GF_Matrix *mx, GF_Vec4 *vec) |
2033 | 0 | { |
2034 | 0 | GF_Vec4 res; |
2035 | 0 | res.x = gf_mulfix(mx->m[0], vec->x) + gf_mulfix(mx->m[4], vec->y) + gf_mulfix(mx->m[8], vec->z) + gf_mulfix(mx->m[12], vec->q); |
2036 | 0 | res.y = gf_mulfix(mx->m[1], vec->x) + gf_mulfix(mx->m[5], vec->y) + gf_mulfix(mx->m[9], vec->z) + gf_mulfix(mx->m[13], vec->q); |
2037 | 0 | res.z = gf_mulfix(mx->m[2], vec->x) + gf_mulfix(mx->m[6], vec->y) + gf_mulfix(mx->m[10], vec->z) + gf_mulfix(mx->m[14], vec->q); |
2038 | 0 | res.q = gf_mulfix(mx->m[3], vec->x) + gf_mulfix(mx->m[7], vec->y) + gf_mulfix(mx->m[11], vec->z) + gf_mulfix(mx->m[15], vec->q); |
2039 | 0 | *vec = res; |
2040 | 0 | } |
2041 | | |
2042 | | /* |
2043 | | * Taken from MESA/GLU (LGPL) |
2044 | | * |
2045 | | * Compute inverse of 4x4 transformation matrix. |
2046 | | * Code contributed by Jacques Leroy jle@star.be |
2047 | | * Return 1 for success, 0 for failure (singular matrix) |
2048 | | */ |
2049 | | |
2050 | | GF_EXPORT |
2051 | | Bool gf_mx_inverse_4x4(GF_Matrix *mx) |
2052 | 0 | { |
2053 | |
|
2054 | 0 | #define SWAP_ROWS(a, b) { Fixed *_tmp = a; (a)=(b); (b)=_tmp; } |
2055 | 0 | Fixed wtmp[4][8]; |
2056 | 0 | Fixed m0, m1, m2, m3, s; |
2057 | 0 | Fixed *r0, *r1, *r2, *r3; |
2058 | 0 | GF_Matrix res; |
2059 | 0 | r0 = wtmp[0]; r1 = wtmp[1]; r2 = wtmp[2]; r3 = wtmp[3]; |
2060 | 0 | r0[0] = mx->m[0]; |
2061 | 0 | r0[1] = mx->m[4]; |
2062 | 0 | r0[2] = mx->m[8]; |
2063 | 0 | r0[3] = mx->m[12]; |
2064 | 0 | r0[4] = FIX_ONE; |
2065 | 0 | r0[5] = r0[6] = r0[7] = 0; |
2066 | 0 | r1[0] = mx->m[1]; |
2067 | 0 | r1[1] = mx->m[5]; |
2068 | 0 | r1[2] = mx->m[9]; |
2069 | 0 | r1[3] = mx->m[13]; |
2070 | 0 | r1[5] = FIX_ONE; |
2071 | 0 | r1[4] = r1[6] = r1[7] = 0; |
2072 | 0 | r2[0] = mx->m[2]; |
2073 | 0 | r2[1] = mx->m[6]; |
2074 | 0 | r2[2] = mx->m[10]; |
2075 | 0 | r2[3] = mx->m[14]; |
2076 | 0 | r2[6] = FIX_ONE; |
2077 | 0 | r2[4] = r2[5] = r2[7] = 0; |
2078 | 0 | r3[0] = mx->m[3]; |
2079 | 0 | r3[1] = mx->m[7]; |
2080 | 0 | r3[2] = mx->m[11]; |
2081 | 0 | r3[3] = mx->m[15]; |
2082 | 0 | r3[7] = FIX_ONE; |
2083 | 0 | r3[4] = r3[5] = r3[6] = 0; |
2084 | | |
2085 | | /* choose pivot - or die */ |
2086 | 0 | if (ABS(r3[0]) > ABS(r2[0])) SWAP_ROWS(r3, r2); |
2087 | 0 | if (ABS(r2[0]) > ABS(r1[0])) SWAP_ROWS(r2, r1); |
2088 | 0 | if (ABS(r1[0]) > ABS(r0[0])) SWAP_ROWS(r1, r0); |
2089 | 0 | if (r0[0]==0) return GF_FALSE; |
2090 | | |
2091 | | /*eliminate first variable*/ |
2092 | 0 | m1 = gf_divfix(r1[0], r0[0]); |
2093 | 0 | m2 = gf_divfix(r2[0], r0[0]); |
2094 | 0 | m3 = gf_divfix(r3[0], r0[0]); |
2095 | 0 | s = r0[1]; |
2096 | 0 | r1[1] -= gf_mulfix(m1, s); |
2097 | 0 | r2[1] -= gf_mulfix(m2, s); |
2098 | 0 | r3[1] -= gf_mulfix(m3, s); |
2099 | 0 | s = r0[2]; |
2100 | 0 | r1[2] -= gf_mulfix(m1, s); |
2101 | 0 | r2[2] -= gf_mulfix(m2, s); |
2102 | 0 | r3[2] -= gf_mulfix(m3, s); |
2103 | 0 | s = r0[3]; |
2104 | 0 | r1[3] -= gf_mulfix(m1, s); |
2105 | 0 | r2[3] -= gf_mulfix(m2, s); |
2106 | 0 | r3[3] -= gf_mulfix(m3, s); |
2107 | 0 | s = r0[4]; |
2108 | 0 | if (s != 0) { |
2109 | 0 | r1[4] -= gf_mulfix(m1, s); |
2110 | 0 | r2[4] -= gf_mulfix(m2, s); |
2111 | 0 | r3[4] -= gf_mulfix(m3, s); |
2112 | 0 | } |
2113 | 0 | s = r0[5]; |
2114 | 0 | if (s != 0) { |
2115 | 0 | r1[5] -= gf_mulfix(m1, s); |
2116 | 0 | r2[5] -= gf_mulfix(m2, s); |
2117 | 0 | r3[5] -= gf_mulfix(m3, s); |
2118 | 0 | } |
2119 | 0 | s = r0[6]; |
2120 | 0 | if (s != 0) { |
2121 | 0 | r1[6] -= gf_mulfix(m1, s); |
2122 | 0 | r2[6] -= gf_mulfix(m2, s); |
2123 | 0 | r3[6] -= gf_mulfix(m3, s); |
2124 | 0 | } |
2125 | 0 | s = r0[7]; |
2126 | 0 | if (s != 0) { |
2127 | 0 | r1[7] -= gf_mulfix(m1, s); |
2128 | 0 | r2[7] -= gf_mulfix(m2, s); |
2129 | 0 | r3[7] -= gf_mulfix(m3, s); |
2130 | 0 | } |
2131 | | |
2132 | | /* choose pivot - or die */ |
2133 | 0 | if (ABS(r3[1]) > ABS(r2[1])) SWAP_ROWS(r3, r2); |
2134 | 0 | if (ABS(r2[1]) > ABS(r1[1])) SWAP_ROWS(r2, r1); |
2135 | 0 | if (r1[1]==0) return GF_FALSE; |
2136 | | |
2137 | | /* eliminate second variable */ |
2138 | 0 | m2 = gf_divfix(r2[1], r1[1]); |
2139 | 0 | m3 = gf_divfix(r3[1], r1[1]); |
2140 | 0 | r2[2] -= gf_mulfix(m2, r1[2]); |
2141 | 0 | r3[2] -= gf_mulfix(m3, r1[2]); |
2142 | 0 | r2[3] -= gf_mulfix(m2, r1[3]); |
2143 | 0 | r3[3] -= gf_mulfix(m3, r1[3]); |
2144 | 0 | s = r1[4]; |
2145 | 0 | if (s!=0) { |
2146 | 0 | r2[4] -= gf_mulfix(m2, s); |
2147 | 0 | r3[4] -= gf_mulfix(m3, s); |
2148 | 0 | } |
2149 | 0 | s = r1[5]; |
2150 | 0 | if (s!=0) { |
2151 | 0 | r2[5] -= gf_mulfix(m2, s); |
2152 | 0 | r3[5] -= gf_mulfix(m3, s); |
2153 | 0 | } |
2154 | 0 | s = r1[6]; |
2155 | 0 | if (s!=0) { |
2156 | 0 | r2[6] -= gf_mulfix(m2, s); |
2157 | 0 | r3[6] -= gf_mulfix(m3, s); |
2158 | 0 | } |
2159 | 0 | s = r1[7]; |
2160 | 0 | if (s!=0) { |
2161 | 0 | r2[7] -= gf_mulfix(m2, s); |
2162 | 0 | r3[7] -= gf_mulfix(m3, s); |
2163 | 0 | } |
2164 | | |
2165 | | /* choose pivot - or die */ |
2166 | 0 | if (ABS(r3[2]) > ABS(r2[2])) SWAP_ROWS(r3, r2); |
2167 | 0 | if (r2[2]==0) return GF_FALSE; |
2168 | | |
2169 | | /* eliminate third variable */ |
2170 | 0 | m3 = gf_divfix(r3[2], r2[2]); |
2171 | 0 | r3[3] -= gf_mulfix(m3, r2[3]); |
2172 | 0 | r3[4] -= gf_mulfix(m3, r2[4]); |
2173 | 0 | r3[5] -= gf_mulfix(m3, r2[5]); |
2174 | 0 | r3[6] -= gf_mulfix(m3, r2[6]); |
2175 | 0 | r3[7] -= gf_mulfix(m3, r2[7]); |
2176 | | /* last check */ |
2177 | 0 | if (r3[3]==0) return GF_FALSE; |
2178 | | |
2179 | 0 | s = gf_invfix(r3[3]); /* now back substitute row 3 */ |
2180 | 0 | r3[4] = gf_mulfix(r3[4], s); |
2181 | 0 | r3[5] = gf_mulfix(r3[5], s); |
2182 | 0 | r3[6] = gf_mulfix(r3[6], s); |
2183 | 0 | r3[7] = gf_mulfix(r3[7], s); |
2184 | |
|
2185 | 0 | m2 = r2[3]; /* now back substitute row 2 */ |
2186 | 0 | s = gf_invfix(r2[2]); |
2187 | 0 | r2[4] = gf_mulfix(s, r2[4] - gf_mulfix(r3[4], m2)); |
2188 | 0 | r2[5] = gf_mulfix(s, r2[5] - gf_mulfix(r3[5], m2)); |
2189 | 0 | r2[6] = gf_mulfix(s, r2[6] - gf_mulfix(r3[6], m2)); |
2190 | 0 | r2[7] = gf_mulfix(s, r2[7] - gf_mulfix(r3[7], m2)); |
2191 | 0 | m1 = r1[3]; |
2192 | 0 | r1[4] -= gf_mulfix(r3[4], m1); |
2193 | 0 | r1[5] -= gf_mulfix(r3[5], m1); |
2194 | 0 | r1[6] -= gf_mulfix(r3[6], m1); |
2195 | 0 | r1[7] -= gf_mulfix(r3[7], m1); |
2196 | 0 | m0 = r0[3]; |
2197 | 0 | r0[4] -= gf_mulfix(r3[4], m0); |
2198 | 0 | r0[5] -= gf_mulfix(r3[5], m0); |
2199 | 0 | r0[6] -= gf_mulfix(r3[6], m0); |
2200 | 0 | r0[7] -= gf_mulfix(r3[7], m0); |
2201 | |
|
2202 | 0 | m1 = r1[2]; /* now back substitute row 1 */ |
2203 | 0 | s = gf_invfix(r1[1]); |
2204 | 0 | r1[4] = gf_mulfix(s, r1[4] - gf_mulfix(r2[4], m1)); |
2205 | 0 | r1[5] = gf_mulfix(s, r1[5] - gf_mulfix(r2[5], m1)); |
2206 | 0 | r1[6] = gf_mulfix(s, r1[6] - gf_mulfix(r2[6], m1)); |
2207 | 0 | r1[7] = gf_mulfix(s, r1[7] - gf_mulfix(r2[7], m1)); |
2208 | 0 | m0 = r0[2]; |
2209 | 0 | r0[4] -= gf_mulfix(r2[4], m0); |
2210 | 0 | r0[5] -= gf_mulfix(r2[5], m0); |
2211 | 0 | r0[6] -= gf_mulfix(r2[6], m0); |
2212 | 0 | r0[7] -= gf_mulfix(r2[7], m0); |
2213 | |
|
2214 | 0 | m0 = r0[1]; /* now back substitute row 0 */ |
2215 | 0 | s = gf_invfix(r0[0]); |
2216 | 0 | r0[4] = gf_mulfix(s, r0[4] - gf_mulfix(r1[4], m0)); |
2217 | 0 | r0[5] = gf_mulfix(s, r0[5] - gf_mulfix(r1[5], m0)); |
2218 | 0 | r0[6] = gf_mulfix(s, r0[6] - gf_mulfix(r1[6], m0)); |
2219 | 0 | r0[7] = gf_mulfix(s, r0[7] - gf_mulfix(r1[7], m0)); |
2220 | |
|
2221 | 0 | gf_mx_init(res) |
2222 | 0 | res.m[0] = r0[4]; |
2223 | 0 | res.m[4] = r0[5]; |
2224 | 0 | res.m[8] = r0[6]; |
2225 | 0 | res.m[12] = r0[7]; |
2226 | 0 | res.m[1] = r1[4]; |
2227 | 0 | res.m[5] = r1[5]; res.m[9] = r1[6]; |
2228 | 0 | res.m[13] = r1[7]; |
2229 | 0 | res.m[2] = r2[4]; |
2230 | 0 | res.m[6] = r2[5]; |
2231 | 0 | res.m[10] = r2[6]; |
2232 | 0 | res.m[14] = r2[7]; |
2233 | 0 | res.m[3] = r3[4]; |
2234 | 0 | res.m[7] = r3[5]; |
2235 | 0 | res.m[11] = r3[6]; |
2236 | 0 | res.m[15] = r3[7]; |
2237 | 0 | gf_mx_copy(*mx, res); |
2238 | 0 | return GF_TRUE; |
2239 | 0 | #undef SWAP_ROWS |
2240 | |
|
2241 | 0 | } |
2242 | | |
2243 | | |
2244 | | |
2245 | | GF_EXPORT |
2246 | | Bool gf_plane_intersect_line(GF_Plane *plane, GF_Vec *linepoint, GF_Vec *linevec, GF_Vec *outPoint) |
2247 | 0 | { |
2248 | 0 | Fixed t, t2; |
2249 | 0 | t2 = gf_vec_dot(plane->normal, *linevec); |
2250 | 0 | if (t2 == 0) return GF_FALSE; |
2251 | 0 | t = - gf_divfix((gf_vec_dot(plane->normal, *linepoint) + plane->d) , t2); |
2252 | 0 | if (t<0) return GF_FALSE; |
2253 | 0 | *outPoint = gf_vec_scale(*linevec, t); |
2254 | 0 | gf_vec_add(*outPoint, *linepoint, *outPoint); |
2255 | 0 | return GF_TRUE; |
2256 | 0 | } |
2257 | | |
2258 | | #if 0 //unused |
2259 | | Bool gf_plane_exists_intersection(GF_Plane *plane, GF_Plane *with) |
2260 | | { |
2261 | | GF_Vec cross; |
2262 | | cross = gf_vec_cross(with->normal, plane->normal); |
2263 | | return gf_vec_lensq(cross) > FIX_EPSILON; |
2264 | | } |
2265 | | |
2266 | | Bool gf_plane_intersect_plane(GF_Plane *plane, GF_Plane *with, GF_Vec *linepoint, GF_Vec *linevec) |
2267 | | { |
2268 | | Fixed fn00 = gf_vec_len(plane->normal); |
2269 | | Fixed fn01 = gf_vec_dot(plane->normal, with->normal); |
2270 | | Fixed fn11 = gf_vec_len(with->normal); |
2271 | | Fixed det = gf_mulfix(fn00,fn11) - gf_mulfix(fn01,fn01); |
2272 | | if (ABS(det) > FIX_EPSILON) { |
2273 | | Fixed fc0, fc1; |
2274 | | GF_Vec v1, v2; |
2275 | | fc0 = gf_divfix( gf_mulfix(fn11, -plane->d) + gf_mulfix(fn01, with->d) , det); |
2276 | | fc1 = gf_divfix( gf_mulfix(fn00, -with->d) + gf_mulfix(fn01, plane->d) , det); |
2277 | | *linevec = gf_vec_cross(plane->normal, with->normal); |
2278 | | v1 = gf_vec_scale(plane->normal, fc0); |
2279 | | v2 = gf_vec_scale(with->normal, fc1); |
2280 | | gf_vec_add(*linepoint, v1, v2); |
2281 | | return GF_TRUE; |
2282 | | } |
2283 | | return GF_FALSE; |
2284 | | } |
2285 | | |
2286 | | Bool gf_plane_intersect_planes(GF_Plane *plane, GF_Plane *p1, GF_Plane *p2, GF_Vec *outPoint) |
2287 | | { |
2288 | | GF_Vec lp, lv; |
2289 | | if (gf_plane_intersect_plane(plane, p1, &lp, &lv)) |
2290 | | return gf_plane_intersect_line(p2, &lp, &lv, outPoint); |
2291 | | return GF_FALSE; |
2292 | | } |
2293 | | |
2294 | | #endif |
2295 | | |
2296 | | |
2297 | | GF_EXPORT |
2298 | | GF_Ray gf_ray(GF_Vec start, GF_Vec end) |
2299 | 0 | { |
2300 | 0 | GF_Ray r; |
2301 | 0 | r.orig = start; |
2302 | 0 | gf_vec_diff(r.dir, end, start); |
2303 | 0 | gf_vec_norm(&r.dir); |
2304 | 0 | return r; |
2305 | 0 | } |
2306 | | |
2307 | | GF_EXPORT |
2308 | | void gf_mx_apply_ray(GF_Matrix *mx, GF_Ray *r) |
2309 | 0 | { |
2310 | 0 | gf_vec_add(r->dir, r->orig, r->dir); |
2311 | 0 | gf_mx_apply_vec(mx, &r->orig); |
2312 | 0 | gf_mx_apply_vec(mx, &r->dir); |
2313 | 0 | gf_vec_diff(r->dir, r->dir, r->orig); |
2314 | 0 | gf_vec_norm(&r->dir); |
2315 | 0 | } |
2316 | | |
2317 | | #define XPLANE 0 |
2318 | | #define YPLANE 1 |
2319 | | #define ZPLANE 2 |
2320 | | |
2321 | | |
2322 | | GF_EXPORT |
2323 | | Bool gf_ray_hit_box(GF_Ray *ray, GF_Vec box_min, GF_Vec box_max, GF_Vec *outPoint) |
2324 | 0 | { |
2325 | 0 | Fixed t1, t2, tNEAR=FIX_MIN, tFAR=FIX_MAX; |
2326 | 0 | Fixed temp; |
2327 | | //s8 xyorz, sign; |
2328 | |
|
2329 | 0 | if (ray->dir.x == 0) { |
2330 | 0 | if ((ray->orig.x < box_min.x) || (ray->orig.x > box_max.x)) |
2331 | 0 | return GF_FALSE; |
2332 | 0 | } else { |
2333 | 0 | t1 = gf_divfix(box_min.x - ray->orig.x, ray->dir.x); |
2334 | 0 | t2 = gf_divfix(box_max.x - ray->orig.x, ray->dir.x); |
2335 | 0 | if (t1 > t2) { |
2336 | 0 | temp = t1; |
2337 | 0 | t1 = t2; |
2338 | 0 | t2 = temp; |
2339 | 0 | } |
2340 | 0 | if (t1 > tNEAR) { |
2341 | 0 | tNEAR = t1; |
2342 | | //xyorz = XPLANE; |
2343 | | //sign = (ray->dir.x < 0) ? 1 : -1; |
2344 | 0 | } |
2345 | 0 | if (t2 < tFAR) tFAR = t2; |
2346 | 0 | if (tNEAR > tFAR) return GF_FALSE; // box missed |
2347 | 0 | if (tFAR < 0) return GF_FALSE; // box behind the ray |
2348 | 0 | } |
2349 | | |
2350 | 0 | if (ray->dir.y == 0) { |
2351 | 0 | if ((ray->orig.y < box_min.y) || (ray->orig.y > box_max.y)) |
2352 | 0 | return GF_FALSE; |
2353 | 0 | } else { |
2354 | 0 | tNEAR=FIX_MIN; |
2355 | 0 | tFAR=FIX_MAX; |
2356 | 0 | t1 = gf_divfix(box_min.y - ray->orig.y, ray->dir.y); |
2357 | 0 | t2 = gf_divfix(box_max.y - ray->orig.y, ray->dir.y); |
2358 | 0 | if (t1 > t2) { |
2359 | 0 | temp = t1; |
2360 | 0 | t1 = t2; |
2361 | 0 | t2 = temp; |
2362 | 0 | } |
2363 | 0 | if (t1 > tNEAR) { |
2364 | 0 | tNEAR = t1; |
2365 | | //xyorz = YPLANE; |
2366 | | //sign = (ray->dir.y < 0) ? 1 : -1; |
2367 | 0 | } |
2368 | 0 | if (t2 < tFAR) tFAR = t2; |
2369 | 0 | if (tNEAR > tFAR) return GF_FALSE; // box missed |
2370 | 0 | if (tFAR < 0) return GF_FALSE; // box behind the ray |
2371 | 0 | } |
2372 | | |
2373 | | // Check the Z plane |
2374 | 0 | if (ray->dir.z == 0) { |
2375 | 0 | if ((ray->orig.z < box_min.z) || (ray->orig.z > box_max.z)) |
2376 | 0 | return GF_FALSE; |
2377 | 0 | } else { |
2378 | 0 | tNEAR=FIX_MIN; |
2379 | 0 | tFAR=FIX_MAX; |
2380 | 0 | t1 = gf_divfix(box_min.z - ray->orig.z, ray->dir.z); |
2381 | 0 | t2 = gf_divfix(box_max.z - ray->orig.z, ray->dir.z); |
2382 | 0 | if (t1 > t2) { |
2383 | 0 | temp = t1; |
2384 | 0 | t1 = t2; |
2385 | 0 | t2 = temp; |
2386 | 0 | } |
2387 | 0 | if (t1 > tNEAR) { |
2388 | 0 | tNEAR = t1; |
2389 | | //xyorz = ZPLANE; |
2390 | | //sign = (ray->dir.z < 0) ? 1 : -1; |
2391 | 0 | } |
2392 | 0 | if (t2 < tFAR) tFAR = t2; |
2393 | 0 | if (tNEAR>tFAR) return GF_FALSE; // box missed |
2394 | 0 | if (tFAR < 0) return GF_FALSE; // box behind the ray |
2395 | 0 | } |
2396 | 0 | if (outPoint) { |
2397 | 0 | *outPoint = gf_vec_scale(ray->dir, tNEAR); |
2398 | 0 | gf_vec_add(*outPoint, *outPoint, ray->orig); |
2399 | 0 | } |
2400 | 0 | return GF_TRUE; |
2401 | 0 | } |
2402 | | |
2403 | | |
2404 | | GF_EXPORT |
2405 | | Bool gf_ray_hit_sphere(GF_Ray *ray, GF_Vec *center, Fixed radius, GF_Vec *outPoint) |
2406 | 0 | { |
2407 | 0 | GF_Vec radv; |
2408 | 0 | Fixed dist, center_proj, center_proj_sq, hcord; |
2409 | 0 | if (center) { |
2410 | 0 | gf_vec_diff(radv, *center, ray->orig); |
2411 | 0 | } else { |
2412 | 0 | radv = ray->orig; |
2413 | 0 | gf_vec_rev(radv); |
2414 | 0 | } |
2415 | 0 | dist = gf_vec_len(radv); |
2416 | 0 | center_proj = gf_vec_dot(radv, ray->dir); |
2417 | 0 | if (radius + ABS(center_proj) < dist ) return GF_FALSE; |
2418 | | |
2419 | 0 | center_proj_sq = gf_mulfix(center_proj, center_proj); |
2420 | 0 | hcord = center_proj_sq - gf_mulfix(dist, dist) + gf_mulfix(radius , radius); |
2421 | 0 | if (hcord < 0) return GF_FALSE; |
2422 | 0 | if (center_proj_sq < hcord) return GF_FALSE; |
2423 | 0 | if (outPoint) { |
2424 | 0 | center_proj -= gf_sqrt(hcord); |
2425 | 0 | radv = gf_vec_scale(ray->dir, center_proj); |
2426 | 0 | gf_vec_add(*outPoint, ray->orig, radv); |
2427 | 0 | } |
2428 | 0 | return GF_TRUE; |
2429 | 0 | } |
2430 | | |
2431 | | /* |
2432 | | * Tomas M�ller and Ben Trumbore. |
2433 | | * Fast, minimum storage ray-triangle intersection. |
2434 | | * Journal of graphics tools, 2(1):21-28, 1997 |
2435 | | * |
2436 | | */ |
2437 | | GF_EXPORT |
2438 | | Bool gf_ray_hit_triangle(GF_Ray *ray, GF_Vec *v0, GF_Vec *v1, GF_Vec *v2, Fixed *dist) |
2439 | 0 | { |
2440 | 0 | Fixed u, v, det; |
2441 | 0 | GF_Vec edge1, edge2, tvec, pvec, qvec; |
2442 | | /* find vectors for two edges sharing vert0 */ |
2443 | 0 | gf_vec_diff(edge1, *v1, *v0); |
2444 | 0 | gf_vec_diff(edge2, *v2, *v0); |
2445 | | /* begin calculating determinant - also used to calculate U parameter */ |
2446 | 0 | pvec = gf_vec_cross(ray->dir, edge2); |
2447 | | /* if determinant is near zero, ray lies in plane of triangle */ |
2448 | 0 | det = gf_vec_dot(edge1, pvec); |
2449 | 0 | if (ABS(det) < FIX_EPSILON) return GF_FALSE; |
2450 | | /* calculate distance from vert0 to ray origin */ |
2451 | 0 | gf_vec_diff(tvec, ray->orig, *v0); |
2452 | | /* calculate U parameter and test bounds */ |
2453 | 0 | u = gf_divfix(gf_vec_dot(tvec, pvec), det); |
2454 | 0 | if ((u < 0) || (u > FIX_ONE)) return GF_FALSE; |
2455 | | /* prepare to test V parameter */ |
2456 | 0 | qvec = gf_vec_cross(tvec, edge1); |
2457 | | /* calculate V parameter and test bounds */ |
2458 | 0 | v = gf_divfix(gf_vec_dot(ray->dir, qvec), det); |
2459 | 0 | if ((v < 0) || (u + v > FIX_ONE)) return GF_FALSE; |
2460 | | #ifdef GPAC_FIXED_POINT |
2461 | | #define VSCALE 4096 |
2462 | | det /= VSCALE; |
2463 | | qvec.x /= VSCALE; |
2464 | | qvec.y /= VSCALE; |
2465 | | qvec.z /= VSCALE; |
2466 | | #undef VSCALE |
2467 | | #endif |
2468 | | /* calculate t, ray intersects triangle */ |
2469 | 0 | *dist = gf_divfix(gf_vec_dot(edge2, qvec), det); |
2470 | 0 | return GF_TRUE; |
2471 | 0 | } |
2472 | | |
2473 | | #if 0 //unused |
2474 | | Bool gf_ray_hit_triangle_backcull(GF_Ray *ray, GF_Vec *v0, GF_Vec *v1, GF_Vec *v2, Fixed *dist) |
2475 | | { |
2476 | | Fixed u, v, det; |
2477 | | GF_Vec edge1, edge2, tvec, pvec, qvec; |
2478 | | /* find vectors for two edges sharing vert0 */ |
2479 | | gf_vec_diff(edge1, *v1, *v0); |
2480 | | gf_vec_diff(edge2, *v2, *v0); |
2481 | | /* begin calculating determinant - also used to calculate U parameter */ |
2482 | | pvec = gf_vec_cross(ray->dir, edge2); |
2483 | | /* if determinant is near zero, ray lies in plane of triangle */ |
2484 | | det = gf_vec_dot(edge1, pvec); |
2485 | | if (det < FIX_EPSILON) return GF_FALSE; |
2486 | | /* calculate distance from vert0 to ray origin */ |
2487 | | gf_vec_diff(tvec, ray->orig, *v0); |
2488 | | /* calculate U parameter and test bounds */ |
2489 | | u = gf_vec_dot(tvec, pvec); |
2490 | | if ((u < 0) || (u > det)) return GF_FALSE; |
2491 | | /* prepare to test V parameter */ |
2492 | | qvec = gf_vec_cross(tvec, edge1); |
2493 | | /* calculate V parameter and test bounds */ |
2494 | | v = gf_vec_dot(ray->dir, qvec); |
2495 | | if ((v < 0) || (u + v > det)) return GF_FALSE; |
2496 | | /* calculate t, scale parameters, ray intersects triangle */ |
2497 | | *dist = gf_divfix(gf_vec_dot(edge2, qvec), det); |
2498 | | return GF_TRUE; |
2499 | | } |
2500 | | #endif |
2501 | | |
2502 | | GF_EXPORT |
2503 | | GF_Vec gf_closest_point_to_line(GF_Vec line_pt, GF_Vec line_vec, GF_Vec pt) |
2504 | 0 | { |
2505 | 0 | GF_Vec c; |
2506 | 0 | Fixed t; |
2507 | 0 | gf_vec_diff(c, pt, line_pt); |
2508 | 0 | t = gf_vec_dot(line_vec, c); |
2509 | 0 | c = gf_vec_scale(line_vec, t); |
2510 | 0 | gf_vec_add(c, c, line_pt); |
2511 | 0 | return c; |
2512 | 0 | } |
2513 | | |
2514 | | |
2515 | | GF_EXPORT |
2516 | | GF_Vec4 gf_quat_from_matrix(GF_Matrix *mx) |
2517 | 0 | { |
2518 | 0 | GF_Vec4 res; |
2519 | 0 | Fixed diagonal, s; |
2520 | 0 | diagonal = mx->m[0] + mx->m[5] + mx->m[10]; |
2521 | |
|
2522 | 0 | if (diagonal > 0) { |
2523 | 0 | s = gf_sqrt(diagonal + FIX_ONE); |
2524 | 0 | res.q = s / 2; |
2525 | 0 | s = gf_invfix(2*s); |
2526 | 0 | res.x = gf_mulfix(mx->m[6] - mx->m[9], s); |
2527 | 0 | res.y = gf_mulfix(mx->m[8] - mx->m[2], s); |
2528 | 0 | res.z = gf_mulfix(mx->m[1] - mx->m[4], s); |
2529 | 0 | } else { |
2530 | 0 | Fixed q[4]; |
2531 | 0 | u32 i, j, k; |
2532 | 0 | static const u32 next[3] = { 1, 2, 0 }; |
2533 | 0 | i = 0; |
2534 | 0 | if (mx->m[5] > mx->m[0]) { |
2535 | 0 | i = 1; |
2536 | 0 | } |
2537 | 0 | if (mx->m[10] > mx->m[4*i+i]) { |
2538 | 0 | i = 2; |
2539 | 0 | } |
2540 | 0 | j = next[i]; |
2541 | 0 | k = next[j]; |
2542 | 0 | s = gf_sqrt(FIX_ONE + mx->m[4*i + i] - (mx->m[4*j+j] + mx->m[4*k+k]) ); |
2543 | 0 | q[i] = s / 2; |
2544 | 0 | if (s != 0) { |
2545 | 0 | s = gf_invfix(2*s); |
2546 | 0 | } |
2547 | 0 | q[3] = gf_mulfix(mx->m[4*j+k] - mx->m[4*k+j], s); |
2548 | 0 | q[j] = gf_mulfix(mx->m[4*i+j] + mx->m[4*j+i], s); |
2549 | 0 | q[k] = gf_mulfix(mx->m[4*i+k] + mx->m[4*k+i], s); |
2550 | 0 | res.x = q[0]; |
2551 | 0 | res.y = q[1]; |
2552 | 0 | res.z = q[2]; |
2553 | 0 | res.q = q[3]; |
2554 | 0 | } |
2555 | 0 | return res; |
2556 | 0 | } |
2557 | | |
2558 | | GF_EXPORT |
2559 | | GF_Vec4 gf_quat_to_rotation(GF_Vec4 *quat) |
2560 | 0 | { |
2561 | 0 | GF_Vec4 r; |
2562 | 0 | Fixed val = gf_acos(quat->q); |
2563 | 0 | if (val == 0) { |
2564 | 0 | r.x = r.y = 0; |
2565 | 0 | r.z = FIX_ONE; |
2566 | 0 | r.q = 0; |
2567 | 0 | } else { |
2568 | 0 | GF_Vec axis; |
2569 | 0 | Fixed sin_val = gf_sin(val); |
2570 | 0 | axis.x = gf_divfix(quat->x, sin_val); |
2571 | 0 | axis.y = gf_divfix(quat->y, sin_val); |
2572 | 0 | axis.z = gf_divfix(quat->z, sin_val); |
2573 | 0 | gf_vec_norm(&axis); |
2574 | 0 | r.x = axis.x; |
2575 | 0 | r.y = axis.y; |
2576 | 0 | r.z = axis.z; |
2577 | 0 | r.q= 2 * val; |
2578 | 0 | } |
2579 | 0 | return r; |
2580 | 0 | } |
2581 | | |
2582 | | GF_EXPORT |
2583 | | GF_Vec4 gf_quat_from_rotation(GF_Vec4 rot) |
2584 | 0 | { |
2585 | 0 | GF_Vec4 res; |
2586 | 0 | Fixed s; |
2587 | 0 | Fixed scale = gf_sqrt( gf_mulfix(rot.x, rot.x) + gf_mulfix(rot.y, rot.y) + gf_mulfix(rot.z, rot.z)); |
2588 | | |
2589 | | /* no rotation - use (multiplication ???) identity quaternion */ |
2590 | 0 | if (scale == 0) { |
2591 | 0 | res.q = FIX_ONE; |
2592 | 0 | res.x = 0; |
2593 | 0 | res.y = 0; |
2594 | 0 | res.z = 0; |
2595 | 0 | } else { |
2596 | 0 | s = gf_sin(rot.q/2); |
2597 | 0 | res.q = gf_cos(rot.q / 2); |
2598 | 0 | res.x = gf_muldiv(s, rot.x, scale); |
2599 | 0 | res.y = gf_muldiv(s, rot.y, scale); |
2600 | 0 | res.z = gf_muldiv(s, rot.z, scale); |
2601 | 0 | gf_quat_norm(res); |
2602 | 0 | } |
2603 | 0 | return res; |
2604 | 0 | } |
2605 | | |
2606 | | GF_EXPORT |
2607 | | GF_Vec4 gf_quat_from_axis_cos(GF_Vec axis, Fixed cos_a) |
2608 | 0 | { |
2609 | 0 | GF_Vec4 r; |
2610 | 0 | if (cos_a < -FIX_ONE) cos_a = -FIX_ONE; |
2611 | 0 | else if (cos_a > FIX_ONE) cos_a = FIX_ONE; |
2612 | 0 | r.x = axis.x; |
2613 | 0 | r.y = axis.y; |
2614 | 0 | r.z = axis.z; |
2615 | 0 | r.q = gf_acos(cos_a); |
2616 | 0 | return gf_quat_from_rotation(r); |
2617 | 0 | } |
2618 | | |
2619 | | static void gf_quat_conjugate(GF_Vec4 *quat) |
2620 | 0 | { |
2621 | 0 | quat->x *= -1; |
2622 | 0 | quat->y *= -1; |
2623 | 0 | quat->z *= -1; |
2624 | 0 | } |
2625 | | |
2626 | | GF_EXPORT |
2627 | | GF_Vec4 gf_quat_get_inv(GF_Vec4 *quat) |
2628 | 0 | { |
2629 | 0 | GF_Vec4 ret = *quat; |
2630 | 0 | gf_quat_conjugate(&ret); |
2631 | 0 | gf_quat_norm(ret); |
2632 | 0 | return ret; |
2633 | 0 | } |
2634 | | |
2635 | | |
2636 | | GF_EXPORT |
2637 | | GF_Vec4 gf_quat_multiply(GF_Vec4 *q1, GF_Vec4 *q2) |
2638 | 0 | { |
2639 | 0 | GF_Vec4 ret; |
2640 | 0 | ret.q = gf_mulfix(q1->q, q2->q) - gf_mulfix(q1->x, q2->x) - gf_mulfix(q1->y, q2->y) - gf_mulfix(q1->z, q2->z); |
2641 | 0 | ret.x = gf_mulfix(q1->q, q2->x) + gf_mulfix(q1->x, q2->q) + gf_mulfix(q1->y, q2->z) - gf_mulfix(q1->z, q2->y); |
2642 | 0 | ret.y = gf_mulfix(q1->q, q2->y) + gf_mulfix(q1->y, q2->q) - gf_mulfix(q1->x, q2->z) + gf_mulfix(q1->z, q2->x); |
2643 | 0 | ret.z = gf_mulfix(q1->q, q2->z) + gf_mulfix(q1->z, q2->q) + gf_mulfix(q1->x, q2->y) - gf_mulfix(q1->y, q2->x); |
2644 | 0 | return ret; |
2645 | 0 | } |
2646 | | |
2647 | | GF_EXPORT |
2648 | | GF_Vec gf_quat_rotate(GF_Vec4 *quat, GF_Vec *vec) |
2649 | 0 | { |
2650 | 0 | GF_Vec ret; |
2651 | 0 | GF_Vec4 q_v, q_i, q_r1, q_r2; |
2652 | 0 | q_v.q = 0; |
2653 | 0 | q_v.x = vec->x; |
2654 | 0 | q_v.y = vec->y; |
2655 | 0 | q_v.z = vec->z; |
2656 | 0 | q_i = gf_quat_get_inv(quat); |
2657 | 0 | q_r1 = gf_quat_multiply(&q_v, &q_i); |
2658 | 0 | q_r2 = gf_quat_multiply(quat, &q_r1); |
2659 | 0 | ret.x = q_r2.x; |
2660 | 0 | ret.y = q_r2.y; |
2661 | 0 | ret.z = q_r2.z; |
2662 | 0 | return ret; |
2663 | 0 | } |
2664 | | |
2665 | | /* |
2666 | | * Code from www.gamasutra.com/features/19980703/quaternions_01.htm, |
2667 | | * Listing 5. |
2668 | | * |
2669 | | * SLERP(p, q, t) = [p sin((1 - t)a) + q sin(ta)] / sin(a) |
2670 | | * |
2671 | | * where a is the arc angle, quaternions pq = cos(q) and 0 <= t <= 1 |
2672 | | */ |
2673 | | GF_EXPORT |
2674 | | GF_Vec4 gf_quat_slerp(GF_Vec4 q1, GF_Vec4 q2, Fixed frac) |
2675 | 0 | { |
2676 | 0 | GF_Vec4 res; |
2677 | 0 | Fixed omega, cosom, sinom, scale0, scale1, q2_array[4]; |
2678 | |
|
2679 | 0 | cosom = gf_mulfix(q1.x, q2.x) + gf_mulfix(q1.y, q2.y) + gf_mulfix(q1.z, q2.z) + gf_mulfix(q1.q, q2.q); |
2680 | 0 | if (cosom < 0) { |
2681 | 0 | cosom = -cosom; |
2682 | 0 | q2_array[0] = -q2.x; |
2683 | 0 | q2_array[1] = -q2.y; |
2684 | 0 | q2_array[2] = -q2.z; |
2685 | 0 | q2_array[3] = -q2.q; |
2686 | 0 | } else { |
2687 | 0 | q2_array[0] = q2.x; |
2688 | 0 | q2_array[1] = q2.y; |
2689 | 0 | q2_array[2] = q2.z; |
2690 | 0 | q2_array[3] = q2.q; |
2691 | 0 | } |
2692 | | |
2693 | | /* calculate coefficients */ |
2694 | 0 | if ((FIX_ONE - cosom) > FIX_EPSILON) { |
2695 | 0 | omega = gf_acos(cosom); |
2696 | 0 | sinom = gf_sin(omega); |
2697 | 0 | scale0 = gf_divfix(gf_sin( gf_mulfix(FIX_ONE - frac, omega)), sinom); |
2698 | 0 | scale1 = gf_divfix(gf_sin( gf_mulfix(frac, omega)), sinom); |
2699 | 0 | } else { |
2700 | | /* q1 & q2 are very close, so do linear interpolation */ |
2701 | 0 | scale0 = FIX_ONE - frac; |
2702 | 0 | scale1 = frac; |
2703 | 0 | } |
2704 | 0 | res.x = gf_mulfix(scale0, q1.x) + gf_mulfix(scale1, q2_array[0]); |
2705 | 0 | res.y = gf_mulfix(scale0, q1.y) + gf_mulfix(scale1, q2_array[1]); |
2706 | 0 | res.z = gf_mulfix(scale0, q1.z) + gf_mulfix(scale1, q2_array[2]); |
2707 | 0 | res.q = gf_mulfix(scale0, q1.q) + gf_mulfix(scale1, q2_array[3]); |
2708 | 0 | return res; |
2709 | 0 | } |
2710 | | |
2711 | | |
2712 | | /*update center & radius & is_set flag*/ |
2713 | | GF_EXPORT |
2714 | | void gf_bbox_refresh(GF_BBox *b) |
2715 | 0 | { |
2716 | 0 | GF_Vec v; |
2717 | 0 | gf_vec_add(v, b->min_edge, b->max_edge); |
2718 | 0 | b->center = gf_vec_scale(v, FIX_ONE / 2); |
2719 | 0 | gf_vec_diff(v, b->max_edge, b->min_edge); |
2720 | 0 | b->radius = gf_vec_len(v) / 2; |
2721 | 0 | b->is_set = GF_TRUE; |
2722 | 0 | } |
2723 | | |
2724 | | GF_EXPORT |
2725 | | void gf_bbox_from_rect(GF_BBox *box, GF_Rect *rc) |
2726 | 0 | { |
2727 | 0 | box->min_edge.x = rc->x; |
2728 | 0 | box->min_edge.y = rc->y - rc->height; |
2729 | 0 | box->min_edge.z = 0; |
2730 | 0 | box->max_edge.x = rc->x + rc->width; |
2731 | 0 | box->max_edge.y = rc->y; |
2732 | 0 | box->max_edge.z = 0; |
2733 | 0 | gf_bbox_refresh(box); |
2734 | 0 | } |
2735 | | |
2736 | | GF_EXPORT |
2737 | | void gf_rect_from_bbox(GF_Rect *rc, GF_BBox *box) |
2738 | 0 | { |
2739 | 0 | rc->x = box->min_edge.x; |
2740 | 0 | rc->y = box->max_edge.y; |
2741 | 0 | rc->width = box->max_edge.x - box->min_edge.x; |
2742 | 0 | rc->height = box->max_edge.y - box->min_edge.y; |
2743 | 0 | } |
2744 | | |
2745 | | GF_EXPORT |
2746 | | void gf_bbox_grow_point(GF_BBox *box, GF_Vec pt) |
2747 | 0 | { |
2748 | 0 | if (pt.x > box->max_edge.x) box->max_edge.x = pt.x; |
2749 | 0 | if (pt.y > box->max_edge.y) box->max_edge.y = pt.y; |
2750 | 0 | if (pt.z > box->max_edge.z) box->max_edge.z = pt.z; |
2751 | 0 | if (pt.x < box->min_edge.x) box->min_edge.x = pt.x; |
2752 | 0 | if (pt.y < box->min_edge.y) box->min_edge.y = pt.y; |
2753 | 0 | if (pt.z < box->min_edge.z) box->min_edge.z = pt.z; |
2754 | 0 | } |
2755 | | |
2756 | | GF_EXPORT |
2757 | | void gf_bbox_union(GF_BBox *b1, GF_BBox *b2) |
2758 | 0 | { |
2759 | 0 | if (b2->is_set) { |
2760 | 0 | if (!b1->is_set) { |
2761 | 0 | *b1 = *b2; |
2762 | 0 | } else { |
2763 | 0 | gf_bbox_grow_point(b1, b2->min_edge); |
2764 | 0 | gf_bbox_grow_point(b1, b2->max_edge); |
2765 | 0 | gf_bbox_refresh(b1); |
2766 | 0 | } |
2767 | 0 | } |
2768 | 0 | } |
2769 | | |
2770 | | GF_EXPORT |
2771 | | Bool gf_bbox_equal(GF_BBox *b1, GF_BBox *b2) |
2772 | 0 | { |
2773 | 0 | return (gf_vec_equal(b1->min_edge, b2->min_edge) && gf_vec_equal(b1->max_edge, b2->max_edge)); |
2774 | 0 | } |
2775 | | |
2776 | | GF_EXPORT |
2777 | | Bool gf_bbox_point_inside(GF_BBox *box, GF_Vec *p) |
2778 | 0 | { |
2779 | 0 | return (p->x >= box->min_edge.x && p->x <= box->max_edge.x && |
2780 | 0 | p->y >= box->min_edge.y && p->y <= box->max_edge.y && |
2781 | 0 | p->z >= box->min_edge.z && p->z <= box->max_edge.z); |
2782 | 0 | } |
2783 | | |
2784 | | /*vertices are ordered to respect p vertex indexes (vertex from bbox closer to plane) |
2785 | | and so that n-vertex (vertex from bbox farther from plane) is 7-p_vx_idx*/ |
2786 | | GF_EXPORT |
2787 | | void gf_bbox_get_vertices(GF_Vec bmin, GF_Vec bmax, GF_Vec *vecs) |
2788 | 0 | { |
2789 | 0 | vecs[0].x = vecs[1].x = vecs[2].x = vecs[3].x = bmax.x; |
2790 | 0 | vecs[4].x = vecs[5].x = vecs[6].x = vecs[7].x = bmin.x; |
2791 | 0 | vecs[0].y = vecs[1].y = vecs[4].y = vecs[5].y = bmax.y; |
2792 | 0 | vecs[2].y = vecs[3].y = vecs[6].y = vecs[7].y = bmin.y; |
2793 | 0 | vecs[0].z = vecs[2].z = vecs[4].z = vecs[6].z = bmax.z; |
2794 | 0 | vecs[1].z = vecs[3].z = vecs[5].z = vecs[7].z = bmin.z; |
2795 | 0 | } |
2796 | | |
2797 | | |
2798 | | GF_EXPORT |
2799 | | void gf_mx_apply_plane(GF_Matrix *mx, GF_Plane *plane) |
2800 | 0 | { |
2801 | 0 | GF_Vec pt, end; |
2802 | | /*get pt*/ |
2803 | 0 | pt = gf_vec_scale(plane->normal, -plane->d); |
2804 | 0 | gf_vec_add(end, pt, plane->normal); |
2805 | 0 | gf_mx_apply_vec(mx, &pt); |
2806 | 0 | gf_mx_apply_vec(mx, &end); |
2807 | 0 | gf_vec_diff(plane->normal, end, pt); |
2808 | 0 | gf_vec_norm(&plane->normal); |
2809 | 0 | plane->d = - gf_vec_dot(pt, plane->normal); |
2810 | 0 | } |
2811 | | |
2812 | | GF_EXPORT |
2813 | | Fixed gf_plane_get_distance(GF_Plane *plane, GF_Vec *p) |
2814 | 0 | { |
2815 | 0 | return gf_vec_dot(*p, plane->normal) + plane->d; |
2816 | 0 | } |
2817 | | |
2818 | | |
2819 | | /*return p-vertex index (vertex from bbox closer to plane) - index range from 0 to 8*/ |
2820 | | GF_EXPORT |
2821 | | u32 gf_plane_get_p_vertex_idx(GF_Plane *p) |
2822 | 0 | { |
2823 | 0 | if (p->normal.x>=0) { |
2824 | 0 | if (p->normal.y>=0) return (p->normal.z>=0) ? 0 : 1; |
2825 | 0 | return (p->normal.z>=0) ? 2 : 3; |
2826 | 0 | } else { |
2827 | 0 | if (p->normal.y>=0) return (p->normal.z>=0) ? 4 : 5; |
2828 | 0 | return (p->normal.z>=0) ? 6 : 7; |
2829 | 0 | } |
2830 | 0 | } |
2831 | | |
2832 | | |
2833 | | GF_EXPORT |
2834 | | u32 gf_bbox_plane_relation(GF_BBox *box, GF_Plane *p) |
2835 | 0 | { |
2836 | 0 | GF_Vec nearv, farv; |
2837 | 0 | nearv = box->max_edge; |
2838 | 0 | farv = box->min_edge; |
2839 | 0 | if (p->normal.x > 0) { |
2840 | 0 | nearv.x = box->min_edge.x; |
2841 | 0 | farv.x = box->max_edge.x; |
2842 | 0 | } |
2843 | 0 | if (p->normal.y > 0) { |
2844 | 0 | nearv.y = box->min_edge.y; |
2845 | 0 | farv.y = box->max_edge.y; |
2846 | 0 | } |
2847 | 0 | if (p->normal.z > 0) { |
2848 | 0 | nearv.z = box->min_edge.z; |
2849 | 0 | farv.z = box->max_edge.z; |
2850 | 0 | } |
2851 | 0 | if (gf_vec_dot(p->normal, nearv) + p->d > 0) return GF_BBOX_FRONT; |
2852 | 0 | if (gf_vec_dot(p->normal, farv) + p->d > 0) return GF_BBOX_INTER; |
2853 | 0 | return GF_BBOX_BACK; |
2854 | 0 | } |
2855 | | |
2856 | | |
2857 | | GF_EXPORT |
2858 | | u32 gf_get_next_pow2(u32 s) |
2859 | 0 | { |
2860 | 0 | u32 res = 1; |
2861 | 0 | while (s > res) { |
2862 | 0 | res <<= 1; |
2863 | 0 | } |
2864 | 0 | return res; |
2865 | 0 | } |
2866 | | |
2867 | | |
2868 | | #endif //DISABLE_MATHS |