This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/ww3d2/lightenvironment.cpp

265 lines
7.7 KiB
C++

/*
** 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 <http://www.gnu.org/licenses/>.
*/
/***********************************************************************************************
*** 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<LightCount; light_index++) {
if (new_light.Contribution() > 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<LightCount; light_index++) {
OutputLights[light_index].Init(InputLights[light_index],camera_tm);
}
OutputAmbient.X = WWMath::Clamp(OutputAmbient.X);
OutputAmbient.Y = WWMath::Clamp(OutputAmbient.Y);
OutputAmbient.Z = WWMath::Clamp(OutputAmbient.Z);
}
void LightEnvironmentClass::Set_Lighting_LOD_Cutoff(float inten)
{
_LightingLODCutoff = inten;
_LightingLODCutoff2 = _LightingLODCutoff * _LightingLODCutoff;
}
float LightEnvironmentClass::Get_Lighting_LOD_Cutoff(void)
{
return _LightingLODCutoff;
}