////////////////////////////////////////////////////////////////////////////// // NAME: // ARGUMENTS: // RETURN: // DESCRIPTION: // // NOTE: This function should only be called from DxLight::Manager::Light() ////////////////////////////////////////////////////////////////////////////// void DxLight::DirectLight(VertexL *dst, U32 count) { ASSERT( dst ); if (!IsActive()) { return; } Material *material = Manager::curMaterial; #if 0 if ( count == 0 || (material_diffuse.r + material_diffuse.g + material_diffuse.b + material_diffuse.a) == 0.0f ) { return; } #endif // calculate the vector to the light in model space #ifndef DOBZ2 direction = WorldMatrix().Front(); #else direction = CalcSimWorldDirection(Vector(0, 0, 1)); #endif direction *= -1.0f; Vid::world_matrix.RotateInv(direction); Bool do_specular = (material->status.specular && Vid::renderState.status.specular && (desc.dwFlags & D3DLIGHT_NO_SPECULAR) != D3DLIGHT_NO_SPECULAR); if (do_specular) { // calculate the halfway vector using the D3D method halfVector = (Vid::model_view_norm + direction); halfVector.Normalize(); } VertexL *out = dst; ColorValue *d = &Manager::diffuse[0]; ColorValue *s = &Manager::specular[0]; U32 iv; for (iv = 0; iv < count; iv++ ) { // calculate the diffuse reflection factor and clamp it to [0,1] // NOTE: both src->nv and light->dvDirection must be normalized vectors F32 diffuse_reflect = Manager::norms[iv].Dot(direction); // -1.0f <= diffuse_reflect <= 1.0f if (diffuse_reflect > 0.0f) { // calculate the diffuse component for the vertex d->r += desc.dcvColor.r * diffuse_reflect * Manager::material_diffuse.r; d->g += desc.dcvColor.g * diffuse_reflect * Manager::material_diffuse.g; d->b += desc.dcvColor.b * diffuse_reflect * Manager::material_diffuse.b; } if (do_specular) { // calculate the partial specular reflection factor F32 specular_reflect = Manager::norms[iv].Dot(halfVector); if ( spec_reflect > SPECULAR_THRESHOLD ) { #if 0 spec_reflect = (F32) pow((double) spec_reflect, (double) material->GetDesc().dvPower); // -1.0f <= spec_reflect <= 1.0f #else // apply the material's power factor to the nearest power of 2 U32 e, ee = material->PowerCount(); for (e = 1; e < ee; e *= 2 ) { spec_reflect = spec_reflect * spec_reflect; } #endif // calculate the diffuse component of the vertex // if vertex color capabilities are added this must be changed s->r += desc.dcvColor.r * specular_reflect * Manager::material_specular.r; s->g += desc.dcvColor.g * specular_reflect * Manager::material_specular.g; s->b += desc.dcvColor.b * specular_reflect * Manager::material_specular.b; } } out++; d++; s++; } // for }
void DxLight::PointLight(Vertex *src, U32 count) { ASSERT( src ); if (!IsActive()) { return; } Material *material = Manager::curMaterial; // calculate the light's model space position Matrix inverse_world_matrix; inverse_world_matrix.SetInverse(Vid::world_matrix); #ifndef DOBZ2 inverse_world_matrix.Transform(position, WorldMatrix().Position()); #else Vector Centre (CalcSimWorldPosition(Vector (0, 0, 0))); inverse_world_matrix.Transform(position, Centre); #endif // calculate the model space direction direction = position; direction.Normalize(); Bool do_specular = (material->status.specular && Vid::renderState.status.specular && (desc.dwFlags & D3DLIGHT_NO_SPECULAR) != D3DLIGHT_NO_SPECULAR); if (do_specular) { // calculate the halfway vector using the D3D method halfVector = (Vid::model_view_norm + direction); halfVector.Normalize(); } Vertex *in = src; ColorValue *d = &Manager::diffuse[0]; ColorValue *s = &Manager::specular[0]; U32 iv; for (iv = 0; iv < count; iv++ ) { // calculate distance from the light to the vertex direction = position - in->vv; F32 dist = direction.Magnitude(); // if distance is greater than range, then no light reaches the vertex // this could use a Magnitude2() check to avoid the sqrt for verts outside range !!! if ( dist <= desc.dvRange ) { // ASSERT( dist > 0.0f); if (dist <= F32_EPSILON) { dist = F32_EPSILON; } F32 invdist = 1.0f / dist; // normalize the distance dist = (desc.dvRange - dist) * invRange; // calculate the attenuation over that distance F32 a = desc.dvAttenuation0 + dist * desc.dvAttenuation1 + (dist*dist) * desc.dvAttenuation2; if ( a > 0.0f ) { // calculate the model space direction direction.x *= invdist; direction.y *= invdist; direction.z *= invdist; // calculate and scale the attenuated color values ColorValue atten; atten.r = a * desc.dcvColor.r; atten.g = a * desc.dcvColor.g; atten.b = a * desc.dcvColor.b; // calculate the diffuse reflection factor and clamp it to [0,1] // NOTE: both src->nv and light->dvDirection must be normalized vectors F32 diffuse_reflect = in->nv.Dot(direction); // -1.0f <= diffuse_reflect <= 1.0f if ( diffuse_reflect > 0.0f ) { // calculate the diffuse component for the vertex d->r += atten.r * diffuse_reflect * Manager::material_diffuse.r; d->g += atten.g * diffuse_reflect * Manager::material_diffuse.g; d->b += atten.b * diffuse_reflect * Manager::material_diffuse.b; } if ( do_specular ) { // calculate the partial specular reflection factor F32 spec_reflect = in->nv.Dot(halfVector); if ( spec_reflect > SPECULAR_THRESHOLD ) { #if 0 spec_reflect = (F32) pow((double) spec_reflect, (double) material->GetDesc().dvPower); // -1.0f <= spec_reflect <= 1.0f #else // apply the material's power factor to the nearest power of 2 U32 e, ee = material->PowerCount(); for (e = 1; e < ee; e *= 2 ) { spec_reflect = spec_reflect * spec_reflect; } #endif // calculate the diffuse component of the vertex // if vertex color capabilities are added this must be changed s->r += atten.r * spec_reflect * Manager::material_specular.r; s->g += atten.g * spec_reflect * Manager::material_specular.g; s->b += atten.b * spec_reflect * Manager::material_specular.b; } } } // if } // if in++; d++; s++; } // for }
////////////////////////////////////////////////////////////////////////////// // NAME: // ARGUMENTS: // RETURN: // DESCRIPTION: // // NOTE: This function should only be called from DxLight::Manager::Light() ////////////////////////////////////////////////////////////////////////////// void DxLight::SpotLight(VertexL *dst, U32 count) { ASSERT( dst ); if (!IsActive()) { return; } Material *material = Manager::curMaterial; // calculate the light's model space position Matrix inverse_world_matrix; inverse_world_matrix.SetInverse(Vid::world_matrix); #ifndef DOBZ2 inverse_world_matrix.Transform(position, WorldMatrix().Position()); #else Vector Centre (CalcSimWorldPosition(Vector (0, 0, 0))); inverse_world_matrix.Transform(position, Centre); #endif // calculate the model space direction direction = position; direction.Normalize(); // get the spot direction vector in model space Vector spot_direction; #ifndef DOBZ2 inverse_world_matrix.Rotate(spot_direction, WorldMatrix().Front()); #else Vector Dir (CalcSimWorldDirection(Vector (0, 0, 1))); inverse_world_matrix.Rotate(spot_direction, Dir); #endif Bool do_specular = (material->status.specular && Vid::renderState.status.specular && (desc.dwFlags & D3DLIGHT_NO_SPECULAR) != D3DLIGHT_NO_SPECULAR); if (do_specular) { // calculate the halfway vector using the D3D method halfVector = (Vid::model_view_norm + direction); halfVector.Normalize(); } VertexL *out = dst; ColorValue *d = &Manager::diffuse[0]; ColorValue *s = &Manager::specular[0]; U32 iv; for (iv = 0; iv < count; iv++ ) { // calculate distance from the light to the vertex direction = position - out->vv; F32 dist = direction.Magnitude(); // if distance is greater than range, then no light reaches the vertex if ( dist <= desc.dvRange ) { // ASSERT( dist > 0.0f); if (dist <= F32_EPSILON) { dist = F32_EPSILON; } F32 invdist = 1.0f / dist; // normalize the distance dist = (desc.dvRange - dist) * invRange; // calculate the attenuation over that distance F32 a = desc.dvAttenuation0 + dist * desc.dvAttenuation1 + (dist*dist) * desc.dvAttenuation2; if ( a > 0.0f ) { // compute the cosine of vectors vert_to_light and the light's model space direction direction *= invdist; F32 cos_dir = -direction.Dot(spot_direction); if ( cos_dir > cosPhi ) { F32 intensity; if ( cos_dir > cosTheta ) // vertex is inside inner cone --> receives full light { intensity = 1.0f; } else // vertex is between inner and outer cone { // intensity = (F32) pow((double) ((cos_dir-cos_phi)/(cos_theta-cos_phi)), (double) desc.dvFalloff); intensity = (cos_dir - cosPhi) * invAngle; } // calculate and scale the attenuated color values ColorValue atten; atten.r = a * desc.dcvColor.r; atten.g = a * desc.dcvColor.g; atten.b = a * desc.dcvColor.b; // calculate the diffuse reflection factor and clamp it to [0,1] // NOTE: both src->nv and light->dvDirection must be normalized vectors F32 diffuse_reflect = Manager::norms[iv].Dot(direction); // -1.0f <= diffuse_reflect <= 1.0f if ( diffuse_reflect > 0.0f ) { diffuse_reflect *= intensity; // calculate the diffuse component for the vertex d->r += atten.r * diffuse_reflect * Manager::material_diffuse.r; d->g += atten.g * diffuse_reflect * Manager::material_diffuse.g; d->b += atten.b * diffuse_reflect * Manager::material_diffuse.b; } if ( do_specular ) { // calculate the partial specular reflection factor F32 spec_reflect = Manager::norms[iv].Dot(halfVector); if ( spec_reflect > SPECULAR_THRESHOLD ) { #if 0 spec_reflect = (F32) pow((double) spec_reflect, (double) material->GetDesc().dvPower); // -1.0f <= spec_reflect <= 1.0f #else // apply the material's power factor to the nearest power of 2 U32 e, ee = material->PowerCount(); for (e = 1; e < ee; e *= 2 ) { spec_reflect = spec_reflect * spec_reflect; } #endif spec_reflect *= intensity; s->r += atten.r * spec_reflect * Manager::material_specular.r; s->g += atten.g * spec_reflect * Manager::material_specular.g; s->b += atten.b * spec_reflect * Manager::material_specular.b; } } } // if } // if } // if out++; d++; s++; } // for }