reactos/win32ss/drivers/displays/vga/objects/bitblt.c

518 lines
15 KiB
C

/*
* PROJECT: ReactOS VGA display driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: win32ss/drivers/displays/vga/objects/bitblt.c
* PURPOSE:
* PROGRAMMERS:
*/
#include <vgaddi.h>
#include "bitblt.h"
typedef BOOL (*PFN_VGABlt)(SURFOBJ*, SURFOBJ*, XLATEOBJ*, RECTL*, POINTL*);
typedef BOOL (APIENTRY *PBLTRECTFUNC)(SURFOBJ* OutputObj,
SURFOBJ* InputObj,
SURFOBJ* Mask,
XLATEOBJ* ColorTranslation,
RECTL* OutputRect,
POINTL* InputPoint,
POINTL* MaskOrigin,
BRUSHOBJ* Brush,
POINTL* BrushOrigin,
ROP4 Rop4);
static BOOL FASTCALL VGADDI_IntersectRect(
OUT RECTL* prcDst,
IN RECTL* prcSrc1,
IN RECTL* prcSrc2)
{
static const RECTL rclEmpty = { 0, 0, 0, 0 };
prcDst->left = max(prcSrc1->left, prcSrc2->left);
prcDst->right = min(prcSrc1->right, prcSrc2->right);
if (prcDst->left < prcDst->right)
{
prcDst->top = max(prcSrc1->top, prcSrc2->top);
prcDst->bottom = min(prcSrc1->bottom, prcSrc2->bottom);
if (prcDst->top < prcDst->bottom) return(TRUE);
}
*prcDst = rclEmpty;
return FALSE;
}
void DIB_BltToVGA_Fixed(int x, int y, int w, int h, void *b, int Source_lDelta, int mod);
BOOL
DIBtoVGA(
IN SURFOBJ *Dest,
IN SURFOBJ *Source,
IN XLATEOBJ *ColorTranslation,
IN RECTL *DestRect,
IN POINTL *SourcePoint)
{
LONG dx, dy;
dx = DestRect->right - DestRect->left;
dy = DestRect->bottom - DestRect->top;
if (NULL == ColorTranslation || 0 != (ColorTranslation->flXlate & XO_TRIVIAL))
{
DIB_BltToVGA(DestRect->left, DestRect->top, dx, dy,
(PVOID)((ULONG_PTR)Source->pvScan0 + SourcePoint->y * Source->lDelta + (SourcePoint->x >> 1)),
Source->lDelta, SourcePoint->x % 2);
}
else
{
/* Perform color translation */
DIB_BltToVGAWithXlate(DestRect->left, DestRect->top, dx, dy,
(PVOID)((ULONG_PTR)Source->pvScan0 + SourcePoint->y * Source->lDelta + (SourcePoint->x >> 1)),
Source->lDelta, ColorTranslation);
}
return FALSE;
}
BOOL
VGAtoDIB(
IN SURFOBJ *Dest,
IN SURFOBJ *Source,
IN XLATEOBJ *ColorTranslation,
IN RECTL *DestRect,
IN POINTL *SourcePoint)
{
LONG i, j, dx, dy;
UCHAR *GDIpos, *initial;
/* Used by the temporary DFB */
//DEVSURF DestDevSurf;
/* FIXME: Optimize to retrieve entire bytes at a time (see ../vgavideo/vgavideo.c:vgaGetByte) */
GDIpos = Dest->pvScan0 /* + (DestRect->top * Dest->lDelta) + (DestRect->left >> 1) */ ;
dx = DestRect->right - DestRect->left;
dy = DestRect->bottom - DestRect->top;
if (ColorTranslation == NULL)
{
/* Prepare a Dest Dev Target and copy from the DFB to the DIB */
//DestDevSurf.NextScan = Dest->lDelta;
//DestDevSurf.StartBmp = Dest->pvScan0;
DIB_BltFromVGA(SourcePoint->x, SourcePoint->y, dx, dy, Dest->pvScan0, Dest->lDelta);
}
else
{
/* Color translation */
for (j = SourcePoint->y; j < SourcePoint->y + dy; j++)
{
initial = GDIpos;
for (i = SourcePoint->x; i < SourcePoint->x + dx; i++)
{
*GDIpos = XLATEOBJ_iXlate(ColorTranslation, vgaGetPixel(i, j));
GDIpos++;
}
GDIpos = initial + Dest->lDelta;
}
}
return FALSE;
}
BOOL
DFBtoVGA(
IN SURFOBJ *Dest,
IN SURFOBJ *Source,
IN XLATEOBJ *ColorTranslation,
IN RECTL *DestRect,
IN POINTL *SourcePoint)
{
/* Do DFBs need color translation?? */
return FALSE;
}
BOOL
VGAtoDFB(
IN SURFOBJ *Dest,
IN SURFOBJ *Source,
IN XLATEOBJ *ColorTranslation,
IN RECTL *DestRect,
IN POINTL *SourcePoint)
{
/* Do DFBs need color translation?? */
return FALSE;
}
BOOL
VGAtoVGA(
IN SURFOBJ *Dest,
IN SURFOBJ *Source,
IN XLATEOBJ *ColorTranslation,
IN RECTL *DestRect,
IN POINTL *SourcePoint)
{
LONG i, i2, j, dx, dy, alterx, altery;
static char buf[SCREEN_X];
/* Calculate deltas */
dx = DestRect->right - DestRect->left;
dy = DestRect->bottom - DestRect->top;
alterx = DestRect->left - SourcePoint->x;
altery = DestRect->top - SourcePoint->y;
i = SourcePoint->x;
i2 = i + alterx;
if (SourcePoint->y >= DestRect->top)
{
for (j = SourcePoint->y; j < SourcePoint->y + dy; j++)
{
LONG j2 = j + altery;
vgaReadScan ( i, j, dx, buf );
vgaWriteScan ( i2, j2, dx, buf );
}
}
else
{
for(j = (SourcePoint->y + dy - 1); j >= SourcePoint->y; j--)
{
LONG j2 = j + altery;
vgaReadScan ( i, j, dx, buf );
vgaWriteScan ( i2, j2, dx, buf );
}
}
return TRUE;
}
BOOL APIENTRY
VGADDI_BltBrush(
IN SURFOBJ* Dest,
IN SURFOBJ* Source,
IN SURFOBJ* MaskSurf,
IN XLATEOBJ* ColorTranslation,
IN RECTL* DestRect,
IN POINTL* SourcePoint,
IN POINTL* MaskPoint,
IN BRUSHOBJ* Brush,
IN POINTL* BrushPoint,
IN ROP4 Rop4)
{
UCHAR SolidColor = 0;
LONG Left;
LONG Length;
PUCHAR Video;
UCHAR Mask;
INT i, j;
ULONG RasterOp = VGA_NORMAL;
/* Punt brush blts to non-device surfaces. */
if (Dest->iType != STYPE_DEVICE)
return FALSE;
/* Punt pattern fills. */
if ((GET_OPINDEX_FROM_ROP4(Rop4) == GET_OPINDEX_FROM_ROP3(PATCOPY)
|| GET_OPINDEX_FROM_ROP4(Rop4) == GET_OPINDEX_FROM_ROP3(PATINVERT)) &&
Brush->iSolidColor == 0xFFFFFFFF)
{
return FALSE;
}
/* Get the brush colour. */
switch (GET_OPINDEX_FROM_ROP4(Rop4))
{
case GET_OPINDEX_FROM_ROP3(PATCOPY): SolidColor = Brush->iSolidColor; break;
case GET_OPINDEX_FROM_ROP3(PATINVERT): SolidColor = Brush->iSolidColor; RasterOp = VGA_XOR; break;
case GET_OPINDEX_FROM_ROP3(WHITENESS): SolidColor = 0xF; break;
case GET_OPINDEX_FROM_ROP3(BLACKNESS): SolidColor = 0x0; break;
case GET_OPINDEX_FROM_ROP3(DSTINVERT): SolidColor = 0xF; RasterOp = VGA_XOR; break;
}
/* Select write mode 3. */
WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x05);
WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x03);
/* Setup set/reset register. */
WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x00);
WRITE_PORT_UCHAR((PUCHAR)GRA_D, (UCHAR)SolidColor);
/* Enable writes to all pixels. */
WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x08);
WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0xFF);
/* Set up data rotate. */
WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x03);
WRITE_PORT_UCHAR((PUCHAR)GRA_D, RasterOp);
/* Fill any pixels on the left which don't fall into a full row of eight. */
if ((DestRect->left % 8) != 0)
{
/* Disable writes to pixels outside of the destination rectangle. */
Mask = (1 << (8 - (DestRect->left % 8))) - 1;
if ((DestRect->right - DestRect->left) < (8 - (DestRect->left % 8)))
Mask &= ~((1 << (8 - (DestRect->right % 8))) - 1);
/* Write the same color to each pixel. */
Video = (PUCHAR)vidmem + DestRect->top * 80 + (DestRect->left >> 3);
for (i = DestRect->top; i < DestRect->bottom; i++, Video += 80)
{
(VOID)READ_REGISTER_UCHAR(Video);
WRITE_REGISTER_UCHAR(Video, Mask);
}
/* Have we finished. */
if ((DestRect->right - DestRect->left) < (8 - (DestRect->left % 8)))
{
/* Restore write mode 2. */
WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x05);
WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x02);
/* Set up data rotate. */
WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x03);
WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x00);
return TRUE;
}
}
/* Fill any whole rows of eight pixels. */
Left = (DestRect->left + 7) & ~0x7;
Length = (DestRect->right >> 3) - (Left >> 3);
for (i = DestRect->top; i < DestRect->bottom; i++)
{
Video = (PUCHAR)vidmem + i * 80 + (Left >> 3);
for (j = 0; j < Length; j++, Video++)
{
#if 0
(VOID)READ_REGISTER_UCHAR(Video);
WRITE_REGISTER_UCHAR(Video, 0xFF);
#else
char volatile Temp = *Video;
Temp |= 0;
*Video = 0xFF;
#endif
}
}
/* Fill any pixels on the right which don't fall into a complete row. */
if ((DestRect->right % 8) != 0)
{
/* Disable writes to pixels outside the destination rectangle. */
Mask = ~((1 << (8 - (DestRect->right % 8))) - 1);
Video = (PUCHAR)vidmem + DestRect->top * 80 + (DestRect->right >> 3);
for (i = DestRect->top; i < DestRect->bottom; i++, Video += 80)
{
(VOID)READ_REGISTER_UCHAR(Video);
WRITE_REGISTER_UCHAR(Video, Mask);
}
}
/* Restore write mode 2. */
WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x05);
WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x02);
/* Set up data rotate. */
WRITE_PORT_UCHAR((PUCHAR)GRA_I, 0x03);
WRITE_PORT_UCHAR((PUCHAR)GRA_D, 0x00);
return TRUE;
}
BOOL APIENTRY
VGADDI_BltSrc(
IN SURFOBJ* Dest,
IN SURFOBJ* Source,
IN SURFOBJ* Mask,
IN XLATEOBJ* ColorTranslation,
IN RECTL* DestRect,
IN POINTL* SourcePoint,
IN POINTL* MaskOrigin,
IN BRUSHOBJ* Brush,
IN POINTL* BrushOrigin,
IN ROP4 Rop4)
{
PFN_VGABlt BltOperation;
ULONG SourceType;
SourceType = Source->iType;
if (SourceType == STYPE_BITMAP && Dest->iType == STYPE_DEVICE)
BltOperation = DIBtoVGA;
else if (SourceType == STYPE_DEVICE && Dest->iType == STYPE_BITMAP)
BltOperation = VGAtoDIB;
else if (SourceType == STYPE_DEVICE && Dest->iType == STYPE_DEVICE)
BltOperation = VGAtoVGA;
else if (SourceType == STYPE_DEVBITMAP && Dest->iType == STYPE_DEVICE)
BltOperation = DFBtoVGA;
else if (SourceType == STYPE_DEVICE && Dest->iType == STYPE_DEVBITMAP)
BltOperation = VGAtoDFB;
else
{
/* Punt blts not involving a device or a device-bitmap. */
return FALSE;
}
BltOperation(Dest, Source, ColorTranslation, DestRect, SourcePoint);
return TRUE;
}
BOOL APIENTRY
VGADDI_BltMask(
IN SURFOBJ* Dest,
IN SURFOBJ* Source,
IN SURFOBJ* Mask,
IN XLATEOBJ* ColorTranslation,
IN RECTL* DestRect,
IN POINTL* SourcePoint,
IN POINTL* MaskPoint,
IN BRUSHOBJ* Brush,
IN POINTL* BrushPoint,
IN ROP4 Rop4)
{
LONG i, j, dx, dy, c8;
BYTE *tMask, *lMask;
dx = DestRect->right - DestRect->left;
dy = DestRect->bottom - DestRect->top;
if (ColorTranslation == NULL)
{
if (Mask != NULL)
{
tMask = Mask->pvScan0;
for (j = 0; j < dy; j++)
{
lMask = tMask;
c8 = 0;
for (i = 0; i < dx; i++)
{
if((*lMask & maskbit[c8]) != 0)
vgaPutPixel(DestRect->left + i, DestRect->top + j, Brush->iSolidColor);
c8++;
if(c8 == 8)
{
lMask++;
c8=0;
}
}
tMask += Mask->lDelta;
}
}
}
return TRUE;
}
BOOL APIENTRY
DrvBitBlt(
IN SURFOBJ *Dest,
IN SURFOBJ *Source,
IN SURFOBJ *Mask,
IN CLIPOBJ *Clip,
IN XLATEOBJ *ColorTranslation,
IN RECTL *DestRect,
IN POINTL *SourcePoint,
IN POINTL *MaskPoint,
IN BRUSHOBJ *Brush,
IN POINTL *BrushPoint,
IN ROP4 rop4)
{
PBLTRECTFUNC BltRectFunc;
RECTL CombinedRect;
BOOL Ret = FALSE;
RECT_ENUM RectEnum;
BOOL EnumMore;
UINT i;
POINTL Pt;
ULONG Direction;
POINTL FinalSourcePoint;
if (Source && SourcePoint)
{
FinalSourcePoint.x = SourcePoint->x;
FinalSourcePoint.y = SourcePoint->y;
}
else
{
FinalSourcePoint.x = 0;
FinalSourcePoint.y = 0;
}
switch (rop4)
{
case ROP3_TO_ROP4(BLACKNESS):
case ROP3_TO_ROP4(PATCOPY):
case ROP3_TO_ROP4(WHITENESS):
case ROP3_TO_ROP4(PATINVERT):
case ROP3_TO_ROP4(DSTINVERT):
BltRectFunc = VGADDI_BltBrush;
break;
case ROP3_TO_ROP4(SRCCOPY):
if (BMF_4BPP == Source->iBitmapFormat && BMF_4BPP == Dest->iBitmapFormat)
BltRectFunc = VGADDI_BltSrc;
else
return FALSE;
break;
case R4_MASK:
BltRectFunc = VGADDI_BltMask;
break;
default:
return FALSE;
}
switch (NULL == Clip ? DC_TRIVIAL : Clip->iDComplexity)
{
case DC_TRIVIAL:
Ret = (*BltRectFunc)(Dest, Source, Mask, ColorTranslation, DestRect,
SourcePoint, MaskPoint, Brush, BrushPoint,
rop4);
break;
case DC_RECT:
/* Clip the blt to the clip rectangle */
VGADDI_IntersectRect(&CombinedRect, DestRect, &(Clip->rclBounds));
Pt.x = FinalSourcePoint.x + CombinedRect.left - DestRect->left;
Pt.y = FinalSourcePoint.y + CombinedRect.top - DestRect->top;
Ret = (*BltRectFunc)(Dest, Source, Mask, ColorTranslation, &CombinedRect,
&Pt, MaskPoint, Brush, BrushPoint,
rop4);
break;
case DC_COMPLEX:
Ret = TRUE;
if (Dest == Source)
{
if (DestRect->top <= FinalSourcePoint.y)
Direction = DestRect->left < FinalSourcePoint.y ? CD_RIGHTDOWN : CD_LEFTDOWN;
else
Direction = DestRect->left < FinalSourcePoint.x ? CD_RIGHTUP : CD_LEFTUP;
}
else
{
Direction = CD_ANY;
}
CLIPOBJ_cEnumStart(Clip, FALSE, CT_RECTANGLES, Direction, 0);
do
{
EnumMore = CLIPOBJ_bEnum(Clip, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
for (i = 0; i < RectEnum.c; i++)
{
VGADDI_IntersectRect(&CombinedRect, DestRect, RectEnum.arcl + i);
Pt.x = FinalSourcePoint.x + CombinedRect.left - DestRect->left;
Pt.y = FinalSourcePoint.y + CombinedRect.top - DestRect->top;
Ret = (*BltRectFunc)(Dest, Source, Mask, ColorTranslation, &CombinedRect,
&Pt, MaskPoint, Brush, BrushPoint, rop4) &&
Ret;
}
} while (EnumMore);
break;
}
return Ret;
}