/*
 =======================================================================================
  Name        : Material.c
  Description : manage with material structure
 =======================================================================================
 */
 
#include "GLD.h"
#include "gli_st.h"
#include "GLI_Defn.h"
#include "mater_st.h"
#include "material.h"
#include "texture.h"
#include "MatBench.h"
#include "TexProcedural.h"
#include "DLLCaps.h"
 
/* for GLI_pGetVisualMaterialForLetter */
#include "Gli.h"
#include "VisuS_st.h"
#include "pcs.h"
#include "PO\POStruc.h"
#define D_ObjsTbls_Define
#include "incGAM.h"
 
/*
 =======================================================================================
    Constants
 =======================================================================================
 */
 
/* Cst replaced with GLI_g_stCaps.fRefreshRate */
/* #define GLI_C_fTransformSecondsInFramesRate 60.0f */
 
/*
 =======================================================================================
    Globals 
 =======================================================================================
 */
MTH_tdxReal     gs_fCoefOfMultiplicationForScolledTextures;
MTH_tdxReal     gs_fCoefOfMultiplicationForAnimatedTexture = 0.0f;
unsigned long   gs_lActualRefreshNumberForScolledTextures = 0;
 
/* 
 * for AGO 
 */
MTH_tdxReal     g_BaseTimeForParticleAnimation ;
unsigned char   g_bHasTextureAnimationFinished = 0 ;
unsigned char   g_bTakeCareOfAnimationCoordination = 0 ;
unsigned char   g_bOneShotAnim = 0;
 
#ifdef MULTI_TEXTURE
void GLI_vRefreshMultiTexturePart( GLI_tdstMaterial *_pst_Material );
#else
#define GLI_vRefreshMultiTexturePart(a)
#endif /*MULTI_TEXTURE*/
 
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
#ifdef __cplusplus
extern "C" 
{
#endif
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
/*
 =======================================================================================
    Material structure function (create/delete/duplicate) 
 =======================================================================================
 */
 
 
/*
 ----------------------------------------------------------------------------------------
  Description   : create a new material
 ----------------------------------------------------------------------------------------
 */
void GLI_xCreateMaterial( ACP_tdxHandleOfMaterial *hMaterial )
{
    MMG_fn_vAddMemoryInfo (MMG_C_lTypeGLI , MMG_C_lSubTypeMaterial , NULL);
    GEO_M_CPAMalloc( *hMaterial, GLI_tdstMaterial *, sizeof ( GLI_tdstMaterial ), E_uwGEONotEnoughtMemory );
  
    (*hMaterial)->stAmbient.xR = 0.0f ;
    (*hMaterial)->stAmbient.xG = 0.1f ;
    (*hMaterial)->stAmbient.xB = 0.1f ;
  
    (*hMaterial)->stDiffuse.xR = 0.8f ;
    (*hMaterial)->stDiffuse.xG = 0.8f ;
    (*hMaterial)->stDiffuse.xB = 0.8f ;
  
    (*hMaterial)->stColor.xR = 1.0f;
    (*hMaterial)->stColor.xG = 0.0f;
    (*hMaterial)->stColor.xB = 1.0f;
  
    (*hMaterial)->p_stTexture = NULL;
    (*hMaterial)->xMaterialType = 0xFFFFFFFF;
    (*hMaterial)->lIncrementIsEnable = 0;
  
    (*hMaterial)->p_stFistAnimatedTExtureNode = NULL;
    (*hMaterial)->p_stActualAnimatedTExtureNode = NULL;
    (*hMaterial)->lNumberOfDisplayNode = 0;
    (*hMaterial)->xActualDisplayTimeSinceStartOfLastTexture = gs_fCoefOfMultiplicationForAnimatedTexture;
    (*hMaterial)->lActualRefreshNumber = gs_lActualRefreshNumberForScolledTextures ;
    GLI_vUnLockAnimatedTexture(*hMaterial);
 
    GLI_Material_fn_vInitMultiTexturePart( *hMaterial );
 
    MATBENCH_fn_vAddMaterialRef( *hMaterial );
}
  
/*
 ----------------------------------------------------------------------------------------
  Description   : create a new material
 ----------------------------------------------------------------------------------------
 */
void GLI_xDeleteMaterial( ACP_tdxHandleOfMaterial hMaterial )
{
    GEO_M_CPAFree( hMaterial);
    MATBENCH_fn_vDeleteMaterialRef( hMaterial );
}
  
/*
 ----------------------------------------------------------------------------------------
  Description   : duplicate a material
 ----------------------------------------------------------------------------------------
 */
void GLI_xDuplicateMaterial ( ACP_tdxHandleOfMaterial *_p_hDest, ACP_tdxHandleOfMaterial _hSource )
  {
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    struct GEO_tdstColor_   stColor;
    GLI_tdstTexture         *p_stTexture;
    unsigned long           xMType;
    long                    lSpecularExponent;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
        
    GLI_xCreateMaterial(_p_hDest);
    
    **_p_hDest = *_hSource;
 
    GLI_xGetMaterialAmbientCoef(_hSource,&stColor);
    GLI_xSetMaterialAmbientCoef(*_p_hDest,&stColor);
    
    GLI_xGetMaterialDiffuseCoef(_hSource,&stColor);
    GLI_xSetMaterialDiffuseCoef(*_p_hDest,&stColor);
    
    GLI_xGetMaterialColor(_hSource,&stColor);
    GLI_xSetMaterialColor(*_p_hDest,&stColor);
    
    GLI_xGetMaterialTexture (_hSource,&p_stTexture);
    GLI_xSetMaterialTexture (*_p_hDest,p_stTexture);
    
    GLI_xGetMaterialType (_hSource,&xMType);
    GLI_xSetMaterialType (*_p_hDest,xMType);
    
    GLI_xGetMaterialSpecularCoef (_hSource,&lSpecularExponent,&stColor);
    GLI_xSetMaterialSpecularCoef (*_p_hDest,lSpecularExponent,&stColor);
}
  
/*
 =======================================================================================
    function to access member of material structure 
 =======================================================================================
 */
 
/*
 * material ambient color
 */
void GLI_xSetMaterialAmbientCoef( ACP_tdxHandleOfMaterial hMaterial, struct GEO_tdstColor_ *p_stColor )
{
    hMaterial->stAmbient = *p_stColor ;
}                        
  
void GLI_xGetMaterialAmbientCoef( ACP_tdxHandleOfMaterial hMaterial, struct GEO_tdstColor_ *p_stColor )
  {
    *p_stColor =   hMaterial->stAmbient ;
    
  }                        
  
/*
 * material color
 */
void GLI_xSetMaterialColor( ACP_tdxHandleOfMaterial hMaterial, struct GEO_tdstColor_ *p_stColor )
{
    hMaterial -> stColor = *p_stColor ;
}                        
  
void GLI_xGetMaterialColor( ACP_tdxHandleOfMaterial hMaterial, struct GEO_tdstColor_ *p_stColor )
{
    *p_stColor =   hMaterial->stColor;
}                        
 
/*
 * material diffuse color
 */
void GLI_xSetMaterialDiffuseCoef( ACP_tdxHandleOfMaterial hMaterial, struct GEO_tdstColor_ *p_stColor )
{
    hMaterial->stDiffuse = *p_stColor ;
}                        
  
void GLI_xGetMaterialDiffuseCoef( ACP_tdxHandleOfMaterial hMaterial, struct GEO_tdstColor_ *p_stColor )
{
    *p_stColor = hMaterial->stDiffuse ;
}                        
 
/*
 * material specular color
 */
void GLI_xSetMaterialSpecularCoef( ACP_tdxHandleOfMaterial hMaterial, long lSpecularExponent, struct GEO_tdstColor_ *p_stColor )
{
    hMaterial->stSpecular = *p_stColor ;
    hMaterial->lSpecularExponent = lSpecularExponent ;
}                        
  
void GLI_xGetMaterialSpecularCoef( ACP_tdxHandleOfMaterial hMaterial, long *p_lSpecularExponent, struct GEO_tdstColor_ *p_stColor )
{
    *p_stColor = hMaterial->stSpecular ;
    *p_lSpecularExponent = hMaterial->lSpecularExponent ;
}                        
 
/*
 * material type
 */
void GLI_xGetMaterialType ( ACP_tdxHandleOfMaterial  hMaterial, unsigned long *xMType ) 
{
    *xMType = hMaterial->xMaterialType; 
}
  
void GLI_xSetMaterialType ( ACP_tdxHandleOfMaterial  hMaterial, unsigned long xMType ) 
{
    hMaterial->xMaterialType = xMType ; 
}
 
void GLI_vSetMaterialAsChromed ( ACP_tdxHandleOfMaterial hMaterial, long lNumberOfTexture )
{
	if ( lNumberOfTexture )
	    hMaterial->xMaterialType &= GLI_C_lAllIsEnable - GLI_C_lIsNotChromed ;
	else
		hMaterial->xMaterialType |= GLI_C_lIsNotChromed ;
}
 
long GLI_bIsMaterialChromed ( ACP_tdxHandleOfMaterial hMaterial )
{
    return ((hMaterial->xMaterialType & GLI_C_lIsNotChromed) == 0);
}
 
long GLI_bIsMaterialBackface ( ACP_tdxHandleOfMaterial hMaterial )
{
    return ((hMaterial->xMaterialType & GLI_C_lIsTestingBackface) == 0);
}
 
long GLI_xIsMaterialTransparent( ACP_tdxHandleOfMaterial hMaterial )
{
    if ( ( hMaterial->xMaterialType & GLI_C_lIsNotGrided ) == 0 )
        return (1);
    if (hMaterial->p_stTexture != NULL)
        if ((hMaterial->p_stTexture->lTextureCaps & (GLI_C_lAlphaTexture + GLI_C_lNZTexture)) != 0)
            return (1);
      
    return 0;
}
 
 
/*
 * material texture
 */
void GLI_xSetMaterialTexture ( ACP_tdxHandleOfMaterial hMaterial, GLI_tdstTexture *p_stTexture )
{
    hMaterial->p_stTexture = p_stTexture ;
    
    if (p_stTexture != NULL)
    {
        if (p_stTexture->lTextureCaps & GLI_C_lAlphaTexture)
            hMaterial -> xMaterialType &= 0xffffffff - GLI_C_lIsTestingBackface;
 
        if (p_stTexture->lTextureCaps & GLI_C_lNoZBufferWriteTexture)
            hMaterial -> xMaterialType &= 0xffffffff - GLI_C_lIsWriteZBuffer;
        else
            hMaterial -> xMaterialType |= GLI_C_lIsWriteZBuffer;
    } 
    else 
        hMaterial -> xMaterialType |= GLI_C_lIsWriteZBuffer;
}
  
void GLI_xGetMaterialTexture ( ACP_tdxHandleOfMaterial hMaterial, GLI_tdstTexture **p_stTexture )
{
    *p_stTexture = hMaterial->p_stTexture;
}                        
 
 
  
 
/*
 =======================================================================================
    Functions for scrolling textures 
 =======================================================================================
 */
 
 
/*
 ----------------------------------------------------------------------------------------
  Description   : Set scrolling coefficient (On/off, speed on u and v)
 ----------------------------------------------------------------------------------------
 */
void GLI_xSetMaterialTextureScrollingCoef( ACP_tdxHandleOfMaterial hMaterial, long lNumberOfTexture, long bSwitch, float fUSpeed, float fVSpeed )
{
    hMaterial->fAddU = hMaterial->fConstantAddU = fUSpeed;
    hMaterial->fAddV = hMaterial->fConstantAddV = fVSpeed;
    hMaterial->lIncrementIsEnable = bSwitch ;
    if ( ( fUSpeed == 0.0f ) && ( fVSpeed == 0.0f ) )
        hMaterial->lIncrementIsEnable = 0;
}                        
  
/*
 ----------------------------------------------------------------------------------------
  Description   : Set shifting coefficient (On/off, position on u and v)
 ----------------------------------------------------------------------------------------
 */
void GLI_xSetMaterialTextureDecalage( ACP_tdxHandleOfMaterial hMaterial, long lNumberOfTexture, long bSwitch, float fUSpeed, float fVSpeed )
{ 
    hMaterial->fAddU = fUSpeed ;
    hMaterial->fAddV = fVSpeed ;
    hMaterial->lIncrementIsEnable = bSwitch ;
    if ( ( fUSpeed == 0.0f ) && ( fVSpeed == 0.0f ) )
        hMaterial->lIncrementIsEnable = 0;
}                        
  
/*
 ----------------------------------------------------------------------------------------
  Description   : retrieve scrolling coefficient (On/off, speed on u and v)
 ----------------------------------------------------------------------------------------
 */
void GLI_xGetMaterialTextureScrollingCoef( ACP_tdxHandleOfMaterial hMaterial, long lNumberOfTexture, long *p_bSwitch, float *p_fUSpeed, float *p_fVSpeed )
{
    *p_fUSpeed = hMaterial->fConstantAddU ;
    *p_fVSpeed = hMaterial->fConstantAddV ;
    *p_bSwitch = hMaterial->lIncrementIsEnable;
}                        
  
/*
 ----------------------------------------------------------------------------------------
  Description   : set state of scroll (on/off)
 ----------------------------------------------------------------------------------------
 */
void GLI_xSetMaterialTextureScrollingOnOff( ACP_tdxHandleOfMaterial hMaterial,long bSwitch) 
{
    if (bSwitch && (hMaterial->fConstantAddU == 0.0f) && (hMaterial -> fConstantAddV == 0.0f))
		return;
    hMaterial->lIncrementIsEnable = bSwitch;
}
 
/*
 =======================================================================================
    Functions for animated textures 
 =======================================================================================
 */
 
/*
 ----------------------------------------------------------------------------------------
  Description   : Create a structure to store a stage of texture animation
 ----------------------------------------------------------------------------------------
 */
void GLI_xCreateAnimatedTextureNode( GLI_tdstAnimatedTextureNode **h_AnimatedTextureNodeToCreate )
{
    MMG_fn_vAddMemoryInfo (MMG_C_lTypeGLI , MMG_C_lSubTypeAnimatedTexture , NULL);
    GEO_M_CPAMalloc( *h_AnimatedTextureNodeToCreate, GLI_tdstAnimatedTextureNode *, sizeof ( GLI_tdstAnimatedTextureNode ), E_uwGEONotEnoughtMemory );
    (*h_AnimatedTextureNodeToCreate)->p_stTexture           = NULL;
    (*h_AnimatedTextureNodeToCreate)->xDisplayTime          = 0;
    (*h_AnimatedTextureNodeToCreate)->p_stNextDisplayNode   = NULL;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : Add an animated texture to material
 ----------------------------------------------------------------------------------------
 */
void GLI_vAddMaterialAnimatedTexture( ACP_tdxHandleOfMaterial hMaterial, long lNumberOfAnimatedTexture, GLI_tdstTexture *p_stTexture ,float fExpositionTimeInSeconds)
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    GLI_tdstAnimatedTextureNode *p_NodeToCreate,*p_LastNode,*p_BeforeLastNode;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    
    hMaterial->lNumberOfDisplayNode++;
    GLI_xCreateAnimatedTextureNode(&p_NodeToCreate);
    p_NodeToCreate->p_stTexture  = p_stTexture ;
    p_NodeToCreate->xDisplayTime = fExpositionTimeInSeconds /* * GLI_g_stCaps.fRefreshRate */;
    
    if ((hMaterial -> lNumberOfDisplayNode == 1) || (lNumberOfAnimatedTexture == 0))
    {
        GLI_xSetMaterialTexture ( hMaterial , p_stTexture );
        p_NodeToCreate->p_stNextDisplayNode         = hMaterial -> p_stFistAnimatedTExtureNode;
        hMaterial->p_stFistAnimatedTExtureNode      = p_NodeToCreate;
        hMaterial->p_stActualAnimatedTExtureNode    = p_NodeToCreate;
    }
    else
    {
        p_BeforeLastNode = p_LastNode = hMaterial -> p_stFistAnimatedTExtureNode ;
        while ((p_LastNode != NULL) && (lNumberOfAnimatedTexture-- !=0 ))
        {
            p_BeforeLastNode = p_LastNode;
            p_LastNode = p_LastNode -> p_stNextDisplayNode ;
        }
        p_NodeToCreate->p_stNextDisplayNode = p_LastNode ;
        p_BeforeLastNode->p_stNextDisplayNode = p_NodeToCreate;
    }
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : return number of texture in animation
 ----------------------------------------------------------------------------------------
 */
long GLI_lGetMaterialNumberOfAnimatedTexture( ACP_tdxHandleOfMaterial hMaterial  )
{
    return ( hMaterial->lNumberOfDisplayNode );
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : get parameters of a node of texture animation
 ----------------------------------------------------------------------------------------
 */
void GLI_vGetMaterialAnimatedTexture( ACP_tdxHandleOfMaterial hMaterial, long lNumberOfAnimatedTexture, GLI_tdstTexture **h_stTexture, float *p_fDisplayTime )
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    GLI_tdstAnimatedTextureNode *p_Node;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  
    p_Node = hMaterial->p_stFistAnimatedTExtureNode;
  
    while (lNumberOfAnimatedTexture != 0)
    {
        lNumberOfAnimatedTexture--;
        p_Node = p_Node->p_stNextDisplayNode ;
    }
  
    *p_fDisplayTime = p_Node->xDisplayTime /* * 1.0f / GLI_g_stCaps.fRefreshRate */;
    *h_stTexture = p_Node->p_stTexture;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : return index of current node in texture animation
 ----------------------------------------------------------------------------------------
 */
long GLI_lGetCurrentAnimatedTextureNumber( ACP_tdxHandleOfMaterial hMaterial )
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    GLI_tdstAnimatedTextureNode *p_Node;
    long                        lNumber=1;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
    p_Node = hMaterial->p_stFistAnimatedTExtureNode;
    while (p_Node != hMaterial->p_stActualAnimatedTExtureNode)
    {
        lNumber ++;
        p_Node = p_Node->p_stNextDisplayNode ;
    }
    
    if(p_Node == hMaterial->p_stActualAnimatedTExtureNode)
	    return lNumber;
    
	return 0;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : change current node in texture animation
 ----------------------------------------------------------------------------------------
 */
void GLI_vSetCurrentAnimatedTextureNumber( ACP_tdxHandleOfMaterial hMaterial, long lTextureNumber )
{
    GLI_tdstAnimatedTextureNode *p_Node;
    long                        lNumber = 1;
 
    p_Node = hMaterial->p_stFistAnimatedTExtureNode ;
    while ( p_Node && lNumber != lTextureNumber )
    {
        lNumber ++;
        p_Node = p_Node -> p_stNextDisplayNode ;
    }
    hMaterial -> p_stActualAnimatedTExtureNode = p_Node ? p_Node : hMaterial->p_stFistAnimatedTExtureNode ;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : change parameters of a node in texture animation
 ----------------------------------------------------------------------------------------
 */
void GLI_vModifyMaterialAnimatedTexture( ACP_tdxHandleOfMaterial hMaterial, long lNumberOfAnimatedTexture, GLI_tdstTexture *p_stTexture, float fDisplayTime)
{
    GLI_tdstAnimatedTextureNode *p_Node;
    
    p_Node = hMaterial->p_stFistAnimatedTExtureNode;
    while (lNumberOfAnimatedTexture != 0)
    {
        lNumberOfAnimatedTexture--;
        p_Node = p_Node->p_stNextDisplayNode ;
    }
    p_Node->xDisplayTime = fDisplayTime /* * GLI_g_stCaps.fRefreshRate */ ;
    p_Node->p_stTexture  = p_stTexture ;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : delete a node in texture animation
 ----------------------------------------------------------------------------------------
 */
void  GLI_vDeleteMaterialAnimatedTexture( ACP_tdxHandleOfMaterial hMaterial, long lNumberOfAnimatedTexture)
{
    GLI_tdstAnimatedTextureNode *p_Node,*p_BeforeLastNode ;
 
    if (hMaterial -> lNumberOfDisplayNode == 0) 
        return;
  
    if (hMaterial -> lNumberOfDisplayNode == 1) 
    {
        hMaterial -> lNumberOfDisplayNode = 0; 
        hMaterial -> p_stActualAnimatedTExtureNode = hMaterial -> p_stFistAnimatedTExtureNode = NULL;
    }
 
	else 
	{
		p_BeforeLastNode = p_Node = hMaterial -> p_stFistAnimatedTExtureNode;

		if (lNumberOfAnimatedTexture == 0) 
		{
			hMaterial -> p_stFistAnimatedTExtureNode = hMaterial -> p_stFistAnimatedTExtureNode -> p_stNextDisplayNode ;
		}
		else
		{
			while ((lNumberOfAnimatedTexture != 0) && (p_Node != NULL))
			{
				lNumberOfAnimatedTexture --;
				p_BeforeLastNode = p_Node ;
				p_Node = p_Node -> p_stNextDisplayNode ;
			}
			p_BeforeLastNode -> p_stNextDisplayNode = p_Node ;
		}
		hMaterial -> lNumberOfDisplayNode--;
	}
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : Lock/Unlock animation
 ----------------------------------------------------------------------------------------
 */
void GLI_vLockAnimatedTexture(ACP_tdxHandleOfMaterial _hMaterial)
{
	_hMaterial->xIsLocked=TRUE;
}
 
void GLI_vUnLockAnimatedTexture(ACP_tdxHandleOfMaterial _hMaterial)
{
	_hMaterial->xIsLocked=FALSE;
}
 
 
/*
 =======================================================================================
    Other functions 
 =======================================================================================
 */
 
/*
 ----------------------------------------------------------------------------------------
  Description   : Set global parameters that are used to scroll and animate texture
 ----------------------------------------------------------------------------------------
 */
void GLI_vRefreshAllCyclingTextures( float fCoefOfMultiplication )
{
    gs_fCoefOfMultiplicationForScolledTextures = fCoefOfMultiplication;
    gs_fCoefOfMultiplicationForAnimatedTexture += fCoefOfMultiplication;
    gs_lActualRefreshNumberForScolledTextures++;
}
 
 
/*
 ----------------------------------------------------------------------------------------
  Description   : refresh scrolled and animated textures
 ----------------------------------------------------------------------------------------
 */
void GLI_xRefreshAnimatedTexture( ACP_tdxHandleOfMaterial hMaterial )
{
    float fNbFramesToDisplay;
    /*if ( (hMaterial->p_stTexture != NULL) && (hMaterial->lActualRefreshNumber != gs_lActualRefreshNumberForScolledTextures) )*/
 
    /*
     * multitexture
     */
    if (hMaterial->lActualRefreshNumber != gs_lActualRefreshNumberForScolledTextures)
        GLI_vRefreshMultiTexturePart( hMaterial );
 
    if ( hMaterial->p_stTexture != NULL ) 
    {
        /*
         * scrolled textures
         */
        if (hMaterial->lIncrementIsEnable != 0)
        {
            hMaterial->p_stTexture->lIncrementIsEnable = 1;
 
            /*if ( hMaterial->lIncrementIsEnable == 1 )*/
            if ( (hMaterial->lIncrementIsEnable == 1) && (hMaterial->lActualRefreshNumber != gs_lActualRefreshNumberForScolledTextures) )
            {
                hMaterial->fAddU += hMaterial->fConstantAddU * gs_fCoefOfMultiplicationForScolledTextures;
                hMaterial->fAddV += hMaterial->fConstantAddV * gs_fCoefOfMultiplicationForScolledTextures;
                /*hMaterial->p_stTexture->fAddU = hMaterial->fAddU;*/
                /*hMaterial->p_stTexture->fAddV = hMaterial->fAddV;*/
 
                if (hMaterial->fAddU >= 0.0f)
                    hMaterial->fAddU = hMaterial->fAddU - MTH_M_xRealToLong(hMaterial->fAddU);
                else
                    hMaterial->fAddU = -((-hMaterial->fAddU) - MTH_M_xRealToLong((-hMaterial->fAddU)));
 
                if (hMaterial->fAddV >= 0.0f)
                    hMaterial->fAddV = hMaterial->fAddV - MTH_M_xRealToLong(hMaterial->fAddV);
                else
                    hMaterial->fAddV = -((-hMaterial->fAddV) - MTH_M_xRealToLong((-hMaterial->fAddV)));
            }
            /*else if (hMaterial->lIncrementIsEnable == 2)*/
            /*{*/
                hMaterial->p_stTexture->fAddU = hMaterial->fAddU ;
                hMaterial->p_stTexture->fAddV = hMaterial->fAddV ;
            /*}*/
        }
        else
            hMaterial->p_stTexture->lIncrementIsEnable = 0;
 
        /*
         * animated textures
         */
	    if ( ( hMaterial->lNumberOfDisplayNode > 1 ) && ( hMaterial->xIsLocked == FALSE ) && (hMaterial->lActualRefreshNumber != gs_lActualRefreshNumberForScolledTextures) )
	    {
	        //long lAntiBug; /* Could bug for example if display time = 0 or if the material has not been displayed since a long time...*/
            long lSaveType;
			    
            //lAntiBug = 10;
            g_bHasTextureAnimationFinished = 0;
 
            if ( g_bTakeCareOfAnimationCoordination ) 
            {
                hMaterial->p_stActualAnimatedTExtureNode = hMaterial->p_stFistAnimatedTExtureNode ;
 
                fNbFramesToDisplay = hMaterial->p_stActualAnimatedTExtureNode->xDisplayTime * GLI_g_stCaps.fRefreshRate;
                while ( (gs_fCoefOfMultiplicationForAnimatedTexture - g_BaseTimeForParticleAnimation > fNbFramesToDisplay ) ) 
                {
			        g_BaseTimeForParticleAnimation += fNbFramesToDisplay;
                    if ( hMaterial->p_stActualAnimatedTExtureNode->p_stNextDisplayNode != NULL ) 
                    {
  		                hMaterial->p_stActualAnimatedTExtureNode = hMaterial->p_stActualAnimatedTExtureNode->p_stNextDisplayNode;
                    }
                    else 
                    {
                        if ( g_bOneShotAnim ) 
                            g_bHasTextureAnimationFinished = 1;
                        else 
                            hMaterial->p_stActualAnimatedTExtureNode = hMaterial->p_stFistAnimatedTExtureNode;
                        break;
                    }
                    fNbFramesToDisplay = hMaterial->p_stActualAnimatedTExtureNode->xDisplayTime * GLI_g_stCaps.fRefreshRate;
                }
            }
            else 
            {
                
                if ( MTH_M_bGreaterZero(hMaterial -> p_stActualAnimatedTExtureNode -> xDisplayTime) )
                {
                    fNbFramesToDisplay = hMaterial->p_stActualAnimatedTExtureNode->xDisplayTime * GLI_g_stCaps.fRefreshRate;
                    //while (((gs_fCoefOfMultiplicationForAnimatedTexture - hMaterial -> xActualDisplayTimeSinceStartOfLastTexture) > hMaterial -> p_stActualAnimatedTExtureNode -> xDisplayTime) && (lAntiBug>0))
                    while (((gs_fCoefOfMultiplicationForAnimatedTexture - hMaterial -> xActualDisplayTimeSinceStartOfLastTexture) > fNbFramesToDisplay) )
                    {
                        //lAntiBug--;
                        hMaterial -> xActualDisplayTimeSinceStartOfLastTexture += fNbFramesToDisplay;
                        if (hMaterial -> p_stActualAnimatedTExtureNode -> p_stNextDisplayNode != NULL)
                            hMaterial -> p_stActualAnimatedTExtureNode = hMaterial -> p_stActualAnimatedTExtureNode -> p_stNextDisplayNode;
                        else
                            hMaterial -> p_stActualAnimatedTExtureNode = hMaterial -> p_stFistAnimatedTExtureNode;
                        fNbFramesToDisplay = hMaterial->p_stActualAnimatedTExtureNode->xDisplayTime * GLI_g_stCaps.fRefreshRate;
                    }
                }
            }
			/*
			if (!lAntiBug)
			{
			    hMaterial->xActualDisplayTimeSinceStartOfLastTexture = gs_fCoefOfMultiplicationForAnimatedTexture;
			    hMaterial->p_stActualAnimatedTExtureNode = hMaterial -> p_stFistAnimatedTExtureNode;
			}
			*/
			if ((hMaterial->p_stActualAnimatedTExtureNode -> p_stTexture != NULL) && (hMaterial -> p_stTexture != NULL))
            {
			    hMaterial->p_stActualAnimatedTExtureNode->p_stTexture->fAddU = hMaterial->p_stTexture->fAddU;
			    hMaterial->p_stActualAnimatedTExtureNode->p_stTexture->fAddV = hMaterial->p_stTexture->fAddV;
			    hMaterial->p_stActualAnimatedTExtureNode->p_stTexture->lIncrementIsEnable = hMaterial->p_stTexture->lIncrementIsEnable;
            }
    	
            GLI_xGetMaterialType ( hMaterial , &lSaveType );
			GLI_xSetMaterialTexture ( hMaterial , hMaterial -> p_stActualAnimatedTExtureNode -> p_stTexture );
            GLI_xSetMaterialType ( hMaterial , lSaveType );
        }
 
        /*
         * Procedural Texture
         */
        TEXPRO_fnv_RefreshProceduralTexture( hMaterial->p_stTexture, gs_lActualRefreshNumberForScolledTextures );
    }
    
    if ( !g_bTakeCareOfAnimationCoordination )
        hMaterial->lActualRefreshNumber = gs_lActualRefreshNumberForScolledTextures;
}
 
/*
 =======================================================================================
    functions to manage with multitexturing
 =======================================================================================
 */
 
#ifdef MULTI_TEXTURE
 
#ifndef RETAIL
 
#define C_lNumberOfColorOp  10
static char *gas_szColorOpDesc[ C_lNumberOfColorOp ] =
{
    "Disable",
    "Specular",
    "Diffuse",
    "Constant",
    "SpecularAlpha",
    "DiffuseAlpha",
    "ConstantAlpha",
    "SpecularColor",
    "DiffuseColor",
    "ConstantColor"
};
 
#define C_lNumberOfOp   8
static char *gas_szOpDesc[ C_lNumberOfOp ] =
{
    "Mul",
    "Add",
    "Copy",
    "AlphaTrans",
    "AlphaPremult",
    "Mul2X",
    "Invert",
    "AddSmooth"
};
 
#define C_lNumberOfUVSource 7
static char *gas_szUVSourceDesc[ C_lNumberOfUVSource ] =
{
    "NoSource",
    "Object1",
    "Object2",
    "Chrome",
    "Screen",
    "Cartoon",
    "SolarPhong"
};
 
#endif /*RETAIL*/
 
/*
 ----------------------------------------------------------------------------------------
  Description   : Init Multi texture part of a material
 ----------------------------------------------------------------------------------------
 */
void GLI_Material_fn_vInitMultiTexturePart( ACP_tdxHandleOfMaterial _hVisualMat )
{
    GLI_tdstMultiTextureMaterial *pst_MTM, *pst_LastMTM;
    
    memset( _hVisualMat->a_stMultiMaterial, 0, 8 * sizeof( GLI_tdstMultiTextureMaterial ) );
    pst_MTM = _hVisualMat->a_stMultiMaterial;
    pst_LastMTM = pst_MTM + 8;
    for ( ; pst_MTM < pst_LastMTM; pst_MTM++ )
    {
        pst_MTM->st_UVStaticPos.stMat[0][0] = 1.0f;
        pst_MTM->st_UVStaticPos.stMat[1][1] = 1.0f;
        pst_MTM->st_UVDynamicPos.stMat[0][0] = 1.0f;
        pst_MTM->st_UVDynamicPos.stMat[1][1] = 1.0f;
    }
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : update UV computing matrice of multimaterial
 ----------------------------------------------------------------------------------------
 */
void GLI_vRefreshMultiTexturePart( GLI_tdstMaterial *_pst_Material )
{
    GLI_tdstMultiTextureMaterial *pst_MTM;
 
    pst_MTM = _pst_Material->a_stMultiMaterial;
    while( pst_MTM->c_Flags & C_MTMF_cIsNotLastTexture)
    {
        pst_MTM++;
 
        TEXPRO_fnv_RefreshProceduralTexture( pst_MTM->pst_Texture, gs_lActualRefreshNumberForScolledTextures);
 
        /*
        {
            char *szName;

            szName = pst_MTM->pst_Texture->a255_cFileName + strlen(pst_MTM->pst_Texture->a255_cFileName);
            
            if ( stricmp( szName - 11, "bumpinv.tga") == 0 )
            {
                static float alpha = 0;
                static float dalpha = 0.05f;
                static float amplitude = 0.02f;
 
                alpha += dalpha;
                pst_MTM->st_UVStaticPos.stTrans[0] = (float) (amplitude * cos(alpha ));
                pst_MTM->st_UVStaticPos.stTrans[1] = (float) (amplitude * sin(alpha ));
            }
            else if ( stricmp( szName - 9, "light.tga") == 0 )
            {
                static float alpha = 0;
                static float dalpha = 0.02f;
                static float amplitude = 0.3f;
 
                alpha += dalpha;
                pst_MTM->st_UVStaticPos.stTrans[0] = (float)( amplitude * cos(alpha ) );
                pst_MTM->st_UVStaticPos.stTrans[1] = (float)( amplitude * sin(alpha ) );
            }
        }
        */
 
        if ( pst_MTM->c_Flags & C_MTMF_cUVDynamicTransEnable )
        {
            pst_MTM->st_UVStaticPos.stTrans[0] += pst_MTM->st_UVDynamicPos.stTrans[0];
            if ( *(long *) &pst_MTM->st_UVStaticPos.stTrans[0] & 0x80000000 )
                pst_MTM->st_UVStaticPos.stTrans[0] = -((-pst_MTM->st_UVStaticPos.stTrans[0]) - MTH_M_xRealToLong((-pst_MTM->st_UVStaticPos.stTrans[0])));
            else 
                pst_MTM->st_UVStaticPos.stTrans[0] = pst_MTM->st_UVStaticPos.stTrans[0] - MTH_M_xRealToLong(pst_MTM->st_UVStaticPos.stTrans[0]);
 
            pst_MTM->st_UVStaticPos.stTrans[1] += pst_MTM->st_UVDynamicPos.stTrans[1];
            if ( *(long *) &pst_MTM->st_UVStaticPos.stTrans[1] & 0x80000000 )
                pst_MTM->st_UVStaticPos.stTrans[1] = -((-pst_MTM->st_UVStaticPos.stTrans[1]) - MTH_M_xRealToLong((-pst_MTM->st_UVStaticPos.stTrans[1])));
            else 
                pst_MTM->st_UVStaticPos.stTrans[1] = pst_MTM->st_UVStaticPos.stTrans[1] - MTH_M_xRealToLong(pst_MTM->st_UVStaticPos.stTrans[1]);
        }
 
        if ( pst_MTM->c_Flags & C_MTMF_cUVDynamicMatEnable )
        {
            float fSave;
 
            fSave = pst_MTM->st_UVStaticPos.stMat[0][0];
            pst_MTM->st_UVStaticPos.stMat[0][0] = fSave * pst_MTM->st_UVDynamicPos.stMat[0][0] + pst_MTM->st_UVStaticPos.stMat[0][1] * pst_MTM->st_UVDynamicPos.stMat[1][0];
            pst_MTM->st_UVStaticPos.stMat[0][1] = fSave * pst_MTM->st_UVDynamicPos.stMat[0][1] + pst_MTM->st_UVStaticPos.stMat[0][1] * pst_MTM->st_UVDynamicPos.stMat[1][1];
 
            fSave = pst_MTM->st_UVStaticPos.stMat[1][0];
            pst_MTM->st_UVStaticPos.stMat[1][0] = fSave * pst_MTM->st_UVDynamicPos.stMat[0][0] + pst_MTM->st_UVStaticPos.stMat[1][1] * pst_MTM->st_UVDynamicPos.stMat[1][0];
            pst_MTM->st_UVStaticPos.stMat[1][1] = fSave * pst_MTM->st_UVDynamicPos.stMat[0][1] + pst_MTM->st_UVStaticPos.stMat[1][1] * pst_MTM->st_UVDynamicPos.stMat[1][1];
        }
    }
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : Set texture for a given stage
 ----------------------------------------------------------------------------------------
 */
long GLI_Material_fn_lSetTexture( ACP_tdxHandleOfMaterial _hVisualMat, long _lIndex, struct GLI_tdstTexture_ *_p_stTexture )
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    long i;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
    if ( (_lIndex < 0) || (_lIndex >= 8) )
        return 0;
 
    _hVisualMat->a_stMultiMaterial[_lIndex].pst_Texture = _p_stTexture;
    for (i = 7; i >= 0; i-- )
    {
        _hVisualMat->a_stMultiMaterial[i].c_Flags = 0;
        if (_hVisualMat->a_stMultiMaterial[i].pst_Texture != NULL )
            break;
    }
    for ( --i ; i >= 0; i-- )
        _hVisualMat->a_stMultiMaterial[i].c_Flags |= C_MTMF_cIsNotLastTexture;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : Set texture operation between stage _lIndex and stage _lIndex + 1
 ----------------------------------------------------------------------------------------
 */
long GLI_Material_fn_lSetTextureOp( ACP_tdxHandleOfMaterial _hVisualMat, long _lIndex, long _lTextureOp )
{
    if ( (_lIndex < 0) || (_lIndex >= 8) )
        return 0;
    _hVisualMat->a_stMultiMaterial[ _lIndex ].c_Operator = (char) _lTextureOp;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : Set texture operation between stage _lIndex and stage _lIndex + 1
 ----------------------------------------------------------------------------------------
 */
long GLI_Material_fn_lSetUVFunction
    ( 
        ACP_tdxHandleOfMaterial _hVisualMat, long _lCanal, long _lFunc, 
        float _fScaleU, float _fScaleV, 
        float _fAlphaSpeed, float _fAlpha, 
        float _fSpeedU, float _fSpeedV,
        float _fOffsetU, float _fOffsetV 
    )
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    GLI_tdstMultiTextureMaterial    *pst_MTM;
    float   fCos, fSin;
    float fMat[2][2];
 
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
    if ( (_lCanal < 0) || (_lCanal >= 8) )
        return 0;
 
    pst_MTM = _hVisualMat->a_stMultiMaterial + _lCanal;
    pst_MTM->c_UVSource = (char) _lFunc;
 
    pst_MTM->st_UVStaticPos.stMat[0][0] = _fScaleU;
    pst_MTM->st_UVStaticPos.stMat[1][1] = _fScaleV;
    if ( (_fScaleU != 1.0f) && (_fScaleV != 1.0f) )
        pst_MTM->c_Flags |= C_MTMF_cUVStaticMatEnable;
 
    if ( _fAlpha != 0.0f )
    {
        fCos = (float) cos( _fAlpha );
        fSin = (float) sin( _fAlpha );
 
        memcpy( fMat, &pst_MTM->st_UVStaticPos, 4 * sizeof( float ) );
 
        pst_MTM->st_UVStaticPos.stMat[0][0] = fMat[0][0] * fCos;
        pst_MTM->st_UVStaticPos.stMat[0][1] = fMat[0][0] * fSin;
        pst_MTM->st_UVStaticPos.stMat[1][0] = -fMat[1][1] * fSin;
        pst_MTM->st_UVStaticPos.stMat[1][1] = fMat[1][1] * fCos;
 
        pst_MTM->c_Flags |= C_MTMF_cUVStaticMatEnable;
    }

    if ( _fAlphaSpeed != 0.0f )
    {
        fCos = (float) cos( _fAlphaSpeed );
        fSin = (float) sin( _fAlphaSpeed );
 
        memcpy( fMat, &pst_MTM->st_UVDynamicPos, 4 * sizeof( float ) );
 
        pst_MTM->st_UVDynamicPos.stMat[0][0] = fMat[0][0] * fCos;
        pst_MTM->st_UVDynamicPos.stMat[0][1] = fMat[0][0] * fSin;
        pst_MTM->st_UVDynamicPos.stMat[1][0] = - fMat[1][1] * fSin;
        pst_MTM->st_UVDynamicPos.stMat[1][1] = fMat[1][1] * fCos;
 
        pst_MTM->c_Flags |= C_MTMF_cUVDynamicMatEnable;
    }
 
    if ( (_fOffsetU != 0.0f) || (_fOffsetV != 0.0f ) )
    {
        pst_MTM->st_UVStaticPos.stTrans[0] = _fOffsetU;
        pst_MTM->st_UVStaticPos.stTrans[1] = _fOffsetV;
        pst_MTM->c_Flags |= C_MTMF_cUVStaticTransEnable;
    }

    if ( (_fSpeedU != 0.0f) || (_fSpeedV != 0.0f ) )
    {
        pst_MTM->st_UVDynamicPos.stTrans[0] = _fSpeedU;
        pst_MTM->st_UVDynamicPos.stTrans[1] = _fSpeedV;
        pst_MTM->c_Flags |= C_MTMF_cUVDynamicTransEnable;
    }
}
 
#ifndef RETAIL 
/*
 ----------------------------------------------------------------------------------------
  Description   : Set texture operation between stage _lIndex and stage _lIndex + 1
                The operation is given by string
 ----------------------------------------------------------------------------------------
 */
long GLI_Material_fn_lSetTextureOpWithString( ACP_tdxHandleOfMaterial _hVisualMat, long _lIndex, char *_szOpString )
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    long i;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
    /*
     * find UVFunc
     */
    for (i = 0; i < C_lNumberOfOp; i++ )
    {
        if ( stricmp( _szOpString, gas_szOpDesc[ i ] ) == 0 )
            return GLI_Material_fn_lSetTextureOp( _hVisualMat, _lIndex, i );
    }
   
    return 0;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : Set UV computation for stage _lCanal. the function is given by a string
 ----------------------------------------------------------------------------------------
 */
long GLI_Material_fn_lSetUVFuncWithString
    ( 
        ACP_tdxHandleOfMaterial _hVisualMat, long _lCanal, char *_szFuncString, 
        float _fScaleU, float _fScaleV, 
        float _fAlphaSpeed, float _fAlpha, 
        float _fSpeedU, float _fSpeedV,
        float _fOffsetU, float _fOffsetV 
    )
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    long i;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
 
    /*
     * find UVFunc
     */
    for (i = 0; i < C_lNumberOfUVSource; i++ )
    {
        if ( stricmp( _szFuncString, gas_szUVSourceDesc[i] ) == 0 )
            return GLI_Material_fn_lSetUVFunction( _hVisualMat, _lCanal, i, _fScaleU, _fScaleV, _fAlphaSpeed, _fAlpha, _fSpeedU, _fSpeedV, _fOffsetU, _fOffsetV );
    }
   
    return 0;
}
 
#endif /*RETAIL*/
 
#endif /*MULTI_TEXTURE*/


tdstEngineObject *g_AlphabetCharacterPointer = NULL;

/* ACP_tdxHandleOfMaterial GLI_pGetVisualMaterialForLetter( int c ) */
void *GLI_pGetVisualMaterialForLetter( int c )
{
	
	PO_tdstPhysicalObject *Po;
	tdxHandleToObjectsTablesList d_stObjectsTable;
	GEO_tdstGeometricObject *pObj;
	GEO_tdstElementIndexedTriangles *pIT;

	if( ! g_AlphabetCharacterPointer ) return NULL;

	d_stObjectsTable = g_AlphabetCharacterPointer->h_3dData->h_CurrentObjectsTable;

	if( c > d_stObjectsTable->wNumberOfElement ) return NULL;
	
	Po = (PO_tdstPhysicalObject *) (d_stObjectsTable->d_stObjectsTable[c].h_Target);
	if (Po==NULL) return NULL;
	pObj=Po->_hVisualSet->d_p_stLodDefinitions[0];

	if (pObj==NULL) return NULL;

	if (pObj->xNbElements==1)
	{
		if (pObj->d_xListOfElementsTypes[0]==GEO_C_xElementIndexedTriangles)
		{
			pIT=(GEO_tdstElementIndexedTriangles *)pObj->d_stListOfElements[0];
			return pIT->hMaterial->hVisualMaterial;
		}
	}
	return NULL;
}
 
 
#ifdef __cplusplus
} /*extern "C"*/
#endif

