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.
 
 
 
 
 
 

817 lines
31 KiB

///////////////////////////////////////////////////////////////////////////////
// Copyright (C) Microsoft Corporation, 1998.
//
// setup.cpp
//
// Direct3D Reference Rasterizer - Primitive Setup
//
///////////////////////////////////////////////////////////////////////////////
#include "pch.cpp"
#pragma hdrstop
//-----------------------------------------------------------------------------
//
// SetPrimitiveAttributeFunctions - Common routine to compute attribute
// functions used for triangles, lines, and points. (This could be done more
// efficiently for lines and points...).
//
//-----------------------------------------------------------------------------
void
ReferenceRasterizer::SetPrimitiveAttributeFunctions(
const RRFVFExtractor& Vtx0,
const RRFVFExtractor& Vtx1,
const RRFVFExtractor& Vtx2,
const RRFVFExtractor& VtxFlat )
{
// compute depth function
m_pSCS->AttribFuncs[ATTRFUNC_Z].SetLinearFunc( Vtx0.GetZ(), Vtx1.GetZ(), Vtx2.GetZ() );
// compute depth range for primitive (needed because we may sample slightly outside
// the primitive when antialiasing which is generally OK for color and texture indices
// but not for depth buffering)
if ( D3DZB_USEW == m_dwRenderState[D3DRENDERSTATE_ZENABLE] )
{
// using W for depth buffering
FLOAT fW0 = 1./Vtx0.GetRHW();
FLOAT fW1 = 1./Vtx1.GetRHW();
FLOAT fW2 = 1./Vtx2.GetRHW();
m_pSCS->fDepthMin = MIN( fW0, fW1 );
m_pSCS->fDepthMin = MIN( m_pSCS->fDepthMin, fW2 );
m_pSCS->fDepthMax = MAX( fW0, fW1 );
m_pSCS->fDepthMax = MAX( m_pSCS->fDepthMax, fW2 );
}
else
{
// using Z for depth buffering
m_pSCS->fDepthMin = MIN( Vtx0.GetZ(), Vtx1.GetZ() );
m_pSCS->fDepthMin = MIN( m_pSCS->fDepthMin, Vtx2.GetZ() );
m_pSCS->fDepthMax = MAX( Vtx0.GetZ(), Vtx1.GetZ() );
m_pSCS->fDepthMax = MAX( m_pSCS->fDepthMax, Vtx2.GetZ() );
}
// compute diffuse color functions
if ( D3DSHADE_FLAT != m_dwRenderState[D3DRENDERSTATE_SHADEMODE] )
{
RRColor VtxColor0( Vtx0.GetDiffuse() );
RRColor VtxColor1( Vtx1.GetDiffuse() );
RRColor VtxColor2( Vtx2.GetDiffuse() );
m_pSCS->AttribFuncs[ATTRFUNC_R].SetPerspFunc( VtxColor0.R, VtxColor1.R, VtxColor2.R );
m_pSCS->AttribFuncs[ATTRFUNC_G].SetPerspFunc( VtxColor0.G, VtxColor1.G, VtxColor2.G );
m_pSCS->AttribFuncs[ATTRFUNC_B].SetPerspFunc( VtxColor0.B, VtxColor1.B, VtxColor2.B );
m_pSCS->AttribFuncs[ATTRFUNC_A].SetPerspFunc( VtxColor0.A, VtxColor1.A, VtxColor2.A );
}
else
{
RRColor VtxColor0( VtxFlat.GetDiffuse() );
m_pSCS->AttribFuncs[ATTRFUNC_R].SetConstant( VtxColor0.R );
m_pSCS->AttribFuncs[ATTRFUNC_G].SetConstant( VtxColor0.G );
m_pSCS->AttribFuncs[ATTRFUNC_B].SetConstant( VtxColor0.B );
m_pSCS->AttribFuncs[ATTRFUNC_A].SetConstant( VtxColor0.A );
}
// compute specular functions
if ( m_qwFVFControl & D3DFVF_SPECULAR )
{
if ( D3DSHADE_FLAT != m_dwRenderState[D3DRENDERSTATE_SHADEMODE] )
{
RRColor VtxSpecular0( Vtx0.GetSpecular() );
RRColor VtxSpecular1( Vtx1.GetSpecular() );
RRColor VtxSpecular2( Vtx2.GetSpecular() );
m_pSCS->AttribFuncs[ATTRFUNC_SR].SetPerspFunc( VtxSpecular0.R, VtxSpecular1.R, VtxSpecular2.R );
m_pSCS->AttribFuncs[ATTRFUNC_SG].SetPerspFunc( VtxSpecular0.G, VtxSpecular1.G, VtxSpecular2.G );
m_pSCS->AttribFuncs[ATTRFUNC_SB].SetPerspFunc( VtxSpecular0.B, VtxSpecular1.B, VtxSpecular2.B );
m_pSCS->AttribFuncs[ATTRFUNC_SA].SetPerspFunc( VtxSpecular0.A, VtxSpecular1.A, VtxSpecular2.A );
}
else
{
RRColor VtxSpecular0( VtxFlat.GetSpecular() );
m_pSCS->AttribFuncs[ATTRFUNC_SR].SetConstant( VtxSpecular0.R );
m_pSCS->AttribFuncs[ATTRFUNC_SG].SetConstant( VtxSpecular0.G );
m_pSCS->AttribFuncs[ATTRFUNC_SB].SetConstant( VtxSpecular0.B );
m_pSCS->AttribFuncs[ATTRFUNC_SA].SetConstant( VtxSpecular0.A );
}
}
// compute vertex fog function
if ( m_dwRenderState[D3DRENDERSTATE_FOGENABLE] &&
( m_dwRenderState[D3DRENDERSTATE_FOGTABLEMODE] == D3DFOG_NONE ) )
{
FLOAT fF0 = (1/255.F)*(FLOAT)RGBA_GETALPHA( Vtx0.GetSpecular() );
FLOAT fF1 = (1/255.F)*(FLOAT)RGBA_GETALPHA( Vtx1.GetSpecular() );
FLOAT fF2 = (1/255.F)*(FLOAT)RGBA_GETALPHA( Vtx2.GetSpecular() );
m_pSCS->AttribFuncs[ATTRFUNC_F].SetPerspFunc( fF0, fF1, fF2 );
}
// compute functions for all potential texture coordinates
for(INT32 iStage = 0; iStage < m_cActiveTextureStages; iStage++)
{
for(INT32 i = 0; i < 4; i++)
{
if (m_pTexture[iStage])
{
m_pSCS->TextureFuncs[iStage][TEXFUNC_0 + i].SetPerspFunc(
m_pSCS->fTexCoord[iStage][0][i],
m_pSCS->fTexCoord[iStage][1][i],
m_pSCS->fTexCoord[iStage][2][i], m_pSCS->bWrap[iStage][i],
((m_pTexture[iStage]->m_uFlags & RR_TEXTURE_SHADOWMAP) != 0));
}
}
}
}
///////////////////////////////////////////////////////////////////////////////
// //
// Triangle Drawing //
// //
///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// DoAreaCalcs - Takes 3 vertices and does screen area computations.
// Saves x, y, w's in RRSCANCNVSTATE, computes determinant, and does
// screen bounding box calculations. Returns TRUE if the triangle is visible,
// FALSE otherwise.
//
//-----------------------------------------------------------------------------
BOOL ReferenceRasterizer::DoAreaCalcs(FLOAT* pfDet, RRFVFExtractor* pVtx0,
RRFVFExtractor* pVtx1, RRFVFExtractor* pVtx2)
{
// set vertex data
m_pSCS->fX0 = pVtx0->GetX();
m_pSCS->fY0 = pVtx0->GetY();
m_pSCS->fRHW0 = pVtx0->GetRHW();
m_pSCS->fX1 = pVtx1->GetX();
m_pSCS->fY1 = pVtx1->GetY();
m_pSCS->fRHW1 = pVtx1->GetRHW();
m_pSCS->fX2 = pVtx2->GetX();
m_pSCS->fY2 = pVtx2->GetY();
m_pSCS->fRHW2 = pVtx2->GetRHW();
// compute determinant
*pfDet = ComputeDeterminant(
m_pSCS->fX0, m_pSCS->fY0,
m_pSCS->fX1, m_pSCS->fY1,
m_pSCS->fX2, m_pSCS->fY2 );
if ( 0. == *pfDet ) { return FALSE; } // bail out if degenerate (no area)
//
// compute bounding box for scan area
//
FLOAT fXMin = MIN( m_pSCS->fX0, MIN( m_pSCS->fX1, m_pSCS->fX2 ) );
FLOAT fXMax = MAX( m_pSCS->fX0, MAX( m_pSCS->fX1, m_pSCS->fX2 ) );
FLOAT fYMin = MIN( m_pSCS->fY0, MIN( m_pSCS->fY1, m_pSCS->fY2 ) );
FLOAT fYMax = MAX( m_pSCS->fY0, MAX( m_pSCS->fY1, m_pSCS->fY2 ) );
// convert to integer (round to +inf)
m_pSCS->iXMin = (INT16)(fXMin+.5);
m_pSCS->iXMax = (INT16)(fXMax+.5);
m_pSCS->iYMin = (INT16)(fYMin+.5);
m_pSCS->iYMax = (INT16)(fYMax+.5);
// clip bbox to rendering surface
m_pSCS->iXMin = MAX( m_pSCS->iXMin, m_pRenderTarget->m_Clip.left );
m_pSCS->iXMax = MIN( m_pSCS->iXMax, m_pRenderTarget->m_Clip.right );
m_pSCS->iYMin = MAX( m_pSCS->iYMin, m_pRenderTarget->m_Clip.top );
m_pSCS->iYMax = MIN( m_pSCS->iYMax, m_pRenderTarget->m_Clip.bottom );
// reject if no coverage
if ( ( m_pSCS->iXMin < m_pRenderTarget->m_Clip.left ) ||
( m_pSCS->iXMax > m_pRenderTarget->m_Clip.right ) ||
( m_pSCS->iYMin < m_pRenderTarget->m_Clip.top ) ||
( m_pSCS->iYMax > m_pRenderTarget->m_Clip.bottom ) )
{
return FALSE;
}
return TRUE;
}
//-----------------------------------------------------------------------------
//
// DoTexCoordCalcs - Takes 2 or 3 vertices and does texture coordinate setup.
// Sets up wrap flags, and conditionally does texture transform.
//
//-----------------------------------------------------------------------------
void ReferenceRasterizer::DoTexCoordCalcs(INT32 iStage, RRFVFExtractor* pVtx0,
RRFVFExtractor* pVtx1, RRFVFExtractor* pVtx2)
{
INT32 iCoordSet = m_pTexture[iStage]->m_pStageState[iStage].m_dwVal[D3DTSS_TEXCOORDINDEX];
INT32 iTexGen = iCoordSet & 0xffff0000;
iCoordSet &= 0xffff;
// map per-coordinate set WRAP controls into per-stage WRAP controls
m_pSCS->bWrap[iStage][0] = (m_dwRenderState[D3DRENDERSTATE_WRAP0+iCoordSet] & (1<<0))?TRUE:FALSE;
m_pSCS->bWrap[iStage][1] = (m_dwRenderState[D3DRENDERSTATE_WRAP0+iCoordSet] & (1<<1))?TRUE:FALSE;
m_pSCS->bWrap[iStage][2] = (m_dwRenderState[D3DRENDERSTATE_WRAP0+iCoordSet] & (1<<2))?TRUE:FALSE;
m_pSCS->bWrap[iStage][3] = (m_dwRenderState[D3DRENDERSTATE_WRAP0+iCoordSet] & (1<<3))?TRUE:FALSE;
INT32 iNumCoords = 0;
switch (D3DFVF_GETTEXCOORDSIZE(m_qwFVFControl, iCoordSet))
{
case D3DFVF_TEXTUREFORMAT1: iNumCoords = 1; break;
case D3DFVF_TEXTUREFORMAT2: iNumCoords = 2; break;
case D3DFVF_TEXTUREFORMAT3: iNumCoords = 3; break;
case D3DFVF_TEXTUREFORMAT4: iNumCoords = 4; break;
}
FLOAT fTexGen[3][3];
if (iTexGen != D3DTSS_TCI_PASSTHRU)
{
iNumCoords = 3;
RRFVFExtractor* ppVtx[3] = { pVtx0, pVtx1, pVtx2 };
for (INT32 i = 0; i < 3; i++)
{
if (ppVtx[i])
{
switch (iTexGen)
{
case D3DTSS_TCI_CAMERASPACENORMAL:
fTexGen[i][0] = ppVtx[i]->GetEyeNormal(0);
fTexGen[i][1] = ppVtx[i]->GetEyeNormal(1);
fTexGen[i][2] = ppVtx[i]->GetEyeNormal(2);
break;
case D3DTSS_TCI_CAMERASPACEPOSITION:
fTexGen[i][0] = ppVtx[i]->GetEyeXYZ(0);
fTexGen[i][1] = ppVtx[i]->GetEyeXYZ(1);
fTexGen[i][2] = ppVtx[i]->GetEyeXYZ(2);
break;
case D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR:
{
FLOAT fNX = ppVtx[i]->GetEyeNormal(0);
FLOAT fNY = ppVtx[i]->GetEyeNormal(1);
FLOAT fNZ = ppVtx[i]->GetEyeNormal(2);
if( GetRenderState()[D3DRENDERSTATE_LOCALVIEWER] == TRUE )
{
FLOAT fX = ppVtx[i]->GetEyeXYZ(0);
FLOAT fY = ppVtx[i]->GetEyeXYZ(1);
FLOAT fZ = ppVtx[i]->GetEyeXYZ(2);
// have to normalize before we reflect,
// result will be normalized
FLOAT fNorm = 1.0f/(FLOAT)sqrt(fX*fX + fY*fY + fZ*fZ);
fX *= fNorm; fY *= fNorm; fZ *= fNorm;
FLOAT fDot2 = 2.0f*(fX*fNX + fY*fNY + fZ*fNZ);
fTexGen[i][0] = fX - fNX*fDot2;
fTexGen[i][1] = fY - fNY*fDot2;
fTexGen[i][2] = fZ - fNZ*fDot2;
}
else
{
FLOAT fDot2 = 2.0f*fNZ;
fTexGen[i][0] = -fNX*fDot2;
fTexGen[i][1] = -fNY*fDot2;
fTexGen[i][2] = 1.f - fNZ*fDot2;
}
}
break;
}
}
}
}
FLOAT fC[3][4];
for (INT32 i = 0; i < 4; i++)
{
if (i < iNumCoords)
{
if (iTexGen != D3DTSS_TCI_PASSTHRU)
{
fC[0][i] = fTexGen[0][i];
fC[1][i] = fTexGen[1][i];
fC[2][i] = fTexGen[2][i];
}
else
{
fC[0][i] = pVtx0->GetTexCrd(i, iCoordSet);
fC[1][i] = pVtx1->GetTexCrd(i, iCoordSet);
if (pVtx2)
{
fC[2][i] = pVtx2->GetTexCrd(i, iCoordSet);
}
}
}
else
{
if (i == iNumCoords)
{
fC[0][i] = 1.0f;
fC[1][i] = 1.0f;
fC[2][i] = 1.0f;
}
else
{
fC[0][i] = 0.0f;
fC[1][i] = 0.0f;
fC[2][i] = 0.0f;
}
}
}
// Do texture transform only if the original
// vertices passed to the refrast were untransformed
BOOL bAlreadyXfmd = FVF_TRANSFORMED( m_dwFVFIn );
if (m_bPointSprite)
{
// disable texture transform if in point sprite mode
bAlreadyXfmd = TRUE;
}
m_pTexture[iStage]->DoTextureTransform( iStage, bAlreadyXfmd, fC[0],
m_pSCS->fTexCoord[iStage][0], &m_pSCS->fRHQW[iStage][0] );
m_pTexture[iStage]->DoTextureTransform( iStage, bAlreadyXfmd, fC[1],
m_pSCS->fTexCoord[iStage][1], &m_pSCS->fRHQW[iStage][1] );
if (pVtx2)
{
m_pTexture[iStage]->DoTextureTransform( iStage, bAlreadyXfmd, fC[2],
m_pSCS->fTexCoord[iStage][2], &m_pSCS->fRHQW[iStage][2] );
}
// shadow map interpolation must not envolve the W of the current
// (viewing) perspective transform
if ((m_pTexture[iStage]->m_uFlags & RR_TEXTURE_SHADOWMAP) == 0)
{
m_pSCS->fRHQW[iStage][0] *= m_pSCS->fRHW0;
m_pSCS->fRHQW[iStage][1] *= m_pSCS->fRHW1;
if (pVtx2)
{
m_pSCS->fRHQW[iStage][2] *= m_pSCS->fRHW2;
}
}
}
//-----------------------------------------------------------------------------
//
// DrawTriangle - Takes three vertices and does triangle setup, setting the
// primitive structure which is input to the triangle scanner, then
// invokes the scan conversion.
//
// This computes the triangle determinant (for culling and normalization) and
// the normalized edge distance and attribute functions.
//
// wFlags - Edge (and other) flags.
//
//-----------------------------------------------------------------------------
void
ReferenceRasterizer::DrawTriangle(
void* pvV0, void* pvV1, void* pvV2, WORD wFlags )
{
DPFM(3, SETUP, ("DrawTriangle:\n"));
// encase FVF vertex pointer and control in class to extract fields
RRFVFExtractor Vtx0( pvV0, m_qwFVFControl, m_dwRenderState[D3DRENDERSTATE_TEXTUREPERSPECTIVE] );
RRFVFExtractor Vtx1( pvV1, m_qwFVFControl, m_dwRenderState[D3DRENDERSTATE_TEXTUREPERSPECTIVE] );
RRFVFExtractor Vtx2( pvV2, m_qwFVFControl, m_dwRenderState[D3DRENDERSTATE_TEXTUREPERSPECTIVE] );
FLOAT fDet;
if (DoAreaCalcs(&fDet, &Vtx0, &Vtx1, &Vtx2) == FALSE)
{
return;
}
// do culling
if (!m_bPointSprite)
{
switch ( m_dwRenderState[D3DRENDERSTATE_CULLMODE] )
{
case D3DCULL_NONE: break;
case D3DCULL_CW: if ( fDet > 0. ) { return; } break;
case D3DCULL_CCW: if ( fDet < 0. ) { return; } break;
}
}
//
// process point and wireframe fill mode
//
if (!m_bPointSprite)
{
if ( m_dwRenderState[D3DRENDERSTATE_FILLMODE] == D3DFILL_POINT )
{
DrawPoint( pvV0, pvV0 );
DrawPoint( pvV1, pvV0 );
DrawPoint( pvV2, pvV0 );
return;
}
else if ( m_dwRenderState[D3DRENDERSTATE_FILLMODE] == D3DFILL_WIREFRAME )
{
if ( wFlags & D3DTRIFLAG_EDGEENABLE1 ) { DrawLine( pvV0, pvV1, pvV0 ); }
if ( wFlags & D3DTRIFLAG_EDGEENABLE2 ) { DrawLine( pvV1, pvV2, pvV0 ); }
if ( wFlags & D3DTRIFLAG_EDGEENABLE3 ) { DrawLine( pvV2, pvV0, pvV0 ); }
return;
}
}
//
// compute edge functions
//
m_pSCS->EdgeFuncs[0].Set( m_pSCS->fX0, m_pSCS->fY0, m_pSCS->fX1, m_pSCS->fY1,
fDet, m_bFragmentProcessingEnabled );
m_pSCS->EdgeFuncs[1].Set( m_pSCS->fX1, m_pSCS->fY1, m_pSCS->fX2, m_pSCS->fY2,
fDet, m_bFragmentProcessingEnabled );
m_pSCS->EdgeFuncs[2].Set( m_pSCS->fX2, m_pSCS->fY2, m_pSCS->fX0, m_pSCS->fY0,
fDet, m_bFragmentProcessingEnabled );
// compute functions for texture coordinates
if (m_cActiveTextureStages)
{
for ( INT32 iStage=0; iStage<m_cActiveTextureStages; iStage++ )
{
if (m_pTexture[iStage])
{
DoTexCoordCalcs(iStage, &Vtx0, &Vtx1, &Vtx2);
}
}
}
// set attribute function static data to values for this triangle
m_pSCS->AttribFuncStatic.SetPerTriangleData(
m_pSCS->fX0, m_pSCS->fY0, m_pSCS->fRHW0,
m_pSCS->fX1, m_pSCS->fY1, m_pSCS->fRHW1,
m_pSCS->fX2, m_pSCS->fY2, m_pSCS->fRHW2,
m_cActiveTextureStages,
(FLOAT*)&m_pSCS->fRHQW[0][0],
fDet );
// set attribute functions
SetPrimitiveAttributeFunctions( Vtx0, Vtx1, Vtx2, Vtx0 );
// not culled, so rasterize it
DoScanCnvTri(3);
}
///////////////////////////////////////////////////////////////////////////////
// //
// Line Drawing //
// //
///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// PointDiamondCheck - Tests if vertex is within diamond of nearest candidate
// position. The +.5 (lower-right) tests are used because this is pixel-relative
// test - this corresponds to an upper-left test for a vertex-relative position.
//
//-----------------------------------------------------------------------------
BOOL
PointDiamondCheck(
INT32 iXFrac, INT32 iYFrac,
BOOL bSlopeIsOne, BOOL bSlopeIsPosOne )
{
const INT32 iPosHalf = 0x8;
const INT32 iNegHalf = -0x8;
INT32 iFracAbsSum = labs( iXFrac ) + labs( iYFrac );
// return TRUE if point is in fully-exclusive diamond
if ( iFracAbsSum < iPosHalf ) return TRUE;
// else return TRUE if diamond is on left or top extreme of point
if ( ( iXFrac == ( bSlopeIsPosOne ? iNegHalf : iPosHalf ) ) &&
( iYFrac == 0 ) )
return TRUE;
if ( ( iYFrac == iPosHalf ) &&
( iXFrac == 0 ) )
return TRUE;
// return true if slope is one, vertex is on edge, and (other conditions...)
if ( bSlopeIsOne && ( iFracAbsSum == iPosHalf ) )
{
if ( bSlopeIsPosOne && ( iXFrac < 0 ) && ( iYFrac > 0 ) )
return TRUE;
if ( !bSlopeIsPosOne && ( iXFrac > 0 ) && ( iYFrac > 0 ) )
return TRUE;
}
return FALSE;
}
//-----------------------------------------------------------------------------
//
// DrawLine - Takes two vertices and draws a line.
//
// This implements the Grid Intersect Quanization (GIQ) convention (which is
// also used in Windows).
//
//-----------------------------------------------------------------------------
void
ReferenceRasterizer::DrawLine(
void* pvV0, void* pvV1, void* pvVFlat )
{
DPFM(3, SETUP, ("DrawLine:\n"));
// encase FVF vertex pointer and control in class to extract fields
RRFVFExtractor Vtx0( pvV0, m_qwFVFControl, m_dwRenderState[D3DRENDERSTATE_TEXTUREPERSPECTIVE] );
RRFVFExtractor Vtx1( pvV1, m_qwFVFControl, m_dwRenderState[D3DRENDERSTATE_TEXTUREPERSPECTIVE] );
RRFVFExtractor VtxFlat( ( ( NULL != pvVFlat ) ? pvVFlat : pvV0 ),
m_qwFVFControl, m_dwRenderState[D3DRENDERSTATE_TEXTUREPERSPECTIVE] );
// set vertex data
m_pSCS->fX0 = Vtx0.GetX();
m_pSCS->fY0 = Vtx0.GetY();
m_pSCS->fRHW0 = Vtx0.GetRHW();
m_pSCS->fX1 = Vtx1.GetX();
m_pSCS->fY1 = Vtx1.GetY();
m_pSCS->fRHW1 = Vtx1.GetRHW();
// compute n.4 fixed point vertex values
INT32 iX0 = AS_INT32( (DOUBLE)m_pSCS->fX0 + DOUBLE_4_SNAP );
INT32 iX1 = AS_INT32( (DOUBLE)m_pSCS->fX1 + DOUBLE_4_SNAP );
INT32 iY0 = AS_INT32( (DOUBLE)m_pSCS->fY0 + DOUBLE_4_SNAP );
INT32 iY1 = AS_INT32( (DOUBLE)m_pSCS->fY1 + DOUBLE_4_SNAP );
// compute x,y extents of the line (fixed point)
INT32 iXSize = iX1 - iX0;
INT32 iYSize = iY1 - iY0;
// TODO: is this right???
if ( ( iXSize == 0 ) && ( iYSize == 0 ) ) { return; }
// determine major direction and compute line function
FLOAT fLineMajorExtent; // signed extent from V0 to V1 in major direction
// use GreaterEqual compare here so X major will be used when slope is
// exactly one - this forces the per-pixel evaluation to be done on the
// Y axis and thus adheres to the rule of inclusive right (instead of
// inclusive left) for slope == 1 cases
if ( labs( iXSize ) >= labs( iYSize ) )
{
// here for X major
m_pSCS->bXMajor = TRUE;
fLineMajorExtent = (FLOAT)iXSize * (1./16.);
// line function: y = F(x) = ( [0]*x + [1] ) / [2]
m_pSCS->iLineEdgeFunc[0] = iYSize;
m_pSCS->iLineEdgeFunc[1] = (INT64)iY0*(INT64)iX1 - (INT64)iY1*(INT64)iX0;
m_pSCS->iLineEdgeFunc[2] = iXSize;
}
else
{
// here for Y major
m_pSCS->bXMajor = FALSE;
fLineMajorExtent = (FLOAT)iYSize * (1./16.);
// line function: x = F(y) = ( [0]*y + [1] ) / [2]
m_pSCS->iLineEdgeFunc[0] = iXSize;
m_pSCS->iLineEdgeFunc[1] = (INT64)iX0*(INT64)iY1 - (INT64)iX1*(INT64)iY0;
m_pSCS->iLineEdgeFunc[2] = iYSize;
}
BOOL bSlopeIsOne = ( labs( iXSize ) == labs( iYSize ) );
BOOL bSlopeIsPosOne =
bSlopeIsOne &&
( ( (FLOAT)m_pSCS->iLineEdgeFunc[0]/(FLOAT)m_pSCS->iLineEdgeFunc[2] ) > 0. );
// compute candidate pixel location for line endpoints
//
// n n
// O-------* *-------O
// n-.5 n+.5 n-.5 n+.5
//
// Nearest Ceiling Nearest Floor
//
// always nearest ceiling for Y; use nearest floor for X for exception (slope == +1)
// case else use nearest ceiling
//
// nearest ceiling of Y is ceil( Y - .5), and is done by converting to floor via:
//
// ceil( A/B ) = floor( (A+B-1)/B )
//
// where A is coordinate - .5, and B is 0x10 (thus A/B is an n.4 fixed point number)
//
// A+B-1 = ( (Y - half) + B - 1 = ( (Y-0x8) + 0x10 - 0x1 = Y + 0x7
// since B is 2**4, divide by B is right shift by 4
//
INT32 iPixX0 = ( iX0 + ( bSlopeIsPosOne ? 0x8 : 0x7 ) ) >> 4;
INT32 iPixX1 = ( iX1 + ( bSlopeIsPosOne ? 0x8 : 0x7 ) ) >> 4;
INT32 iPixY0 = ( iY0 + 0x7 ) >> 4;
INT32 iPixY1 = ( iY1 + 0x7 ) >> 4;
// check for vertices in/out of diamond
BOOL bV0InDiamond = PointDiamondCheck( iX0 - (iPixX0<<4), iY0 - (iPixY0<<4), bSlopeIsOne, bSlopeIsPosOne );
BOOL bV1InDiamond = PointDiamondCheck( iX1 - (iPixX1<<4), iY1 - (iPixY1<<4), bSlopeIsOne, bSlopeIsPosOne );
// compute step value
m_pSCS->iLineStep = ( fLineMajorExtent > 0 ) ? ( +1 ) : ( -1 );
// compute float and integer major start (V0) and end (V1) positions
INT32 iLineMajor0 = ( m_pSCS->bXMajor ) ? ( iX0 ) : ( iY0 );
INT32 iLineMajor1 = ( m_pSCS->bXMajor ) ? ( iX1 ) : ( iY1 );
m_pSCS->iLineMin = ( m_pSCS->bXMajor ) ? ( iPixX0 ) : ( iPixY0 );
m_pSCS->iLineMax = ( m_pSCS->bXMajor ) ? ( iPixX1 ) : ( iPixY1 );
// need to do lots of compares which are flipped if major direction is negative
#define LINEDIR_CMP( _A, _B ) \
( ( fLineMajorExtent > 0 ) ? ( (_A) < (_B) ) : ( (_A) > (_B) ) )
// do first pixel handling - keep first pixel if not in or behind diamond
if ( !( bV0InDiamond || LINEDIR_CMP( iLineMajor0, (m_pSCS->iLineMin<<4) ) ) )
{
m_pSCS->iLineMin += m_pSCS->iLineStep;
}
// do last-pixel handling - keep last pixel if past diamond (in which case
// the pixel is always filled) or if in diamond and rendering last pixel
if ( !( ( !bV1InDiamond && LINEDIR_CMP( (m_pSCS->iLineMax<<4), iLineMajor1 ) ) ||
( bV1InDiamond && m_dwRenderState[D3DRENDERSTATE_LASTPIXEL] ) ) )
{
m_pSCS->iLineMax -= m_pSCS->iLineStep;
}
// return if no (major) extent (both before and after clamping to render buffer)
if ( LINEDIR_CMP( m_pSCS->iLineMax, m_pSCS->iLineMin ) ) return;
// snap major extent to render buffer
INT16 iRendBufMajorMin = m_pSCS->bXMajor ? m_pRenderTarget->m_Clip.left : m_pRenderTarget->m_Clip.top;
INT16 iRendBufMajorMax = m_pSCS->bXMajor ? m_pRenderTarget->m_Clip.right : m_pRenderTarget->m_Clip.bottom;
if ( ( ( m_pSCS->iLineMin < iRendBufMajorMin ) &&
( m_pSCS->iLineMax < iRendBufMajorMin ) ) ||
( ( m_pSCS->iLineMin > iRendBufMajorMax ) &&
( m_pSCS->iLineMax > iRendBufMajorMax ) ) ) { return; }
m_pSCS->iLineMin = MAX( 0, MIN( iRendBufMajorMax, m_pSCS->iLineMin ) );
m_pSCS->iLineMax = MAX( 0, MIN( iRendBufMajorMax, m_pSCS->iLineMax ) );
// return if no (major) extent
if ( LINEDIR_CMP( m_pSCS->iLineMax, m_pSCS->iLineMin ) ) return;
// reject if line does not cross surface
{
// TODO
}
// compute functions for texture coordinates
if (m_cActiveTextureStages)
{
for ( INT32 iStage=0; iStage<m_cActiveTextureStages; iStage++ )
{
if (m_pTexture[iStage])
{
DoTexCoordCalcs(iStage, &Vtx0, &Vtx1, NULL);
}
}
}
// set attribute function static data to values for this line
m_pSCS->AttribFuncStatic.SetPerLineData(
m_pSCS->fX0, m_pSCS->fY0, m_pSCS->fRHW0,
m_pSCS->fX1, m_pSCS->fY1, m_pSCS->fRHW1,
m_cActiveTextureStages,
(FLOAT*)&m_pSCS->fRHQW[0][0],
fLineMajorExtent, m_pSCS->bXMajor );
// set attribute functions
SetPrimitiveAttributeFunctions( Vtx0, Vtx1, Vtx1, VtxFlat );
// rasterize it
DoScanCnvLine();
}
///////////////////////////////////////////////////////////////////////////////
// //
// Point Drawing //
// //
///////////////////////////////////////////////////////////////////////////////
void
ReferenceRasterizer::DrawPoint(
void* pvV0Public, void* pvVFlat )
{
DPFM(3, SETUP, ("DrawPoint:\n"));
DWORD dwStride = GetFVFVertexSize(m_qwFVFControl);
void *pvV0 = MEMALLOC( dwStride );
void *pvV1 = MEMALLOC( dwStride );
void *pvV2 = MEMALLOC( dwStride );
_ASSERTa( ( NULL != pvV0 ) && ( NULL != pvV1 ) && ( NULL != pvV2),
"malloc failure on ReferenceRasterizer::DrawPoint", return; );
memcpy(pvV0, pvV0Public, dwStride);
memcpy(pvV1, pvV0Public, dwStride);
memcpy(pvV2, pvV0Public, dwStride);
// encase FVF vertex pointer and control in class to extract fields
RRFVFExtractor Vtx0( pvV0, m_qwFVFControl, m_dwRenderState[D3DRENDERSTATE_TEXTUREPERSPECTIVE] );
RRFVFExtractor Vtx1( pvV1, m_qwFVFControl, m_dwRenderState[D3DRENDERSTATE_TEXTUREPERSPECTIVE] );
RRFVFExtractor Vtx2( pvV2, m_qwFVFControl, m_dwRenderState[D3DRENDERSTATE_TEXTUREPERSPECTIVE] );
// use per vertex S if it exists, otherwise use D3DRENDERSTATE_POINTSIZE
BOOL bAlreadyXfmd = FVF_TRANSFORMED( m_dwFVFIn );
FLOAT fS = 1.0f;
#ifdef __POINTSPRITES
if (m_qwFVFControl & D3DFVF_S)
{
fS = Vtx0.GetS();
}
else if( m_dwDriverType > RRTYPE_DP2HAL )
{
fS = m_fRenderState[D3DRENDERSTATE_POINTSIZE];
}
#endif
// divide point size by 2 to get delta
fS *= .5f;
// Move points based on point size
FLOAT *pXY = Vtx0.GetPtrXYZ();
FLOAT fX3 = pXY[0] + fS;
FLOAT fY3 = pXY[1] + fS;
pXY[0] += -fS;
pXY[1] += -fS;
pXY = Vtx1.GetPtrXYZ();
pXY[0] += fS;
pXY[1] += -fS;
pXY = Vtx2.GetPtrXYZ();
pXY[0] += -fS;
pXY[1] += fS;
FLOAT fDet;
if (DoAreaCalcs(&fDet, &Vtx0, &Vtx1, &Vtx2) == FALSE)
{
goto PointCleanupAndExit;
}
//
// compute edge functions
//
m_pSCS->EdgeFuncs[0].Set( m_pSCS->fX0, m_pSCS->fY0, m_pSCS->fX1, m_pSCS->fY1,
fDet, m_bFragmentProcessingEnabled );
m_pSCS->EdgeFuncs[1].Set( m_pSCS->fX1, m_pSCS->fY1, fX3, fY3,
fDet, m_bFragmentProcessingEnabled );
m_pSCS->EdgeFuncs[2].Set( fX3, fY3, m_pSCS->fX2, m_pSCS->fY2,
fDet, m_bFragmentProcessingEnabled );
m_pSCS->EdgeFuncs[3].Set( m_pSCS->fX2, m_pSCS->fY2, m_pSCS->fX0, m_pSCS->fY0,
fDet, m_bFragmentProcessingEnabled );
// compute functions for texture coordinates
if (m_cActiveTextureStages)
{
for ( INT32 iStage=0; iStage<m_cActiveTextureStages; iStage++ )
{
if (m_pTexture[iStage])
{
DoTexCoordCalcs(iStage, &Vtx0, &Vtx1, &Vtx2);
#ifdef __POINTSPRITES
if (m_dwRenderState[D3DRENDERSTATE_POINTSPRITEENABLE])
{
// vtx0
m_pSCS->fTexCoord[iStage][0][0] = 0.0f;
m_pSCS->fTexCoord[iStage][0][1] = 0.0f;
m_pSCS->fTexCoord[iStage][0][2] = 1.0f;
m_pSCS->fTexCoord[iStage][0][3] = 0.0f;
m_pSCS->fRHQW[iStage][0] = m_pSCS->fRHW0;
// vtx1
m_pSCS->fTexCoord[iStage][1][0] = SPRITETEXCOORDMAX;
m_pSCS->fTexCoord[iStage][1][1] = 0.0f;
m_pSCS->fTexCoord[iStage][1][2] = 1.0f;
m_pSCS->fTexCoord[iStage][1][3] = 0.0f;
m_pSCS->fRHQW[iStage][1] = m_pSCS->fRHW1;
// vtx2
m_pSCS->fTexCoord[iStage][2][0] = 0.0f;
m_pSCS->fTexCoord[iStage][2][1] = SPRITETEXCOORDMAX;
m_pSCS->fTexCoord[iStage][2][2] = 1.0f;
m_pSCS->fTexCoord[iStage][2][3] = 0.0f;
m_pSCS->fRHQW[iStage][2] = m_pSCS->fRHW2;
}
#endif //__POINTSPRITES
}
}
}
// set attribute function static data to values for this quad
// (since slopes are constant for quad, any triangle can be used
// to set them).
m_pSCS->AttribFuncStatic.SetPerTriangleData(
m_pSCS->fX0, m_pSCS->fY0, m_pSCS->fRHW0,
m_pSCS->fX1, m_pSCS->fY1, m_pSCS->fRHW1,
m_pSCS->fX2, m_pSCS->fY2, m_pSCS->fRHW2,
m_cActiveTextureStages,
(FLOAT*)&m_pSCS->fRHQW[0][0],
fDet );
// set attribute functions
SetPrimitiveAttributeFunctions( Vtx0, Vtx1, Vtx2, Vtx0 );
// not culled, so rasterize it
DoScanCnvTri(4);
PointCleanupAndExit:
MEMFREE(pvV0);
MEMFREE(pvV1);
MEMFREE(pvV2);
}
///////////////////////////////////////////////////////////////////////////////
// end