/******************************Module*Header*******************************\
* Module Name: pointer.c
*
* This module contains the hardware pointer support for the XGA dispaly driver.
*
*
* Copyright (c) 1992 Microsoft Corporation
\**************************************************************************/

#include "driver.h"

ULONG DrvSetColorPointerShape(
    SURFOBJ     *pso,
    SURFOBJ     *psoMask,
    SURFOBJ     *psoColor,
    XLATEOBJ    *pxlo,
    LONG        xHot,
    LONG        yHot,
    LONG        x,
    LONG        y,
    RECTL       *prcl,
    FLONG       fl
) ;

ULONG DrvSetMonoHwPointerShape(
    SURFOBJ     *pso,
    SURFOBJ     *psoMask,
    SURFOBJ     *psoColor,
    XLATEOBJ    *pxlo,
    LONG        xHot,
    LONG        yHot,
    LONG        x,
    LONG        y,
    RECTL       *prcl,
    FLONG       fl
) ;


VOID DrvMoveColorPointer(SURFOBJ *pso,LONG x,LONG y,RECTL *prcl) ;
VOID DrvMoveHwPointer(SURFOBJ *pso,LONG x,LONG y,RECTL *prcl) ;


#define VALID_SAVE_BUFFER 0x1
#define COLOR_POINTER     0x2
#define TAKE_DOWN_POINTER 0X4



/*****************************************************************************
 * DrvMovePointer -
 ****************************************************************************/
VOID DrvMovePointer(SURFOBJ *pso,LONG x,LONG y,RECTL *prcl)
{
PPDEV   ppdev ;

        ppdev = (PPDEV) pso->dhpdev ;

        if (ppdev->gPointerFlags & COLOR_POINTER)
            DrvMoveColorPointer(pso, x, y, prcl) ;
        else
            DrvMoveHwPointer(pso, x, y, prcl) ;

        return ;

}


/*****************************************************************************
 * DrvMoveColorPointer -
 ****************************************************************************/
VOID DrvMoveColorPointer(SURFOBJ *pso,LONG x,LONG y,RECTL *prcl)
{
        return ;


}

/*****************************************************************************
 * DrvMoveHwPointer -
 ****************************************************************************/
VOID DrvMoveHwPointer(SURFOBJ *pso,LONG x,LONG y,RECTL *prcl)
{
WORD    msb,
        lsb ;

PPDEV   ppdev ;
INT     XgaIndexReg ;

        // get a local pointer to the pdev and all the registers we plan
        // to use.

        ppdev = (PPDEV) pso->dhpdev ;
        XgaIndexReg = ppdev->ulXgaIoRegsBase + INDEX_REG ;

        // If x is -1 then take down the cursor.

        if (x == -1)
        {
            outpw (XgaIndexReg, SPRITE_CONTROL) ;
            return ;
        }

        // Adjust the actual pointer position depending upon
        // the hot spot.

        x -= ppdev->gxHot ;
        y -= ppdev->gyHot ;

        if (x <= 0)
        {
            outpw (XgaIndexReg, ((-x << 8) | SPRITE_HORZ_PRESET)) ;
            x = 0 ;
        }
        else
        {
            outpw (XgaIndexReg, ((0 << 8) | SPRITE_HORZ_PRESET)) ;
        }

        if (y <= 0)
        {
            outpw (XgaIndexReg, ((-y << 8) | SPRITE_VERT_PRESET)) ;
            y = 0 ;
        }
        else
        {
            outpw (XgaIndexReg, ((0 << 8) | SPRITE_VERT_PRESET)) ;
        }

        // Set the position of the cursor.

        msb = HIBYTE (x) ;
        lsb = LOBYTE (x) ;
        outpw (XgaIndexReg, ((lsb << 8) | SPRITE_HORZ_START_LOW)) ;
        outpw (XgaIndexReg, ((msb << 8) | SPRITE_HORZ_START_HIGH)) ;

        msb = HIBYTE (y) ;
        lsb = LOBYTE (y) ;
        outpw (XgaIndexReg, ((lsb << 8) | SPRITE_VERT_START_LOW)) ;
        outpw (XgaIndexReg, ((msb << 8) | SPRITE_VERT_START_HIGH)) ;

        return ;
}


/*****************************************************************************
 * DrvSetPointerShape -
 ****************************************************************************/
ULONG DrvSetPointerShape(
    SURFOBJ     *pso,
    SURFOBJ     *psoMask,
    SURFOBJ     *psoColor,
    XLATEOBJ    *pxlo,
    LONG        xHot,
    LONG        yHot,
    LONG        x,
    LONG        y,
    RECTL       *prcl,
    FLONG       fl)
{
ULONG   ulRet ;

PPDEV   ppdev ;
INT     XgaIndexReg ;

        DISPDBG((3, "Change hardware pointer shape\n"));

        // get a local pointer to the pdev and all the registers we plan
        // to use.

        ppdev = (PPDEV) pso->dhpdev ;
        XgaIndexReg = ppdev->ulXgaIoRegsBase + INDEX_REG ;

        // Save the position and hot spot in globals.

        ppdev->gxHot = xHot ;
        ppdev->gyHot = yHot ;

        if (psoColor != NULL)
        {
            // Disable the mono hardware pointer.

            outpw (XgaIndexReg, SPRITE_CONTROL) ;

            ppdev->gPointerFlags |= COLOR_POINTER ;
            ulRet = DrvSetColorPointerShape(pso, psoMask, psoColor, pxlo,
                                            xHot, yHot, x, y, prcl, fl) ;

        }
        else
        {
            // Take down the color pointer if it is visible.

            if (   (ppdev->gPointerFlags & COLOR_POINTER)
                && (ppdev->gPointerFlags & VALID_SAVE_BUFFER)
               )
            {
                ulRet = DrvSetColorPointerShape(NULL, NULL, NULL, NULL,
                                                0, 0, 0, 0, NULL, 0) ;
            }

            // Take care of the monochrome pointer.

            ppdev->gPointerFlags &= ~COLOR_POINTER ;
            ulRet = DrvSetMonoHwPointerShape(pso, psoMask, psoColor, pxlo,
                                             xHot, yHot, x, y, prcl, fl) ;
        }


        return (ulRet) ;
}


/*****************************************************************************
 * DrvSetColorPointerShape -
 ****************************************************************************/
ULONG DrvSetColorPointerShape(
    SURFOBJ     *pso,
    SURFOBJ     *psoMask,
    SURFOBJ     *psoColor,
    XLATEOBJ    *pxlo,
    LONG        xHot,
    LONG        yHot,
    LONG        x,
    LONG        y,
    RECTL       *prcl,
    FLONG       fl)
{
        return (SPS_DECLINE) ;
}

/*****************************************************************************
 * DrvSetMonoHwPointerShape -
 ****************************************************************************/
ULONG DrvSetMonoHwPointerShape(
    SURFOBJ     *pso,
    SURFOBJ     *psoMask,
    SURFOBJ     *psoColor,
    XLATEOBJ    *pxlo,
    LONG        xHot,
    LONG        yHot,
    LONG        x,
    LONG        y,
    RECTL       *prcl,
    FLONG       fl)
{

UINT    i,
        j,
        cxMask,
        cyMask,
        cyAND,
        cxAND,
        cyXOR,
        cxXOR ;

PBYTE   pjAND,
        pjXOR ;

INT     lDelta ;

PPDEV   ppdev ;
INT     XgaIndexReg ;

INT     ix,
        iy,
        is,
        ip,
        iBit,
        jAndByte,
        jXorByte,
        jSpriteBits,
        jSpriteByte ;

BYTE    ajAndMask[64][8],
        ajXorMask[64][8] ;

BYTE    ajXgaSprite[1024] ;


        DISPDBG((3, "XGA.DLL:DrvSetPointerShape - Entry\n")) ;
        DISPDBG((3, "\txHot: %d\n", xHot)) ;
        DISPDBG((3, "\tyHot: %d\n", yHot)) ;

        // get a local pointer to the pdev and all the registers we plan
        // to use.

        ppdev = (PPDEV) pso->dhpdev ;
        XgaIndexReg = ppdev->ulXgaIoRegsBase + INDEX_REG ;

        // If the mask is NULL this implies the pointer is not
        // visible.

        if (psoMask == NULL)
        {
            outpw (XgaIndexReg, SPRITE_CONTROL) ;
            return (SPS_ACCEPT_NOEXCLUDE) ;
        }

        // Init the AND and XOR masks.

        memset (ajAndMask, 0xFFFFFFFF, 512) ;
        memset (ajXorMask, 0, 512) ;

        // Get the bitmap dimensions.

        cxMask = psoMask->sizlBitmap.cx ;
        cyMask = psoMask->sizlBitmap.cy ;

        cyAND = cyXOR = cyMask / 2 ;
        cxAND = cxXOR = cxMask / 8 ;

        // Set up pointers to the AND and XOR masks.

        pjAND  =  psoMask->pvScan0 ;
        lDelta = psoMask->lDelta ;
        pjXOR  = pjAND + (cyAND * lDelta) ;

        // Copy the AND mask.

        for (i = 0 ; i < cyAND ; i++)
        {
            // Copy over a line of the AND mask.

            for (j = 0 ; j < cxAND ; j++)
            {
                ajAndMask[i][j] = pjAND[j] ;
            }

            // point to the next line of the AND mask.

            pjAND += lDelta ;
        }

        // Copy the XOR mask.

        for (i = 0 ; i < cyXOR ; i++)
        {
            // Copy over a line of the XOR mask.

            for (j = 0 ; j < cxXOR ; j++)
            {
                ajXorMask[i][j] = pjXOR[j] ;
            }

            // point to the next line of the XOR mask.

            pjXOR += lDelta ;
        }

        // Build up the XGA sprite from NT's And and Xor masks.

        // Init the indexes into the sprite buffer (is) and the
        // index for the bit pairs (ip).

        is = 0 ;
        ip = 0 ;

        // Outer most loop goes over NT's And and Xor rows.

        for (iy = 0 ; iy < 64 ; iy++)
        {
            // loop over Nt's columns.

            for (ix = 0 ; ix < 8 ; ix++)
            {
                // pickup a source byte for each mask.

                jAndByte = ajAndMask[iy][ix] ;
                jXorByte = ajXorMask[iy][ix] ;

                // loop over the bits in the byte.

                for (iBit = 0x80 ; iBit != 0 ; iBit >>= 1)
                {
                    // init the sprite  bitpair.

                    jSpriteBits = 0x0 ;

                    // Set the sprite bit pairs.

                    if (jAndByte & iBit)
                        jSpriteBits |= 0x02 ;

                    if (jXorByte & iBit)
                        jSpriteBits |= 0x01 ;

                    // If all 4 bit pairs in this byte are filled in
                    // flush the sprite byte to the sprite byte array.
                    // and set the first bit pair.

                    if ((ip % 4) == 0)
                    {
                        if (ip != 0)
                        {
                            ajXgaSprite[is++] = jSpriteByte ;
                        }
                        jSpriteByte = jSpriteBits ;
                    }

                    // If the sprite byte is not full, shift the bit pair
                    // into position, and or it into the sprite byte.

                    else
                    {
                        jSpriteBits <<= (ip % 4) * 2 ;
                        jSpriteByte  |= jSpriteBits ;
                    }

                    // bump the bit pair counter.

                    ip++ ;
                }
            }
        }

        // Flush the last byte.

        ajXgaSprite[is++] = jSpriteByte ;


        // Disable the pointer.

        outpw (XgaIndexReg, SPRITE_CONTROL) ;

        // Set the sprite index to 0.

        outpw (XgaIndexReg, SPRITE_INDEX_LOW) ;
        outpw (XgaIndexReg, SPRITE_INDEX_HIGH) ;

        // Down load the sprite data to the XGA.

        for (i = 0 ; i < 1024 ; i++)
        {
            jSpriteByte = ajXgaSprite[i] ;
            outpw (XgaIndexReg, ((jSpriteByte << 8) | SPRITE_DATA)) ;
        }

        // Set the pointer colors.

        outpw (XgaIndexReg, SPRITE_COLOR_REG0_RED) ;
        outpw (XgaIndexReg, SPRITE_COLOR_REG0_GREEN) ;
        outpw (XgaIndexReg, SPRITE_COLOR_REG0_BLUE) ;

        outpw (XgaIndexReg, ((0xff << 8) | SPRITE_COLOR_REG1_RED)) ;
        outpw (XgaIndexReg, ((0xff << 8) | SPRITE_COLOR_REG1_GREEN)) ;
        outpw (XgaIndexReg, ((0xff << 8) | SPRITE_COLOR_REG1_BLUE)) ;

        // Set the position of the cursor.

        DrvMovePointer(pso, x, y, NULL) ;

        outpw (XgaIndexReg, ((SC << 8) | SPRITE_CONTROL)) ;

        return (SPS_ACCEPT_NOEXCLUDE) ;
}