/*
Tested with LINT
*/
#include <assert.h>
 
#include"gli_st.h"
#include "GLI_Defn.h"
#include "vertex.h"
#include "light_st.h"
#include "PvObj_st.h"
#include "watrplan.h"
#include "camera.h"
#include "matstack.h"
#include "COL.h"
 
#include "gmt.h"
 
 
#define GLI_TSINTA 64
float a64_fSinTable[128];
extern long GLD_RenderingCounter;
long gs_lXBase;
long gs_lYBase;
static float GLI_fF2pow24;
static float GLI_gsWaterPlaneRefraction = 0.6f;
static float GLI_gsWaterPlaneDepthSizeOf2DMove = 2.0f;
static float GLI_gsWaterPlaneDepthStartOf2DMove = -1.0f;
 
long bWaterPlaneState;
MTH3D_tdstVector stWaterPlaneNormale;
MTH_tdxReal fWaterPlaneDistance;
MTH_tdxReal GLI_gsfWaterPlaneFogStart = 2.0f;
GLI_tdstColor GLI_gsfWaterPlaneFogColor ;
extern long TRYIT;  
extern GLI_tdstInternalGlobalValuesFor3dEngine *GLI_BIG_GLOBALS;
void  GLI_vWaitEndOfRendering();
void GLI_vWaitEndOfVertexTransfert();
void GLI_vWaitEndOfVSync();
 
/*ANNECY VL04/03/98{*/
/*
 * var for sinus effect
 */
MTH_tdxReal			a3_xSinEffectBase[3];
long				a3_lSinEffectFreq[3];
MTH3D_tdstVector	stSinEffectAmp;
MTH3D_tdstVector	stSinEffectVector;
MTH_tdxReal			xSinusEffectDepthStart;
char				g_cSinusEffectState;
char				g_cSinusEffectFlag;
/*ENDANNECY VL}*/
 
 
/**********************************************************************************************/
/* Name: GLI_vSetWaterplane*/
/* Goal : Set The Plane For Water Effect*/
/* Code: Philippe Vimont */
/* OPTIMMIZED : */
/**********************************************************************************************/
void GLI_vSetWaterplane(struct GLD_tdstViewportAttributes_ *p_stVpt,
                        MTH3D_tdstVector *p_stNormale,
                        MTH_tdxReal xDistance)
{
    stWaterPlaneNormale = *p_stNormale;
    fWaterPlaneDistance = xDistance;
}
/**********************************************************************************************/
/* Name: GLI_vSetWaterplaneRefraction*/
/* Goal : 0.0f is nothing, 1.0f is maximum*/
/* Code: Philippe Vimont */
/* OPTIMMIZED : */
/**********************************************************************************************/
void GLI_vSetWaterplane2DMoveSize(MTH_tdxReal xSizeInPixels)
{
    GLI_gsWaterPlaneDepthSizeOf2DMove = xSizeInPixels;
}
void GLI_vSetWaterplane2DMoveDepthStart(MTH_tdxReal xDepth)
{
    GLI_gsWaterPlaneDepthStartOf2DMove = xDepth;
}
/**********************************************************************************************/
/* Name: GLI_vSetWaterplaneRefraction*/
/* Goal : 0.0f is nothing, 1.0f is maximum*/
/* Code: Philippe Vimont */
/* OPTIMMIZED : */
/**********************************************************************************************/
void GLI_vSetWaterplaneRefraction(MTH_tdxReal xRefraction)
{
    GLI_gsWaterPlaneRefraction = xRefraction;
}
/**********************************************************************************************/
/* Name: GLI_vSetWaterplaneOn*/
/* Goal : watrplane ON*/
/* Code: Philippe Vimont */
/* OPTIMMIZED : */
/**********************************************************************************************/
void GLI_vSetWaterplaneOn()
{
    bWaterPlaneState |= GLI_C_l2DPlaneIsEnable;
}
/**********************************************************************************************/
/* Name: GLI_vSetWaterplaneOff*/
/* Goal : No watrplane*/
/* Code: Philippe Vimont */
/* OPTIMMIZED : */
/**********************************************************************************************/
void GLI_vSetWaterplaneOff()
{
    bWaterPlaneState &= 0xffffffff - GLI_C_l2DPlaneIsEnable;
}
void GLI_vWaterplaneEnableRefraction()
{
    bWaterPlaneState &= 0xffffffff - GLI_C_lWaterPlaneNoRefraction;
}
long GLI_vIsWaterplaneEnable(GLI_tdstInternalGlobalValuesFor3dEngine *p_stGlobalsParrameters)
{
    return ((bWaterPlaneState & GLI_C_l2DPlaneIsEnable));
}
void GLI_vWaterplaneDisableRefraction()
{
    bWaterPlaneState |= GLI_C_lWaterPlaneNoRefraction;
}
void GLI_vWaterplaneEnable2DSinus()
{
    bWaterPlaneState &= 0xffffffff - GLI_C_lWaterPlaneNoSinusMoves;
}
void GLI_vWaterplaneDisable2DSinus()
{
    bWaterPlaneState |= GLI_C_lWaterPlaneNoSinusMoves;
}
void GLI_vWaterplaneEnableFog()
{
    bWaterPlaneState &= 0xffffffff - GLI_C_lWaterPlaneNoFog ;
}
void GLI_vWaterplaneDisableFog()
{
    bWaterPlaneState |= GLI_C_lWaterPlaneNoFog ;
}
 
/**********************************************************************************************/
/* Name: GLI_vFogWaterPlaneEffect*/
/* Goal : Make a Dpth */
/* Code: Philippe Vimont */
/* OPTIMMIZE : FINAL VERSION SHOULD BE IN ASSEMBLY*/
/**********************************************************************************************/
void
GLI_vFogWaterPlaneEffect(GLI_tdstInternalGlobalValuesFor3dEngine *p_stGlobalsParrameters,long xStart,long xNumber)
{
    float *p_xCounter,fOoWaterPlaneFogStart,fLocal;
    long lLocal2;
    GLI_tdstColor  *p_Color , *p_ColorEnd ;
    
    if ((!(bWaterPlaneState & GLI_C_l2DPlaneIsEnable)) ||
        (GLI_C_lWaterPlaneNoFog & bWaterPlaneState)) return;
    
    p_Color = p_stGlobalsParrameters->GLI_aDEF_stColorsRLID + xStart;
    
    p_ColorEnd = p_Color +  xNumber;
    p_xCounter = p_stGlobalsParrameters->GLI_aDEF_xWaterPlaneDepth + xStart;
    fOoWaterPlaneFogStart = -1.0f / GLI_gsfWaterPlaneFogStart;
    *((float *)&lLocal2) = -GLI_gsfWaterPlaneFogStart ;
    
    for (;p_Color <p_ColorEnd;p_Color ++,p_xCounter++)
        if (*((long *)p_xCounter) < 0)
        {
            if (*p_xCounter  > -GLI_gsfWaterPlaneFogStart)
            {
                fLocal = fOoWaterPlaneFogStart * *p_xCounter;
                p_Color -> xR += fLocal * GLI_gsfWaterPlaneFogColor . xR;
                p_Color -> xG += fLocal * GLI_gsfWaterPlaneFogColor . xG;
                p_Color -> xB += fLocal * GLI_gsfWaterPlaneFogColor . xB;
            }
            else
            {
                p_Color -> xR += GLI_gsfWaterPlaneFogColor . xR ;
                p_Color -> xG += GLI_gsfWaterPlaneFogColor . xG ;
                p_Color -> xB += GLI_gsfWaterPlaneFogColor . xB ;
            }
        }
}
 
 
 
/**********************************************************************************************/
/* Name: GLI_vSetWaterFog*/
/* Goal : Init waterplane module*/
/* Code: Philippe Vimont */
/* OPTIMMIZED : */
/**********************************************************************************************/
void GLI_vSetWaterFog(MTH_tdxReal xDepth,GLI_tdstColor *p_stFogColor)
{
    GLI_gsfWaterPlaneFogColor = *p_stFogColor;
    GLI_gsfWaterPlaneFogStart = xDepth;
}
/**********************************************************************************************/
/* Name: GLI_vInitWaterplaneModule*/
/* Goal : Init waterplane module*/
/* Code: Philippe Vimont */
/* OPTIMMIZED : */
/**********************************************************************************************/
void GLI_vInitWaterplaneModule()
{
    /* !!! = Could be used as a REINIT function, so it could stay optimlised*/
    long lCounter;
    static unsigned char lIsAlreadyInit = 1;
    
    GLI_fF2pow24 = (float)(3L * pow(2,23));
    
    if (lIsAlreadyInit)
        for (lCounter=0;lCounter<GLI_TSINTA;lCounter++)
        {
            a64_fSinTable[lCounter]= (MTH_M_xCos( ((2.0*3.1415927f/GLI_TSINTA) * (float)lCounter))) * 2;
        }
    
    lIsAlreadyInit = 0;
    bWaterPlaneState = 0;
    gs_lXBase = 0;
    gs_lYBase = 32;
    GLI_gsfWaterPlaneFogColor . xR = -0.6f;
    GLI_gsfWaterPlaneFogColor . xG = -0.3f;
    GLI_gsfWaterPlaneFogColor . xB = -0.4f;
    GLI_gsWaterPlaneRefraction = 0.7f;
    GLI_gsWaterPlaneDepthSizeOf2DMove = 1.4f;
    GLI_gsWaterPlaneDepthStartOf2DMove = -5.0f;
    GLI_gsfWaterPlaneFogStart = 7.0f;
    stWaterPlaneNormale . xX = 0.0f;
    stWaterPlaneNormale . xZ = 0.0f;
    stWaterPlaneNormale . xY = 1.0f;
    fWaterPlaneDistance = 0.0f;
 
    /*ANNECY VL04/03/98{*/
	stSinEffectAmp.xX = 1.0f;
	stSinEffectAmp.xY = 0.0f;
	stSinEffectAmp.xZ = 0.0f;
 
	a3_lSinEffectFreq[0] = 1;
	a3_lSinEffectFreq[1] = 0;
	a3_lSinEffectFreq[2] = 0;
 
	a3_xSinEffectBase[0] = MTH_C_ZERO;
	a3_xSinEffectBase[1] = MTH_C_ZERO;
	a3_xSinEffectBase[2] = MTH_C_ZERO;
 
	xSinusEffectDepthStart = 10.0f;
 
	g_cSinusEffectState = 0;
	g_cSinusEffectFlag = 0;
	/*ENDANNECY VL}*/
}
 
/*ANNECY VL04/03/98{*/
/*
 =======================================================================================
	Function for sinus Effect 
 =======================================================================================
 */
 
/*
 ----------------------------------------------------------------------------------------
  Description   : get / set state
 ----------------------------------------------------------------------------------------
 */
void GLI_fn_SinusEffect_vSetState( char _cState )
{
	g_cSinusEffectState = _cState;
}
 
char GLI_fn_SinusEffect_vGetState( void )
{
	return g_cSinusEffectState;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : get / set flag
 ----------------------------------------------------------------------------------------
 */
void GLI_fn_SinusEffect_vSetFlag( char _cFlag )
{
	g_cSinusEffectFlag = _cFlag;
}
 
char GLI_fn_SinusEffect_vGetFlag( void )
{
	return g_cSinusEffectFlag;
}
 
 
/*
 ----------------------------------------------------------------------------------------
  Description   : return non zero value if object in second viewport have to be
				affected by sinus effect
 ----------------------------------------------------------------------------------------
 */
char GLI_fn_SinusEffect_cIsSecondViewportAffected( void )
{
	return g_cSinusEffectFlag & C_SinusEffect_cAffectSecondViewPort;
}
 
 
/*
 ----------------------------------------------------------------------------------------
  Description   : set frequences
 ----------------------------------------------------------------------------------------
 */
void GLI_fn_SinusEffect_vSetFreq( long _lXFreq, long _lYFreq, long _lZFreq )
{
	a3_lSinEffectFreq[0] = _lXFreq;
	a3_lSinEffectFreq[1] = _lYFreq;
	a3_lSinEffectFreq[2] = _lZFreq;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : Set amplitude vector
 ----------------------------------------------------------------------------------------
 */
void GLI_fn_SinusEffect_vSetAmplitude( MTH3D_tdstVector *_p_stAmpVector )
{
	MTH3D_M_vCopyVector( &stSinEffectAmp, _p_stAmpVector );
}
 
 
/*
 ----------------------------------------------------------------------------------------
  Description   : 2D Sinus effect 
 ----------------------------------------------------------------------------------------
 */
void GLI_v2DSinusEffect(GLI_tdstInternalGlobalValuesFor3dEngine *p_stGlobalsParrameters,long xStart,long xNumber)
{
	/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
	long					lVerticeY;
	long					lVerticeX;
	GLI_tdstAligned3DVector *p_Vertex3D ;
	GLI_tdstAligned2DVector *p_Vertex2D , *p_Vertex2DEnd ;
	MTH_tdxReal				xFactor;
	/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
	
	/*
	 * init loop data
	 */
	p_Vertex3D		= p_stGlobalsParrameters->GLI_TurnedScaledDisplecedPoint + xStart;
	p_Vertex2D		= p_stGlobalsParrameters->GLI_ScreenPoint + xStart;
	p_Vertex2DEnd	= p_Vertex2D + xNumber;
 
	/*
	 * loop on vertex
	 */
	if (g_cSinusEffectFlag & C_SinusEffect_cUseZFactor )
	{
		for ( ;p_Vertex2D < p_Vertex2DEnd; p_Vertex2D++, p_Vertex3D ++)
		{
			if (p_Vertex3D->xZ > GLI_C_xZClippingNear)
			{
				*(float *)((void *)&lVerticeX) = (p_Vertex2D->xX) + a3_xSinEffectBase[0] + GLI_fF2pow24;
				*(float *)((void *)&lVerticeY) = (p_Vertex2D->xY) + a3_xSinEffectBase[1] + GLI_fF2pow24;
				xFactor = (p_Vertex2D->xOoZ > 0.005) ? 1 : 200 * p_Vertex2D->xOoZ;
 
				p_Vertex2D->xX += p_Vertex2D->xX + a64_fSinTable [ lVerticeX & 63] * stSinEffectAmp.xX * xFactor;
				p_Vertex2D->xY += p_Vertex2D->xY + a64_fSinTable [ lVerticeY & 63] * stSinEffectAmp.xY * xFactor;
			}
		}
	}
	else
	{
		for ( ;p_Vertex2D < p_Vertex2DEnd; p_Vertex2D++, p_Vertex3D ++)
		{
			if (p_Vertex3D->xZ > GLI_C_xZClippingNear)
			{
				*(float *)((void *)&lVerticeX) = (p_Vertex2D->xX) + a3_xSinEffectBase[0] + GLI_fF2pow24;
				*(float *)((void *)&lVerticeY) = (p_Vertex2D->xY) + a3_xSinEffectBase[1] + GLI_fF2pow24;
 
				p_Vertex2D->xX += a64_fSinTable[ lVerticeX & 63 ] * stSinEffectAmp.xX;
				p_Vertex2D->xY += a64_fSinTable[ lVerticeY & 63 ] * stSinEffectAmp.xY;
			}
		}
	}
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : update effect variable.
					called only once by trame before world is displayed
 ----------------------------------------------------------------------------------------
 */
MTH_tdxReal gs_xFactor;
 
void GLI_vUpdateEffectData( unsigned long _ulDeltaT )
{
	MTH_tdxReal xFactor;
 
	gs_xFactor = xFactor = MTH_M_xMul( (float)_ulDeltaT, 0.0128f );
 
	a3_xSinEffectBase[0] += a3_lSinEffectFreq[0] * xFactor;
	a3_xSinEffectBase[1] += a3_lSinEffectFreq[1] * xFactor;
	a3_xSinEffectBase[2] += a3_lSinEffectFreq[2] * xFactor;
}
 
 
/*ENDANNECY VL}*/
 
#ifdef __cplusplus
} /*extern "C"*/
#endif
