/*
Tested with LINT
*/
#include"gli_st.h"
#include "GLI_Defn.h"
#include "light_st.h"
#include "PvObj_st.h"
#include "proj.h"
#include "camera.h"
 
 
tdstGlobalsProjection stProjGlobs;
 
#ifdef __cplusplus
extern "C"
{
#endif
    /**********************************************************************************************/
    /* Name: GLI_xSerialProjectionNoTrans 1.1 */
    /* Goal: Perspective Project a list of 3d vertex with no translation - for sprites*/
    /* Code: Elie Khoury / 1.0*/
    /*       Philippe Vimont / 1.1 -> ASSEMBLY CODE*/
	/*		 Steve McCalla / 1.2 -> No Trans, no isometric cameras*/
    /* OPTIMMIZED : */
    /**********************************************************************************************/
void 
GLI_xSerialProjectionNoTrans  (	GLI_tdstCamera *p_stCam ,
								long lNbOfVertex ,
								GLI_tdstAligned3DVector *p_stSource ,
								GLI_tdstAligned2DVector *p_stDest )
{
    GLI_tdxValue xInterm ;
    long lNewX;
    GLI_tdstAligned2DVector  *p_stDestLast;
    p_stDestLast = p_stDest + lNbOfVertex;
    *(float * )&lNewX = 8000.0f;
 
	assert(p_stCam -> lCameraMode == GLI_C_lPersCamWithoutDistorsion 
			|| p_stCam -> lCameraMode == GLI_C_lPersCamWithDistorsion);
 
	for ( ; p_stDest < p_stDestLast ; p_stSource++ ,p_stDest++)
	{
		if ( *(long *)&p_stSource->xZ < *(long *)&p_stCam -> xNear )
		{
			*(long *)&p_stDest -> xOoZ |= 0x80000000;
			*((unsigned long *)&p_stDest->xX) = lNewX | ((*((unsigned long *)&p_stSource->xX) & 0x80000000) ^ 0x80000000);
			*((unsigned long *)&p_stDest->xY) = lNewX | ((*((unsigned long *)&p_stSource->xY) & 0x80000000) ^ 0x80000000);
			continue ;
		}
		p_stDest -> xOoZ = MTH_M_xInvLow((float)p_stSource -> xZ ) ;
		xInterm = p_stCam -> xScreen * p_stDest -> xOoZ ;
		p_stDest -> xOoZ *= GLI_C_xZClippingNear /*(float)p_stCam -> xNear*/ ;
		p_stDest -> xX = p_stSource -> xX * p_stCam -> stScale . xX * xInterm ;
		p_stDest -> xY = p_stSource -> xY * p_stCam -> stScale . xY * xInterm ;
	}
    return;
}
    
 
 
    /**********************************************************************************************/
    /* Name: GLI_xSerialProjection 1.1 */
    /* Goal: Project a list of 3d vertex*/
    /* Code: Elie Khoury / 1.0*/
    /*       Philippe Vimont / 1.1 -> ASSEMBLY CODE*/
    /* OPTIMMIZED : */
    /**********************************************************************************************/
    void 
        GLI_xSerialProjection ( GLI_tdstCamera *p_stCam ,
        long lNbOfVertex ,
        GLI_tdstAligned3DVector *p_stSource ,
        GLI_tdstAligned2DVector *p_stDest )
    {
        GLI_tdxValue xInterm ;
        long lVertexIndex , lNewX;
        GLI_tdstAligned2DVector  *p_stDestLast;
        p_stDestLast = p_stDest + lNbOfVertex;
        *(float * )&lNewX = 8000.0f;
        switch ( p_stCam -> lCameraMode )
        {
        case GLI_C_lPersCamWithDistorsion :
        case GLI_C_lPersCamWithoutDistorsion :
            
            for ( ; p_stDest < p_stDestLast ; p_stSource++ ,p_stDest++)
            {
                if ( *(long *)&p_stSource->xZ < *(long *)&p_stCam->xNear )
                {
                    *(long *)&p_stDest -> xOoZ |= 0x80000000;
                    *((unsigned long *)&p_stDest->xX) = lNewX | ((*((unsigned long *)&p_stSource->xX) & 0x80000000) ^ 0x80000000);
                    *((unsigned long *)&p_stDest->xY) = lNewX | ((*((unsigned long *)&p_stSource->xY) & 0x80000000) ^ 0x80000000);
                    continue ;
                }
                p_stDest -> xOoZ = MTH_M_xInvLow((float)p_stSource -> xZ ) ;
                xInterm = p_stCam -> xScreen * p_stDest -> xOoZ ;
                p_stDest -> xOoZ *= GLI_C_xZClippingNear /*(float)p_stCam -> xNear*/ ;
                p_stDest -> xX = p_stCam -> stTrans . xX + p_stSource -> xX * p_stCam -> stScale . xX * xInterm ;
                p_stDest -> xY = p_stCam -> stTrans . xY + p_stSource -> xY * p_stCam -> stScale . xY * xInterm ;
            }          /*  */
            
            
            break ;
            
        case GLI_C_lIsoCamWithDistorsion :
        case GLI_C_lIsoCamWithoutDistorsion :
            for ( lVertexIndex = 0 ; lVertexIndex < lNbOfVertex ; lVertexIndex ++ )
            {
                /**** NO PROJECTION IF THE POINT IS BEFORE NEAR PLAN ****/
                if ( p_stSource[lVertexIndex].xZ < p_stCam -> xNear )
                    continue ;
                p_stDest[lVertexIndex].xOoZ =1.0f;
                
                p_stDest[lVertexIndex].xX = 
                    MTH_M_xRealToFloat( 
                    GLI_M_Add ( p_stCam -> stTrans . xX ,
                    GLI_M_Mul ( p_stSource[lVertexIndex] . xX ,
                    p_stCam -> stScale . xX ) ) ) ;
                
                p_stDest[lVertexIndex].xY = 
                    MTH_M_xRealToFloat( 
                    GLI_M_Add ( p_stCam -> stTrans . xY ,
                    GLI_M_Mul ( p_stSource[lVertexIndex] . xY ,
                    p_stCam -> stScale . xY ) ) ) ;
            }          
            break ;
        }
        
        return  ;
    }
    
    
    /**********************************************************************************************/
    /* Name: GLI_xProjection 1.0*/
    /* Goal: Project a 3d vertex*/
    /* Code: Elie Khoury / 1.0*/
    /* OPTIMMIZED : unused*/
    /**********************************************************************************************/
    void 
        GLI_xProjection ( GLI_tdstCamera *p_stCam ,
        MTH3D_tdstVector *p_stSource ,
        GLI_tdst2DVertex *p_stDest )
    {
        float xInterm ;
        
        switch ( p_stCam -> lCameraMode )
        {
        case GLI_C_lPersCamWithDistorsion :
        case GLI_C_lPersCamWithoutDistorsion :
            /**** NO PROJECTION IF THE POINT IS BEFORE NEAR PLAN ****/
            if ( p_stSource -> xZ < p_stCam -> xNear )
                return  ;
            p_stDest -> xOoZ = MTH_M_xInvLow((float) p_stSource -> xZ ) ;
            xInterm = p_stCam -> xScreen * p_stDest -> xOoZ ;
            p_stDest -> xOoZ *= GLI_C_xZClippingNear /*(float)p_stCam -> xNear*/ ;
            p_stDest -> xX = p_stCam -> stTrans . xX + p_stSource -> xX * p_stCam -> stScale . xX * xInterm ;
            p_stDest -> xY = p_stCam -> stTrans . xY + p_stSource -> xY * p_stCam -> stScale . xY * xInterm ;
            break ;
            
        case GLI_C_lIsoCamWithDistorsion :
        case GLI_C_lIsoCamWithoutDistorsion :
            /**** NO PROJECTION IF THE POINT IS BEFORE NEAR PLAN ****/
            if ( p_stSource -> xZ < p_stCam -> xNear )
                return  ;
            
            p_stDest -> xOoZ = 1.0f;
            
            p_stDest -> xX
                = 
                MTH_M_xRealToFloat( 
                GLI_M_Add ( p_stCam -> stTrans . xX ,
                GLI_M_Mul ( p_stSource -> xX ,
                p_stCam -> stScale . xX ) ) ) ;
            
            p_stDest -> xY
                = 
                MTH_M_xRealToFloat( 
                GLI_M_Add ( p_stCam -> stTrans . xY ,
                GLI_M_Mul ( p_stSource -> xY ,
                p_stCam -> stScale . xY ) ) ) ;
            break ;
        }
        
        return  ;
    }
    
    /**********************************************************************************************/
    /* Name: GLI_vInit_Projections*/
    /* Goal: Init a table for f(x) = 1/x;*/
    /* Code: Philippe Vimont / 1.0*/
    /* OPTIMMIZED : No*/
    /**********************************************************************************************/
    void 
        GLI_vInit_Projections()
    {
        ACP_tdxIndex xZcounter;
        long *p_lZAdjust;
        for (xZcounter = 0 ; xZcounter < 1024 ; xZcounter ++)
        {
            stProjGlobs.xOoXTable[xZcounter] =(1.0f) / ((float)( xZcounter +1024 ) * 1024.0f );
        }
        
        p_lZAdjust = (long *) stProjGlobs.xOoXTable;
        for (xZcounter = 0 ; xZcounter < 1024 ; xZcounter++, p_lZAdjust++ )
        {
            *(p_lZAdjust) = *(p_lZAdjust) + 0x49800000;
        }
    }
    
   
#ifdef __cplusplus
}/* extern "C" */
#endif
