W3DGhostObject.cpp 39 KB

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