//#include <d3d.h>
#include <windows.h>
#include <gl/gl.h>
#include "PRF.h"

#include "OGL_Options.h"
#include "OGL_Errors.h"
#include "OGL_Thread.h"


/*
 =======================================================================================
    Globals 
 =======================================================================================
 */

void GLI_DRV_xSendSpriteToClip_TRIANGLES( GLI_tdstAligned2DVector *a4_st2DVertex, GLI_tdstInternalGlobalValuesFor3dEngine *p_stGlobaleMT);


GLI_tdScreenVertx   ga_stVertexBuffer[ 3000 ];
GLI_tdScreenVertx   *CurrentDestXYZ = ga_stVertexBuffer;

#define GLI_M_RestoreCW()

void GLI_BeforeDraw()
{
    CurrentDestXYZ = ga_stVertexBuffer;
	OGLThread_fn_vWaitForSynchro();
}


void GLI_AfterDraw()
{

	//OGLThread_fn_vWaitForSynchro(); 
    if (CurrentDestXYZ != ga_stVertexBuffer)
		OGLThread_fn_vPostCmd_1Long(OGLT1_RENDER, (long)CurrentDestXYZ);
	//OGLThread_fn_vWaitForSynchro();
}



GLI_FuncNodeBegin(GLI_vDrawTriangle)
{
    CurrentDestXYZ += 3;
}

GLI_FuncNodeBegin(GLI_vDrawWiredTriangle)
{
}

GLI_FuncNodeBegin(GLI_vZSortTriangle)
{
    /* draw */
    float ZMax;
    if ((unsigned long)GLI_BIG_GLOBALS -> p_TheZListe -> p_CurrentPoint > (unsigned long)GLI_BIG_GLOBALS -> p_TheZListe -> p_TableOfPoints + ((3L << GLI_MaxZListeTrianglesPO2)* sizeof (GLI_tdScreenVertx)) - 3L * sizeof(GLI_tdScreenVertx))
        return;
    /* 3DFX BUG */
    memcpy(GLI_BIG_GLOBALS -> p_TheZListe -> p_CurrentPoint , CurrentDestXYZ , sizeof(GLI_tdScreenVertx) * 3L);
    if (*(unsigned long *)&GetZ(CurrentDestXYZ[0]) < *(unsigned long *)&GetZ(CurrentDestXYZ[1]))
        *(unsigned long *)&ZMax = *(unsigned long *)&GetZ(CurrentDestXYZ[0]);
    else
        *(unsigned long *)&ZMax = *(unsigned long *)&GetZ(CurrentDestXYZ[1]);
    if (*(unsigned long *)&ZMax > *(unsigned long *)&GetZ(CurrentDestXYZ[2]))
        *(unsigned long *)&ZMax = *(unsigned long *)&GetZ(CurrentDestXYZ[2]);
    GLI_v_AddNodeInZList(ZMax);
    (unsigned long)GLI_BIG_GLOBALS -> p_TheZListe -> p_CurrentPoint += sizeof(GLI_tdScreenVertx) * 3L;
}

/*
 ----------------------------------------------------------------------------------------
  Description   : draw a quad stored in CurrentDestXYZ array or add it in Z list
                    
                     1-----0
                      |  /|     Send two triangle : 0 1 2 and 3 2 0
                      | / |     
                      |/  |
                     2-----3
 ----------------------------------------------------------------------------------------
 */
void GLI_DrawQuad(void)
{
    /* draw 2 triangles */
    if ( GLI_BIG_GLOBALS -> lClippingModeMask & GLI_C_TrianglesMustBeSorted )
    {
        GLI_BIG_GLOBALS -> lCurrentDrawMask &= ~GLI_C_lIsGouraud;
        if ((unsigned long)GLI_BIG_GLOBALS -> p_TheZListe -> p_CurrentPoint > (unsigned long)GLI_BIG_GLOBALS -> p_TheZListe -> p_TableOfPoints + ((3L << GLI_MaxZListeTrianglesPO2)* sizeof (GLI_tdScreenVertx)) - 4L * sizeof(GLI_tdScreenVertx))
            return;
        memcpy(GLI_BIG_GLOBALS -> p_TheZListe -> p_CurrentPoint , CurrentDestXYZ , sizeof(GLI_tdScreenVertx) * 4L);
        GLI_v_AddNodeInZList(GetZ(CurrentDestXYZ[0]));
        (unsigned long)GLI_BIG_GLOBALS -> p_TheZListe -> p_CurrentPoint += sizeof(GLI_tdScreenVertx) * 4L;
    } 
	else
    {
        CurrentDestXYZ[4] = CurrentDestXYZ[0];
        CurrentDestXYZ[5] = CurrentDestXYZ[2];
        CurrentDestXYZ += 6;
    }
}

/*
 ----------------------------------------------------------------------------------------
  Description   : Draw a line
 ----------------------------------------------------------------------------------------
 */
void GLI_DrawLine(void)
{
}

/*
 ----------------------------------------------------------------------------------------
  Description   : draw Zsorted triangle
 ----------------------------------------------------------------------------------------
 */
void GLI_vDrawZSortedTriangle(void *p_3Point)
{
    memcpy( CurrentDestXYZ, p_3Point, 3 * sizeof(GLI_tdScreenVertx) );
    CurrentDestXYZ += 3;
}

/*
 ----------------------------------------------------------------------------------------
  Description   : draw ZSorted quad
 ----------------------------------------------------------------------------------------
 */
void GLI_vDrawZSortedQuad(void *p_3Point)
{
    memcpy( CurrentDestXYZ, p_3Point, 4 * sizeof(GLI_tdScreenVertx) );
    CurrentDestXYZ[4] = *((GLI_tdScreenVertx *) p_3Point + 2);
    CurrentDestXYZ[5] = *((GLI_tdScreenVertx *) p_3Point);
    CurrentDestXYZ += 6;
}

/*
 ----------------------------------------------------------------------------------------
  Description   : choose good drawing function
 ----------------------------------------------------------------------------------------
 */
void GLI_vAddDrawFunc()
{
    if (GLI_BIG_GLOBALS -> lClippingModeMask & GLI_C_TrianglesMustBeSorted)
        GLI_M_AddFunc(GLI_vZSortTriangle);
//    else if ( (GLI_BIG_GLOBALS->lCurrentDrawMask & GLI_C_lIsNotWired) == 0 )
//		GLI_M_AddFunc(GLI_vDrawWiredTriangle);
    else
	    GLI_M_AddFunc(GLI_vDrawTriangle);
}


/*
 ----------------------------------------------------------------------------------------
  Description   : compute clipping mask
 ----------------------------------------------------------------------------------------
 */
void GLI_ReComputeClippingMask()
{
    *(float *)&fX_CMP_Optimize = GLI_BIG_GLOBALS->fXMaxClipping;
	*(float *)&fY_CMP_Optimize = GLI_BIG_GLOBALS->fYMaxClipping;
	*(float *)&fXMin_CLIP_Optimize = GLI_BIG_GLOBALS->fXMinClipping;
	*(float *)&fYMin_CLIP_Optimize = GLI_BIG_GLOBALS->fYMinClipping;
	*(float *)&fXMax_CLIP_Optimize = GLI_BIG_GLOBALS->fXMaxClipping; // - 1.0f;
    *(float *)&fYMax_CLIP_Optimize = GLI_BIG_GLOBALS->fYMaxClipping; // - 1.0f;

    GLI_BIG_GLOBALS -> lClippingModeMask |= (GLI_BIG_GLOBALS -> lClippingModeMask & GLI_C_lCLIP_ALL) << 4;
}

/*
 ----------------------------------------------------------------------------------------
  Description   : clip a sprite
 ----------------------------------------------------------------------------------------
 */
void GLI_DRV_vSendSpriteToClip
	(
		GLI_tdstAligned2DVector *a4_st2DVertex ,
		MTH_tdxReal				xZ ,
		GLI_tdstInternalGlobalValuesFor3dEngine *p_stGlobaleMT
	)
{
	float fClipYMax, fClipYMin, fClipXMax, fClipXMin;

    GLI_BeforeDraw();

    if (a4_st2DVertex[0].xY == a4_st2DVertex[1].xY) /* Aligned sprite */
    {
        GLI_ReComputeClippingMask();

        if ( ( *(long *) &a4_st2DVertex[0].xY > fYMax_CLIP_Optimize) || (*(long *) &a4_st2DVertex[2].xY < fYMin_CLIP_Optimize) || (*(long *) &a4_st2DVertex[0].xX < fXMin_CLIP_Optimize) || (*(long *) &a4_st2DVertex[1].xX > fXMax_CLIP_Optimize) )
		    return;

        /*
	     * clip xMax
	     */
	    if ( *(long *) &a4_st2DVertex[0].xX > fXMax_CLIP_Optimize )
	    {
		    fClipXMax = (GLI_BIG_GLOBALS->fXMaxClipping - a4_st2DVertex[1].xX) / ( a4_st2DVertex[0].xX - a4_st2DVertex[1].xX );
		    a4_st2DVertex[0].xX = a4_st2DVertex[3].xX = GLI_BIG_GLOBALS->fXMaxClipping;
	    }
	    else
		    fClipXMax = 1.0f;

	    /*
	     * clip xMin
	     */
	    if ( *(long *) &a4_st2DVertex[1].xX < fXMin_CLIP_Optimize )
	    {
		    fClipXMin = (fClipXMax * ( GLI_BIG_GLOBALS->fXMinClipping - a4_st2DVertex[1].xX) ) / ( a4_st2DVertex[0].xX - a4_st2DVertex[1].xX );
		    a4_st2DVertex[1].xX = a4_st2DVertex[2].xX = GLI_BIG_GLOBALS->fXMinClipping;
	    }
	    else 
		    fClipXMin = 0.0f;
	
	    /*
	     * clip yMin
	     */
	    if ( *(long *) &a4_st2DVertex[0].xY < fYMin_CLIP_Optimize )
	    {
		    fClipYMin = (GLI_BIG_GLOBALS->fYMinClipping - a4_st2DVertex[2].xY) / ( a4_st2DVertex[0].xY - a4_st2DVertex[2].xY );
		    a4_st2DVertex[0].xY = a4_st2DVertex[1].xY = GLI_BIG_GLOBALS->fYMinClipping;
	    }
	    else
		    fClipYMin = 1.0f;

	    /*
	     * clip yMax
	     */
	    if ( *(long *) &a4_st2DVertex[2].xY > fYMax_CLIP_Optimize )
	    {
		    fClipYMax = (fClipYMin * ( GLI_BIG_GLOBALS->fYMaxClipping - a4_st2DVertex[2].xY ) ) / ( a4_st2DVertex[0].xY - a4_st2DVertex[2].xY );
		    a4_st2DVertex[2].xY = a4_st2DVertex[3].xY = GLI_BIG_GLOBALS->fYMaxClipping;
	    }
	    else 
		    fClipYMax = 0.0f;
    }
    else
    {
        if ( *(long *) &GLI_BIG_GLOBALS->xWaterPlaneDistance != 0 );
        {
            GLI_DRV_xSendSpriteToClip_TRIANGLES( a4_st2DVertex, p_stGlobaleMT);
            return;
        }
	    
        if ( (a4_st2DVertex [0] . xY < 0.0f) || (a4_st2DVertex [1] . xY < 0.0f) || (a4_st2DVertex [2] . xY < 0.0f) || (a4_st2DVertex [3] . xY < 0.0f) ) return;
        if ( (a4_st2DVertex [0] . xX < 0.0f) || (a4_st2DVertex [1] . xX < 0.0f) || (a4_st2DVertex [2] . xX < 0.0f) || (a4_st2DVertex [3] . xX < 0.0f) ) return;
        if ( (a4_st2DVertex [0] . xY > 480.0f) || (a4_st2DVertex [1] . xY > 480.0f) || (a4_st2DVertex [2] . xY > 480.0f) || (a4_st2DVertex [3] . xY > 480.0f) ) return;
        if ( (a4_st2DVertex [0] . xX > 640.0f) || (a4_st2DVertex [1] . xX > 640.0f) || (a4_st2DVertex [2] . xX > 640.0f) || (a4_st2DVertex [3] . xX > 640.0f) ) return;
        fClipXMin = fClipYMax = 0.0f;
        fClipYMin = fClipXMax = 1.0f;
        
    }

    GLI_M_InitSprite();
	
	SetU(CurrentDestXYZ[0], fClipXMax );
	SetV(CurrentDestXYZ[0], fClipYMin );
    SetU(CurrentDestXYZ[1], fClipXMin );
	SetV(CurrentDestXYZ[1], fClipYMin );
	SetU(CurrentDestXYZ[2], fClipXMin );
	SetV(CurrentDestXYZ[2], fClipYMax );
    SetU(CurrentDestXYZ[3], fClipXMax );
	SetV(CurrentDestXYZ[3], fClipYMax );

    GLI_DrawQuad();
    GLI_AfterDraw();
}

/*
 ----------------------------------------------------------------------------------------
  Description   : clip a sprite that have UV coordinates (it seems to be unused)
 ----------------------------------------------------------------------------------------
 */
void GLI_DRV_vSendSpriteToClipWithUV
(
 GLI_tdstAligned2DVector *a4_st2DVertex ,
 MTH_tdxReal *a8_stUVVertex,
 MTH_tdxReal xZ ,
 GLI_tdstInternalGlobalValuesFor3dEngine *p_stGlobaleMT)
{
    GLI_BeforeDraw();
    GLI_M_InitSprite();

    if (a4_st2DVertex [0] . xY < 0.0f) return;
    if (a4_st2DVertex [1] . xY < 0.0f) return;
    if (a4_st2DVertex [2] . xY < 0.0f) return;
    if (a4_st2DVertex [3] . xY < 0.0f) return;
    if (a4_st2DVertex [0] . xY > GLI_BIG_GLOBALS->fYMaxClipping) return;
    if (a4_st2DVertex [1] . xY > GLI_BIG_GLOBALS->fYMaxClipping) return;
    if (a4_st2DVertex [2] . xY > GLI_BIG_GLOBALS->fYMaxClipping) return;
    if (a4_st2DVertex [3] . xY > GLI_BIG_GLOBALS->fYMaxClipping) return;

    if ( p_stGlobaleMT->p_stCurrentTexture->lIncrementIsEnable )
    {
        float fAddU, fAddV;
        fAddU = p_stGlobaleMT-> p_stCurrentTexture -> fAddU;
        fAddV = p_stGlobaleMT-> p_stCurrentTexture -> fAddV;
        SetU(CurrentDestXYZ[2], a8_stUVVertex[4] + fAddU );
        SetV(CurrentDestXYZ[2], a8_stUVVertex[4 + 1] + fAddV);
        SetU(CurrentDestXYZ[3], a8_stUVVertex[6] + fAddU);
        SetV(CurrentDestXYZ[3], a8_stUVVertex[6 + 1] + fAddV);
        SetU(CurrentDestXYZ[0], a8_stUVVertex[0] + fAddU);
        SetV(CurrentDestXYZ[0], a8_stUVVertex[0 + 1] + fAddV);
        SetU(CurrentDestXYZ[1], a8_stUVVertex[2] + fAddU);
        SetV(CurrentDestXYZ[1], a8_stUVVertex[2 + 1] + fAddV);
    }
    else
    {
        SetU(CurrentDestXYZ[2], a8_stUVVertex[4]);
        SetV(CurrentDestXYZ[2], a8_stUVVertex[4 + 1]);
        SetU(CurrentDestXYZ[3], a8_stUVVertex[6]);
        SetV(CurrentDestXYZ[3], a8_stUVVertex[6 + 1]);
        SetU(CurrentDestXYZ[0], a8_stUVVertex[0]);
        SetV(CurrentDestXYZ[0], a8_stUVVertex[0 + 1]);
        SetU(CurrentDestXYZ[1], a8_stUVVertex[2]);
        SetV(CurrentDestXYZ[1], a8_stUVVertex[2 + 1]);
    }
    GLI_DrawQuad();
    GLI_AfterDraw();
}


/*
 ----------------------------------------------------------------------------------------
  Description   : clip a line (not implemented)
 ----------------------------------------------------------------------------------------
 */
void GLI_DRV_vSendSingleLineToClip
	(
		GLD_tdstViewportAttributes *p_stVpt ,
        GLI_tdstAligned3DVector *p_stVertex1 ,
        GLI_tdstAligned2DVector *p_st2DVertex1 ,
        GLI_tdstAligned3DVector *p_stVertex2 ,
        GLI_tdstAligned2DVector *p_st2DVertex2 ,
        GLI_tdstInternalGlobalValuesFor3dEngine *p_stGlobaleMT,
        long lDrawModeMask, GEO_tdstColor *p_stColor
	)
{
#ifdef _DEBUG
	/*
    GLI_tdstAligned2DVector *p_stP1, *p_stP2;
	GLI_tdstAligned3DVector	*p_st3DP1, *p_st3DP2;
    */
    GLI_tdstAligned2DVector stP1, stP2;
    GLI_tdstAligned3DVector st3DP1, st3DP2;
	float fFactor;

    p_st2DVertex1->ulPackedColor = 0xFFFFFFFF;
    p_st2DVertex2->ulPackedColor = 0xFFFFFFFF;

    /* xClipping */
	if (p_st2DVertex1->xX < p_st2DVertex2->xX)
	{
		stP1 = *p_st2DVertex1;
		st3DP1 = *p_stVertex1;
		stP2 = *p_st2DVertex2;
		st3DP2 = *p_stVertex2;
	}
	else
	{
		stP1 = *p_st2DVertex2;
		st3DP1 = *p_stVertex2;
		stP2 = *p_st2DVertex1;
		st3DP2 = *p_stVertex1;
	}

	if (( stP2.xX < 0.0f) || ( stP1.xX > 640.0f ) )
		return;

	if ( stP1.xX < 0.0f )
	{
		fFactor = stP2.xX / (stP2.xX - stP1.xX );
		
		stP1.xY = stP2.xY - ( stP2.xY - stP1.xY) * fFactor;
		//(*p_stP1)->ulPackedColor = (unsigned long) ((*p_stP2)->ulPackedColor - ( (*p_stP2)->ulPackedColor - (*p_stP1)->ulPackedColor) * fFactor);
		st3DP1.xZ = st3DP2.xZ - ( st3DP2.xY - st3DP1.xY) * fFactor;
		stP1.xX = 0.0f;
	}

	if ( stP2.xX > 640.0f)
	{
		fFactor =  (stP1.xX - 640.0f) / (stP2.xX - stP1.xX );
		
		stP2.xY = stP1.xY - ( stP2.xY - stP1.xY) * fFactor;
		//(*p_stP2)->ulPackedColor = (unsigned long) ((*p_stP1)->ulPackedColor - ( (*p_stP2)->ulPackedColor - (*p_stP1)->ulPackedColor) * fFactor);
		st3DP2.xZ = st3DP1.xZ - ( st3DP2.xY - st3DP1.xY) * fFactor;
		stP2.xX = 640.0f;
	}

	/* yClipping */
	if ( stP1.xY < stP2.xY)
	{
		p_st2DVertex1 = &stP1;
		p_stVertex1 = &st3DP1;
		p_st2DVertex2 = &stP2;
		p_stVertex2 = &st3DP2;
	}
	else
	{
		p_st2DVertex1 = &stP2;
		p_stVertex1 = &st3DP2;
		p_st2DVertex2 = &stP1;
		p_stVertex2 = &st3DP1;
	}

	if (( p_st2DVertex2->xY < 0.0f) || ( p_st2DVertex1->xY > 480.0f ) )
		return;

	if ( p_st2DVertex1->xY < 0.0f )
	{
		fFactor = p_st2DVertex2->xY / (p_st2DVertex2->xY - p_st2DVertex1->xY );
		
		p_st2DVertex1->xX = p_st2DVertex2->xX - ( p_st2DVertex2->xX - p_st2DVertex1->xX) * fFactor;
		//(*p_st2DVertex1)->ulPackedColor = (unsigned long) ((*p_st2DVertex2)->ulPackedColor - ( (*p_st2DVertex2)->ulPackedColor - (*p_st2DVertex1)->ulPackedColor) * fFactor);
		p_stVertex1->xZ = p_stVertex2->xZ - ( p_stVertex2->xZ - p_stVertex1->xZ) * fFactor;
		p_st2DVertex1->xY = 0.0f;
	}

	if ( p_st2DVertex2->xY > 480.0f)
	{
		//fFactor = ( (*p_st2DVertex2)->xX - (*p_st2DVertex1)->xX) / ((*p_st2DVertex2)->xY - (*p_st2DVertex1)->xY );
		fFactor = (p_st2DVertex1->xY - 480.0f) / (p_st2DVertex2->xY - p_st2DVertex1->xY );
		
		p_st2DVertex2->xX = p_st2DVertex1->xX - ( p_st2DVertex2->xX - p_st2DVertex1->xX) * fFactor;
		//(*p_st2DVertex2)->ulPackedColor = (unsigned long) ((*p_st2DVertex1)->ulPackedColor - ( (*p_st2DVertex2)->ulPackedColor - (*p_st2DVertex1)->ulPackedColor) * fFactor);
		p_stVertex2->xZ = p_stVertex1->xZ - ( p_stVertex2->xZ - p_stVertex1->xZ) * fFactor;
		p_st2DVertex2->xY = 480.0f;
	}
    
    
#else
	if (p_st2DVertex1->xX < 0) return;
	if (p_st2DVertex1->xY < 0) return;
	if (p_st2DVertex1->xX > 640.0f) return;
	if (p_st2DVertex1->xY > 480.0f) return;
	if (p_st2DVertex2->xX < 0) return;
	if (p_st2DVertex2->xY < 0) return;
	if (p_st2DVertex2->xX > 640.0f) return;
	if (p_st2DVertex2->xY > 480.0f) return;
#endif
    
	GLI_M_InitLine();

	GLI_BeforeDraw();

	GLI_DrawLine();

	GLI_AfterDraw();
}
