W3DGhostObject.cpp 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258
  1. /*
  2. ** Command & Conquer Generals Zero Hour(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. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // FILE: W3DGhostObject.cpp /////////////////////////////////////////////////////
  24. //
  25. // Placeholder for objects that have been deleted but need to be maintained because
  26. // a player can see them fogged.
  27. //
  28. // Author: Mark Wilczynski, August 2002
  29. ///////////////////////////////////////////////////////////////////////////////
  30. #include "Common/Debug.h"
  31. #include "Common/Player.h"
  32. #include "Common/PlayerList.h"
  33. #include "Common/ThingTemplate.h"
  34. #include "Common/Xfer.h"
  35. #include "GameClient/Drawable.h"
  36. #include "GameClient/GameClient.h"
  37. #include "GameLogic/GameLogic.h"
  38. #include "GameLogic/Object.h"
  39. #include "GameLogic/PartitionManager.h"
  40. #include "W3DDevice/GameClient/Module/W3DModelDraw.h"
  41. #include "W3DDevice/GameClient/W3DAssetManager.h"
  42. #include "W3DDevice/GameClient/W3DDisplay.h"
  43. #include "W3DDevice/GameLogic/W3DGhostObject.h"
  44. #include "WW3D2/rendobj.h"
  45. #include "WW3D2/hlod.h"
  46. #include "WW3D2/Scene.h"
  47. #include "WW3D2/matinfo.h"
  48. #ifdef _INTERNAL
  49. // for occasional debugging...
  50. //#pragma optimize("", off)
  51. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  52. #endif
  53. /**This class will hold all information about a W3D RenderObject needed to
  54. reconstruct it if necessary*/
  55. class W3DRenderObjectSnapshot : public Snapshot
  56. {
  57. friend W3DGhostObject;
  58. W3DRenderObjectSnapshot(RenderObjClass *m_parentRobj, DrawableInfo *drawInfo, Bool cloneParentRobj = TRUE);
  59. ~W3DRenderObjectSnapshot() {REF_PTR_RELEASE(m_robj);}
  60. inline void update(RenderObjClass *robj, DrawableInfo *drawInfo, Bool cloneParentRobj=TRUE); ///<refresh the current snapshot with latest state
  61. inline void addToScene(void); ///< add this fogged renderobject to the scene.
  62. protected:
  63. virtual void crc( Xfer *xfer );
  64. virtual void xfer( Xfer *xfer );
  65. virtual void loadPostProcess( void );
  66. #ifdef DEBUG_FOG_MEMORY
  67. const char *m_robjName; ///<debug pointer so we know what this is a snapshot of.
  68. #endif
  69. RenderObjClass *m_robj; ///<render object representing state at time of snapshot
  70. W3DRenderObjectSnapshot *m_next; ///<snapshot of next render object belonging to same drawable
  71. };
  72. //Dummy material override which we assign to all ghost objects to disable their
  73. //texture animation.
  74. static RenderObjClass::Material_Override animationDisableOverride;
  75. //Helper function used to disable all UV mapper animations on a given model.
  76. //Also use this pass to disable muzzle effects.
  77. void disableUVAnimations(RenderObjClass *robj)
  78. {
  79. if (robj && robj->Class_ID() == RenderObjClass::CLASSID_HLOD)
  80. {
  81. //Also disable any animations that may be playing using mappers (texture scrolling)
  82. for (Int i=0; i < robj->Get_Num_Sub_Objects(); i++)
  83. {
  84. RenderObjClass *subObj=robj->Get_Sub_Object(i);
  85. if (subObj && subObj->Class_ID() == RenderObjClass::CLASSID_MESH)
  86. { //check if sub-object has the correct material to do texture scrolling.
  87. MaterialInfoClass *mat=subObj->Get_Material_Info();
  88. if (mat)
  89. { for (Int j=0; j<mat->Vertex_Material_Count(); j++)
  90. {
  91. VertexMaterialClass *vmaterial=mat->Peek_Vertex_Material(j);
  92. LinearOffsetTextureMapperClass *mapper=(LinearOffsetTextureMapperClass *)vmaterial->Peek_Mapper();
  93. if (mapper && mapper->Mapper_ID() == TextureMapperClass::MAPPER_ID_LINEAR_OFFSET)
  94. {
  95. subObj->Set_User_Data(&animationDisableOverride); //tell W3D about custom material settings
  96. }
  97. }
  98. REF_PTR_RELEASE(mat);
  99. }
  100. //We don't want muzzle flashes visible inside fog, so turn them off.
  101. if (subObj->Get_Name() && strstr(subObj->Get_Name(),"MUZZLEFX"))
  102. subObj->Set_Hidden(true);
  103. }
  104. REF_PTR_RELEASE(subObj);
  105. }
  106. }
  107. }
  108. // ------------------------------------------------------------------------------------------------
  109. // ------------------------------------------------------------------------------------------------
  110. void W3DRenderObjectSnapshot::update(RenderObjClass *robj, DrawableInfo *drawInfo,
  111. Bool cloneParentRobj)
  112. {
  113. REF_PTR_RELEASE(m_robj);
  114. if( cloneParentRobj == TRUE )
  115. {
  116. m_robj=robj->Clone();
  117. m_robj->Set_ObjectColor(robj->Get_ObjectColor());
  118. #ifdef DEBUG_FOG_MEMORY
  119. m_robjName = m_robj->Get_Name();
  120. #endif
  121. //Set cloned object to same state as original object.
  122. m_robj->Set_Transform(robj->Get_Transform());
  123. if (robj->Class_ID() == RenderObjClass::CLASSID_HLOD)
  124. {
  125. float frame,mult;
  126. int mode,numFrames;
  127. HAnimClass *hanim=((HLodClass *)robj)->Peek_Animation_And_Info(frame,numFrames,mode,mult);
  128. m_robj->Set_Animation(hanim,frame);
  129. disableUVAnimations(m_robj);
  130. } //HLOD
  131. }
  132. else
  133. m_robj=robj;
  134. m_robj->Set_User_Data(drawInfo);
  135. }
  136. // ------------------------------------------------------------------------------------------------
  137. // ------------------------------------------------------------------------------------------------
  138. void W3DRenderObjectSnapshot::addToScene(void)
  139. {
  140. ((SimpleSceneClass *)W3DDisplay::m_3DScene)->Add_Render_Object(m_robj);
  141. }
  142. // ------------------------------------------------------------------------------------------------
  143. // ------------------------------------------------------------------------------------------------
  144. W3DRenderObjectSnapshot::W3DRenderObjectSnapshot(RenderObjClass *robj, DrawableInfo *drawInfo,
  145. Bool cloneParentRobj)
  146. {
  147. m_robj=NULL;
  148. m_next=NULL;
  149. update(robj, drawInfo, cloneParentRobj);
  150. }
  151. // ------------------------------------------------------------------------------------------------
  152. /** CRC */
  153. // ------------------------------------------------------------------------------------------------
  154. void W3DRenderObjectSnapshot::crc( Xfer *xfer )
  155. {
  156. } // end crc
  157. // ------------------------------------------------------------------------------------------------
  158. /** Xfer method
  159. * Version Info:
  160. * 1: Initial version */
  161. // ------------------------------------------------------------------------------------------------
  162. void W3DRenderObjectSnapshot::xfer( Xfer *xfer )
  163. {
  164. // version
  165. XferVersion currentVersion = 1;
  166. XferVersion version = currentVersion;
  167. xfer->xferVersion( &version, currentVersion );
  168. // sanity
  169. DEBUG_ASSERTCRASH( m_robj, ("W3DRenderObjectSnapshot::xfer - invalid m_robj\n") );
  170. // transform on the main render object
  171. Matrix3D transform;
  172. transform = m_robj->Get_Transform();
  173. xfer->xferUser( &transform, sizeof( Matrix3D ) );
  174. if( xfer->getXferMode() == XFER_LOAD )
  175. m_robj->Set_Transform( transform );
  176. // how many sub objects of data will follow
  177. Int subObjectCount = m_robj->Get_Num_Sub_Objects();
  178. xfer->xferInt( &subObjectCount );
  179. Bool visible;
  180. RenderObjClass *subObject;
  181. AsciiString subObjectName;
  182. for( Int i = 0; i < subObjectCount; ++i )
  183. {
  184. //
  185. // when saving we get sub objects by index and xfer their name, when loading
  186. // we read the name and find that sub object
  187. //
  188. if( xfer->getXferMode() == XFER_SAVE )
  189. {
  190. // get sub object
  191. subObject = m_robj->Get_Sub_Object( i );
  192. // xfer sub object name which is unique among those in this render object
  193. subObjectName.set( subObject->Get_Name() );
  194. xfer->xferAsciiString( &subObjectName );
  195. } // end if, save
  196. else
  197. {
  198. // read sub object name
  199. xfer->xferAsciiString( &subObjectName );
  200. // find this sub object on the object
  201. subObject = m_robj->Get_Sub_Object_By_Name( subObjectName.str() );
  202. } // end else load
  203. //
  204. // NOTE that the remainder of this xfer code works on a sub object only *if*
  205. // it is present. It is possible that in future patches we change the artwork
  206. // for some objects which could remove sub objects for which we have data saved
  207. // for in the save game file. If we encounter data in the save file for
  208. // sub objects that are no longer in the artwork we just read the data and
  209. // throw it away
  210. //
  211. // visible/hidden status of this sub object
  212. if( subObject )
  213. visible = subObject->Is_Not_Hidden_At_All();
  214. xfer->xferBool( &visible );
  215. if( subObject && xfer->getXferMode() == XFER_LOAD )
  216. subObject->Set_Hidden( !visible );
  217. // transform of this sub object
  218. if( subObject )
  219. transform = subObject->Get_Transform();
  220. xfer->xferUser( &transform, sizeof( Matrix3D ) );
  221. if( subObject && xfer->getXferMode() == XFER_LOAD )
  222. subObject->Set_Transform( transform );
  223. // need to tell W3D that this sub object transforms are ok
  224. if( subObject )
  225. {
  226. // need to cast to HLod if we can to validate the hierarchy
  227. if( subObject->Class_ID() == RenderObjClass::CLASSID_HLOD )
  228. ((HLodClass *)subObject)->Friend_Set_Hierarchy_Valid( TRUE );
  229. } // end if
  230. // release reference to sub object
  231. if( subObject )
  232. REF_PTR_RELEASE( subObject );
  233. } // end for, i
  234. // tell W3D that the transforms for our sub objects are all OK cause we've done them ourselves
  235. m_robj->Set_Sub_Object_Transforms_Dirty( FALSE );
  236. } // end xfer
  237. // ------------------------------------------------------------------------------------------------
  238. /** Load post process */
  239. // ------------------------------------------------------------------------------------------------
  240. void W3DRenderObjectSnapshot::loadPostProcess( void )
  241. {
  242. } // end loadPostProcess
  243. // ------------------------------------------------------------------------------------------------
  244. // ------------------------------------------------------------------------------------------------
  245. W3DGhostObject::W3DGhostObject()
  246. {
  247. for (Int i=0; i< MAX_PLAYER_COUNT; i++)
  248. m_parentSnapshots[i]=NULL;
  249. m_drawableInfo.m_drawable = NULL;
  250. m_drawableInfo.m_flags = 0;
  251. m_drawableInfo.m_ghostObject = NULL;
  252. m_drawableInfo.m_shroudStatusObjectID = INVALID_ID;
  253. m_nextSystem = NULL;
  254. m_prevSystem = NULL;
  255. }
  256. // ------------------------------------------------------------------------------------------------
  257. // ------------------------------------------------------------------------------------------------
  258. W3DGhostObject::~W3DGhostObject()
  259. {
  260. #ifdef DEBUG_FOG_MEMORY
  261. for (Int i=0; i<MAX_PLAYER_COUNT; i++)
  262. {
  263. DEBUG_ASSERTCRASH(m_parentSnapshots[i] == NULL, ("Delete of non-empty GhostObject"));
  264. }
  265. #else
  266. DEBUG_ASSERTCRASH(m_parentSnapshots[TheGhostObjectManager->getLocalPlayerIndex()] == NULL, ("Delete of non-empty GhostObject"));
  267. #endif
  268. }
  269. // ------------------------------------------------------------------------------------------------
  270. /** Record the current state of the renderobjects used by this parent object
  271. so we can display cached state when player is looking at fogged object.
  272. Should only be called when object enters the fogged state.*/
  273. // ------------------------------------------------------------------------------------------------
  274. void W3DGhostObject::snapShot(int playerIndex)
  275. {
  276. #ifndef DEBUG_FOG_MEMORY
  277. if (playerIndex != TheGhostObjectManager->getLocalPlayerIndex())
  278. return; //we only snapshot things for the initial local player because local player can't change in non-debug game.
  279. #endif
  280. Drawable *draw=m_parentObject->getDrawable();
  281. if (draw->isDrawableEffectivelyHidden())
  282. return; //don't bother to snapshot things which nobody can see.
  283. W3DRenderObjectSnapshot *snap=m_parentSnapshots[playerIndex],*prevSnap=NULL;
  284. //walk through all W3D render objects used by this object
  285. for (DrawModule ** dm = draw->getDrawModules(); *dm; ++dm)
  286. {
  287. const ObjectDrawInterface* di = (*dm)->getObjectDrawInterface();
  288. if (di)
  289. {
  290. W3DModelDraw *w3dDraw= (W3DModelDraw *)di;
  291. RenderObjClass *robj=NULL;
  292. robj=w3dDraw->getRenderObject();
  293. //robj may be null for modules which have no render objects such
  294. //as for build-ups that are currently disabled.
  295. if (robj)
  296. {
  297. if (snap == NULL)
  298. {
  299. snap = NEW W3DRenderObjectSnapshot(robj, &m_drawableInfo); // poolify
  300. if (prevSnap)
  301. prevSnap->m_next=snap;
  302. else
  303. m_parentSnapshots[playerIndex]=snap;
  304. }
  305. else
  306. m_parentSnapshots[playerIndex]->update(robj, &m_drawableInfo);
  307. //Adding and removing render objects to the scene is expensive
  308. //so only do it for the real player watching the screen. There is
  309. //also no point in displaying the other player's ghost objects to
  310. //the current player.
  311. if (playerIndex == TheGhostObjectManager->getLocalPlayerIndex())
  312. {
  313. robj->Remove(); //remove normal object from scene
  314. snap->addToScene();
  315. }
  316. prevSnap=snap;
  317. snap = snap->m_next;
  318. }
  319. }
  320. }
  321. //Check if we captured at least one snapshot
  322. if (snap != m_parentSnapshots[playerIndex])
  323. { //save off other info we may need in case the parent object is destroyed.
  324. ///@todo: We're going to ignore the case where each player index could be
  325. //looking at a different geometry info/orientation because ghostobjects
  326. //are supposed to be used on immobile buildings.
  327. m_parentGeometryType=m_parentObject->getGeometryInfo().getGeomType();
  328. m_parentGeometryIsSmall=m_parentObject->getGeometryInfo().getIsSmall();
  329. m_parentGeometryMajorRadius=m_parentObject->getGeometryInfo().getMajorRadius();
  330. m_parentGeometryminorRadius=m_parentObject->getGeometryInfo().getMinorRadius();
  331. m_parentPosition=*m_parentObject->getPosition();
  332. m_parentAngle=m_parentObject->getOrientation();
  333. }
  334. }
  335. // ------------------------------------------------------------------------------------------------
  336. /** Remove the original object from our 3D scene*/
  337. // ------------------------------------------------------------------------------------------------
  338. void W3DGhostObject::removeParentObject(void)
  339. {
  340. // sanity
  341. if( m_parentObject == NULL )
  342. return;
  343. Drawable *draw=m_parentObject->getDrawable();
  344. //After we remove the unfogged object, we also disable
  345. //anything that should be hidden inside fog - shadow, particles, etc.
  346. draw->setFullyObscuredByShroud(true);
  347. //walk through all W3D render objects used by this object
  348. for (DrawModule ** dm = draw->getDrawModules(); *dm; ++dm)
  349. {
  350. const ObjectDrawInterface* di = (*dm)->getObjectDrawInterface();
  351. if (di)
  352. {
  353. W3DModelDraw *w3dDraw= (W3DModelDraw *)di;
  354. RenderObjClass *robj=NULL;
  355. robj=w3dDraw->getRenderObject();
  356. if (robj)
  357. {
  358. DEBUG_ASSERTCRASH(robj->Peek_Scene() != NULL, ("Removing GhostObject parent not in scene "));
  359. robj->Remove();
  360. }
  361. }
  362. }
  363. }
  364. // ------------------------------------------------------------------------------------------------
  365. /** Reinsert the original object into our 3D scene*/
  366. // ------------------------------------------------------------------------------------------------
  367. void W3DGhostObject::restoreParentObject(void)
  368. {
  369. Drawable *draw=m_parentObject->getDrawable();
  370. if (!draw)
  371. return;
  372. //Notify drawable that it's okay to render its render objects again.
  373. draw->setFullyObscuredByShroud(false);
  374. //walk through all W3D render objects used by this object
  375. for (DrawModule ** dm = draw->getDrawModules(); *dm; ++dm)
  376. {
  377. const ObjectDrawInterface* di = (*dm)->getObjectDrawInterface();
  378. if (di)
  379. {
  380. W3DModelDraw *w3dDraw= (W3DModelDraw *)di;
  381. RenderObjClass *robj=NULL;
  382. robj=w3dDraw->getRenderObject();
  383. //robj may be null for modules which have no render objects such
  384. //as for build-ups that are currently disabled.
  385. if (robj)
  386. { //if we have a render object that's not in the scene, it must have been
  387. //removed by the ghost object manager, so restore it. If we have a render
  388. //object that is in the scene, then it was probably added because the model
  389. //changed while the object was ghosted (for damage states, garrison, etc.).
  390. if (robj->Peek_Scene() == NULL)
  391. ((SimpleSceneClass *)W3DDisplay::m_3DScene)->Add_Render_Object(robj);
  392. }
  393. }
  394. }
  395. }
  396. // ------------------------------------------------------------------------------------------------
  397. // ------------------------------------------------------------------------------------------------
  398. void W3DGhostObject::freeAllSnapShots(void)
  399. {
  400. Int playerIndex;
  401. #ifdef DEBUG_FOG_MEMORY
  402. for (playerIndex=0; playerIndex<MAX_PLAYER_COUNT; playerIndex++)
  403. #else
  404. playerIndex = TheGhostObjectManager->getLocalPlayerIndex();
  405. #endif
  406. if (m_parentSnapshots[playerIndex])
  407. { //if we have a snapshot for this object, remove it from
  408. //scene.
  409. removeFromScene(playerIndex);
  410. //Restore actual objects assuming they are still alive.
  411. if (m_parentObject)
  412. restoreParentObject();
  413. W3DRenderObjectSnapshot *snap=m_parentSnapshots[playerIndex];
  414. W3DRenderObjectSnapshot *nextSnap;
  415. while (snap)
  416. { nextSnap = snap->m_next;
  417. delete snap;
  418. snap = nextSnap;
  419. }
  420. m_parentSnapshots[playerIndex]=NULL;
  421. }
  422. }
  423. // ------------------------------------------------------------------------------------------------
  424. /** Player has unfogged the object so he no longer needs the snapshot*/
  425. // ------------------------------------------------------------------------------------------------
  426. void W3DGhostObject::freeSnapShot(int playerIndex)
  427. {
  428. #ifndef DEBUG_FOG_MEMORY
  429. if (playerIndex != TheGhostObjectManager->getLocalPlayerIndex())
  430. return; //we only snapshot things for the local player
  431. #endif
  432. if (m_parentSnapshots[playerIndex])
  433. { //if we have a snapshot for this object, remove it from
  434. //scene and put back the original object if it still exists.
  435. if (playerIndex == TheGhostObjectManager->getLocalPlayerIndex())
  436. {
  437. //Adding and removing render objects to the scene is expensive
  438. //so only do it for the real player watching the screen. There is
  439. //also no point in displaying the other player's objects to
  440. //the current player.
  441. removeFromScene(playerIndex);
  442. //Restore actual objects assuming they are still alive.
  443. if (m_parentObject)
  444. restoreParentObject();
  445. }
  446. W3DRenderObjectSnapshot *snap=m_parentSnapshots[playerIndex];
  447. W3DRenderObjectSnapshot *nextSnap;
  448. while (snap)
  449. { nextSnap = snap->m_next;
  450. delete snap;
  451. snap = nextSnap;
  452. }
  453. m_parentSnapshots[playerIndex]=NULL;
  454. }
  455. }
  456. // ------------------------------------------------------------------------------------------------
  457. // ------------------------------------------------------------------------------------------------
  458. void W3DGhostObject::updateParentObject(Object *object, PartitionData *mod)
  459. {
  460. m_parentObject = object;
  461. m_partitionData = mod;
  462. }
  463. // ------------------------------------------------------------------------------------------------
  464. /**Remove the dummy render objects from scene that belong to given player*/
  465. // ------------------------------------------------------------------------------------------------
  466. void W3DGhostObject::removeFromScene(int playerIndex)
  467. {
  468. W3DRenderObjectSnapshot *snap=m_parentSnapshots[playerIndex];
  469. while (snap)
  470. {
  471. snap->m_robj->Remove();
  472. snap=snap->m_next;
  473. }
  474. }
  475. // ------------------------------------------------------------------------------------------------
  476. /**Add the dummy render objects to scene so player sees the correct version within the fog*/
  477. // ------------------------------------------------------------------------------------------------
  478. void W3DGhostObject::addToScene(int playerIndex)
  479. {
  480. W3DRenderObjectSnapshot *snap=m_parentSnapshots[playerIndex];
  481. while (snap)
  482. {
  483. ((SimpleSceneClass *)W3DDisplay::m_3DScene)->Add_Render_Object(snap->m_robj);
  484. snap=snap->m_next;
  485. }
  486. }
  487. // ------------------------------------------------------------------------------------------------
  488. // ------------------------------------------------------------------------------------------------
  489. void W3DGhostObject::release(void)
  490. {
  491. W3DRenderObjectSnapshot *snap,*nextSnap;
  492. for (Int i=0; i<MAX_PLAYER_COUNT; i++)
  493. { snap = m_parentSnapshots[i];
  494. while (snap)
  495. {
  496. nextSnap=snap->m_next;
  497. delete snap;
  498. snap=nextSnap;
  499. }
  500. m_parentSnapshots[i]=NULL;
  501. }
  502. }
  503. // ------------------------------------------------------------------------------------------------
  504. // ------------------------------------------------------------------------------------------------
  505. void W3DGhostObject::getShroudStatus(int playerIndex)
  506. {
  507. m_partitionData->getShroudedStatus(playerIndex);
  508. }
  509. // ------------------------------------------------------------------------------------------------
  510. /** CRC */
  511. // ------------------------------------------------------------------------------------------------
  512. void W3DGhostObject::crc( Xfer *xfer )
  513. {
  514. // extend base class
  515. GhostObject::crc( xfer );
  516. } // end crc
  517. // ------------------------------------------------------------------------------------------------
  518. /** Xfer method
  519. * Version Info:
  520. * 1: Initial version */
  521. // ------------------------------------------------------------------------------------------------
  522. void W3DGhostObject::xfer( Xfer *xfer )
  523. {
  524. // version
  525. XferVersion currentVersion = 1;
  526. XferVersion version = currentVersion;
  527. xfer->xferVersion( &version, currentVersion );
  528. // extend base class
  529. GhostObject::xfer( xfer );
  530. // xfer the drawable info object id
  531. xfer->xferObjectID( &m_drawableInfo.m_shroudStatusObjectID );
  532. // drawable info flags
  533. xfer->xferInt( &m_drawableInfo.m_flags );
  534. // drawable info drawable pointer
  535. DrawableID drawableID = m_drawableInfo.m_drawable ? m_drawableInfo.m_drawable->getID() : INVALID_DRAWABLE_ID;
  536. xfer->xferDrawableID( &drawableID );
  537. if( xfer->getXferMode() == XFER_LOAD )
  538. {
  539. // reconnect the drawable pointer
  540. m_drawableInfo.m_drawable = TheGameClient->findDrawableByID( drawableID );
  541. // sanity
  542. if( drawableID != INVALID_DRAWABLE_ID && m_drawableInfo.m_drawable == NULL )
  543. DEBUG_CRASH(( "W3DGhostObject::xfer - Unable to find drawable for ghost object\n" ));
  544. } // end if
  545. //
  546. // no need to mess with this "circular" back into itself pointer to the ghost object
  547. // because it is already valid and assigned upon creation of this ghost object
  548. //
  549. // m_drawableInfo.m_ghostObject <--- no need to mess with this
  550. // xfer snapshot array
  551. UnsignedByte snapshotCount;
  552. for( Int i = 0; i < MAX_PLAYER_COUNT; ++i )
  553. {
  554. // count the snapshots at this index
  555. snapshotCount = 0;
  556. W3DRenderObjectSnapshot *objectSnapshot = m_parentSnapshots[ i ];
  557. while( objectSnapshot )
  558. {
  559. // increment count
  560. snapshotCount++;
  561. // on to the next snapshot
  562. objectSnapshot = objectSnapshot->m_next;
  563. } // end while
  564. // xfer the snapshot count at this index
  565. xfer->xferUnsignedByte( &snapshotCount );
  566. //
  567. // sanity, this catches when we read from the file a count of zero, but our data
  568. // structure already has something allocated in this snapshot index
  569. //
  570. if( snapshotCount == 0 && m_parentSnapshots[ i ] != NULL )
  571. {
  572. DEBUG_CRASH(( "W3DGhostObject::xfer - m_parentShapshots[ %d ] has data present but the count from the xfer stream is empty\n" ));
  573. throw INI_INVALID_DATA;
  574. } // end if
  575. // xfer each of the snapshots at this index
  576. Real scale;
  577. UnsignedInt color;
  578. AsciiString name;
  579. if( xfer->getXferMode() == XFER_SAVE )
  580. {
  581. // iterate through list
  582. objectSnapshot = m_parentSnapshots[ i ];
  583. while( objectSnapshot )
  584. {
  585. // write name from render object
  586. name.set( objectSnapshot->m_robj->Get_Name() );
  587. xfer->xferAsciiString( &name );
  588. // write scale from render object
  589. scale = objectSnapshot->m_robj->Get_ObjectScale();
  590. xfer->xferReal( &scale );
  591. // write color from render object
  592. color = objectSnapshot->m_robj->Get_ObjectColor();
  593. xfer->xferUnsignedInt( &color );
  594. // xfer data
  595. xfer->xferSnapshot( objectSnapshot );
  596. // onto the next
  597. objectSnapshot = objectSnapshot->m_next;
  598. } // end while
  599. } // end if, save
  600. else
  601. {
  602. RenderObjClass *renderObject;
  603. W3DRenderObjectSnapshot *prevObjectSnapshot = NULL;
  604. for( UnsignedByte j = 0; j < snapshotCount; ++j )
  605. {
  606. // read render object name
  607. xfer->xferAsciiString( &name );
  608. // read scale
  609. xfer->xferReal( &scale );
  610. // read color
  611. xfer->xferUnsignedInt( &color );
  612. // create the render object
  613. renderObject = W3DDisplay::m_assetManager->Create_Render_Obj( name.str(), scale, color );
  614. disableUVAnimations(renderObject);
  615. // we're loading, allocate new snapshot
  616. objectSnapshot = NEW W3DRenderObjectSnapshot( renderObject, &m_drawableInfo, FALSE );
  617. // attach to list
  618. if( prevObjectSnapshot )
  619. prevObjectSnapshot->m_next = objectSnapshot;
  620. else
  621. m_parentSnapshots[ i ] = objectSnapshot;
  622. prevObjectSnapshot = objectSnapshot;
  623. // xfer data
  624. xfer->xferSnapshot( objectSnapshot );
  625. // add snapshot to the scene
  626. objectSnapshot->addToScene();
  627. } // end for, j
  628. } // end else, load
  629. } // end for, i
  630. //
  631. // since there is a snapshot for this object, there cannot be a regular object/drawable
  632. // in the world, we need to remove it
  633. //
  634. if( m_parentObject &&
  635. m_parentSnapshots[ ThePlayerList->getLocalPlayer()->getPlayerIndex() ] != NULL &&
  636. xfer->getXferMode() == XFER_LOAD )
  637. removeParentObject();
  638. // count of partition shroudedness info to follow
  639. UnsignedByte shroudednessCount = 0;
  640. UnsignedByte playerIndex;
  641. for( playerIndex = 0; playerIndex < MAX_PLAYER_COUNT; ++playerIndex )
  642. if( m_parentSnapshots[ playerIndex ] )
  643. shroudednessCount++;
  644. xfer->xferUnsignedByte( &shroudednessCount );
  645. // shroudedness info
  646. ObjectShroudStatus status;
  647. if( xfer->getXferMode() == XFER_SAVE )
  648. {
  649. // iterate through all array points
  650. for( playerIndex = 0; playerIndex < MAX_PLAYER_COUNT; ++playerIndex )
  651. {
  652. // is this a location with any info
  653. if( m_parentSnapshots[ playerIndex ] )
  654. {
  655. // write this index
  656. xfer->xferUnsignedByte( &playerIndex );
  657. // write shroudedness
  658. // status = m_partitionData->getShroudedStatus( playerIndex );
  659. // xfer->xferUser( &status, sizeof( ObjectShroudStatus ) );
  660. // write previous shroudedness
  661. status = m_partitionData->friend_getShroudednessPrevious( playerIndex );
  662. xfer->xferUser( &status, sizeof( ObjectShroudStatus ) );
  663. } // end if, snapshot list here exists
  664. } // end for, i
  665. } // end if, save
  666. else
  667. {
  668. UnsignedByte i;
  669. // how much data is here
  670. for( i = 0; i < shroudednessCount; ++i )
  671. {
  672. // which player index is this data for
  673. xfer->xferUnsignedByte( &playerIndex );
  674. // read shrouded status and set
  675. // xfer->xferUser( &status, sizeof( ObjectShroudStatus ) );
  676. // m_partitionData->friend_setShroudedness( playerIndex, status );
  677. // read shroudedness previous and set
  678. xfer->xferUser( &status, sizeof( ObjectShroudStatus ) );
  679. m_partitionData->friend_setShroudednessPrevious( playerIndex, status );
  680. } // end for, i
  681. } // end else load
  682. } // end xfer
  683. // ------------------------------------------------------------------------------------------------
  684. /** Load post process */
  685. // ------------------------------------------------------------------------------------------------
  686. void W3DGhostObject::loadPostProcess( void )
  687. {
  688. // extend base class
  689. GhostObject::loadPostProcess();
  690. } // end loadPostProcess
  691. // ------------------------------------------------------------------------------------------------
  692. // ------------------------------------------------------------------------------------------------
  693. W3DGhostObjectManager::W3DGhostObjectManager(void)
  694. {
  695. m_freeModules = NULL;
  696. m_usedModules = NULL;
  697. }
  698. // ------------------------------------------------------------------------------------------------
  699. // ------------------------------------------------------------------------------------------------
  700. W3DGhostObjectManager::~W3DGhostObjectManager()
  701. {
  702. reset(); //make sure it's empty
  703. W3DGhostObject *mod = m_freeModules;
  704. W3DGhostObject *nextmod;
  705. while (mod)
  706. {
  707. nextmod=mod->m_nextSystem;
  708. delete mod;
  709. mod=nextmod;
  710. }
  711. }
  712. // ------------------------------------------------------------------------------------------------
  713. // ------------------------------------------------------------------------------------------------
  714. void W3DGhostObjectManager::reset(void)
  715. {
  716. W3DGhostObject *mod = m_usedModules;
  717. W3DGhostObject *nextmod;
  718. //Remove any orphaned modules that were not deleted with their parent object because player had fogged memory of them.
  719. while (mod)
  720. {
  721. nextmod=mod->m_nextSystem;
  722. if (!mod->m_parentObject) //make sure it has no parent object
  723. {
  724. ThePartitionManager->unRegisterGhostObject(mod);
  725. removeGhostObject(mod);
  726. }
  727. mod=nextmod;
  728. }
  729. DEBUG_ASSERTCRASH(m_usedModules == NULL, ("Reset of Non-Empty GhostObjectManager"));
  730. //Delete any remaining modules (should be none)
  731. mod=m_usedModules;
  732. while (mod)
  733. {
  734. nextmod=mod->m_nextSystem;
  735. removeGhostObject(mod);
  736. mod=nextmod;
  737. }
  738. }
  739. // ------------------------------------------------------------------------------------------------
  740. // ------------------------------------------------------------------------------------------------
  741. void W3DGhostObjectManager::removeGhostObject(GhostObject *object)
  742. {
  743. if (!object)
  744. return;
  745. W3DGhostObject *mod = (W3DGhostObject *)object;
  746. mod->freeAllSnapShots();
  747. // remove module from used list
  748. if( mod->m_nextSystem )
  749. mod->m_nextSystem->m_prevSystem = mod->m_prevSystem;
  750. if( mod->m_prevSystem )
  751. mod->m_prevSystem->m_nextSystem = mod->m_nextSystem;
  752. else
  753. m_usedModules = mod->m_nextSystem;
  754. // add module to free list
  755. mod->m_prevSystem = NULL;
  756. mod->m_nextSystem = m_freeModules;
  757. if( m_freeModules )
  758. m_freeModules->m_prevSystem = mod;
  759. m_freeModules = mod;
  760. }
  761. // ------------------------------------------------------------------------------------------------
  762. // ------------------------------------------------------------------------------------------------
  763. GhostObject *W3DGhostObjectManager::addGhostObject(Object *object, PartitionData *pd)
  764. {
  765. // we disabled adding new ghost objects - used during map border resizing and loading
  766. if (m_lockGhostObjects || m_saveLockGhostObjects )
  767. return NULL;
  768. #ifdef DEBUG_FOG_MEMORY
  769. // sanity
  770. if( object != NULL )
  771. {
  772. W3DGhostObject *sanity = m_usedModules;
  773. while( sanity )
  774. {
  775. DEBUG_ASSERTCRASH( sanity->m_parentObject != object,
  776. ("W3DGhostObjectManager::addGhostObject - Duplicate ghost object detected\n") );
  777. sanity = sanity->m_nextSystem;
  778. } // end while
  779. } // end if
  780. #endif
  781. W3DGhostObject *mod = m_freeModules;
  782. if( mod )
  783. {
  784. // take module off the free list
  785. if( mod->m_nextSystem )
  786. mod->m_nextSystem->m_prevSystem = mod->m_prevSystem;
  787. if( mod->m_prevSystem )
  788. mod->m_prevSystem->m_nextSystem = mod->m_nextSystem;
  789. else
  790. m_freeModules = mod->m_nextSystem;
  791. }
  792. else
  793. {
  794. mod = NEW W3DGhostObject; // poolify
  795. }
  796. mod->m_prevSystem = NULL;
  797. mod->m_nextSystem = m_usedModules;
  798. if( m_usedModules )
  799. m_usedModules->m_prevSystem = mod;
  800. m_usedModules = mod;
  801. //Copy settings from parent object
  802. mod->m_parentObject=object;
  803. mod->m_drawableInfo.m_drawable=NULL; //these dummy render objects don't have drawables.
  804. mod->m_drawableInfo.m_ghostObject = mod;
  805. mod->m_partitionData=pd;
  806. return mod;
  807. }
  808. // ------------------------------------------------------------------------------------------------
  809. // ------------------------------------------------------------------------------------------------
  810. void W3DGhostObjectManager::setLocalPlayerIndex(int index)
  811. {
  812. //Whenever we switch local players, we need to remove all ghost objects belonging
  813. //to another player from the map. We then insert the current local player's
  814. //ghost objects into the map.
  815. W3DGhostObject *mod = m_usedModules;
  816. while (mod)
  817. {
  818. mod->removeFromScene(m_localPlayer);
  819. if (mod->m_parentSnapshots[index])
  820. { //new player has his own snapshot
  821. if (!mod->m_parentSnapshots[m_localPlayer] && mod->m_parentObject)
  822. { //previous player didn't have a snapshot so real object must
  823. //have been in the scene. Replace it with our snapshot.
  824. mod->removeParentObject();
  825. }
  826. mod->addToScene(index);
  827. }
  828. //new player doesn't have a snapshot which means restore original object
  829. //if it was replaced by a snapshot by the previous player.
  830. else
  831. if (mod->m_parentSnapshots[m_localPlayer] && mod->m_parentObject)
  832. mod->restoreParentObject();
  833. mod=mod->m_nextSystem;
  834. }
  835. m_localPlayer = index;
  836. }
  837. // ------------------------------------------------------------------------------------------------
  838. /** When a game object/drawable dies, it is removed from the rest of the engine. It leaves behind
  839. a GhostObject in case any players didn't see the death and have a fogged view of the pre-death object.
  840. We need to manually determine if these orphaned GhostObjects ever become visible and are no longer
  841. needed*/
  842. // ------------------------------------------------------------------------------------------------
  843. void W3DGhostObjectManager::updateOrphanedObjects(int *playerIndexList, int numNonLocalPlayers)
  844. {
  845. W3DGhostObject *mod = m_usedModules, *nextmod;
  846. int numStoredSnapshots;
  847. while (mod)
  848. {
  849. //updating the shroud status of this ghostobject could remove
  850. //it from the scene if it becomes visible but parent object is gone.
  851. nextmod=mod->m_nextSystem;
  852. if (!mod->m_parentObject)
  853. {
  854. numStoredSnapshots=0;
  855. #ifdef DEBUG_FOG_MEMORY
  856. for (int i=0; i<numNonLocalPlayers; i++, playerIndexList++)
  857. {
  858. if (mod->m_parentSnapshots[*playerIndexList])
  859. mod->getShroudStatus(*playerIndexList);
  860. if (mod->m_parentSnapshots[*playerIndexList])
  861. numStoredSnapshots++;
  862. }
  863. #endif
  864. mod->getShroudStatus(m_localPlayer);
  865. if (mod->m_parentSnapshots[m_localPlayer])
  866. numStoredSnapshots++;
  867. if (!numStoredSnapshots)
  868. { ThePartitionManager->unRegisterGhostObject(mod);
  869. mod->m_partitionData=NULL;
  870. removeGhostObject(mod);
  871. }
  872. }
  873. mod=nextmod;
  874. }
  875. }
  876. // ------------------------------------------------------------------------------------------------
  877. /*When a map border changes (via script) we reset the partition manager. Since ghost objects are
  878. stored inside the partition manager, we need to save and restore them. This function will save
  879. enough data to restore the state of the partition manager.*/
  880. // ------------------------------------------------------------------------------------------------
  881. void W3DGhostObjectManager::releasePartitionData(void)
  882. {
  883. W3DGhostObject *mod = m_usedModules;
  884. W3DGhostObject *nextmod;
  885. while (mod)
  886. {
  887. nextmod=mod->m_nextSystem;
  888. //if module has no parent object, then its holding a ghost object which
  889. //needs to have it's own partition data.
  890. if (!mod->m_parentObject)
  891. {
  892. ThePartitionManager->unRegisterGhostObject(mod);
  893. mod->m_partitionData = NULL;
  894. }
  895. else
  896. { //The parent object will handle unregistering so just tell to break the
  897. //ghost object link.
  898. mod->friend_getPartitionData()->friend_setGhostObject(NULL);
  899. mod->m_partitionData = NULL;
  900. }
  901. mod=nextmod;
  902. }
  903. }
  904. // ------------------------------------------------------------------------------------------------
  905. /*Insert ghost objects back into the partition manager*/
  906. // ------------------------------------------------------------------------------------------------
  907. void W3DGhostObjectManager::restorePartitionData(void)
  908. {
  909. W3DGhostObject *mod = m_usedModules;
  910. W3DGhostObject *nextmod;
  911. while (mod)
  912. {
  913. nextmod=mod->m_nextSystem;
  914. //if module has no parent object, then its holding a ghost object which
  915. //needs to have it's own partition data.
  916. if (mod->m_parentObject)
  917. {
  918. //restore into parent's partition data
  919. mod->m_parentObject->friend_getPartitionData()->friend_setGhostObject(mod);
  920. mod->m_partitionData=mod->m_parentObject->friend_getPartitionData();
  921. }
  922. else
  923. {
  924. //restore into our own partition data
  925. ThePartitionManager->registerGhostObject(mod);
  926. }
  927. //set partition data to reflect that we've seen a fogged version
  928. //of this object if one exists.
  929. for (Int i=0; i<MAX_PLAYER_COUNT; i++)
  930. { if (mod->m_parentSnapshots[i])
  931. mod->m_partitionData->friend_setShroudednessPrevious(i,OBJECTSHROUD_FOGGED);
  932. }
  933. mod=nextmod;
  934. }
  935. }
  936. // ------------------------------------------------------------------------------------------------
  937. /** CRC */
  938. // ------------------------------------------------------------------------------------------------
  939. void W3DGhostObjectManager::crc( Xfer *xfer )
  940. {
  941. // extend base class
  942. GhostObjectManager::crc( xfer );
  943. } // end crc
  944. // ------------------------------------------------------------------------------------------------
  945. /** Xfer Method
  946. * Version Info:
  947. * 1: Initial version */
  948. // ------------------------------------------------------------------------------------------------
  949. void W3DGhostObjectManager::xfer( Xfer *xfer )
  950. {
  951. // version
  952. XferVersion currentVersion = 1;
  953. XferVersion version = currentVersion;
  954. xfer->xferVersion( &version, currentVersion );
  955. // extend base class
  956. GhostObjectManager::xfer( xfer );
  957. // count the number of used modules we have
  958. UnsignedShort count = 0;
  959. W3DGhostObject *w3dGhostObject;
  960. for( w3dGhostObject = m_usedModules; w3dGhostObject; w3dGhostObject = w3dGhostObject->m_nextSystem )
  961. count++;
  962. // xfer count
  963. xfer->xferUnsignedShort( &count );
  964. // ghost object themselves
  965. ObjectID objectID;
  966. if( xfer->getXferMode() == XFER_SAVE )
  967. {
  968. // iterate all ghost objects
  969. for( w3dGhostObject = m_usedModules; w3dGhostObject; w3dGhostObject = w3dGhostObject->m_nextSystem )
  970. {
  971. // write out object ID
  972. if( w3dGhostObject->m_parentObject )
  973. objectID = w3dGhostObject->m_parentObject->getID();
  974. else
  975. objectID = INVALID_ID;
  976. xfer->xferObjectID( &objectID );
  977. // write out ghost object data
  978. xfer->xferSnapshot( w3dGhostObject );
  979. } // end for, ghostObject
  980. } // end if, saving
  981. else
  982. {
  983. // sanity, there should be no ghost objects loaded at this time
  984. DEBUG_ASSERTCRASH( m_usedModules == NULL,
  985. ("W3DGhostObjectManager::xfer - The used module list is not NULL upon load, but should be!\n") );
  986. // now it's time to unlock the ghost objects for loading
  987. DEBUG_ASSERTCRASH( m_saveLockGhostObjects == TRUE,
  988. ("W3DGhostObjectManager::xfer - Ghost object manager is not save locked, but should be\n") );
  989. TheGhostObjectManager->saveLockGhostObjects( FALSE );
  990. // read all ghost objects
  991. GhostObject *ghostObject;
  992. Object *object;
  993. for( UnsignedShort i = 0; i < count; ++i )
  994. {
  995. // read object id
  996. xfer->xferObjectID( &objectID );
  997. // get object from id
  998. object = TheGameLogic->findObjectByID( objectID );
  999. // create ghost object data
  1000. if( object )
  1001. {
  1002. // create ghost object
  1003. ghostObject = addGhostObject( object, object->friend_getPartitionData() );
  1004. // sanity
  1005. DEBUG_ASSERTCRASH( ghostObject != NULL,
  1006. ("W3DGhostObjectManager::xfer - Could not create ghost object for object '%s'\n",
  1007. object->getTemplate()->getName().str()) );
  1008. // link the ghost object and logical object togehter through partition/ghostObject dat
  1009. DEBUG_ASSERTCRASH( object->friend_getPartitionData()->getGhostObject() == NULL,
  1010. ("W3DGhostObjectManager::xfer - Ghost object already on object '%s'\n",
  1011. object->getTemplate()->getName().str()) );
  1012. object->friend_getPartitionData()->friend_setGhostObject( ghostObject );
  1013. } // end if
  1014. else
  1015. {
  1016. // create object with no object or partition data
  1017. ghostObject = addGhostObject( NULL, NULL );
  1018. // register ghost object object with partition system and fill out partition data
  1019. ThePartitionManager->registerGhostObject( ghostObject );
  1020. } // end else
  1021. // read ghost object data
  1022. xfer->xferSnapshot( ghostObject );
  1023. } // end for, i
  1024. } // end else, loading
  1025. } // end xfer
  1026. // ------------------------------------------------------------------------------------------------
  1027. /** Load post process */
  1028. // ------------------------------------------------------------------------------------------------
  1029. void W3DGhostObjectManager::loadPostProcess( void )
  1030. {
  1031. // extend base class
  1032. GhostObjectManager::loadPostProcess();
  1033. } // end loadPostProcess