ViewerScene.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** 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 ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : W3DView *
  23. * *
  24. * $Archive:: /Commando/Code/Tools/W3DView/ViewerScene.cpp $*
  25. * *
  26. * Author:: Patrick Smith *
  27. * *
  28. * $Modtime:: 3/15/01 3:04p $*
  29. * *
  30. * $Revision:: 10 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "StdAfx.H"
  36. #include "ViewerScene.H"
  37. #include "Camera.H"
  38. #include "WW3D.H"
  39. #include "RendObj.H"
  40. #include "AssetMgr.H"
  41. #include "rinfo.h"
  42. #include "lightenvironment.h"
  43. /*
  44. ** ViewerSceneIterator
  45. ** This iterator is used by the ViewerSceneClass to allow
  46. ** the user to iterate through its render objects.
  47. */
  48. class ViewerSceneIterator : public SceneIterator
  49. {
  50. public:
  51. virtual void First(void);
  52. virtual void Next(void);
  53. virtual bool Is_Done(void);
  54. virtual RenderObjClass * Current_Item(void);
  55. protected:
  56. ViewerSceneIterator(RefRenderObjListClass * renderlist);
  57. RefRenderObjListIterator RobjIterator;
  58. friend class ViewerSceneClass;
  59. };
  60. ViewerSceneIterator::ViewerSceneIterator(RefRenderObjListClass *list)
  61. : RobjIterator(list)
  62. {
  63. }
  64. void ViewerSceneIterator::First(void)
  65. {
  66. RobjIterator.First();
  67. }
  68. void ViewerSceneIterator::Next(void)
  69. {
  70. RobjIterator.Next();
  71. }
  72. bool ViewerSceneIterator::Is_Done(void)
  73. {
  74. return RobjIterator.Is_Done();
  75. }
  76. RenderObjClass * ViewerSceneIterator::Current_Item(void)
  77. {
  78. return RobjIterator.Peek_Obj();
  79. }
  80. /*
  81. **
  82. ** ViewerSceneClass Implementation!
  83. **
  84. */
  85. ////////////////////////////////////////////////////////////////////////
  86. //
  87. // Visibility_Check
  88. //
  89. // Note: We overide this method to remove the LOD preparation. We
  90. // need to be able to specify an LOD and not have it switch on us.
  91. //
  92. ////////////////////////////////////////////////////////////////////////
  93. void
  94. ViewerSceneClass::Visibility_Check (CameraClass *camera)
  95. {
  96. RefRenderObjListIterator it(&RenderList);
  97. // Loop over all top-level RenderObjects in this scene. If the bounding sphere is not in front
  98. // of all the frustum planes, it is invisible.
  99. for (it.First(); !it.Is_Done(); it.Next()) {
  100. RenderObjClass * robj = it.Peek_Obj();
  101. if (robj->Is_Force_Visible()) {
  102. robj->Set_Visible(true);
  103. } else {
  104. robj->Set_Visible(!camera->Cull_Sphere(robj->Get_Bounding_Sphere()));
  105. }
  106. int lod_level = robj->Get_LOD_Level ();
  107. // Prepare visible objects for LOD:
  108. if (robj->Is_Really_Visible()) {
  109. robj->Prepare_LOD(*camera);
  110. }
  111. if (m_AllowLODSwitching == false) {
  112. robj->Set_LOD_Level (lod_level);
  113. }
  114. }
  115. Visibility_Checked = true;
  116. //SimpleSceneClass::Visibility_Check (camera);
  117. return ;
  118. }
  119. void
  120. ViewerSceneClass::Add_To_Lineup (RenderObjClass *obj)
  121. {
  122. assert(obj);
  123. // If this is an insignificant object (ie. we don't need to
  124. // rearrange existing objects to accomodate it), don't bother
  125. // adding it to the lineup. Ex: Adding a light to the lineup
  126. // is pretty silly.
  127. if (!Can_Line_Up(obj))
  128. return;
  129. // We will add this object to the scene next to any
  130. // existing objects. It will be placed at (0, Y, 0)
  131. // where Y is a value to be calculated such that the
  132. // center of the scene (0,0,0) is in the middle of the
  133. // row of objects. The existing objects will need to
  134. // be moved along the -Y axis to make room.
  135. // Figure out how 'wide' the object is (width assuming it
  136. // it facing along the +X axis).
  137. AABoxClass obj_box;
  138. obj->Get_Obj_Space_Bounding_Box(obj_box);
  139. float obj_width = obj_box.Extent.Y * 2.0f;
  140. // Figure out the bounding box for the objects in the lineup.
  141. AABoxClass scene_box = Get_Line_Up_Bounding_Box();
  142. float scene_width = scene_box.Extent.Y * 2.0f;
  143. // How much do we have to move the existing objects by?
  144. float new_scene_width = scene_width + obj_width + obj_width/3;
  145. float delta = (new_scene_width - scene_width) / 2;
  146. // Move the existing objects along the -Y axis.
  147. int num_existing_objects = 0;
  148. SceneIterator *it = Create_Iterator();
  149. assert(it);
  150. for (; !it->Is_Done(); it->Next())
  151. {
  152. RenderObjClass *current_obj = it->Current_Item();
  153. assert(current_obj);
  154. if (Can_Line_Up(current_obj))
  155. {
  156. Vector3 pos = current_obj->Get_Position();
  157. pos.Y -= delta;
  158. current_obj->Set_Position(pos);
  159. ++num_existing_objects;
  160. }
  161. }
  162. Destroy_Iterator(it);
  163. // Move the new object so that it will be in line
  164. // with the existing objects.
  165. if (num_existing_objects > 0)
  166. obj->Set_Position(Vector3(0,new_scene_width/2 - obj_box.Extent.Y, 0));
  167. else
  168. obj->Set_Position(Vector3(0,0,0));
  169. // Add the object to the scene.
  170. Add_Render_Object(obj);
  171. // Add the object to the list of objects in the lineup.
  172. LineUpList.Add(obj);
  173. }
  174. void
  175. ViewerSceneClass::Clear_Lineup (void)
  176. {
  177. // Remove every object in the lineup from the scene,
  178. // and remove each object from the line up list.
  179. RenderObjClass *obj = NULL;
  180. while (obj = LineUpList.Remove_Head())
  181. Remove_Render_Object(obj);
  182. }
  183. SphereClass
  184. ViewerSceneClass::Get_Bounding_Sphere (void)
  185. {
  186. // Iterate through every object in the scene, adding its
  187. // bounding sphere to the current bounding sphere. The sum of
  188. // the bounding spheres will be the scene's bounding sphere.
  189. SphereClass bounding_sphere(Vector3(0,0,0), 0.0f);
  190. SceneIterator *it = Create_Iterator();
  191. assert(it);
  192. for (; !it->Is_Done(); it->Next())
  193. {
  194. RenderObjClass *rend_obj = it->Current_Item();
  195. assert(rend_obj);
  196. // Omit lights in the bounding sphere calculations.
  197. if (rend_obj->Class_ID() != RenderObjClass::CLASSID_LIGHT)
  198. bounding_sphere.Add_Sphere(rend_obj->Get_Bounding_Sphere());
  199. }
  200. Destroy_Iterator(it);
  201. return bounding_sphere;
  202. }
  203. AABoxClass
  204. ViewerSceneClass::Get_Line_Up_Bounding_Box (void)
  205. {
  206. // Iterate through each object in the lineup, adding its
  207. // bounding box to the current bounding box. The sum
  208. // of the bounding boxes will be the lineup's bounding box.
  209. AABoxClass sum_of_boxes(Vector3(0,0,0), Vector3(0,0,0));
  210. SceneIterator *it = Create_Iterator();
  211. assert(it);
  212. for (; !it->Is_Done(); it->Next())
  213. {
  214. RenderObjClass *rend_obj = it->Current_Item();
  215. assert(rend_obj);
  216. if (Can_Line_Up(rend_obj))
  217. sum_of_boxes.Add_Box(rend_obj->Get_Bounding_Box());
  218. }
  219. Destroy_Iterator(it);
  220. return sum_of_boxes;
  221. }
  222. bool
  223. ViewerSceneClass::Can_Line_Up (RenderObjClass * obj)
  224. {
  225. assert(obj);
  226. return Can_Line_Up(obj->Class_ID());
  227. }
  228. bool
  229. ViewerSceneClass::Can_Line_Up (int class_id)
  230. {
  231. return (class_id == RenderObjClass::CLASSID_HMODEL) ||
  232. (class_id == RenderObjClass::CLASSID_HLOD);
  233. }
  234. SceneIterator *
  235. ViewerSceneClass::Create_Line_Up_Iterator (void)
  236. {
  237. return new ViewerSceneIterator(&LineUpList);
  238. }
  239. void
  240. ViewerSceneClass::Destroy_Line_Up_Iterator (SceneIterator *it)
  241. {
  242. delete it;
  243. }
  244. void ViewerSceneClass::Add_Render_Object(RenderObjClass * obj)
  245. {
  246. SceneClass::Add_Render_Object(obj);
  247. if (obj->Class_ID()==RenderObjClass::CLASSID_LIGHT)
  248. LightList.Add(obj);
  249. else
  250. RenderList.Add(obj);
  251. // Recalculate the fogging distances.
  252. Recalculate_Fog_Planes();
  253. }
  254. void ViewerSceneClass::Recalculate_Fog_Planes (void)
  255. {
  256. const float FOG_OPAQUE_MULTIPLE = 8.0f;
  257. const float FOG_MINIMUM_DEPTH = 200.0f;
  258. // Adjust the fog far clipping plane based on the size of the
  259. // scene's bounding box depth (X value). We'll have the fog be
  260. // completely opaque at FOG_OPAQUE_MULTIPLE times the depth of
  261. // the scene's bounding box.
  262. float fog_near=0, fog_far=0;
  263. Get_Fog_Range(&fog_near, &fog_far);
  264. SphereClass sphere = Get_Bounding_Sphere();
  265. // Calculate the fog far plane. If it is too close to the
  266. // near plane, use the camera's far clip plane setting.
  267. fog_far = sphere.Radius * FOG_OPAQUE_MULTIPLE;
  268. if (fog_far < fog_near + FOG_MINIMUM_DEPTH)
  269. fog_far = fog_near + FOG_MINIMUM_DEPTH;
  270. Set_Fog_Range(fog_near, fog_far);
  271. }
  272. void ViewerSceneClass::Customized_Render(RenderInfoClass & rinfo)
  273. {
  274. #ifdef WW3D_DX8 // just use simplescene for now...
  275. // If visibility has not been checked for this scene since the last
  276. // Render() call, check it (set/clear the visibility bit in all render
  277. // objects in the scene).
  278. if (!Visibility_Checked) {
  279. // set the visibility bit in all render objects in all layers.
  280. Visibility_Check(&rinfo.Camera);
  281. }
  282. Visibility_Checked = false;
  283. // Install the vertex processors. Derived scenes may want to use some
  284. // form of spatial subdivision to only insert the needed vps...
  285. RefRenderObjListIterator it(&LightList);
  286. for (it.First(); !it.Is_Done(); it.Next()) {
  287. it.Peek_Obj()->Vertex_Processor_Push(rinfo);
  288. }
  289. if (FogEnabled) Fog->Vertex_Processor_Push(rinfo);
  290. // make a light environmemt class
  291. LightEnvironmentClass lenv;
  292. lenv.Reset(Vector3(0,0,0),AmbientLight);
  293. RefRenderObjListIterator it(&LightList);
  294. for (it.First(&LightList); !it.Is_Done(); it.Next()) {
  295. lenv.Add_Light(*(LightClass*)it.Peek_Obj());
  296. }
  297. lenv.Pre_Render_Update(rinfo.Camera.Get_Transform());
  298. rinfo.light_environment=&lenv;
  299. // allow all objects in the update list to do their "every frame" processing
  300. for (it.First(&UpdateList); !it.Is_Done(); it.Next()) {
  301. it.Peek_Obj()->On_Frame_Update();
  302. }
  303. // loop through all render objects in the list:
  304. for (it.First(&RenderList); !it.Is_Done(); it.Next()) {
  305. // get the render object
  306. RenderObjClass * robj = it.Peek_Obj();
  307. if (robj->Is_Really_Visible()) {
  308. // Do "visible" processing and add to the surrender scene
  309. robj->Render(rinfo);
  310. }
  311. }
  312. if (FogEnabled) Fog->Vertex_Processor_Pop(rinfo);
  313. // Now loop through the objects, removing their vertex processors. See
  314. // note above regarding more efficient methods of managing vertex processors.
  315. for (it.First(&LightList); !it.Is_Done(); it.Next()) {
  316. it.Peek_Obj()->Vertex_Processor_Pop(rinfo);
  317. }
  318. #else
  319. SimpleSceneClass::Customized_Render(rinfo);
  320. #endif //WW3D_DX8
  321. }