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.
1656 lines
45 KiB
1656 lines
45 KiB
/******************************Module*Header**********************************\
|
|
*
|
|
* *******************
|
|
* * GDI SAMPLE CODE *
|
|
* *******************
|
|
*
|
|
* Module Name: pxrxstrp.c
|
|
*
|
|
* Content:
|
|
*
|
|
//@@BEGIN_DDKSPLIT
|
|
* All the line code in this driver amounts to a big bag of dirt. Someday,
|
|
* I'm going to rewrite it all. Not today, though (sigh)...
|
|
* Original comment!. Rewritten for GLINT. Styled lines could do with more
|
|
* work, but Solid lines should be about as optimal as possible without
|
|
* rewriting the algorithm that calls these functions.
|
|
//@@END_DDKSPLIT
|
|
*
|
|
* Copyright (c) 1994-1999 3Dlabs Inc. Ltd. All rights reserved.
|
|
* Copyright (c) 1995-2003 Microsoft Corporation. All rights reserved.
|
|
\*****************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#include "pxrx.h"
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* BOOL pxrxInitStrips
|
|
*
|
|
\**************************************************************************/
|
|
BOOL pxrxInitStrips(
|
|
PPDEV ppdev,
|
|
ULONG ulColor,
|
|
DWORD logicOp,
|
|
RECTL *prclClip )
|
|
{
|
|
DWORD config2D;
|
|
BOOL bInvalidateScissor = FALSE;
|
|
GLINT_DECL;
|
|
|
|
VALIDATE_DD_CONTEXT;
|
|
|
|
SET_WRITE_BUFFERS;
|
|
|
|
WAIT_PXRX_DMA_TAGS( 7 );
|
|
|
|
if( logicOp == __GLINT_LOGICOP_COPY )
|
|
{
|
|
config2D = __CONFIG2D_CONSTANTSRC |
|
|
__CONFIG2D_FBWRITE;
|
|
}
|
|
else
|
|
{
|
|
config2D = __CONFIG2D_LOGOP_FORE(logicOp) |
|
|
__CONFIG2D_CONSTANTSRC |
|
|
__CONFIG2D_FBWRITE;
|
|
|
|
if( LogicopReadDest[logicOp] )
|
|
{
|
|
config2D |= __CONFIG2D_FBDESTREAD;
|
|
SET_READ_BUFFERS;
|
|
}
|
|
}
|
|
|
|
LOAD_FOREGROUNDCOLOUR( ulColor );
|
|
|
|
if( prclClip )
|
|
{
|
|
config2D |= __CONFIG2D_USERSCISSOR;
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagScissorMinXY,
|
|
MAKEDWORD_XY(prclClip->left, prclClip->top ) );
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagScissorMaxXY,
|
|
MAKEDWORD_XY(prclClip->right, prclClip->bottom) );
|
|
|
|
if(ppdev->cPelSize == GLINTDEPTH32)
|
|
{
|
|
bInvalidateScissor = TRUE;
|
|
}
|
|
}
|
|
|
|
LOAD_CONFIG2D( config2D );
|
|
|
|
SEND_PXRX_DMA_BATCH;
|
|
|
|
glintInfo->savedConfig2D = config2D;
|
|
glintInfo->savedLOP = logicOp;
|
|
glintInfo->savedCol = ulColor;
|
|
glintInfo->savedClip = prclClip;
|
|
|
|
DISPDBG((DBGLVL, "pxrxInitStrips done"));
|
|
return (bInvalidateScissor);
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* VOID pxrxResetStrips
|
|
*
|
|
\**************************************************************************/
|
|
VOID pxrxResetStrips(
|
|
PPDEV ppdev )
|
|
{
|
|
GLINT_DECL;
|
|
|
|
DISPDBG((DBGLVL, "pxrxResetStrips called"));
|
|
|
|
// Reset the scissor maximums:
|
|
WAIT_PXRX_DMA_TAGS( 1 );
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagScissorMaxXY, 0x7FFF7FFF );
|
|
SEND_PXRX_DMA_BATCH;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* VOID pxrxIntegerLine
|
|
*
|
|
\**************************************************************************/
|
|
BOOL pxrxIntegerLine(
|
|
PPDEV ppdev,
|
|
LONG X1,
|
|
LONG Y1,
|
|
LONG X2,
|
|
LONG Y2 )
|
|
{
|
|
LONG dx, dy, adx, ady;
|
|
GLINT_DECL;
|
|
|
|
// Convert points to INT format:
|
|
X1 >>= 4;
|
|
Y1 >>= 4;
|
|
X2 >>= 4;
|
|
Y2 >>= 4;
|
|
|
|
if( (adx = dx = X2 - X1) < 0 )
|
|
{
|
|
adx = -adx;
|
|
}
|
|
|
|
if( (ady = dy = Y2 - Y1) < 0 )
|
|
{
|
|
ady = -ady;
|
|
}
|
|
|
|
WAIT_PXRX_DMA_TAGS( 3+2 );
|
|
if( adx > ady )
|
|
{
|
|
// X major line:
|
|
if( ady == dy )
|
|
{
|
|
// +ve minor delta
|
|
if((ady) &&
|
|
(adx != ady) &&
|
|
(adx > MAX_LENGTH_CONFORMANT_P3_INTEGER_LINES_P) )
|
|
{
|
|
DISPDBG((DBGLVL, "pxrxIntegerLine failed"));
|
|
return FALSE;
|
|
}
|
|
|
|
DISPDBG((DBGLVL, "pxrxIntegerLine: [X +] delta = (%d, %d), "
|
|
"bias = (0x%08x)",
|
|
dx, dy, P3_LINES_BIAS_P));
|
|
|
|
QUEUE_PXRX_DMA_TAG( __DeltaTagYBias, P3_LINES_BIAS_P );
|
|
}
|
|
else
|
|
{
|
|
// -ve minor delta
|
|
if( (ady) &&
|
|
(adx != ady) &&
|
|
(adx > MAX_LENGTH_CONFORMANT_P3_INTEGER_LINES_N) )
|
|
{
|
|
DISPDBG((DBGLVL, "pxrxIntegerLine failed"));
|
|
return FALSE;
|
|
}
|
|
|
|
DISPDBG((DBGLVL, "pxrxIntegerLine: [X -] delta = (%d, %d), "
|
|
"bias = (0x%08x)",
|
|
dx, dy, P3_LINES_BIAS_N));
|
|
|
|
QUEUE_PXRX_DMA_TAG( __DeltaTagYBias, P3_LINES_BIAS_N );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Y major line:
|
|
if( adx == dx )
|
|
{
|
|
// +ve minor delta
|
|
if( (adx) &&
|
|
(adx != ady) &&
|
|
(ady > MAX_LENGTH_CONFORMANT_P3_INTEGER_LINES_P) )
|
|
{
|
|
DISPDBG((DBGLVL, "pxrxIntegerLine failed"));
|
|
return FALSE;
|
|
}
|
|
|
|
DISPDBG((DBGLVL, "pxrxIntegerLine: [Y +] delta = (%d, %d), "
|
|
"bias = (0x%08x)",
|
|
dx, dy, P3_LINES_BIAS_P));
|
|
|
|
QUEUE_PXRX_DMA_TAG( __DeltaTagXBias, P3_LINES_BIAS_P );
|
|
}
|
|
else
|
|
{
|
|
// -ve minor delta
|
|
if( (adx) &&
|
|
(adx != ady) &&
|
|
(ady > MAX_LENGTH_CONFORMANT_P3_INTEGER_LINES_N) )
|
|
{
|
|
DISPDBG((DBGLVL, "pxrxIntegerLine failed"));
|
|
return FALSE;
|
|
}
|
|
|
|
DISPDBG((DBGLVL, "pxrxIntegerLine: [Y -] delta = (%d, %d), "
|
|
"bias = (0x%08x)",
|
|
dx, dy, P3_LINES_BIAS_N));
|
|
|
|
QUEUE_PXRX_DMA_TAG( __DeltaTagXBias, P3_LINES_BIAS_N );
|
|
}
|
|
}
|
|
|
|
QUEUE_PXRX_DMA_INDEX3( __DeltaTagLineCoord0,
|
|
__DeltaTagLineCoord1,
|
|
__DeltaTagDrawLine2D01 );
|
|
|
|
QUEUE_PXRX_DMA_DWORD( MAKEDWORD_XY(X1, Y1) );
|
|
QUEUE_PXRX_DMA_DWORD( MAKEDWORD_XY(X2, Y2) );
|
|
QUEUE_PXRX_DMA_DWORD( 0 );
|
|
|
|
SEND_PXRX_DMA_BATCH;
|
|
|
|
glintInfo->lastLine = 1;
|
|
|
|
DISPDBG((DBGLVL, "pxrxIntegerLine done"));
|
|
return TRUE;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* BOOL pxrxContinueLine
|
|
*
|
|
\**************************************************************************/
|
|
BOOL pxrxContinueLine(
|
|
PPDEV ppdev,
|
|
LONG X1,
|
|
LONG Y1,
|
|
LONG X2,
|
|
LONG Y2 )
|
|
{
|
|
LONG dx, dy, adx, ady;
|
|
GLINT_DECL;
|
|
|
|
// Convert points to INT format:
|
|
X1 >>= 4;
|
|
Y1 >>= 4;
|
|
X2 >>= 4;
|
|
Y2 >>= 4;
|
|
|
|
if( (adx = dx = X2 - X1) < 0 )
|
|
{
|
|
adx = -adx;
|
|
}
|
|
|
|
if( (ady = dy = Y2 - Y1) < 0 )
|
|
{
|
|
ady = -ady;
|
|
}
|
|
|
|
WAIT_PXRX_DMA_TAGS( 3+2 );
|
|
|
|
if( adx > ady )
|
|
{
|
|
// X major line:
|
|
if( ady == dy )
|
|
{
|
|
// +ve minor delta
|
|
if( (ady) &&
|
|
(adx != ady) &&
|
|
(adx > MAX_LENGTH_CONFORMANT_P3_INTEGER_LINES_P) )
|
|
{
|
|
DISPDBG((DBGLVL, "pxrxContinueLine failed"));
|
|
return FALSE;
|
|
}
|
|
|
|
DISPDBG((DBGLVL, "pxrxContinueLine: delta = (%d, %d), "
|
|
"bias = (0x%08x), last = %d",
|
|
dx, dy, P3_LINES_BIAS_P, glintInfo->lastLine));
|
|
|
|
QUEUE_PXRX_DMA_TAG( __DeltaTagYBias, P3_LINES_BIAS_P );
|
|
}
|
|
else
|
|
{
|
|
// -ve minor delta
|
|
if( (ady) &&
|
|
(adx != ady) &&
|
|
(adx > MAX_LENGTH_CONFORMANT_P3_INTEGER_LINES_N) )
|
|
{
|
|
DISPDBG((DBGLVL, "pxrxContinueLine failed"));
|
|
return FALSE;
|
|
}
|
|
|
|
DISPDBG((DBGLVL, "pxrxContinueLine: delta = (%d, %d), "
|
|
"bias = (0x%08x), last = %d",
|
|
dx, dy, P3_LINES_BIAS_N, glintInfo->lastLine));
|
|
|
|
QUEUE_PXRX_DMA_TAG( __DeltaTagYBias, P3_LINES_BIAS_N );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Y major line:
|
|
if( adx == dx )
|
|
{
|
|
// +ve minor delta
|
|
if( (adx) &&
|
|
(adx != ady) &&
|
|
(ady > MAX_LENGTH_CONFORMANT_P3_INTEGER_LINES_P) )
|
|
{
|
|
DISPDBG((DBGLVL, "pxrxContinueLine failed"));
|
|
return FALSE;
|
|
}
|
|
|
|
DISPDBG((DBGLVL, "pxrxContinueLine: delta = (%d, %d), "
|
|
"bias = (0x%08x), last = %d",
|
|
dx, dy, P3_LINES_BIAS_P, glintInfo->lastLine));
|
|
|
|
QUEUE_PXRX_DMA_TAG( __DeltaTagXBias, P3_LINES_BIAS_P );
|
|
}
|
|
else
|
|
{
|
|
// -ve minor delta
|
|
if( (adx) &&
|
|
(adx != ady) &&
|
|
(ady > MAX_LENGTH_CONFORMANT_P3_INTEGER_LINES_N) )
|
|
{
|
|
DISPDBG((DBGLVL, "pxrxContinueLine failed"));
|
|
return FALSE;
|
|
}
|
|
|
|
DISPDBG((DBGLVL, "pxrxContinueLine: delta = (%d, %d), "
|
|
"bias = (0x%08x), last = %d",
|
|
dx, dy, P3_LINES_BIAS_N, glintInfo->lastLine));
|
|
|
|
QUEUE_PXRX_DMA_TAG( __DeltaTagXBias, P3_LINES_BIAS_N );
|
|
}
|
|
}
|
|
|
|
if( glintInfo->lastLine == 0 )
|
|
{
|
|
QUEUE_PXRX_DMA_INDEX2( __DeltaTagLineCoord1,
|
|
__DeltaTagDrawLine2D01 );
|
|
QUEUE_PXRX_DMA_DWORD( MAKEDWORD_XY(X2, Y2) );
|
|
QUEUE_PXRX_DMA_DWORD( 0 );
|
|
glintInfo->lastLine = 1;
|
|
}
|
|
else if( glintInfo->lastLine == 1 )
|
|
{
|
|
QUEUE_PXRX_DMA_INDEX2( __DeltaTagLineCoord0,
|
|
__DeltaTagDrawLine2D10 );
|
|
QUEUE_PXRX_DMA_DWORD( MAKEDWORD_XY(X2, Y2) );
|
|
QUEUE_PXRX_DMA_DWORD( 0 );
|
|
glintInfo->lastLine = 0;
|
|
}
|
|
else
|
|
{
|
|
// lastline == 2
|
|
QUEUE_PXRX_DMA_INDEX3( __DeltaTagLineCoord0,
|
|
__DeltaTagLineCoord1,
|
|
__DeltaTagDrawLine2D01 );
|
|
QUEUE_PXRX_DMA_DWORD( MAKEDWORD_XY(X1, Y1) );
|
|
QUEUE_PXRX_DMA_DWORD( MAKEDWORD_XY(X2, Y2) );
|
|
QUEUE_PXRX_DMA_DWORD( 0 );
|
|
|
|
glintInfo->lastLine = 1;
|
|
}
|
|
|
|
SEND_PXRX_DMA_BATCH;
|
|
|
|
DISPDBG((DBGLVL, "pxrxContinueLine done"));
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vPXRXSolidHorizontalLine
|
|
*
|
|
* Draws left-to-right x-major near-horizontal lines using short-stroke
|
|
* vectors.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vPXRXSolidHorizontalLine(
|
|
PDEV *ppdev,
|
|
STRIP *pStrip,
|
|
LINESTATE *pLineState )
|
|
{
|
|
LONG cStrips;
|
|
PLONG pStrips;
|
|
LONG iCurrent;
|
|
GLINT_DECL;
|
|
|
|
cStrips = pStrip->cStrips;
|
|
|
|
WAIT_PXRX_DMA_TAGS( 10 );
|
|
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagdXDom, 0 );
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagdXSub, 0 );
|
|
|
|
// Set up the start point
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagStartXDom, INTtoFIXED(pStrip->ptlStart.x) );
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagStartY, INTtoFIXED(pStrip->ptlStart.y) );
|
|
|
|
// Set up the deltas for rectangle drawing. Also set Y return value.
|
|
if( !(pStrip->flFlips & FL_FLIP_V) )
|
|
{
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagdY, INTtoFIXED(1) );
|
|
pStrip->ptlStart.y += cStrips;
|
|
}
|
|
else
|
|
{
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagdY, 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
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagStartXSub, INTtoFIXED(iCurrent) );
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagCount, 1 );// Rectangle 1 scanline high
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagRender, __RENDER_TRAPEZOID_PRIMITIVE );
|
|
|
|
if( --cStrips )
|
|
{
|
|
while( cStrips > 1 )
|
|
{
|
|
// First strip of each pair to fill. XSub is valid. Need new Xdom
|
|
iCurrent += *pStrips++;
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagStartXDom, INTtoFIXED(iCurrent) );
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagContinueNewDom, 1 );
|
|
|
|
WAIT_PXRX_DMA_TAGS( 2 + 2 );
|
|
|
|
// Second strip of each pair to fill. XDom is valid. Need new XSub
|
|
iCurrent += *pStrips++;
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagStartXSub, INTtoFIXED(iCurrent) );
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagContinueNewSub, 1 );
|
|
|
|
cStrips -=2;
|
|
}
|
|
|
|
// We may have one last line to draw. Xsub will be valid.
|
|
if( cStrips )
|
|
{
|
|
iCurrent += *pStrips++;
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagStartXDom, INTtoFIXED(iCurrent) );
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagContinueNewDom, 1 );
|
|
}
|
|
}
|
|
|
|
SEND_PXRX_DMA_BATCH;
|
|
|
|
// Return last point. Y already calculated when we knew the direction.
|
|
pStrip->ptlStart.x = iCurrent;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vPXRXSolidVertical
|
|
*
|
|
* Draws left-to-right y-major near-vertical lines using short-stroke
|
|
* vectors.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vPXRXSolidVerticalLine(
|
|
PDEV *ppdev,
|
|
STRIP *pStrip,
|
|
LINESTATE *pLineState )
|
|
{
|
|
LONG cStrips, yDir;
|
|
PLONG pStrips;
|
|
LONG iCurrent, iLen, iLenSum;
|
|
GLINT_DECL;
|
|
|
|
cStrips = pStrip->cStrips;
|
|
|
|
WAIT_PXRX_DMA_TAGS( 10 );
|
|
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagdXDom, 0 );
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagdXSub, 0 );
|
|
|
|
// Set up the start point
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagStartXDom, INTtoFIXED(pStrip->ptlStart.x) );
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagStartY, INTtoFIXED(pStrip->ptlStart.y) );
|
|
|
|
// Set up the deltas for rectangle drawing.
|
|
if( !(pStrip->flFlips & FL_FLIP_V) )
|
|
{
|
|
yDir = 1;
|
|
}
|
|
else
|
|
{
|
|
yDir = -1;
|
|
}
|
|
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagdY, 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++);
|
|
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagStartXSub, INTtoFIXED(iCurrent) );
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagCount, iLen ); // Rectangle 1 scanline high
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagRender, __RENDER_TRAPEZOID_PRIMITIVE );
|
|
|
|
if( --cStrips )
|
|
{
|
|
while( cStrips > 1 )
|
|
{
|
|
// First strip of each pair to fill. XSub is valid. Need new Xdom
|
|
iCurrent++;
|
|
iLenSum += (iLen = *pStrips++);
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagStartXDom, INTtoFIXED(iCurrent) );
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagContinueNewDom, iLen );
|
|
|
|
WAIT_PXRX_DMA_TAGS( 2 + 2 );
|
|
|
|
// Second strip of each pair to fill. XDom is valid. Need new XSub
|
|
iCurrent++;
|
|
iLenSum += (iLen = *pStrips++);
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagStartXSub, INTtoFIXED(iCurrent) );
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagContinueNewSub, iLen );
|
|
cStrips -=2;
|
|
}
|
|
|
|
// We may have one last line to draw. Xsub will be valid.
|
|
if( cStrips )
|
|
{
|
|
iCurrent++;
|
|
iLenSum += (iLen = *pStrips++);
|
|
QUEUE_PXRX_DMA_TAG(__GlintTagStartXDom, INTtoFIXED(iCurrent));
|
|
QUEUE_PXRX_DMA_TAG(__GlintTagContinueNewDom, iLen);
|
|
}
|
|
}
|
|
|
|
SEND_PXRX_DMA_BATCH;
|
|
|
|
// Return last point.
|
|
pStrip->ptlStart.x = iCurrent;
|
|
pStrip->ptlStart.y += iLenSum * yDir;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vPXRXSolidDiagonalVertical
|
|
*
|
|
* Draws left-to-right y-major near-diagonal lines using short-stroke
|
|
* vectors.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vPXRXSolidDiagonalVerticalLine(
|
|
PDEV *ppdev,
|
|
STRIP *pStrip,
|
|
LINESTATE *pLineState )
|
|
{
|
|
LONG cStrips, yDir;
|
|
PLONG pStrips;
|
|
LONG iCurrent, iLen, iLenSum;
|
|
GLINT_DECL;
|
|
|
|
cStrips = pStrip->cStrips;
|
|
|
|
if( !(pStrip->flFlips & FL_FLIP_V) )
|
|
{
|
|
yDir = 1;
|
|
}
|
|
else
|
|
{
|
|
yDir = -1;
|
|
}
|
|
|
|
WAIT_PXRX_DMA_TAGS( 10 );
|
|
|
|
// Set up the deltas for rectangle drawing.
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagdXDom, INTtoFIXED(1) );
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagdXSub, INTtoFIXED(1) );
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagdY, 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
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagStartY, INTtoFIXED(pStrip->ptlStart.y) );
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagStartXDom, INTtoFIXED(pStrip->ptlStart.x+1) );
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagStartXSub, INTtoFIXED(pStrip->ptlStart.x) );
|
|
|
|
iLenSum = (iLen = *pStrips++);
|
|
iCurrent = pStrip->ptlStart.x + iLen - 1; // Start of next strip
|
|
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagCount, iLen); // Trap iLen scanline high
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagRender, __RENDER_TRAPEZOID_PRIMITIVE);
|
|
|
|
if( --cStrips )
|
|
{
|
|
while( cStrips > 1 )
|
|
{
|
|
// First strip of each pair to fill. XSub is valid. Need new Xdom
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagStartXDom, INTtoFIXED(iCurrent) );
|
|
iLenSum += (iLen = *pStrips++);
|
|
iCurrent += iLen - 1;
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagContinueNewDom, iLen );
|
|
|
|
WAIT_PXRX_DMA_TAGS( 2 + 2 );
|
|
|
|
// Second strip of each pair to fill. XDom is valid. Need new XSub
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagStartXSub, INTtoFIXED(iCurrent) );
|
|
iLenSum += (iLen = *pStrips++);
|
|
iCurrent += iLen - 1;
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagContinueNewSub, iLen );
|
|
|
|
cStrips -=2;
|
|
}
|
|
|
|
// We may have one last line to draw. Xsub will be valid.
|
|
if (cStrips)
|
|
{
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagStartXDom, INTtoFIXED(iCurrent) );
|
|
iLenSum += (iLen = *pStrips++);
|
|
iCurrent += iLen - 1;
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagContinueNewDom, iLen );
|
|
}
|
|
}
|
|
|
|
SEND_PXRX_DMA_BATCH;
|
|
|
|
// Return last point.
|
|
pStrip->ptlStart.x = iCurrent;
|
|
pStrip->ptlStart.y += iLenSum * yDir;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vPXRXSolidDiagonalHorizontalLine
|
|
*
|
|
* Draws left-to-right x-major near-diagonal lines using short-stroke
|
|
* vectors.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vPXRXSolidDiagonalHorizontalLine(
|
|
PDEV *ppdev,
|
|
STRIP *pStrip,
|
|
LINESTATE *pLineState )
|
|
{
|
|
LONG cStrips, yDir, xCurrent, yCurrent, iLen;
|
|
PLONG pStrips;
|
|
GLINT_DECL;
|
|
|
|
// 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;
|
|
|
|
WAIT_PXRX_DMA_TAGS( 3 + 4 );
|
|
|
|
// Set up the deltas for rectangle drawing.
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagdXDom, INTtoFIXED(1) );
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagdXSub, INTtoFIXED(1) );
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagdY, INTtoFIXED(yDir) );
|
|
|
|
while( TRUE )
|
|
{
|
|
// Set up the start point
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagStartXDom, INTtoFIXED(xCurrent) );
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagStartY, INTtoFIXED(yCurrent) );
|
|
|
|
iLen = *pStrips++;
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagCount, iLen );
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagRender, __RENDER_LINE_PRIMITIVE );
|
|
|
|
xCurrent += iLen;
|
|
if( yDir > 0 )
|
|
{
|
|
yCurrent += iLen - 1;
|
|
}
|
|
else
|
|
{
|
|
yCurrent -= iLen - 1;
|
|
}
|
|
|
|
if( !(--cStrips) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
WAIT_PXRX_DMA_TAGS( 4 );
|
|
}
|
|
|
|
SEND_PXRX_DMA_BATCH;
|
|
|
|
// Return last point.
|
|
pStrip->ptlStart.x = xCurrent;
|
|
pStrip->ptlStart.y = yCurrent;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vPXRXStyledHorizontal
|
|
*
|
|
* 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 if
|
|
* anyone cared enough about styled lines improve it.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vPXRXStyledHorizontalLine(
|
|
PDEV *ppdev,
|
|
STRIP *pstrip,
|
|
LINESTATE *pls )
|
|
{
|
|
LONG x;
|
|
LONG y;
|
|
LONG dy;
|
|
LONG* plStrip;
|
|
LONG cStrips;
|
|
LONG cStyle;
|
|
LONG cStrip;
|
|
LONG cThis;
|
|
ULONG bIsGap;
|
|
GLINT_DECL;
|
|
|
|
//@@BEGIN_DDKSPLIT
|
|
// This routine does some quite complex things with patterns. For ease of
|
|
// implementation on GLINT, I have just changed the relevant parts. This,
|
|
// therefore, is definitly not an optimal solution. However, styled lines
|
|
// are really not that important. If anyone feels inclined to do more work
|
|
// here, then fine! XXXX
|
|
//@@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 horizontal line drawing.
|
|
WAIT_PXRX_DMA_TAGS( 2 );
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagdXDom, INTtoFIXED(1) );
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagdY, 0 );
|
|
|
|
cStrip = *plStrip; // Number of pels in first strip
|
|
|
|
cStyle = pls->spRemaining; // Number of pels in first 'gap' or 'dash'
|
|
bIsGap = pls->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;
|
|
pls->psp++;
|
|
if (pls->psp > pls->pspEnd)
|
|
{
|
|
pls->psp = pls->pspStart;
|
|
}
|
|
|
|
cStyle = *pls->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 scan and need a new strip:
|
|
|
|
y += dy;
|
|
|
|
plStrip++;
|
|
cStrips--;
|
|
if (cStrips == 0)
|
|
{
|
|
goto AllDone;
|
|
}
|
|
|
|
cStrip = *plStrip;
|
|
|
|
SkipAGap:
|
|
|
|
cThis = min(cStrip, cStyle);
|
|
cStyle -= cThis;
|
|
cStrip -= cThis;
|
|
|
|
x += 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;
|
|
pls->psp++;
|
|
if (pls->psp > pls->pspEnd)
|
|
{
|
|
pls->psp = pls->pspStart;
|
|
}
|
|
|
|
cStyle = *pls->psp;
|
|
|
|
// If 'cStrip' is zero, we also need a new strip.
|
|
|
|
if (cStrip != 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++;
|
|
cStrips--;
|
|
if( cStrips == 0 )
|
|
{
|
|
goto AllDone;
|
|
}
|
|
|
|
cStrip = *plStrip;
|
|
|
|
OutputADash:
|
|
|
|
cThis = min(cStrip, cStyle);
|
|
cStyle -= cThis;
|
|
cStrip -= cThis;
|
|
|
|
// With glint we just download the lines to draw
|
|
|
|
WAIT_PXRX_DMA_TAGS( 4 );
|
|
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagStartXDom, INTtoFIXED(x) );
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagStartY, INTtoFIXED(y) );
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagCount, cThis );
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagRender, __GLINT_LINE_PRIMITIVE );
|
|
|
|
x += cThis;
|
|
|
|
if( cStyle == 0 )
|
|
{
|
|
goto PrepareToSkipAGap;
|
|
}
|
|
}
|
|
|
|
AllDone:
|
|
|
|
SEND_PXRX_DMA_BATCH;
|
|
|
|
// Update our state variables so that the next line can continue
|
|
// where we left off:
|
|
|
|
pls->spRemaining = cStyle;
|
|
pls->ulStyleMask = bIsGap;
|
|
pstrip->ptlStart.x = x;
|
|
pstrip->ptlStart.y = y;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vPXRXStyledVertical
|
|
*
|
|
* 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 if
|
|
* anyone cared enough about styled lines improve it.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vPXRXStyledVerticalLine(
|
|
PDEV *ppdev,
|
|
STRIP *pstrip,
|
|
LINESTATE *pls )
|
|
{
|
|
LONG x;
|
|
LONG y;
|
|
LONG dy;
|
|
LONG* plStrip;
|
|
LONG cStrips;
|
|
LONG cStyle;
|
|
LONG cStrip;
|
|
LONG cThis;
|
|
ULONG bIsGap;
|
|
GLINT_DECL;
|
|
|
|
//@@BEGIN_DDKSPLIT
|
|
// This routine does some quite complex things with patterns. For ease of
|
|
// implemantation on GLINT, I have just changed the relevant parts. This,
|
|
// therefore, is definitly not an optimal solution. However, styled lines
|
|
// are really not that important. If anyone feels inclined to do more work
|
|
// here, then fine! XXXX
|
|
//@@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.
|
|
WAIT_PXRX_DMA_TAGS( 2 );
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagdXDom, 0 );
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagdY, INTtoFIXED(dy) );
|
|
|
|
// dxDom and dXSub are initialised to 0, 0, so
|
|
// we don't need to re-load them here.
|
|
|
|
cStrip = *plStrip; // Number of pels in first strip
|
|
|
|
cStyle = pls->spRemaining; // Number of pels in first 'gap' or 'dash'
|
|
bIsGap = pls->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;
|
|
pls->psp++;
|
|
if (pls->psp > pls->pspEnd)
|
|
{
|
|
pls->psp = pls->pspStart;
|
|
}
|
|
|
|
cStyle = *pls->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;
|
|
pls->psp++;
|
|
if (pls->psp > pls->pspEnd)
|
|
{
|
|
pls->psp = pls->pspStart;
|
|
}
|
|
|
|
cStyle = *pls->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 glint we just download the lines to draw
|
|
|
|
WAIT_PXRX_DMA_TAGS( 4 );
|
|
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagStartXDom, INTtoFIXED(x) );
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagStartY, INTtoFIXED(y) );
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagCount, cThis );
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagRender, __GLINT_LINE_PRIMITIVE );
|
|
|
|
y += (dy > 0) ? cThis : -cThis;
|
|
|
|
if( cStyle == 0 )
|
|
{
|
|
goto PrepareToSkipAGap;
|
|
}
|
|
}
|
|
|
|
AllDone:
|
|
|
|
SEND_PXRX_DMA_BATCH;
|
|
|
|
// Update our state variables so that the next line can continue
|
|
// where we left off:
|
|
pls->spRemaining = cStyle;
|
|
pls->ulStyleMask = bIsGap;
|
|
pstrip->ptlStart.x = x;
|
|
pstrip->ptlStart.y = y;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* 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 pxrxDrawLine
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL pxrxDrawLine(
|
|
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;
|
|
GLINT_DECL;
|
|
|
|
// 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;
|
|
|
|
DISPDBG((DBGLVL, "GDI Line %x, %x deltas %x, %x",
|
|
startX, startY, dx, dy));
|
|
|
|
if (adx < ady)
|
|
{
|
|
goto y_major;
|
|
}
|
|
|
|
if (adx > ady)
|
|
{
|
|
goto x_major;
|
|
}
|
|
|
|
|
|
//slope1_line:
|
|
|
|
// All slope 1 lines are sampled in X. i.e. we move the start coord to
|
|
// an integer x and let GLINT 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 GLINT 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 glint if we are worried
|
|
// about conformance.
|
|
if ((adx > (MAX_LENGTH_CONFORMANT_NONINTEGER_LINES << 4)) &&
|
|
(glintInfo->flags & GLICAP_NT_CONFORMANT_LINES) &&
|
|
(ady != 0))
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
if (dx < 0)
|
|
{
|
|
goto right_to_left_x;
|
|
}
|
|
|
|
// left_to_right_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 glint if we are worried
|
|
// about conformance.
|
|
if ((ady > (MAX_LENGTH_CONFORMANT_NONINTEGER_LINES << 4)) &&
|
|
(glintInfo->flags & GLICAP_NT_CONFORMANT_LINES) &&
|
|
(adx != 0))
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
if (dy < 0)
|
|
{
|
|
goto high_to_low_y;
|
|
}
|
|
|
|
// low_to_high_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:
|
|
WAIT_PXRX_DMA_TAGS( 6 );
|
|
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagStartXDom, startX + 0x7fff );
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagStartY, startY + 0x7fff );
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagdXDom, dX );
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagdY, dY );
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagCount, count );
|
|
QUEUE_PXRX_DMA_TAG( __GlintTagRender, __RENDER_LINE_PRIMITIVE );
|
|
|
|
SEND_PXRX_DMA_BATCH;
|
|
|
|
return TRUE;
|
|
}
|