windows-nt/Source/XPSP1/NT/multimedia/directx/dxg/ref8/tnl/procprim.cpp
2020-09-26 16:20:57 +08:00

1291 lines
46 KiB
C++

#include "pch.cpp"
#pragma hdrstop
//---------------------------------------------------------------------
// Constructor:
//
//---------------------------------------------------------------------
RefVP::RefVP() :
m_LightArray(),
m_LightVertexTable()
{
m_LightArray.SetGrowSize( 32 );
memset( &m_Material, 0, sizeof(m_Material) );
memset( &m_xfmProj, 0, sizeof(m_xfmProj) );
memset( &m_xfmView, 0, sizeof(m_xfmView) );
memset( m_xfmWorld, 0, sizeof(m_xfmView)*RD_MAX_WORLD_MATRICES );
m_dwTLState = 0;
m_dwDirtyFlags = 0;
memset( m_xfmCurrent, 0, sizeof(m_xfmView)*RD_MAX_WORLD_MATRICES );
memset( m_xfmToEye, 0, sizeof(m_xfmView)*RD_MAX_WORLD_MATRICES );
memset( m_xfmToEyeInv, 0, sizeof(m_xfmView)*RD_MAX_WORLD_MATRICES );
m_qwFVFIn = 0;
m_numVertexBlends = 0;
memset( &m_TransformData, 0, sizeof(m_TransformData) ) ;
m_fPointSize = 0;
m_fPointAttA = 0;
m_fPointAttB = 0;
m_fPointAttC = 0;
m_fPointSizeMin = 0;
m_fPointSizeMax = RD_MAX_POINT_SIZE;
m_fTweenFactor = 0.0f;
m_LightVertexTable.pfnDirectional = RDLV_Directional;
m_LightVertexTable.pfnParallelPoint = RDLV_Directional;
m_LightVertexTable.pfnSpot = RDLV_PointAndSpot;
m_LightVertexTable.pfnPoint = RDLV_PointAndSpot;
m_dwNumActiveTextureStages = 0;
m_pDev = NULL;
}
//---------------------------------------------------------------------
// SetupStrides:
//---------------------------------------------------------------------
HRESULT
RefDev::SetupStrides()
{
RDVDeclaration& Decl = m_pCurrentVShader->m_Declaration;
// Null out the PtrStrides
m_RefVP.m_position.Null();
m_RefVP.m_position2.Null();
m_RefVP.m_blendweights.Null();
m_RefVP.m_blendindices.Null();
m_RefVP.m_normal.Null();
m_RefVP.m_normal2.Null();
m_RefVP.m_specular.Null();
m_RefVP.m_diffuse.Null();
m_RefVP.m_pointsize.Null();
for( int t = 0; t < 8 ; t++ )
m_RefVP.m_tex[t].Null();
for( DWORD i = 0; i < Decl.m_dwNumElements; i++ )
{
RDVElement& Element = Decl.m_VertexElements[i];
RDVStream& Stream = m_VStream[Element.m_dwStreamIndex];
DWORD dwStride = Stream.m_dwStride;
DWORD dwStartVertex = m_dwStartVertex;
switch( Element.m_dwRegister )
{
case D3DVSDE_POSITION:
m_RefVP.m_position.Init(
(LPBYTE)Stream.m_pData + Element.m_dwOffset +
dwStride * dwStartVertex, dwStride );
break;
case D3DVSDE_POSITION2:
m_RefVP.m_position2.Init(
(LPBYTE)Stream.m_pData + Element.m_dwOffset +
dwStride * dwStartVertex, dwStride );
break;
case D3DVSDE_BLENDWEIGHT:
m_RefVP.m_blendweights.Init(
(LPBYTE)Stream.m_pData + Element.m_dwOffset +
dwStride * dwStartVertex, dwStride );
break;
case D3DVSDE_BLENDINDICES:
// This only happens if the vertex declaration is a non-FVF one
_ASSERT( !RDVSD_ISLEGACY( m_CurrentVShaderHandle ),
"FVF shader could not have provided a"
" separate blend-index" );
m_RefVP.m_blendindices.Init(
(LPBYTE)Stream.m_pData + Element.m_dwOffset +
dwStride * dwStartVertex, dwStride );
break;
case D3DVSDE_NORMAL:
m_RefVP.m_normal.Init(
(LPBYTE)Stream.m_pData + Element.m_dwOffset +
dwStride * dwStartVertex, dwStride );
break;
case D3DVSDE_NORMAL2:
m_RefVP.m_normal2.Init(
(LPBYTE)Stream.m_pData + Element.m_dwOffset +
dwStride * dwStartVertex, dwStride );
break;
case D3DVSDE_PSIZE:
m_RefVP.m_pointsize.Init(
(LPBYTE)Stream.m_pData + Element.m_dwOffset +
dwStride * dwStartVertex, dwStride );
break;
case D3DVSDE_DIFFUSE:
m_RefVP.m_diffuse.Init(
(LPBYTE)Stream.m_pData + Element.m_dwOffset +
dwStride * dwStartVertex, dwStride );
break;
case D3DVSDE_SPECULAR:
m_RefVP.m_specular.Init(
(LPBYTE)Stream.m_pData + Element.m_dwOffset +
dwStride * dwStartVertex, dwStride );
break;
case D3DVSDE_TEXCOORD0:
m_RefVP.m_tex[0].Init(
(LPBYTE)Stream.m_pData + Element.m_dwOffset +
dwStride * dwStartVertex, dwStride );
break;
case D3DVSDE_TEXCOORD1:
m_RefVP.m_tex[1].Init(
(LPBYTE)Stream.m_pData + Element.m_dwOffset +
dwStride * dwStartVertex, dwStride );
break;
case D3DVSDE_TEXCOORD2:
m_RefVP.m_tex[2].Init(
(LPBYTE)Stream.m_pData + Element.m_dwOffset +
dwStride * dwStartVertex, dwStride );
break;
case D3DVSDE_TEXCOORD3:
m_RefVP.m_tex[3].Init(
(LPBYTE)Stream.m_pData + Element.m_dwOffset +
dwStride * dwStartVertex, dwStride );
break;
case D3DVSDE_TEXCOORD4:
m_RefVP.m_tex[4].Init(
(LPBYTE)Stream.m_pData + Element.m_dwOffset +
dwStride * dwStartVertex, dwStride );
break;
case D3DVSDE_TEXCOORD5:
m_RefVP.m_tex[5].Init(
(LPBYTE)Stream.m_pData + Element.m_dwOffset +
dwStride * dwStartVertex, dwStride );
break;
case D3DVSDE_TEXCOORD6:
m_RefVP.m_tex[6].Init(
(LPBYTE)Stream.m_pData + Element.m_dwOffset +
dwStride * dwStartVertex, dwStride );
break;
case D3DVSDE_TEXCOORD7:
m_RefVP.m_tex[7].Init(
(LPBYTE)Stream.m_pData + Element.m_dwOffset +
dwStride * dwStartVertex, dwStride );
break;
}
}
// If it is a FVF vertex shader and index-vertex blending is enabled
// then the blend-indices are found in the last beta (which is the blend
// weight) of the vertex.
if( RDVSD_ISLEGACY( m_CurrentVShaderHandle ) &&
(m_RefVP.m_dwTLState & RDPV_DOINDEXEDVERTEXBLEND) )
{
m_RefVP.m_blendindices.Init(
(float *)m_RefVP.m_blendweights.GetFirst() +
m_RefVP.m_numVertexBlends,
m_RefVP.m_blendweights.GetStride() );
}
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
// Process primitives implementation:
// 1) Compute FVF info
// 2) Grow buffers to the requisite size
// 3) Initialize clipping state
// 4) Update T&L state
// 5) Transform, Light and compute clipping for vertices
// 6) Clip and Draw the primitives
//
///////////////////////////////////////////////////////////////////////////////
HRESULT
RefDev::ProcessPrimitive( D3DPRIMITIVETYPE PrimType,
DWORD StartVertex,
DWORD cVertices,
DWORD StartIndex,
DWORD cIndices )
{
HRESULT hr = D3D_OK;
DWORD dwVertexPoolSize = 0;
// Save Prim Type for later use
m_primType = PrimType;
m_dwNumVertices = cVertices;
m_dwStartVertex = StartVertex;
m_dwNumIndices = cIndices;
m_dwStartIndex = StartIndex;
//
// Update T&L state (must be before FVFData is set up)
//
// Update Lighting and related state and flags and computes Output FVF
HR_RET( UpdateTLState() );
//
// Clipping information depends both on the output FVF computation
// and the other State, so do it here after both have been computed
//
HR_RET( UpdateClipper() );
//
// Grow TLVArray if required
//
if( FAILED( m_TLVArray.Grow( m_dwNumVertices ) ) )
{
DPFERR( "Could not grow TL vertex buffer" );
return DDERR_OUTOFMEMORY;
}
//
// Transform, Light and compute clipping for vertices
//
DWORD clipIntersection = m_RefVP.ProcessVertices( m_qwFVFOut, m_TLVArray,
m_dwNumVertices );
if( m_primType == D3DPT_POINTLIST )
{
// We clip points by Z planes and user clip planes, because point
// sprites could be still visible when a point is outside X or Y plane
clipIntersection &= ~(RDCLIP_LEFT | RDCLIP_RIGHT |
RDCLIP_TOP | RDCLIP_BOTTOM |
RDCLIPGB_ALL);
}
if( clipIntersection )
{
// If the entire primitive lies outside the view frustum, quit
// without drawing
return D3D_OK;
}
//
// Clip and Draw the primitives
//
if( m_dwNumIndices )
{
if( !NeedClipping(m_Clipper.UseGuardBand(), m_Clipper.m_clipUnion) )
{
if( m_IndexStream.m_dwStride == 4 )
hr = DrawOneIndexedPrimitive(
m_TLVArray,
0,
(LPDWORD)m_IndexStream.m_pData,
m_dwStartIndex,
m_dwNumIndices,
m_primType );
else
hr = DrawOneIndexedPrimitive(
m_TLVArray,
0,
(LPWORD)m_IndexStream.m_pData,
m_dwStartIndex,
m_dwNumIndices,
m_primType );
}
else
{
if( m_IndexStream.m_dwStride == 4 )
hr = m_Clipper.DrawOneIndexedPrimitive(
m_TLVArray,
0,
(LPDWORD)m_IndexStream.m_pData,
m_dwStartIndex,
m_dwNumIndices,
m_primType );
else
hr = m_Clipper.DrawOneIndexedPrimitive(
m_TLVArray,
0,
(LPWORD)m_IndexStream.m_pData,
m_dwStartIndex,
m_dwNumIndices,
m_primType );
}
}
else
{
if( !NeedClipping((m_Clipper.UseGuardBand()), m_Clipper.m_clipUnion) )
{
hr = DrawOnePrimitive(
m_TLVArray,
0,
m_primType,
m_dwNumVertices );
}
else
{
hr = m_Clipper.DrawOnePrimitive(
m_TLVArray,
0,
m_primType,
m_dwNumVertices );
}
}
return hr;
}
//---------------------------------------------------------------------
// RefDev::UpdateTLState
// Updates transform and lighting related state
//---------------------------------------------------------------------
HRESULT
RefDev::UpdateTLState()
{
HRESULT hr = D3D_OK;
UINT64 qwFVFIn = m_RefVP.m_qwFVFIn;
//
// Sort out vertex blending.
//
// Total number of floats/dwords provided per vertex according to
// the FVF.
DWORD numBetas = 0;
if( (qwFVFIn & D3DFVF_POSITION_MASK) !=
(D3DFVF_XYZ & D3DFVF_POSITION_MASK) )
numBetas = ((qwFVFIn & D3DFVF_POSITION_MASK) >> 1) - 2;
DWORD numWeights = GetRS()[D3DRENDERSTATE_VERTEXBLEND];
// If tweening is enabled, there better be Position2 or Normal2
if( numWeights == D3DVBF_TWEENING )
{
if( (qwFVFIn & (D3DFVFP_POSITION2 | D3DFVFP_NORMAL2)) == 0 )
{
DPFERR( "Tweening is enabled, but there is neither position2"
" nor normal2 available\n" );
return E_FAIL;
}
if( qwFVFIn & D3DFVFP_POSITION2 )
m_RefVP.m_dwTLState |= RDPV_DOPOSITIONTWEENING;
if( qwFVFIn & D3DFVFP_NORMAL2 )
m_RefVP.m_dwTLState |= RDPV_DONORMALTWEENING;
numWeights = 0;
}
else
{
m_RefVP.m_dwTLState &= ~(RDPV_DOPOSITIONTWEENING |
RDPV_DONORMALTWEENING);
}
if( numWeights == D3DVBF_DISABLE )
m_RefVP.m_dwTLState &= ~RDPV_DOINDEXEDVERTEXBLEND;
if( numWeights == D3DVBF_0WEIGHTS ) numWeights = 0;
if( m_RefVP.m_dwTLState & RDPV_DOINDEXEDVERTEXBLEND )
{
// If it is a FVF shader (legacy) the blend indices are provided as
// the betas. There should be enough betas to cover this.
if( RDVSD_ISLEGACY( m_CurrentVShaderHandle ) &&
(numBetas < (numWeights + 1)) )
{
DPFERR( "Not enough blend-weights to do indexed vertex blending" );
return E_FAIL;
}
else if( !RDVSD_ISLEGACY( m_CurrentVShaderHandle ) &&
((qwFVFIn & D3DFVFP_BLENDINDICES) == 0) )
{
DPFERR( "Blend-indices not provided" );
return E_FAIL;
}
}
else if( numWeights )
{
if( numBetas < numWeights )
{
DPFERR( "Not enough blend-weights to do vertex blending" );
return E_FAIL;
}
}
m_RefVP.m_numVertexBlends = numWeights;
//
// Check prim type to see if point size computation is needed
// Need to set this before the transform state is set
//
m_RefVP.m_dwTLState &= ~(RDPV_DOCOMPUTEPOINTSIZE | RDPV_DOPOINTSCALE);
switch(m_primType)
{
case D3DPT_POINTLIST:
m_RefVP.m_dwTLState |= RDPV_DOCOMPUTEPOINTSIZE;
if( GetRS()[D3DRS_POINTSCALEENABLE] )
m_RefVP.m_dwTLState |= RDPV_DOPOINTSCALE;
break;
}
// Fog or not:
// Compute fog if: 1) Fogging is enabled
// 2) VertexFog mode is not FOG_NONE
// 3) TableFog mode is FOG_NONE
// If both table and vertex fog are not FOG_NONE, table fog
// is applied.
if( GetRS()[D3DRENDERSTATE_FOGENABLE] &&
GetRS()[D3DRENDERSTATE_FOGVERTEXMODE] &&
!GetRS()[D3DRENDERSTATE_FOGTABLEMODE] )
{
m_RefVP.m_dwTLState |= RDPV_DOFOG;
// Range Fog
if( GetRS()[D3DRENDERSTATE_RANGEFOGENABLE] )
{
m_RefVP.m_dwTLState |= RDPV_RANGEFOG;
}
else
{
m_RefVP.m_dwTLState &= ~RDPV_RANGEFOG;
}
}
else
{
m_RefVP.m_dwTLState &= ~(RDPV_DOFOG | RDPV_RANGEFOG);
}
//
// Evaluate if any texture transform/gen is required. If so, then compute
// the output Texture Coordinates
//
UpdateActiveTexStageCount();
m_RefVP.m_dwNumActiveTextureStages = m_cActiveTextureStages;
m_RefVP.m_dwTLState &= ~(RDPV_DOTEXGEN | RDPV_DOTEXXFORM |
RDPV_NEEDEYENORMAL | RDPV_NEEDEYEXYZ);
for( DWORD dwStage=0; dwStage<(DWORD)m_cActiveTextureStages; dwStage++ )
{
if( (GetTSS(dwStage)[D3DTSS_TEXTURETRANSFORMFLAGS]
& ~D3DTTFF_PROJECTED) != D3DTTFF_DISABLE )
{
m_RefVP.m_dwTLState |= RDPV_DOTEXXFORM;
}
if( GetTSS(dwStage)[D3DTSS_TEXCOORDINDEX] & 0xffff0000 )
{
m_RefVP.m_dwTLState |= RDPV_DOTEXGEN;
}
}
// Something changed in the transformation state
// Recompute digested transform state
HR_RET(m_RefVP.UpdateXformData());
// Something changed in the lighting state
if( (m_RefVP.m_dwTLState & RDPV_DOLIGHTING) &&
(m_RefVP.m_dwDirtyFlags & RDPV_DIRTY_LIGHTING) )
{
RDLIGHTINGDATA& LData = m_RefVP.m_lighting;
//
// Compute Colorvertex flags only if the lighting is enabled
//
m_RefVP.m_dwTLState &= ~RDPV_COLORVERTEXFLAGS;
LData.pAmbientSrc = &LData.matAmb;
LData.pDiffuseSrc = &LData.matDiff;
LData.pSpecularSrc = &LData.matSpec;
LData.pEmissiveSrc = &LData.matEmis;
LData.pDiffuseAlphaSrc = &LData.materialDiffAlpha;
LData.pSpecularAlphaSrc = &LData.materialSpecAlpha;
if( GetRS()[D3DRENDERSTATE_COLORVERTEX] )
{
switch( GetRS()[D3DRENDERSTATE_AMBIENTMATERIALSOURCE] )
{
case D3DMCS_MATERIAL:
break;
case D3DMCS_COLOR1:
{
if( qwFVFIn & D3DFVF_DIFFUSE )
{
m_RefVP.m_dwTLState |=
(RDPV_VERTEXDIFFUSENEEDED | RDPV_COLORVERTEXAMB);
LData.pAmbientSrc = &LData.vertexDiffuse;
}
}
break;
case D3DMCS_COLOR2:
{
if( qwFVFIn & D3DFVF_SPECULAR )
{
m_RefVP.m_dwTLState |=
(RDPV_VERTEXSPECULARNEEDED | RDPV_COLORVERTEXAMB);
LData.pAmbientSrc = &LData.vertexSpecular;
}
}
break;
}
switch( GetRS()[D3DRENDERSTATE_DIFFUSEMATERIALSOURCE] )
{
case D3DMCS_MATERIAL:
break;
case D3DMCS_COLOR1:
{
if( qwFVFIn & D3DFVF_DIFFUSE )
{
m_RefVP.m_dwTLState |=
(RDPV_VERTEXDIFFUSENEEDED | RDPV_COLORVERTEXDIFF);
LData.pDiffuseSrc = &LData.vertexDiffuse;
LData.pDiffuseAlphaSrc =
&LData.vertexDiffAlpha;
}
}
break;
case D3DMCS_COLOR2:
{
if( qwFVFIn & D3DFVF_SPECULAR )
{
m_RefVP.m_dwTLState |=
(RDPV_VERTEXSPECULARNEEDED | RDPV_COLORVERTEXDIFF);
LData.pDiffuseSrc = &LData.vertexSpecular;
LData.pDiffuseAlphaSrc =
&LData.vertexSpecAlpha;
}
}
break;
}
switch( GetRS()[D3DRENDERSTATE_SPECULARMATERIALSOURCE] )
{
case D3DMCS_MATERIAL:
break;
case D3DMCS_COLOR1:
{
if( qwFVFIn & D3DFVF_DIFFUSE )
{
m_RefVP.m_dwTLState |=
(RDPV_VERTEXDIFFUSENEEDED | RDPV_COLORVERTEXSPEC);
LData.pSpecularSrc = &LData.vertexDiffuse;
LData.pSpecularAlphaSrc =
&LData.vertexDiffAlpha;
}
}
break;
case D3DMCS_COLOR2:
{
if( qwFVFIn & D3DFVF_SPECULAR )
{
m_RefVP.m_dwTLState |=
(RDPV_VERTEXSPECULARNEEDED | RDPV_COLORVERTEXSPEC);
LData.pSpecularSrc = &LData.vertexSpecular;
LData.pSpecularAlphaSrc =
&LData.vertexSpecAlpha;
}
}
break;
}
switch( GetRS()[D3DRENDERSTATE_EMISSIVEMATERIALSOURCE] )
{
case D3DMCS_MATERIAL:
break;
case D3DMCS_COLOR1:
{
if( qwFVFIn & D3DFVF_DIFFUSE )
{
m_RefVP.m_dwTLState |=
(RDPV_VERTEXDIFFUSENEEDED | RDPV_COLORVERTEXEMIS);
LData.pEmissiveSrc = &LData.vertexDiffuse;
}
}
break;
case D3DMCS_COLOR2:
{
if( qwFVFIn & D3DFVF_SPECULAR )
{
m_RefVP.m_dwTLState |=
(RDPV_VERTEXSPECULARNEEDED | RDPV_COLORVERTEXEMIS);
LData.pEmissiveSrc = &LData.vertexSpecular;
}
}
break;
}
}
// If specular is needed in the output and has been provided
// in the input, force the copy of specular data
if( qwFVFIn & D3DFVF_SPECULAR )
{
m_RefVP.m_dwTLState |= RDPV_VERTEXSPECULARNEEDED;
}
//
// Update the remaining light state
//
HR_RET(m_RefVP.UpdateLightingData());
}
if( (m_RefVP.m_dwTLState & RDPV_DOFOG) &&
(m_RefVP.m_dwDirtyFlags & RDPV_DIRTY_FOG) )
{
HR_RET(m_RefVP.UpdateFogData());
}
//
// Compute output FVF
//
BOOL bFogEnabled = GetRS()[D3DRENDERSTATE_FOGENABLE];
BOOL bSpecularEnabled = GetRS()[D3DRENDERSTATE_SPECULARENABLE];
m_qwFVFOut = D3DFVF_XYZRHW;
// If normal is present we have to compute specular and diffuse
// Otherwise set these bits the same as input.
// Not that normal should not be present for XYZRHW position type
if( m_RefVP.m_dwTLState & RDPV_DOLIGHTING )
{
m_qwFVFOut |= D3DFVF_DIFFUSE | D3DFVF_SPECULAR;
}
else
{
m_qwFVFOut |= (qwFVFIn & (D3DFVF_DIFFUSE | D3DFVF_SPECULAR));
}
// Clear specular flag if specular disabled
// else if( !this->rstates[D3DRENDERSTATE_SPECULARENABLE] )
if( !bSpecularEnabled && ((qwFVFIn & D3DFVF_SPECULAR) == 0))
{
m_qwFVFOut &= ~D3DFVF_SPECULAR;
}
// Always set specular flag if fog is enabled
// if( this->rstates[D3DRENDERSTATE_FOGENABLE] )
if( bFogEnabled && (!GetRS()[D3DRENDERSTATE_FOGTABLEMODE]) )
{
m_qwFVFOut |= D3DFVFP_FOG;
}
// Reserve space for point size, if needed
if( m_RefVP.m_dwTLState & RDPV_DOCOMPUTEPOINTSIZE )
{
m_qwFVFOut |= D3DFVF_PSIZE;
}
if( m_RefVP.m_dwTLState & (RDPV_DOTEXGEN | RDPV_DOTEXXFORM) )
{
// If there was any need for TexTransform or TexGen, we need to
// override the TCI per stage.
m_bOverrideTCI = TRUE;
m_qwFVFOut |= (m_cActiveTextureStages << D3DFVF_TEXCOUNT_SHIFT);
// Now compute the texture formats
for( dwStage = 0; dwStage < (DWORD)m_cActiveTextureStages; dwStage++ )
{
DWORD dwTextureFormat = 0;
DWORD TCI = GetTSS(dwStage)[D3DTSS_TEXCOORDINDEX];
DWORD TexGenMode = TCI & ~0xFFFF;
TCI &= 0xFFFF;
switch( TexGenMode )
{
case D3DTSS_TCI_CAMERASPACENORMAL:
dwTextureFormat = D3DFVF_TEXCOORDSIZE3(dwStage);
m_RefVP.m_dwTLState |= RDPV_NEEDEYENORMAL;
break;
case D3DTSS_TCI_CAMERASPACEPOSITION:
dwTextureFormat = D3DFVF_TEXCOORDSIZE3(dwStage);
m_RefVP.m_dwTLState |= RDPV_NEEDEYEXYZ;
break;
case D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR:
dwTextureFormat = D3DFVF_TEXCOORDSIZE3(dwStage);
m_RefVP.m_dwTLState |= (RDPV_NEEDEYENORMAL | RDPV_NEEDEYEXYZ);
break;
case 0: // No TexGen
// Set back the input texture format
dwTextureFormat =
(D3DFVF_GETTEXCOORDSIZE( qwFVFIn, TCI ) << (dwStage*2 + 16));
break;
default:
DPFERR( "Unknown TexGen mode" );
return E_FAIL;
}
// Adjust the format for TexTransform
DWORD TexXfmFlags =
GetTSS(dwStage)[D3DTSS_TEXTURETRANSFORMFLAGS];
if( TexXfmFlags )
{
switch( TexXfmFlags & ~D3DTTFF_PROJECTED )
{
case D3DTTFF_DISABLE:
break;
case D3DTTFF_COUNT1:
dwTextureFormat = D3DFVF_TEXCOORDSIZE1( dwStage );
break;
case D3DTTFF_COUNT2:
dwTextureFormat = D3DFVF_TEXCOORDSIZE2( dwStage );
break;
case D3DTTFF_COUNT3:
dwTextureFormat = D3DFVF_TEXCOORDSIZE3( dwStage );
break;
case D3DTTFF_COUNT4:
dwTextureFormat = D3DFVF_TEXCOORDSIZE4( dwStage );
break;
default:
DPFERR( "Unknown dimension" );
return E_FAIL;
}
}
m_qwFVFOut |= dwTextureFormat;
}
}
else
{
// Set up number of texture coordinates and copy texture formats
DWORD numTex = FVF_TEXCOORD_NUMBER(qwFVFIn);
m_qwFVFOut |= (numTex << D3DFVF_TEXCOUNT_SHIFT) |
(qwFVFIn & 0xFFFF0000);
}
m_RefVP.m_qwFVFOut = m_qwFVFOut;
//
// Set up the strides for the vertex processing
//
return SetupStrides();
}
///////////////////////////////////////////////////////////////////////////////
// RefVP method implementations
///////////////////////////////////////////////////////////////////////////////
//---------------------------------------------------------------------
// RefVP::ProcessVertices
//---------------------------------------------------------------------
RDCLIPCODE
RefVP::ProcessVertices( UINT64 outFVF, GArrayT<RDVertex>& VtxArray,
DWORD count )
{
UINT64 inFVF = m_qwFVFIn;
RefClipper& Clipper = m_pDev->GetClipper();
DWORD flags = m_dwTLState;
RDCLIPCODE clipIntersection = ~0;
RDCLIPCODE clipUnion = 0;
RDLIGHTINGELEMENT le;
BOOL bVertexInEyeSpace = FALSE;
DWORD dwCurrVtx = 0;
RDVECTOR3* pPos = (RDVECTOR3 *)m_position.GetFirst();
RDVECTOR3* pPos2 = (RDVECTOR3 *)m_position2.GetFirst();
float* pBlendFactors = (float *)m_blendweights.GetFirst();
DWORD* pBlendIndices = (DWORD *)m_blendindices.GetFirst();
RDVECTOR3* pNormal = (RDVECTOR3 *)m_normal.GetFirst();
RDVECTOR3* pNormal2 = (RDVECTOR3 *)m_normal2.GetFirst();
DWORD* pDiffuse = (DWORD *)m_diffuse.GetFirst();
DWORD* pSpecular = (DWORD *)m_specular.GetFirst();
float* pPointSize = (float *)m_pointsize.GetFirst();
float* pTex[8];
RDVECTOR3 positionT, normalT; // Tweening results are saved here
for( int t = 0; t < 8 ; t++ )
pTex[t] = (float *)m_tex[t].GetFirst();
//
// Number of vertices to blend. i.e number of blend-matrices to
// use is numVertexBlends+1.
//
int numVertexBlends = m_numVertexBlends;
m_lighting.outDiffuse = RD_DEFAULT_DIFFUSE;
m_lighting.outSpecular = RD_DEFAULT_SPECULAR;
//
// The main transform loop
//
for( DWORD i = count; i; i-- )
{
RDVertex& Vout = VtxArray[dwCurrVtx++];
Vout.SetFVF( outFVF | D3DFVFP_CLIP );
float x_clip=0.0f, y_clip=0.0f, z_clip=0.0f, w_clip=0.0f;
float inv_w_clip=0.0f;
float cumulBlend = 0; // Blend accumulated so far
ZeroMemory( &le, sizeof(RDLIGHTINGELEMENT) );
RDVECTOR3 ZeroNormal;
if( pNormal == NULL )
{
pNormal = &ZeroNormal;
}
//
// Transform vertex to the clipping space, and position and normal
// into eye space, if needed.
//
// Tween the Position if needed
if( flags & RDPV_DOPOSITIONTWEENING )
{
positionT.x = pPos->x * (1.0f - m_fTweenFactor) +
pPos2->x * m_fTweenFactor;
positionT.y = pPos->y * (1.0f - m_fTweenFactor) +
pPos2->y * m_fTweenFactor;
positionT.z = pPos->z * (1.0f - m_fTweenFactor) +
pPos2->z * m_fTweenFactor;
pPos = &positionT;
}
if( flags & RDPV_DONORMALTWEENING )
{
normalT.x = pNormal->x * (1.0f - m_fTweenFactor) +
pNormal2->x * m_fTweenFactor;
normalT.y = pNormal->y * (1.0f - m_fTweenFactor) +
pNormal2->y * m_fTweenFactor;
normalT.z = pNormal->z * (1.0f - m_fTweenFactor) +
pNormal2->z * m_fTweenFactor;
pNormal = &normalT;
}
for( int j=0; j<=numVertexBlends; j++)
{
float blend;
if( numVertexBlends == 0 )
{
blend = 1.0f;
}
else if( j == numVertexBlends )
{
blend = 1.0f - cumulBlend;
}
else
{
blend = pBlendFactors[j];
cumulBlend += pBlendFactors[j];
}
if( flags & (RDPV_DOCOMPUTEPOINTSIZE | RDPV_DOLIGHTING |
RDPV_NEEDEYEXYZ) )
{
bVertexInEyeSpace = TRUE;
if( flags & RDPV_DOINDEXEDVERTEXBLEND )
{
BYTE m = ((BYTE *)pBlendIndices)[j];
UpdateWorld( m );
le.dvPosition.x += (pPos->x*m_xfmToEye[m]._11 +
pPos->y*m_xfmToEye[m]._21 +
pPos->z*m_xfmToEye[m]._31 +
m_xfmToEye[m]._41) * blend;
le.dvPosition.y += (pPos->x*m_xfmToEye[m]._12 +
pPos->y*m_xfmToEye[m]._22 +
pPos->z*m_xfmToEye[m]._32 +
m_xfmToEye[m]._42) * blend;
le.dvPosition.z += (pPos->x*m_xfmToEye[m]._13 +
pPos->y*m_xfmToEye[m]._23 +
pPos->z*m_xfmToEye[m]._33 +
m_xfmToEye[m]._43) * blend;
}
else
{
le.dvPosition.x += (pPos->x*m_xfmToEye[j]._11 +
pPos->y*m_xfmToEye[j]._21 +
pPos->z*m_xfmToEye[j]._31 +
m_xfmToEye[j]._41) * blend;
le.dvPosition.y += (pPos->x*m_xfmToEye[j]._12 +
pPos->y*m_xfmToEye[j]._22 +
pPos->z*m_xfmToEye[j]._32 +
m_xfmToEye[j]._42) * blend;
le.dvPosition.z += (pPos->x*m_xfmToEye[j]._13 +
pPos->y*m_xfmToEye[j]._23 +
pPos->z*m_xfmToEye[j]._33 +
m_xfmToEye[j]._43) * blend;
}
}
if( flags & (RDPV_DOLIGHTING | RDPV_NEEDEYENORMAL) )
{
if( flags & RDPV_DOINDEXEDVERTEXBLEND )
{
BYTE m = ((BYTE *)pBlendIndices)[j];
UpdateWorld( m );
le.dvNormal.x += (pNormal->x*m_xfmToEyeInv[m]._11 +
pNormal->y*m_xfmToEyeInv[m]._12 +
pNormal->z*m_xfmToEyeInv[m]._13) * blend;
le.dvNormal.y += (pNormal->x*m_xfmToEyeInv[m]._21 +
pNormal->y*m_xfmToEyeInv[m]._22 +
pNormal->z*m_xfmToEyeInv[m]._23) * blend;
le.dvNormal.z += (pNormal->x*m_xfmToEyeInv[m]._31 +
pNormal->y*m_xfmToEyeInv[m]._32 +
pNormal->z*m_xfmToEyeInv[m]._33) * blend;
}
else
{
// Transform vertex normal to the eye space
// We use inverse transposed matrix
le.dvNormal.x += (pNormal->x*m_xfmToEyeInv[j]._11 +
pNormal->y*m_xfmToEyeInv[j]._12 +
pNormal->z*m_xfmToEyeInv[j]._13) * blend;
le.dvNormal.y += (pNormal->x*m_xfmToEyeInv[j]._21 +
pNormal->y*m_xfmToEyeInv[j]._22 +
pNormal->z*m_xfmToEyeInv[j]._23) * blend;
le.dvNormal.z += (pNormal->x*m_xfmToEyeInv[j]._31 +
pNormal->y*m_xfmToEyeInv[j]._32 +
pNormal->z*m_xfmToEyeInv[j]._33) * blend;
}
}
if( flags & RDPV_DOINDEXEDVERTEXBLEND )
{
BYTE m = ((BYTE *)pBlendIndices)[j];
UpdateWorld( m );
x_clip += (pPos->x*m_xfmCurrent[m]._11 +
pPos->y*m_xfmCurrent[m]._21 +
pPos->z*m_xfmCurrent[m]._31 +
m_xfmCurrent[m]._41) * blend;
y_clip += (pPos->x*m_xfmCurrent[m]._12 +
pPos->y*m_xfmCurrent[m]._22 +
pPos->z*m_xfmCurrent[m]._32 +
m_xfmCurrent[m]._42) * blend;
z_clip += (pPos->x*m_xfmCurrent[m]._13 +
pPos->y*m_xfmCurrent[m]._23 +
pPos->z*m_xfmCurrent[m]._33 +
m_xfmCurrent[m]._43) * blend;
w_clip += (pPos->x*m_xfmCurrent[m]._14 +
pPos->y*m_xfmCurrent[m]._24 +
pPos->z*m_xfmCurrent[m]._34 +
m_xfmCurrent[m]._44) * blend;
}
else
{
// Apply WORLDj
x_clip += (pPos->x*m_xfmCurrent[j]._11 +
pPos->y*m_xfmCurrent[j]._21 +
pPos->z*m_xfmCurrent[j]._31 +
m_xfmCurrent[j]._41) * blend;
y_clip += (pPos->x*m_xfmCurrent[j]._12 +
pPos->y*m_xfmCurrent[j]._22 +
pPos->z*m_xfmCurrent[j]._32 +
m_xfmCurrent[j]._42) * blend;
z_clip += (pPos->x*m_xfmCurrent[j]._13 +
pPos->y*m_xfmCurrent[j]._23 +
pPos->z*m_xfmCurrent[j]._33 +
m_xfmCurrent[j]._43) * blend;
w_clip += (pPos->x*m_xfmCurrent[j]._14 +
pPos->y*m_xfmCurrent[j]._24 +
pPos->z*m_xfmCurrent[j]._34 +
m_xfmCurrent[j]._44) * blend;
}
}
// Save the clip-coordinates
Vout.m_clip_x = x_clip;
Vout.m_clip_y = y_clip;
Vout.m_clip_z = z_clip;
Vout.m_clip_w = w_clip;
if( (flags & RDPV_NORMALIZENORMALS) &&
(flags & (RDPV_DOLIGHTING | RDPV_NEEDEYENORMAL)) )
{
Normalize(le.dvNormal);
}
FLOAT fPointSize = 0.0f;
if( flags & RDPV_DOCOMPUTEPOINTSIZE )
{
FLOAT fDist = (FLOAT)sqrt(le.dvPosition.x*le.dvPosition.x +
le.dvPosition.y*le.dvPosition.y +
le.dvPosition.z*le.dvPosition.z);
if( inFVF & D3DFVF_PSIZE )
{
fPointSize = *pPointSize;
}
else
{
// from D3DRENDERSTATE_POINTSIZE
fPointSize = m_fPointSize;
}
if( flags & RDPV_DOPOINTSCALE )
{
fPointSize = (float)Clipper.m_Viewport.dwHeight*
fPointSize*(FLOAT)sqrt(1.0f/
(m_fPointAttA + m_fPointAttB*fDist +
m_fPointAttC*fDist*fDist));
}
fPointSize = max(m_fPointSizeMin, fPointSize);
fPointSize = min(m_fPointSizeMax, fPointSize);
FLOAT *pfSOut = &Vout.m_pointsize;
*pfSOut = fPointSize;
}
//
// Compute clip codes if needed
//
if( flags & RDPV_DOCLIPPING )
{
RDCLIPCODE clip = Clipper.ComputeClipCodes( &clipIntersection,
&clipUnion, x_clip,
y_clip, z_clip,
w_clip);
if( clip == 0 )
{
Vout.m_clip = 0;
inv_w_clip = D3DVAL(1)/w_clip;
}
else
{
if( Clipper.UseGuardBand() )
{
if( (clip & ~RDCLIP_INGUARDBAND) == 0 )
{
// If vertex is inside the guardband we have to compute
// screen coordinates
inv_w_clip = D3DVAL(1)/w_clip;
Vout.m_clip = (RDCLIPCODE)clip;
goto l_DoScreenCoord;
}
}
Vout.m_clip = (RDCLIPCODE)clip;
// If vertex is outside the frustum we can not compute screen
// coordinates. skip to lighting
#if 0
Vout.m_pos.x = x_clip;
Vout.m_pos.y = y_clip;
Vout.m_pos.z = z_clip;
Vout.m_rhw = w_clip;
#endif
goto l_DoLighting;
}
}
else
{
// We have to check this only for DONOTCLIP case, because otherwise
// the vertex with "we = 0" will be clipped and screen coordinates
// will not be computed
// "clip" is not zero, if "we" is zero.
if( !FLOAT_EQZ(w_clip) )
inv_w_clip = D3DVAL(1)/w_clip;
else
inv_w_clip = __HUGE_PWR2;
}
l_DoScreenCoord:
Vout.m_pos.x = x_clip * inv_w_clip * Clipper.scaleX +
Clipper.offsetX;
Vout.m_pos.y = y_clip * inv_w_clip * Clipper.scaleY +
Clipper.offsetY;
Vout.m_pos.z = z_clip * inv_w_clip * Clipper.scaleZ +
Clipper.offsetZ;
Vout.m_rhw = inv_w_clip;
l_DoLighting:
if( flags & RDPV_DOLIGHTING )
{
bVertexInEyeSpace = TRUE;
//
// If Diffuse color is needed, extract it for color vertex.
//
if( flags & RDPV_VERTEXDIFFUSENEEDED )
{
const DWORD color = *pDiffuse;
MakeRDCOLOR3(&m_lighting.vertexDiffuse, color);
m_lighting.vertexDiffAlpha = color & 0xff000000;
}
//
// If Specular color is needed and provided
// , extract it for color vertex.
//
if( flags & RDPV_VERTEXSPECULARNEEDED )
{
const DWORD color = *pSpecular;
MakeRDCOLOR3(&m_lighting.vertexSpecular, color);
m_lighting.vertexSpecAlpha = color & 0xff000000;
}
//
// Light the vertex
//
LightVertex( &le );
if( outFVF & D3DFVFP_FOG )
{
Vout.m_fog =
(FLOAT)RGBA_GETALPHA( *(m_lighting.pSpecularAlphaSrc) )/255.0f;
}
}
else if( inFVF & (D3DFVF_DIFFUSE | D3DFVF_SPECULAR) )
{
if( inFVF & D3DFVF_DIFFUSE )
m_lighting.outDiffuse = *pDiffuse;
if( inFVF & D3DFVF_SPECULAR )
{
m_lighting.outSpecular = *pSpecular;
if( outFVF & D3DFVFP_FOG )
{
Vout.m_fog = (FLOAT)RGBA_GETALPHA( *pSpecular )/255.0f;
}
}
}
//
// Compute Vertex Fog if needed
//
if( flags & RDPV_DOFOG )
{
FogVertex( Vout, *pPos, &le, numVertexBlends,
pBlendFactors, bVertexInEyeSpace );
}
if( outFVF & D3DFVF_DIFFUSE )
{
MakeRDCOLOR4( &Vout.m_diffuse, m_lighting.outDiffuse );
}
if( outFVF & D3DFVF_SPECULAR )
{
MakeRDCOLOR4( &Vout.m_specular, m_lighting.outSpecular );
}
if( flags & (RDPV_DOTEXGEN | RDPV_DOTEXXFORM) )
{
for( DWORD dwStage = 0;
dwStage < m_dwNumActiveTextureStages;
dwStage++ )
{
DWORD TexXfmFlags =
m_pDev->GetTSS(dwStage)[D3DTSS_TEXTURETRANSFORMFLAGS];
DWORD TCI =
m_pDev->GetTSS(dwStage)[D3DTSS_TEXCOORDINDEX];
DWORD TexGenMode = TCI & ~0xFFFF;
TCI &= 0xFFFF;
// Perform TexGen
switch( TexGenMode )
{
case D3DTSS_TCI_CAMERASPACENORMAL:
Vout.m_tex[dwStage].x = le.dvNormal.x;
Vout.m_tex[dwStage].y = le.dvNormal.y;
Vout.m_tex[dwStage].z = le.dvNormal.z;
Vout.m_tex[dwStage].w = 1.0f;
break;
case D3DTSS_TCI_CAMERASPACEPOSITION:
Vout.m_tex[dwStage].x = le.dvPosition.x;
Vout.m_tex[dwStage].y = le.dvPosition.y;
Vout.m_tex[dwStage].z = le.dvPosition.z;
Vout.m_tex[dwStage].w = 1.0f;
break;
case D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR:
{
FLOAT fNX = le.dvNormal.x;
FLOAT fNY = le.dvNormal.y;
FLOAT fNZ = le.dvNormal.z;
FLOAT fNorm = 0;
if( m_pDev->GetRS()[D3DRENDERSTATE_LOCALVIEWER] == TRUE )
{
FLOAT fX = le.dvPosition.x;
FLOAT fY = le.dvPosition.y;
FLOAT fZ = le.dvPosition.z;
// have to normalize before we reflect,
// result will be normalized
FLOAT fDist = (FLOAT)sqrt(fX*fX + fY*fY + fZ*fZ);
if( FLOAT_NEZ( fDist ) )
{
fNorm = 1.0f/fDist;
}
fX *= fNorm; fY *= fNorm; fZ *= fNorm;
FLOAT fDot2 = 2.0f*(fX*fNX + fY*fNY + fZ*fNZ);
Vout.m_tex[dwStage].x = fX - fNX*fDot2;
Vout.m_tex[dwStage].y = fY - fNY*fDot2;
Vout.m_tex[dwStage].z = fZ - fNZ*fDot2;
}
else
{
FLOAT fDot2 = 2.0f*fNZ;
Vout.m_tex[dwStage].x = -fNX*fDot2;
Vout.m_tex[dwStage].y = -fNY*fDot2;
Vout.m_tex[dwStage].z = 1.f - fNZ*fDot2;
}
Vout.m_tex[dwStage].w = 1.0f;
break;
}
case 0: // No TexGen
{
// Copy the tex coordinate for this stage
DWORD n = GetTexCoordDim( inFVF, TCI );
float *pCoord = (float *)&Vout.m_tex[dwStage];
for( DWORD j = 0; j < n; j++ )
{
pCoord[j] = pTex[TCI][j];
}
if( n < 4 ) pCoord[n] = 1.0f;
for( j = n+1; j < 4; j++ ) pCoord[j] = 0.0f;
break;
}
default:
DPFERR( "Unknown TexGen mode" );
return E_FAIL;
}
// Perform TexTransform
if( ( TexXfmFlags & ~D3DTTFF_PROJECTED ) != D3DTTFF_DISABLE )
{
LPD3DMATRIX pM = &m_xfmTex[dwStage];
FLOAT fX = Vout.m_tex[dwStage].x;
FLOAT fY = Vout.m_tex[dwStage].y;
FLOAT fZ = Vout.m_tex[dwStage].z;
FLOAT fW = Vout.m_tex[dwStage].w;
FLOAT fXout = fX*pM->_11 + fY*pM->_21 + fZ*pM->_31 +
fW*pM->_41;
FLOAT fYout = fX*pM->_12 + fY*pM->_22 + fZ*pM->_32 +
fW*pM->_42;
FLOAT fZout = fX*pM->_13 + fY*pM->_23 + fZ*pM->_33 +
fW*pM->_43;
FLOAT fWout = fX*pM->_14 + fY*pM->_24 + fZ*pM->_34 +
fW*pM->_44;
Vout.m_tex[dwStage].x = fXout;
Vout.m_tex[dwStage].y = fYout;
Vout.m_tex[dwStage].z = fZout;
Vout.m_tex[dwStage].w = fWout;
}
}
}
else
{
// Copy the textures over
// If there is no TexGen or TexTransform
DWORD i, j;
DWORD numTex = FVF_TEXCOORD_NUMBER(outFVF);
for( i = 0; i < numTex; i++ )
{
DWORD n = GetTexCoordDim( outFVF, i );
// DWORD n = (DWORD)(m_dwTexCoordSizeArray[i] >> 2);
float *pCoord = (float *)&Vout.m_tex[i];
for( j = 0; j < n; j++ )
{
pCoord[j] = pTex[i][j];
}
}
}
//
// Update the current pointers
//
pPos = (RDVECTOR3 *)m_position.Next();
pPos2 = (RDVECTOR3 *)m_position2.Next();
pBlendFactors = (float *)m_blendweights.Next();
pBlendIndices = (DWORD *)m_blendindices.Next();
pNormal = (RDVECTOR3 *)m_normal.Next();
pNormal2 = (RDVECTOR3 *)m_normal2.Next();
pDiffuse = (DWORD *)m_diffuse.Next();
pSpecular = (DWORD *)m_specular.Next();
pPointSize = (float *)m_pointsize.Next();
for( t = 0; t < 8; t++ )
pTex[t] = (float *)m_tex[t].Next();
}
if( flags & RDPV_DOCLIPPING )
{
Clipper.m_clipIntersection = clipIntersection;
Clipper.m_clipUnion = clipUnion;
}
else
{
Clipper.m_clipIntersection = 0;
Clipper.m_clipUnion = 0;
}
// Returns whether all the vertices were off screen
return Clipper.m_clipIntersection;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////