/******************************Module*Header**********************************\
*
*                           *******************
*                           * D3D SAMPLE CODE *
*                           *******************
*
* Module Name: d3dhw.c
*
*  Content: Hardware dependent texture setup for D3D 
*
* Copyright (c) 1994-1998 3Dlabs Inc. Ltd. All rights reserved.
* Copyright (c) 1995-1999 Microsoft Corporation.  All rights reserved.
\*****************************************************************************/

#include "precomp.h"
#include "d3dhw.h"
#include "d3dcntxt.h"
#include "d3ddelta.h"
#include "dd.h"
#include "heap.h"
#include "d3dtxman.h"


//-----------------------------------------------------------------------------
//
// PERMEDIA_D3DTEXTURE *TextureHandleToPtr
//
// Find the texture associated to a given texture handle vale (which is to
// say , to a surface handle )
//
//-----------------------------------------------------------------------------

PERMEDIA_D3DTEXTURE *
TextureHandleToPtr(UINT_PTR thandle, PERMEDIA_D3DCONTEXT* pContext)
{

    //  only a DX7 context can get here
    ASSERTDD(NULL != pContext->pHandleList,
                       "pHandleList==NULL in TextureHandleToPtr");

    if (pContext->pHandleList->dwSurfaceList == NULL)
    {
        // avoid AV if our surface list is missing
        return NULL;
    }

    if ((PtrToUlong(pContext->pHandleList->dwSurfaceList[0]) > thandle) && 
        (0 != thandle))
    {
        return pContext->pHandleList->dwSurfaceList[(DWORD)thandle];
    }

    // Request for pointer for an invalid handle returns NULL
    return NULL;               
} // TextureHandleToPtr

//-----------------------------------------------------------------------------
//
// PERMEDIA_D3DTEXTURE *PaletteHandleToPtr
//
//-----------------------------------------------------------------------------

PERMEDIA_D3DPALETTE *
PaletteHandleToPtr(UINT_PTR phandle, PERMEDIA_D3DCONTEXT* pContext)
{
    ASSERTDD(NULL != pContext->pHandleList,
               "pHandleList==NULL in PaletteHandleToPtr");

    if ( (NULL != pContext->pHandleList->dwPaletteList) &&
         (PtrToUlong(pContext->pHandleList->dwPaletteList[0]) > phandle) &&
         (0 != phandle)
       )
    {
        return pContext->pHandleList->dwPaletteList[(DWORD)phandle];
    }
    return NULL;               
} // PaletteHandleToPtr


//-----------------------------------------------------------------------------
//
//void StorePermediaLODLevel
//
// Store private data specific to a level of detail
//
//-----------------------------------------------------------------------------
void 
StorePermediaLODLevel(PPDev ppdev, 
                      PERMEDIA_D3DTEXTURE* pTexture, 
                      LPDDRAWI_DDRAWSURFACE_LCL pSurf, 
                      int LOD)
{
    DWORD dwPartialWidth;
    int iPixelSize;

    DBG_D3D((10,"Entering StorePermediaLODLevel"));

    // if it's any surface type that's not created by driver
    // certainly there's no need to texture it
    if (NULL == pTexture->pTextureSurface)
        return; 

    // Get the BYTE Offset to the texture map
    if (DDSCAPS_NONLOCALVIDMEM & pTexture->dwCaps)
    {
        pTexture->MipLevels[LOD].PixelOffset = 
                (DWORD)(DD_AGPSURFACEPHYSICAL(pSurf->lpGbl) - ppdev->dwGARTDev);
    }
    else 
    {
        pTexture->MipLevels[LOD].PixelOffset = (DWORD)pSurf->lpGbl->fpVidMem;  
    }
    // .. Convert it to Pixels
    switch(pTexture->pTextureSurface->SurfaceFormat.PixelSize) 
    {
        case __PERMEDIA_4BITPIXEL:
            pTexture->MipLevels[LOD].PixelOffset <<= 1;
            break;
        case __PERMEDIA_8BITPIXEL: /* No Change*/
            break;
        case __PERMEDIA_16BITPIXEL:
            pTexture->MipLevels[LOD].PixelOffset >>= 1;
            break;
        case __PERMEDIA_24BITPIXEL:
            pTexture->MipLevels[LOD].PixelOffset /= 3;
            break;
        case __PERMEDIA_32BITPIXEL:
            pTexture->MipLevels[LOD].PixelOffset >>= 2;
            break;
        default:
            ASSERTDD(0,"Invalid Texture Pixel Size!");
            pTexture->MipLevels[LOD].PixelOffset >>= 1;
            break;
    }
    // P2 recognises that the texture is AGP if you set bit 30 to be 1.
    if (DDSCAPS_NONLOCALVIDMEM & pTexture->dwCaps)
    {
        pTexture->MipLevels[LOD].PixelOffset |= (1 << 30);
    }
    DBG_D3D((4,"Storing LOD: %d, Pitch: %d, Width: %d PixelOffset=%08lx", 
                LOD, pSurf->lpGbl->lPitch, 
                pSurf->lpGbl->wWidth,pTexture->MipLevels[LOD].PixelOffset));
    

    // Get the Partial Products for this LOD
    iPixelSize = pTexture->pTextureSurface->SurfaceFormat.PixelSize;

    if (iPixelSize == __PERMEDIA_4BITPIXEL)
    {
        dwPartialWidth = (pSurf->lpGbl->lPitch << 1);
    } 
    else 
    {
        if (iPixelSize != __PERMEDIA_24BITPIXEL)
        {
            dwPartialWidth = (pSurf->lpGbl->lPitch >> iPixelSize);
        } 
        else 
        {
            dwPartialWidth = pSurf->lpGbl->lPitch / 3;
        }
    }

    if (dwPartialWidth < 32) 
        dwPartialWidth = 32;

    vCalcPackedPP( dwPartialWidth, NULL, &pTexture->MipLevels[LOD].ulPackedPP);

    pTexture->MipLevels[LOD].logWidth = log2((int)pSurf->lpGbl->wWidth);
    pTexture->MipLevels[LOD].logHeight = log2((int)pSurf->lpGbl->wHeight);

    DBG_D3D((10,"Exiting StorePermediaLODLevel"));

} // StorePermediaLODLevel


//-----------------------------------------------------------------------------
//
// void DisableTexturePermedia
//
// Disable texturing in P2
//
//-----------------------------------------------------------------------------
void 
DisableTexturePermedia(PERMEDIA_D3DCONTEXT* pContext)
{
    DWORD* pFlags = &pContext->Hdr.Flags;
    PERMEDIA_D3DTEXTURE* pTexture = NULL;
    __P2RegsSoftwareCopy* pSoftPermedia = &pContext->Hdr.SoftCopyP2Regs;
    PERMEDIA_DEFS(pContext->ppdev);

    DBG_D3D((10,"Entering DisableTexturePermedia"));

    pContext->FakeBlendNum &= ~FAKE_ALPHABLEND_MODULATE;
    
    // The textures have been turned off, so...
    ASSERTDD(pContext->CurrentTextureHandle == 0,
        "DisableTexturePermedia expected zero texture handle");

    DBG_D3D((4, "Disabling Texturing"));
    
    RESERVEDMAPTR(8);
    // Turn off texture address generation
    pSoftPermedia->TextureAddressMode.Enable = 0;
    COPY_PERMEDIA_DATA(TextureAddressMode, pSoftPermedia->TextureAddressMode);

    // Turn off texture reads
    pSoftPermedia->TextureReadMode.Enable = 0;
    COPY_PERMEDIA_DATA(TextureReadMode, pSoftPermedia->TextureReadMode);
    
    // Turn off textures
    pSoftPermedia->TextureColorMode.TextureEnable = 0;
    COPY_PERMEDIA_DATA(TextureColorMode, pSoftPermedia->TextureColorMode);

    // Set the texture base address to 0
    // (turning off the 'AGP' bit in the process)
    // Also stop TexelLUTTransfer messages
    SEND_PERMEDIA_DATA(TextureBaseAddress, 0);
    SEND_PERMEDIA_DATA(TexelLUTTransfer, __PERMEDIA_DISABLE);


    // Set current texture to 0
    pContext->CurrentTextureHandle = 0;
    *pFlags &= ~CTXT_HAS_TEXTURE_ENABLED;
    RENDER_TEXTURE_DISABLE(pContext->RenderCommand);
    
    // If textures were in copy mode, we may have fiddled with the DDA,
    // to improve performance.
    if ((unsigned int)pSoftPermedia->TextureColorMode.ApplicationMode ==
        _P2_TEXTURE_COPY) 
    {
        if (*pFlags & CTXT_HAS_GOURAUD_ENABLED) 
        {
            pSoftPermedia->DeltaMode.SmoothShadingEnable = 1;

            COPY_PERMEDIA_DATA(DeltaMode, pSoftPermedia->DeltaMode);
            pSoftPermedia->ColorDDAMode.UnitEnable = 1;
             // Smooth shade, DDA Enable
            COPY_PERMEDIA_DATA(ColorDDAMode, pSoftPermedia->ColorDDAMode);

        }
        else 
        {
            pSoftPermedia->DeltaMode.SmoothShadingEnable = 0;

            COPY_PERMEDIA_DATA(DeltaMode, pSoftPermedia->DeltaMode);
            pSoftPermedia->ColorDDAMode.UnitEnable = 1;
             // Flat shade, DDA Enable
            COPY_PERMEDIA_DATA(ColorDDAMode, pSoftPermedia->ColorDDAMode);

        }
    }

    if (pContext->bCanChromaKey == TRUE) 
    {
        // Turn off Chroma Keying
        
        pSoftPermedia->YUVMode.TestMode = PM_YUVMODE_CHROMATEST_DISABLE;
        pSoftPermedia->YUVMode.Enable = __PERMEDIA_DISABLE;

        COPY_PERMEDIA_DATA(YUVMode, pSoftPermedia->YUVMode);

        pContext->bCanChromaKey = FALSE;
    }

    COMMITDMAPTR();

    DBG_D3D((10,"Exiting DisableTexturePermedia"));

    return;

} // DisableTexturePermedia

//-----------------------------------------------------------------------------
//
// void Convert_Chroma_2_8888ARGB
//
// Conversion of a chroma value into 32bpp ARGB
//
//-----------------------------------------------------------------------------
void
Convert_Chroma_2_8888ARGB(DWORD *pdwLowerBound, DWORD *pdwUpperBound,
                          DWORD dwRedMask, DWORD dwAlphaMask, DWORD dwPixelSize)
{
    DBG_D3D((10,"Entering Convert_Chroma_2_8888ARGB"));

    switch (dwPixelSize) {
    case __PERMEDIA_8BITPIXEL:
        if (dwRedMask == 0xE0)
        {
            // Never any alpha
            *pdwLowerBound = 
                CHROMA_LOWER_ALPHA(FORMAT_332_32BIT_BGR(*pdwLowerBound));
            *pdwUpperBound = 
                CHROMA_UPPER_ALPHA(FORMAT_332_32BIT_BGR(*pdwUpperBound));
        }
        else
        {
            *pdwLowerBound = FORMAT_2321_32BIT_BGR(*pdwLowerBound);
            *pdwUpperBound = FORMAT_2321_32BIT_BGR(*pdwUpperBound);
            if (!dwAlphaMask)
            {
                *pdwLowerBound = CHROMA_LOWER_ALPHA(*pdwLowerBound);
                *pdwUpperBound = CHROMA_UPPER_ALPHA(*pdwUpperBound);
            }
        }

        break;

    case __PERMEDIA_16BITPIXEL:
        switch (dwRedMask)
        {
        case 0xf00:
            *pdwLowerBound = (FORMAT_4444_32BIT_BGR(*pdwLowerBound));
            *pdwUpperBound = (FORMAT_4444_32BIT_BGR(*pdwUpperBound));
            if (!dwAlphaMask) 
            {
                *pdwLowerBound = CHROMA_LOWER_ALPHA(*pdwLowerBound);
                *pdwUpperBound = CHROMA_UPPER_ALPHA(*pdwUpperBound);
            }
            // Acount for the internal 8888 -> 4444 translation
            // which causes bilinear chroma keying to fail in
            // some cases
            *pdwLowerBound = *pdwLowerBound & 0xF0F0F0F0;
            *pdwUpperBound = *pdwUpperBound | 0x0F0F0F0F;

            break;
        case 0x7c00:
            *pdwLowerBound = FORMAT_5551_32BIT_BGR(*pdwLowerBound);
            *pdwUpperBound = FORMAT_5551_32BIT_BGR(*pdwUpperBound);
            if (!dwAlphaMask) 
            {
                *pdwLowerBound = CHROMA_LOWER_ALPHA(*pdwLowerBound);
                *pdwUpperBound = CHROMA_UPPER_ALPHA(*pdwUpperBound);
            }
            // Acount for the internal 8888 -> 5551 translation
            // which causes bilinear chroma keying to fail in
            // some cases
            *pdwLowerBound = *pdwLowerBound & 0x80F8F8F8;
            *pdwUpperBound = *pdwUpperBound | 0x7F070707;
            break;
        default:
            // Always supply full range of alpha values to ensure test 
            // is done
            *pdwLowerBound = 
                CHROMA_LOWER_ALPHA(FORMAT_565_32BIT_BGR(*pdwLowerBound));
            *pdwUpperBound = 
                CHROMA_UPPER_ALPHA(FORMAT_565_32BIT_BGR(*pdwUpperBound));
            if (!dwAlphaMask)
            {
                *pdwLowerBound = CHROMA_LOWER_ALPHA(*pdwLowerBound);
                *pdwUpperBound = CHROMA_UPPER_ALPHA(*pdwUpperBound);
            }
            // Acount for the internal 888 -> 565 translation
            // which causes bilinear chroma keying to fail in
            // some cases
            *pdwLowerBound = *pdwLowerBound & 0xF8F8FCF8;
            *pdwUpperBound = *pdwUpperBound | 0x07070307;
            break;
        }
        break;
    case __PERMEDIA_24BITPIXEL:
    case __PERMEDIA_32BITPIXEL:
        *pdwLowerBound = FORMAT_8888_32BIT_BGR(*pdwLowerBound);
        *pdwUpperBound = FORMAT_8888_32BIT_BGR(*pdwUpperBound);
        // If the surface isn't alpha'd then set a valid
        // range of alpha to catch all cases.
        if (!dwAlphaMask)
        {
            *pdwLowerBound = CHROMA_LOWER_ALPHA(*pdwLowerBound);
            *pdwUpperBound = CHROMA_UPPER_ALPHA(*pdwUpperBound);
        }
        break;
    }

    DBG_D3D((10,"Exiting Convert_Chroma_2_8888ARGB"));

} // Convert_Chroma_2_8888ARGB


//-----------------------------------------------------------------------------
//
// void EnableTexturePermedia
//
// Enable and setup texturing for pContext->CurrentTextureHandle
//
//-----------------------------------------------------------------------------
void 
EnableTexturePermedia(PERMEDIA_D3DCONTEXT* pContext)
{
    DWORD* pFlags = &pContext->Hdr.Flags;
    PERMEDIA_D3DTEXTURE* pTexture = NULL;
    __P2RegsSoftwareCopy* pSoftPermedia = &pContext->Hdr.SoftCopyP2Regs;
    PERMEDIA_DEFS(pContext->ppdev);
    PERMEDIA_D3DPALETTE* pPalette=NULL;
    LPPALETTEENTRY lpColorTable=NULL;   // array of palette entries
    PPDev   ppdev = pContext->ppdev;

    DBG_D3D((10,"Entering EnableTexturePermedia %d",
        pContext->CurrentTextureHandle));

    pContext->FakeBlendNum &= ~FAKE_ALPHABLEND_MODULATE;

    // A texture has been turned on so ...
    ASSERTDD(pContext->CurrentTextureHandle != 0,
        "EnableTexturePermedia expected non zero texture handle");

    // We must be texturing so...
    pTexture = TextureHandleToPtr(pContext->CurrentTextureHandle, pContext);
    
    if (CHECK_D3DSURFACE_VALIDITY(pTexture)) 
    {
        PermediaSurfaceData* pPrivateData;
        DWORD cop = pContext->TssStates[D3DTSS_COLOROP];
        DWORD ca1 = pContext->TssStates[D3DTSS_COLORARG1];
        DWORD ca2 = pContext->TssStates[D3DTSS_COLORARG2];
        DWORD aop = pContext->TssStates[D3DTSS_ALPHAOP];
        DWORD aa1 = pContext->TssStates[D3DTSS_ALPHAARG1];

        // Current is the same as diffuse in stage 0
        if (ca2 == D3DTA_CURRENT)
            ca2 = D3DTA_DIFFUSE;

        pPrivateData = pTexture->pTextureSurface;

        if (!CHECK_P2_SURFACEDATA_VALIDITY(pPrivateData))
        {
            DBG_D3D((0,"EnableTexturePermedia get invalid pPrivateData=0x%x"
                " from SurfaceHandle=%d", pPrivateData,
                pContext->CurrentTextureHandle));
            pContext->CurrentTextureHandle = 0;

            // If the texture is bad, let's ensure it's marked as such. 
            pTexture->MagicNo = TC_MAGIC_DISABLE;

            goto Exit_EnableTexturePermedia;
        }

        if (pTexture->dwCaps2 & DDSCAPS2_TEXTUREMANAGE)
        {
            if (NULL==pPrivateData->fpVidMem)
            {
                TextureCacheManagerAllocNode(pContext,pTexture);
                if (NULL==pPrivateData->fpVidMem)
                {
                    DBG_D3D((0,"EnableTexturePermedia unable to allocate memory from heap"));
                    pContext->CurrentTextureHandle = 0;
                    goto Exit_EnableTexturePermedia;
                }
                pPrivateData->dwFlags |= P2_SURFACE_NEEDUPDATE;
            }
            TextureCacheManagerTimeStamp(pContext->pTextureManager,pTexture);
            if (pPrivateData->dwFlags & P2_SURFACE_NEEDUPDATE)
            {
                RECTL   rect;
                rect.left=rect.top=0;
                rect.right=pTexture->wWidth;
                rect.bottom=pTexture->wHeight;
                // texture download
                // Switch to DirectDraw context
                pPrivateData->dwFlags &= ~P2_SURFACE_NEEDUPDATE;
                // .. Convert it to Pixels

                pTexture->MipLevels[0].PixelOffset = 
                    (DWORD)(pPrivateData->fpVidMem);

                switch(pTexture->pTextureSurface->SurfaceFormat.PixelSize) 
                {
                    case __PERMEDIA_4BITPIXEL:
                        pTexture->MipLevels[0].PixelOffset <<= 1;
                        break;
                    case __PERMEDIA_8BITPIXEL: /* No Change*/
                        break;
                    case __PERMEDIA_16BITPIXEL:
                        pTexture->MipLevels[0].PixelOffset >>= 1;
                        break;
                    case __PERMEDIA_24BITPIXEL:
                        pTexture->MipLevels[0].PixelOffset /= 3;
                        break;
                    case __PERMEDIA_32BITPIXEL:
                        pTexture->MipLevels[0].PixelOffset >>= 2;
                        break;
                    default:
                        ASSERTDD(0,"Invalid Texture Pixel Size!");
                        pTexture->MipLevels[0].PixelOffset >>= 1;
                        break;
                }
                PermediaPatchedTextureDownload(pContext->ppdev, 
                                           pPrivateData,
                                           pTexture->fpVidMem,
                                           pTexture->lPitch,
                                           &rect,
                                           pPrivateData->fpVidMem,
                                           pTexture->lPitch,
                                           &rect);

                //need to restore following registers
                RESERVEDMAPTR(7);
                SEND_PERMEDIA_DATA(FBReadPixel, pSoftPermedia->FBReadPixel);
                COPY_PERMEDIA_DATA(FBReadMode, pSoftPermedia->FBReadMode);
                SEND_PERMEDIA_DATA(FBPixelOffset, pContext->PixelOffset);
                SEND_PERMEDIA_DATA(FBWindowBase,0);   
                COPY_PERMEDIA_DATA(Window, pSoftPermedia->Window);
                COPY_PERMEDIA_DATA(AlphaBlendMode, pSoftPermedia->AlphaBlendMode);
                COPY_PERMEDIA_DATA(DitherMode, pSoftPermedia->DitherMode);
                COMMITDMAPTR();

                DBG_D3D((10, "Copy from %08lx to %08lx w=%08lx h=%08lx p=%08lx b=%08lx",
                    pTexture->fpVidMem,pPrivateData->fpVidMem,pTexture->wWidth,
                    pTexture->wHeight,pTexture->lPitch,pTexture->dwRGBBitCount));
            }
        }        
        // If it is a palette indexed texture, we simply follow the chain
        // down from the surface to it's palette and pull out the LUT values
        // from the PALETTEENTRY's in the palette.
        if (pPrivateData->SurfaceFormat.Format == PERMEDIA_8BIT_PALETTEINDEX ||
            pPrivateData->SurfaceFormat.Format == PERMEDIA_4BIT_PALETTEINDEX) 
        {
            pPalette = 
                    PaletteHandleToPtr(pTexture->dwPaletteHandle,pContext);
            if (NULL != pPalette)
            {
                //some apps are not setting their alpha correctly with palette
                //then it's up to palette to tell us
                pPrivateData->SurfaceFormat.bAlpha =
                    pPalette->dwFlags & DDRAWIPAL_ALPHA;
            }
        }

        if ((ca2 == D3DTA_DIFFUSE && ca1 == D3DTA_TEXTURE) &&
             cop == D3DTOP_MODULATE &&
             (aa1 == D3DTA_TEXTURE && aop == D3DTOP_LEGACY_ALPHAOVR)) 
        {
            // if this is legacy modulation then we take the texture alpha
            // only if the texure format has it
            if (pPrivateData->SurfaceFormat.bAlpha)
                pContext->FakeBlendNum |= FAKE_ALPHABLEND_MODULATE;
        }
        else if ((ca2 == D3DTA_DIFFUSE && ca1 == D3DTA_TEXTURE) &&
             cop == D3DTOP_MODULATE &&
             (aa1 == D3DTA_TEXTURE && aop == D3DTOP_SELECTARG1)) 
        {
            // if this is DX6 modulation then we take the texture alpha
            // no matter what ( it will be xFF if it doesn't exist)
            pContext->FakeBlendNum |= FAKE_ALPHABLEND_MODULATE;
        }

        // Enable Texture Address calculation
        pSoftPermedia->TextureAddressMode.Enable = 1;
            
        // Enable Textures
        pSoftPermedia->TextureColorMode.TextureEnable = 1;
        if (*pFlags & CTXT_HAS_SPECULAR_ENABLED)
        {
            pSoftPermedia->DeltaMode.SpecularTextureEnable = 1;
            pSoftPermedia->TextureColorMode.KsDDA = 1; 
            pSoftPermedia->TextureColorMode.ApplicationMode |= 
                                                         _P2_TEXTURE_SPECULAR;
        } 
        else 
        {
            pSoftPermedia->DeltaMode.SpecularTextureEnable = 0;
            pSoftPermedia->TextureColorMode.KsDDA = 0; 
            pSoftPermedia->TextureColorMode.ApplicationMode &= 
                                                        ~_P2_TEXTURE_SPECULAR;
        }

        // reserve here for all cases in this function!!
        RESERVEDMAPTR(272);
        
        COPY_PERMEDIA_DATA(DeltaMode, pSoftPermedia->DeltaMode);

        // Set Partial products for texture (assume no mipmapping).
        pSoftPermedia->TextureMapFormat.PackedPP = 
            pTexture->MipLevels[0].ulPackedPP;

        pSoftPermedia->TextureMapFormat.TexelSize = 
                                        pPrivateData->SurfaceFormat.PixelSize;

        if (pPrivateData->dwFlags & P2_ISPATCHED)
        {
            DBG_D3D((4,"   Enabling Patching for this texture"));
            pSoftPermedia->TextureMapFormat.SubPatchMode = 1;
        } 
        else 
        {
            pSoftPermedia->TextureMapFormat.SubPatchMode = 0;
        }

        DBG_D3D((4, "    Texel Size: 0x%x", 
                 pPrivateData->SurfaceFormat.PixelSize));

        // Set texture size
        DBG_D3D((4,"     Texture Width: 0x%x", 
                 pTexture->MipLevels[0].logWidth));
        DBG_D3D((4,"     Texture Height: 0x%x", 
                 pTexture->MipLevels[0].logHeight));

        pSoftPermedia->TextureReadMode.Width = 
                                       pTexture->MipLevels[0].logWidth;
        pSoftPermedia->TextureReadMode.Height = 
                                       pTexture->MipLevels[0].logHeight;

        pSoftPermedia->TextureReadMode.Enable = 1;
        pContext->DeltaWidthScale = (float)pTexture->wWidth * (1 / 2048.0f);
        pContext->DeltaHeightScale = (float)pTexture->wHeight * (1 / 2048.0f);

        pContext->MaxTextureXf = (float)(2048 / pTexture->wWidth);
        pContext->MaxTextureYf = (float)(2048 / pTexture->wHeight);

        myFtoui(&pContext->MaxTextureXi, pContext->MaxTextureXf);
        pContext->MaxTextureXi -= 1;
        myFtoui(&pContext->MaxTextureYi, pContext->MaxTextureYf);
        pContext->MaxTextureYi -= 1;

        *pFlags |= CTXT_HAS_TEXTURE_ENABLED;
        RENDER_TEXTURE_ENABLE(pContext->RenderCommand);
        
        DBG_D3D((4,"     Texture Format: 0x%x", 
                 pPrivateData->SurfaceFormat.Format));
        DBG_D3D((4,"     Texture Format Extension: 0x%x", 
                 pPrivateData->SurfaceFormat.FormatExtension));

        pSoftPermedia->TextureDataFormat.TextureFormat = 
                                            pPrivateData->SurfaceFormat.Format;
        pSoftPermedia->TextureDataFormat.TextureFormatExtension = 
                                   pPrivateData->SurfaceFormat.FormatExtension;

        if (pPrivateData->SurfaceFormat.bAlpha) 
        {
            pSoftPermedia->TextureDataFormat.NoAlphaBuffer = 0;
        } 
        else 
        {
            pSoftPermedia->TextureDataFormat.NoAlphaBuffer = 1;
        }

        // If we are copying textures, there is no need for colour data
        // to be generated, so we turn off the DDA
        if (((unsigned int)pSoftPermedia->TextureColorMode.ApplicationMode) == 
                                                              _P2_TEXTURE_COPY)
        {
            pSoftPermedia->ColorDDAMode.UnitEnable = 0;
            DBG_D3D((4, "    Disabling DDA"));
        }
        else
        {
            pSoftPermedia->ColorDDAMode.UnitEnable = 1;
            DBG_D3D((4, "    Enabling DDA"));
        }
        
        // Load the texture base address BEFORE the TexelLUTTransfer message 
        // to ensure we load the LUT from the right sort of memory (AGP or not)
        // Always set the base address at the root texture (not the miplevels 
        // if there are any)
        DBG_D3D((4, "Setting texture base address to 0x%08X", 
                 pTexture->MipLevels[0].PixelOffset));
        SEND_PERMEDIA_DATA(TextureBaseAddress, 
                           pTexture->MipLevels[0].PixelOffset);

        // If it is a palette indexed texture, we simply follow the chain
        // down from the surface to it's palette and pull out the LUT values
        // from the PALETTEENTRY's in the palette.
        if (pPrivateData->SurfaceFormat.Format == PERMEDIA_8BIT_PALETTEINDEX) 
        {

            if (NULL != pPalette)
            {
                int i;
                lpColorTable = pPalette->ColorTable;
                

                if (pPalette->dwFlags & DDRAWIPAL_ALPHA)
                {
                    for (i = 0; i < 256; i++)
                    {
                        SEND_PERMEDIA_DATA(TexelLUTData, *(DWORD*)lpColorTable);
                        lpColorTable++;
                    }
                }
                else
                {
                    for (i = 0; i < 256; i++)
                    {
                        SEND_PERMEDIA_DATA(TexelLUTData,
                            CHROMA_UPPER_ALPHA(*(DWORD*)lpColorTable));
                        lpColorTable++;
                    }
                }

                SEND_PERMEDIA_DATA(TexelLUTMode, __PERMEDIA_ENABLE);

                DBG_D3D((4,"Texel LUT pPalette->dwFlags=%08lx bAlpha=%d", 
                    pPalette->dwFlags,pPrivateData->SurfaceFormat.bAlpha));

                // Must reset the LUT index on Permedia P2
                SEND_PERMEDIA_DATA(TexelLUTIndex, 0);
                
            }
            else
            {
                DBG_D3D((0, "NULL == pPalette in EnableTexturePermedia"
                    "dwPaletteHandle=%08lx dwSurfaceHandle=%08lx",
                    pTexture->dwPaletteHandle,
                    pContext->CurrentTextureHandle)); 
            }
        } 
        else if (pPrivateData->SurfaceFormat.Format == 
                                                    PERMEDIA_4BIT_PALETTEINDEX)
        {
            if (NULL != pPalette)
            {
                int i;
                lpColorTable = pPalette->ColorTable;
                
                SEND_PERMEDIA_DATA(TexelLUTMode, __PERMEDIA_ENABLE);

                if (pPalette->dwFlags & DDRAWIPAL_ALPHA)
                {
                    for (i = 0; i < 16; i++)
                    {
                        SEND_PERMEDIA_DATA_OFFSET(TexelLUT0,
                                                *(DWORD*)lpColorTable,i);
                        lpColorTable++;
                    }
                }
                else
                {
                    for (i = 0; i < 16; i++)
                    {
                        SEND_PERMEDIA_DATA_OFFSET(TexelLUT0,
                            CHROMA_UPPER_ALPHA(*(DWORD*)lpColorTable),i);
                        lpColorTable++;
                    }
                }
                

                // Must reset the LUT index on Permedia P2
                
                SEND_PERMEDIA_DATA(TexelLUTIndex, 0);
                SEND_PERMEDIA_DATA(TexelLUTTransfer, __PERMEDIA_DISABLE);
            
            }
            else
            {
                DBG_D3D((0, "NULL == pPalette in EnableTexturePermedia"
                    "dwPaletteHandle=%08lx dwSurfaceHandle=%08lx",
                    pTexture->dwPaletteHandle,
                    pContext->CurrentTextureHandle)); 
            }
        }
        else
        {
            // Not palette indexed
            
            SEND_PERMEDIA_DATA(TexelLUTMode, __PERMEDIA_DISABLE);
            
        }

        if ((pTexture->dwFlags & DDRAWISURF_HASCKEYSRCBLT)
            && (pContext->RenderStates[D3DRENDERSTATE_COLORKEYENABLE])) 
        {
            DWORD LowerBound = pTexture->dwKeyLow;
            DWORD UpperBound = pTexture->dwKeyHigh;
            DWORD dwLowIndexColor;

            pContext->bCanChromaKey = TRUE;
            
            DBG_D3D((4,"    Can Chroma Key the texture"));
            // Enable Chroma keying for the texture
            // ..and set the correct colour

            // Evaluate the new chroma key value.  Shouldn't be too expensive,
            // as it is only bit shifts and a couple of tests.
            // We also change only when the texture map has changed.
            DBG_D3D((4, "dwColorSpaceLow = 0x%08X", LowerBound));
            DBG_D3D((4, "dwColorSpaceHigh = 0x%08X", UpperBound));

            if (NULL != pPalette) 
            {
                if (pPrivateData->SurfaceFormat.Format == 
                                                    PERMEDIA_4BIT_PALETTEINDEX)
                {
                    LowerBound &= 0x0F;
                }
                else
                {
                    LowerBound &= 0xFF;
                }
                lpColorTable = pPalette->ColorTable;

                // ChromaKeying for 4/8 Bit textures is done on the looked up 
                // color, not the index. This means using a range is 
                // meaningless and we have to lookup the color from the 
                // palette.  Make sure the user doesn't force us to access 
                // invalid memory.
                dwLowIndexColor = *(DWORD*)(&lpColorTable[LowerBound]);
                if (pPalette->dwFlags & DDRAWIPAL_ALPHA)
                {
                    LowerBound = UpperBound = dwLowIndexColor;
                }
                else
                {
                    LowerBound = CHROMA_LOWER_ALPHA(dwLowIndexColor);
                    UpperBound = CHROMA_UPPER_ALPHA(dwLowIndexColor);
                }
                DBG_D3D((4,"PaletteHandle=%08lx Lower=%08lx ChromaColor=%08lx"
                    "lpColorTable=%08lx dwFlags=%08lx",
                    pTexture->dwPaletteHandle, LowerBound, dwLowIndexColor,
                    lpColorTable, pPalette->dwFlags));
            }
            else 
                Convert_Chroma_2_8888ARGB(&LowerBound,
                                      &UpperBound,
                                      pPrivateData->SurfaceFormat.RedMask,
                                      pPrivateData->SurfaceFormat.AlphaMask,
                                      pPrivateData->SurfaceFormat.PixelSize);

            DBG_D3D((4,"LowerBound Selected: 0x%x", LowerBound));
            DBG_D3D((4,"UpperBound Selected: 0x%x", UpperBound));

            // If it's a P2 we can use alpha mapping to 
            // improve bilinear chroma keying.
            if (0/*(unsigned int)pSoftPermedia->TextureReadMode.FilterMode == 1*/)
            {
                pSoftPermedia->TextureDataFormat.AlphaMap = 
                                             PM_TEXDATAFORMAT_ALPHAMAP_EXCLUDE;
                pSoftPermedia->TextureDataFormat.NoAlphaBuffer = 1;
                
                SEND_PERMEDIA_DATA(AlphaMapUpperBound, UpperBound);
                SEND_PERMEDIA_DATA(AlphaMapLowerBound, LowerBound);
                SEND_PERMEDIA_DATA(ChromaUpperBound, 0xFFFFFFFF);
                SEND_PERMEDIA_DATA(ChromaLowerBound, 0xFF000000);
                
                pSoftPermedia->YUVMode.TestMode = 
                                               PM_YUVMODE_CHROMATEST_PASSWITHIN;
            }
            else
            {
                pSoftPermedia->TextureDataFormat.AlphaMap =  
                                              PM_TEXDATAFORMAT_ALPHAMAP_DISABLE;
                
                SEND_PERMEDIA_DATA(ChromaUpperBound, UpperBound);
                SEND_PERMEDIA_DATA(ChromaLowerBound, LowerBound);
                

                pSoftPermedia->YUVMode.TestMode = 
                                               PM_YUVMODE_CHROMATEST_FAILWITHIN;
            }
        }
        else
        {
            DBG_D3D((2,"    Can't Chroma Key the texture"));
            pContext->bCanChromaKey = FALSE;
            pSoftPermedia->TextureDataFormat.AlphaMap = __PERMEDIA_DISABLE;
            pSoftPermedia->YUVMode.TestMode = PM_YUVMODE_CHROMATEST_DISABLE;
        }
        

        // Restore the filter mode from the mag filter.
        if (pContext->bMagFilter) 
        {
            pSoftPermedia->TextureReadMode.FilterMode = 1;
        }
        else 
        {
            pSoftPermedia->TextureReadMode.FilterMode = 0;
        }

        // If the texture is a YUV texture we need to change the color order
        // of the surface and turn on the YUV->RGB conversoin
        if (pPrivateData->SurfaceFormat.Format == PERMEDIA_YUV422) 
        {
            pSoftPermedia->YUVMode.Enable = __PERMEDIA_ENABLE;
            pSoftPermedia->TextureDataFormat.ColorOrder = INV_COLOR_MODE;
        }
        else 
        {
            pSoftPermedia->YUVMode.Enable = __PERMEDIA_DISABLE;
            pSoftPermedia->TextureDataFormat.ColorOrder = COLOR_MODE;
        }   

        // Send the Commands at the end (except the texture base address!!)
        
        COPY_PERMEDIA_DATA(TextureReadMode, pSoftPermedia->TextureReadMode);
        COPY_PERMEDIA_DATA(TextureDataFormat, pSoftPermedia->TextureDataFormat);
        COPY_PERMEDIA_DATA(ColorDDAMode, pSoftPermedia->ColorDDAMode);
        COPY_PERMEDIA_DATA(TextureMapFormat, pSoftPermedia->TextureMapFormat);
        COPY_PERMEDIA_DATA(TextureColorMode, pSoftPermedia->TextureColorMode);
        COPY_PERMEDIA_DATA(YUVMode, pSoftPermedia->YUVMode);
        COPY_PERMEDIA_DATA(TextureAddressMode, 
                                             pSoftPermedia->TextureAddressMode);

        COMMITDMAPTR();
        FLUSHDMA();
    }
    else 
    {
        DBG_D3D((0,"Invalid Texture handle (%d)!, doing nothing", 
                 pContext->CurrentTextureHandle));
        pContext->CurrentTextureHandle = 0;

        // If the texture is bad, let's ensure it's marked as such.
        // But only if the texture is actually there!!
        if (pTexture) 
            pTexture->MagicNo = TC_MAGIC_DISABLE;     
    }


Exit_EnableTexturePermedia:

    DBG_D3D((10,"Exiting EnableTexturePermedia"));

} // EnableTexturePermedia

//-----------------------------------------------------------------------------
//
// void: __PermediaDisableUnits
//
// Disables all the mode registers to give us a clean start.
//
//-----------------------------------------------------------------------------
void 
__PermediaDisableUnits(PERMEDIA_D3DCONTEXT* pContext)
{
    PERMEDIA_DEFS(pContext->ppdev);

    DBG_D3D((10,"Entering __PermediaDisableUnits"));

    RESERVEDMAPTR(28);

    SEND_PERMEDIA_DATA(RasterizerMode,       __PERMEDIA_DISABLE);
    SEND_PERMEDIA_DATA(AreaStippleMode,      __PERMEDIA_DISABLE);
    SEND_PERMEDIA_DATA(ScissorMode,          __PERMEDIA_DISABLE);

    SEND_PERMEDIA_DATA(ColorDDAMode,         __PERMEDIA_DISABLE);
    SEND_PERMEDIA_DATA(FogMode,              __PERMEDIA_DISABLE);

    SEND_PERMEDIA_DATA(LBReadMode,           __PERMEDIA_DISABLE);
    SEND_PERMEDIA_DATA(Window,               __PERMEDIA_DISABLE);
    SEND_PERMEDIA_DATA(StencilMode,          __PERMEDIA_DISABLE);
    SEND_PERMEDIA_DATA(DepthMode,            __PERMEDIA_DISABLE);

    SEND_PERMEDIA_DATA(LBWriteMode,          __PERMEDIA_DISABLE);
    SEND_PERMEDIA_DATA(FBReadMode,           __PERMEDIA_DISABLE);

    SEND_PERMEDIA_DATA(DitherMode,           __PERMEDIA_DISABLE);
    SEND_PERMEDIA_DATA(AlphaBlendMode,       __PERMEDIA_DISABLE);
    SEND_PERMEDIA_DATA(LogicalOpMode,        __PERMEDIA_DISABLE);
    SEND_PERMEDIA_DATA(FBWriteMode,          __PERMEDIA_DISABLE);

    SEND_PERMEDIA_DATA(StatisticMode,        __PERMEDIA_DISABLE);
    SEND_PERMEDIA_DATA(FilterMode,           __PERMEDIA_DISABLE);
    SEND_PERMEDIA_DATA(FBSourceData,         __PERMEDIA_DISABLE);

    SEND_PERMEDIA_DATA(LBWriteFormat,        __PERMEDIA_DISABLE);

    SEND_PERMEDIA_DATA(TextureReadMode,      __PERMEDIA_DISABLE);
    SEND_PERMEDIA_DATA(TextureMapFormat,     __PERMEDIA_DISABLE);
    SEND_PERMEDIA_DATA(TextureDataFormat,    __PERMEDIA_DISABLE);
    SEND_PERMEDIA_DATA(TexelLUTMode,         __PERMEDIA_DISABLE);

    SEND_PERMEDIA_DATA(TextureColorMode,     __PERMEDIA_DISABLE);
    SEND_PERMEDIA_DATA(AStart,               PM_BYTE_COLOR(0xFF));

    // Ensure AGP bit not set.
    SEND_PERMEDIA_DATA(TextureBaseAddress,   0);
    SEND_PERMEDIA_DATA(TexelLUTIndex,        0);
    SEND_PERMEDIA_DATA(TexelLUTTransfer,     __PERMEDIA_DISABLE);

    COMMITDMAPTR();
    FLUSHDMA();

    DBG_D3D((10,"Exiting __PermediaDisableUnits"));

} // __PermediaDisableUnits


#ifdef DBG

//-----------------------------------------------------------------------------
//
// void DumpTexture
//
// Debug dump of texture information
//
//-----------------------------------------------------------------------------
void 
DumpTexture(PPDev ppdev, 
            PERMEDIA_D3DTEXTURE* pTexture, 
            DDPIXELFORMAT* pPixelFormat)
{
    DBG_D3D((4, "\n** Texture Dump:"));

    DBG_D3D((4,"  Texture Width: %d", pTexture->wWidth));
    DBG_D3D((4,"  Texture Height: %d", pTexture->wHeight));

    if (NULL != pTexture->pTextureSurface)
    {
        DBG_D3D((4,"  LogWidth: %d", 
                 pTexture->MipLevels[0].logWidth));
        DBG_D3D((4,"  LogHeight: %d", 
                 pTexture->MipLevels[0].logHeight));
        DBG_D3D((4,"  PackedPP0: 0x%x", 
            pTexture->pTextureSurface->ulPackedPP));
    }
    DBG_D3D((4,"  Pixel Offset of Texture (PERMEDIA Chip): 0x%x", 
             pTexture->MipLevels[0].PixelOffset));
    
    // Show texture format
    if (pPixelFormat->dwRGBAlphaBitMask == 0xf000) 
    {
        DBG_D3D((4,"  Texture is 4:4:4:4"));
    }
    else if (pPixelFormat->dwRBitMask == 0xff0000) 
    {
        if (pPixelFormat->dwRGBAlphaBitMask != 0) 
        {
            DBG_D3D((4,"  Texture is 8:8:8:8"));
        }
        else 
        {
            DBG_D3D((4,"  Texture is 8:8:8"));
        }
    }
    else if (pPixelFormat->dwRBitMask == 0x7c00) 
    {
        if (pPixelFormat->dwRGBAlphaBitMask != 0) 
        {
            DBG_D3D((4,"  Texture is 1:5:5:5"));
        }
        else 
        {
            DBG_D3D((4,"  Texture is 5:5:5"));
        }
    }
    else if (pPixelFormat->dwRBitMask == 0xf800) 
    {
        DBG_D3D((4,"  Texture is 5:6:5"));
    }
    else if (pPixelFormat->dwRBitMask == 0xe0) 
    {
        DBG_D3D((4,"  Texture is 3:3:2"));
    }
} // DumpTexture
#endif

