/******************************Module*Header*******************************\ * Module Name: mcdmath.h * * Various useful defines and macros to do efficient floating-point * processing for MCD drivers. * * Copyright (c) 1996 Microsoft Corporation \**************************************************************************/ #define CASTINT(a) (*((LONG *)&(a))) #define ZERO (MCDFLOAT)0.0 #define __MCDZERO ZERO #define __MCDONE (MCDFLOAT)1.0 #define __MCDHALF (MCDFLOAT)0.5 #define __MCDFIXSCALE (MCDFLOAT)65536.0 #define __MCD_MAX_WINDOW_SIZE_LOG2 14 #define __MCD_VERTEX_FIX_POINT (__MCD_MAX_WINDOW_SIZE_LOG2+1) #define __MCD_VERTEX_X_FIX (1 << __MCD_VERTEX_FIX_POINT) #define __MCD_VERTEX_Y_FIX __MCD_VERTEX_X_FIX #define __MCD_FLOAT_MANTISSA_BITS 23 #define __MCD_FLOAT_MANTISSA_SHIFT 0 #define __MCD_FLOAT_EXPONENT_BIAS 127 #define __MCD_FLOAT_EXPONENT_BITS 8 #define __MCD_FLOAT_EXPONENT_SHIFT 23 #define __MCD_FLOAT_SIGN_SHIFT 31 // If the MSB of a FP number is known then float-to-int conversion // becomes a simple shift and mask // The value must be positive #define __MCD_FIXED_FLOAT_TO_INT(flt, shift) \ ((*(LONG *)&(flt) >> (shift)) & \ ((1 << (__MCD_FLOAT_MANTISSA_BITS-(shift)))-1) | \ (1 << (__MCD_FLOAT_MANTISSA_BITS-(shift)))) // Same as above except without the MSB, which can be useful // for getting unbiased numbers when the bias is only the MSB // The value must be positive #define __MCD_FIXED_FLOAT_TO_INT_NO_MSB(flt, shift) \ ((*(LONG *)&(flt) >> (shift)) & \ ((1 << (__MCD_FLOAT_MANTISSA_BITS-(shift)))-1)) // Produces the fixed-point form // The value must be positive #define __MCD_FIXED_FLOAT_TO_FIXED(flt) \ ((*(LONG *)&(flt)) & \ ((1 << (__MCD_FLOAT_MANTISSA_BITS))-1) | \ (1 << (__MCD_FLOAT_MANTISSA_BITS))) #define __MCD_FIXED_FLOAT_TO_FIXED_NO_MSB(flt) \ ((*(LONG *)&(flt)) & \ ((1 << (__MCD_FLOAT_MANTISSA_BITS))-1)) // The fixed-point fraction as an integer // The value must be positive #define __MCD_FIXED_FLOAT_FRACTION(flt, shift) \ (*(LONG *)&(flt) & ((1 << (shift))-1)) // Converts the fixed-point form to an IEEE float, but still typed // as an int because a cast to float would cause the compiler to do // an int-float conversion // The value must be positive #define __MCD_FIXED_TO_FIXED_FLOAT(fxed, shift) \ ((fxed) & ((1 << (__MCD_FLOAT_MANTISSA_BITS))-1) | \ ((__MCD_FLOAT_EXPONENT_BIAS+(shift)) << __MCD_FLOAT_EXPONENT_SHIFT)) #ifdef _X86_ #define __MCD_FLOAT_GTZ(flt) (*(LONG *)&(flt) > 0) #define __MCD_FLOAT_LTZ(flt) (*(LONG *)&(flt) < 0) #define __MCD_FLOAT_EQZ(flt) (*(LONG *)&(flt) == 0) #define __MCD_FLOAT_LEZ(flt) (*(LONG *)&(flt) <= 0) #define __MCD_FLOAT_NEQZ(flt) (*(LONG *)&(flt) != 0) #define __MCD_FLOAT_EQUAL(f1, f2) (*(LONG *)&(f1) == *(LONG *)&(f2)) #define __MCD_FLOAT_NEQUAL(f1, f2) (*(LONG *)&(f1) != *(LONG *)&(f2)) #else #define __MCD_FLOAT_GTZ(flt) ((flt) > __MCDZERO) #define __MCD_FLOAT_LTZ(flt) ((flt) < __MCDZERO) #define __MCD_FLOAT_EQZ(flt) ((flt) == __MCDZERO) #define __MCD_FLOAT_LEZ(flt) ((flt) <= __MCDZERO) #define __MCD_FLOAT_NEQZ(flt) ((flt) != __MCDZERO) #define __MCD_FLOAT_EQUAL(f1, f2) ((f1) == (f2)) #define __MCD_FLOAT_NEQUAL(f1, f2) ((f1) != (f2)) #endif // _X86_ // Macro to start an FP divide in the FPU, used to overlap a // divide with integer operations // Can't just use C because it stores the result immediately #ifdef _X86_ #define __MCD_FLOAT_SIMPLE_BEGIN_DIVIDE(num, den, result) \ __asm fld num \ __asm fdiv den #define __MCD_FLOAT_SIMPLE_END_DIVIDE(result) \ __asm fstp DWORD PTR result //USED __inline void __MCD_FLOAT_BEGIN_DIVIDE(MCDFLOAT num, MCDFLOAT den, MCDFLOAT *result) { __asm fld num __asm fdiv den } __inline void __MCD_FLOAT_END_DIVIDE(MCDFLOAT *result) { __asm mov eax, result __asm fstp DWORD PTR [eax] } #else #define __MCD_FLOAT_SIMPLE_BEGIN_DIVIDE(num, den, result) \ ((result) = (num)/(den)) #define __MCD_FLOAT_SIMPLE_END_DIVIDE(result) #define __MCD_FLOAT_BEGIN_DIVIDE(num, den, result) (*(result) = (num)/(den)) #define __MCD_FLOAT_END_DIVIDE(result) #endif // _X86_ #ifdef _X86_ #pragma warning(disable:4035) // Function doesn't return a value // Convert float to int 15.16 __inline LONG __fastcall FLT_TO_FIX( float a) { LARGE_INTEGER li; __asm { mov eax, a test eax, 07fffffffh jz RetZero add eax, 08000000h mov a, eax fld a fistp li mov eax, DWORD PTR li jmp Done RetZero: xor eax, eax Done: } } // Convert float to int 15.16, can cause overflow exceptions __inline LONG __fastcall UNSAFE_FLT_TO_FIX( float a) { LONG l; __asm { mov eax, a test eax, 07fffffffh jz RetZero add eax, 08000000h mov a, eax fld a fistp l mov eax, l jmp Done RetZero: xor eax, eax Done: } } // Convert float to int 0.31 __inline LONG __fastcall FLT_FRACTION( float a) { LARGE_INTEGER li; __asm { mov eax, a test eax, 07fffffffh jz RetZero add eax, 0f800000h mov a, eax fld a fistp li mov eax, DWORD PTR li jmp Done RetZero: xor eax, eax Done: } } // Convert float to int 0.31, can cause overflow exceptions __inline LONG __fastcall UNSAFE_FLT_FRACTION( float a) { LONG l; __asm { mov eax, a test eax, 07fffffffh jz RetZero add eax, 0f800000h mov a, eax fld a fistp l mov eax, l jmp Done RetZero: xor eax, eax Done: } } #pragma warning(default:4035) // Function doesn't return a value // Convert float*scale to int __inline LONG __fastcall FLT_TO_FIX_SCALE( float a, float b) { LARGE_INTEGER li; __asm { fld a fmul b fistp li } return li.LowPart; } #define FLT_TO_UCHAR_SCALE(value_in, scale) \ ((UCHAR)FLT_TO_FIX_SCALE(value_in, scale)) __inline LONG __fastcall FTOL( float a) { LARGE_INTEGER li; _asm { fld a fistp li } return li.LowPart; } // Can cause overflow exceptions __inline LONG __fastcall UNSAFE_FTOL( float a) { LONG l; _asm { fld a fistp l } return l; } // Requires R-G-B to be FP stack 2-1-0 // Requires gc in edx #define FLT_STACK_RGB_TO_GC_FIXED(rOffset, gOffset, bOffset) \ __asm fld __glVal65536 \ __asm fmul st(3), st(0) \ __asm fmul st(2), st(0) \ __asm fmulp st(1), st(0) \ __asm fistp DWORD PTR [edx+bOffset] \ __asm fistp DWORD PTR [edx+gOffset] \ __asm fistp DWORD PTR [edx+rOffset] #define CHOP_ROUND_ON() \ WORD cwSave; \ WORD cwTemp; \ \ __asm { \ _asm wait \ _asm fstcw cwSave \ _asm wait \ _asm mov ax, cwSave \ _asm or ah,0xc \ _asm and ah,0xfc \ _asm mov cwTemp,ax \ _asm fldcw cwTemp \ } #define CHOP_ROUND_OFF() \ __asm { \ _asm wait \ _asm fldcw cwSave \ } #else // _X86_ #define FTOL(value) \ ((GLint)(value)) #define UNSAFE_FTOL(value) \ FTOL(value) #define FLT_TO_FIX_SCALE(value_in, scale) \ ((GLint)((MCDFLOAT)(value_in) * scale)) #define FLT_TO_UCHAR_SCALE(value_in, scale) \ ((UCHAR)((GLint)((MCDFLOAT)(value_in) * scale))) #define FLT_TO_FIX(value_in) \ ((GLint)((MCDFLOAT)(value_in) * __MCDFIXSCALE)) #define UNSAFE_FLT_TO_FIX(value_in) \ FLT_TO_FIX(value_in) #define FLT_FRACTION(f) \ FTOL((f) * __glVal2147483648) #define UNSAFE_FLT_FRACTION(f) \ FLT_FRACTION(f) #define CHOP_ROUND_ON() #define CHOP_ROUND_OFF() #define ASSERT_CHOP_ROUND() #endif //_X86_ #define __MCD_VERTEX_FRAC_BITS \ (__MCD_FLOAT_MANTISSA_BITS-__MCD_VERTEX_FIX_POINT) //USED #define __MCD_VERTEX_FRAC_HALF \ (1 << (__MCD_VERTEX_FRAC_BITS-1)) #define __MCD_VERTEX_FRAC_ONE \ (1 << __MCD_VERTEX_FRAC_BITS) // Converts a floating-point window coordinate to integer #define __MCD_VERTEX_FLOAT_TO_INT(windowCoord) \ __MCD_FIXED_FLOAT_TO_INT(windowCoord, __MCD_VERTEX_FRAC_BITS) //USED // To fixed point #define __MCD_VERTEX_FLOAT_TO_FIXED(windowCoord) \ __MCD_FIXED_FLOAT_TO_FIXED(windowCoord) // And back #define __MCD_VERTEX_FIXED_TO_FLOAT(fxWindowCoord) \ __MCD_FIXED_TO_FIXED_FLOAT(fxWindowCoord, __MCD_VERTEX_FRAC_BITS) //USED // Fixed-point to integer #define __MCD_VERTEX_FIXED_TO_INT(fxWindowCoord) \ ((fxWindowCoord) >> __MCD_VERTEX_FRAC_BITS) // Returns the fraction from a FP window coordinate as an N // bit integer, where N depends on the FP mantissa size and the // FIX size #define __MCD_VERTEX_FLOAT_FRACTION(windowCoord) \ __MCD_FIXED_FLOAT_FRACTION(windowCoord, __MCD_VERTEX_FRAC_BITS) // Scale the fraction to 2^31 for step values #define __MCD_VERTEX_PROMOTE_FRACTION(frac) \ ((frac) << (31-__MCD_VERTEX_FRAC_BITS)) #define __MCD_VERTEX_PROMOTED_FRACTION(windowCoord) \ __MCD_VERTEX_PROMOTE_FRACTION(__MCD_VERTEX_FLOAT_FRACTION(windowCoord)) // Compare two window coordinates. Since window coordinates // are fixed-point numbers, they can be compared directly as // integers #define __MCD_VERTEX_COMPARE(a, op, b) \ ((*(LONG *)&(a)) op (*(LONG *)&(b)))