|
|
#include "pch.cpp"
#pragma hdrstop
///////////////////////////////////////////////////////////////////////////////
// Vertex Lighting function implementations
///////////////////////////////////////////////////////////////////////////////
//---------------------------------------------------------------------
void RDLV_Directional( RDLIGHTINGDATA& LData, D3DLIGHT7 *pLight, RDLIGHTI *pLightI, RDLIGHTINGELEMENT *in, DWORD dwFlags, UINT64 qwFVFIn) { // ATTENTION: Need to heed the specular flag set per light here!!
BOOL bDoSpecular = dwFlags & RDPV_DOSPECULAR; BOOL bDoLocalViewer = dwFlags & RDPV_LOCALVIEWER; BOOL bDoColVertexAmbient = dwFlags & RDPV_COLORVERTEXAMB; BOOL bDoColVertexDiffuse = dwFlags & RDPV_COLORVERTEXDIFF; BOOL bDoColVertexSpecular = dwFlags & RDPV_COLORVERTEXSPEC;
//
// Add the material's ambient component
//
if (!bDoColVertexAmbient) { LData.diffuse.r += pLightI->Ma_La.r; LData.diffuse.g += pLightI->Ma_La.g; LData.diffuse.b += pLightI->Ma_La.b; } else { //
// Note:
// In case ColorVertexAmbient is enabled, note that it uses
// VertexSpecular instead of VertexDiffuse
//
LData.diffuse.r += pLightI->La.r * LData.pAmbientSrc->r; LData.diffuse.g += pLightI->La.g * LData.pAmbientSrc->g; LData.diffuse.b += pLightI->La.b * LData.pAmbientSrc->b; }
//
// If no normals are present, bail out since we cannot perform the
// normal-dependent computations
//
if( (qwFVFIn & D3DFVF_NORMAL) == 0 ) { return; }
D3DVALUE dot = DotProduct( pLightI->direction_in_eye, in->dvNormal ); if (FLOAT_GTZ(dot)) { if (!bDoColVertexDiffuse) { LData.diffuse.r += pLightI->Md_Ld.r * dot; LData.diffuse.g += pLightI->Md_Ld.g * dot; LData.diffuse.b += pLightI->Md_Ld.b * dot; } else { LData.diffuse.r += pLightI->Ld.r * LData.pDiffuseSrc->r * dot; LData.diffuse.g += pLightI->Ld.g * LData.pDiffuseSrc->g * dot; LData.diffuse.b += pLightI->Ld.b * LData.pDiffuseSrc->b * dot; }
if (bDoSpecular) { RDVECTOR3 h; // halfway vector
RDVECTOR3 eye; // incident vector ie vector from eye
if (bDoLocalViewer) { // calc vector from vertex to the eye
SubtractVector( LData.eye_in_eye, in->dvPosition, eye );
// normalize
Normalize( eye ); } else { eye.x = D3DVALUE( 0.0 ); eye.y = D3DVALUE( 0.0 ); eye.z = D3DVALUE(-1.0 ); }
// calc halfway vector
AddVector( pLightI->direction_in_eye, eye, h );
// normalize
Normalize( h );
dot = DotProduct( h, in->dvNormal );
if (FLOAT_GTZ(dot)) { if (FLOAT_CMP_POS(dot, >=, LData.specThreshold)) { D3DVALUE coeff = pow( dot, LData.material.power ); if (!bDoColVertexSpecular) { LData.specular.r += pLightI->Ms_Ls.r * coeff; LData.specular.g += pLightI->Ms_Ls.g * coeff; LData.specular.b += pLightI->Ms_Ls.b * coeff; } else { LData.specular.r += (pLightI->Ls.r * LData.pSpecularSrc->r * coeff); LData.specular.g += (pLightI->Ls.g * LData.pSpecularSrc->g * coeff); LData.specular.b += (pLightI->Ls.b * LData.pSpecularSrc->b * coeff); } } } } } return; }
void RDLV_PointAndSpot( RDLIGHTINGDATA &LData, D3DLIGHT7 *pLight, RDLIGHTI *pLightI, RDLIGHTINGELEMENT *in, DWORD dwFlags, UINT64 qwFVFIn) { // ATTENTION: Need to heed the specular flag set per light here!!
BOOL bDoSpecular = dwFlags & RDPV_DOSPECULAR; BOOL bDoLocalViewer = dwFlags & RDPV_LOCALVIEWER; BOOL bDoColVertexAmbient = dwFlags & RDPV_COLORVERTEXAMB; BOOL bDoColVertexDiffuse = dwFlags & RDPV_COLORVERTEXDIFF; BOOL bDoColVertexSpecular = dwFlags & RDPV_COLORVERTEXSPEC; RDVECTOR3 d; // Direction to light
D3DVALUE att; D3DVALUE dist; D3DVALUE dot;
SubtractVector( pLightI->position_in_eye, in->dvPosition, d );
// early out if out of range or exactly on the vertex
D3DVALUE distSquared = SquareMagnitude( d ); if (FLOAT_CMP_POS(distSquared, >=, pLightI->range_squared) || FLOAT_EQZ(distSquared)) { return; }
//
// Compute the attenuation
//
dist = SQRTF( distSquared ); att = pLight->dvAttenuation0 + pLight->dvAttenuation1 * dist + pLight->dvAttenuation2 * distSquared;
if (FLOAT_EQZ(att)) att = FLT_MAX; else att = (D3DVALUE)1.0/att;
dist = D3DVAL(1)/dist;
//
// If the light is a spotlight compute the spot-light factor
//
if (pLight->dltType == D3DLIGHT_SPOT) { // Calc dot product of direction to light with light direction to
// be compared anganst the cone angles to see if we are in the
// light.
// Note that cone_dot is still scaled by dist
D3DVALUE cone_dot = DotProduct(d, pLightI->direction_in_eye) * dist;
if (FLOAT_CMP_POS(cone_dot, <=, pLightI->cos_phi_by_2)) { return; }
// modify att if in the region between phi and theta
if (FLOAT_CMP_POS(cone_dot, <, pLightI->cos_theta_by_2)) { D3DVALUE val = (cone_dot - pLightI->cos_phi_by_2) * pLightI->inv_theta_minus_phi;
if (!FLOAT_EQZ( pLight->dvFalloff - 1.0 )) { val = POWF( val, pLight->dvFalloff ); } att *= val; } }
//
// Add the material's ambient component
//
if (!bDoColVertexAmbient) { LData.diffuse.r += att*pLightI->Ma_La.r; LData.diffuse.g += att*pLightI->Ma_La.g; LData.diffuse.b += att*pLightI->Ma_La.b; } else { //
// Note:
// In case ColorVertexAmbient is enabled, note that it uses
// VertexSpecular instead of VertexDiffuse
//
LData.diffuse.r += att*pLightI->La.r * LData.pAmbientSrc->r; LData.diffuse.g += att*pLightI->La.g * LData.pAmbientSrc->g; LData.diffuse.b += att*pLightI->La.b * LData.pAmbientSrc->b; }
// Calc dot product of light dir with normal. Note that since we
// didn't normalize the direction the result is scaled by the distance.
if( (qwFVFIn & D3DFVF_NORMAL) == 0) { // If no normals are present, bail out since we cannot perform the
// normal-dependent computations
return; } else { dot = DotProduct( d, in->dvNormal ); }
if (FLOAT_GTZ( dot )) { dot *= dist*att;
if (!bDoColVertexDiffuse) { LData.diffuse.r += pLightI->Md_Ld.r * dot; LData.diffuse.g += pLightI->Md_Ld.g * dot; LData.diffuse.b += pLightI->Md_Ld.b * dot; } else { LData.diffuse.r += pLightI->Ld.r * LData.pDiffuseSrc->r * dot; LData.diffuse.g += pLightI->Ld.g * LData.pDiffuseSrc->g * dot; LData.diffuse.b += pLightI->Ld.b * LData.pDiffuseSrc->b * dot; }
if (bDoSpecular) { RDVECTOR3 h; // halfway vector
RDVECTOR3 eye; // incident vector ie vector from eye
// normalize light direction
d.x *= dist; d.y *= dist; d.z *= dist;
if (bDoLocalViewer) { // calc vector from vertex to the eye
SubtractVector( LData.eye_in_eye, in->dvPosition, eye );
// normalize
Normalize( eye ); } else { eye.x = D3DVALUE( 0.0 ); eye.y = D3DVALUE( 0.0 ); eye.z = D3DVALUE(-1.0 ); }
// calc halfway vector
AddVector( d, eye, h ); Normalize( h );
dot = DotProduct( h, in->dvNormal );
if (FLOAT_CMP_POS(dot, >=, LData.specThreshold)) { D3DVALUE coeff = pow( dot, LData.material.power ) * att; if (!bDoColVertexSpecular) { LData.specular.r += pLightI->Ms_Ls.r * coeff; LData.specular.g += pLightI->Ms_Ls.g * coeff; LData.specular.b += pLightI->Ms_Ls.b * coeff; } else { LData.specular.r += (pLightI->Ls.r * LData.pSpecularSrc->r * coeff); LData.specular.g += (pLightI->Ls.g * LData.pSpecularSrc->g * coeff); LData.specular.b += (pLightI->Ls.b * LData.pSpecularSrc->b * coeff); } } } } return; }
///////////////////////////////////////////////////////////////////////////////
// RDLight
///////////////////////////////////////////////////////////////////////////////
RDLight::RDLight() { m_dwFlags = RDLIGHT_NEEDSPROCESSING; m_Next = NULL;
ZeroMemory(&m_Light, sizeof(m_Light)); ZeroMemory(&m_LightI, sizeof(m_LightI));
// Initialize the light to some default values
m_Light.dltType = D3DLIGHT_DIRECTIONAL;
m_Light.dcvDiffuse.r = 1; m_Light.dcvDiffuse.g = 1; m_Light.dcvDiffuse.b = 1; m_Light.dcvDiffuse.a = 0;
m_Light.dvDirection.x = 0; m_Light.dvDirection.y = 0; m_Light.dvDirection.z = 1;
// m_Light.dcvSpecular = {0,0,0,0};
// m_Light.dcvAmbient = {0,0,0,0};
// m_Light.dvPosition = {0,0,0};
// m_Light.dvRange = 0;
// m_Light.dvFalloff = 0;
// m_Light.dvAttenuation0 = 0;
// m_Light.dvAttenuation1 = 0;
// m_Light.dvAttenuation2 = 0;
// m_Light.dvTheta = 0;
// m_Light.dvPhi = 0;
return; }
HRESULT RDLight::SetLight(LPD3DLIGHT7 pLight) {
// Validate the parameters passed
switch (pLight->dltType) { case D3DLIGHT_POINT: case D3DLIGHT_SPOT: case D3DLIGHT_DIRECTIONAL: break; default: // No other light types are allowed
DPFRR(0, "Invalid light type passed"); return DDERR_INVALIDPARAMS; } if (pLight) m_Light = *pLight;
// Mark it for processing later
m_dwFlags |= (RDLIGHT_NEEDSPROCESSING | RDLIGHT_REFERED); return DD_OK; }
HRESULT RDLight::GetLight(LPD3DLIGHT7 pLight) { if (pLight == NULL) return DDERR_GENERIC; *pLight = m_Light; return D3D_OK; }
void RDLight::ProcessLight(D3DMATERIAL7 *mat, RDLIGHTVERTEX_FUNC_TABLE *pTbl) { //
// If it is already processed, return
//
if (!NeedsProcessing()) return;
//
// Save the ambient light (0-1)
//
m_LightI.La.r = m_Light.dcvAmbient.r; m_LightI.La.g = m_Light.dcvAmbient.g; m_LightI.La.b = m_Light.dcvAmbient.b;
//
// Save the diffuse light (0-1)
//
m_LightI.Ld.r = m_Light.dcvDiffuse.r; m_LightI.Ld.g = m_Light.dcvDiffuse.g; m_LightI.Ld.b = m_Light.dcvDiffuse.b;
//
// Save the specular light (0-1)
//
m_LightI.Ls.r = m_Light.dcvSpecular.r; m_LightI.Ls.g = m_Light.dcvSpecular.g; m_LightI.Ls.b = m_Light.dcvSpecular.b;
//
// Material Ambient times Light Ambient
//
m_LightI.Ma_La.r = m_LightI.La.r * mat->ambient.r * D3DVALUE(255.0); m_LightI.Ma_La.g = m_LightI.La.g * mat->ambient.g * D3DVALUE(255.0); m_LightI.Ma_La.b = m_LightI.La.b * mat->ambient.b * D3DVALUE(255.0);
//
// Material Diffuse times Light Diffuse
//
m_LightI.Md_Ld.r = m_LightI.Ld.r * mat->diffuse.r * D3DVALUE(255.0); m_LightI.Md_Ld.g = m_LightI.Ld.g * mat->diffuse.g * D3DVALUE(255.0); m_LightI.Md_Ld.b = m_LightI.Ld.b * mat->diffuse.b * D3DVALUE(255.0);
//
// Material Specular times Light Specular
//
m_LightI.Ms_Ls.r = m_LightI.Ls.r * mat->specular.r * D3DVALUE(255.0); m_LightI.Ms_Ls.g = m_LightI.Ls.g * mat->specular.g * D3DVALUE(255.0); m_LightI.Ms_Ls.b = m_LightI.Ls.b * mat->specular.b * D3DVALUE(255.0);
//
// Assign the actual lighting function pointer, in addition to
// performing some precomputation of light-type specific data
//
m_pfnLightVertex = NULL; switch (m_Light.dltType) { case D3DLIGHT_DIRECTIONAL: m_pfnLightVertex = pTbl->pfnDirectional; break; case D3DLIGHT_POINT: m_LightI.range_squared = m_Light.dvRange * m_Light.dvRange; m_LightI.inv_theta_minus_phi = 1.0f; m_pfnLightVertex = pTbl->pfnPoint; break; case D3DLIGHT_SPOT: m_LightI.range_squared = m_Light.dvRange * m_Light.dvRange; m_LightI.cos_theta_by_2 = (float)cos(m_Light.dvTheta / 2.0); m_LightI.cos_phi_by_2 = (float)cos(m_Light.dvPhi / 2.0); m_LightI.inv_theta_minus_phi = m_LightI.cos_theta_by_2 - m_LightI.cos_phi_by_2; if (m_LightI.inv_theta_minus_phi != 0.0) { m_LightI.inv_theta_minus_phi = 1.0f/m_LightI.inv_theta_minus_phi; } else { m_LightI.inv_theta_minus_phi = 1.0f; } m_pfnLightVertex = pTbl->pfnSpot; break; default: DPFRR( 0, "Cannot process light of unknown type" ); break; }
// Mark it as been processed
m_dwFlags &= ~RDLIGHT_NEEDSPROCESSING; return; }
void RDLight::Enable(RDLight **ppRoot) { // Assert that it is not already enabled
if (IsEnabled()) return;
// Assert that Root Ptr is not Null
if (ppRoot == NULL) return;
RDLight *pTmp = *ppRoot; *ppRoot = this; m_Next = pTmp; m_dwFlags |= (RDLIGHT_ENABLED | RDLIGHT_REFERED);
return; }
void RDLight::Disable(RDLight **ppRoot) { // Assert that the light is enabled
if (!IsEnabled()) return;
// Assert that Root Ptr is not Null
if (ppRoot == NULL) return;
RDLight *pLightPrev = *ppRoot;
// If this is the first light in the active list
if (pLightPrev == this) { *ppRoot = m_Next; m_dwFlags &= ~RDLIGHT_ENABLED; return; }
while (pLightPrev->m_Next != this) { // Though this light was marked as enabled, it is not on
// the active list. Assert this.
if (pLightPrev->m_Next == NULL) { m_dwFlags &= ~RDLIGHT_ENABLED; return; }
// Else get the next pointer
pLightPrev = pLightPrev->m_Next; }
pLightPrev->m_Next = m_Next; m_dwFlags &= ~RDLIGHT_ENABLED; m_dwFlags |= RDLIGHT_REFERED; return; }
void RDLight::XformLight( RDMATRIX *mView ) { // If the light is not a directional light,
// tranform its position to camera space
if (m_Light.dltType != D3DLIGHT_DIRECTIONAL) { XformBy4x3((RDVECTOR3*)&m_Light.dvPosition, mView, &m_LightI.position_in_eye); }
if (m_Light.dltType != D3DLIGHT_POINT) { // Transform light direction to the eye space
Xform3VecBy3x3( (RDVECTOR3*)&m_Light.dvDirection, mView, &m_LightI.direction_in_eye ); // Normalize it
Normalize( m_LightI.direction_in_eye );
// Reverse it such that the direction is to the light
ReverseVector( m_LightI.direction_in_eye, m_LightI.direction_in_eye ); }
return; }
//---------------------------------------------------------------------
// ScaleRGBColorTo255: Scales colors from 0-1 range to 0-255 range
//---------------------------------------------------------------------
void ScaleRGBColorTo255( const D3DCOLORVALUE& src, RDCOLOR3& dest ) { dest.r = D3DVALUE(255.0) * src.r; dest.g = D3DVALUE(255.0) * src.g; dest.b = D3DVALUE(255.0) * src.b; }
//---------------------------------------------------------------------
// RefVP::GrowLightArray
// Grows the light array and recreated the active-list
// if a realloc has taken place.
//---------------------------------------------------------------------
HRESULT RefVP::GrowLightArray( DWORD dwIndex ) { HRESULT hr = S_OK; BOOL bRealloc = FALSE;
HR_RET(m_LightArray.Grow( dwIndex, &bRealloc )); if( bRealloc == TRUE ) { m_lighting.pActiveLights = NULL; for( DWORD i = 0; i < m_LightArray.GetSize(); i++ ) { if( m_LightArray[i].IsEnabled() ) { m_LightArray[i].m_Next = m_lighting.pActiveLights; m_lighting.pActiveLights = &(m_LightArray[i]); } } }
return S_OK; }
//---------------------------------------------------------------------
// RefVP::UpdateLightingData
// Updates lighting data used by ProcessVertices
//---------------------------------------------------------------------
HRESULT RefVP::UpdateLightingData() { HRESULT hr = D3D_OK; RDLIGHTINGDATA& LData = m_lighting; RDLight *pLight = m_lighting.pActiveLights; RDVECTOR3 t; D3DMATERIAL7 *mat = &m_Material;
//
// Eye in eye space
//
LData.eye_in_eye.x = (D3DVALUE)0; LData.eye_in_eye.y = (D3DVALUE)0; LData.eye_in_eye.z = (D3DVALUE)0;
// ATTENTION: Colorvertex may have changed the values of the
// material alphas
if (m_dwDirtyFlags & RDPV_DIRTY_MATERIAL) { //
// Save the material to be used to light vertices
//
LData.material = *mat; ScaleRGBColorTo255( mat->ambient, LData.matAmb ); ScaleRGBColorTo255( mat->diffuse, LData.matDiff ); ScaleRGBColorTo255( mat->specular, LData.matSpec ); ScaleRGBColorTo255( mat->emissive, LData.matEmis );
//
// Compute the Material Diffuse Alpha
//
LData.materialDiffAlpha = mat->diffuse.a * D3DVALUE(255); if (mat->diffuse.a < 0) LData.materialDiffAlpha = 0; else if (LData.materialDiffAlpha > 255) LData.materialDiffAlpha = 255 << 24; else LData.materialDiffAlpha <<= 24;
//
// Compute the Material Specular Alpha
//
LData.materialSpecAlpha = mat->specular.a * D3DVALUE(255); if (mat->specular.a < 0) LData.materialSpecAlpha = 0; else if (LData.materialSpecAlpha > 255) LData.materialSpecAlpha = 255 << 24; else LData.materialSpecAlpha <<= 24;
//
// Precompute the ambient and emissive components that are
// not dependent on any contribution by the lights themselves
//
LData.ambEmiss.r = LData.ambient_red * LData.matAmb.r + LData.matEmis.r; LData.ambEmiss.g = LData.ambient_green * LData.matAmb.g + LData.matEmis.g; LData.ambEmiss.b = LData.ambient_blue * LData.matAmb.b + LData.matEmis.b;
//
// If the dot product is less than this
// value, specular factor is zero
//
if (mat->power > D3DVAL(0.001)) { LData.specThreshold = D3DVAL(pow(0.001, 1.0/mat->power)); } }
while (pLight) { if ((m_dwDirtyFlags & RDPV_DIRTY_MATERIAL) || pLight->NeedsProcessing()) { // If the material is dirty, light needs processing, regardless
if (m_dwDirtyFlags & RDPV_DIRTY_MATERIAL) { pLight->m_dwFlags |= RDLIGHT_NEEDSPROCESSING; }
// If the light has been set, or some material paramenters
// changed, re-process the light.
pLight->ProcessLight( &m_Material, &m_LightVertexTable );
// Transform the light to Eye space
// Lights are defined in world space, so simply apply the
// Viewing transform
pLight->XformLight( &m_xfmView );
} else if (m_dwDirtyFlags & RDPV_DIRTY_NEEDXFMLIGHT) { pLight->XformLight( &m_xfmView ); }
pLight = pLight->m_Next; }
// Clear Lighting dirty flags
m_dwDirtyFlags &= ~RDPV_DIRTY_LIGHTING; return hr; }
//---------------------------------------------------------------------
// RefVP::UpdateFogData
// Updates Fog data used by ProcessVertices
//---------------------------------------------------------------------
HRESULT RefVP::UpdateFogData() { HRESULT hr = D3D_OK;
if (m_lighting.fog_end == m_lighting.fog_start) m_lighting.fog_factor = D3DVAL(0.0); else m_lighting.fog_factor = D3DVAL(255) / (m_lighting.fog_end - m_lighting.fog_start);
// Clear Fog dirty flags
m_dwDirtyFlags &= ~RDPV_DIRTY_FOG; return hr; }
//---------------------------------------------------------------------
// RefVP::LightVertex
// Actual lighting computation takes place here
//---------------------------------------------------------------------
void RefVP::LightVertex(RDLIGHTINGELEMENT *pLE) { RDLIGHTINGDATA &LData = m_lighting; RDLight *pLight;
//
// Initialize Diffuse color with the Ambient and Emissive component
// independent of the light (Ma*La + Me)
//
if (m_dwTLState & (RDPV_COLORVERTEXEMIS | RDPV_COLORVERTEXAMB)) { // If the material values need to be replaced, compute
LData.diffuse.r = LData.ambient_red * LData.pAmbientSrc->r + LData.pEmissiveSrc->r; LData.diffuse.g = LData.ambient_green * LData.pAmbientSrc->g + LData.pEmissiveSrc->g; LData.diffuse.b = LData.ambient_blue * LData.pAmbientSrc->b + LData.pEmissiveSrc->b; } else { // If none of the material values needs to be replaced
LData.diffuse = LData.ambEmiss; }
//
// Initialize the Specular to Zero
//
LData.specular.r = D3DVAL(0); LData.specular.g = D3DVAL(0); LData.specular.b = D3DVAL(0);
//
// In a loop accumulate color from the activated lights
//
pLight = LData.pActiveLights; while (pLight) { if (pLight->m_pfnLightVertex) (*pLight->m_pfnLightVertex)(m_lighting, &pLight->m_Light, &pLight->m_LightI, pLE, m_dwTLState, m_qwFVFIn); pLight = pLight->m_Next; }
//
// Compute the diffuse color of the vertex
//
int r = FTOI(LData.diffuse.r); int g = FTOI(LData.diffuse.g); int b = FTOI(LData.diffuse.b); DWORD a = *LData.pDiffuseAlphaSrc;
//
// Clamp the r, g, b, components
//
if (r < 0) r = 0; else if (r > 255) r = 255; if (g < 0) g = 0; else if (g > 255) g = 255; if (b < 0) b = 0; else if (b > 255) b = 255;
LData.outDiffuse = a + (r<<16) + (g<<8) + b;
//
// Obtain the specular Alpha
//
a = *(LData.pSpecularAlphaSrc);
//
// Compute the RGB part of the specular color
//
if (m_dwTLState & RDPV_DOSPECULAR) { r = FTOI(LData.specular.r); g = FTOI(LData.specular.g); b = FTOI(LData.specular.b);
//
// Clamp the r, g, b, components
//
if (r < 0) r = 0; else if (r > 255) r = 255; if (g < 0) g = 0; else if (g > 255) g = 255; if (b < 0) b = 0; else if (b > 255) b = 255;
} // Need another render-state to control if the
// the specular color (color2) needs to be passed down to
// the rasterizer.
//
// If SPECULAR is not enabled but the specular color
// had been provided in the input vertex, simply copy.
//
else if (m_qwFVFOut & D3DFVF_SPECULAR ) { r = FTOI(LData.vertexSpecular.r); g = FTOI(LData.vertexSpecular.g); b = FTOI(LData.vertexSpecular.b); a = LData.vertexSpecAlpha; } //
// If SpecularColor is not enabled
//
else { r = g = b = 0; }
LData.outSpecular = a + (r<<16) + (g<<8) + b;
return; }
//---------------------------------------------------------------------
// RefVP::FogVertex
// Vertex Fog computation
// Input:
// v - input vertex in the model space
// le - vertex, transformed to the camera space
// Output:
// Alpha component of pv->lighting.outSpecular is set
//---------------------------------------------------------------------
void RefVP::FogVertex( RDVertex& Vout, RDVECTOR3 &v, RDLIGHTINGELEMENT *pLE, int numVertexBlends, float *pBlendFactors, BOOL bVertexInEyeSpace ) { D3DVALUE dist = 0.0f;
//
// Calculate the distance
//
if (bVertexInEyeSpace) { // Vertex is already transformed to the camera space
if (m_dwTLState & RDPV_RANGEFOG) { dist = SQRTF(pLE->dvPosition.x*pLE->dvPosition.x + pLE->dvPosition.y*pLE->dvPosition.y + pLE->dvPosition.z*pLE->dvPosition.z); } else { dist = ABSF( pLE->dvPosition.z ); } } else if (m_dwTLState & RDPV_RANGEFOG) { D3DVALUE x = 0, y = 0, z = 0; float cumulBlend = 0.0f;
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( m_dwTLState & RDPV_DOINDEXEDVERTEXBLEND ) { BYTE m = ((BYTE *)&pBlendFactors[numVertexBlends])[j]; UpdateWorld( m ); x += (v.x*m_xfmToEye[m]._11 + v.y*m_xfmToEye[m]._21 + v.z*m_xfmToEye[m]._31 + m_xfmToEye[m]._41) * blend; y += (v.x*m_xfmToEye[m]._12 + v.y*m_xfmToEye[m]._22 + v.z*m_xfmToEye[m]._32 + m_xfmToEye[m]._42) * blend; z += (v.x*m_xfmToEye[m]._13 + v.y*m_xfmToEye[m]._23 + v.z*m_xfmToEye[m]._33 + m_xfmToEye[m]._43) * blend; } else { x += (v.x*m_xfmToEye[j]._11 + v.y*m_xfmToEye[j]._21 + v.z*m_xfmToEye[j]._31 + m_xfmToEye[j]._41) * blend; y += (v.x*m_xfmToEye[j]._12 + v.y*m_xfmToEye[j]._22 + v.z*m_xfmToEye[j]._32 + m_xfmToEye[j]._42) * blend; z += (v.x*m_xfmToEye[j]._13 + v.y*m_xfmToEye[j]._23 + v.z*m_xfmToEye[j]._33 + m_xfmToEye[j]._43) * blend; } }
dist = SQRTF(x*x + y*y + z*z); } else { float cumulBlend = 0.0f;
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( m_dwTLState & RDPV_DOINDEXEDVERTEXBLEND ) { BYTE m = ((BYTE *)&pBlendFactors[numVertexBlends])[j]; UpdateWorld( m ); dist += (v.x*m_xfmToEye[m]._13 + v.y*m_xfmToEye[m]._23 + v.z*m_xfmToEye[m]._33 + m_xfmToEye[m]._43) * blend; } else { dist += (v.x*m_xfmToEye[j]._13 + v.y*m_xfmToEye[j]._23 + v.z*m_xfmToEye[j]._33 + m_xfmToEye[j]._43) * blend; } } dist = ABSF( dist ); }
if (m_lighting.fog_mode == D3DFOG_LINEAR) { if (dist < m_lighting.fog_start) { Vout.m_fog = 1.0f; } else if (dist >= m_lighting.fog_end) { Vout.m_fog = 0.0f; } else { Vout.m_fog = (m_lighting.fog_end - dist) * m_lighting.fog_factor / 255.0f ; } } else { D3DVALUE tmp = dist * m_lighting.fog_density; if (m_lighting.fog_mode == D3DFOG_EXP2) { tmp *= tmp; } Vout.m_fog = (FLOAT)exp(-tmp); }
return; }
|