// SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1999-2014 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. // See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- /// \file m_fixed.h /// \brief Fixed point arithmetics implementation /// Fixed point, 32bit as 16.16. #ifndef __M_FIXED__ #define __M_FIXED__ #include "doomtype.h" #ifdef __GNUC__ #include #endif #ifdef _WIN32_WCE #include "sdl/SRB2CE/cehelp.h" #endif /*! \brief bits of the fraction */ #define FRACBITS 16 /*! \brief units of the fraction */ #define FRACUNIT (1<> 16); \ } /** \brief The DMulScale16 function \param a a parameter of type fixed_t \param b a parameter of type fixed_t \param c a parameter of type fixed_t \param d a parameter of type fixed_t \return fixed_t */ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t DMulScale16(fixed_t a, fixed_t b, fixed_t c, fixed_t d) \ { \ return (fixed_t)((((INT64)a * (INT64)b) + ((INT64)c * (INT64)d)) >> 16); \ } #if defined (__WATCOMC__) && FRACBITS == 16 #pragma aux FixedMul = \ "imul ebx", \ "shrd eax,edx,16" \ parm [eax] [ebx] \ value [eax] \ modify exact [eax edx] #pragma aux FixedDiv2 = \ "cdq", \ "shld edx,eax,16", \ "sal eax,16", \ "idiv ebx" \ parm [eax] [ebx] \ value [eax] \ modify exact [eax edx] #elif defined (__GNUC__) && defined (__i386__) && !defined (NOASM) // DJGPP, i386 linux, cygwin or mingw FUNCMATH FUNCINLINE static inline fixed_t FixedMul(fixed_t a, fixed_t b) // asm { fixed_t ret; asm ( "imull %2;" // a*b "shrdl %3,%%edx,%0;" // shift logical right FRACBITS bits :"=a" (ret) // eax is always the result and the first operand (%0,%1) :"0" (a), "r" (b) // and %2 is what we use imull on with what in %1 , "I" (FRACBITS) // %3 holds FRACBITS (normally 16) :"%cc", "%edx" // edx and condition codes clobbered ); return ret; } FUNCMATH FUNCINLINE static inline fixed_t FixedDiv2(fixed_t a, fixed_t b) { fixed_t ret; asm ( "movl %1,%%edx;" // these two instructions allow the next two to pair, on the Pentium processor. "sarl $31,%%edx;" // shift arithmetic right 31 on EDX "shldl %3,%1,%%edx;" // DP shift logical left FRACBITS on EDX "sall %3,%0;" // shift arithmetic left FRACBITS on EAX "idivl %2;" // EDX/b = EAX : "=a" (ret) : "0" (a), "r" (b) , "I" (FRACBITS) : "%edx" ); return ret; } #elif defined (__GNUC__) && defined (__arm__) && !defined(__thumb__) && !defined(NOASM) //ARMv4 ASM FUNCMATH FUNCINLINE static inline fixed_t FixedMul(fixed_t a, fixed_t b) // let abuse smull { fixed_t ret; asm ( "smull %[lo], r1, %[a], %[b];" "mov %[lo], %[lo], lsr %3;" "orr %[lo], %[lo], r1, lsl %3;" : [lo] "=&r" (ret) // rhi, rlo and rm must be distinct registers : [a] "r" (a), [b] "r" (b) , "i" (FRACBITS) : "r1" ); return ret; } #define __USE_C_FIXEDDIV__ // no double or asm div in ARM land #elif defined (__GNUC__) && defined (__ppc__) && !defined(NOASM) && 0 // WII: PPC CPU FUNCMATH FUNCINLINE static inline fixed_t FixedMul(fixed_t a, fixed_t b) // asm { fixed_t ret, hi, lo; asm ( "mullw %0, %2, %3;" "mulhw %1, %2, %3" : "=r" (hi), "=r" (lo) : "r" (a), "r" (b) , "I" (FRACBITS) ); ret = (INT64)((hi>>FRACBITS)+lo)<>FRACBITS)+b)<> (FRACBITS-2)) >= abs(b)) return (a^b) < 0 ? INT32_MIN : INT32_MAX; return FixedDiv2(a, b); } /** \brief The FixedRem function \param x fixed_t number \param y fixed_t number \return remainder of dividing x by y */ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedRem(fixed_t x, fixed_t y) { const boolean n = x < 0; x = abs(x); while (x >= y) x -= y; if (n) return -x; else return x; } /** \brief The FixedSqrt function \param x fixed_t number \return sqrt(x) */ FUNCMATH fixed_t FixedSqrt(fixed_t x); /** \brief The FixedHypot function \param x fixed_t number \param y fixed_t number \return sqrt(x*x+y*y) */ FUNCMATH fixed_t FixedHypot(fixed_t x, fixed_t y); /** \brief The FixedFloor function \param x fixed_t number \return floor(x) */ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedFloor(fixed_t x) { const fixed_t a = abs(x); //absolute of x const fixed_t i = (a>>FRACBITS)<>FRACBITS)< 0) return x-f; else return x+f; } return INT32_MIN; } /** \brief The FixedCeil function \param x fixed_t number \return ceil(x) */ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedCeil(fixed_t x) { const fixed_t a = abs(x); //absolute of x const fixed_t i = (a>>FRACBITS)<>FRACBITS)< 0) return x+(FRACUNIT-f); else return x-(FRACUNIT-f); } return INT32_MAX; } #ifdef NEED_FIXED_VECTOR typedef struct { fixed_t x; fixed_t y; } vector2_t; vector2_t *FV2_Load(vector2_t *vec, fixed_t x, fixed_t y); vector2_t *FV2_UnLoad(vector2_t *vec, fixed_t *x, fixed_t *y); vector2_t *FV2_Copy(vector2_t *a_o, const vector2_t *a_i); vector2_t *FV2_AddEx(const vector2_t *a_i, const vector2_t *a_c, vector2_t *a_o); vector2_t *FV2_Add(vector2_t *a_i, const vector2_t *a_c); vector2_t *FV2_SubEx(const vector2_t *a_i, const vector2_t *a_c, vector2_t *a_o); vector2_t *FV2_Sub(vector2_t *a_i, const vector2_t *a_c); vector2_t *FV2_MulEx(const vector2_t *a_i, fixed_t a_c, vector2_t *a_o); vector2_t *FV2_Mul(vector2_t *a_i, fixed_t a_c); vector2_t *FV2_DivideEx(const vector2_t *a_i, fixed_t a_c, vector2_t *a_o); vector2_t *FV2_Divide(vector2_t *a_i, fixed_t a_c); vector2_t *FV2_Midpoint(const vector2_t *a_1, const vector2_t *a_2, vector2_t *a_o); fixed_t FV2_Distance(const vector2_t *p1, const vector2_t *p2); fixed_t FV2_Magnitude(const vector2_t *a_normal); fixed_t FV2_NormalizeEx(const vector2_t *a_normal, vector2_t *a_o); fixed_t FV2_Normalize(vector2_t *a_normal); vector2_t *FV2_NegateEx(const vector2_t *a_1, vector2_t *a_o); vector2_t *FV2_Negate(vector2_t *a_1); boolean FV2_Equal(const vector2_t *a_1, const vector2_t *a_2); fixed_t FV2_Dot(const vector2_t *a_1, const vector2_t *a_2); vector2_t *FV2_Point2Vec (const vector2_t *point1, const vector2_t *point2, vector2_t *a_o); typedef struct { fixed_t x, y, z; } vector3_t; vector3_t *FV3_Load(vector3_t *vec, fixed_t x, fixed_t y, fixed_t z); vector3_t *FV3_UnLoad(vector3_t *vec, fixed_t *x, fixed_t *y, fixed_t *z); vector3_t *FV3_Copy(vector3_t *a_o, const vector3_t *a_i); vector3_t *FV3_AddEx(const vector3_t *a_i, const vector3_t *a_c, vector3_t *a_o); vector3_t *FV3_Add(vector3_t *a_i, const vector3_t *a_c); vector3_t *FV3_SubEx(const vector3_t *a_i, const vector3_t *a_c, vector3_t *a_o); vector3_t *FV3_Sub(vector3_t *a_i, const vector3_t *a_c); vector3_t *FV3_MulEx(const vector3_t *a_i, fixed_t a_c, vector3_t *a_o); vector3_t *FV3_Mul(vector3_t *a_i, fixed_t a_c); vector3_t *FV3_DivideEx(const vector3_t *a_i, fixed_t a_c, vector3_t *a_o); vector3_t *FV3_Divide(vector3_t *a_i, fixed_t a_c); vector3_t *FV3_Midpoint(const vector3_t *a_1, const vector3_t *a_2, vector3_t *a_o); fixed_t FV3_Distance(const vector3_t *p1, const vector3_t *p2); fixed_t FV3_Magnitude(const vector3_t *a_normal); fixed_t FV3_NormalizeEx(const vector3_t *a_normal, vector3_t *a_o); fixed_t FV3_Normalize(vector3_t *a_normal); vector3_t *FV3_NegateEx(const vector3_t *a_1, vector3_t *a_o); vector3_t *FV3_Negate(vector3_t *a_1); boolean FV3_Equal(const vector3_t *a_1, const vector3_t *a_2); fixed_t FV3_Dot(const vector3_t *a_1, const vector3_t *a_2); vector3_t *FV3_Cross(const vector3_t *a_1, const vector3_t *a_2, vector3_t *a_o); vector3_t *FV3_ClosestPointOnLine(const vector3_t *Line, const vector3_t *p, vector3_t *out); void FV3_ClosestPointOnTriangle(const vector3_t *tri, const vector3_t *point, vector3_t *result); vector3_t *FV3_Point2Vec(const vector3_t *point1, const vector3_t *point2, vector3_t *a_o); void FV3_Normal(const vector3_t *a_triangle, vector3_t *a_normal); fixed_t FV3_PlaneDistance(const vector3_t *a_normal, const vector3_t *a_point); boolean FV3_IntersectedPlane(const vector3_t *a_triangle, const vector3_t *a_line, vector3_t *a_normal, fixed_t *originDistance); fixed_t FV3_PlaneIntersection(const vector3_t *pOrigin, const vector3_t *pNormal, const vector3_t *rOrigin, const vector3_t *rVector); fixed_t FV3_IntersectRaySphere(const vector3_t *rO, const vector3_t *rV, const vector3_t *sO, fixed_t sR); vector3_t *FV3_IntersectionPoint(const vector3_t *vNormal, const vector3_t *vLine, fixed_t distance, vector3_t *ReturnVec); UINT8 FV3_PointOnLineSide(const vector3_t *point, const vector3_t *line); boolean FV3_PointInsideBox(const vector3_t *point, const vector3_t *box); typedef struct { fixed_t m[16]; } matrix_t; void FM_LoadIdentity(matrix_t* matrix); void FM_CreateObjectMatrix(matrix_t *matrix, fixed_t x, fixed_t y, fixed_t z, fixed_t anglex, fixed_t angley, fixed_t anglez, fixed_t upx, fixed_t upy, fixed_t upz, fixed_t radius); void FM_MultMatrixVec3(const matrix_t *matrix, const vector3_t *vec, vector3_t *out); void FM_MultMatrix(matrix_t *dest, const matrix_t *multme); void FM_Translate(matrix_t *dest, fixed_t x, fixed_t y, fixed_t z); void FM_Scale(matrix_t *dest, fixed_t x, fixed_t y, fixed_t z); #endif // defined NEED_FIXED_VECTOR #endif //m_fixed.h