mirror of
https://github.com/electronicarts/CnC_Renegade.git
synced 2025-12-16 23:51:41 -05:00
Initial commit of Command & Conquer Renegade source code.
This commit is contained in:
390
Code/Tools/W3DView/ViewerScene.cpp
Normal file
390
Code/Tools/W3DView/ViewerScene.cpp
Normal file
@@ -0,0 +1,390 @@
|
||||
/*
|
||||
** 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 : W3DView *
|
||||
* *
|
||||
* $Archive:: /Commando/Code/Tools/W3DView/ViewerScene.cpp $*
|
||||
* *
|
||||
* Author:: Patrick Smith *
|
||||
* *
|
||||
* $Modtime:: 3/15/01 3:04p $*
|
||||
* *
|
||||
* $Revision:: 10 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#include "StdAfx.H"
|
||||
#include "ViewerScene.H"
|
||||
#include "Camera.H"
|
||||
#include "WW3D.H"
|
||||
|
||||
#include "RendObj.H"
|
||||
#include "AssetMgr.H"
|
||||
#include "rinfo.h"
|
||||
#include "lightenvironment.h"
|
||||
|
||||
/*
|
||||
** ViewerSceneIterator
|
||||
** This iterator is used by the ViewerSceneClass to allow
|
||||
** the user to iterate through its render objects.
|
||||
*/
|
||||
class ViewerSceneIterator : public SceneIterator
|
||||
{
|
||||
public:
|
||||
virtual void First(void);
|
||||
virtual void Next(void);
|
||||
virtual bool Is_Done(void);
|
||||
virtual RenderObjClass * Current_Item(void);
|
||||
|
||||
protected:
|
||||
|
||||
ViewerSceneIterator(RefRenderObjListClass * renderlist);
|
||||
|
||||
RefRenderObjListIterator RobjIterator;
|
||||
|
||||
friend class ViewerSceneClass;
|
||||
};
|
||||
|
||||
ViewerSceneIterator::ViewerSceneIterator(RefRenderObjListClass *list)
|
||||
: RobjIterator(list)
|
||||
{
|
||||
}
|
||||
|
||||
void ViewerSceneIterator::First(void)
|
||||
{
|
||||
RobjIterator.First();
|
||||
}
|
||||
|
||||
void ViewerSceneIterator::Next(void)
|
||||
{
|
||||
RobjIterator.Next();
|
||||
}
|
||||
|
||||
bool ViewerSceneIterator::Is_Done(void)
|
||||
{
|
||||
return RobjIterator.Is_Done();
|
||||
}
|
||||
|
||||
RenderObjClass * ViewerSceneIterator::Current_Item(void)
|
||||
{
|
||||
return RobjIterator.Peek_Obj();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
**
|
||||
** ViewerSceneClass Implementation!
|
||||
**
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Visibility_Check
|
||||
//
|
||||
// Note: We overide this method to remove the LOD preparation. We
|
||||
// need to be able to specify an LOD and not have it switch on us.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
void
|
||||
ViewerSceneClass::Visibility_Check (CameraClass *camera)
|
||||
{
|
||||
RefRenderObjListIterator it(&RenderList);
|
||||
|
||||
// Loop over all top-level RenderObjects in this scene. If the bounding sphere is not in front
|
||||
// of all the frustum planes, it is invisible.
|
||||
for (it.First(); !it.Is_Done(); it.Next()) {
|
||||
|
||||
RenderObjClass * robj = it.Peek_Obj();
|
||||
|
||||
if (robj->Is_Force_Visible()) {
|
||||
robj->Set_Visible(true);
|
||||
} else {
|
||||
robj->Set_Visible(!camera->Cull_Sphere(robj->Get_Bounding_Sphere()));
|
||||
}
|
||||
|
||||
int lod_level = robj->Get_LOD_Level ();
|
||||
|
||||
// Prepare visible objects for LOD:
|
||||
if (robj->Is_Really_Visible()) {
|
||||
robj->Prepare_LOD(*camera);
|
||||
}
|
||||
|
||||
if (m_AllowLODSwitching == false) {
|
||||
robj->Set_LOD_Level (lod_level);
|
||||
}
|
||||
}
|
||||
|
||||
Visibility_Checked = true;
|
||||
|
||||
//SimpleSceneClass::Visibility_Check (camera);
|
||||
return ;
|
||||
}
|
||||
|
||||
void
|
||||
ViewerSceneClass::Add_To_Lineup (RenderObjClass *obj)
|
||||
{
|
||||
assert(obj);
|
||||
|
||||
// If this is an insignificant object (ie. we don't need to
|
||||
// rearrange existing objects to accomodate it), don't bother
|
||||
// adding it to the lineup. Ex: Adding a light to the lineup
|
||||
// is pretty silly.
|
||||
if (!Can_Line_Up(obj))
|
||||
return;
|
||||
|
||||
|
||||
// We will add this object to the scene next to any
|
||||
// existing objects. It will be placed at (0, Y, 0)
|
||||
// where Y is a value to be calculated such that the
|
||||
// center of the scene (0,0,0) is in the middle of the
|
||||
// row of objects. The existing objects will need to
|
||||
// be moved along the -Y axis to make room.
|
||||
|
||||
// Figure out how 'wide' the object is (width assuming it
|
||||
// it facing along the +X axis).
|
||||
AABoxClass obj_box;
|
||||
obj->Get_Obj_Space_Bounding_Box(obj_box);
|
||||
float obj_width = obj_box.Extent.Y * 2.0f;
|
||||
|
||||
// Figure out the bounding box for the objects in the lineup.
|
||||
AABoxClass scene_box = Get_Line_Up_Bounding_Box();
|
||||
float scene_width = scene_box.Extent.Y * 2.0f;
|
||||
|
||||
// How much do we have to move the existing objects by?
|
||||
float new_scene_width = scene_width + obj_width + obj_width/3;
|
||||
float delta = (new_scene_width - scene_width) / 2;
|
||||
|
||||
// Move the existing objects along the -Y axis.
|
||||
int num_existing_objects = 0;
|
||||
SceneIterator *it = Create_Iterator();
|
||||
assert(it);
|
||||
for (; !it->Is_Done(); it->Next())
|
||||
{
|
||||
RenderObjClass *current_obj = it->Current_Item();
|
||||
assert(current_obj);
|
||||
if (Can_Line_Up(current_obj))
|
||||
{
|
||||
Vector3 pos = current_obj->Get_Position();
|
||||
pos.Y -= delta;
|
||||
current_obj->Set_Position(pos);
|
||||
|
||||
++num_existing_objects;
|
||||
}
|
||||
}
|
||||
Destroy_Iterator(it);
|
||||
|
||||
// Move the new object so that it will be in line
|
||||
// with the existing objects.
|
||||
if (num_existing_objects > 0)
|
||||
obj->Set_Position(Vector3(0,new_scene_width/2 - obj_box.Extent.Y, 0));
|
||||
else
|
||||
obj->Set_Position(Vector3(0,0,0));
|
||||
|
||||
// Add the object to the scene.
|
||||
Add_Render_Object(obj);
|
||||
|
||||
// Add the object to the list of objects in the lineup.
|
||||
LineUpList.Add(obj);
|
||||
}
|
||||
|
||||
void
|
||||
ViewerSceneClass::Clear_Lineup (void)
|
||||
{
|
||||
// Remove every object in the lineup from the scene,
|
||||
// and remove each object from the line up list.
|
||||
RenderObjClass *obj = NULL;
|
||||
while (obj = LineUpList.Remove_Head())
|
||||
Remove_Render_Object(obj);
|
||||
}
|
||||
|
||||
SphereClass
|
||||
ViewerSceneClass::Get_Bounding_Sphere (void)
|
||||
{
|
||||
// Iterate through every object in the scene, adding its
|
||||
// bounding sphere to the current bounding sphere. The sum of
|
||||
// the bounding spheres will be the scene's bounding sphere.
|
||||
SphereClass bounding_sphere(Vector3(0,0,0), 0.0f);
|
||||
SceneIterator *it = Create_Iterator();
|
||||
assert(it);
|
||||
for (; !it->Is_Done(); it->Next())
|
||||
{
|
||||
RenderObjClass *rend_obj = it->Current_Item();
|
||||
assert(rend_obj);
|
||||
// Omit lights in the bounding sphere calculations.
|
||||
if (rend_obj->Class_ID() != RenderObjClass::CLASSID_LIGHT)
|
||||
bounding_sphere.Add_Sphere(rend_obj->Get_Bounding_Sphere());
|
||||
}
|
||||
Destroy_Iterator(it);
|
||||
|
||||
return bounding_sphere;
|
||||
}
|
||||
|
||||
AABoxClass
|
||||
ViewerSceneClass::Get_Line_Up_Bounding_Box (void)
|
||||
{
|
||||
// Iterate through each object in the lineup, adding its
|
||||
// bounding box to the current bounding box. The sum
|
||||
// of the bounding boxes will be the lineup's bounding box.
|
||||
AABoxClass sum_of_boxes(Vector3(0,0,0), Vector3(0,0,0));
|
||||
SceneIterator *it = Create_Iterator();
|
||||
assert(it);
|
||||
for (; !it->Is_Done(); it->Next())
|
||||
{
|
||||
RenderObjClass *rend_obj = it->Current_Item();
|
||||
assert(rend_obj);
|
||||
if (Can_Line_Up(rend_obj))
|
||||
sum_of_boxes.Add_Box(rend_obj->Get_Bounding_Box());
|
||||
}
|
||||
Destroy_Iterator(it);
|
||||
|
||||
return sum_of_boxes;
|
||||
}
|
||||
|
||||
bool
|
||||
ViewerSceneClass::Can_Line_Up (RenderObjClass * obj)
|
||||
{
|
||||
assert(obj);
|
||||
return Can_Line_Up(obj->Class_ID());
|
||||
}
|
||||
|
||||
bool
|
||||
ViewerSceneClass::Can_Line_Up (int class_id)
|
||||
{
|
||||
return (class_id == RenderObjClass::CLASSID_HMODEL) ||
|
||||
(class_id == RenderObjClass::CLASSID_HLOD);
|
||||
}
|
||||
|
||||
SceneIterator *
|
||||
ViewerSceneClass::Create_Line_Up_Iterator (void)
|
||||
{
|
||||
return new ViewerSceneIterator(&LineUpList);
|
||||
}
|
||||
|
||||
void
|
||||
ViewerSceneClass::Destroy_Line_Up_Iterator (SceneIterator *it)
|
||||
{
|
||||
delete it;
|
||||
}
|
||||
|
||||
void ViewerSceneClass::Add_Render_Object(RenderObjClass * obj)
|
||||
{
|
||||
SceneClass::Add_Render_Object(obj);
|
||||
if (obj->Class_ID()==RenderObjClass::CLASSID_LIGHT)
|
||||
LightList.Add(obj);
|
||||
else
|
||||
RenderList.Add(obj);
|
||||
|
||||
// Recalculate the fogging distances.
|
||||
Recalculate_Fog_Planes();
|
||||
}
|
||||
|
||||
void ViewerSceneClass::Recalculate_Fog_Planes (void)
|
||||
{
|
||||
const float FOG_OPAQUE_MULTIPLE = 8.0f;
|
||||
const float FOG_MINIMUM_DEPTH = 200.0f;
|
||||
|
||||
// Adjust the fog far clipping plane based on the size of the
|
||||
// scene's bounding box depth (X value). We'll have the fog be
|
||||
// completely opaque at FOG_OPAQUE_MULTIPLE times the depth of
|
||||
// the scene's bounding box.
|
||||
float fog_near=0, fog_far=0;
|
||||
Get_Fog_Range(&fog_near, &fog_far);
|
||||
SphereClass sphere = Get_Bounding_Sphere();
|
||||
|
||||
// Calculate the fog far plane. If it is too close to the
|
||||
// near plane, use the camera's far clip plane setting.
|
||||
fog_far = sphere.Radius * FOG_OPAQUE_MULTIPLE;
|
||||
if (fog_far < fog_near + FOG_MINIMUM_DEPTH)
|
||||
fog_far = fog_near + FOG_MINIMUM_DEPTH;
|
||||
Set_Fog_Range(fog_near, fog_far);
|
||||
}
|
||||
|
||||
void ViewerSceneClass::Customized_Render(RenderInfoClass & rinfo)
|
||||
{
|
||||
#ifdef WW3D_DX8 // just use simplescene for now...
|
||||
// If visibility has not been checked for this scene since the last
|
||||
// Render() call, check it (set/clear the visibility bit in all render
|
||||
// objects in the scene).
|
||||
if (!Visibility_Checked) {
|
||||
// set the visibility bit in all render objects in all layers.
|
||||
Visibility_Check(&rinfo.Camera);
|
||||
}
|
||||
Visibility_Checked = false;
|
||||
|
||||
// Install the vertex processors. Derived scenes may want to use some
|
||||
// form of spatial subdivision to only insert the needed vps...
|
||||
RefRenderObjListIterator it(&LightList);
|
||||
for (it.First(); !it.Is_Done(); it.Next()) {
|
||||
it.Peek_Obj()->Vertex_Processor_Push(rinfo);
|
||||
}
|
||||
|
||||
if (FogEnabled) Fog->Vertex_Processor_Push(rinfo);
|
||||
|
||||
// make a light environmemt class
|
||||
|
||||
LightEnvironmentClass lenv;
|
||||
|
||||
lenv.Reset(Vector3(0,0,0),AmbientLight);
|
||||
RefRenderObjListIterator it(&LightList);
|
||||
|
||||
for (it.First(&LightList); !it.Is_Done(); it.Next()) {
|
||||
lenv.Add_Light(*(LightClass*)it.Peek_Obj());
|
||||
}
|
||||
lenv.Pre_Render_Update(rinfo.Camera.Get_Transform());
|
||||
|
||||
rinfo.light_environment=&lenv;
|
||||
|
||||
// allow all objects in the update list to do their "every frame" processing
|
||||
for (it.First(&UpdateList); !it.Is_Done(); it.Next()) {
|
||||
it.Peek_Obj()->On_Frame_Update();
|
||||
}
|
||||
|
||||
// loop through all render objects in the list:
|
||||
for (it.First(&RenderList); !it.Is_Done(); it.Next()) {
|
||||
|
||||
// get the render object
|
||||
RenderObjClass * robj = it.Peek_Obj();
|
||||
|
||||
if (robj->Is_Really_Visible()) {
|
||||
|
||||
// Do "visible" processing and add to the surrender scene
|
||||
robj->Render(rinfo);
|
||||
}
|
||||
}
|
||||
|
||||
if (FogEnabled) Fog->Vertex_Processor_Pop(rinfo);
|
||||
|
||||
// Now loop through the objects, removing their vertex processors. See
|
||||
// note above regarding more efficient methods of managing vertex processors.
|
||||
for (it.First(&LightList); !it.Is_Done(); it.Next()) {
|
||||
it.Peek_Obj()->Vertex_Processor_Pop(rinfo);
|
||||
}
|
||||
|
||||
#else
|
||||
SimpleSceneClass::Customized_Render(rinfo);
|
||||
#endif //WW3D_DX8
|
||||
}
|
||||
Reference in New Issue
Block a user