Coverage Report

Created: 2026-03-13 06:55

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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