/*
 =======================================================================================
  Name        : Fog.c
  Description : Fog high level functions
 =======================================================================================
 */
 
/*
Tested with LINT
*/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
#define MTH_LOW
#include "gli_st.h"
#include "GLI_Defn.h"
#include "light_st.h"
#include "PvObj_st.h"
#include "Liste.h"
#include "vpt3D.h"
#include "camera.h"
#include "light.h"
#include "PRF.h"
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
extern GLI_tdstInternalGlobalValuesFor3dEngine *GLI_BIG_GLOBALS;
 
/*
 =======================================================================================
    Globals 
 =======================================================================================
 */
 
/* Global variables for a global fog */
tdstFogParams		GLI_g_stSaveFog;
ACP_tdxBool			GLI_g_bSaveFog;
 
char			    GLI_cGlobalFogIsOn = 0;
MTH_tdxReal		    GLI_xFogNear, GLI_xFogFar, GLI_xFogInfinite;
MTH_tdxReal		    GLI_xFogBlendNear, GLI_xFogBlendFar;
GEO_tdstColor	    GLI_stFogColor;
 
tdstFogParams       GLI_ga_stFogTable[ GLI_C_lMaxFog ];
tdstFogParams       *GLI_gp_stCurrentFog = GLI_ga_stFogTable;
tdstFogParams       *GLI_gp_stLastFog = GLI_ga_stFogTable + GLI_C_lMaxFog;
 
/*
 =======================================================================================
    Functions 
 =======================================================================================
 */
 
#ifdef __cplusplus
extern "C"
{
#endif
 
#ifndef RETAIL
/*
 ----------------------------------------------------------------------------------------
  Description   : Set the Fog (old function kept for compatibility )
                used only by editors
 ----------------------------------------------------------------------------------------
 */
void GLI_vSetFog(GLI_tdxValue  xDepthStart, GLI_tdxValue  xDepthEnd, GLI_tdxValue  xInfinite, GEO_tdstColor *p_stFogColor)
{
	long xDepthStartCOR, xDepthEndCOR ;
    float xChange;
 
    /*
     * check params
     */
    if (xDepthEnd < xDepthStart) 
    {
        xChange = xDepthStart;
        xDepthStart = xDepthEnd ;
        xDepthEnd  = xChange;
    }
    if (xInfinite < xDepthEnd) 
        xInfinite = xDepthEnd;
 
    /* This is for correct a bug*/
    if ( xInfinite != 0 )
    {
        xDepthStartCOR = (long)(xDepthStart*64.f / xInfinite) ;
        xDepthEndCOR = (long)(xDepthEnd*64.f / xInfinite) ;
        xDepthStart = (float)(pow(2.0f,3.0 + (double)(xDepthStartCOR>>2)) / (float)(8 - (xDepthStartCOR & 3)) * GLI_C_xZClippingNear);
        xDepthEnd = (float)(pow(2.0f,3.0 + (double)(xDepthEndCOR>>2)) / (float)(8 - (xDepthEndCOR & 3)) * GLI_C_xZClippingNear);
    }
 
    GLI_vSetFog2(0.0f, xDepthStart / 4.0f, 255.0f, xDepthEnd / 4.0f, 0.0f,p_stFogColor);
}
#endif
 
/*
 ----------------------------------------------------------------------------------------
  Description   : Set the Fog (old function kept for compatibility )
 ----------------------------------------------------------------------------------------
 */
void GLI_vSetFog2( GLI_tdxValue xBlendStart, GLI_tdxValue xDepthStart, GLI_tdxValue xBlendEnd, GLI_tdxValue xDepthEnd, GLI_tdxValue xInfinite, GEO_tdstColor *p_stFogColor)
{
    tdstFogParams  *GLI_ga_stFogStart;
 
    /*
     * check params
     */
    if (xDepthEnd < xDepthStart) 
    {
        GLI_gp_stCurrentFog->xDepthStart = xDepthEnd;
        GLI_gp_stCurrentFog->xDepthEnd   = xDepthStart;
    }
    else
    {
        GLI_gp_stCurrentFog->xDepthStart = xDepthStart;
        GLI_gp_stCurrentFog->xDepthEnd   = xDepthEnd;
    }
 
    if (xInfinite < GLI_gp_stCurrentFog->xDepthEnd) 
        GLI_gp_stCurrentFog->xInfinite   = xDepthEnd;
    else
        GLI_gp_stCurrentFog->xInfinite   = xInfinite;
 
    if (xBlendStart < 0.0f)
        xBlendStart = 0.0f;
    else if (xBlendStart > 255.0f)
        xBlendStart = 255.0f;
 
    if (xBlendEnd < 0.0f)
        xBlendEnd = 0.0f;
    else if (xBlendEnd > 255.0f)
        xBlendEnd = 255.0f;
 
    GLI_gp_stCurrentFog->xBlendStart = xBlendStart;
    GLI_gp_stCurrentFog->xBlendEnd   = xBlendEnd;
    GLI_gp_stCurrentFog->stColor     = *p_stFogColor;
 
    
    for ( GLI_ga_stFogStart = GLI_ga_stFogTable; GLI_ga_stFogStart < GLI_gp_stCurrentFog; GLI_ga_stFogStart++ )
    {
        if (memcmp( GLI_gp_stCurrentFog, GLI_ga_stFogStart, sizeof(tdstFogParams) ) == 0)
        {
            GLI_BIG_GLOBALS->p_stActiveFog = GLI_ga_stFogStart;
            return;
        }
    }
 
    
    GLI_BIG_GLOBALS->p_stActiveFog = GLI_gp_stCurrentFog++;
    if (GLI_gp_stCurrentFog == GLI_gp_stLastFog)
        GLI_gp_stCurrentFog = GLI_ga_stFogTable;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : Get the Fog (old function kept for compatibility )
 ----------------------------------------------------------------------------------------
 */
void GLI_vGetFog(GLI_tdxValue *p_xDepthStart, GLI_tdxValue *p_xDepthEnd, GEO_tdstColor *p_stFogColor)
{
  *p_xDepthStart    = GLI_BIG_GLOBALS->p_stActiveFog->xDepthStart;
  *p_xDepthEnd      = GLI_BIG_GLOBALS->p_stActiveFog->xDepthEnd;
  *p_stFogColor     = GLI_BIG_GLOBALS->p_stActiveFog->stColor;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : set fog flag to indicate that fog is on
 ----------------------------------------------------------------------------------------
 */
void GLI_vFogOn(void)
{
    GLI_BIG_GLOBALS->xFogIsOn = 1;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : set fog flag for no fog
 ----------------------------------------------------------------------------------------
 */
void GLI_vFogOff(void)
{
    GLI_BIG_GLOBALS->p_stLastComputedFog = NULL;
    GLI_BIG_GLOBALS->p_stActiveFog = NULL;
    GLI_BIG_GLOBALS->xFogIsOn = 0;
}
 
#ifdef __cplusplus
} /* extern "C" */
#endif
