//---------------------------------------------------------------------------- // // Copyright (C) Microsoft Corporation, 1997. // // d3dflt.h // // Floating-point constants and operations on FP values. // //---------------------------------------------------------------------------- #ifndef _D3DFLT_H_ #define _D3DFLT_H_ #include #include #ifdef __cplusplus extern "C" { #endif typedef union tagFLOATINT32 { FLOAT f; INT32 i; UINT32 u; } FLOATINT32, *PFLOATINT32; // // Type-forcing macros to access FP as integer and vice-versa. // ATTENTION - VC5's optimizer turns these macros into ftol sometimes, // completely breaking them. // Using FLOATINT32 works around the problem but is not as flexible, // so the old code is kept around for the time when the compiler is fixed. // Note that pointer casting with FLOATINT32 fails just as the direct // pointer casting does, so it's not a remedy. // // Use these macros with extreme care. // #define ASFLOAT(i) (*(FLOAT *)&(i)) #define ASINT32(f) (*(INT32 *)&(f)) #define ASUINT32(f) (*(UINT32 *)&(f)) // // FP constants. // // Powers of two for snap values. These should not be used in code. #define CONST_TWOPOW0 1 #define CONST_TWOPOW1 2 #define CONST_TWOPOW2 4 #define CONST_TWOPOW3 8 #define CONST_TWOPOW4 16 #define CONST_TWOPOW5 32 #define CONST_TWOPOW6 64 #define CONST_TWOPOW7 128 #define CONST_TWOPOW8 256 #define CONST_TWOPOW9 512 #define CONST_TWOPOW10 1024 #define CONST_TWOPOW11 2048 #define CONST_TWOPOW12 4096 #define CONST_TWOPOW13 8192 #define CONST_TWOPOW14 16384 #define CONST_TWOPOW15 32768 #define CONST_TWOPOW16 65536 #define CONST_TWOPOW17 131072 #define CONST_TWOPOW18 262144 #define CONST_TWOPOW19 524288 #define CONST_TWOPOW20 1048576 #define CONST_TWOPOW21 2097152 #define CONST_TWOPOW22 4194304 #define CONST_TWOPOW23 8388608 #define CONST_TWOPOW24 16777216 #define CONST_TWOPOW25 33554432 #define CONST_TWOPOW26 67108864 #define CONST_TWOPOW27 134217728 #define CONST_TWOPOW28 268435456 #define CONST_TWOPOW29 536870912 #define CONST_TWOPOW30 1073741824 #define CONST_TWOPOW31 2147483648 #define CONST_TWOPOW32 4294967296 #define CONST_TWOPOW33 8589934592 #define CONST_TWOPOW34 17179869184 #define CONST_TWOPOW35 34359738368 #define CONST_TWOPOW36 68719476736 #define CONST_TWOPOW37 137438953472 #define CONST_TWOPOW38 274877906944 #define CONST_TWOPOW39 549755813888 #define CONST_TWOPOW40 1099511627776 #define CONST_TWOPOW41 2199023255552 #define CONST_TWOPOW42 4398046511104 #define CONST_TWOPOW43 8796093022208 #define CONST_TWOPOW44 17592186044416 #define CONST_TWOPOW45 35184372088832 #define CONST_TWOPOW46 70368744177664 #define CONST_TWOPOW47 140737488355328 #define CONST_TWOPOW48 281474976710656 #define CONST_TWOPOW49 562949953421312 #define CONST_TWOPOW50 1125899906842624 #define CONST_TWOPOW51 2251799813685248 #define CONST_TWOPOW52 4503599627370496 #define FLOAT_TWOPOW0 ((FLOAT)(CONST_TWOPOW0)) #define FLOAT_TWOPOW1 ((FLOAT)(CONST_TWOPOW1)) #define FLOAT_TWOPOW2 ((FLOAT)(CONST_TWOPOW2)) #define FLOAT_TWOPOW3 ((FLOAT)(CONST_TWOPOW3)) #define FLOAT_TWOPOW4 ((FLOAT)(CONST_TWOPOW4)) #define FLOAT_TWOPOW5 ((FLOAT)(CONST_TWOPOW5)) #define FLOAT_TWOPOW6 ((FLOAT)(CONST_TWOPOW6)) #define FLOAT_TWOPOW7 ((FLOAT)(CONST_TWOPOW7)) #define FLOAT_TWOPOW8 ((FLOAT)(CONST_TWOPOW8)) #define FLOAT_TWOPOW9 ((FLOAT)(CONST_TWOPOW9)) #define FLOAT_TWOPOW10 ((FLOAT)(CONST_TWOPOW10)) #define FLOAT_TWOPOW11 ((FLOAT)(CONST_TWOPOW11)) #define FLOAT_TWOPOW12 ((FLOAT)(CONST_TWOPOW12)) #define FLOAT_TWOPOW13 ((FLOAT)(CONST_TWOPOW13)) #define FLOAT_TWOPOW14 ((FLOAT)(CONST_TWOPOW14)) #define FLOAT_TWOPOW15 ((FLOAT)(CONST_TWOPOW15)) #define FLOAT_TWOPOW16 ((FLOAT)(CONST_TWOPOW16)) #define FLOAT_TWOPOW17 ((FLOAT)(CONST_TWOPOW17)) #define FLOAT_TWOPOW18 ((FLOAT)(CONST_TWOPOW18)) #define FLOAT_TWOPOW19 ((FLOAT)(CONST_TWOPOW19)) #define FLOAT_TWOPOW20 ((FLOAT)(CONST_TWOPOW20)) #define FLOAT_TWOPOW21 ((FLOAT)(CONST_TWOPOW21)) #define FLOAT_TWOPOW22 ((FLOAT)(CONST_TWOPOW22)) #define FLOAT_TWOPOW23 ((FLOAT)(CONST_TWOPOW23)) #define FLOAT_TWOPOW24 ((FLOAT)(CONST_TWOPOW24)) #define FLOAT_TWOPOW25 ((FLOAT)(CONST_TWOPOW25)) #define FLOAT_TWOPOW26 ((FLOAT)(CONST_TWOPOW26)) #define FLOAT_TWOPOW27 ((FLOAT)(CONST_TWOPOW27)) #define FLOAT_TWOPOW28 ((FLOAT)(CONST_TWOPOW28)) #define FLOAT_TWOPOW29 ((FLOAT)(CONST_TWOPOW29)) #define FLOAT_TWOPOW30 ((FLOAT)(CONST_TWOPOW30)) #define FLOAT_TWOPOW31 ((FLOAT)(CONST_TWOPOW31)) #define FLOAT_TWOPOW32 ((FLOAT)(CONST_TWOPOW32)) #define FLOAT_TWOPOW33 ((FLOAT)(CONST_TWOPOW33)) #define FLOAT_TWOPOW34 ((FLOAT)(CONST_TWOPOW34)) #define FLOAT_TWOPOW35 ((FLOAT)(CONST_TWOPOW35)) #define FLOAT_TWOPOW36 ((FLOAT)(CONST_TWOPOW36)) #define FLOAT_TWOPOW37 ((FLOAT)(CONST_TWOPOW37)) #define FLOAT_TWOPOW38 ((FLOAT)(CONST_TWOPOW38)) #define FLOAT_TWOPOW39 ((FLOAT)(CONST_TWOPOW39)) #define FLOAT_TWOPOW40 ((FLOAT)(CONST_TWOPOW40)) #define FLOAT_TWOPOW41 ((FLOAT)(CONST_TWOPOW41)) #define FLOAT_TWOPOW42 ((FLOAT)(CONST_TWOPOW42)) #define FLOAT_TWOPOW43 ((FLOAT)(CONST_TWOPOW43)) #define FLOAT_TWOPOW44 ((FLOAT)(CONST_TWOPOW44)) #define FLOAT_TWOPOW45 ((FLOAT)(CONST_TWOPOW45)) #define FLOAT_TWOPOW46 ((FLOAT)(CONST_TWOPOW46)) #define FLOAT_TWOPOW47 ((FLOAT)(CONST_TWOPOW47)) #define FLOAT_TWOPOW48 ((FLOAT)(CONST_TWOPOW48)) #define FLOAT_TWOPOW49 ((FLOAT)(CONST_TWOPOW49)) #define FLOAT_TWOPOW50 ((FLOAT)(CONST_TWOPOW50)) #define FLOAT_TWOPOW51 ((FLOAT)(CONST_TWOPOW51)) #define FLOAT_TWOPOW52 ((FLOAT)(CONST_TWOPOW52)) // Values that are smaller than the named value by the smallest // representable amount. Since this depends on the type used // there is no CONST form. #define FLOAT_NEARTWOPOW31 ((FLOAT)2147483583) #define FLOAT_NEARTWOPOW32 ((FLOAT)4294967167) // Value close enough to zero to consider zero. This can't be too small // but it can't be too large. In other words, it's picked by guessing. #define FLOAT_NEARZERO (1e-5f) // General FP constants. #define FLOAT_E ((FLOAT)2.7182818284590452354) // Integer value of first exponent bit in a float. Provides a scaling factor // for exponent values extracted directly from float representation. #define FLOAT_EXPSCALE ((FLOAT)0x00800000) // Integer representation of 1.0f. #define INT32_FLOAT_ONE 0x3f800000 #ifdef _X86_ // All FP values are loaded from memory so declare them all as global // variables. extern FLOAT g_fE; extern FLOAT g_fZero; extern FLOAT g_fNearZero; extern FLOAT g_fHalf; extern FLOAT g_fp95; extern FLOAT g_fOne; extern FLOAT g_fOneMinusEps; extern FLOAT g_fExpScale; extern FLOAT g_fOoExpScale; extern FLOAT g_f255oTwoPow15; extern FLOAT g_fOo255; extern FLOAT g_fOo256; extern FLOAT g_fTwoPow7; extern FLOAT g_fTwoPow8; extern FLOAT g_fTwoPow11; extern FLOAT g_fTwoPow15; extern FLOAT g_fOoTwoPow15; extern FLOAT g_fTwoPow16; extern FLOAT g_fOoTwoPow16; extern FLOAT g_fTwoPow20; extern FLOAT g_fOoTwoPow20; extern FLOAT g_fTwoPow27; extern FLOAT g_fOoTwoPow27; extern FLOAT g_fTwoPow30; extern FLOAT g_fTwoPow31; extern FLOAT g_fNearTwoPow31; extern FLOAT g_fOoTwoPow31; extern FLOAT g_fOoNearTwoPow31; extern FLOAT g_fTwoPow32; extern FLOAT g_fNearTwoPow32; extern FLOAT g_fTwoPow39; extern FLOAT g_fTwoPow47; #else // Leave FP values as constants. #define g_fE FLOAT_E #define g_fNearZero FLOAT_NEARZERO #define g_fZero (0.0f) #define g_fHalf (0.5f) #define g_fp95 (0.95f) #define g_fOne (1.0f) #define g_fOneMinusEps (1.0f - FLT_EPSILON) #define g_fExpScale FLOAT_EXPSCALE #define g_fOoExpScale ((FLOAT)(1.0 / (double)FLOAT_EXPSCALE)) #define g_f255oTwoPow15 ((FLOAT)(255.0 / (double)CONST_TWOPOW15)) #define g_fOo255 ((FLOAT)(1.0 / 255.0)) #define g_fOo256 ((FLOAT)(1.0 / 256.0)) #define g_fTwoPow7 FLOAT_TWOPOW7 #define g_fTwoPow8 FLOAT_TWOPOW8 #define g_fTwoPow11 FLOAT_TWOPOW11 #define g_fTwoPow15 FLOAT_TWOPOW15 #define g_fOoTwoPow15 ((FLOAT)(1.0 / (double)CONST_TWOPOW15)) #define g_fTwoPow16 FLOAT_TWOPOW16 #define g_fOoTwoPow16 ((FLOAT)(1.0 / (double)CONST_TWOPOW16)) #define g_fTwoPow20 FLOAT_TWOPOW20 #define g_fOoTwoPow20 ((FLOAT)(1.0 / (double)CONST_TWOPOW20)) #define g_fTwoPow27 FLOAT_TWOPOW27 #define g_fOoTwoPow27 ((FLOAT)(1.0 / (double)CONST_TWOPOW27)) #define g_fTwoPow30 FLOAT_TWOPOW30 #define g_fTwoPow31 FLOAT_TWOPOW31 #define g_fNearTwoPow31 FLOAT_NEARTWOPOW31 #define g_fOoTwoPow31 ((FLOAT)(1.0 / (double)CONST_TWOPOW31)) #define g_fOoNearTwoPow31 ((FLOAT)(1.0 / ((double)FLOAT_NEARTWOPOW31))) #define g_fTwoPow32 FLOAT_TWOPOW32 #define g_fNearTwoPow32 FLOAT_NEARTWOPOW32 #define g_fTwoPow39 FLOAT_TWOPOW39 #define g_fTwoPow47 FLOAT_TWOPOW47 #endif // _X86_ // // Conversion tables. // // Takes an unsigned byte to a float in [0.0, 1.0]. 257'th entry is // also one to allow overflow. extern FLOAT g_fUInt8ToFloat[257]; // Floating-point pinning values for float-int conversion. extern double g_dSnap[33]; // // x86 FP control for optimized FTOI and single-precision divides. // #ifdef _X86_ #define FPU_GET_MODE(uMode) \ __asm fnstcw WORD PTR uMode #define FPU_SET_MODE(uMode) \ __asm fldcw WORD PTR uMode #define FPU_SAFE_SET_MODE(uMode) \ __asm fnclex \ __asm fldcw WORD PTR uMode #define FPU_MODE_CHOP_ROUND(uMode) \ ((uMode) | 0xc00) #define FPU_MODE_LOW_PRECISION(uMode) \ ((uMode) & 0xfcff) #define FPU_MODE_MASK_EXCEPTIONS(uMode) \ ((uMode) | 0x3f) #if DBG #define ASSERT_CHOP_ROUND() \ { \ WORD cw; \ __asm fnstcw cw \ DDASSERT((cw & 0xc00) == 0xc00); \ } #else #define ASSERT_CHOP_ROUND() #endif // DBG #else // Initialize with zero to avoid use-before-set errors. #define FPU_GET_MODE(uMode) \ ((uMode) = 0) #define FPU_SET_MODE(uMode) #define FPU_SAFE_SET_MODE(uMode) #define FPU_MODE_CHOP_ROUND(uMode) 0 #define FPU_MODE_LOW_PRECISION(uMode) 0 #define FPU_MODE_MASK_EXCEPTIONS(uMode) 0 #define ASSERT_CHOP_ROUND() #endif // _X86_ // // Single-precision FP functions. // May produce invalid results for exceptional or denormal values. // ATTENTION - Alpha exposes float math routines and they may be a small win. // #define COSF(fV) ((FLOAT)cos((double)(fV))) #define SINF(fV) ((FLOAT)sin((double)(fV))) #define SQRTF(fV) ((FLOAT)sqrt((double)(fV))) #define POWF(fV, fE) ((FLOAT)pow((double)(fV), (double)(fE))) // Approximate log and power functions using Jim Blinn's CG&A technique. // Only work for positive values. #ifdef POINTER_CASTING __inline FLOAT APPXLG2F(FLOAT f) { return (FLOAT)(ASINT32(f) - INT32_FLOAT_ONE) * g_fOoExpScale; } __inline FLOAT APPXPOW2F(FLOAT f) { INT32 i = (INT32)(f * g_fExpScale) + INT32_FLOAT_ONE; return ASFLOAT(i); } __inline FLOAT APPXINVF(FLOAT f) { INT32 i = (INT32_FLOAT_ONE << 1) - ASINT32(f); return ASFLOAT(i); } __inline FLOAT APPXSQRTF(FLOAT f) { INT32 i = (ASINT32(f) >> 1) + (INT32_FLOAT_ONE >> 1); return ASFLOAT(i); } __inline FLOAT APPXISQRTF(FLOAT f) { INT32 i = INT32_FLOAT_ONE + (INT32_FLOAT_ONE >> 1) - (ASINT32(f) >> 1); return ASFLOAT(i); } __inline FLOAT APPXPOWF(FLOAT f, FLOAT exp) { INT32 i = (INT32)(exp * (ASINT32(f) - INT32_FLOAT_ONE)) + INT32_FLOAT_ONE; return ASFLOAT(i); } #else __inline FLOAT APPXLG2F(FLOAT f) { FLOATINT32 fi; fi.f = f; return (FLOAT)(fi.i - INT32_FLOAT_ONE) * g_fOoExpScale; } __inline FLOAT APPXPOW2F(FLOAT f) { FLOATINT32 fi; fi.i = (INT32)(f * g_fExpScale) + INT32_FLOAT_ONE; return fi.f; } __inline FLOAT APPXINVF(FLOAT f) { FLOATINT32 fi; fi.f = f; fi.i = (INT32_FLOAT_ONE << 1) - fi.i; return fi.f; } __inline FLOAT APPXSQRTF(FLOAT f) { FLOATINT32 fi; fi.f = f; fi.i = (fi.i >> 1) + (INT32_FLOAT_ONE >> 1); return fi.f; } __inline FLOAT APPXISQRTF(FLOAT f) { FLOATINT32 fi; fi.f = f; fi.i = INT32_FLOAT_ONE + (INT32_FLOAT_ONE >> 1) - (fi.i >> 1); return fi.f; } __inline FLOAT APPXPOWF(FLOAT f, FLOAT exp) { FLOATINT32 fi; fi.f = f; fi.i = (INT32)(exp * (fi.i - INT32_FLOAT_ONE)) + INT32_FLOAT_ONE; return fi.f; } #endif #ifdef _X86_ // Uses a table float __fastcall TableInvSqrt(float value); // Uses Jim Blinn's floating point trick float __fastcall JBInvSqrt(float value); #define ISQRTF(fV) TableInvSqrt(fV); #ifdef POINTER_CASTING // Strip sign bit in integer. __inline FLOAT ABSF(FLOAT f) { UINT32 i = ASUINT32(f) & 0x7fffffff; return ASFLOAT(i); } // Toggle sign bit in integer. __inline FLOAT NEGF(FLOAT f) { UINT32 i = ASUINT32(f) ^ 0x80000000; return ASFLOAT(i); } #else // Strip sign bit in integer. __inline FLOAT ABSF(FLOAT f) { FLOATINT32 fi; fi.f = f; fi.u &= 0x7fffffff; return fi.f; } // Toggle sign bit in integer. __inline FLOAT NEGF(FLOAT f) { FLOATINT32 fi; fi.f = f; fi.u ^= 0x80000000; return fi.f; } #endif // POINTER_CASTING // Requires chop rounding. __inline INT32 SCALED_FRACTION(FLOAT f) { LARGE_INTEGER i; __asm { fld f fmul g_fTwoPow31 fistp i } return i.LowPart; } // Requires chop rounding. __inline INT FTOI(FLOAT f) { LARGE_INTEGER i; __asm { fld f fistp i } return i.LowPart; } // Requires chop rounding. #define ICEILF(f) (FLOAT_LEZ(f) ? FTOI(f) : FTOI((f) + g_fOneMinusEps)) #define CEILF(f) ((FLOAT)ICEILF(f)) #define IFLOORF(f) (FLOAT_LTZ(f) ? FTOI((f) - g_fOneMinusEps) : FTOI(f)) #define FLOORF(f) ((FLOAT)IFLOORF(f)) #else // _X86_ #define ISQRTF(fV) (1.0f / (FLOAT)sqrt((double)(fV))) #define ABSF(f) ((FLOAT)fabs((double)(f))) #define NEGF(f) (-(f)) #define SCALED_FRACTION(f) ((INT32)((f) * g_fTwoPow31)) #define FTOI(f) ((INT)(f)) #define CEILF(f) ((FLOAT)ceil((double)(f))) #define ICEILF(f) ((INT)CEILF(f)) #define FLOORF(f) ((FLOAT)floor((double)(f))) #define IFLOORF(f) ((INT)FLOORF(f)) #endif // _X86_ // // Overlapped divide support. // #ifdef _X86_ // Starts a divide directly from memory. Result field is provided for // compatibility with non-x86 code that does the divide immediately. #define FLD_BEGIN_DIVIDE(Num, Den, Res) { __asm fld Num __asm fdiv Den } #define FLD_BEGIN_IDIVIDE(Num, Den, Res) { __asm fld Num __asm fidiv Den } // Store a divide result directly to memory. #define FSTP_END_DIVIDE(Res) { __asm fstp Res } #else // _X86_ #define FLD_BEGIN_DIVIDE(Num, Den, Res) ((Res) = (Num) / (Den)) #define FLD_BEGIN_IDIVIDE(Num, Den, Res) ((Res) = (Num) / (FLOAT)(Den)) #define FSTP_END_DIVIDE(Res) #endif // _X86_ // // Specialized FP comparison functions. // // On the x86, it's faster to do compares with an integer cast // than it is to do the fcom. // // The zero operations work for all normalized FP numbers, -0 included. // #ifdef _X86_ #define FLOAT_CMP_POS(fa, op, fb) (ASINT32(fa) op ASINT32(fb)) #define FLOAT_CMP_PONE(flt, op) (ASINT32(flt) op INT32_FLOAT_ONE) #ifdef POINTER_CASTING #define FLOAT_GTZ(flt) (ASINT32(flt) > 0) #define FLOAT_LTZ(flt) (ASUINT32(flt) > 0x80000000) #define FLOAT_GEZ(flt) (ASUINT32(flt) <= 0x80000000) #define FLOAT_LEZ(flt) (ASINT32(flt) <= 0) #define FLOAT_EQZ(flt) ((ASUINT32(flt) & 0x7fffffff) == 0) #define FLOAT_NEZ(flt) ((ASUINT32(flt) & 0x7fffffff) != 0) #else __inline int FLOAT_GTZ(FLOAT f) { FLOATINT32 fi; fi.f = f; return fi.i > 0; } __inline int FLOAT_LTZ(FLOAT f) { FLOATINT32 fi; fi.f = f; return fi.u > 0x80000000; } __inline int FLOAT_GEZ(FLOAT f) { FLOATINT32 fi; fi.f = f; return fi.u <= 0x80000000; } __inline int FLOAT_LEZ(FLOAT f) { FLOATINT32 fi; fi.f = f; return fi.i <= 0; } __inline int FLOAT_EQZ(FLOAT f) { FLOATINT32 fi; fi.f = f; return (fi.u & 0x7fffffff) == 0; } __inline int FLOAT_NEZ(FLOAT f) { FLOATINT32 fi; fi.f = f; return (fi.u & 0x7fffffff) != 0; } #endif // POINTER_CASTING #else #define FLOAT_GTZ(flt) ((flt) > g_fZero) #define FLOAT_LTZ(flt) ((flt) < g_fZero) #define FLOAT_GEZ(flt) ((flt) >= g_fZero) #define FLOAT_LEZ(flt) ((flt) <= g_fZero) #define FLOAT_EQZ(flt) ((flt) == g_fZero) #define FLOAT_NEZ(flt) ((flt) != g_fZero) #define FLOAT_CMP_POS(fa, op, fb) ((fa) op (fb)) #define FLOAT_CMP_PONE(flt, op) ((flt) op g_fOne) #endif // _X86_ #ifdef __cplusplus } #endif #endif // #ifndef _D3DFLT_H_