 
#include "GLD.h"
#include "GEO.h"
#include "TEX.h"
#include "gli_st.h"
#include "textu_st.h"
#include "texture.h"
#include "FIL.h"
 
#define __MSC__
#include <glide.h>
#include "TextuDFX.h"
#include "DLLCom.h"

extern GrHwConfiguration hwconfig;
extern long GLI_gl_MaxTmuAvailable; 
 
short TEXTURETWIDDLED[1024L*1024L];

/*
 ----------------------------------------------------------------------------------------
  Structure for texture memory block (use to load texture into VRam)
 ----------------------------------------------------------------------------------------
 */
typedef struct tdstTextureMemoryBlock_
{
    long    lTmu;
    long    lStart;
    long    lCurrent;
    long    lEnd;
} tdstTextureMemoryBlock;

 
/*
 ----------------------------------------------------------------------------------------
  Description   : get total memory size available for texture
 ----------------------------------------------------------------------------------------
 */
long GLI_fn_lGetTotalTextureMemorySize( void )
{
    long i,lSize;

    lSize = 0;
    for (i = 0 ; i < GLI_gl_MaxTmuAvailable; i++)
        lSize += grTexMaxAddress( i ) - grTexMinAddress( i );
    
    return (lSize);
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : get video memory size taken by a given texture
 ----------------------------------------------------------------------------------------
 */
long GLI_DRV_lGetSizeOfTexture( GLI_tdstTexture *p_stTexture )
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    long lTextureSize;
    long lRef, lSize;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
    lTextureSize = p_stTexture->lHeight * p_stTexture->lWidth;
 
    /*
     * If aspect ratio is too big, texture will waste memory (8:1 is the max aspect ratio for voodoo)
     */
    {
        unsigned long ulRatio;
        if( p_stTexture->lHeight > p_stTexture->lWidth )
            ulRatio = p_stTexture->lHeight / p_stTexture->lWidth;
        else
            ulRatio = p_stTexture->lWidth / p_stTexture->lHeight;
        if( ulRatio > 8 )
            lTextureSize <<= ulRatio >> 4;
    }
 
    /*
     * 8 bits
     */
    if (!(p_stTexture->lTextureCaps & GLI_C_lPaletteTexture))
        lTextureSize <<= 1;
 
    /*
     * mipmap
     */
    if (p_stTexture ->lNumberOfLod)
    {
        lRef = (p_stTexture->lWidth > p_stTexture->lHeight) ? p_stTexture->lHeight : p_stTexture->lWidth;
        lSize   = lTextureSize;

        while ( lRef )
        {
            lSize >>= 2;
            lRef  >>= 1;
            lTextureSize += lSize;
        }
    }
 
    /*
     * alignment
     */
    if ( lTextureSize & 0x7 )
    {
        lTextureSize += 8 - (lTextureSize & 0x7);
    }
 
    GLI_MDRV_TEXBENCH_vSetTextureSize( p_stTexture, TEXBENCH_C_cComputedSize, lTextureSize );
 
    return lTextureSize;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : get correspondante GRLOd constant
 ----------------------------------------------------------------------------------------
 */
static long GLI_lFindGrLOD(long lvalue)
{
    if (lvalue == 256) return GR_LOD_256;
    if (lvalue == 128) return GR_LOD_128;
    if (lvalue == 64) return GR_LOD_64;
    if (lvalue == 32) return GR_LOD_32;
    if (lvalue == 16) return GR_LOD_16;
    if (lvalue == 8) return GR_LOD_8;
    if (lvalue == 4) return GR_LOD_4;
    if (lvalue == 2) return GR_LOD_2;
    if (lvalue == 1) return GR_LOD_1;
    return 0;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : compute texture aspect ration
 ----------------------------------------------------------------------------------------
 */
long GLI_lFindAspectRatioAndMultiplySize(GLI_tdstTexture *p_stTexture)
{
    long lValue1,lValue2;
    GLI_tdstTextureDFX *p_stSpecParam;
    p_stSpecParam=p_stTexture->p_stSpecParam;
    
    lValue1 = p_stTexture -> lWidth;
    lValue2 = p_stTexture -> lHeight;
    
    if ((lValue1>>3) == lValue2) 
    {
        p_stSpecParam -> lMultiplyWidth = 255.0f;
        p_stSpecParam -> lMultiplyHeight = 31.0f;
        return GR_ASPECT_8x1;
    }
    if ((lValue1>>2) == lValue2) 
    {
        p_stSpecParam -> lMultiplyWidth = 255.0f;
        p_stSpecParam -> lMultiplyHeight = 63.0f;
        return GR_ASPECT_4x1;
    }
    if ((lValue1>>1) == lValue2) 
    {
        p_stSpecParam -> lMultiplyWidth = 255.0f;
        p_stSpecParam -> lMultiplyHeight =127.0f;
        return GR_ASPECT_2x1;
    }
    if ((lValue1) == (lValue2)) 
    {
        p_stSpecParam -> lMultiplyWidth = 255.0f;
        p_stSpecParam -> lMultiplyHeight =255.0f;
        return GR_ASPECT_1x1;
    }
    if ((lValue1) == (lValue2>>1)) 
    {
        p_stSpecParam -> lMultiplyWidth = 127.0f;
        p_stSpecParam -> lMultiplyHeight =255.0f;
        return GR_ASPECT_1x2;
    }
    if ((lValue1) == (lValue2>>2)) 
    {
        p_stSpecParam -> lMultiplyWidth =  63.0f;
        p_stSpecParam -> lMultiplyHeight =255.0f;
        return GR_ASPECT_1x4;
    }
    if ((lValue1) == (lValue2>>3)) 
    {
        p_stSpecParam -> lMultiplyWidth =  31.0f;
        p_stSpecParam -> lMultiplyHeight =255.0f;
        return GR_ASPECT_1x8;
    }
    return 0; /* GROS BUG */
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : Compress texture and compute mip map levels
 ----------------------------------------------------------------------------------------
 */
static void GLI_vCompressTex ( GLI_tdstTexture *p_stTexture , GrTexInfo *p_stTexInfo )
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    long                lCurrentDecalTextureForMipMapping,Verify;
    unsigned short      *p_Destination;
    unsigned char       *p_ucDest;
    unsigned long       *p_ulPalette;
    long                lNbLod;
    unsigned short      lWidth, lHeight;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
    if (p_stTexture == NULL ) 
        return;
 
    lCurrentDecalTextureForMipMapping   = 0;
    p_Destination                       = TEXTURETWIDDLED;
    p_stTexture->p_vBitMap              = GLI_gs_p_ConvertBufferMipMapping;
       
    /*
     * load texture
     */
    GLI_MDRV_xLoadTextureInTexelField(p_stTexture, GLI_gs_p_ConvertBufferMipMapping, TRUE);
    
    /*
     * check for alpha texture
     */
    if ((p_stTexture -> lTextureCaps & GLI_C_lAlphaTexture) || (p_stTexture -> lTextureCaps & GLI_C_lNZFilteredTexture))
    {
        Verify = GLI_MDRV_vVerifyTextureIsRealyAlpha(p_stTexture);
        if ((Verify & 0xE0000000) == 0xE0000000)
            p_stTexture -> lTextureCaps &= 0xffffffff - GLI_C_lAlphaTexture;
        if ((Verify & 0x80000000) == 0x80000000)
            p_stTexture -> lTextureCaps &= 0xffffffff - GLI_C_lNZFilteredTexture;
    }
 
 
    p_stTexture->p_vBitMap = GLI_gs_p_ConvertBufferMipMapping;
    lNbLod  = p_stTexture->lNumberOfLod;
    lWidth  = p_stTexture->lWidth;
    lHeight = p_stTexture->lHeight;


    if ( p_stTexture->lTextureCaps & GLI_C_lPaletteTexture )
    {
        p_ucDest    = (char *) p_Destination;
        p_ulPalette = (unsigned long *) p_stTexture->p_vColorTable;
        
        ((GLI_tdstTextureDFX  *) p_stTexture->p_stSpecParam)->stInfoBitmapGlide.format = GR_TEXFMT_P_8;
        memcpy( p_ucDest, GLI_gs_p_ConvertBufferMipMapping, p_stTexture->lHeight * p_stTexture->lWidth );
        lCurrentDecalTextureForMipMapping = p_stTexture->lHeight * p_stTexture->lWidth ;
    
        while( lNbLod-- )
        {
            GLI_MDRV_vDivideBitmapSurfaceBy2Palette( (unsigned long *)GLI_gs_p_ConvertBufferMipMapping , p_ulPalette, p_stTexture->lHeight, p_stTexture->lWidth );
            p_stTexture->lHeight >>= 1;
            p_stTexture->lWidth  >>= 1;
            memcpy( p_ucDest + lCurrentDecalTextureForMipMapping, GLI_gs_p_ConvertBufferMipMapping, p_stTexture->lHeight * p_stTexture->lWidth );
            lCurrentDecalTextureForMipMapping += p_stTexture->lHeight * p_stTexture->lWidth;
        }
    }
    /* TEST sur nouveau traitement sur texture NZ : marche pas bien pour l'instant */
    else if ( p_stTexture->lTextureCaps & GLI_C_lAlphaTest )
    {
        ((GLI_tdstTextureDFX  *) p_stTexture->p_stSpecParam)->stInfoBitmapGlide.format = GR_TEXFMT_ARGB_1555;

        GLI_MDRV_vCompressTex1555( p_stTexture  ,(void *)(p_Destination)) ;
        lCurrentDecalTextureForMipMapping = p_stTexture->lHeight * p_stTexture->lWidth ;

        while( lNbLod-- )
        {
            GLI_MDRV_vDivideBitmapSurfaceBy2NonZero((unsigned long *)GLI_gs_p_ConvertBufferMipMapping , (unsigned long *)GLI_gs_p_ConvertBufferMipMapping , p_stTexture->lHeight, p_stTexture->lWidth, p_stTexture->lChromakeyColorRGBA); /* G.CLEMENT 04/08/1999 : added chromakey */
            p_stTexture->lHeight >>= 1;
            p_stTexture->lWidth  >>= 1;
            GLI_MDRV_vCompressTex1555( p_stTexture  ,(void *)(p_Destination + lCurrentDecalTextureForMipMapping)) ;
            lCurrentDecalTextureForMipMapping += p_stTexture->lHeight * p_stTexture->lWidth;
        }
    }
    else if ((!(p_stTexture -> lTextureCaps & GLI_C_lAlphaTexture)) && (p_stTexture -> lTextureCaps & GLI_C_lNZFilteredTexture))
    {
        ((GLI_tdstTextureDFX  *) p_stTexture->p_stSpecParam)->stInfoBitmapGlide.format = GR_TEXFMT_ARGB_1555;

        GLI_MDRV_vCompressTex1555( p_stTexture  ,(void *)(p_Destination)) ;
        lCurrentDecalTextureForMipMapping = p_stTexture->lHeight * p_stTexture->lWidth ;

        while( lNbLod-- )
        {
            if (p_stTexture -> lTextureCaps & GLI_C_lNZTexture)
                GLI_MDRV_vDivideBitmapSurfaceBy2NonZero((unsigned long *)GLI_gs_p_ConvertBufferMipMapping , (unsigned long *)GLI_gs_p_ConvertBufferMipMapping , p_stTexture -> lHeight, p_stTexture -> lWidth, p_stTexture->lChromakeyColorRGBA); /* G.CLEMENT 04/08/1999 : added chromakey */
            else
                GLI_MDRV_vDivideBitmapSurfaceBy2((unsigned long *)GLI_gs_p_ConvertBufferMipMapping , (unsigned long *)GLI_gs_p_ConvertBufferMipMapping , p_stTexture -> lHeight, p_stTexture -> lWidth);
            p_stTexture->lHeight >>= 1;
            p_stTexture->lWidth  >>= 1;
            GLI_MDRV_vCompressTex1555( p_stTexture  ,(void *)(p_Destination + lCurrentDecalTextureForMipMapping)) ;
            lCurrentDecalTextureForMipMapping += p_stTexture->lHeight * p_stTexture->lWidth;
        }
    }
    else if (p_stTexture -> lTextureCaps & GLI_C_lAlphaTexture)
    {
        ((GLI_tdstTextureDFX  *) p_stTexture->p_stSpecParam)->stInfoBitmapGlide.format = GR_TEXFMT_ARGB_4444;

        GLI_MDRV_vCompressTex4444( p_stTexture , (void *)(p_Destination)) ;
        lCurrentDecalTextureForMipMapping = p_stTexture->lHeight * p_stTexture->lWidth ;

        while( lNbLod-- )
        {
            if (p_stTexture -> lTextureCaps & GLI_C_lNZTexture)
                GLI_MDRV_vDivideBitmapSurfaceBy2NonZero((unsigned long *)GLI_gs_p_ConvertBufferMipMapping , (unsigned long *)GLI_gs_p_ConvertBufferMipMapping , p_stTexture -> lHeight , p_stTexture -> lWidth, p_stTexture->lChromakeyColorRGBA); /* G.CLEMENT 04/08/1999 : added chromakey */
            else
                GLI_MDRV_vDivideBitmapSurfaceBy2((unsigned long *)GLI_gs_p_ConvertBufferMipMapping , (unsigned long *)GLI_gs_p_ConvertBufferMipMapping , p_stTexture -> lHeight , p_stTexture -> lWidth );
            p_stTexture->lHeight >>= 1;
            p_stTexture->lWidth  >>= 1;
            GLI_MDRV_vCompressTex4444( p_stTexture , (void *)(p_Destination + lCurrentDecalTextureForMipMapping)) ;
            lCurrentDecalTextureForMipMapping += p_stTexture->lHeight * p_stTexture->lWidth;
        }
    }
    else
    {
        ((GLI_tdstTextureDFX  *) p_stTexture->p_stSpecParam)->stInfoBitmapGlide.format = GR_TEXFMT_RGB_565;

        GLI_MDRV_vCompressTex565( p_stTexture , (void *)(p_Destination)) ;
        lCurrentDecalTextureForMipMapping = p_stTexture->lHeight * p_stTexture->lWidth ;

        while( lNbLod-- )
        {
            if (p_stTexture -> lTextureCaps & GLI_C_lNZTexture)
                GLI_MDRV_vDivideBitmapSurfaceBy2NonZero((unsigned long *)GLI_gs_p_ConvertBufferMipMapping , (unsigned long *)GLI_gs_p_ConvertBufferMipMapping , p_stTexture -> lHeight, p_stTexture -> lWidth, p_stTexture->lChromakeyColorRGBA); /* G.CLEMENT 04/08/1999 : added chromakey */
            else
                GLI_MDRV_vDivideBitmapSurfaceBy2((unsigned long *)GLI_gs_p_ConvertBufferMipMapping , (unsigned long *)GLI_gs_p_ConvertBufferMipMapping , p_stTexture -> lHeight, p_stTexture -> lWidth);
            p_stTexture->lHeight >>= 1;
            p_stTexture->lWidth  >>= 1;
            GLI_MDRV_vCompressTex565 ( p_stTexture , (void *)(p_Destination + lCurrentDecalTextureForMipMapping)) ;
            lCurrentDecalTextureForMipMapping += p_stTexture->lHeight * p_stTexture->lWidth;
        }
    }

    p_stTexture->lWidth = lWidth;
    p_stTexture->lHeight = lHeight;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : adjust Tex info parameters
 ----------------------------------------------------------------------------------------
 */
static void GLI_vComputeGrTexInfo ( GLI_tdstTexture *p_stTexture , GrTexInfo *p_stTexInfo )
{
    if (p_stTexture -> lHeight >= p_stTexture -> lWidth)
    {
        p_stTexInfo -> smallLod = GLI_lFindGrLOD(p_stTexture -> lHeight >> p_stTexture -> lNumberOfLod);
        p_stTexInfo -> largeLod = GLI_lFindGrLOD(p_stTexture -> lHeight );
    } else
    {
        p_stTexInfo -> smallLod = GLI_lFindGrLOD(p_stTexture -> lWidth >> p_stTexture -> lNumberOfLod);
        p_stTexInfo -> largeLod = GLI_lFindGrLOD(p_stTexture -> lWidth );
    }
    p_stTexInfo -> aspectRatio = GLI_lFindAspectRatioAndMultiplySize(p_stTexture);
    p_stTexInfo -> data = TEXTURETWIDDLED;
}



 
 
/*
 ----------------------------------------------------------------------------------------
  Description   : get total memory size available for texture
 ----------------------------------------------------------------------------------------
 */
void GLI_DRV_vDownLoadTextures(long bRestore, long _lTextureMode, BOOL bReloading )
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    tdstTextureMemoryBlock  st_TexMemBlock[6];
    tdstTextureMemoryBlock  *pst_TexMemBlock;
    long                    lNbTexMemBlocks;
    long                    i;
    long                    lMemoryNeeded;
    long                    lTextureCounter;
    GLI_tdstTexture         *p_stTexture;
    GLI_tdstTextureDFX      *p_stSpecParam;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

    /*
     * init texture block;
     */
    lNbTexMemBlocks = 0;
    for ( i = 0; i < GLI_gl_MaxTmuAvailable; i++)
    {
        st_TexMemBlock[ lNbTexMemBlocks ].lTmu       = i;
        st_TexMemBlock[ lNbTexMemBlocks ].lStart     = grTexMinAddress( i );
        st_TexMemBlock[ lNbTexMemBlocks ].lCurrent   = st_TexMemBlock[ lNbTexMemBlocks ].lStart;
        
        lMemoryNeeded = grTexMaxAddress( i );
        if (lMemoryNeeded > 2097152 )
        {
            st_TexMemBlock[ lNbTexMemBlocks++ ].lEnd     = 2097152;

            st_TexMemBlock[ lNbTexMemBlocks ].lTmu       = i;
            st_TexMemBlock[ lNbTexMemBlocks ].lStart     = 2097152;
            st_TexMemBlock[ lNbTexMemBlocks ].lCurrent   = st_TexMemBlock[ lNbTexMemBlocks ].lStart;
        }
        st_TexMemBlock[ lNbTexMemBlocks++ ].lEnd = lMemoryNeeded;
    }
 
    grTexMipMapMode( GR_TMU0, GR_MIPMAP_NEAREST_DITHER, FXFALSE);
    grTexMipMapMode( GR_TMU1, GR_MIPMAP_NEAREST_DITHER, FXFALSE);

    /*
     * load all textures
     */
    for (lTextureCounter = 0; lTextureCounter < GLI_C_lNBMaxOfTextures ; lTextureCounter ++)
    {
        if (gs_aDEFTableOfTextureMemoryChannels[lTextureCounter] == GLI_TEXIsUnallocated )
            continue;
 
        p_stTexture = gs_aDEFTableOfTextureAlreadyRead[lTextureCounter];
        if (p_stTexture == NULL)
            continue;
 
        p_stTexture->p_stSpecParam = (GLI_tdstTextureDFX *) GLI_MDRV_p_vTmpMalloc( sizeof(GLI_tdstTextureDFX) );
        p_stSpecParam = p_stTexture->p_stSpecParam;
        
        p_stTexture -> bIsAvailable = 0;
        p_stSpecParam -> lMultiplyWidth = 0.0f;
        p_stSpecParam -> lMultiplyHeight = 0.0f;
        p_stSpecParam -> xEvenOdd = GR_MIPMAPLEVELMASK_BOTH ;
        
        GLI_vComputeGrTexInfo( p_stTexture , &p_stSpecParam->stInfoBitmapGlide ) ;
        GLI_vCompressTex( p_stTexture , &p_stSpecParam->stInfoBitmapGlide ) ;

        lMemoryNeeded = grTexTextureMemRequired( p_stSpecParam -> xEvenOdd , &p_stSpecParam -> stInfoBitmapGlide );
	    
        /*
         * search a block that accept current texture
         */
        pst_TexMemBlock = st_TexMemBlock;
        for ( i = 0; i < lNbTexMemBlocks; i++, pst_TexMemBlock++ )
        {
            if (lMemoryNeeded < pst_TexMemBlock->lEnd - pst_TexMemBlock->lCurrent )
                break;
        }
        if ( i == lNbTexMemBlocks)
            continue;
 
		/* bench texture size */
		GLI_MDRV_TEXBENCH_vSetTextureSize( p_stTexture, 1, lMemoryNeeded );

        p_stTexture -> bIsAvailable     = 1;
        p_stSpecParam->xTmuNumber       = pst_TexMemBlock->lTmu;
        p_stSpecParam->xStartAddress    = pst_TexMemBlock->lCurrent;
        pst_TexMemBlock->lCurrent      += lMemoryNeeded;

        grTexDownloadMipMap (p_stSpecParam -> xTmuNumber,p_stSpecParam -> xStartAddress ,p_stSpecParam -> xEvenOdd ,&p_stSpecParam -> stInfoBitmapGlide  );
    }
}

/*
 ----------------------------------------------------------------------------------------
  Description   : get total memory size available for texture
 ----------------------------------------------------------------------------------------
 */
void GLI_DRV_vUnLoadTextures()
{
    long lTextureCounter;
    
    GLI_tdstTexture *p_stTexture;
    
    for ( lTextureCounter = 0 ; lTextureCounter < C_lMaxNumberOfTexture ;lTextureCounter ++)
    {
        if ( gs_aDEFTableOfTextureMemoryChannels[lTextureCounter] != GLI_TEXIsUnallocated )
        {
            p_stTexture = gs_aDEFTableOfTextureAlreadyRead[lTextureCounter];
            if (p_stTexture != NULL)
            {
                if (p_stTexture->bIsAvailable)
                {
					if (p_stTexture-> p_stSpecParam)
						GLI_MDRV_vTmpFree( (void *) p_stTexture-> p_stSpecParam );
                    p_stTexture->bIsAvailable = 0;
                }
            }
        }
    }
}
 
 
#ifdef __cplusplus
} /* extern "C" */
#endif
