/*
 =======================================================================================
  Name        : TexCompress.c
  Author      : Gliglou Corporation
  Description : compression of textures
 =======================================================================================
 */
 
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
#include "PvObj_st.h"
#include "texture.h"
#include "TEX.h"
#include "DLLInter.h"
#include "DLLCaps.h"
#include "TexArray.h"
#include "prf.h"
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
 
/*
 ----------------------------------------------------------------------------------------
  Description   : compress texture width
 ----------------------------------------------------------------------------------------
 */
long GLI_lCompressTexturesSizeInX(struct GLI_tdstTexture_ *p_stTexture)
{
    long lTextureSizeBefore;
    
    lTextureSizeBefore = GLI_DRV_lGetTextureSize(p_stTexture);
    p_stTexture -> lWidth >>= 1;
    return (  lTextureSizeBefore - GLI_DRV_lGetTextureSize(p_stTexture));
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : compress texture height
 ----------------------------------------------------------------------------------------
 */
long GLI_lCompressTexturesSizeInY(struct GLI_tdstTexture_ *p_stTexture)
{
    long lTextureSizeBefore;
    lTextureSizeBefore = GLI_DRV_lGetTextureSize(p_stTexture);
    p_stTexture -> lHeight >>= 1;
    return (  lTextureSizeBefore - GLI_DRV_lGetTextureSize(p_stTexture));
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : compress texture size
 ----------------------------------------------------------------------------------------
 */
long GLI_lCompressTextureSize(GLI_tdstTexture *p_stTexture)
{
    long lTextureSizeBefore;
    
    if ( (p_stTexture -> lHeight <= 4) || (p_stTexture -> lWidth <= 4) )
        return 0;
 
    lTextureSizeBefore = GLI_DRV_lGetTextureSize(p_stTexture);
    
    p_stTexture -> lCompressionCounter ++;
    p_stTexture -> lHeight >>= 1;
    p_stTexture -> lWidth >>= 1;
    
    return (  lTextureSizeBefore - GLI_DRV_lGetTextureSize(p_stTexture));
}
 
 
/*
 ----------------------------------------------------------------------------------------
  Description   : compute texture compression 
 ----------------------------------------------------------------------------------------
 */
long TEX_lComputeCompression()
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    long lSizeOfLevel,lSizeAvailable, lTextureCounter;
    long lCounterAntiInfinite, lNbTexLowQuality;
    unsigned long lMaxTextureSize,lIsAcceptNonSquaredTextures;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    
    lSizeOfLevel                = GLI_lComputeTexturesSize();
    /*
    lSizeAvailable              = GLI_DRV_lGetHardwareTotalTextureMemorySize( GLI_lGetTextureMode() );
    lMaxTextureSize             = GLI_DRV_lGetHardwareMaxTextureSize() ;
    lIsAcceptNonSquaredTextures = GLI_DRV_lIsHardwareAcceptNonSquaredTextures();
    */
    lSizeAvailable              = GLI_g_stCaps.ulTotalTextureMemory;
    lMaxTextureSize             = GLI_g_stCaps.ulTextureMaxSize;;
    lIsAcceptNonSquaredTextures = GLI_g_stCaps.ulTextureCaps & GLICAPS_TEX_C_ulSupportNonSquare;
 
    PRF_fn_vSetIndependantVariable( PRF_C_ulIdpTextureSize, lSizeOfLevel );
    PRF_fn_vSetIndependantVariable( PRF_C_ulIdpTextureMemorySize, lSizeAvailable );
    /*
    * if hardware doesn't accept non-squared textures squared them
    * and compress texture if hardware size is smaller than texture
    */
    if (lIsAcceptNonSquaredTextures == 0)
    {
        for  (lTextureCounter = 0 ; lTextureCounter < GLI_C_lNBMaxOfTextures; lTextureCounter ++)
        {
            if (gs_aDEFTableOfTextureMemoryChannels[lTextureCounter] == GLI_TEXIsUnallocated)
                continue;
            
            /* Make them squared */
            while (gs_aDEFTableOfTextureAlreadyRead[lTextureCounter]->lWidth  > gs_aDEFTableOfTextureAlreadyRead[lTextureCounter]->lHeight)
                lSizeOfLevel -= GLI_lCompressTexturesSizeInX(gs_aDEFTableOfTextureAlreadyRead [lTextureCounter]);
 
            while (gs_aDEFTableOfTextureAlreadyRead[lTextureCounter]->lWidth  < gs_aDEFTableOfTextureAlreadyRead[lTextureCounter]->lHeight)
                lSizeOfLevel -= GLI_lCompressTexturesSizeInY(gs_aDEFTableOfTextureAlreadyRead [lTextureCounter]);
            
            /* then compress too large textures */
            while ( gs_aDEFTableOfTextureAlreadyRead[lTextureCounter]->lWidth  > lMaxTextureSize )
            {
                lSizeOfLevel -= GLI_lCompressTexturesSizeInX(gs_aDEFTableOfTextureAlreadyRead [lTextureCounter]);
                lSizeOfLevel -= GLI_lCompressTexturesSizeInY(gs_aDEFTableOfTextureAlreadyRead [lTextureCounter]);
            }
        }
    }
    else
    {
        /* Compress Height */
        for  (lTextureCounter = 0 ; lTextureCounter < GLI_C_lNBMaxOfTextures; lTextureCounter ++)
        {
            if (gs_aDEFTableOfTextureMemoryChannels[lTextureCounter] == GLI_TEXIsUnallocated)
                continue;
                
            while (gs_aDEFTableOfTextureAlreadyRead[lTextureCounter]->lWidth  > lMaxTextureSize)
                lSizeOfLevel -= GLI_lCompressTexturesSizeInX(gs_aDEFTableOfTextureAlreadyRead [lTextureCounter]);
                
        }
        /* Compress Width */
        for  (lTextureCounter = 0 ; lTextureCounter < GLI_C_lNBMaxOfTextures; lTextureCounter ++)
        {
            if (gs_aDEFTableOfTextureMemoryChannels[lTextureCounter] == GLI_TEXIsUnallocated)
                continue;
 
            while (gs_aDEFTableOfTextureAlreadyRead[lTextureCounter]->lHeight > lMaxTextureSize)
                lSizeOfLevel -= GLI_lCompressTexturesSizeInY(gs_aDEFTableOfTextureAlreadyRead [lTextureCounter]);
        }
    }
    
    if (lSizeAvailable == -1) /* Case of the reality engine */
        return 0;
    
    lCounterAntiInfinite = 10;
    lNbTexLowQuality = 1;
    while ((lSizeOfLevel > lSizeAvailable) && (lCounterAntiInfinite-- > 0))
    {
        if( lNbTexLowQuality )
        {
            lNbTexLowQuality--;
            /* First compress the low textures */
            for  (lTextureCounter =GLI_C_lNBMaxOfTextures - 1 ; (lTextureCounter >= 0) && (lSizeOfLevel > lSizeAvailable); lTextureCounter --)
            {
                if (gs_aDEFTableOfTextureMemoryChannels[lTextureCounter] == GLI_TEXIsUnallocated)
                    continue;
 
                if (TEX_ucGetTextureQualityLevel(gs_aDEFTableOfTextureAlreadyRead[lTextureCounter]) != TEX_C_QNORMAL)
                {
                    if (TEX_ucGetTextureQualityLevel(gs_aDEFTableOfTextureAlreadyRead[lTextureCounter]) != TEX_C_QHIGH) /* = LOW quality*/
                    /*if (GLI_M_bNotAnLODLevel(gs_aDEFTableOfTextureMemoryChannels[lTextureCounter]))*/
                    {
                        lNbTexLowQuality++;
                        lSizeOfLevel -= GLI_lCompressTextureSize(gs_aDEFTableOfTextureAlreadyRead [ lTextureCounter ]);
                        if (lSizeOfLevel < lSizeAvailable) 
                            continue;
                        lSizeOfLevel -= GLI_lCompressTextureSize(gs_aDEFTableOfTextureAlreadyRead [ lTextureCounter ]);
                    }
                }
            }
        }
        
        /* then compress Normal textures;*/
        for  (lTextureCounter =0 ;  (lTextureCounter < GLI_C_lNBMaxOfTextures) && (lSizeOfLevel > lSizeAvailable); lTextureCounter ++)
        {
            if (gs_aDEFTableOfTextureMemoryChannels[lTextureCounter] == GLI_TEXIsUnallocated)
                continue;
        
            if (TEX_ucGetTextureQualityLevel(gs_aDEFTableOfTextureAlreadyRead[lTextureCounter]) == TEX_C_QNORMAL)
                lSizeOfLevel -= GLI_lCompressTextureSize(gs_aDEFTableOfTextureAlreadyRead [ lTextureCounter ]);
        }
    
    }
    return 0;
}
