| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390 |
- /*
- ** 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
- }
|