//=================================================================
//
// Copyright (c) Microsoft Corporation 1999 - All Rights Reserved.
//
//=================================================================

#ifndef _RASTER_H_
#define _RASTER_H_

#define FloatToZBUFFER2   FloatToFixed0_32

extern float    FloatShift16;

// Everything that may be interfaced with assembly language should be declared "C" for
//   ease of implementation

extern "C" GRFRENDERDATA    g_grdRenderData;
extern "C" GRFCHUNKDATA     g_grdChunkData;

extern "C"
{
    long __cdecl IntegerDivide(long N, long D); //return N/D (approx for D== 3,5,6,7)
}

unsigned int log2(unsigned int x);

inline long IntegerMod(long N, long D)
{
    return N - D*IntegerDivide(N,D);
}

// Does a ceil on a 28.4 value that's guaranteed not to be negative
// (actually it can be as low as -15/16).
inline long Ceil28_4NonNeg(FIX28_4 Value)
{
    assert (Value >= -15);
    return (Value + 15) >> 4;
}

// converts a float in the range 0-0x7FFFF to a 28.4 fixed value
inline unsigned int FloatToFixed28_4NonNeg(FLOAT Value)
{
    assert (Value >= 0);
    g_grdRenderData.floatTemp = Value + 0x80000;
    return *(unsigned int *)&g_grdRenderData.floatTemp & 0x007FFFFF;
}

inline long FloatToLong(float fl)
{
    LARGE_INTEGER tmp;
    _asm
    {
        fld fl
        fistp [tmp]
    }
    return tmp.LowPart;
}

#pragma warning( disable : 4244)  //warning C4244: 'return' : conversion from..., possible loss of data

inline float Fixed28_4ToFloat( FIX28_4 Value )
    { return Value * (1.0f/16.0f);}

inline float Fixed16_16ToFloat( FIX16_16 Value )
    { return Value * (1.0f/65536.0f);}

inline FIX16_16 FloatToFixed16_16( float Value )
{
#if USE_C
    return FloatToLong(Value*65536.0f);
#else
    _asm {
        fld [Value]
        fmul [FloatShift16]
        fistp dword ptr [g_grdRenderData.iTemp]
    }

    return *(FIX16_16 *)&g_grdRenderData.iTemp;
#endif
}

inline long FloatToFixed0_32(float Value)
{
    return FloatToLong(Value*4294967295.0f);
}

#pragma warning( default : 4244)

// Calculates both properly floored quotient (proper for negative numbers in particular)
// and modulo results at once; allows single div to be used.
// Reference: Chris Hecker's _Game Developer_ columns starting in April/May 1995.
inline void FloorQuoRem( long Numerator, long Denominator, long &Floor,	long &Modx )
{
#if defined(_DEBUG)
//	assert(Denominator > 0);		// we assume it's positive
    if (Denominator <= 0)  // really should be assert, but won't compile...
        _asm int 3
#endif

#if USE_C
    if(Numerator >= 0)
    {
        // positive case, C is okay
		Modx = IntegerMod(Numerator,Denominator);
        Floor = IntegerDivide((Numerator-Modx),Denominator);
    }
    else
    {
        // Numerator is negative, do the right thing
		Modx = IntegerMod((-Numerator),Denominator);
        if(Modx)
			Modx = Denominator - Modx; // deal with the remainder
        Floor = IntegerDivide((Numerator-Modx),Denominator);
    }
#else
    _asm
    {
    mov eax,[Numerator]
    xor edx,edx
    test eax,eax
    jz  Done
    mov ecx,[Denominator]
    js  Nega

    test ecx,0xFFFF0000
    jnz Full64x32
    mov edx,eax
    shr edx,16
    cmp edx,ecx
    jae Full64x32
    div cx
    xor ecx,ecx
    mov cx,ax
    mov eax,ecx
    mov cx,dx
    mov edx,ecx
    jmp Done

Full64x32:
    xor edx,edx
    div ecx
    jmp Done
Nega:
    mov edx,-1
    idiv ecx
    test edx,edx
    jz  Done
    dec eax
    add edx,ecx
Done:
    mov ecx,[Modx]
    mov [ecx],edx
    mov ecx,[Floor]
    mov [ecx],eax
	}
#endif
}


#endif  // _RASTER_H_

