1007 lines
29 KiB
C++
1007 lines
29 KiB
C++
#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;
|
|
}
|
|
|