LCOV - code coverage report
Current view: top level - utils - math.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 954 995 95.9 %
Date: 2021-04-29 23:48:07 Functions: 88 89 98.9 %

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

Generated by: LCOV version 1.13