/******************************Module*Header**********************************\
*
*                           *********************
*                           * DDraw SAMPLE CODE *
*                           *********************
*
* Module Name: ddstrblt.c
*
* Content:    
*
* Copyright (c) 1994-1998 3Dlabs Inc. Ltd. All rights reserved.
* Copyright (c) 1995-1999 Microsoft Corporation.  All rights reserved.
\*****************************************************************************/


#include "precomp.h"
#include "directx.h"
#include "dd.h"



//--------------------------------------------------------------------------
//
//  ConvertColorKeys
//
//  converts a color key to the Permedia internal format according to 
//  the given Permedia surface format
//
//--------------------------------------------------------------------------

VOID
ConvertColorKeys(PermediaSurfaceData *pSurface,
                 DWORD &dwLowerBound, 
                 DWORD &dwUpperBound)
{
    switch (pSurface->SurfaceFormat.Format)
    {
        case PERMEDIA_444_RGB:
            dwLowerBound = CHROMA_LOWER_ALPHA(
                FORMAT_4444_32BIT_BGR(dwLowerBound));
            dwUpperBound = CHROMA_UPPER_ALPHA(
                FORMAT_4444_32BIT_BGR(dwUpperBound));
            break;
        case PERMEDIA_332_RGB:
            dwLowerBound = CHROMA_LOWER_ALPHA(
                FORMAT_332_32BIT_BGR(dwLowerBound));
            dwUpperBound = CHROMA_UPPER_ALPHA(
                FORMAT_332_32BIT_BGR(dwUpperBound));
            break;
        case PERMEDIA_2321_RGB:
            dwLowerBound = CHROMA_LOWER_ALPHA(
                FORMAT_2321_32BIT_BGR(dwLowerBound));
            dwUpperBound = CHROMA_UPPER_ALPHA(
                FORMAT_2321_32BIT_BGR(dwUpperBound));
            break;
        case PERMEDIA_4BIT_PALETTEINDEX:
        case PERMEDIA_8BIT_PALETTEINDEX:
            dwLowerBound = CHROMA_LOWER_ALPHA(
                FORMAT_PALETTE_32BIT(dwLowerBound));
            dwUpperBound = CHROMA_UPPER_ALPHA(
                FORMAT_PALETTE_32BIT(dwUpperBound));
            break;
        case PERMEDIA_5551_RGB:
            dwLowerBound = CHROMA_LOWER_ALPHA(
                FORMAT_5551_32BIT_BGR(dwLowerBound));
            dwUpperBound = CHROMA_UPPER_ALPHA(
                FORMAT_5551_32BIT_BGR(dwUpperBound));
            dwLowerBound = dwLowerBound & 0xF8F8F8F8;   
            dwUpperBound = dwUpperBound | 0x07070707;
            break;
        case PERMEDIA_8888_RGB:
            // The permedia 565 mode is an extension, so don't confuse it with 
            // the 8888 mode which has the same number
            if (pSurface->SurfaceFormat.FormatExtension == 
                PERMEDIA_565_RGB_EXTENSION)
            {
                dwLowerBound = CHROMA_LOWER_ALPHA(
                    FORMAT_565_32BIT_BGR(dwLowerBound));
                dwUpperBound = CHROMA_UPPER_ALPHA(
                    FORMAT_565_32BIT_BGR(dwUpperBound));
                dwLowerBound = dwLowerBound & 0xF8F8FcF8; 
                dwUpperBound = dwUpperBound | 0x07070307;
            }
            else
            {
                dwLowerBound = CHROMA_LOWER_ALPHA(
                    FORMAT_8888_32BIT_BGR(dwLowerBound));
                dwUpperBound = CHROMA_UPPER_ALPHA(
                    FORMAT_8888_32BIT_BGR(dwUpperBound));
            }
            break;
        case PERMEDIA_888_RGB:
            dwLowerBound = CHROMA_LOWER_ALPHA(
                FORMAT_8888_32BIT_BGR(dwLowerBound));
            dwUpperBound = CHROMA_UPPER_ALPHA(
                FORMAT_8888_32BIT_BGR(dwUpperBound));
            break;
    }

    // swap blue and red if we have a RGB surface
    if (!pSurface->SurfaceFormat.ColorOrder)
    {
        dwLowerBound = SWAP_BR(dwLowerBound);   
        dwUpperBound = SWAP_BR(dwUpperBound);   
    }
}

//--------------------------------------------------------------------------
//
// PermediaStretchCopyBlt
//
// stretched blt through texture unit. no keying.
// handle mirroring if the stretched image requires it.
//
//--------------------------------------------------------------------------

VOID 
PermediaStretchCopyBlt( PPDev ppdev, 
                        LPDDHAL_BLTDATA lpBlt, 
                        PermediaSurfaceData* pDest, 
                        PermediaSurfaceData* pSource, 
                        RECTL *rDest, 
                        RECTL *rSrc, 
                        DWORD dwWindowBase, 
                        DWORD dwSourceOffset
                        )
{
    LONG lXScale;
    LONG lYScale;
    BOOL bYMirror=FALSE;
    BOOL bXMirror=FALSE;
    LONG lPixelSize=pDest->SurfaceFormat.PixelSize;

    DWORD dwDestWidth = rDest->right - rDest->left;
    DWORD dwDestHeight = rDest->bottom - rDest->top;
    DWORD dwSourceWidth = rSrc->right - rSrc->left;
    DWORD dwSourceHeight = rSrc->bottom - rSrc->top;

    DWORD dwTexSStart, dwTexTStart;
    DWORD dwRenderDirection;

    PERMEDIA_DEFS(ppdev);

    DBG_DD(( 5, "DDraw:PermediaStretchCopyBlt dwWindowBase=%08lx "
        "dwSourceOffset=%08lx", dwWindowBase, dwSourceOffset));

    ASSERTDD(pDest, "Not valid private surface in destination");
    ASSERTDD(pSource, "Not valid private surface in source");

    lXScale = (dwSourceWidth << 20) / dwDestWidth;
    lYScale = (dwSourceHeight << 20) / dwDestHeight;
    
    // Changes pixel depth to Dest buffer pixel depth if neccessary.
    RESERVEDMAPTR(28);

    SEND_PERMEDIA_DATA( FBPixelOffset, 0x0);
    SEND_PERMEDIA_DATA( FBReadPixel, pDest->SurfaceFormat.FBReadPixel);

    if (lPixelSize != 0)
    {
        // set writeback to dest surface...
        SEND_PERMEDIA_DATA( DitherMode,  
                            (pDest->SurfaceFormat.ColorOrder << 
                                PM_DITHERMODE_COLORORDER) | 
                            (pDest->SurfaceFormat.Format << 
                                PM_DITHERMODE_COLORFORMAT) |
                            (pDest->SurfaceFormat.FormatExtension << 
                                PM_DITHERMODE_COLORFORMATEXTENSION) |
                            (__PERMEDIA_ENABLE << PM_DITHERMODE_ENABLE)); 

    } 

    SEND_PERMEDIA_DATA(FBWindowBase, dwWindowBase);

    // set no read of dest.
    SEND_PERMEDIA_DATA(FBReadMode, pDest->ulPackedPP);
    SEND_PERMEDIA_DATA(LogicalOpMode, __PERMEDIA_DISABLE);

    // set base of source
    SEND_PERMEDIA_DATA(TextureBaseAddress, dwSourceOffset);
    SEND_PERMEDIA_DATA(TextureAddressMode,(1 << PM_TEXADDRESSMODE_ENABLE));
    SEND_PERMEDIA_DATA(TextureColorMode,  (1 << PM_TEXCOLORMODE_ENABLE) |
                                          (_P2_TEXTURE_COPY << 
                                                PM_TEXCOLORMODE_APPLICATION));

    SEND_PERMEDIA_DATA(TextureReadMode,
                        PM_TEXREADMODE_ENABLE(__PERMEDIA_ENABLE)|
                        PM_TEXREADMODE_FILTER(__PERMEDIA_DISABLE)|
                        PM_TEXREADMODE_WIDTH(11) |
                        PM_TEXREADMODE_HEIGHT(11) );

    // set source bitmap format
    SEND_PERMEDIA_DATA(TextureDataFormat, 
                        (pSource->SurfaceFormat.Format << 
                            PM_TEXDATAFORMAT_FORMAT) |
                        (pSource->SurfaceFormat.FormatExtension << 
                            PM_TEXDATAFORMAT_FORMATEXTENSION) |
                        (pSource->SurfaceFormat.ColorOrder << 
                            PM_TEXDATAFORMAT_COLORORDER));
    SEND_PERMEDIA_DATA(TextureMapFormat, (pSource->ulPackedPP) | 
                                         (pSource->SurfaceFormat.PixelSize << 
                                            PM_TEXMAPFORMAT_TEXELSIZE) );

    // If we are doing special effects, and we are mirroring, 
    // we need to fix up the rectangles and change the sense of 
    // the render operation - we need to be carefull with overlapping
    // rectangles
    if (dwWindowBase != dwSourceOffset)
    {
        dwRenderDirection = 1;
    }
    else
    {
        if(rSrc->top < rDest->top)
        {
            dwRenderDirection = 0;
        }
        else if(rSrc->top > rDest->top)
        {
            dwRenderDirection = 1;
        }
        else if(rSrc->left < rDest->left)
        {
            dwRenderDirection = 0;
        }
        else dwRenderDirection = 1;
    }

    if(NULL != lpBlt && lpBlt->dwFlags & DDBLT_DDFX)
    {
        bYMirror = lpBlt->bltFX.dwDDFX & DDBLTFX_MIRRORUPDOWN;
        bXMirror = lpBlt->bltFX.dwDDFX & DDBLTFX_MIRRORLEFTRIGHT;

    } else
    {
        if (dwRenderDirection==0)
        {
            bXMirror = TRUE;
            bYMirror = TRUE;
        }
    }

    if (bXMirror)        
    {
        dwTexSStart = rSrc->right - 1;
        lXScale = -lXScale;
    }   
    else
    {
        dwTexSStart = rSrc->left;
    }

    if (bYMirror)        
    {
        dwTexTStart = rSrc->bottom - 1;
        lYScale = -lYScale;
    }
    else
    {
        dwTexTStart = rSrc->top;
    }

    SEND_PERMEDIA_DATA(SStart,      dwTexSStart << 20);
    SEND_PERMEDIA_DATA(TStart,      dwTexTStart << 20);
    SEND_PERMEDIA_DATA(dSdx,        lXScale);
    SEND_PERMEDIA_DATA(dSdyDom,     0);
    SEND_PERMEDIA_DATA(dTdx,        0);
    SEND_PERMEDIA_DATA(dTdyDom,     lYScale);
    
    // Render the rectangle

    if (dwRenderDirection)
    {
        SEND_PERMEDIA_DATA(StartXDom, INTtoFIXED(rDest->left));
        SEND_PERMEDIA_DATA(StartXSub, INTtoFIXED(rDest->right));
        SEND_PERMEDIA_DATA(StartY,    INTtoFIXED(rDest->top));
        SEND_PERMEDIA_DATA(dY,        INTtoFIXED(1));
        SEND_PERMEDIA_DATA(Count,     rDest->bottom - rDest->top);
        SEND_PERMEDIA_DATA(Render,    __RENDER_TRAPEZOID_PRIMITIVE | 
                                      __RENDER_TEXTURED_PRIMITIVE);
    }
    else
    {
        // Render right to left, bottom to top
        SEND_PERMEDIA_DATA(StartXDom, INTtoFIXED(rDest->right));
        SEND_PERMEDIA_DATA(StartXSub, INTtoFIXED(rDest->left));
        SEND_PERMEDIA_DATA(StartY,    INTtoFIXED(rDest->bottom - 1));
        SEND_PERMEDIA_DATA(dY,        (DWORD)INTtoFIXED(-1));
        SEND_PERMEDIA_DATA(Count,     rDest->bottom - rDest->top);
        SEND_PERMEDIA_DATA(Render,    __RENDER_TRAPEZOID_PRIMITIVE | 
                                      __RENDER_TEXTURED_PRIMITIVE);
    }

    SEND_PERMEDIA_DATA(DitherMode, __PERMEDIA_DISABLE);
    SEND_PERMEDIA_DATA(TextureAddressMode, __PERMEDIA_DISABLE);
    SEND_PERMEDIA_DATA(TextureColorMode, __PERMEDIA_DISABLE);
    SEND_PERMEDIA_DATA(TextureReadMode, __PERMEDIA_DISABLE);

    COMMITDMAPTR();
    FLUSHDMA();

}   // PermediaStretchCopyBlt 

//--------------------------------------------------------------------------
//
// PermediaSourceChromaBlt
//
// Does a blit through the texture unit to allow chroma keying.
// Note the unpacking of the colour key to fit into the Permedia format.
//
//--------------------------------------------------------------------------

VOID 
PermediaSourceChromaBlt(    PPDev ppdev, 
                            LPDDHAL_BLTDATA lpBlt, 
                            PermediaSurfaceData* pDest, 
                            PermediaSurfaceData* pSource, 
                            RECTL *rDest, 
                            RECTL *rSrc, 
                            DWORD dwWindowBase, 
                            DWORD dwSourceOffset
                            )
{
    DWORD dwLowerBound = lpBlt->bltFX.ddckSrcColorkey.dwColorSpaceLowValue;
    DWORD dwUpperBound = lpBlt->bltFX.ddckSrcColorkey.dwColorSpaceHighValue;
    DWORD dwRenderDirection;
    LONG lPixelSize=pDest->SurfaceFormat.PixelSize;

    PERMEDIA_DEFS(ppdev);

    DBG_DD(( 5, "DDraw:PermediaSourceChromaBlt"));

    ASSERTDD(pDest, "Not valid private surface in destination");
    ASSERTDD(pSource, "Not valid private surface in source");

    // Changes pixel depth to Frame buffer pixel depth if neccessary.

    ConvertColorKeys( pSource, dwLowerBound, dwUpperBound);

    RESERVEDMAPTR(31);

    SEND_PERMEDIA_DATA(FBReadPixel, pDest->SurfaceFormat.FBReadPixel);

    if (lPixelSize != 0)
    {
        
        // set writeback to dest surface...
        SEND_PERMEDIA_DATA( DitherMode,
                            (pDest->SurfaceFormat.ColorOrder << 
                                PM_DITHERMODE_COLORORDER) | 
                            (pDest->SurfaceFormat.Format << 
                                PM_DITHERMODE_COLORFORMAT) |
                            (pDest->SurfaceFormat.FormatExtension << 
                                PM_DITHERMODE_COLORFORMATEXTENSION) |
                            (1 << PM_DITHERMODE_ENABLE)); 
        
    } 

    
    // Reject range
    SEND_PERMEDIA_DATA(YUVMode, PM_YUVMODE_CHROMATEST_FAILWITHIN << 1);
    SEND_PERMEDIA_DATA(FBWindowBase, dwWindowBase);

    // set no read of source.
    // add read src/dest enable
    SEND_PERMEDIA_DATA(FBReadMode,pDest->ulPackedPP);
    SEND_PERMEDIA_DATA(LogicalOpMode, __PERMEDIA_DISABLE);

    // set base of source
    SEND_PERMEDIA_DATA(TextureBaseAddress, dwSourceOffset);
    SEND_PERMEDIA_DATA(TextureAddressMode,(1 << PM_TEXADDRESSMODE_ENABLE));
    //
    // modulate & ramp??
    SEND_PERMEDIA_DATA(TextureColorMode, (1 << PM_TEXCOLORMODE_ENABLE) |
                                         (_P2_TEXTURE_COPY << 
                                            PM_TEXCOLORMODE_APPLICATION));

    SEND_PERMEDIA_DATA(TextureReadMode, 
                       PM_TEXREADMODE_ENABLE(__PERMEDIA_ENABLE) |
                       PM_TEXREADMODE_FILTER(__PERMEDIA_DISABLE) |
                       PM_TEXREADMODE_WIDTH(11) |
                       PM_TEXREADMODE_HEIGHT(11) );

    SEND_PERMEDIA_DATA(TextureDataFormat,   
                       (pSource->SurfaceFormat.Format << 
                            PM_TEXDATAFORMAT_FORMAT) |
                       (pSource->SurfaceFormat.FormatExtension << 
                            PM_TEXDATAFORMAT_FORMATEXTENSION) |
                       (pSource->SurfaceFormat.ColorOrder << 
                            PM_TEXDATAFORMAT_COLORORDER));

    SEND_PERMEDIA_DATA( TextureMapFormat, 
                        (pSource->ulPackedPP) | 
                        (pSource->SurfaceFormat.PixelSize << 
                            PM_TEXMAPFORMAT_TEXELSIZE) );


    SEND_PERMEDIA_DATA(ChromaLowerBound, dwLowerBound);
    SEND_PERMEDIA_DATA(ChromaUpperBound, dwUpperBound);
    
    if ((lpBlt->lpDDDestSurface->lpGbl->fpVidMem) != 
        (lpBlt->lpDDSrcSurface->lpGbl->fpVidMem))
    {
        dwRenderDirection = 1;
    }
    else
    {
        if(rSrc->top < rDest->top)
        {
            dwRenderDirection = 0;
        }
        else if(rSrc->top > rDest->top)
        {
            dwRenderDirection = 1;
        }
        else if(rSrc->left < rDest->left)
        {
            dwRenderDirection = 0;
        }
        else dwRenderDirection = 1;
    }

    /*
     * Render the rectangle
     */

    // Left -> right, top->bottom
    if (dwRenderDirection)
    {
        // set offset of source
        SEND_PERMEDIA_DATA(SStart,    rSrc->left<<20);
        SEND_PERMEDIA_DATA(TStart,    rSrc->top<<20);
        SEND_PERMEDIA_DATA(dSdx,      1 << 20);
        SEND_PERMEDIA_DATA(dSdyDom,   0);
        SEND_PERMEDIA_DATA(dTdx,      0);
        SEND_PERMEDIA_DATA(dTdyDom,   1 << 20);

        SEND_PERMEDIA_DATA(StartXDom, INTtoFIXED(rDest->left));
        SEND_PERMEDIA_DATA(StartXSub, INTtoFIXED(rDest->right));
        SEND_PERMEDIA_DATA(StartY,    INTtoFIXED(rDest->top));
        SEND_PERMEDIA_DATA(dY,        INTtoFIXED(1));
        SEND_PERMEDIA_DATA(Count,     rDest->bottom - rDest->top);
        SEND_PERMEDIA_DATA(Render,    __RENDER_TRAPEZOID_PRIMITIVE | 
                                      __RENDER_TEXTURED_PRIMITIVE);
    }
    else
    // right->left, bottom->top
    {
        // set offset of source
        SEND_PERMEDIA_DATA(SStart,    rSrc->right << 20);
        SEND_PERMEDIA_DATA(TStart,    (rSrc->bottom - 1) << 20);
        SEND_PERMEDIA_DATA(dSdx,      (DWORD)(-1 << 20));
        SEND_PERMEDIA_DATA(dSdyDom,   0);
        SEND_PERMEDIA_DATA(dTdx,      0);
        SEND_PERMEDIA_DATA(dTdyDom,   (DWORD)(-1 << 20));

        // Render right to left, bottom to top
        SEND_PERMEDIA_DATA(StartXDom, INTtoFIXED(rDest->right));
        SEND_PERMEDIA_DATA(StartXSub, INTtoFIXED(rDest->left));
        SEND_PERMEDIA_DATA(StartY,    INTtoFIXED(rDest->bottom - 1));
        SEND_PERMEDIA_DATA(dY,        (DWORD)INTtoFIXED(-1));
        SEND_PERMEDIA_DATA(Count,     rDest->bottom - rDest->top);
        SEND_PERMEDIA_DATA(Render,    __RENDER_TRAPEZOID_PRIMITIVE | 
                                      __RENDER_TEXTURED_PRIMITIVE);
    }


    // Turn off chroma key
    SEND_PERMEDIA_DATA(YUVMode, 0x0);

    SEND_PERMEDIA_DATA(TextureAddressMode, __PERMEDIA_DISABLE);
    SEND_PERMEDIA_DATA(TextureColorMode, __PERMEDIA_DISABLE);
    SEND_PERMEDIA_DATA(TextureReadMode, __PERMEDIA_DISABLE);

    if (pSource->SurfaceFormat.PixelSize != 0)
    {   
        SEND_PERMEDIA_DATA(DitherMode, 0);
    }

    COMMITDMAPTR();
    FLUSHDMA();

}   // PermediaSourceChromaBlt 

//--------------------------------------------------------------------------
//
// PermediaStretchCopyChromaBlt
//
// Does a blit through the texture unit to allow stretching.  Also
// handle mirroring and chroma keying if the stretched image requires it.
//
//--------------------------------------------------------------------------

VOID 
PermediaStretchCopyChromaBlt(   PPDev ppdev, 
                                LPDDHAL_BLTDATA lpBlt, 
                                PermediaSurfaceData* pDest, 
                                PermediaSurfaceData* pSource, 
                                RECTL *rDest, 
                                RECTL *rSrc, 
                                DWORD dwWindowBase, 
                                DWORD dwSourceOffset
                                )
{
    LONG lXScale;
    LONG lYScale;
    BOOL bYMirror;
    BOOL bXMirror;
    DWORD dwDestWidth = rDest->right - rDest->left;
    DWORD dwDestHeight = rDest->bottom - rDest->top;
    DWORD dwSourceWidth = rSrc->right - rSrc->left;
    DWORD dwSourceHeight = rSrc->bottom - rSrc->top;
    DWORD dwTexSStart, dwTexTStart;
    DWORD dwRenderDirection;
    LONG lPixelSize=pDest->SurfaceFormat.PixelSize;

    DWORD dwLowerBound = lpBlt->bltFX.ddckSrcColorkey.dwColorSpaceLowValue;
    DWORD dwUpperBound = lpBlt->bltFX.ddckSrcColorkey.dwColorSpaceHighValue;
    PERMEDIA_DEFS(ppdev);

    DBG_DD(( 5, "DDraw:PermediaStretchCopyChromaBlt"));

    ASSERTDD(pDest, "Not valid private surface in destination");
    ASSERTDD(pSource, "Not valid private surface in source");

    // Changes pixel depth to Frame buffer pixel depth if neccessary.

    ConvertColorKeys( pSource, dwLowerBound, dwUpperBound);

    RESERVEDMAPTR(31);

    SEND_PERMEDIA_DATA(FBReadPixel, pDest->SurfaceFormat.FBReadPixel);

    if (lPixelSize != 0)
    {

        // set writeback to dest surface...
        SEND_PERMEDIA_DATA( DitherMode,  
                            (pDest->SurfaceFormat.ColorOrder << 
                                PM_DITHERMODE_COLORORDER) | 
                            (pDest->SurfaceFormat.Format << 
                                PM_DITHERMODE_COLORFORMAT) |
                            (pDest->SurfaceFormat.FormatExtension << 
                                PM_DITHERMODE_COLORFORMATEXTENSION) |
                            (1 << PM_DITHERMODE_ENABLE)); 

    } 

    // Reject range
    SEND_PERMEDIA_DATA(YUVMode, PM_YUVMODE_CHROMATEST_FAILWITHIN <<1);
    SEND_PERMEDIA_DATA(FBWindowBase, dwWindowBase);

    // set no read of source.
    SEND_PERMEDIA_DATA(FBReadMode, pDest->ulPackedPP);
    SEND_PERMEDIA_DATA(LogicalOpMode, __PERMEDIA_DISABLE);

    // set base of source
    SEND_PERMEDIA_DATA(TextureBaseAddress, dwSourceOffset);
    SEND_PERMEDIA_DATA(TextureAddressMode,(1 << PM_TEXADDRESSMODE_ENABLE));
    
    SEND_PERMEDIA_DATA( TextureColorMode,
                        (1 << PM_TEXCOLORMODE_ENABLE) |
                        (_P2_TEXTURE_COPY << PM_TEXCOLORMODE_APPLICATION));

    SEND_PERMEDIA_DATA( TextureReadMode, 
                        PM_TEXREADMODE_ENABLE(__PERMEDIA_ENABLE) |
                        PM_TEXREADMODE_FILTER(__PERMEDIA_DISABLE) |
                        PM_TEXREADMODE_WIDTH(11) |
                        PM_TEXREADMODE_HEIGHT(11));

    lXScale = (dwSourceWidth << 20) / (dwDestWidth);
    lYScale = (dwSourceHeight << 20) / (dwDestHeight);

    SEND_PERMEDIA_DATA( TextureDataFormat,
                        (pSource->SurfaceFormat.Format << 
                            PM_TEXDATAFORMAT_FORMAT) |
                        (pSource->SurfaceFormat.FormatExtension << 
                            PM_TEXDATAFORMAT_FORMATEXTENSION) |
                        (pSource->SurfaceFormat.ColorOrder << 
                            PM_TEXDATAFORMAT_COLORORDER));

    SEND_PERMEDIA_DATA( TextureMapFormat, 
                        (pSource->ulPackedPP) | 
                        (pSource->SurfaceFormat.PixelSize << 
                            PM_TEXMAPFORMAT_TEXELSIZE) );

    bYMirror = FALSE;
    bXMirror = FALSE;

    if ((lpBlt->lpDDDestSurface->lpGbl->fpVidMem) != 
        (lpBlt->lpDDSrcSurface->lpGbl->fpVidMem))
    {
        dwRenderDirection = 1;
    }
    else
    {
        if(rSrc->top < rDest->top)
        {
            dwRenderDirection = 0;
        }
        else if(rSrc->top > rDest->top)
        {
            dwRenderDirection = 1;
        }
        else if(rSrc->left < rDest->left)
        {
            dwRenderDirection = 0;
        }
        else dwRenderDirection = 1;
    }

    if(lpBlt->dwFlags & DDBLT_DDFX)
    {
        bYMirror = lpBlt->bltFX.dwDDFX & DDBLTFX_MIRRORUPDOWN;
        bXMirror = lpBlt->bltFX.dwDDFX & DDBLTFX_MIRRORLEFTRIGHT;

    } else
    {
        if (dwRenderDirection==0)
        {
            bXMirror = TRUE;
            bYMirror = TRUE;
        }
    }

    if (bXMirror)        
    {
        dwTexSStart = rSrc->right - 1;
        lXScale = -lXScale;
    }   
    else
    {
        dwTexSStart = rSrc->left;
    }

    if (bYMirror)        
    {
        dwTexTStart = rSrc->bottom - 1;
        lYScale = -lYScale;
    }
    else
    {
        dwTexTStart = rSrc->top;
    }

    SEND_PERMEDIA_DATA(dTdyDom, lYScale);
    SEND_PERMEDIA_DATA(ChromaLowerBound, dwLowerBound);
    SEND_PERMEDIA_DATA(ChromaUpperBound, dwUpperBound);

    // set texture coordinates
    SEND_PERMEDIA_DATA(SStart,      dwTexSStart << 20);
    SEND_PERMEDIA_DATA(TStart,      dwTexTStart << 20);
    SEND_PERMEDIA_DATA(dSdx,        lXScale);
    SEND_PERMEDIA_DATA(dSdyDom,     0);
    SEND_PERMEDIA_DATA(dTdx,        0);

    //
    // Render the rectangle
    //

    if (dwRenderDirection)
    {
        SEND_PERMEDIA_DATA(StartXDom, INTtoFIXED(rDest->left));
        SEND_PERMEDIA_DATA(StartXSub, INTtoFIXED(rDest->right));
        SEND_PERMEDIA_DATA(StartY,    INTtoFIXED(rDest->top));
        SEND_PERMEDIA_DATA(dY,        INTtoFIXED(1));
    }
    else
    {
        SEND_PERMEDIA_DATA(StartXDom, INTtoFIXED(rDest->right));
        SEND_PERMEDIA_DATA(StartXSub, INTtoFIXED(rDest->left));
        SEND_PERMEDIA_DATA(StartY,    INTtoFIXED(rDest->bottom - 1));
        SEND_PERMEDIA_DATA(dY,        (DWORD)INTtoFIXED(-1));
    }

    SEND_PERMEDIA_DATA(Count,     rDest->bottom - rDest->top);
    SEND_PERMEDIA_DATA(Render,    __RENDER_TRAPEZOID_PRIMITIVE | 
                                  __RENDER_TEXTURED_PRIMITIVE);


    // Turn off units
    SEND_PERMEDIA_DATA(YUVMode, __PERMEDIA_DISABLE);
    SEND_PERMEDIA_DATA(TextureAddressMode, __PERMEDIA_DISABLE);
    SEND_PERMEDIA_DATA(TextureColorMode, __PERMEDIA_DISABLE);
    SEND_PERMEDIA_DATA(TextureReadMode, __PERMEDIA_DISABLE);

    if (pSource->SurfaceFormat.PixelSize != 0)
    {
        SEND_PERMEDIA_DATA(DitherMode, 0);
    }

    COMMITDMAPTR();
    FLUSHDMA();

} // PermediaStretchCopyChromaBlt 

//--------------------------------------------------------------------------
//
// PermediaYUVtoRGB
//
// Permedia2 YUV to RGB conversion blt
//
//--------------------------------------------------------------------------


VOID 
PermediaYUVtoRGB(   PPDev ppdev, 
                    DDBLTFX* lpBltFX, 
                    PermediaSurfaceData* pDest, 
                    PermediaSurfaceData* pSource, 
                    RECTL *rDest, 
                    RECTL *rSrc, 
                    DWORD dwWindowBase, 
                    DWORD dwSourceOffset)
{
    DWORD lXScale;
    DWORD lYScale;
    DWORD dwDestWidth = rDest->right - rDest->left;
    DWORD dwDestHeight = rDest->bottom - rDest->top;
    DWORD dwSourceWidth = rSrc->right - rSrc->left;
    DWORD dwSourceHeight = rSrc->bottom - rSrc->top;
    PERMEDIA_DEFS(ppdev);
    
    ASSERTDD(pDest, "Not valid private surface in destination");
    ASSERTDD(pSource, "Not valid private surface in source");
    
    lXScale = (dwSourceWidth << 20) / dwDestWidth;
    lYScale = (dwSourceHeight << 20) / dwDestHeight;
    
    // Changes pixel depth to Frame buffer pixel depth if neccessary.
    
    RESERVEDMAPTR(29);

    SEND_PERMEDIA_DATA(FBReadPixel,ppdev->bPixShift);
    
    if (pDest->SurfaceFormat.PixelSize != __PERMEDIA_8BITPIXEL)
    {
        SEND_PERMEDIA_DATA(DitherMode, 
            (COLOR_MODE << PM_DITHERMODE_COLORORDER) | 
            (pDest->SurfaceFormat.Format << PM_DITHERMODE_COLORFORMAT) |
            (pDest->SurfaceFormat.FormatExtension << 
                PM_DITHERMODE_COLORFORMATEXTENSION) |
            (1 << PM_DITHERMODE_ENABLE) |
            (1 << PM_DITHERMODE_DITHERENABLE));
    }
    
    SEND_PERMEDIA_DATA(FBWindowBase, dwWindowBase);
    
    // set no read of source.
    SEND_PERMEDIA_DATA(FBReadMode, pDest->ulPackedPP);
    SEND_PERMEDIA_DATA(LogicalOpMode, __PERMEDIA_DISABLE);
    
    // set base of source
    SEND_PERMEDIA_DATA(TextureBaseAddress, dwSourceOffset);
    SEND_PERMEDIA_DATA(TextureAddressMode,(1 << PM_TEXADDRESSMODE_ENABLE));
    
    SEND_PERMEDIA_DATA( TextureColorMode,
                        (1 << PM_TEXCOLORMODE_ENABLE) |
                        (_P2_TEXTURE_COPY << PM_TEXCOLORMODE_APPLICATION));
    
    SEND_PERMEDIA_DATA( TextureReadMode, 
                        PM_TEXREADMODE_ENABLE(__PERMEDIA_ENABLE) |
                        PM_TEXREADMODE_FILTER(__PERMEDIA_ENABLE) |
                        PM_TEXREADMODE_WIDTH(11) |
                        PM_TEXREADMODE_HEIGHT(11) );
    
    SEND_PERMEDIA_DATA( TextureDataFormat, 
                        (pSource->SurfaceFormat.Format << 
                            PM_TEXDATAFORMAT_FORMAT) |
                        (pSource->SurfaceFormat.FormatExtension << 
                            PM_TEXDATAFORMAT_FORMATEXTENSION) |
                        (INV_COLOR_MODE << PM_TEXDATAFORMAT_COLORORDER));
    
    SEND_PERMEDIA_DATA( TextureMapFormat,    
                        (pSource->ulPackedPP) | 
                        (pSource->SurfaceFormat.PixelSize << 
                            PM_TEXMAPFORMAT_TEXELSIZE) );
    
    // Turn on the YUV unit
    SEND_PERMEDIA_DATA(YUVMode, 0x1);
    
    SEND_PERMEDIA_DATA(LogicalOpMode, 0);
    
    // set offset of source
    SEND_PERMEDIA_DATA(SStart,    rSrc->left << 20);
    SEND_PERMEDIA_DATA(TStart,    rSrc->top << 20);
    SEND_PERMEDIA_DATA(dSdx,      lXScale);
    SEND_PERMEDIA_DATA(dSdyDom,   0);
    SEND_PERMEDIA_DATA(dTdx,      0);
    SEND_PERMEDIA_DATA(dTdyDom, lYScale);
    
    
    // Render the rectangle
    //
    SEND_PERMEDIA_DATA(StartXDom, INTtoFIXED(rDest->left));
    SEND_PERMEDIA_DATA(StartXSub, INTtoFIXED(rDest->right));
    SEND_PERMEDIA_DATA(StartY,    INTtoFIXED(rDest->top));
    SEND_PERMEDIA_DATA(dY,        INTtoFIXED(1));
    SEND_PERMEDIA_DATA(Count,     rDest->bottom - rDest->top);
    SEND_PERMEDIA_DATA(Render,    __RENDER_TRAPEZOID_PRIMITIVE | 
                                  __RENDER_TEXTURED_PRIMITIVE);
    
    if (pSource->SurfaceFormat.PixelSize != __PERMEDIA_8BITPIXEL)
    {
        SEND_PERMEDIA_DATA(DitherMode, 0);
    }
    
    // Turn off units
    SEND_PERMEDIA_DATA(YUVMode, 0x0);
    SEND_PERMEDIA_DATA( TextureAddressMode,
                        (0 << PM_TEXADDRESSMODE_ENABLE));
    SEND_PERMEDIA_DATA( TextureColorMode,    
                        (0 << PM_TEXCOLORMODE_ENABLE));
    COMMITDMAPTR();
    FLUSHDMA();
}


