Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2115 lines
54 KiB

/**********************************Module*Header*******************************\
* Module Name: Strips.c
*
* Hardware line drawing support routines
*
* Copyright (c) 1994-1998 3Dlabs Inc. Ltd. All rights reserved.
* Copyright (c) 1995-1999 Microsoft Corporation. All rights reserved.
\******************************************************************************/
#include "precomp.h"
#include "gdi.h"
#define STRIP_LOG_LEVEL 6
//-----------------------------------------------------------------------------
//
// BOOL bInitializeStrips
//
// Setup hardware for sucessive calls to strips functions.
//
//-----------------------------------------------------------------------------
BOOL
bInitializeStrips(PDev* ppdev,
ULONG ulSolidColor, // Solid color fill
DWORD dwLogicOp, // Logical Operation to perform
RECTL* prclClip) // Clip region (Or NULL if no clip)
{
DWORD dwColorReg;
BOOL bRC = FALSE;
Surf* psurfDst = ppdev->psurf;
ULONG* pBuffer;
PERMEDIA_DECL;
DBG_GDI((STRIP_LOG_LEVEL + 1, "bInitializeStrips"));
InputBufferReserve(ppdev, 16, &pBuffer);
pBuffer[0] = __Permedia2TagFBWindowBase;
pBuffer[1] = psurfDst->ulPixOffset;
pBuffer += 2;
if ( dwLogicOp == K_LOGICOP_COPY )
{
dwColorReg = __Permedia2TagFBWriteData;
pBuffer[0] = __Permedia2TagLogicalOpMode;
pBuffer[1] = __PERMEDIA_CONSTANT_FB_WRITE;
pBuffer[2] = __Permedia2TagFBReadMode;
pBuffer[3] = PM_FBREADMODE_PARTIAL(psurfDst->ulPackedPP)
| PM_FBREADMODE_PACKEDDATA(__PERMEDIA_DISABLE);
pBuffer += 4;
}
else
{
DWORD dwReadMode;
//@@BEGIN_DDKSPLIT
//
// TODO: look into what the heck is going on here
// for now, I'll remove the code because it is not clear to
// me that it will work
//@@END_DDKSPLIT
// Special case for 3DS Max when page flipping. Max uses an XOR'ed GDI
// line within the 3d window. When pageflipping we double write GDI and
// so always write to buffer 0. We need to make sure the frame buffer
// read happens from the currently displayed buffer.
//
dwColorReg = __Permedia2TagConstantColor;
dwReadMode = psurfDst->ulPackedPP | LogicopReadDest[dwLogicOp];
pBuffer[0] = __Permedia2TagColorDDAMode;
pBuffer[1] = __COLOR_DDA_FLAT_SHADE;
pBuffer[2] = __Permedia2TagLogicalOpMode;
pBuffer[3] = P2_ENABLED_LOGICALOP(dwLogicOp);
pBuffer[4] = __Permedia2TagFBReadMode;
pBuffer[5] = dwReadMode;
pBuffer += 6;
//
// We have changed the DDA Mode setting so we must return TRUE so we can
// re-set it later.
//
bRC = TRUE;
}
pBuffer[0] = dwColorReg;
pBuffer[1] = ulSolidColor;
pBuffer += 2;
if ( prclClip )
{
pBuffer[0] = __Permedia2TagScissorMode;
pBuffer[1] = SCREEN_SCISSOR_DEFAULT | USER_SCISSOR_ENABLE;
pBuffer[2] =__Permedia2TagScissorMinXY;
pBuffer[3] = ((prclClip->left) << SCISSOR_XOFFSET)
| ((prclClip->top) << SCISSOR_YOFFSET);
pBuffer[4] =__Permedia2TagScissorMaxXY;
pBuffer[5] = ((prclClip->right) << SCISSOR_XOFFSET)
| ((prclClip->bottom) << SCISSOR_YOFFSET);
pBuffer += 6;
//
// Need to reset scissor mode
//
bRC = TRUE;
}
InputBufferCommit(ppdev, pBuffer);
DBG_GDI((STRIP_LOG_LEVEL + 1, "bInitializeStrips done return %d", bRC));
return(bRC);
}// bInitializeStrips()
//-----------------------------------------------------------------------------
//
// VOID vResetStrips
//
// Resets the hardware to its default state
//
//-----------------------------------------------------------------------------
VOID
vResetStrips(PDev* ppdev)
{
ULONG* pBuffer;
DBG_GDI((STRIP_LOG_LEVEL + 1, "vResetStrips"));
//
// Reset hardware to default state
//
InputBufferReserve(ppdev, 4 , &pBuffer);
pBuffer[0] = __Permedia2TagScissorMode;
pBuffer[1] = SCREEN_SCISSOR_DEFAULT;
pBuffer[2] = __Permedia2TagColorDDAMode;
pBuffer[3] = __PERMEDIA_DISABLE;
pBuffer += 4;
InputBufferCommit(ppdev, pBuffer);
}// vResetStrips()
//-----------------------------------------------------------------------------
//
// BOOL bFastIntegerLine
//
// Integer line drawing.
//
// Returns FALSE if the line can not be drawn due to hardware limitations
//
// NOTE: This algorithm is not completely compliant. Lines > 190 pixels long
// may get some incorrect pixels plotted somewhere along the length.
// If we detect these long lines then we fail the call.
// NOTE: GLICAP_NT_CONFORMANT_LINES will always be set.
//
//-----------------------------------------------------------------------------
BOOL
bFastIntegerLine(PDev* ppdev,
LONG X1,
LONG Y1,
LONG X2,
LONG Y2)
{
LONG dx, dy, adx, ady;
LONG gdx, gdy, count;
ULONG* pBuffer;
PERMEDIA_DECL;
DBG_GDI((STRIP_LOG_LEVEL, "bFastIntegerLine"));
//
// Convert points to INT format
//
X1 >>= 4;
Y1 >>= 4;
X2 >>= 4;
Y2 >>= 4;
//
// Get deltas and absolute deltas
//
if ( (adx = dx = X2 - X1) < 0 )
{
adx = -adx;
}
if ( (ady = dy = Y2 - Y1) < 0 )
{
ady = -ady;
}
if ( adx > ady )
{
//
// X Major line
//
gdx = (dx > 0) ? INTtoFIXED(1) : INTtoFIXED(-1);
if ( ady == 0 )
{
//
// Horizontal lines
//
gdy = 0;
}// if (ady == 0)
else
{
//
// We dont necessarily want to push any lines through Permedia2 that
// might not be conformant
//
if ( (adx > MAX_LENGTH_CONFORMANT_INTEGER_LINES)
&&(permediaInfo->flags & GLICAP_NT_CONFORMANT_LINES) )
{
return(FALSE);
}
gdy = INTtoFIXED(dy);
//
// Need to explicitly round delta down for -ve deltas.
//
if ( dy < 0 )
{
gdy -= adx - 1;
}
gdy /= adx;
}// if (ady != 0)
count = adx;
}// if ( adx > ady )
else if ( adx < ady )
{
//
// Y Major line
//
gdy = (dy > 0) ? INTtoFIXED(1) : INTtoFIXED(-1);
if ( adx == 0 )
{
//
// Vertical lines
//
gdx = 0;
}
else
{
//
// We dont necessarily want to push any lines through Permedia2 that
// might not be conformant
//
if ( (ady > MAX_LENGTH_CONFORMANT_INTEGER_LINES)
&&(permediaInfo->flags & GLICAP_NT_CONFORMANT_LINES) )
{
return(FALSE);
}
gdx = INTtoFIXED(dx);
//
// Need to explicitly round delta down for -ve deltas.
//
if ( dx < 0 )
{
gdx -= ady - 1;
}
gdx /= ady;
}
count = ady;
}// if ( adx < ady )
else
{
//
// Special case for 45 degree lines. These are always conformant.
//
gdx = (dx > 0) ? INTtoFIXED(1) : INTtoFIXED(-1);
gdy = (dy > 0) ? INTtoFIXED(1) : INTtoFIXED(-1);
count = adx;
}
InputBufferReserve(ppdev, 16, &pBuffer);
//
// Set up the start point
//
pBuffer[0] = __Permedia2TagStartXDom;
pBuffer[1] = INTtoFIXED(X1) + NEARLY_HALF;
pBuffer[2] = __Permedia2TagStartY;
pBuffer[3] = INTtoFIXED(Y1) + NEARLY_HALF;
pBuffer[4] = __Permedia2TagdXDom;
pBuffer[5] = gdx;
pBuffer[6] = __Permedia2TagdY;
pBuffer[7] = gdy;
pBuffer[8] = __Permedia2TagCount;
pBuffer[9] = count;
pBuffer[10] = __Permedia2TagRender;
pBuffer[11] = __RENDER_LINE_PRIMITIVE;
pBuffer[12] = __Permedia2TagdXDom;
pBuffer[13] = 0;
pBuffer[14] = __Permedia2TagdY;
pBuffer[15] = INTtoFIXED(1);
pBuffer += 16;
InputBufferCommit(ppdev, pBuffer);
DBG_GDI((STRIP_LOG_LEVEL + 1, "bFastIntegerLine Done"));
return(TRUE);
}// bFastIntegerLine()
//-----------------------------------------------------------------------------
//
// BOOL bFastIntegerContinueLine
//
// Integer line drawing through Permedia2.
//
// Returns FALSE if the line can not be drawn due to hardware limitations.
//
// NOTE: This algorithm is not completely compliant. Lines > 190 pixels long
// may get some incorrect pixels plotted somewhere along the length.
// If we detect these long lines then we fail the call.
// NOTE: GLICAP_NT_CONFORMANT_LINES will always be set.
//
//-----------------------------------------------------------------------------
BOOL
bFastIntegerContinueLine(PDev* ppdev,
LONG X1,
LONG Y1,
LONG X2,
LONG Y2)
{
LONG dx, dy, adx, ady;
LONG gdx, gdy, count;
ULONG* pBuffer;
PERMEDIA_DECL;
DBG_GDI((STRIP_LOG_LEVEL + 1, "bFastIntegerContinueLine"));
//
// This assumes that the end point of the previous line is correct.
// The Fraction adjust should be set to nearly a half to remove any
// error from the end point of the previous line.
// Get deltas and absolute deltas from 28.4 format
//
if ( (adx = dx = (X2 - X1) >> 4) < 0 )
{
adx = -adx;
}
if ( (ady = dy = (Y2 - Y1) >> 4) < 0 )
{
ady = -ady;
}
if ( adx > ady )
{
//
// X Major line
//
gdx = (dx > 0) ? INTtoFIXED(1) : INTtoFIXED(-1);
if (ady == 0)
{
//
// Horizontal lines
//
gdy = 0;
}
else
{
//
// We dont necessarily want to push any lines through Permedia2 that
// might not be conformant
//
if ( (adx > MAX_LENGTH_CONFORMANT_INTEGER_LINES)
&&(permediaInfo->flags & GLICAP_NT_CONFORMANT_LINES) )
{
return(FALSE);
}
gdy = INTtoFIXED(dy);
//
// Need to explicitly round delta down for -ve deltas.
//
if ( dy < 0 )
{
gdy -= adx - 1;
}
gdy /= adx;
}
count = adx;
}// if ( adx > ady )
else if (adx < ady)
{
//
// Y Major line
//
gdy = (dy > 0) ? INTtoFIXED(1) : INTtoFIXED(-1);
if ( adx == 0 )
{
//
// Vertical lines
//
gdx = 0;
}
else
{
//
// We dont necessarily want to push any lines through Permedia2 that
// might not be conformant
//
if ( (ady > MAX_LENGTH_CONFORMANT_INTEGER_LINES)
&&(permediaInfo->flags & GLICAP_NT_CONFORMANT_LINES) )
{
return(FALSE);
}
gdx = INTtoFIXED(dx);
//
// Need to explicitly round delta down for -ve deltas.
//
if ( dx < 0 )
{
gdx -= ady - 1;
}
gdx /= ady;
}
count = ady;
}
else
{
//
// Special case for 45 degree lines. These are always conformant.
//
if ( ady == 0 )
{
return(TRUE); // adx == ady == 0! Nothing to draw.
}
gdx = (dx > 0) ? INTtoFIXED(1) : INTtoFIXED(-1);
gdy = (dy > 0) ? INTtoFIXED(1) : INTtoFIXED(-1);
count = adx;
}
InputBufferReserve(ppdev, 10 , &pBuffer);
//
// Set up the start point
//
DBG_GDI((7, "Loading dXDom 0x%x, dY 0x%x, count 0x%x", gdx, gdy, count));
pBuffer[0] = __Permedia2TagdXDom;
pBuffer[1] = gdx;
pBuffer[2] = __Permedia2TagdY;
pBuffer[3] = gdy;
pBuffer[4] = __Permedia2TagContinueNewLine;
pBuffer[5] = count;
//
// Restore dXDom and dY to their defaults
//
pBuffer[6] = __Permedia2TagdXDom;
pBuffer[7] = 0;
pBuffer[8] = __Permedia2TagdY;
pBuffer[9] = INTtoFIXED(1);
pBuffer += 10;
InputBufferCommit(ppdev, pBuffer);
DBG_GDI((STRIP_LOG_LEVEL + 1, "bFastIntegerContinueLine Done"));
return(TRUE);
}// bFastIntegerContinueLine()
//-----------------------------------------------------------------------------
//
// VOID vSolidHorizontal
//
// Draws left-to-right x-major near-horizontal lines using short-stroke
// vectors.
//
//-----------------------------------------------------------------------------
VOID
vSolidHorizontalLine(PDev* ppdev,
STRIP* pStrip,
LINESTATE* pLineState)
{
LONG cStrips;
PLONG pStrips;
LONG iCurrent;
ULONG* pBuffer;
PERMEDIA_DECL;
DBG_GDI((STRIP_LOG_LEVEL, "vSolidHorizontalLine"));
cStrips = pStrip->cStrips;
InputBufferReserve(ppdev, 16, &pBuffer);
//
// Set up the start point
//
pBuffer[0] = __Permedia2TagStartXDom;
pBuffer[1] = INTtoFIXED(pStrip->ptlStart.x);
pBuffer[2] = __Permedia2TagStartY;
pBuffer[3] = INTtoFIXED(pStrip->ptlStart.y);
//
// Set up the deltas for rectangle drawing. Also set Y return value.
//
if ( !(pStrip->flFlips & FL_FLIP_V) )
{
pBuffer[4] = __Permedia2TagdXDom;
pBuffer[5] = INTtoFIXED(0);
pBuffer[6] = __Permedia2TagdXSub;
pBuffer[7] = INTtoFIXED(0);
pBuffer[8] = __Permedia2TagdY;
pBuffer[9] = INTtoFIXED(1);
pStrip->ptlStart.y += cStrips;
}
else
{
pBuffer[4] = __Permedia2TagdXDom;
pBuffer[5] = INTtoFIXED(0);
pBuffer[6] = __Permedia2TagdXSub;
pBuffer[7] = INTtoFIXED(0);
pBuffer[8] = __Permedia2TagdY;
pBuffer[9] = INTtoFIXED(-1);
pStrip->ptlStart.y -= cStrips;
}
pStrips = pStrip->alStrips;
//
// We have to do first strip manually, as we have to use RENDER
// for the first strip, and CONTINUENEW... for the following strips
//
iCurrent = pStrip->ptlStart.x + *pStrips++; // Xsub, Start of next strip
pBuffer[10] = __Permedia2TagStartXSub;
pBuffer[11] = INTtoFIXED(iCurrent);
pBuffer[12] = __Permedia2TagCount;
pBuffer[13] = 1; // Rectangle 1 scanline high
pBuffer[14] = __Permedia2TagRender;
pBuffer[15] = __RENDER_TRAPEZOID_PRIMITIVE;
pBuffer += 16;
InputBufferCommit(ppdev, pBuffer);
if ( --cStrips )
{
while ( cStrips > 1 )
{
//
// First strip of each pair to fill. XSub is valid. Need new Xdom
//
iCurrent += *pStrips++;
InputBufferReserve(ppdev, 8, &pBuffer);
pBuffer[0] = __Permedia2TagStartXDom;
pBuffer[1] = INTtoFIXED(iCurrent);
pBuffer[2] = __Permedia2TagContinueNewDom;
pBuffer[3] = 1;
//
// Second strip of each pair to fill. XDom is valid. Need new XSub
//
iCurrent += *pStrips++;
pBuffer[4] = __Permedia2TagStartXSub;
pBuffer[5] = INTtoFIXED(iCurrent);
pBuffer[6] = __Permedia2TagContinueNewSub;
pBuffer[7] = 1;
pBuffer += 8;
InputBufferCommit(ppdev, pBuffer);
cStrips -=2;
}// while ( cStrips > 1 )
//
// We may have one last line to draw. Xsub will be valid.
//
if ( cStrips )
{
iCurrent += *pStrips++;
InputBufferReserve(ppdev, 4, &pBuffer);
pBuffer[0] = __Permedia2TagStartXDom;
pBuffer[1] = INTtoFIXED(iCurrent);
pBuffer[2] = __Permedia2TagContinueNewDom;
pBuffer[3] = 1;
pBuffer += 4;
InputBufferCommit(ppdev, pBuffer);
}
}// if ( --cStrips )
//
// Return last point. Y already calculated when we knew the direction.
//
pStrip->ptlStart.x = iCurrent;
if ( pStrip->flFlips & FL_FLIP_V )
{
//
// Restore hardware to default state
//
InputBufferReserve(ppdev, 2, &pBuffer);
pBuffer[0] = __Permedia2TagdY;
pBuffer[1] = INTtoFIXED(1);
pBuffer += 2;
InputBufferCommit(ppdev, pBuffer);
}
}// vSolidHorizontalLine()
//-----------------------------------------------------------------------------
//
// VOID vSolidVertical
//
// Draws left-to-right y-major near-vertical lines using short-stroke
// vectors.
//
//-----------------------------------------------------------------------------
VOID
vSolidVerticalLine(PDev* ppdev,
STRIP* pStrip,
LINESTATE* pLineState)
{
LONG cStrips, yDir;
PLONG pStrips;
LONG iCurrent, iLen, iLenSum;
ULONG* pBuffer;
PERMEDIA_DECL;
DBG_GDI((STRIP_LOG_LEVEL, "vSolidVerticalLine"));
cStrips = pStrip->cStrips;
InputBufferReserve(ppdev, 16, &pBuffer);
//
// Set up the start point
//
pBuffer[0] = __Permedia2TagStartXDom;
pBuffer[1] = INTtoFIXED(pStrip->ptlStart.x);
pBuffer[2] = __Permedia2TagStartY;
pBuffer[3] = INTtoFIXED(pStrip->ptlStart.y);
pBuffer[4] = __Permedia2TagdXDom;
pBuffer[5] = INTtoFIXED(0);
pBuffer[6] = __Permedia2TagdXSub;
pBuffer[7] = INTtoFIXED(0);
//
// Set up the deltas for rectangle drawing.
// dxDom, dXSub and dY all are to 0, 0, and 1 by default
//
if ( !(pStrip->flFlips & FL_FLIP_V) )
{
yDir = 1;
}
else
{
yDir = -1;
}
pBuffer[8] = __Permedia2TagdY;
pBuffer[9] = INTtoFIXED(yDir);
pStrips = pStrip->alStrips;
//
// We have to do first strip manually, as we have to use RENDER
// for the first strip, and CONTINUENEW... for the following strips
//
iCurrent = pStrip->ptlStart.x + 1; // Xsub, Start of next strip
iLenSum = (iLen = *pStrips++);
pBuffer[10] = __Permedia2TagStartXSub;
pBuffer[11] = INTtoFIXED(iCurrent);
pBuffer[12] = __Permedia2TagCount;
pBuffer[13] = iLen; // Rectangle 1 scanline high
pBuffer[14] = __Permedia2TagRender;
pBuffer[15] = __RENDER_TRAPEZOID_PRIMITIVE;
pBuffer += 16;
InputBufferCommit(ppdev, pBuffer);
if ( --cStrips )
{
while ( cStrips > 1 )
{
//
// First strip of each pair to fill. XSub is valid. Need new Xdom
//
iCurrent++;
InputBufferReserve(ppdev, 8, &pBuffer);
pBuffer[0] = __Permedia2TagStartXDom;
pBuffer[1] = INTtoFIXED(iCurrent);
iLenSum += (iLen = *pStrips++);
pBuffer[2] = __Permedia2TagContinueNewDom;
pBuffer[3] = iLen;
//
// Second strip of each pair to fill. XDom is valid. Need new XSub
//
iCurrent ++;
pBuffer[4] = __Permedia2TagStartXSub;
pBuffer[5] = INTtoFIXED(iCurrent);
iLenSum += (iLen = *pStrips++);
pBuffer[6] = __Permedia2TagContinueNewSub;
pBuffer[7] = iLen;
pBuffer += 8;
InputBufferCommit(ppdev, pBuffer);
cStrips -=2;
}// while ( cStrips > 1 )
//
// We may have one last line to draw. Xsub will be valid.
//
if ( cStrips )
{
iCurrent ++;
InputBufferReserve(ppdev, 4, &pBuffer);
pBuffer[0] = __Permedia2TagStartXDom;
pBuffer[1] = INTtoFIXED(iCurrent);
iLenSum += (iLen = *pStrips++);
pBuffer[2] = __Permedia2TagContinueNewDom;
pBuffer[3] = iLen;
pBuffer += 4;
InputBufferCommit(ppdev, pBuffer);
}
}// if ( --cStrips )
//
// Restore hardware to default
//
InputBufferReserve(ppdev, 2, &pBuffer);
pBuffer[0] = __Permedia2TagdY;
pBuffer[1] = INTtoFIXED(1);
pBuffer += 2;
InputBufferCommit(ppdev, pBuffer);
//
// Return last point.
//
pStrip->ptlStart.x = iCurrent;
pStrip->ptlStart.y += iLenSum * yDir;
DBG_GDI((STRIP_LOG_LEVEL + 1, "vSolidVerticalLine done"));
}// vSolidVerticalLine()
//-----------------------------------------------------------------------------
//
// VOID vSolidDiagonalVertical
//
// Draws left-to-right y-major near-diagonal lines using short-stroke
// vectors.
//
//-----------------------------------------------------------------------------
VOID
vSolidDiagonalVerticalLine(PDev* ppdev,
STRIP* pStrip,
LINESTATE* pLineState)
{
LONG cStrips, yDir;
PLONG pStrips;
LONG iCurrent, iLen, iLenSum;
ULONG* pBuffer;
PERMEDIA_DECL;
DBG_GDI((STRIP_LOG_LEVEL, "vSolidDiagonalVerticalLine"));
cStrips = pStrip->cStrips;
if ( !(pStrip->flFlips & FL_FLIP_V) )
{
yDir = 1;
}
else
{
yDir = -1;
}
InputBufferReserve(ppdev, 16, &pBuffer);
//
// Set up the deltas for rectangle drawing.
//
pBuffer[0] = __Permedia2TagdXDom;
pBuffer[1] = INTtoFIXED(1);
pBuffer[2] = __Permedia2TagdXSub;
pBuffer[3] = INTtoFIXED(1);
pBuffer[4] = __Permedia2TagdY;
pBuffer[5] = INTtoFIXED(yDir);
pStrips = pStrip->alStrips;
//
// We have to do first strip manually, as we have to use RENDER
// for the first strip, and CONTINUENEW... for the following strips
//
pBuffer[6] = __Permedia2TagStartY;
pBuffer[7] = INTtoFIXED(pStrip->ptlStart.y);
pBuffer[8] = __Permedia2TagStartXDom;
pBuffer[9] = INTtoFIXED(pStrip->ptlStart.x + 1);
pBuffer[10] = __Permedia2TagStartXSub;
pBuffer[11] = INTtoFIXED(pStrip->ptlStart.x);
iLenSum = (iLen = *pStrips++);
iCurrent = pStrip->ptlStart.x + iLen - 1;// Start of next strip
pBuffer[12] = __Permedia2TagCount;
pBuffer[13] = iLen; // Trap iLen scanline high
pBuffer[14] = __Permedia2TagRender;
pBuffer[15] = __RENDER_TRAPEZOID_PRIMITIVE;
pBuffer += 16;
InputBufferCommit(ppdev, pBuffer);
if ( --cStrips )
{
while ( cStrips > 1 )
{
//
// First strip of each pair to fill. XSub is valid. Need new Xdom
//
InputBufferReserve(ppdev, 8, &pBuffer);
pBuffer[0] = __Permedia2TagStartXDom;
pBuffer[1] = INTtoFIXED(iCurrent);
iLenSum += (iLen = *pStrips++);
iCurrent += iLen - 1;
pBuffer[2] = __Permedia2TagContinueNewDom;
pBuffer[3] = iLen;
//
// Second strip of each pair to fill. XDom is valid. Need new XSub
//
pBuffer[4] = __Permedia2TagStartXSub;
pBuffer[5] = INTtoFIXED(iCurrent);
iLenSum += (iLen = *pStrips++);
iCurrent += iLen - 1;
pBuffer[6] = __Permedia2TagContinueNewSub;
pBuffer[7] = iLen;
pBuffer += 8;
InputBufferCommit(ppdev, pBuffer);
cStrips -=2;
}// while ( cStrips > 1 )
//
// We may have one last line to draw. Xsub will be valid.
//
if ( cStrips )
{
InputBufferReserve(ppdev, 4, &pBuffer);
pBuffer[0] = __Permedia2TagStartXDom;
pBuffer[1] = INTtoFIXED(iCurrent);
iLenSum += (iLen = *pStrips++);
iCurrent += iLen - 1;
pBuffer[2] = __Permedia2TagContinueNewDom;
pBuffer[3] = iLen;
pBuffer += 4;
InputBufferCommit(ppdev, pBuffer);
}
}// if ( --cStrips )
InputBufferReserve(ppdev, 6, &pBuffer);
pBuffer[0] = __Permedia2TagdXDom;
pBuffer[1] = 0;
pBuffer[2] = __Permedia2TagdXSub;
pBuffer[3] = 0;
pBuffer[4] = __Permedia2TagdY;
pBuffer[5] = INTtoFIXED(1);
pBuffer += 6;
InputBufferCommit(ppdev, pBuffer);
//
// Return last point.
//
pStrip->ptlStart.x = iCurrent;
pStrip->ptlStart.y += iLenSum * yDir;
DBG_GDI((STRIP_LOG_LEVEL + 1, "vSolidDiagonalVerticalLine done"));
}// vSolidDiagonalVerticalLine()
//-----------------------------------------------------------------------------
//
// VOID vSolidDiagonalHorizontalLine
//
// Draws left-to-right x-major near-diagonal lines using short-stroke
// vectors.
//
//-----------------------------------------------------------------------------
VOID
vSolidDiagonalHorizontalLine(PDev* ppdev,
STRIP* pStrip,
LINESTATE* pLineState)
{
LONG cStrips, yDir, xCurrent, yCurrent, iLen;
PLONG pStrips;
ULONG* pBuffer;
PERMEDIA_DECL;
DBG_GDI((STRIP_LOG_LEVEL, "vSolidDiagonalHorizontalLine"));
// This routine has to be implemented in a different way to the other 3
// solid line drawing functions because the rasterizer unit will not
// produce 2 pixels on the same scanline without a lot of effort in
// producing delta values. In this case, we have to draw a complete new
// primitive for each strip. Therefore, we have to use lines rather than
// trapezoids to generate the required strips. With lines we use 4 messages
// per strip, where trapezoids would use 5.
cStrips = pStrip->cStrips;
if ( !(pStrip->flFlips & FL_FLIP_V) )
{
yDir = 1;
}
else
{
yDir = -1;
}
pStrips = pStrip->alStrips;
xCurrent = pStrip->ptlStart.x;
yCurrent = pStrip->ptlStart.y;
InputBufferReserve(ppdev, 6, &pBuffer);
//
// Set up the deltas for rectangle drawing.
//
pBuffer[0] = __Permedia2TagdXDom;
pBuffer[1] = INTtoFIXED(1);
pBuffer[2] = __Permedia2TagdXSub;
pBuffer[3] = INTtoFIXED(1);
pBuffer[4] = __Permedia2TagdY;
pBuffer[5] = INTtoFIXED(yDir);
pBuffer += 6;
InputBufferCommit(ppdev, pBuffer);
while ( TRUE )
{
//
// Set up the start point
//
InputBufferReserve(ppdev, 8, &pBuffer);
pBuffer[0] = __Permedia2TagStartXDom;
pBuffer[1] = INTtoFIXED(xCurrent);
pBuffer[2] = __Permedia2TagStartY;
pBuffer[3] = INTtoFIXED(yCurrent);
iLen = *pStrips++;
pBuffer[4] = __Permedia2TagCount;
pBuffer[5] = iLen;
pBuffer[6] = __Permedia2TagRender;
pBuffer[7] = __RENDER_LINE_PRIMITIVE;
pBuffer += 8;
InputBufferCommit(ppdev, pBuffer);
xCurrent += iLen;
if ( yDir > 0 )
{
yCurrent += iLen - 1;
}
else
{
yCurrent -= iLen - 1;
}
if ( !(--cStrips) )
{
break;
}
}// while ( TRUE )
InputBufferReserve(ppdev, 6, &pBuffer);
pBuffer[0] = __Permedia2TagdXDom;
pBuffer[1] = 0;
pBuffer[2] = __Permedia2TagdXSub;
pBuffer[3] = 0;
pBuffer[4] = __Permedia2TagdY;
pBuffer[5] = INTtoFIXED(1);
pBuffer += 6;
InputBufferCommit(ppdev, pBuffer);
//
// Return last point.
//
pStrip->ptlStart.x = xCurrent;
pStrip->ptlStart.y = yCurrent;
DBG_GDI((STRIP_LOG_LEVEL + 1, "vSolidDiagonalHorizontalLine done"));
}// vSolidDiagonalHorizontalLine()
//-----------------------------------------------------------------------------
//
// VOID vStyledHorizontalLine()
//
// Takes the list of strips that define the pixels that would be lit for
// a solid line, and breaks them into styling chunks according to the
// styling information that is passed in.
//
// This particular routine handles x-major lines that run left-to-right,
// and are comprised of horizontal strips. It draws the dashes using
// short-stroke vectors.
//
// The performance of this routine could be improved significantly.
//
// Parameters
// ppdev-------PDEV pointer
// pStrip------Strip info. Note: the data in the strip are already in normal
// integer format, not 28.4 format
// pLineState--Line state info
//
//-----------------------------------------------------------------------------
VOID
vStyledHorizontalLine(PDev* ppdev,
STRIP* pStrip,
LINESTATE* pLineState)
{
LONG x;
LONG y;
LONG dy;
LONG* plStrip;
ULONG* pBuffer;
LONG lStripLength;
LONG lTotalNumOfStrips;
LONG lNumPixelRemain;
LONG lCurrentLength;
ULONG bIsGap;
PERMEDIA_DECL;
DBG_GDI((STRIP_LOG_LEVEL, "vStyledHorizontalLine"));
if ( pStrip->flFlips & FL_FLIP_V )
{
dy = -1;
}
else
{
dy = 1;
}
lTotalNumOfStrips = pStrip->cStrips;// Total number of strips we'll do
plStrip = pStrip->alStrips; // Points to current strip
x = pStrip->ptlStart.x; // x position of start of first strip
y = pStrip->ptlStart.y; // y position of start of first strip
//
// Set up the deltas for horizontal line drawing.
//
InputBufferReserve(ppdev, 4, &pBuffer);
pBuffer[0] = __Permedia2TagdXDom;
pBuffer[1] = INTtoFIXED(1);
pBuffer[2] = __Permedia2TagdY;
pBuffer[3] = 0;
pBuffer += 4;
InputBufferCommit(ppdev, pBuffer);
lStripLength = *plStrip; // Number of pixels in first strip
//
// Number of pixels in first strip
//
lNumPixelRemain = pLineState->spRemaining;
//
// ulStyleMask is non-zero if we're in the middle of a 'gap',
// and zero if we're in the middle of a 'dash':
//
bIsGap = pLineState->ulStyleMask;
if ( bIsGap )
{
//
// A gap
//
goto SkipAGap;
}
else
{
//
// A dash
//
goto OutputADash;
}
PrepareToSkipAGap:
//
// Advance in the style-state array, so that we can find the next
// 'dot' that we'll have to display:
//
bIsGap = ~bIsGap;
pLineState->psp++;
if ( pLineState->psp > pLineState->pspEnd )
{
pLineState->psp = pLineState->pspStart;
}
lNumPixelRemain = *pLineState->psp;
//
// If 'lStripLength' is zero, we also need a new strip:
//
if ( lStripLength != 0 )
{
goto SkipAGap;
}
//
// Here, we're in the middle of a 'gap' where we don't have to
// display anything. We simply cycle through all the strips
// we can, keeping track of the current position, until we run
// out of 'gap':
//
while ( TRUE )
{
//
// Each time we loop, we move to a new scan and need a new strip
//
y += dy;
plStrip++;
lTotalNumOfStrips--;
if ( lTotalNumOfStrips == 0 )
{
goto AllDone;
}
lStripLength = *plStrip;
SkipAGap:
lCurrentLength = min(lStripLength, lNumPixelRemain);
lNumPixelRemain -= lCurrentLength;
lStripLength -= lCurrentLength;
x += lCurrentLength;
if ( lNumPixelRemain == 0 )
{
goto PrepareToOutputADash;
}
}// while (TRUE)
PrepareToOutputADash:
//
// Advance in the style-state array, so that we can find the next
// 'dot' that we'll have to display:
//
bIsGap = ~bIsGap;
pLineState->psp++;
if ( pLineState->psp > pLineState->pspEnd )
{
pLineState->psp = pLineState->pspStart;
}
lNumPixelRemain = *pLineState->psp;
//
// If 'lStripLength' is zero, we also need a new strip.
//
if ( lStripLength != 0 )
{
//
// There's more to be done in the current strip, so set 'y'
// to be the current scan:
//
goto OutputADash;
}
while ( TRUE )
{
//
// Each time we loop, we move to a new scan and need a new strip:
//
y += dy;
plStrip++;
lTotalNumOfStrips--;
if ( lTotalNumOfStrips == 0 )
{
goto AllDone;
}
lStripLength = *plStrip;
OutputADash:
lCurrentLength = min(lStripLength, lNumPixelRemain);
lNumPixelRemain -= lCurrentLength;
lStripLength -= lCurrentLength;
//
// With Permedia2 we just download the lines to draw
//
InputBufferReserve(ppdev, 8, &pBuffer);
pBuffer[0] = __Permedia2TagStartXDom;
pBuffer[1] = INTtoFIXED(x);
pBuffer[2] = __Permedia2TagStartY;
pBuffer[3] = INTtoFIXED(y);
pBuffer[4] = __Permedia2TagCount;
pBuffer[5] = lCurrentLength;
pBuffer[6] = __Permedia2TagRender;
pBuffer[7] = __PERMEDIA_LINE_PRIMITIVE;
pBuffer += 8;
InputBufferCommit(ppdev, pBuffer);
x += lCurrentLength;
if ( lNumPixelRemain == 0 )
{
goto PrepareToSkipAGap;
}
}// while ( TRUE )
AllDone:
//
// Restore default state
//
InputBufferReserve(ppdev, 4, &pBuffer);
pBuffer[0] = __Permedia2TagdXDom;
pBuffer[1] = 0;
pBuffer[2] = __Permedia2TagdY;
pBuffer[3] = INTtoFIXED(1);
pBuffer += 4;
InputBufferCommit(ppdev, pBuffer);
//
// Update our state variables so that the next line can continue
// where we left off:
//
pLineState->spRemaining = lNumPixelRemain;
pLineState->ulStyleMask = bIsGap;
pStrip->ptlStart.x = x;
pStrip->ptlStart.y = y;
DBG_GDI((STRIP_LOG_LEVEL + 1, "vStyledHorizontalLine done"));
}// vStyledHorizontalLine()
//-----------------------------------------------------------------------------
//
// VOID vStripStyledVertical
//
// Takes the list of strips that define the pixels that would be lit for
// a solid line, and breaks them into styling chunks according to the
// styling information that is passed in.
//
// This particular routine handles y-major lines that run left-to-right,
// and are comprised of vertical strips. It draws the dashes using
// short-stroke vectors.
//
// The performance of this routine could be improved significantly.
//
//-----------------------------------------------------------------------------
VOID
vStyledVerticalLine(PDev* ppdev,
STRIP* pStrip,
LINESTATE* pLineState)
{
LONG x;
LONG y;
LONG dy;
LONG* plStrip;
LONG cStrips;
LONG cStyle;
LONG cStrip;
LONG cThis;
ULONG bIsGap;
ULONG* pBuffer;
PERMEDIA_DECL;
DBG_GDI((STRIP_LOG_LEVEL, "vStyledVerticalLine"));
//@@BEGIN_DDKSPLIT
//
// TODO: improve the performance of this routine
//
//@@END_DDKSPLIT
if ( pStrip->flFlips & FL_FLIP_V )
{
dy = -1;
}
else
{
dy = 1;
}
cStrips = pStrip->cStrips; // Total number of strips we'll do
plStrip = pStrip->alStrips; // Points to current strip
x = pStrip->ptlStart.x; // x position of start of first strip
y = pStrip->ptlStart.y; // y position of start of first strip
//
// Set up the deltas for vertical line drawing.
//
InputBufferReserve(ppdev, 6, &pBuffer);
pBuffer[0] = __Permedia2TagdXDom;
pBuffer[1] = INTtoFIXED(0);
pBuffer[2] = __Permedia2TagdXSub;
pBuffer[3] = INTtoFIXED(0);
pBuffer[4] = __Permedia2TagdY;
pBuffer[5] = INTtoFIXED(dy);
pBuffer += 6;
InputBufferCommit(ppdev, pBuffer);
cStrip = *plStrip; // Number of pels in first strip
cStyle = pLineState->spRemaining; // Number of pels in first 'gap' or 'dash'
bIsGap = pLineState->ulStyleMask; // Tells whether in a 'gap' or a 'dash'
// ulStyleMask is non-zero if we're in the middle of a 'gap',
// and zero if we're in the middle of a 'dash':
if ( bIsGap )
{
goto SkipAGap;
}
else
{
goto OutputADash;
}
PrepareToSkipAGap:
//
// Advance in the style-state array, so that we can find the next
// 'dot' that we'll have to display:
//
bIsGap = ~bIsGap;
pLineState->psp++;
if ( pLineState->psp > pLineState->pspEnd )
{
pLineState->psp = pLineState->pspStart;
}
cStyle = *pLineState->psp;
//
// If 'cStrip' is zero, we also need a new strip:
//
if ( cStrip != 0 )
{
goto SkipAGap;
}
//
// Here, we're in the middle of a 'gap' where we don't have to
// display anything. We simply cycle through all the strips
// we can, keeping track of the current position, until we run
// out of 'gap':
//
while ( TRUE )
{
//
// Each time we loop, we move to a new column and need a new strip:
//
x++;
plStrip++;
cStrips--;
if ( cStrips == 0 )
{
goto AllDone;
}
cStrip = *plStrip;
SkipAGap:
cThis = min(cStrip, cStyle);
cStyle -= cThis;
cStrip -= cThis;
y += (dy > 0) ? cThis : -cThis;
if ( cStyle == 0 )
{
goto PrepareToOutputADash;
}
}
PrepareToOutputADash:
//
// Advance in the style-state array, so that we can find the next
// 'dot' that we'll have to display:
//
bIsGap = ~bIsGap;
pLineState->psp++;
if ( pLineState->psp > pLineState->pspEnd )
{
pLineState->psp = pLineState->pspStart;
}
cStyle = *pLineState->psp;
//
// If 'cStrip' is zero, we also need a new strip.
//
if ( cStrip != 0 )
{
goto OutputADash;
}
while ( TRUE )
{
//
// Each time we loop, we move to a new column and need a new strip:
//
x++;
plStrip++;
cStrips--;
if ( cStrips == 0 )
{
goto AllDone;
}
cStrip = *plStrip;
OutputADash:
cThis = min(cStrip, cStyle);
cStyle -= cThis;
cStrip -= cThis;
//
// With Permedia2 we just download the lines to draw
//
InputBufferReserve(ppdev, 8, &pBuffer);
pBuffer[0] = __Permedia2TagStartXDom;
pBuffer[1] = INTtoFIXED(x);
pBuffer[2] = __Permedia2TagStartY;
pBuffer[3] = INTtoFIXED(y);
pBuffer[4] = __Permedia2TagCount;
pBuffer[5] = cThis;
pBuffer[6] = __Permedia2TagRender;
pBuffer[7] = __PERMEDIA_LINE_PRIMITIVE;
pBuffer += 8;
InputBufferCommit(ppdev, pBuffer);
y += (dy > 0) ? cThis : -cThis;
if ( cStyle == 0 )
{
goto PrepareToSkipAGap;
}
}// while ( TRUE )
AllDone:
//
// Restore hardware to default state
//
InputBufferReserve(ppdev, 2, &pBuffer);
pBuffer[0] = __Permedia2TagdY;
pBuffer[1] = INTtoFIXED(1);
pBuffer += 2;
InputBufferCommit(ppdev, pBuffer);
//
// Update our state variables so that the next line can continue
// where we left off:
//
pLineState->spRemaining = cStyle;
pLineState->ulStyleMask = bIsGap;
pStrip->ptlStart.x = x;
pStrip->ptlStart.y = y;
}// vStyledVerticalLine()
//
// For a given sub-pixel coordinate (x.m, y.n) in 28.4 fixed point
// format this array is indexed by (m,n) and indicates whether the
// given sub-pixel is within a GIQ diamond. m coordinates run left
// to right; n coordinates ru top to bottom so index the array with
// ((n<<4)+m). The array as seen here really contains 4 quarter
// diamonds.
//
static unsigned char in_diamond[] =
{
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
/* 0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0 */
/* 1 */ 1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1, /* 1 */
/* 2 */ 1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1, /* 2 */
/* 3 */ 1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1, /* 3 */
/* 4 */ 1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1, /* 4 */
/* 5 */ 1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1, /* 5 */
/* 6 */ 1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1, /* 6 */
/* 7 */ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7 */
/* 8 */ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8 */
/* 9 */ 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9 */
/* a */ 1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1, /* a */
/* b */ 1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1, /* b */
/* c */ 1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1, /* c */
/* d */ 1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1, /* d */
/* e */ 1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1, /* e */
/* f */ 1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1, /* f */
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
};
//
// For lines with abs(slope) != 1 use IN_DIAMOND to determine if an
// end point is in a diamond. For lines of slope = 1 use IN_S1DIAMOND.
// For lines of slope = -1 use IN_SM1DIAMOND. The last two are a bit
// strange. The documentation leaves us with a problem for slope 1
// lines which run exactly betwen the diamonds. According to the docs
// such a line can enter a diamond, leave it and enter again. This is
// plainly rubbish so along the appropriate edge of the diamond we
// consider a slope 1 line to be inside the diamond. This is the
// bottom right edge for lines of slope -1 and the bottom left edge for
// lines of slope 1.
//
#define IN_DIAMOND(m, n) (in_diamond[((m) << 4) + (n)])
#define IN_S1DIAMOND(m, n) ((in_diamond[((m) << 4) + (n)]) || \
((m) - (n) == 8))
#define IN_SM1DIAMOND(m, n) ((in_diamond[((m) << 4) + (n)]) || \
((m) + (n) == 8))
BOOL
bFastLine(PPDev ppdev,
LONG fx1,
LONG fy1,
LONG fx2,
LONG fy2)
{
register LONG adx, ady, tmp;
FIX m1, n1, m2, n2;
LONG dx, dy;
LONG dX, dY;
LONG count, startX, startY;
ULONG* pBuffer;
PERMEDIA_DECL;
DBG_GDI((STRIP_LOG_LEVEL, "bFastLine"));
//
// This function is only called if we have a line with non integer end points
// and the unsigned coordinates are no greater than 15.4.
//
// We can only guarantee to do lines whose coords need <= 12 bits
// of integer. This is because to get the delta we must shift
// by 16 bits. This includes 4 bits of fraction which means if
// we have more than 12 bits of integer we get overrun on the
// shift. We could use floating point to give us a better 16
// bits of integer but this requires an extra set of multiplies
// and divides in order to convert from 28.4 to fp. In any case
// we have to have a test to reject coords needing > 16 bits
// of integer.
// Actually, we can deal with 16.4 coordinates provided dx and dy
// never require more than 12 bits of integer.
// So optimise for the common case where the line is completely
// on the screen (actually 0 to 2047.f). Since the coords have
// 4 bits of fraction we note that a 32 bit signed number
// outside the range 0 to 2047.f will have one of its top 17
// bits set. So logical or all the coords and test against
// 0xffff8000. This is about as quick a test as we can get for
// both ends of the line being on the screen. If this test fails
// then we can check everything else at a leisurely pace.
//
//
// Get signed and absolute deltas
//
if ((adx = dx = fx2 - fx1) < 0)
{
adx = -adx;
}
if ((ady = dy = fy2 - fy1) < 0)
{
ady = -ady;
}
//
// Refuse to draw any lines whose delta is out of range.
// We have to shift the delta by 16, so we dont want to loose any precision
//
if ( (adx | ady) & 0xffff8000 )
{
return(FALSE);
}
//
// Fractional bits are used to check if point is in a diamond
//
m1 = fx1 & 0xf;
n1 = fy1 & 0xf;
m2 = fx2 & 0xf;
n2 = fy2 & 0xf;
//
// The rest of the code is a series of cases. Each one is "called" by a
// goto. This is simply to keep the nesting down. Main cases are: lines
// with absolute slope == 1; x-major lines; and y-major lines. We draw
// lines as they are given rather than always drawing in one direction.
// This adds extra code but saves the time required to swap the points
// and adjust for not drawing the end point.
//
startX = fx1 << 12;
startY = fy1 << 12;
DBG_GDI((7, "GDI Line %x, %x deltas %x, %x", startX, startY, dx, dy));
if ( adx < ady )
{
goto y_major;
}
if ( adx > ady )
{
goto x_major;
}
//
// All slope 1 lines are sampled in X. i.e. we move the start coord to
// an integer x and let Permedia2 truncate in y. This is because all GIQ
// lines are rounded down in y for values exactly half way between two
// pixels. If we sampled in y then we would have to round up in x for
// lines of slope 1 and round down in x for other lines. Sampling in x
// allows us to use the same Permedia2 bias in all cases (0x7fff). We do
// the x round up or down when we move the start point.
//
if ( dx != dy )
{
goto slope_minus_1;
}
if ( dx < 0 )
{
goto slope1_reverse;
}
dX = 1 << 16;
dY = 1 << 16;
if ( IN_S1DIAMOND(m1, n1) )
{
tmp = (startX + 0x8000) & ~0xffff;
}
else
{
tmp = (startX + 0xffff) & ~0xffff;
}
startY += tmp - startX;
startX = tmp;
if ( IN_S1DIAMOND(m2, n2) )
{
fx2 = (fx2 + 0x8) & ~0xf; // nearest integer
}
else
{
fx2 = (fx2 + 0xf) & ~0xf; // next integer
}
count = (fx2 >> 4) - (startX >> 16);
goto Draw_Line;
slope1_reverse:
dX = -1 << 16;
dY = -1 << 16;
if ( IN_S1DIAMOND(m1, n1) )
{
tmp = (startX + 0x8000) & ~0xffff;
}
else
{
tmp = startX & ~0xffff;
}
startY += tmp - startX;
startX = tmp;
if ( IN_S1DIAMOND(m2, n2) )
{
fx2 = (fx2 + 0x8) & ~0xf; // nearest integer
}
else
{
fx2 &= ~0xf; // previous integer
}
count = (startX >> 16) - (fx2 >> 4);
goto Draw_Line;
slope_minus_1:
if ( dx < 0 )
{
goto slope_minus_dx;
}
//
// dx > 0, dy < 0
//
dX = 1 << 16;
dY = -1 << 16;
if (IN_SM1DIAMOND(m1, n1))
{
tmp = (startX + 0x7fff) & ~0xffff;
}
else
{
tmp = (startX + 0xffff) & ~0xffff;
}
startY += startX - tmp;
startX = tmp;
if (IN_SM1DIAMOND(m2, n2))
{
fx2 = (fx2 + 0x7) & ~0xf; // nearest integer
}
else
{
fx2 = (fx2 + 0xf) & ~0xf; // next integer
}
count = (fx2 >> 4) - (startX >> 16);
goto Draw_Line;
slope_minus_dx:
dX = -1 << 16;
dY = 1 << 16;
if ( IN_SM1DIAMOND(m1, n1) )
{
tmp = (startX + 0x7fff) & ~0xffff;
}
else
{
tmp = startX & ~0xffff;
}
startY += startX - tmp;
startX = tmp;
if ( IN_SM1DIAMOND(m2, n2) )
{
fx2 = (fx2 + 0x7) & ~0xf; // nearest integer
}
else
{
fx2 &= ~0xf; // previous integer
}
count = (startX >> 16) - (fx2 >> 4);
goto Draw_Line;
x_major:
//
// Dont necessarily render through Permedia2 if we are worried about
// conformance.
//
if ( (adx > (MAX_LENGTH_CONFORMANT_NONINTEGER_LINES << 4))
&&(permediaInfo->flags & GLICAP_NT_CONFORMANT_LINES)
&&(ady != 0) )
{
return(FALSE);
}
if ( dx < 0 )
{
goto right_to_left_x;
}
//
// Line goes left to right. Round up the start x to an integer
// coordinate. This is the coord of the first diamond that the
// line crosses. Adjust start y to match this point on the line.
//
dX = 1 << 16;
if ( IN_DIAMOND(m1, n1) )
{
tmp = (startX + 0x7fff) & ~0xffff; // nearest integer
}
else
{
tmp = (startX + 0xffff) & ~0xffff; // next integer
}
//
// We can optimise for horizontal lines
//
if ( dy != 0 )
{
dY = dy << 16;
//
// Need to explicitly round delta down for -ve deltas.
//
if ( dy < 0 )
{
dY -= adx - 1;
}
dY /= adx;
startY += (((tmp - startX) >> 12) * dY) >> 4;
}
else
{
dY = 0;
}
startX = tmp;
if ( IN_DIAMOND(m2, n2) )
{
fx2 = (fx2 + 0x7) & ~0xf; // nearest integer
}
else
{
fx2 = (fx2 + 0xf) & ~0xf; // next integer
}
count = (fx2 >> 4) - (startX >> 16);
goto Draw_Line;
right_to_left_x:
dX = -1 << 16;
if ( IN_DIAMOND(m1, n1) )
{
tmp = (startX + 0x7fff) & ~0xffff; // nearest integer
}
else
{
tmp = startX & ~0xffff; // previous integer
}
//
// We can optimise for horizontal lines
//
if (dy != 0)
{
dY = dy << 16;
//
// Need to explicitly round delta down for -ve deltas.
//
if ( dy < 0 )
{
dY -= adx - 1;
}
dY /= adx;
startY += (((startX - tmp) >> 12) * dY) >> 4;
}
else
{
dY = 0;
}
startX = tmp;
if ( IN_DIAMOND(m2, n2) )
{
fx2 = (fx2 + 0x7) & ~0xf; // nearest integer
}
else
{
fx2 &= ~0xf; // previous integer
}
count = (startX >> 16) - (fx2 >> 4);
goto Draw_Line;
y_major:
//
// Dont necessarily render through Permedia2 if we are worried
// about conformance.
//
if ( (ady > (MAX_LENGTH_CONFORMANT_NONINTEGER_LINES << 4))
&&(permediaInfo->flags & GLICAP_NT_CONFORMANT_LINES)
&&(adx != 0) )
{
return(FALSE);
}
if ( dy < 0 )
{
goto high_to_low_y;
}
dY = 1 << 16;
if ( IN_DIAMOND(m1, n1) )
{
tmp = (startY + 0x7fff) & ~0xffff; // nearest integer
}
else
{
tmp = (startY + 0xffff) & ~0xffff; // next integer
}
//
// We can optimise for vertical lines
//
if ( dx != 0 )
{
dX = dx << 16;
//
// Need to explicitly round delta down for -ve deltas.
//
if ( dx < 0 )
{
dX -= ady - 1;
}
dX /= ady;
startX += (((tmp - startY) >> 12) * dX) >> 4;
}
else
{
dX = 0;
}
startY = tmp;
if ( IN_DIAMOND(m2, n2) )
{
fy2 = (fy2 + 0x7) & ~0xf; // nearest integer
}
else
{
fy2 = (fy2 + 0xf) & ~0xf; // next integer
}
count = (fy2 >> 4) - (startY >> 16);
goto Draw_Line;
high_to_low_y:
dY = -1 << 16;
if ( IN_DIAMOND(m1, n1) )
{
tmp = (startY + 0x7fff) & ~0xffff; // nearest integer
}
else
{
tmp = startY & ~0xffff; // previous integer
}
//
// We can optimise for horizontal lines
//
if ( dx != 0 )
{
dX = dx << 16;
//
// Need to explicitly round delta down for -ve deltas.
//
if ( dx < 0 )
{
dX -= ady - 1;
}
dX /= ady;
startX += (((startY - tmp) >> 12) * dX) >> 4;
}
else
{
dX = 0;
}
startY = tmp;
if ( IN_DIAMOND(m2, n2) )
{
fy2 = (fy2 + 0x7) & ~0xf; // nearest integer
}
else
{
fy2 &= ~0xf; // previous integer
}
count = (startY >> 16) - (fy2 >> 4);
Draw_Line:
//
// We need 6 fifo entries to draw a line
//
InputBufferReserve(ppdev, 16, &pBuffer);
DBG_GDI((7, "Line %x, %x deltas %x, %x Count %x",
startX + 0x7fff, startY + 0x7fff, dX, dY, count));
pBuffer[0] = __Permedia2TagStartXDom;
pBuffer[1] = startX + 0x7fff;
pBuffer[2] = __Permedia2TagStartY;
pBuffer[3] = startY + 0x7fff;
pBuffer[4] = __Permedia2TagdXDom;
pBuffer[5] = dX;
pBuffer[6] = __Permedia2TagdY;
pBuffer[7] = dY;
pBuffer[8] = __Permedia2TagCount;
pBuffer[9] = count;
pBuffer[10] = __Permedia2TagRender;
pBuffer[11] = __RENDER_LINE_PRIMITIVE;
//
// Restore default state
//
pBuffer[12] = __Permedia2TagdXDom;
pBuffer[13] = 0;
pBuffer[14] = __Permedia2TagdY;
pBuffer[15] = INTtoFIXED(1);
pBuffer += 16;
InputBufferCommit(ppdev, pBuffer);
return(TRUE);
}// bFastLine()