|
|
/******************************Module*Header*******************************\
* Module Name: pointer.c * * Contains the pointer management functions. * * Copyright (c) 1992-1995 Microsoft Corporation * \**************************************************************************/
#include "precomp.h"
ULONG SetMonoHwPointerShape( SURFOBJ *pso, SURFOBJ *psoMask, SURFOBJ *psoColor, XLATEOBJ *pxlo, LONG xHot, LONG yHot, LONG x, LONG y, RECTL *prcl, FLONG fl);
BYTE jRepMask2[] = { 0x00, 0x05, 0x0a, 0x0f, 0x50, 0x55, 0x5a, 0x5f, 0xa0, 0xa5, 0xaa, 0xaf, 0xf0, 0xf5, 0xfa, 0xff, };
/*****************************************************************************
* DrvMovePointer - ****************************************************************************/ VOID DrvMovePointer( SURFOBJ* pso, LONG x, LONG y, RECTL* prcl) { PPDEV ppdev; INT xx, yy;
ppdev = (PPDEV) pso->dhpdev;
// If x is -1 then take down the cursor.
if (x == -1) { DISABLE_SPRITE(ppdev); return; }
// Adjust the actual pointer position depending upon
// the hot spot.
x -= ppdev->W32SpriteData.ptlHot.x; y -= ppdev->W32SpriteData.ptlHot.y;
if (ppdev->ulChipID == ET6000) { char xPreset = 0; char yPreset = 0;
// We may have disabled the sprite if it went off the screen.
// So, now have to detect if we did and re-enable it if necessary.
if (ppdev->W32SpriteData.fl & POINTER_DISABLED) { ENABLE_SPRITE(ppdev); }
if (x < 0) { xPreset = (CHAR)~x; x = 0; } if (y < 0) { yPreset = (CHAR)~y; y = 0; }
ET6K_HORZ_PRESET(ppdev, xPreset); ET6K_VERT_PRESET(ppdev, yPreset); ET6K_SPRITE_HORZ_POSITION(ppdev, x); ET6K_SPRITE_VERT_POSITION(ppdev, y); return; } else { //
// Adjust pointer x position for color depth
//
x *= ppdev->cBpp;
// Yet another bug.
// If the cursor is moved entirely off the screen, it could cause
// the screen to shake. So, we have to disable the cursor if it
// is moved entirely off the screen.
if ((x < - ((LONG) (ppdev->W32SpriteData.szlPointer.cx))) || (x > ((LONG) (ppdev->cxScreen * ppdev->cBpp))) || (y < - ((LONG) (ppdev->W32SpriteData.szlPointer.cy))) || (y > ((LONG) (ppdev->cyScreen)))) { DISABLE_SPRITE(ppdev); return; }
// We may have disabled the sprite if it went off the screen.
// So, now have to detect if we did and re-enable it if necessary.
// (remembering to keep track of the state).
if (ppdev->W32SpriteData.fl & POINTER_DISABLED) { ENABLE_SPRITE(ppdev); }
// The W32 non-rev-B has a problem with a vertical offset of 0x3f.
// All the other W32's have a problem with the last nibble being
// 0x0F for both the horizontal and the verical.
// Never set the bad presets on the chips in question.
if (x <= 0) { if ((ppdev->ulChipID == W32) && (ppdev->ulRevLevel != REV_B)) { xx = -x; if ((xx & 0x0F) == 0x0F) xx &= ~0x01;
SET_HORZ_PRESET(xx); } else { SET_HORZ_PRESET(-x); } x = 0; } else { SET_HORZ_PRESET(0); }
if (y <= 0) { if (ppdev->ulChipID == W32) { yy = -y;
if (ppdev->ulRevLevel != REV_B) { if (yy == 0x3F) yy = 0x3E; } else { if ((yy & 0x0F) == 0x0F) yy &= ~0x01; } SET_VERT_PRESET(yy); } else { SET_VERT_PRESET(-y); }
y = 0; } else { SET_VERT_PRESET(0); }
// You guessed it. Another bug.
// On the W32 Rev B you can not put the cursor on the bottom line
// of the display. And if were in interlaced mode you can't put it
// on the bottom two lines.
if ((ppdev->ulChipID == W32) && (ppdev->ulRevLevel == REV_B)) { INT i;
if (y > (i = ppdev->cyScreen - 2)) { OUTP(0x3D4, 0x35); if (INP(0x3D5) & 0x80) y = i; } else if (y > (i+1)) { y = i+1; } }
//////////////////////////////////////////////////////
// Set the position of the sprite.
if ((ppdev->ulChipID == W32I) || (ppdev->ulChipID == W32P)) { // You bet, one more bug, and this one is a lulu.
// First we have to set the vertical position before the horz
// position. Why you ask, because, if this is a W32 Rev B or later
// we may have to toggle a bit in a test register to really set the
// vertical position, but of course we don't want to set anything
// else at this point.
BYTE status, byte;
// Wait for horz display interval.
while ( (INP(0x3DA) & 0x02)); while (!((status = INP(0x3DA)) & 0x02));
SET_VERT_POSITION(y);
// Check if the sprite is being displayed at this very moment.
// And if it is then skip the test bit stuff.
if (!(status & 0x04)) { // Looks like we will have to toggle the test bit to
// really set the vertical position.
ENABLE_KEY(ppdev);
OUTP(0x3D4, 0x37); byte = INP(0x3D5); byte |= 0x40; OUTP(0x3D5, byte); byte &= ~0x40; OUTP(0x3D5, byte);
DISABLE_KEY(ppdev); }
SET_HORZ_POSITION(x); } else { // For consistency sake, we're going to set the vertical first
// even for non-W32 Rev B chips.
SET_VERT_POSITION(y); SET_HORZ_POSITION(x); }
return; } }
/******************************Public*Routine******************************\
* DrvSetPointerShape * * Sets the new pointer shape. \**************************************************************************/
ULONG DrvSetPointerShape( SURFOBJ *pso, SURFOBJ *psoMask, SURFOBJ *psoColor, XLATEOBJ *pxlo, LONG xHot, LONG yHot, LONG x, LONG y, RECTL *prcl, FLONG fl) { PPDEV ppdev; ULONG ulRet;
ppdev = (PPDEV) pso->dhpdev;
if (ppdev->flCaps & CAPS_SW_POINTER) { return(SPS_DECLINE); }
// Save the hot spot and dimensions of the cursor in globals.
ppdev->W32SpriteData.ptlHot.x = xHot; ppdev->W32SpriteData.ptlHot.y = yHot;
ppdev->W32SpriteData.szlPointer.cx = psoMask->sizlBitmap.cx * ppdev->cBpp; ppdev->W32SpriteData.szlPointer.cy = psoMask->sizlBitmap.cy / 2;
if (psoColor != NULL) { // Disable the mono hardware pointer, and decline the pointer
// shape
DISABLE_SPRITE(ppdev);
ulRet = SPS_DECLINE;
} else { // Take care of the monochrome pointer.
ulRet = SetMonoHwPointerShape(pso, psoMask, psoColor, pxlo, xHot, yHot, x, y, prcl, fl); if (ulRet == SPS_DECLINE) { DISABLE_SPRITE(ppdev); } }
return (ulRet); }
/*****************************************************************************
* DrvSetMonoHwPointerShape - ****************************************************************************/ ULONG SetMonoHwPointerShape( SURFOBJ *pso, SURFOBJ *psoMask, SURFOBJ *psoColor, XLATEOBJ *pxlo, LONG xHot, LONG yHot, LONG x, LONG y, RECTL *prcl, FLONG fl) {
INT i, j, cxMask, cyMask, cyAND, cxAND, cyXOR, cxXOR;
PBYTE pjAND, pjXOR;
INT lDelta;
PPDEV ppdev;
INT ix, iy, is, ip, iBit, jAndByte, jXorByte, jSpriteBits, jSpriteByte;
INT njSpriteBuffer; BOOL bDetectXOR;
BYTE* pjBase;
BYTE ajAndMask[64][8], ajXorMask[64][8];
BYTE ajW32Sprite[1024]; LONG cBpp; INT ndx = 0;
ppdev = (PPDEV) pso->dhpdev; pjBase = ppdev->pjBase; cBpp = ppdev->cBpp;
// The W32 does not handle an XOR and an AND.
// So, set a bool if we need to detect this condition.
bDetectXOR = FALSE; if (ppdev->ulChipID == W32) bDetectXOR = TRUE;
// If the mask is NULL this implies the pointer is not
// visible.
if (psoMask == NULL) { DISABLE_SPRITE(ppdev); 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 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 the 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 (bDetectXOR == TRUE) { if ((jAndByte & iBit) && (jXorByte & iBit)) { return (SPS_DECLINE); } }
if ((ip % 4) == 0) { // 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 != 0) { ajW32Sprite[is++] = (BYTE)jSpriteByte; } jSpriteByte = jSpriteBits; } else { // If the sprite byte is not full, shift the bit pair
// into position, and or it into the sprite byte.
jSpriteBits <<= (ip % 4) * 2; jSpriteByte |= jSpriteBits; }
// bump the bit pair counter.
ip++; } } }
// Flush the last byte.
ajW32Sprite[is++] = (BYTE)jSpriteByte;
// Disable the pointer.
DISABLE_SPRITE(ppdev);
DISPDBG((1,"setting sprite shape at offset (%xh)", ppdev->cjPointerOffset));
if (ppdev->ulChipID == ET6000) { BYTE * pjDst = ppdev->pjScreen + ppdev->cjPointerOffset; BYTE * pjSrc = ajW32Sprite;
for (i = 0; i < 1024; i++) { *pjDst++ = *pjSrc++; } } else { ndx = 0; CP_MMU_BP0(ppdev, pjBase, ppdev->cjPointerOffset); if (cBpp == 1) { for (i = 0; i < 1024; i++) { //*pjSpriteBuffer++ = ajW32Sprite[i];
CP_WRITE_MMU_BYTE(ppdev, 0, ndx, ajW32Sprite[i]); ndx++; } } else if (cBpp == 2) { for (i = 0; i < 64; i++) { for (j = 0; j < 8; j++) { //*pjSpriteBuffer++ = jRepMask2[ajW32Sprite[(16*i)+j] & 0xf];
//*pjSpriteBuffer++ = jRepMask2[ajW32Sprite[(16*i)+j] >> 4];
CP_WRITE_MMU_BYTE(ppdev, 0, ndx, jRepMask2[ajW32Sprite[(16*i)+j] & 0xf]); ndx++; CP_WRITE_MMU_BYTE(ppdev, 0, ndx, jRepMask2[ajW32Sprite[(16*i)+j] >> 4]); ndx++; } } } }
// Set the position of the cursor.
DrvMovePointer(pso, x, y, NULL);
return (SPS_ACCEPT_NOEXCLUDE); }
/******************************Public*Routine******************************\
* VOID vDisablePointer * \**************************************************************************/
VOID vDisablePointer( PDEV* ppdev) { // Nothing to do, really
}
/******************************Public*Routine******************************\
* VOID vAssertModePointer * \**************************************************************************/
VOID vAssertModePointer( PDEV* ppdev, BOOL bEnable) { BYTE* pjBase; ULONG ulPhysicalAddr; INT i, j, nBytesPerBank, njSpriteBuffer, n8kBanks, nRemainingBytes;
if (ppdev->flCaps & CAPS_SW_POINTER) { // With a software pointer, we don't have to do anything.
} else { DISPDBG((1,"vAssertModePointer: cxMemory = %d", ppdev->cxMemory)); DISPDBG((1,"vAssertModePointer: cyMemory = %d", ppdev->cyMemory)); DISPDBG((1,"vAssertModePointer: cxScreen = %d", ppdev->cxScreen)); DISPDBG((1,"vAssertModePointer: cyScreen = %d", ppdev->cyScreen));
pjBase = ppdev->pjBase;
// Take care of the init for the Sprite.
if (ppdev->ulChipID == ET6000) { BYTE * pjDst = ppdev->pjScreen + ppdev->cjPointerOffset;
ET6K_SPRITE_HORZ_POSITION(ppdev, ppdev->cxScreen / 2); // Center it.
ET6K_SPRITE_VERT_POSITION(ppdev, ppdev->cyScreen / 2); // Center it.
ET6K_HORZ_PRESET(ppdev, 0); ET6K_VERT_PRESET(ppdev, 0); ET6K_SPRITE_START_ADDR(ppdev, ppdev->cjPointerOffset); ET6K_SPRITE_COLOR(ppdev, 0xFF00);
for (i = 0; i < 1024; i++) { *pjDst++ = 0xaa; } } else { SET_HORZ_POSITION(ppdev->cxScreen * ppdev->cBpp / 2); SET_VERT_POSITION(ppdev->cyScreen / 2); SET_HORZ_PRESET(0); SET_VERT_PRESET(0);
SET_SPRITE_START_ADDR(ppdev->cjPointerOffset); SET_SPRITE_ROW_OFFSET;
// Set the CRTCB pixel pan register to 0.
OUTP(CRTCB_SPRITE_INDEX, CRTCB_PIXEL_PANNING); OUTP(CRTCB_SPRITE_DATA, 0);
// Set the pixel depth to 2 bits per pixel.
// (even though the doc says this is only for the CRTCB mode and not
// the sprite mode, the doesn't work unless these values are 0.
OUTP(CRTCB_SPRITE_INDEX, CRTCB_COLOR_DEPTH); OUTP(CRTCB_SPRITE_DATA, 0x01);
// Set the CRTCB/Sprite control to a 64 X 64 Sprite in overlay mode.
OUTP(CRTCB_SPRITE_INDEX, CRTCB_SPRITE_CONTROL); OUTP(CRTCB_SPRITE_DATA, 0x02);
// Fill the sprite buffer and the next 17 lines with a transparent
// pattern. This is to get around one of the sprite bugs.
njSpriteBuffer = SPRITE_BUFFER_SIZE;
nBytesPerBank = 0x2000; n8kBanks = njSpriteBuffer / nBytesPerBank; nRemainingBytes = njSpriteBuffer % nBytesPerBank;
for (j = 0; j < n8kBanks; j++) { // First set Aperture 0 to the sprite buffer address.
CP_MMU_BP0(ppdev, pjBase, (ppdev->cjPointerOffset + (j * nBytesPerBank)));
// Reset the linear address to the beginning of this 8K segment
for (i = 0; i < nBytesPerBank; i++) { //*pjSpriteBuffer++ = 0xAA;
CP_WRITE_MMU_BYTE(ppdev, 0, i, 0xAA); } }
// Set Aperture 0 to the sprite buffer address.
CP_MMU_BP0(ppdev, pjBase, (ppdev->cjPointerOffset + (j * nBytesPerBank)));
// Reset the linear address to the beginning of this 8K segment
for (i = 0; i < nRemainingBytes; i++) { //*pjSpriteBuffer++ = 0xAA;
CP_WRITE_MMU_BYTE(ppdev, 0, i, 0xAA); }
} ENABLE_SPRITE(ppdev); } }
/******************************Public*Routine******************************\
* BOOL bEnablePointer * \**************************************************************************/
BOOL bEnablePointer( PDEV* ppdev) { if (ppdev->flCaps & CAPS_SW_POINTER) { // With a software pointer, we don't have to do anything.
} else { // Enable the W32 hardware pointer.
}
// Actually turn on the pointer:
vAssertModePointer(ppdev, TRUE);
DISPDBG((5, "Passed bEnablePointer"));
return(TRUE); }
|