1574 lines
43 KiB
C++
1574 lines
43 KiB
C++
/**************************************************************************\
|
|
*
|
|
* Copyright (c) 1998 Microsoft Corporation
|
|
*
|
|
* Module Name:
|
|
*
|
|
* TextureFill.cpp
|
|
*
|
|
* Abstract:
|
|
*
|
|
* texture fill routines.
|
|
*
|
|
* Revision History:
|
|
*
|
|
* 01/21/1999 ikkof
|
|
* Created it.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.hpp"
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Initializes the fixed point variables needed for texture mapping.
|
|
*
|
|
* Created:
|
|
*
|
|
* 03/14/2000 andrewgo
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
DpOutputBilinearSpan_MMX::InitializeFixedPointState()
|
|
{
|
|
// If the numbers are too large for 16.16 fixed, we'll do the computation
|
|
// in floating-point, per call to OutputSpan:
|
|
|
|
ScaleMatrixValid = GpValidFixed16(DeviceToWorld.GetM11()) &&
|
|
GpValidFixed16(DeviceToWorld.GetM12()) &&
|
|
GpValidFixed16(DeviceToWorld.GetM21()) &&
|
|
GpValidFixed16(DeviceToWorld.GetM22());
|
|
|
|
if (ScaleMatrixValid)
|
|
{
|
|
GpPointF vector(1.0f, 0.0f);
|
|
DeviceToWorld.VectorTransform(&vector);
|
|
UIncrement = GpRound(vector.X * (1L << 16));
|
|
VIncrement = GpRound(vector.Y * (1L << 16));
|
|
|
|
TranslateMatrixValid = GpValidFixed16(DeviceToWorld.GetDx()) &&
|
|
GpValidFixed16(DeviceToWorld.GetDy());
|
|
|
|
if (TranslateMatrixValid)
|
|
{
|
|
M11 = GpRound(DeviceToWorld.GetM11() * (1L << 16));
|
|
M12 = GpRound(DeviceToWorld.GetM12() * (1L << 16));
|
|
M21 = GpRound(DeviceToWorld.GetM21() * (1L << 16));
|
|
M22 = GpRound(DeviceToWorld.GetM22() * (1L << 16));
|
|
Dx = GpRound(DeviceToWorld.GetDx() * (1L << 16));
|
|
Dy = GpRound(DeviceToWorld.GetDy() * (1L << 16));
|
|
}
|
|
|
|
ModulusWidth = (BmpData.Width << 16);
|
|
ModulusHeight = (BmpData.Height << 16);
|
|
|
|
// When the u,v coordinates have the pixel in the last row or column
|
|
// of the texture space, the offset of the pixel to the right and the
|
|
// pixel below (for bilinear filtering) is the following (for tile modes)
|
|
// because they wrap around the texture space.
|
|
|
|
// The XEdgeIncrement is the byte increment of the pixel to the right of
|
|
// the pixel on the far right hand column of the texture. In tile mode,
|
|
// we want the pixel on the same scanline, but in the first column of the
|
|
// texture hence 4bytes - stride
|
|
|
|
XEdgeIncrement = 4-BmpData.Stride;
|
|
|
|
// The YEdgeIncrement is the byte increment of the pixel below the current
|
|
// pixel when the current pixel is in the last scanline of the texture.
|
|
// In tile mode the correct pixel is the one directly above this one in
|
|
// the first scanline - hence the increment below:
|
|
|
|
YEdgeIncrement = -(INT)(BmpData.Height-1)*(INT)(BmpData.Stride);
|
|
|
|
if ((BilinearWrapMode == WrapModeTileFlipX) ||
|
|
(BilinearWrapMode == WrapModeTileFlipXY))
|
|
{
|
|
ModulusWidth *= 2;
|
|
|
|
// Wrap increment is zero for Flip mode
|
|
|
|
XEdgeIncrement = 0;
|
|
}
|
|
if ((BilinearWrapMode == WrapModeTileFlipY) ||
|
|
(BilinearWrapMode == WrapModeTileFlipXY))
|
|
{
|
|
ModulusHeight *= 2;
|
|
|
|
// Wrap increment is zero for Flip mode
|
|
|
|
YEdgeIncrement = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Texture brush constructor.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Created:
|
|
*
|
|
* 04/26/1999 ikkof
|
|
*
|
|
\**************************************************************************/
|
|
|
|
DpOutputBilinearSpan::DpOutputBilinearSpan(
|
|
const GpTexture *textureBrush,
|
|
DpScanBuffer *scan,
|
|
GpMatrix *worldToDevice,
|
|
DpContext *context
|
|
)
|
|
{
|
|
ASSERT(textureBrush);
|
|
|
|
dBitmap = NULL;
|
|
Scan = scan;
|
|
|
|
// Initialize the wrap state.
|
|
|
|
BilinearWrapMode = textureBrush->GetWrapMode();
|
|
ClampColor = 0;
|
|
SrcRectClamp = FALSE;
|
|
|
|
if(textureBrush->GetImageType() != ImageTypeBitmap)
|
|
{
|
|
// Currently, Metafile is not implemented yet.
|
|
|
|
Bitmap = NULL;
|
|
return;
|
|
}
|
|
|
|
Bitmap = textureBrush->GetBitmap();
|
|
|
|
// on bad bitmap, we return with Valid = FALSE
|
|
if (Bitmap == NULL ||
|
|
!Bitmap->IsValid() ||
|
|
Bitmap->LockBits(
|
|
NULL,
|
|
IMGLOCK_READ,
|
|
PixelFormat32bppPARGB,
|
|
&BmpData
|
|
) != Ok)
|
|
{
|
|
Bitmap = NULL;
|
|
return;
|
|
}
|
|
|
|
Size size;
|
|
Bitmap->GetSize(&size);
|
|
|
|
SrcRect.X = SrcRect.Y = 0;
|
|
SrcRect.Width = (REAL)size.Width;
|
|
SrcRect.Height = (REAL)size.Height;
|
|
WorldToDevice = *worldToDevice;
|
|
|
|
// If we have a PixelOffset of Half then offset the srcRect by -0.5
|
|
// need to change the WorldToDevice to take this into account.
|
|
// We need to do this here because texture brushes don't have enough
|
|
// information to handle the PixelOffset at a higher level. We construct
|
|
// the SrcRect here, so we apply the PixelOffset immediately.
|
|
|
|
if (context->PixelOffset == PixelOffsetModeHalf ||
|
|
context->PixelOffset == PixelOffsetModeHighQuality)
|
|
{
|
|
SrcRect.Offset(-0.5f, -0.5f);
|
|
WorldToDevice.Translate(0.5f, 0.5f, MatrixOrderPrepend);
|
|
}
|
|
|
|
if(WorldToDevice.IsInvertible())
|
|
{
|
|
// !!![andrewgo] This failure case is bad, we will fall over
|
|
// later with an uninitialized DeviceToWorld.
|
|
|
|
DeviceToWorld = WorldToDevice;
|
|
DeviceToWorld.Invert();
|
|
}
|
|
}
|
|
|
|
DpOutputBilinearSpan::DpOutputBilinearSpan(
|
|
const DpBitmap *bitmap,
|
|
DpScanBuffer *scan,
|
|
GpMatrix *worldToDevice,
|
|
DpContext *context,
|
|
DpImageAttributes *imageAttributes
|
|
)
|
|
{
|
|
ASSERT(bitmap);
|
|
|
|
dBitmap = bitmap;
|
|
Scan = scan;
|
|
|
|
// Set the imageAttributes state that's relevant to the bilinear span.
|
|
|
|
BilinearWrapMode = imageAttributes->wrapMode;
|
|
ClampColor = imageAttributes->clampColor;
|
|
SrcRectClamp = imageAttributes->srcRectClamp;
|
|
|
|
Bitmap = NULL;
|
|
|
|
// on bad bitmap, we return with Valid = FALSE
|
|
if (dBitmap == NULL || !dBitmap->IsValid() )
|
|
{
|
|
dBitmap = NULL;
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
BmpData.Width = dBitmap->Width;
|
|
BmpData.Height = dBitmap->Height;
|
|
BmpData.PixelFormat = PIXFMT_32BPP_PARGB;
|
|
BmpData.Stride = dBitmap->Delta;
|
|
BmpData.Scan0 = dBitmap->Bits;
|
|
}
|
|
|
|
// NOTE: SrcRect is not used.
|
|
// The HalfPixelOffset is already incorporated into the
|
|
// wordToDevice matrix passed in - which is not the same matrix as
|
|
// context->WorldToDevice
|
|
|
|
SrcRect.X = 0;
|
|
SrcRect.Y = 0;
|
|
SrcRect.Width = (REAL)dBitmap->Width;
|
|
SrcRect.Height = (REAL)dBitmap->Height;
|
|
|
|
WorldToDevice = *worldToDevice;
|
|
|
|
if(WorldToDevice.IsInvertible())
|
|
{
|
|
// !!![andrewgo] This failure case is bad, we will fall over
|
|
// later with an uninitialized DeviceToWorld.
|
|
|
|
DeviceToWorld = WorldToDevice;
|
|
DeviceToWorld.Invert();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Texture brush constructor.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Created:
|
|
*
|
|
* 04/26/1999 ikkof
|
|
*
|
|
\**************************************************************************/
|
|
|
|
DpOutputBilinearSpan::DpOutputBilinearSpan(
|
|
DpBitmap* bitmap,
|
|
DpScanBuffer * scan,
|
|
DpContext* context,
|
|
DpImageAttributes imageAttributes,
|
|
INT numPoints,
|
|
const GpPointF *dstPoints,
|
|
const GpRectF *srcRect
|
|
)
|
|
{
|
|
// NOTE: This constructor is not used.
|
|
// I have no idea if it even works anymore.
|
|
|
|
WARNING(("DpOutputBilinearSpan: unsupported constructor"));
|
|
|
|
Scan = scan;
|
|
BilinearWrapMode = imageAttributes.wrapMode;
|
|
ClampColor = imageAttributes.clampColor;
|
|
SrcRectClamp = imageAttributes.srcRectClamp;
|
|
dBitmap = bitmap;
|
|
Bitmap = NULL;
|
|
|
|
// on bad bitmap, we return with Valid = FALSE
|
|
if (dBitmap == NULL || !dBitmap->IsValid() )
|
|
{
|
|
dBitmap = NULL;
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
BmpData.Width = dBitmap->Width;
|
|
BmpData.Height = dBitmap->Height;
|
|
BmpData.PixelFormat = PIXFMT_32BPP_PARGB;
|
|
BmpData.Stride = dBitmap->Delta;
|
|
BmpData.Scan0 = dBitmap->Bits;
|
|
}
|
|
|
|
WorldToDevice = context->WorldToDevice;
|
|
context->GetDeviceToWorld(&DeviceToWorld);
|
|
|
|
// If we have a srcRect then it's already taking the PixelOffset mode into
|
|
// account.
|
|
if(srcRect)
|
|
SrcRect = *srcRect;
|
|
else
|
|
{
|
|
SrcRect.X = 0;
|
|
SrcRect.Y = 0;
|
|
SrcRect.Width = (REAL)dBitmap->Width;
|
|
SrcRect.Height = (REAL)dBitmap->Height;
|
|
if (context->PixelOffset == PixelOffsetModeHalf ||
|
|
context->PixelOffset == PixelOffsetModeHighQuality)
|
|
{
|
|
SrcRect.Offset(-0.5f, -0.5f);
|
|
}
|
|
}
|
|
|
|
GpPointF points[4];
|
|
|
|
GpMatrix xForm;
|
|
BOOL existsTransform = TRUE;
|
|
|
|
switch(numPoints)
|
|
{
|
|
case 0:
|
|
points[0].X = 0;
|
|
points[0].Y = 0;
|
|
points[1].X = (REAL) SrcRect.Width;
|
|
points[1].Y = 0;
|
|
points[2].X = 0;
|
|
points[2].Y = (REAL) SrcRect.Height;
|
|
break;
|
|
|
|
case 1:
|
|
points[0] = dstPoints[0];
|
|
points[1].X = (REAL) (points[0].X + SrcRect.Width);
|
|
points[1].Y = points[0].Y;
|
|
points[2].X = points[0].X;
|
|
points[2].Y = (REAL) (points[0].Y + SrcRect.Height);
|
|
break;
|
|
|
|
case 3:
|
|
case 4:
|
|
GpMemcpy(&points[0], dstPoints, numPoints*sizeof(GpPointF));
|
|
break;
|
|
|
|
default:
|
|
existsTransform = FALSE;
|
|
}
|
|
|
|
if(existsTransform)
|
|
{
|
|
xForm.InferAffineMatrix(points, SrcRect);
|
|
}
|
|
|
|
WorldToDevice = context->WorldToDevice;
|
|
WorldToDevice.Prepend(xForm);
|
|
if(WorldToDevice.IsInvertible())
|
|
{
|
|
DeviceToWorld = WorldToDevice;
|
|
DeviceToWorld.Invert();
|
|
}
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* From the ARGB value of the four corners, this returns
|
|
* the bilinearly interpolated ARGB value.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] colors - ARGB values at the four corners.
|
|
* [IN] xFrac - the fractional value of the x-coordinates.
|
|
* [IN] yFrac - the fractional value of the y-coordinates.
|
|
* [IN] one, shift. half2, shift2 - the extra arguments used in the
|
|
* calculations.
|
|
*
|
|
* Return Value:
|
|
*
|
|
* ARGB: returns the biliearly interpolated ARGB.
|
|
*
|
|
* Created:
|
|
*
|
|
* 04/26/1999 ikkof
|
|
*
|
|
\**************************************************************************/
|
|
|
|
inline ARGB
|
|
getBilinearFilteredARGB(
|
|
ARGB* colors,
|
|
INT xFrac,
|
|
INT yFrac,
|
|
INT one,
|
|
INT shift,
|
|
INT half2,
|
|
INT shift2)
|
|
{
|
|
INT a[4], r[4], g[4], b[4];
|
|
INT alpha, red, green, blue;
|
|
|
|
for(INT k = 0; k < 4; k++)
|
|
{
|
|
ARGB c = colors[k];
|
|
a[k] = GpColor::GetAlphaARGB(c);
|
|
r[k] = GpColor::GetRedARGB(c);
|
|
g[k] = GpColor::GetGreenARGB(c);
|
|
b[k] = GpColor::GetBlueARGB(c);
|
|
}
|
|
|
|
alpha =
|
|
(
|
|
(one - yFrac)*((a[0] << shift)
|
|
+ (a[1] - a[0])*xFrac)
|
|
+ yFrac*((a[2] << shift)
|
|
+ (a[3] - a[2])*xFrac)
|
|
+ half2
|
|
) >> shift2;
|
|
red =
|
|
(
|
|
(one - yFrac)*((r[0] << shift)
|
|
+ (r[1] - r[0])*xFrac)
|
|
+ yFrac*((r[2] << shift)
|
|
+ (r[3] - r[2])*xFrac)
|
|
+ half2
|
|
) >> shift2;
|
|
green =
|
|
(
|
|
(one - yFrac)*((g[0] << shift)
|
|
+ (g[1] - g[0])*xFrac)
|
|
+ yFrac*((g[2] << shift)
|
|
+ (g[3] - g[2])*xFrac)
|
|
+ half2
|
|
) >> shift2;
|
|
blue =
|
|
(
|
|
(one - yFrac)*((b[0] << shift)
|
|
+ (b[1] - b[0])*xFrac)
|
|
+ yFrac*((b[2] << shift)
|
|
+ (b[3] - b[2])*xFrac)
|
|
+ half2
|
|
) >> shift2;
|
|
|
|
return GpColor::MakeARGB
|
|
(
|
|
(BYTE) alpha,
|
|
(BYTE) red,
|
|
(BYTE) green,
|
|
(BYTE) blue
|
|
);
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
* virtual destructor for DpOutputBilinearSpan
|
|
*
|
|
\**************************************************************************/
|
|
|
|
DpOutputBilinearSpan::~DpOutputBilinearSpan()
|
|
{
|
|
if (Bitmap != NULL)
|
|
{
|
|
Bitmap->UnlockBits(&BmpData);
|
|
}
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Applies the correct wrap mode to a set of coordinates
|
|
*
|
|
* Created:
|
|
*
|
|
* 03/10/2000 asecchia
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void ApplyWrapMode(INT WrapMode, INT &x, INT &y, INT w, INT h)
|
|
{
|
|
INT xm, ym;
|
|
switch(WrapMode) {
|
|
case WrapModeTile:
|
|
x = RemainderI(x, w);
|
|
y = RemainderI(y, h);
|
|
break;
|
|
case WrapModeTileFlipX:
|
|
xm = RemainderI(x, w);
|
|
if(((x-xm)/w) & 1) {
|
|
x = w-1-xm;
|
|
}
|
|
else
|
|
{
|
|
x = xm;
|
|
}
|
|
y = RemainderI(y, h);
|
|
break;
|
|
case WrapModeTileFlipY:
|
|
x = RemainderI(x, w);
|
|
ym = RemainderI(y, h);
|
|
if(((y-ym)/h) & 1) {
|
|
y = h-1-ym;
|
|
}
|
|
else
|
|
{
|
|
y = ym;
|
|
}
|
|
break;
|
|
case WrapModeTileFlipXY:
|
|
xm = RemainderI(x, w);
|
|
if(((x-xm)/w) & 1) {
|
|
x = w-1-xm;
|
|
}
|
|
else
|
|
{
|
|
x = xm;
|
|
}
|
|
ym = RemainderI(y, h);
|
|
if(((y-ym)/h) & 1) {
|
|
y = h-1-ym;
|
|
}
|
|
else
|
|
{
|
|
y = ym;
|
|
}
|
|
break;
|
|
/*
|
|
// WrapModeExtrapolate is no longer used.
|
|
|
|
case WrapModeExtrapolate:
|
|
// Clamp the coordinates to the edge pixels of the source
|
|
if(x<0) x=0;
|
|
if(x>w-1) x=w-1;
|
|
if(y<0) y=0;
|
|
if(y>h-1) y=h-1;
|
|
break;
|
|
*/
|
|
case WrapModeClamp:
|
|
// Don't do anything - the filter code will substitute the clamp
|
|
// color when it detects clamp.
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Outputs a single span within a raster with a texture.
|
|
* Is called by the rasterizer.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] y - the Y value of the raster being output
|
|
* [IN] leftEdge - the DDA class of the left edge
|
|
* [IN] rightEdge - the DDA class of the right edge
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok
|
|
*
|
|
* Created:
|
|
*
|
|
* 01/21/1999 ikkof
|
|
*
|
|
\**************************************************************************/
|
|
|
|
GpStatus
|
|
DpOutputBilinearSpan::OutputSpan(
|
|
INT y,
|
|
INT xMin,
|
|
INT xMax // xMax is exclusive
|
|
)
|
|
{
|
|
// Nothing to do.
|
|
|
|
if(xMin==xMax)
|
|
{
|
|
return Ok;
|
|
}
|
|
|
|
ASSERT(xMin < xMax);
|
|
|
|
ARGB argb;
|
|
INT width = xMax - xMin;
|
|
ARGB * buffer = Scan->NextBuffer(xMin, y, width);
|
|
|
|
GpPointF pt1, pt2;
|
|
pt1.X = (REAL) xMin;
|
|
pt1.Y = pt2.Y = (REAL) y;
|
|
pt2.X = (REAL) xMax;
|
|
|
|
DeviceToWorld.Transform(&pt1);
|
|
DeviceToWorld.Transform(&pt2);
|
|
|
|
ARGB *srcPtr0 = static_cast<ARGB*> (BmpData.Scan0);
|
|
INT stride = BmpData.Stride/sizeof(ARGB);
|
|
INT i;
|
|
|
|
REAL dx, dy, x0, y0;
|
|
INT ix, iy;
|
|
|
|
x0 = pt1.X;
|
|
y0 = pt1.Y;
|
|
|
|
ASSERT(width > 0);
|
|
dx = (pt2.X - pt1.X)/width;
|
|
dy = (pt2.Y - pt1.Y)/width;
|
|
|
|
// Filtered image stretch.
|
|
|
|
ARGB *srcPtr1, *srcPtr2;
|
|
INT shift = 11; // (2*shift + 8 < 32 bits --> shift < 12)
|
|
INT shift2 = shift + shift;
|
|
INT one = 1 << shift;
|
|
INT half2 = 1 << (shift2 - 1);
|
|
INT xFrac, yFrac;
|
|
REAL real;
|
|
ARGB colors[4];
|
|
|
|
INT x1, y1, x2, y2;
|
|
for(i = 0; i < width; i++)
|
|
{
|
|
iy = GpFloor(y0);
|
|
ix = GpFloor(x0);
|
|
xFrac = GpRound((x0 - ix)*one);
|
|
yFrac = GpRound((y0 - iy)*one);
|
|
|
|
x1=ix;
|
|
x2=ix+1;
|
|
y1=iy;
|
|
y2=iy+1;
|
|
|
|
if( ((UINT)ix >= (UINT)(BmpData.Width-1) ) ||
|
|
((UINT)iy >= (UINT)(BmpData.Height-1)) )
|
|
{
|
|
ApplyWrapMode(BilinearWrapMode, x1, y1, BmpData.Width, BmpData.Height);
|
|
ApplyWrapMode(BilinearWrapMode, x2, y2, BmpData.Width, BmpData.Height);
|
|
}
|
|
|
|
if(y1 >= 0 && y1 < (INT) BmpData.Height)
|
|
{
|
|
srcPtr1 = srcPtr0 + stride*y1;
|
|
}
|
|
else
|
|
{
|
|
srcPtr1 = NULL;
|
|
}
|
|
|
|
if(y2 >= 0 && y2 < (INT) BmpData.Height)
|
|
{
|
|
srcPtr2 = srcPtr0 + stride*y2;
|
|
}
|
|
else
|
|
{
|
|
srcPtr2 = NULL;
|
|
}
|
|
|
|
if(x1 >= 0 && x1 < (INT) BmpData.Width)
|
|
{
|
|
if(srcPtr1)
|
|
{
|
|
colors[0] = *(srcPtr1 + x1);
|
|
}
|
|
else
|
|
{
|
|
colors[0] = ClampColor;
|
|
}
|
|
|
|
if(srcPtr2)
|
|
{
|
|
colors[2] = *(srcPtr2 + x1);
|
|
}
|
|
else
|
|
{
|
|
colors[2] = ClampColor;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
colors[0] = ClampColor;
|
|
colors[2] = ClampColor;
|
|
}
|
|
|
|
if(x2 >= 0 && x2 < (INT) BmpData.Width)
|
|
{
|
|
if(srcPtr1)
|
|
{
|
|
colors[1] = *(srcPtr1 + x2);
|
|
}
|
|
else
|
|
{
|
|
colors[1] = ClampColor;
|
|
}
|
|
|
|
if(srcPtr2)
|
|
{
|
|
colors[3] = *(srcPtr2 + x2);
|
|
}
|
|
else
|
|
{
|
|
colors[3] = ClampColor;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
colors[1] = ClampColor;
|
|
colors[3] = ClampColor;
|
|
}
|
|
|
|
if((x2 >= 0) &&
|
|
(x1 < (INT) BmpData.Width) &&
|
|
(y2 >= 0) &&
|
|
(y1 < (INT) BmpData.Height))
|
|
{
|
|
*buffer++ = ::getBilinearFilteredARGB(
|
|
colors,
|
|
xFrac,
|
|
yFrac,
|
|
one,
|
|
shift,
|
|
half2,
|
|
shift2
|
|
);
|
|
}
|
|
else
|
|
{
|
|
*buffer++ = ClampColor;
|
|
}
|
|
|
|
x0 += dx;
|
|
y0 += dy;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Handles bilinear texture drawing with arbitrary rotation using MMX.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] y - the Y value of the raster being output
|
|
* [IN] leftEdge - the DDA class of the left edge
|
|
* [IN] rightEdge - the DDA class of the right edge
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok
|
|
*
|
|
* Created:
|
|
*
|
|
* 01/06/2000 andrewgo
|
|
*
|
|
\**************************************************************************/
|
|
|
|
GpStatus
|
|
DpOutputBilinearSpan_MMX::OutputSpan(
|
|
INT y,
|
|
INT xMin,
|
|
INT xMax // xMax is exclusive
|
|
)
|
|
{
|
|
// Be a little paranoid in checking some state.
|
|
|
|
ASSERT((((ULONG_PTR) BmpData.Scan0) & 3) == 0);
|
|
ASSERT((BmpData.Stride & 3) == 0);
|
|
ASSERT(xMax > xMin);
|
|
|
|
#if defined(_X86_)
|
|
|
|
INT count = xMax - xMin;
|
|
ARGB *buffer = Scan->NextBuffer(xMin, y, count);
|
|
|
|
// Transform an array of points using the matrix v' = v M:
|
|
//
|
|
// ( M11 M12 0 )
|
|
// (vx', vy', 1) = (vx, vy, 1) ( M21 M22 0 )
|
|
// ( dx dy 1 )
|
|
//
|
|
// All (u, v) calculations are done in 16.16 fixed point.
|
|
|
|
INT u;
|
|
INT v;
|
|
|
|
// If the values were out of range for fixed point, compute u and v in
|
|
// floating-point, then convert:
|
|
|
|
if (TranslateMatrixValid)
|
|
{
|
|
u = M11 * xMin + M21 * y + Dx;
|
|
v = M12 * xMin + M22 * y + Dy;
|
|
}
|
|
else
|
|
{
|
|
GpPointF point(TOREAL(xMin), TOREAL(y));
|
|
DeviceToWorld.Transform(&point, 1);
|
|
|
|
u = GpRound(point.X * (1 << 16));
|
|
v = GpRound(point.Y * (1 << 16));
|
|
}
|
|
|
|
INT uIncrement = UIncrement;
|
|
INT vIncrement = VIncrement;
|
|
INT modulusWidth = ModulusWidth;
|
|
INT modulusHeight = ModulusHeight;
|
|
VOID *scan0 = BmpData.Scan0;
|
|
INT stride = BmpData.Stride;
|
|
INT width = BmpData.Width;
|
|
INT height = BmpData.Height;
|
|
INT xEdgeIncrement = XEdgeIncrement;
|
|
INT yEdgeIncrement = YEdgeIncrement;
|
|
|
|
INT widthMinus1 = width - 1;
|
|
INT heightMinus1 = height - 1;
|
|
UINT uMax = widthMinus1 << 16;
|
|
UINT vMax = heightMinus1 << 16;
|
|
BOOL clampMode = (BilinearWrapMode == WrapModeClamp);
|
|
ARGB clampColor = ClampColor;
|
|
static ULONGLONG Half8dot8 = 0x0080008000800080;
|
|
|
|
_asm
|
|
{
|
|
mov eax, u
|
|
mov ebx, v
|
|
mov ecx, stride
|
|
mov edi, buffer
|
|
pxor mm0, mm0
|
|
movq mm3, Half8dot8
|
|
|
|
; edx = scratch
|
|
; esi = source pixel
|
|
|
|
PixelLoop:
|
|
|
|
; Most of the time, our texture coordinate will be from the interior
|
|
; of the texture. Things only really get tricky when we have to
|
|
; span the texture edges.
|
|
;
|
|
; Fortunately, the interior case will happen most of the time,
|
|
; so we make that as fast as possible. We pop out-of-line to
|
|
; handle the tricky cases.
|
|
|
|
cmp eax, uMax
|
|
jae HandleTiling ; Note unsigned compare
|
|
|
|
cmp ebx, vMax
|
|
jae HandleTiling ; Note unsigned compare
|
|
|
|
mov edx, eax
|
|
shr edx, 14
|
|
and edx, 0xfffffffc
|
|
|
|
mov esi, ebx
|
|
shr esi, 16
|
|
imul esi, ecx
|
|
|
|
add esi, edx
|
|
add esi, scan0 ; esi = upper left pixel
|
|
|
|
; Stall city. Write first, then reorder with VTune.
|
|
|
|
movd mm4, [esi]
|
|
movd mm5, [esi+4]
|
|
movd mm6, [esi+ecx]
|
|
movd mm7, [esi+ecx+4]
|
|
|
|
ContinueLoop:
|
|
movd mm1, eax
|
|
punpcklwd mm1, mm1
|
|
punpckldq mm1, mm1
|
|
psrlw mm1, 8 ; mm1 = x fraction in low bytes
|
|
|
|
movd mm2, ebx
|
|
punpcklwd mm2, mm2
|
|
punpckldq mm2, mm2
|
|
psrlw mm2, 8 ; mm2 = y fraction in low bytes
|
|
|
|
punpcklbw mm4, mm0
|
|
punpcklbw mm5, mm0 ; unpack pixels A & B to low bytes
|
|
|
|
psubw mm5, mm4
|
|
pmullw mm5, mm1
|
|
paddw mm5, mm3
|
|
psrlw mm5, 8
|
|
paddb mm5, mm4 ; mm5 = A' = A + xFrac * (B - A)
|
|
|
|
punpcklbw mm6, mm0
|
|
punpcklbw mm7, mm0 ; unpack pixels C & D to low bytes
|
|
|
|
psubw mm7, mm6
|
|
pmullw mm7, mm1
|
|
paddw mm7, mm3
|
|
psrlw mm7, 8
|
|
paddb mm7, mm6 ; mm7 = B' = C + xFrac * (D - C)
|
|
|
|
psubw mm7, mm5
|
|
pmullw mm7, mm2
|
|
paddw mm7, mm3
|
|
psrlw mm7, 8
|
|
paddb mm7, mm5 ; mm7 = A' + yFrac * (B' - A')
|
|
|
|
packuswb mm7, mm7
|
|
movd [edi], mm7 ; write the final pixel
|
|
|
|
add eax, uIncrement
|
|
add ebx, vIncrement
|
|
add edi, 4
|
|
|
|
dec count
|
|
jnz PixelLoop
|
|
jmp AllDone
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;
|
|
; Handle tiling cases here
|
|
;
|
|
; All the tough edge cases are handled here, where we deal with
|
|
; texture coordinates that span the texture boundary.
|
|
|
|
HandleTiling:
|
|
cmp clampMode, 0
|
|
jnz HandleClamping
|
|
|
|
; Get 'u' in the range 0 <= u < modulusWidth:
|
|
|
|
cmp eax, modulusWidth
|
|
jb WidthInRange ; note unsigned compare
|
|
|
|
cdq
|
|
idiv modulusWidth
|
|
mov eax, edx ; u %= modulusWidth
|
|
|
|
cmp eax, 0
|
|
jge WidthInRange
|
|
add eax, modulusWidth ; 0 <= u < modulusWidth
|
|
|
|
WidthInRange:
|
|
|
|
; Get 'v' in the range 0 <= v < modulusHeight:
|
|
|
|
cmp ebx, modulusHeight
|
|
jb HeightInRange
|
|
|
|
push eax
|
|
mov eax, ebx
|
|
cdq
|
|
idiv modulusHeight
|
|
mov ebx, edx ; v %= modulusHeight
|
|
pop eax
|
|
|
|
cmp ebx, 0
|
|
jge HeightInRange
|
|
add ebx, modulusHeight ; 0 <= v < modulusHeight
|
|
|
|
HeightInRange:
|
|
|
|
; Now we're going to need to convert our 'u' and 'v' values
|
|
; to integers, so save the 16.16 versions:
|
|
|
|
push eax
|
|
push ebx
|
|
push ecx
|
|
push edi
|
|
|
|
sar eax, 16
|
|
sar ebx, 16 ; note arithmetic shift
|
|
|
|
; Handle 'flipping'. Note that edi hold flipping flags, where
|
|
; the bits have the following meanings:
|
|
; 1 = X flip in progress
|
|
; 2 = Y flip in progress
|
|
; 4 = X flip end boundary not yet reached
|
|
; 8 = Y flip end boundary not yet reached.
|
|
|
|
xor edi, edi
|
|
cmp eax, width
|
|
jb XFlipHandled
|
|
|
|
; u is in the range (width <= u < 2*width).
|
|
;
|
|
; We want to flip it such that (0 <= u' < width), which we do by
|
|
; u' = 2*width - u - 1. Don't forget ~u = -u - 1.
|
|
|
|
or edi, 1 ; mark the flip
|
|
not eax
|
|
add eax, width
|
|
add eax, width
|
|
jz XFlipHandled
|
|
sub eax, 1
|
|
or edi, 4 ; mark flip where adjacent pixels available
|
|
|
|
|
|
XFlipHandled:
|
|
cmp ebx, height
|
|
jb YFlipHandled
|
|
|
|
|
|
; v is in the range (height <= v < 2*height).
|
|
;
|
|
; We want to flip it such that (0 <= v' < height), which we do by
|
|
; v' = 2*height - v - 1. Don't forget ~v = -v - 1.
|
|
|
|
or edi, 2 ; mark the flip
|
|
not ebx
|
|
add ebx, height
|
|
add ebx, height
|
|
jz YFlipHandled
|
|
sub ebx, 1
|
|
or edi, 8 ; mark flip where adjacent pixels available
|
|
|
|
YFlipHandled:
|
|
mov esi, ebx
|
|
imul esi, ecx ; esi = y * stride
|
|
|
|
; Set 'edx' to the byte offset to the pixel one to the right, accounting
|
|
; for wrapping past the edge of the bitmap. Only set the byte offset to
|
|
; point to right pixel for non edge cases.
|
|
|
|
mov edx, 4
|
|
test edi, 4
|
|
jnz RightIncrementCalculated
|
|
test edi, 1
|
|
jnz SetXEdgeInc
|
|
cmp eax, widthMinus1
|
|
jb RightIncrementCalculated
|
|
SetXEdgeInc:
|
|
mov edx, xEdgeIncrement
|
|
|
|
; When we flipX and the current pixel is the last pixel in the texture
|
|
; line, wrapping past the end of the bitmap wraps back in the same side
|
|
; of the bitmap. I.e. for this one specific pixel we can set the pixel
|
|
; on-the-right to be the same as this pixel (increment of zero).
|
|
; Only valid because this is the edge condition.
|
|
; Note that this will occur for two successive pixels as the texture
|
|
; wrap occurs - first at width-1 and then at width-1 after wrapping.
|
|
;
|
|
; A | B
|
|
; --+--
|
|
; C | D
|
|
;
|
|
; At this point, pixel A has been computed correctly accounting for the
|
|
; flip/tile and wrapping beyond the edge of the texture. We work out
|
|
; the offset of B from A, but we again need to take into account the
|
|
; possible flipX mode if pixel A happens to be the last pixel in the
|
|
; texture scanline (the code immediately above takes into account
|
|
; tiling across the texture boundary, but not the flip)
|
|
|
|
|
|
RightIncrementCalculated:
|
|
|
|
; Set 'ecx' to the byte offset to the pixel one down, accounting for
|
|
; wrapping past the edge of the bitmap. Only set the byte offset to
|
|
; point to one pixel down for non edge cases.
|
|
|
|
test edi, 8
|
|
jnz DownIncrementCalculated
|
|
test edi, 2
|
|
jnz SetYEdgeInc
|
|
cmp ebx, heightMinus1
|
|
jb DownIncrementCalculated
|
|
SetYEdgeInc:
|
|
mov ecx, yEdgeIncrement
|
|
|
|
; When we flipY and the current pixel is in the last scanline in the
|
|
; texture, wrapping past the end of the bitmap wraps back in the same
|
|
; side of the bitmap. I.e. for this one specific scanline we can set
|
|
; the pixel offset one down to be the same as this pixel
|
|
; (increment of zero).
|
|
; Only valid because this is the edge condition.
|
|
; (see comment above RightIncrementCalculated:)
|
|
|
|
DownIncrementCalculated:
|
|
|
|
; Finish calculating the upper-left pixel address:
|
|
|
|
add esi, scan0
|
|
shl eax, 2
|
|
add esi, eax ; esi = upper left pixel
|
|
|
|
; Load the 4 pixels:
|
|
|
|
movd mm4, [esi]
|
|
movd mm5, [esi+edx]
|
|
add esi, ecx
|
|
movd mm6, [esi]
|
|
movd mm7, [esi+edx]
|
|
|
|
; Finish handling the flip:
|
|
|
|
test edi, 1
|
|
jz XSwapDone
|
|
|
|
movq mm1, mm5
|
|
movq mm5, mm4
|
|
movq mm4, mm1 ; swap pixels A and B
|
|
|
|
movq mm1, mm6
|
|
movq mm6, mm7
|
|
movq mm7, mm1 ; swap pixels C and D
|
|
|
|
XSwapDone:
|
|
test edi, 2
|
|
jz YSwapDone
|
|
|
|
movq mm1, mm4
|
|
movq mm4, mm6
|
|
movq mm6, mm1 ; swap pixels A and C
|
|
|
|
movq mm1, mm5
|
|
movq mm5, mm7
|
|
movq mm7, mm1 ; swap pixels B and D
|
|
|
|
YSwapDone:
|
|
|
|
; Restore everything and get out:
|
|
|
|
pop edi
|
|
pop ecx
|
|
pop ebx
|
|
pop eax
|
|
jmp ContinueLoop
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;
|
|
; Clamp mode.
|
|
;
|
|
; Set the pixel values to 0 for any not on the texture.
|
|
|
|
HandleClamping:
|
|
push eax
|
|
push ebx
|
|
|
|
movd mm4, clampColor
|
|
movq mm5, mm4
|
|
movq mm6, mm4 ; initialize invisible pixels to
|
|
movq mm7, mm4 ; the clampColor.
|
|
|
|
sar eax, 16
|
|
sar ebx, 16 ; note these are arithmetic shifts
|
|
|
|
; We need to look at a 2x2 square of pixels in the texture, where
|
|
; (eax, ebx) represents the (x, y) texture coordinates. First we
|
|
; check for the case where none of the four pixel locations are
|
|
; actually anywhere on the texture.
|
|
|
|
cmp eax, -1
|
|
jl FinishClamp
|
|
cmp eax, width
|
|
jge FinishClamp ; early out if (x < -1) or (x >= width)
|
|
|
|
cmp ebx, -1
|
|
jl FinishClamp
|
|
cmp ebx, height
|
|
jge FinishClamp ; handle trivial rejection
|
|
|
|
; Okay, now we know that we have to pull at least one pixel from
|
|
; the texture. Find the address of the upper-left pixel:
|
|
|
|
mov edx, eax
|
|
shl edx, 2
|
|
mov esi, ebx
|
|
imul esi, ecx
|
|
add esi, edx
|
|
add esi, scan0 ; esi = upper left pixel
|
|
|
|
; Our pixel nomenclature for the 2x2 square is as follows:
|
|
;
|
|
; A | B
|
|
; ---+---
|
|
; C | D
|
|
|
|
cmp ebx, 0 ; if (y < 0), we can't look at
|
|
jl Handle_CD ; row y
|
|
cmp eax, 0 ; if (x < 0), we can't look at
|
|
jl Done_A ; column x
|
|
movd mm4, [esi] ; read pixel (x, y)
|
|
|
|
Done_A:
|
|
cmp eax, widthMinus1 ; if (x >= width - 1), we can't
|
|
jge Handle_CD ; look at column x
|
|
movd mm5, [esi+4] ; read pixel (x+1, y)
|
|
|
|
Handle_CD:
|
|
cmp ebx, heightMinus1 ; if (y >= height - 1), we can't
|
|
jge FinishClamp ; look at row y
|
|
cmp eax, 0 ; if (x < 0), we can't look at
|
|
jl Done_C ; column x
|
|
movd mm6, [esi+ecx] ; read pixel (x, y+1)
|
|
|
|
Done_C:
|
|
cmp eax, widthMinus1 ; if (x >= width - 1), we can't
|
|
jge FinishClamp ; look at column x
|
|
movd mm7, [esi+ecx+4] ; read pixel (x+1, y+1)
|
|
|
|
FinishClamp:
|
|
pop ebx
|
|
pop eax
|
|
jmp ContinueLoop
|
|
|
|
AllDone:
|
|
emms
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Output routine for handling texture brushes with indentity transforms
|
|
* and either 'Tile' or 'Clamp' wrap modes.
|
|
*
|
|
* Created:
|
|
*
|
|
* 03/14/2000 andrewgo
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
DpOutputBilinearSpan_Identity::OutputSpan(
|
|
INT y,
|
|
INT xMin,
|
|
INT xMax // xMax is exclusive
|
|
)
|
|
{
|
|
ASSERT(xMax > xMin);
|
|
|
|
INT count = xMax - xMin;
|
|
ARGB *buffer = Scan->NextBuffer(xMin, y, count);
|
|
|
|
INT u = xMin + Dx;
|
|
INT v = y + Dy;
|
|
INT width = BmpData.Width;
|
|
INT height = BmpData.Height;
|
|
INT i;
|
|
|
|
if (BilinearWrapMode == WrapModeTile)
|
|
{
|
|
if (PowerOfTwo)
|
|
{
|
|
u &= (width - 1);
|
|
v &= (height - 1);
|
|
}
|
|
else
|
|
{
|
|
// Single unsigned compare handles (u < 0) and (u >= width)
|
|
|
|
if (static_cast<unsigned>(u) >= static_cast<unsigned>(width))
|
|
{
|
|
u = RemainderI(u, width);
|
|
}
|
|
|
|
// Single unsigned compare handles (v < 0) and (v >= width)
|
|
|
|
if (static_cast<unsigned>(v) >= static_cast<unsigned>(height))
|
|
{
|
|
v = RemainderI(v, height);
|
|
}
|
|
}
|
|
|
|
ARGB *row = reinterpret_cast<ARGB*>
|
|
(static_cast<BYTE*>(BmpData.Scan0) + (v * BmpData.Stride));
|
|
ARGB *src;
|
|
|
|
src = row + u;
|
|
i = min(width - u, count);
|
|
count -= i;
|
|
|
|
// We don't call GpMemcpy here because by doing the copy explicitly,
|
|
// the compiler still converts to a 'rep movsd', but it doesn't have
|
|
// to add to the destination 'buffer' pointer when done:
|
|
|
|
do {
|
|
*buffer++ = *src++;
|
|
|
|
} while (--i != 0);
|
|
|
|
while (count > 0)
|
|
{
|
|
src = row;
|
|
i = min(width, count);
|
|
count -= i;
|
|
|
|
do {
|
|
*buffer++ = *src++;
|
|
|
|
} while (--i != 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ASSERT(BilinearWrapMode == WrapModeClamp);
|
|
|
|
ARGB borderColor = ClampColor;
|
|
|
|
// Check for trivial rejection. Unsigned compare handles
|
|
// (v < 0) and (v >= height).
|
|
|
|
if ((static_cast<unsigned>(v) >= static_cast<unsigned>(height)) ||
|
|
(u >= width) ||
|
|
(u + count <= 0))
|
|
{
|
|
// The whole scan should be the border color:
|
|
|
|
i = count;
|
|
do {
|
|
*buffer++ = borderColor;
|
|
|
|
} while (--i != 0);
|
|
}
|
|
else
|
|
{
|
|
ARGB *src = reinterpret_cast<ARGB*>
|
|
(static_cast<BYTE*>(BmpData.Scan0) + (v * BmpData.Stride));
|
|
|
|
if (u < 0)
|
|
{
|
|
i = -u;
|
|
count -= i;
|
|
do {
|
|
*buffer++ = borderColor;
|
|
|
|
} while (--i != 0);
|
|
}
|
|
else
|
|
{
|
|
src += u;
|
|
width -= u;
|
|
}
|
|
|
|
i = min(count, width);
|
|
ASSERT(i > 0); // Trivial rejection ensures this
|
|
count -= i;
|
|
|
|
|
|
/*
|
|
The compiler was generating particularly stupid code
|
|
for this loop.
|
|
|
|
do {
|
|
*buffer++ = *src++;
|
|
|
|
} while (--i != 0);
|
|
*/
|
|
|
|
GpMemcpy(buffer, src, i*sizeof(ARGB));
|
|
buffer += i;
|
|
|
|
while (count-- > 0)
|
|
{
|
|
*buffer++ = borderColor;
|
|
}
|
|
}
|
|
}
|
|
|
|
return(Ok);
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Hatch brush constructor.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Created:
|
|
*
|
|
* 04/15/1999 ikkof
|
|
*
|
|
\**************************************************************************/
|
|
|
|
DpOutputHatchSpan::DpOutputHatchSpan(
|
|
const GpHatch *hatchBrush,
|
|
DpScanBuffer * scan,
|
|
DpContext* context
|
|
)
|
|
{
|
|
Scan = scan;
|
|
ForeARGB = hatchBrush->DeviceBrush.Colors[0].GetPremultipliedValue();
|
|
BackARGB = hatchBrush->DeviceBrush.Colors[1].GetPremultipliedValue();
|
|
|
|
// Store the context rendering origin for the brush origin.
|
|
|
|
m_BrushOriginX = context->RenderingOriginX;
|
|
m_BrushOriginY = context->RenderingOriginY;
|
|
|
|
INT a[3], r[3], g[3], b[3];
|
|
|
|
a[0] = (BYTE) GpColor::GetAlphaARGB(ForeARGB);
|
|
r[0] = (BYTE) GpColor::GetRedARGB(ForeARGB);
|
|
g[0] = (BYTE) GpColor::GetGreenARGB(ForeARGB);
|
|
b[0] = (BYTE) GpColor::GetBlueARGB(ForeARGB);
|
|
a[1] = (BYTE) GpColor::GetAlphaARGB(BackARGB);
|
|
r[1] = (BYTE) GpColor::GetRedARGB(BackARGB);
|
|
g[1] = (BYTE) GpColor::GetGreenARGB(BackARGB);
|
|
b[1] = (BYTE) GpColor::GetBlueARGB(BackARGB);
|
|
|
|
a[2] = (a[0] + 3*a[1]) >> 2;
|
|
r[2] = (r[0] + 3*r[1]) >> 2;
|
|
g[2] = (g[0] + 3*g[1]) >> 2;
|
|
b[2] = (b[0] + 3*b[1]) >> 2;
|
|
AverageARGB = GpColor::MakeARGB((BYTE) a[2], (BYTE) r[2],
|
|
(BYTE) g[2], (BYTE) b[2]);
|
|
|
|
// Antialiase diagonal hatches.
|
|
if(hatchBrush->DeviceBrush.Style == HatchStyleForwardDiagonal ||
|
|
hatchBrush->DeviceBrush.Style == HatchStyleBackwardDiagonal ||
|
|
hatchBrush->DeviceBrush.Style == HatchStyleDiagonalCross)
|
|
{
|
|
REAL temp;
|
|
|
|
// occupied = (2*sqrt(2) - 1)/2
|
|
|
|
REAL occupied = TOREAL(0.914213562);
|
|
|
|
if(a[0] != 255 || a[1] != 255)
|
|
{
|
|
temp = TOREAL(occupied*(a[0] - a[1]) + a[1]);
|
|
a[0] = (BYTE) temp;
|
|
}
|
|
temp = TOREAL(occupied*(r[0] - r[1]) + r[1]);
|
|
if(temp > 255)
|
|
r[0] = 255;
|
|
else
|
|
r[0] = (BYTE) temp;
|
|
temp = TOREAL(occupied*(g[0] - g[1]) + g[1]);
|
|
if(temp > 255)
|
|
g[0] = 255;
|
|
else
|
|
g[0] = (BYTE) temp;
|
|
temp = TOREAL(occupied*(b[0] - b[1]) + b[1]);
|
|
if(temp > 255)
|
|
b[0] = 255;
|
|
else
|
|
b[0] = (BYTE) temp;
|
|
ForeARGB = GpColor::MakeARGB((BYTE) a[0], (BYTE) r[0],
|
|
(BYTE) g[0], (BYTE) b[0]);
|
|
}
|
|
|
|
for(INT i = 0; i < 8; i++)
|
|
{
|
|
for(INT j= 0; j < 8; j++)
|
|
{
|
|
Data[i][j] = hatchBrush->DeviceBrush.Data[i][j];
|
|
}
|
|
}
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Outputs a single span within a raster with a hatch brush
|
|
* Is called by the rasterizer.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] y - the Y value of the raster being output
|
|
* [IN] leftEdge - the DDA class of the left edge
|
|
* [IN] rightEdge - the DDA class of the right edge
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok
|
|
*
|
|
* Created:
|
|
*
|
|
* 04/15/1999 ikkof
|
|
*
|
|
\**************************************************************************/
|
|
|
|
GpStatus
|
|
DpOutputHatchSpan::OutputSpan(
|
|
INT y,
|
|
INT xMin,
|
|
INT xMax // xMax is exclusive
|
|
)
|
|
{
|
|
ARGB argb;
|
|
INT width = xMax - xMin;
|
|
ARGB* buffer = Scan->NextBuffer(xMin, y, width);
|
|
|
|
INT yMod = (y - m_BrushOriginY) & 0x7;
|
|
|
|
for(INT x = xMin; x < xMax; x++)
|
|
{
|
|
INT xMod = (x - m_BrushOriginX) & 0x7;
|
|
INT value = Data[yMod][xMod];
|
|
if(value == 255)
|
|
*buffer++ = ForeARGB;
|
|
else if(value == 0)
|
|
*buffer++ = BackARGB;
|
|
else
|
|
*buffer++ = AverageARGB; // for antialising.
|
|
}
|
|
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Outputs a single span within a raster with a hatch brush
|
|
* Is called by the rasterizer. This is a special version which stretches
|
|
* up the size of the hatch span to device resolution.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] y - the Y value of the raster being output
|
|
* [IN] leftEdge - the DDA class of the left edge
|
|
* [IN] rightEdge - the DDA class of the right edge
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok
|
|
*
|
|
* Created:
|
|
*
|
|
* 2/20/1 - ericvan
|
|
*
|
|
\**************************************************************************/
|
|
|
|
GpStatus
|
|
DpOutputStretchedHatchSpan::OutputSpan(
|
|
INT y,
|
|
INT xMin,
|
|
INT xMax // xMax is exclusive
|
|
)
|
|
{
|
|
ARGB argb;
|
|
INT width = xMax - xMin;
|
|
ARGB* buffer = Scan->NextBuffer(xMin, y, width);
|
|
|
|
INT yMod = (y - m_BrushOriginY) % (8*ScaleFactor);
|
|
|
|
for(INT x = xMin; x < xMax; x++)
|
|
{
|
|
INT xMod = (x - m_BrushOriginX) % (8*ScaleFactor);
|
|
INT value = Data[yMod/ScaleFactor][xMod/ScaleFactor];
|
|
if(value == 255)
|
|
*buffer++ = ForeARGB;
|
|
else if(value == 0)
|
|
*buffer++ = BackARGB;
|
|
else
|
|
*buffer++ = AverageARGB; // for antialising.
|
|
}
|
|
|
|
return Ok;
|
|
}
|
|
|