/* ** Command & Conquer Renegade(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ /*********************************************************************************************** *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** *********************************************************************************************** * * * Project Name : WWPhys * * * * $Archive:: /Commando/Code/ww3d2/lightenvironment.cpp $* * * * Original Author:: Greg Hjelstrom * * * * $Author:: Greg_h $* * * * $Modtime:: 3/01/02 3:43p $* * * * $Revision:: 4 $* * * *---------------------------------------------------------------------------------------------* * Functions: * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #include "lightenvironment.h" #include "matrix3d.h" #include "camera.h" #include "light.h" /* ** Constants */ const float DIFFUSE_TO_AMBIENT_FRACTION = 1.0f; /* ** Static variables */ static _LightingLODCutoff = 0.5f; static _LightingLODCutoff2 = 0.5f * 0.5f; /************************************************************************************************ ** ** LightEnvironmentClass::InputLightStruct Implementation ** ************************************************************************************************/ void LightEnvironmentClass::InputLightStruct::Init ( const LightClass & light, const Vector3 & object_center ) { switch(light.Get_Type()) { case LightClass::POINT: case LightClass::SPOT: Init_From_Point_Or_Spot_Light(light,object_center); break; case LightClass::DIRECTIONAL: Init_From_Directional_Light(light,object_center); break; }; } void LightEnvironmentClass::InputLightStruct::Init_From_Point_Or_Spot_Light ( const LightClass & light, const Vector3 & object_center ) { /* ** Compute the direction vector and the distance to the light */ Direction = light.Get_Position() - object_center; float dist = Direction.Length(); if (dist > 0.0f) { Direction /= dist; } /* ** Compute the attenuation factor */ double atten_start,atten_end; light.Get_Far_Attenuation_Range(atten_start,atten_end); float atten = 1.0f - (dist - atten_start) / (atten_end - atten_start); atten = WWMath::Clamp(atten,0.0f,1.0f); if (light.Get_Type() == LightClass::SPOT) { Vector3 spot_dir; light.Get_Spot_Direction(spot_dir); Matrix3D::Rotate_Vector(light.Get_Transform(),spot_dir,&spot_dir); float spot_angle_cos = light.Get_Spot_Angle_Cos(); atten *= (Vector3::Dot_Product(-spot_dir,Direction) - spot_angle_cos) / (1.0f - spot_angle_cos); atten = WWMath::Clamp(atten,0.0f,1.0f); } /* ** Compute the ambient and diffuse values. Rejecting the diffuse ** component and folding it into the ambient component if it is below ** the LOD cutoff */ light.Get_Ambient(&Ambient); light.Get_Diffuse(&Diffuse); if (Diffuse.Length2() > _LightingLODCutoff2) { DiffuseRejected = false; Ambient *= atten; Diffuse *= atten; } else { DiffuseRejected = true; Ambient *= atten; Ambient += atten * DIFFUSE_TO_AMBIENT_FRACTION * Diffuse; Diffuse.Set(0,0,0); } } void LightEnvironmentClass::InputLightStruct::Init_From_Directional_Light ( const LightClass & light, const Vector3 & object_center ) { Direction = -light.Get_Transform().Get_Z_Vector(); DiffuseRejected = false; light.Get_Ambient(&Ambient); light.Get_Diffuse(&Diffuse); } float LightEnvironmentClass::InputLightStruct::Contribution(void) { return Diffuse.Length2(); } /************************************************************************************************ ** ** LightEnvironmentClass::OutputLightStruct Implementation ** ************************************************************************************************/ void LightEnvironmentClass::OutputLightStruct::Init ( const InputLightStruct & input, const Matrix3D & camera_tm ) { Diffuse = input.Diffuse; Matrix3D::Inverse_Rotate_Vector(camera_tm,input.Direction,&Direction); } /************************************************************************************************ ** ** LightEnvironmentClass Implementation ** ************************************************************************************************/ LightEnvironmentClass::LightEnvironmentClass(void) : LightCount(0), ObjectCenter(0,0,0), OutputAmbient(0,0,0) { } LightEnvironmentClass::~LightEnvironmentClass(void) { } void LightEnvironmentClass::Reset(const Vector3 & object_center,const Vector3 & ambient) { LightCount = 0; ObjectCenter = object_center; OutputAmbient = ambient; } void LightEnvironmentClass::Add_Light(const LightClass & light) { /* ** Compute the equivalent directional + ambient light */ InputLightStruct new_light; new_light.Init(light,ObjectCenter); /* ** Add in the ambient component */ OutputAmbient += new_light.Ambient; /* ** If not rejected, add the directional component to the active lights */ if (new_light.DiffuseRejected == false) { if (LightCount < MAX_LIGHTS) { InputLights[LightCount] = new_light; LightCount++; } else { for (int light_index=0; light_index InputLights[light_index].Contribution()) { InputLights[light_index] = new_light; light_index = MAX_LIGHTS; } } } } } void LightEnvironmentClass::Pre_Render_Update(const Matrix3D & camera_tm) { /* ** Transform each light into camera space ** and add up the ambient effect of each light */ for (int light_index=0; light_index