mirror of
https://github.com/electronicarts/CnC_Renegade.git
synced 2025-12-16 07:31:40 -05:00
Initial commit of Command & Conquer Renegade source code.
This commit is contained in:
306
Code/wwphys/dynamicshadowmanager.cpp
Normal file
306
Code/wwphys/dynamicshadowmanager.cpp
Normal file
@@ -0,0 +1,306 @@
|
||||
/*
|
||||
** 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/wwphys/dynamicshadowmanager.cpp $*
|
||||
* *
|
||||
* Original Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Author:: Greg_h $*
|
||||
* *
|
||||
* $Modtime:: 12/07/01 4:39p $*
|
||||
* *
|
||||
* $Revision:: 14 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#include "dynamicshadowmanager.h"
|
||||
#include "chunkio.h"
|
||||
#include "phys.h"
|
||||
#include "dyntexproject.h"
|
||||
#include "pscene.h"
|
||||
#include "physcoltest.h"
|
||||
#include "light.h"
|
||||
#include "texture.h"
|
||||
#include "physresourcemgr.h"
|
||||
|
||||
|
||||
#define SINGLE_SHADOW_CODE 1
|
||||
|
||||
DynamicShadowManagerClass::DynamicShadowManagerClass(PhysClass & parent) :
|
||||
Parent(parent),
|
||||
Shadow(NULL),
|
||||
ShadowNearZ(-1.0f),
|
||||
ShadowFarZ(-1.0f),
|
||||
ForceUseBlobBox(false),
|
||||
BlobBoxProjectionScale(1,1,1)
|
||||
{
|
||||
}
|
||||
|
||||
DynamicShadowManagerClass::~DynamicShadowManagerClass(void)
|
||||
{
|
||||
Release_Shadow();
|
||||
}
|
||||
|
||||
|
||||
void DynamicShadowManagerClass::Update_Shadow(void)
|
||||
{
|
||||
#if SINGLE_SHADOW_CODE
|
||||
/*
|
||||
** Shadow Update
|
||||
** - if shadows are off, release projector and RETURN
|
||||
** - find dominant light source (or multiple sources?)
|
||||
** - if no light sources, set projector intensity to 0.0 and RETURN
|
||||
** - for each light source
|
||||
** - re-use projector from previous frame or allocate a new projector
|
||||
** - initialize the projection parameters, depending on: blob/real,point/directional
|
||||
** - set the shadow's intensity by attenuating it with distance from lightsource
|
||||
*/
|
||||
PhysicsSceneClass * scene = PhysicsSceneClass::Get_Instance();
|
||||
PhysicsSceneClass::ShadowEnum shadow_mode = scene->Get_Shadow_Mode();
|
||||
|
||||
float near_atten;
|
||||
float far_atten;
|
||||
scene->Get_Shadow_Attenuation(&near_atten,&far_atten);
|
||||
|
||||
RenderObjClass * model = Parent.Peek_Model();
|
||||
|
||||
/*
|
||||
** Grab the bounding box info based on whether we are using blobs or real projections
|
||||
** use blobs IF(the mode is BLOBS or (the mode is BLOBS_PLUS and we're not the 'star'))
|
||||
*/
|
||||
AABoxClass objbox;
|
||||
|
||||
bool use_blob = (shadow_mode == PhysicsSceneClass::SHADOW_MODE_BLOBS) ||
|
||||
((shadow_mode == PhysicsSceneClass::SHADOW_MODE_BLOBS_PLUS) && (!Parent.Is_Force_Projection_Shadow_Enabled()));
|
||||
|
||||
if (use_blob) {
|
||||
Parent.Get_Shadow_Blob_Box(&objbox);
|
||||
} else {
|
||||
if (ForceUseBlobBox) {
|
||||
Parent.Get_Shadow_Blob_Box(&objbox);
|
||||
objbox.Extent.Scale(BlobBoxProjectionScale);
|
||||
} else {
|
||||
model->Get_Obj_Space_Bounding_Box(objbox);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Check if the center of the bounding box is well beyond the shadow fading
|
||||
** distance. If so, we will exit early
|
||||
*/
|
||||
Vector3 position;
|
||||
Matrix3D::Transform_Vector(Parent.Get_Transform(),objbox.Center,&position);
|
||||
float shadow_shutoff2 = far_atten * 1.3f * far_atten * 1.3f;
|
||||
float shadow_dist2 = (position - scene->Get_Last_Camera_Position()).Length2();
|
||||
|
||||
/*
|
||||
** If shadow generation is disabled or we are farther than 1.2x the shadow attenuation distance,
|
||||
** release any projector that we may have and return
|
||||
*/
|
||||
if ( (Parent.Do_Any_Effects_Suppress_Shadows()) ||
|
||||
(Parent.Is_Shadow_Generation_Enabled() == false) ||
|
||||
(shadow_mode == PhysicsSceneClass::SHADOW_MODE_NONE) ||
|
||||
(shadow_dist2 > shadow_shutoff2) ||
|
||||
(model == NULL) ||
|
||||
(model->Is_Hidden()) ||
|
||||
(objbox.Extent.Length2() < 0.1f) )
|
||||
{
|
||||
if (Shadow != NULL) {
|
||||
scene->Remove_Dynamic_Texture_Projector(Shadow);
|
||||
Shadow->Release_Ref();
|
||||
Shadow = NULL;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
** Find dominant light source. First check if sun is available, then find closest
|
||||
** static light.
|
||||
*/
|
||||
bool found_light = false;
|
||||
Vector3 sunlight;
|
||||
scene->Get_Sun_Light_Vector(&sunlight);
|
||||
|
||||
if (Parent.Is_In_The_Sun()) {
|
||||
|
||||
/*
|
||||
** We can see the sunlight so set our projector up for it.
|
||||
** Our shadow is attenuated only by distance from the camera so
|
||||
** set the intensity to 'normal' and set the flag which causes
|
||||
** the physics scene to attenuate it with distance.
|
||||
*/
|
||||
Allocate_Shadow();
|
||||
|
||||
/*
|
||||
** Save parameters in the projector so it can continue to
|
||||
** update later if it needs to fade out
|
||||
*/
|
||||
LightClass * sun = scene->Get_Sun_Light();
|
||||
Shadow->Enable_Perspective(false);
|
||||
Shadow->Set_Light_Source_ID((uint32)sun);
|
||||
Shadow->Set_Light_Vector(sunlight);
|
||||
sun->Release_Ref();
|
||||
found_light = true;
|
||||
|
||||
} else {
|
||||
|
||||
#pragma message ("(gth) Disabling local shadows")
|
||||
#if 0
|
||||
/*
|
||||
** We couldn't use the sunlight so now we look for the nearest
|
||||
** local light source which casts shadows. If we find one, initialize
|
||||
** our shadow projector with it.
|
||||
*/
|
||||
NonRefPhysListClass lightlist;
|
||||
scene->Collect_Lights(position,true,false,&lightlist);
|
||||
|
||||
if (!lightlist.Is_Empty()) {
|
||||
|
||||
/*
|
||||
** Ensure that a shadow is allocated!
|
||||
*/
|
||||
Allocate_Shadow();
|
||||
|
||||
LightClass * best_light = NULL;
|
||||
NonRefPhysListIterator it(&lightlist);
|
||||
for (it.First(); !it.Is_Done(); it.Next()) {
|
||||
best_light = (LightClass *)(it.Peek_Obj()->Peek_Model());
|
||||
break;
|
||||
}
|
||||
|
||||
if (best_light) {
|
||||
|
||||
#if TRUE_PERSPECTIVE_SHADOWS // This code uses true perspective projection for local light sources
|
||||
Shadow->Enable_Perspective(true);
|
||||
Shadow->Set_Light_Source_ID((uint32)best_light);
|
||||
Shadow->Set_Light_Vector(best_light->Get_Position());
|
||||
|
||||
#else // This code uses an orthographic approximation
|
||||
Shadow->Enable_Perspective(false);
|
||||
Shadow->Set_Light_Source_ID((uint32)best_light);
|
||||
|
||||
Vector3 direction;
|
||||
Get_Position(&direction);
|
||||
direction -= best_light->Get_Position();
|
||||
direction.Normalize();
|
||||
Shadow->Set_Light_Vector(direction);
|
||||
#endif
|
||||
found_light = true;
|
||||
|
||||
DEBUG_RENDER_VECTOR(position,best_light->Get_Position()-position,Vector3(1,1,1));
|
||||
}
|
||||
}
|
||||
#endif //0
|
||||
}
|
||||
|
||||
if (found_light) {
|
||||
|
||||
/*
|
||||
** We have a shadow and a light so update the projection parameters.
|
||||
** If we are using blob shadows, just plug in the blob texture and
|
||||
** clear the dirty flag. Otherwise, mark the texture dirty so it will
|
||||
** be re-generated if the shadow actually gets projected onto something
|
||||
*/
|
||||
Shadow->Update_Projection(objbox,Parent.Get_Transform(),ShadowNearZ,ShadowFarZ);
|
||||
Shadow->Set_Intensity(scene->Get_Shadow_Normal_Intensity());
|
||||
|
||||
if (use_blob) {
|
||||
TextureClass * shadow_texture = PhysResourceMgrClass::Get_Shadow_Blob_Texture();
|
||||
WWASSERT(shadow_texture != NULL);
|
||||
Shadow->Set_Texture(shadow_texture);
|
||||
shadow_texture->Release_Ref();
|
||||
Shadow->Set_Texture_Dirty(false);
|
||||
} else {
|
||||
Shadow->Set_Texture_Dirty(true);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/*
|
||||
** If we have a shadow but we don't want it any more, wait until
|
||||
** it fades out before we release it
|
||||
*/
|
||||
if (Shadow) {
|
||||
Shadow->Set_Intensity(0.0f);
|
||||
if (!Shadow->Is_Intensity_Zero()) {
|
||||
Shadow->Update_Projection(objbox,Parent.Get_Transform(),ShadowNearZ,ShadowFarZ);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
** - Collect all lights that want to and can cast a shadow with this object (raytest, etc)
|
||||
** - Reduce number of lights in list to MaxShadowsPerObject
|
||||
** - Create new empty shadow object list
|
||||
** - For each light
|
||||
** - Try to find shadow which used this light from prev-frame's shadow list, if found
|
||||
** remove it from prev-frame's list and put in current frame's shadow list
|
||||
** Else create a new shadow object, immediately set its intensity to zero (since it is turning on)
|
||||
** - Initialize projector with light parameters
|
||||
** - For each shadow still in prev-frame's list
|
||||
** - If intensity is zero, destroy it.
|
||||
** Else
|
||||
** - Set target intensity to zero
|
||||
** - Update projection parameters, move into this frame's shadow list
|
||||
*/
|
||||
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void DynamicShadowManagerClass::Allocate_Shadow(void)
|
||||
{
|
||||
if (Shadow == NULL) {
|
||||
PhysicsSceneClass * scene = PhysicsSceneClass::Get_Instance();
|
||||
|
||||
Shadow = NEW_REF(DynTexProjectClass,(&Parent));
|
||||
Shadow->Enable_Attenuation(true);
|
||||
Shadow->Enable_Depth_Gradient(true);
|
||||
Shadow->Enable_Affect_Dynamic_Objects(false);
|
||||
Shadow->Set_Intensity(scene->Get_Shadow_Normal_Intensity(),true);
|
||||
Shadow->Peek_Material_Pass()->Enable_On_Translucent_Meshes(false);
|
||||
|
||||
scene->Add_Dynamic_Texture_Projector(Shadow);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DynamicShadowManagerClass::Release_Shadow(void)
|
||||
{
|
||||
if (Shadow) {
|
||||
if (PhysicsSceneClass::Get_Instance()->Contains(Shadow)) {
|
||||
PhysicsSceneClass::Get_Instance()->Remove_Dynamic_Texture_Projector(Shadow);
|
||||
}
|
||||
Shadow->Release_Ref();
|
||||
Shadow = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user