fxShapeReplicator.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "T3D/fx/fxShapeReplicator.h"
  24. #include "gfx/gfxDevice.h"
  25. #include "gfx/primBuilder.h"
  26. #include "console/consoleTypes.h"
  27. #include "core/stream/bitStream.h"
  28. #include "math/mRandom.h"
  29. #include "math/mathIO.h"
  30. #include "T3D/gameBase/gameConnection.h"
  31. #include "scene/sceneManager.h"
  32. #include "scene/sceneRenderState.h"
  33. #include "renderInstance/renderPassManager.h"
  34. #include "console/engineAPI.h"
  35. //------------------------------------------------------------------------------
  36. //
  37. // Put this in /example/common/editor/editor.cs in function [Editor::create()] (around line 66).
  38. //
  39. // // Ignore Replicated fxStatic Instances.
  40. // EWorldEditor.ignoreObjClass("fxShapeReplicatedStatic");
  41. //
  42. //------------------------------------------------------------------------------
  43. //
  44. // Put this in /example/common/editor/EditorGui.cs in [function Creator::init( %this )]
  45. //
  46. // %Environment_Item[8] = "fxShapeReplicator"; <-- ADD THIS.
  47. //
  48. //------------------------------------------------------------------------------
  49. //
  50. // Put the function in /example/common/editor/ObjectBuilderGui.gui [around line 458] ...
  51. //
  52. // function ObjectBuilderGui::buildfxShapeReplicator(%this)
  53. // {
  54. // %this.className = "fxShapeReplicator";
  55. // %this.process();
  56. // }
  57. //
  58. //------------------------------------------------------------------------------
  59. //
  60. // Put this in /example/common/client/missionDownload.cs in [function clientCmdMissionStartPhase3(%seq,%missionName)] (line 65)
  61. // after codeline 'onPhase2Complete();'.
  62. //
  63. // StartClientReplication();
  64. //
  65. //------------------------------------------------------------------------------
  66. //
  67. // Put this in /engine/console/simBase.h (around line 509) in
  68. //
  69. // namespace Sim
  70. // {
  71. // DeclareNamedSet(fxReplicatorSet) <-- ADD THIS (Note no semi-colon).
  72. //
  73. //------------------------------------------------------------------------------
  74. //
  75. // Put this in /engine/console/simBase.cc (around line 19) in
  76. //
  77. // ImplementNamedSet(fxReplicatorSet) <-- ADD THIS
  78. //
  79. //------------------------------------------------------------------------------
  80. //
  81. // Put this in /engine/console/simManager.cc [function void init()] (around line 269).
  82. //
  83. // namespace Sim
  84. // {
  85. // InstantiateNamedSet(fxReplicatorSet); <-- ADD THIS
  86. //
  87. //------------------------------------------------------------------------------
  88. extern bool gEditingMission;
  89. //------------------------------------------------------------------------------
  90. IMPLEMENT_CO_NETOBJECT_V1(fxShapeReplicator);
  91. IMPLEMENT_CO_NETOBJECT_V1(fxShapeReplicatedStatic);
  92. ConsoleDocClass( fxShapeReplicator,
  93. "@brief An emitter for objects to replicate across an area.\n"
  94. "@ingroup Foliage\n"
  95. );
  96. ConsoleDocClass( fxShapeReplicatedStatic,
  97. "@brief The object definition for shapes that will be replicated across an area using an fxShapeReplicator.\n"
  98. "@ingroup Foliage\n"
  99. );
  100. //------------------------------------------------------------------------------
  101. // Class: fxShapeReplicator
  102. //------------------------------------------------------------------------------
  103. fxShapeReplicator::fxShapeReplicator()
  104. {
  105. // Setup NetObject.
  106. mTypeMask |= StaticObjectType;
  107. mNetFlags.set(Ghostable | ScopeAlways);
  108. // Reset Shape Count.
  109. mCurrentShapeCount = 0;
  110. // Reset Creation Area Angle Animation.
  111. mCreationAreaAngle = 0;
  112. // Reset Last Render Time.
  113. mLastRenderTime = 0;
  114. mPlacementSB = NULL;
  115. }
  116. //------------------------------------------------------------------------------
  117. fxShapeReplicator::~fxShapeReplicator()
  118. {
  119. mPlacementSB = NULL;
  120. }
  121. //------------------------------------------------------------------------------
  122. void fxShapeReplicator::initPersistFields()
  123. {
  124. // Add out own persistent fields.
  125. addGroup( "Debugging" ); // MM: Added Group Header.
  126. addField( "HideReplications", TypeBool, Offset( mFieldData.mHideReplications, fxShapeReplicator ), "Replicated shapes are hidden when set to true." );
  127. addField( "ShowPlacementArea", TypeBool, Offset( mFieldData.mShowPlacementArea, fxShapeReplicator ), "Draw placement rings when set to true." );
  128. addField( "PlacementAreaHeight", TypeS32, Offset( mFieldData.mPlacementBandHeight, fxShapeReplicator ), "Height of the placement ring in world units." );
  129. addField( "PlacementColour", TypeColorF, Offset( mFieldData.mPlaceAreaColour, fxShapeReplicator ), "Color of the placement ring." );
  130. endGroup( "Debugging" ); // MM: Added Group Footer.
  131. addGroup( "Media" ); // MM: Added Group Header.
  132. addField( "ShapeFile", TypeShapeFilename, Offset( mFieldData.mShapeFile, fxShapeReplicator ), "Filename of shape to replicate." );
  133. endGroup( "Media" ); // MM: Added Group Footer.
  134. addGroup( "Replications" ); // MM: Added Group Header.
  135. addField( "Seed", TypeS32, Offset( mFieldData.mSeed, fxShapeReplicator ), "Random seed for shape placement." );
  136. addField( "ShapeCount", TypeS32, Offset( mFieldData.mShapeCount, fxShapeReplicator ), "Maximum shape instance count." );
  137. addField( "ShapeRetries", TypeS32, Offset( mFieldData.mShapeRetries, fxShapeReplicator ), "Number of times to try placing a shape instance before giving up." );
  138. endGroup( "Replications" ); // MM: Added Group Footer.
  139. addGroup( "Placement Radius" ); // MM: Added Group Header.
  140. addField( "InnerRadiusX", TypeS32, Offset( mFieldData.mInnerRadiusX, fxShapeReplicator ), "Placement area inner radius on the X axis" );
  141. addField( "InnerRadiusY", TypeS32, Offset( mFieldData.mInnerRadiusY, fxShapeReplicator ), "Placement area inner radius on the Y axis" );
  142. addField( "OuterRadiusX", TypeS32, Offset( mFieldData.mOuterRadiusX, fxShapeReplicator ), "Placement area outer radius on the X axis" );
  143. addField( "OuterRadiusY", TypeS32, Offset( mFieldData.mOuterRadiusY, fxShapeReplicator ), "Placement area outer radius on the Y axis" );
  144. endGroup( "Placement Radius" ); // MM: Added Group Footer.
  145. addGroup( "Restraints" ); // MM: Added Group Header.
  146. addField( "AllowOnTerrain", TypeBool, Offset( mFieldData.mAllowOnTerrain, fxShapeReplicator ), "Shapes will be placed on terrain when set." );
  147. addField( "AllowOnInteriors", TypeBool, Offset( mFieldData.mAllowOnInteriors, fxShapeReplicator ), "Shapes will be placed on InteriorInstances when set." );
  148. addField( "AllowOnStatics", TypeBool, Offset( mFieldData.mAllowStatics, fxShapeReplicator ), "Shapes will be placed on Static shapes when set." );
  149. addField( "AllowOnWater", TypeBool, Offset( mFieldData.mAllowOnWater, fxShapeReplicator ), "Shapes will be placed on/under water when set." );
  150. addField( "AllowWaterSurface", TypeBool, Offset( mFieldData.mAllowWaterSurface, fxShapeReplicator ), "Shapes will be placed on water when set. Requires AllowOnWater." );
  151. addField( "AlignToTerrain", TypeBool, Offset( mFieldData.mAlignToTerrain, fxShapeReplicator ), "Align shapes to surface normal when set." );
  152. addField( "Interactions", TypeBool, Offset( mFieldData.mInteractions, fxShapeReplicator ), "Allow physics interactions with shapes." );
  153. addField( "AllowedTerrainSlope", TypeS32, Offset( mFieldData.mAllowedTerrainSlope, fxShapeReplicator ), "Maximum surface angle allowed for shape instances." );
  154. addField( "TerrainAlignment", TypePoint3F, Offset( mFieldData.mTerrainAlignment, fxShapeReplicator ), "Surface normals will be multiplied by these values when AlignToTerrain is enabled." );
  155. endGroup( "Restraints" ); // MM: Added Group Footer.
  156. addGroup( "Object Transforms" ); // MM: Added Group Header.
  157. addField( "ShapeScaleMin", TypePoint3F, Offset( mFieldData.mShapeScaleMin, fxShapeReplicator ), "Minimum shape scale." );
  158. addField( "ShapeScaleMax", TypePoint3F, Offset( mFieldData.mShapeScaleMax, fxShapeReplicator ), "Maximum shape scale." );
  159. addField( "ShapeRotateMin", TypePoint3F, Offset( mFieldData.mShapeRotateMin, fxShapeReplicator ), "Minimum shape rotation angles.");
  160. addField( "ShapeRotateMax", TypePoint3F, Offset( mFieldData.mShapeRotateMax, fxShapeReplicator ), "Maximum shape rotation angles." );
  161. addField( "OffsetZ", TypeS32, Offset( mFieldData.mOffsetZ, fxShapeReplicator ), "Offset shapes by this amount vertically." );
  162. endGroup( "Object Transforms" ); // MM: Added Group Footer.
  163. // Initialise parents' persistent fields.
  164. Parent::initPersistFields();
  165. }
  166. //------------------------------------------------------------------------------
  167. void fxShapeReplicator::CreateShapes(void)
  168. {
  169. F32 HypX, HypY;
  170. F32 Angle;
  171. U32 RelocationRetry;
  172. Point3F ShapePosition;
  173. Point3F ShapeStart;
  174. Point3F ShapeEnd;
  175. Point3F ShapeScale;
  176. EulerF ShapeRotation;
  177. QuatF QRotation;
  178. bool CollisionResult;
  179. RayInfo RayEvent;
  180. TSShape* pShape;
  181. // Don't create shapes if we are hiding replications.
  182. if (mFieldData.mHideReplications) return;
  183. // Cannot continue without shapes!
  184. if (dStrcmp(mFieldData.mShapeFile, "") == 0) return;
  185. // Check that we can position somewhere!
  186. if (!( mFieldData.mAllowOnTerrain ||
  187. mFieldData.mAllowOnInteriors ||
  188. mFieldData.mAllowStatics ||
  189. mFieldData.mAllowOnWater))
  190. {
  191. // Problem ...
  192. Con::warnf(ConsoleLogEntry::General, "[%s] - Could not place object, All alloweds are off!", getName());
  193. // Return here.
  194. return;
  195. }
  196. // Check Shapes.
  197. AssertFatal(mCurrentShapeCount==0,"Shapes already present, this should not be possible!")
  198. // Check that we have a shape...
  199. if (!mFieldData.mShapeFile) return;
  200. // Set Seed.
  201. RandomGen.setSeed(mFieldData.mSeed);
  202. // Set shape vector.
  203. mReplicatedShapes.clear();
  204. // Add shapes.
  205. for (U32 idx = 0; idx < mFieldData.mShapeCount; idx++)
  206. {
  207. fxShapeReplicatedStatic* fxStatic;
  208. // Create our static shape.
  209. fxStatic = new fxShapeReplicatedStatic();
  210. // Set the 'shapeName' field.
  211. fxStatic->setField("shapeName", mFieldData.mShapeFile);
  212. // Is this Replicator on the Server?
  213. if (isServerObject())
  214. // Yes, so stop it from Ghosting. (Hack, Hack, Hack!)
  215. fxStatic->touchNetFlags(Ghostable, false);
  216. else
  217. // No, so flag as ghost object. (Another damn Hack!)
  218. fxStatic->touchNetFlags(IsGhost, true);
  219. // Register the Object.
  220. if (!fxStatic->registerObject())
  221. {
  222. // Problem ...
  223. Con::warnf(ConsoleLogEntry::General, "[%s] - Could not load shape file '%s'!", getName(), mFieldData.mShapeFile);
  224. // Destroy Shape.
  225. delete fxStatic;
  226. // Destroy existing hapes.
  227. DestroyShapes();
  228. // Quit.
  229. return;
  230. }
  231. // Get Allocated Shape.
  232. pShape = fxStatic->getShape();
  233. // Reset Relocation Retry.
  234. RelocationRetry = mFieldData.mShapeRetries;
  235. // Find it a home ...
  236. do
  237. {
  238. // Get the Replicator Position.
  239. ShapePosition = getPosition();
  240. // Calculate a random offset
  241. HypX = RandomGen.randF(mFieldData.mInnerRadiusX, mFieldData.mOuterRadiusX);
  242. HypY = RandomGen.randF(mFieldData.mInnerRadiusY, mFieldData.mOuterRadiusY);
  243. Angle = RandomGen.randF(0, (F32)M_2PI);
  244. // Calcualte the new position.
  245. ShapePosition.x += HypX * mCos(Angle);
  246. ShapePosition.y += HypY * mSin(Angle);
  247. // Initialise RayCast Search Start/End Positions.
  248. ShapeStart = ShapeEnd = ShapePosition;
  249. ShapeStart.z = 2000.f;
  250. ShapeEnd.z= -2000.f;
  251. // Is this the Server?
  252. if (isServerObject())
  253. // Perform Ray Cast Collision on Server Terrain.
  254. CollisionResult = gServerContainer.castRay(ShapeStart, ShapeEnd, FXREPLICATOR_COLLISION_MASK, &RayEvent);
  255. else
  256. // Perform Ray Cast Collision on Client Terrain.
  257. CollisionResult = gClientContainer.castRay( ShapeStart, ShapeEnd, FXREPLICATOR_COLLISION_MASK, &RayEvent);
  258. // Did we hit anything?
  259. if (CollisionResult)
  260. {
  261. // For now, let's pretend we didn't get a collision.
  262. CollisionResult = false;
  263. // Yes, so get it's type.
  264. U32 CollisionType = RayEvent.object->getTypeMask();
  265. // Check Illegal Placements.
  266. if (((CollisionType & TerrainObjectType) && !mFieldData.mAllowOnTerrain) ||
  267. ((CollisionType & InteriorObjectType) && !mFieldData.mAllowOnInteriors) ||
  268. ((CollisionType & StaticShapeObjectType) && !mFieldData.mAllowStatics) ||
  269. ((CollisionType & WaterObjectType) && !mFieldData.mAllowOnWater) ) continue;
  270. // If we collided with water and are not allowing on the water surface then let's find the
  271. // terrain underneath and pass this on as the original collision else fail.
  272. //
  273. // NOTE:- We need to do this on the server/client as appropriate.
  274. if ((CollisionType & WaterObjectType) && !mFieldData.mAllowWaterSurface)
  275. {
  276. // Is this the Server?
  277. if (isServerObject())
  278. {
  279. // Yes, so do it on the server container.
  280. if (!gServerContainer.castRay( ShapeStart, ShapeEnd, FXREPLICATOR_NOWATER_COLLISION_MASK, &RayEvent)) continue;
  281. }
  282. else
  283. {
  284. // No, so do it on the client container.
  285. if (!gClientContainer.castRay( ShapeStart, ShapeEnd, FXREPLICATOR_NOWATER_COLLISION_MASK, &RayEvent)) continue;
  286. }
  287. }
  288. // We passed with flying colours so carry on.
  289. CollisionResult = true;
  290. }
  291. // Invalidate if we are below Allowed Terrain Angle.
  292. if (RayEvent.normal.z < mSin(mDegToRad(90.0f-mFieldData.mAllowedTerrainSlope))) CollisionResult = false;
  293. // Wait until we get a collision.
  294. } while(!CollisionResult && --RelocationRetry);
  295. // Check for Relocation Problem.
  296. if (RelocationRetry > 0)
  297. {
  298. // Adjust Impact point.
  299. RayEvent.point.z += mFieldData.mOffsetZ;
  300. // Set New Position.
  301. ShapePosition = RayEvent.point;
  302. }
  303. else
  304. {
  305. // Warning.
  306. Con::warnf(ConsoleLogEntry::General, "[%s] - Could not find satisfactory position for shape '%s' on %s!", getName(), mFieldData.mShapeFile,isServerObject()?"Server":"Client");
  307. // Unregister Object.
  308. fxStatic->unregisterObject();
  309. // Destroy Shape.
  310. delete fxStatic;
  311. // Skip to next.
  312. continue;
  313. }
  314. // Get Shape Transform.
  315. MatrixF XForm = fxStatic->getTransform();
  316. // Are we aligning to Terrain?
  317. if (mFieldData.mAlignToTerrain)
  318. {
  319. // Yes, so set rotation to Terrain Impact Normal.
  320. ShapeRotation = RayEvent.normal * mFieldData.mTerrainAlignment;
  321. }
  322. else
  323. {
  324. // No, so choose a new Rotation (in Radians).
  325. ShapeRotation.set( mDegToRad(RandomGen.randF(mFieldData.mShapeRotateMin.x, mFieldData.mShapeRotateMax.x)),
  326. mDegToRad(RandomGen.randF(mFieldData.mShapeRotateMin.y, mFieldData.mShapeRotateMax.y)),
  327. mDegToRad(RandomGen.randF(mFieldData.mShapeRotateMin.z, mFieldData.mShapeRotateMax.z)));
  328. }
  329. // Set Quaternion Roation.
  330. QRotation.set(ShapeRotation);
  331. // Set Transform Rotation.
  332. QRotation.setMatrix(&XForm);
  333. // Set Position.
  334. XForm.setColumn(3, ShapePosition);
  335. // Set Shape Position / Rotation.
  336. fxStatic->setTransform(XForm);
  337. // Choose a new Scale.
  338. ShapeScale.set( RandomGen.randF(mFieldData.mShapeScaleMin.x, mFieldData.mShapeScaleMax.x),
  339. RandomGen.randF(mFieldData.mShapeScaleMin.y, mFieldData.mShapeScaleMax.y),
  340. RandomGen.randF(mFieldData.mShapeScaleMin.z, mFieldData.mShapeScaleMax.z));
  341. // Set Shape Scale.
  342. fxStatic->setScale(ShapeScale);
  343. // Lock it.
  344. fxStatic->setLocked(true);
  345. // Store Shape in Replicated Shapes Vector.
  346. //mReplicatedShapes[mCurrentShapeCount++] = fxStatic;
  347. mReplicatedShapes.push_back(fxStatic);
  348. }
  349. mCurrentShapeCount = mReplicatedShapes.size();
  350. // Take first Timestamp.
  351. mLastRenderTime = Platform::getVirtualMilliseconds();
  352. }
  353. //------------------------------------------------------------------------------
  354. void fxShapeReplicator::DestroyShapes(void)
  355. {
  356. // Finish if we didn't create any shapes.
  357. if (mCurrentShapeCount == 0) return;
  358. // Remove shapes.
  359. for (U32 idx = 0; idx < mCurrentShapeCount; idx++)
  360. {
  361. fxShapeReplicatedStatic* fxStatic;
  362. // Fetch the Shape Object.
  363. fxStatic = mReplicatedShapes[idx];
  364. // Got a Shape?
  365. if (fxStatic)
  366. {
  367. // Unlock it.
  368. fxStatic->setLocked(false);
  369. // Unregister the object.
  370. fxStatic->unregisterObject();
  371. // Delete it.
  372. delete fxStatic;
  373. }
  374. }
  375. // Empty the Replicated Shapes Vector.
  376. mReplicatedShapes.clear();
  377. // Reset Shape Count.
  378. mCurrentShapeCount = 0;
  379. }
  380. //------------------------------------------------------------------------------
  381. void fxShapeReplicator::RenewShapes(void)
  382. {
  383. // Destroy any shapes.
  384. DestroyShapes();
  385. // Don't create shapes on the Server if we don't need interactions.
  386. if (isServerObject() && !mFieldData.mInteractions) return;
  387. // Create Shapes.
  388. CreateShapes();
  389. }
  390. //------------------------------------------------------------------------------
  391. void fxShapeReplicator::StartUp(void)
  392. {
  393. RenewShapes();
  394. }
  395. //------------------------------------------------------------------------------
  396. bool fxShapeReplicator::onAdd()
  397. {
  398. if(!Parent::onAdd())
  399. return(false);
  400. // Add the Replicator to the Replicator Set.
  401. dynamic_cast<SimSet*>(Sim::findObject("fxReplicatorSet"))->addObject(this);
  402. // Set Default Object Box.
  403. mObjBox.minExtents.set( -0.5, -0.5, -0.5 );
  404. mObjBox.maxExtents.set( 0.5, 0.5, 0.5 );
  405. resetWorldBox();
  406. // Add to Scene.
  407. setRenderTransform(mObjToWorld);
  408. addToScene();
  409. // Register for notification when GhostAlways objects are done loading
  410. NetConnection::smGhostAlwaysDone.notify( this, &fxShapeReplicator::onGhostAlwaysDone );
  411. return true;
  412. }
  413. //------------------------------------------------------------------------------
  414. void fxShapeReplicator::onRemove()
  415. {
  416. // Remove the Replicator from the Replicator Set.
  417. dynamic_cast<SimSet*>(Sim::findObject("fxReplicatorSet"))->removeObject(this);
  418. NetConnection::smGhostAlwaysDone.remove( this, &fxShapeReplicator::onGhostAlwaysDone );
  419. removeFromScene();
  420. // Destroy Shapes.
  421. DestroyShapes();
  422. // Do Parent.
  423. Parent::onRemove();
  424. }
  425. //------------------------------------------------------------------------------
  426. void fxShapeReplicator::onGhostAlwaysDone()
  427. {
  428. RenewShapes();
  429. }
  430. //------------------------------------------------------------------------------
  431. void fxShapeReplicator::inspectPostApply()
  432. {
  433. // Set Parent.
  434. Parent::inspectPostApply();
  435. // Renew Shapes.
  436. RenewShapes();
  437. // Set Replication Mask.
  438. setMaskBits(ReplicationMask);
  439. }
  440. //------------------------------------------------------------------------------
  441. DefineEngineFunction(StartClientReplication, void, (),, "Activates the shape replicator.\n"
  442. "@tsexample\n"
  443. "// Call the function\n"
  444. "StartClientReplication()\n"
  445. "@endtsexample\n"
  446. "@ingroup Foliage"
  447. )
  448. {
  449. // Find the Replicator Set.
  450. SimSet *fxReplicatorSet = dynamic_cast<SimSet*>(Sim::findObject("fxReplicatorSet"));
  451. // Return if Error.
  452. if (!fxReplicatorSet) return;
  453. // StartUp Replication Object.
  454. for (SimSetIterator itr(fxReplicatorSet); *itr; ++itr)
  455. {
  456. // Fetch the Replicator Object.
  457. fxShapeReplicator* Replicator = static_cast<fxShapeReplicator*>(*itr);
  458. // Start Client Objects Only.
  459. if (Replicator->isClientObject()) Replicator->StartUp();
  460. }
  461. // Info ...
  462. Con::printf("Client Replication Startup has Happened!");
  463. }
  464. //------------------------------------------------------------------------------
  465. void fxShapeReplicator::prepRenderImage( SceneRenderState* state )
  466. {
  467. ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
  468. ri->renderDelegate.bind(this, &fxShapeReplicator::renderObject);
  469. // The fxShapeReplicator isn't technically foliage but our debug
  470. // effect seems to render best as a Foliage type (translucent,
  471. // renders itself, no sorting)
  472. ri->type = RenderPassManager::RIT_Foliage;
  473. state->getRenderPass()->addInst( ri );
  474. }
  475. //------------------------------------------------------------------------------
  476. // Renders a triangle stripped oval
  477. void fxShapeReplicator::renderArc(const F32 fRadiusX, const F32 fRadiusY)
  478. {
  479. PrimBuild::begin(GFXTriangleStrip, 720);
  480. for (U32 Angle = mCreationAreaAngle; Angle < (mCreationAreaAngle+360); Angle++)
  481. {
  482. F32 XPos, YPos;
  483. // Calculate Position.
  484. XPos = fRadiusX * mCos(mDegToRad(-(F32)Angle));
  485. YPos = fRadiusY * mSin(mDegToRad(-(F32)Angle));
  486. // Set Colour.
  487. PrimBuild::color4f(mFieldData.mPlaceAreaColour.red,
  488. mFieldData.mPlaceAreaColour.green,
  489. mFieldData.mPlaceAreaColour.blue,
  490. AREA_ANIMATION_ARC * (Angle-mCreationAreaAngle));
  491. PrimBuild::vertex3f(XPos, YPos, -(F32)mFieldData.mPlacementBandHeight/2.0f);
  492. PrimBuild::vertex3f(XPos, YPos, +(F32)mFieldData.mPlacementBandHeight/2.0f);
  493. }
  494. PrimBuild::end();
  495. }
  496. // This currently uses the primbuilder, could convert out, but why allocate the buffer if we
  497. // never edit the misison?
  498. void fxShapeReplicator::renderPlacementArea(const F32 ElapsedTime)
  499. {
  500. if (gEditingMission && mFieldData.mShowPlacementArea)
  501. {
  502. GFX->pushWorldMatrix();
  503. GFX->multWorld(getTransform());
  504. if (!mPlacementSB)
  505. {
  506. GFXStateBlockDesc transparent;
  507. transparent.setCullMode(GFXCullNone);
  508. transparent.alphaTestEnable = true;
  509. transparent.setZReadWrite(true);
  510. transparent.zWriteEnable = false;
  511. transparent.setBlend(true, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha);
  512. mPlacementSB = GFX->createStateBlock( transparent );
  513. }
  514. GFX->setStateBlock(mPlacementSB);
  515. // Do we need to draw the Outer Radius?
  516. if (mFieldData.mOuterRadiusX || mFieldData.mOuterRadiusY)
  517. renderArc((F32) mFieldData.mOuterRadiusX, (F32) mFieldData.mOuterRadiusY);
  518. // Inner radius?
  519. if (mFieldData.mInnerRadiusX || mFieldData.mInnerRadiusY)
  520. renderArc((F32) mFieldData.mInnerRadiusX, (F32) mFieldData.mInnerRadiusY);
  521. GFX->popWorldMatrix();
  522. mCreationAreaAngle = (U32)(mCreationAreaAngle + (1000 * ElapsedTime));
  523. mCreationAreaAngle = mCreationAreaAngle % 360;
  524. }
  525. }
  526. //------------------------------------------------------------------------------
  527. void fxShapeReplicator::renderObject(ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance* overrideMat)
  528. {
  529. if (overrideMat)
  530. return;
  531. // Return if placement area not needed.
  532. if (!mFieldData.mShowPlacementArea)
  533. return;
  534. // Calculate Elapsed Time and take new Timestamp.
  535. S32 Time = Platform::getVirtualMilliseconds();
  536. F32 ElapsedTime = (Time - mLastRenderTime) * 0.001f;
  537. mLastRenderTime = Time;
  538. renderPlacementArea(ElapsedTime);
  539. }
  540. //------------------------------------------------------------------------------
  541. U32 fxShapeReplicator::packUpdate(NetConnection * con, U32 mask, BitStream * stream)
  542. {
  543. // Pack Parent.
  544. U32 retMask = Parent::packUpdate(con, mask, stream);
  545. // Write Replication Flag.
  546. if (stream->writeFlag(mask & ReplicationMask))
  547. {
  548. stream->writeAffineTransform(mObjToWorld); // Replicator Position.
  549. stream->writeInt(mFieldData.mSeed, 32); // Replicator Seed.
  550. stream->writeInt(mFieldData.mShapeCount, 32); // Shapes Count.
  551. stream->writeInt(mFieldData.mShapeRetries, 32); // Shapes Retries.
  552. stream->writeString(mFieldData.mShapeFile);
  553. stream->writeInt(mFieldData.mInnerRadiusX, 32); // Shapes Inner Radius X.
  554. stream->writeInt(mFieldData.mInnerRadiusY, 32); // Shapes Inner Radius Y.
  555. stream->writeInt(mFieldData.mOuterRadiusX, 32); // Shapes Outer Radius X.
  556. stream->writeInt(mFieldData.mOuterRadiusY, 32); // Shapes Outer Radius Y.
  557. mathWrite(*stream, mFieldData.mShapeScaleMin); // Shapes Scale Min.
  558. mathWrite(*stream, mFieldData.mShapeScaleMax); // Shapes Scale Max.
  559. mathWrite(*stream, mFieldData.mShapeRotateMin); // Shapes Rotate Min.
  560. mathWrite(*stream, mFieldData.mShapeRotateMax); // Shapes Rotate Max.
  561. stream->writeSignedInt(mFieldData.mOffsetZ, 32); // Shapes Offset Z.
  562. stream->writeFlag(mFieldData.mAllowOnTerrain); // Allow on Terrain.
  563. stream->writeFlag(mFieldData.mAllowOnInteriors); // Allow on Interiors.
  564. stream->writeFlag(mFieldData.mAllowStatics); // Allow on Statics.
  565. stream->writeFlag(mFieldData.mAllowOnWater); // Allow on Water.
  566. stream->writeFlag(mFieldData.mAllowWaterSurface); // Allow on Water Surface.
  567. stream->writeSignedInt(mFieldData.mAllowedTerrainSlope, 32); // Shapes Offset Z.
  568. stream->writeFlag(mFieldData.mAlignToTerrain); // Shapes AlignToTerrain.
  569. mathWrite(*stream, mFieldData.mTerrainAlignment); // Write Terrain Alignment.
  570. stream->writeFlag(mFieldData.mHideReplications); // Hide Replications.
  571. stream->writeFlag(mFieldData.mInteractions); // Shape Interactions.
  572. stream->writeFlag(mFieldData.mShowPlacementArea); // Show Placement Area Flag.
  573. stream->writeInt(mFieldData.mPlacementBandHeight, 32); // Placement Area Height.
  574. stream->write(mFieldData.mPlaceAreaColour);
  575. }
  576. // Were done ...
  577. return(retMask);
  578. }
  579. //------------------------------------------------------------------------------
  580. void fxShapeReplicator::unpackUpdate(NetConnection * con, BitStream * stream)
  581. {
  582. // Unpack Parent.
  583. Parent::unpackUpdate(con, stream);
  584. // Read Replication Details.
  585. if(stream->readFlag())
  586. {
  587. MatrixF ReplicatorObjectMatrix;
  588. stream->readAffineTransform(&ReplicatorObjectMatrix); // Replication Position.
  589. mFieldData.mSeed = stream->readInt(32); // Replicator Seed.
  590. mFieldData.mShapeCount = stream->readInt(32); // Shapes Count.
  591. mFieldData.mShapeRetries = stream->readInt(32); // Shapes Retries.
  592. mFieldData.mShapeFile = stream->readSTString(); // Shape File.
  593. mFieldData.mInnerRadiusX = stream->readInt(32); // Shapes Inner Radius X.
  594. mFieldData.mInnerRadiusY = stream->readInt(32); // Shapes Inner Radius Y.
  595. mFieldData.mOuterRadiusX = stream->readInt(32); // Shapes Outer Radius X.
  596. mFieldData.mOuterRadiusY = stream->readInt(32); // Shapes Outer Radius Y.
  597. mathRead(*stream, &mFieldData.mShapeScaleMin); // Shapes Scale Min.
  598. mathRead(*stream, &mFieldData.mShapeScaleMax); // Shapes Scale Max.
  599. mathRead(*stream, &mFieldData.mShapeRotateMin); // Shapes Rotate Min.
  600. mathRead(*stream, &mFieldData.mShapeRotateMax); // Shapes Rotate Max.
  601. mFieldData.mOffsetZ = stream->readSignedInt(32); // Shapes Offset Z.
  602. mFieldData.mAllowOnTerrain = stream->readFlag(); // Allow on Terrain.
  603. mFieldData.mAllowOnInteriors = stream->readFlag(); // Allow on Interiors.
  604. mFieldData.mAllowStatics = stream->readFlag(); // Allow on Statics.
  605. mFieldData.mAllowOnWater = stream->readFlag(); // Allow on Water.
  606. mFieldData.mAllowWaterSurface = stream->readFlag(); // Allow on Water Surface.
  607. mFieldData.mAllowedTerrainSlope = stream->readSignedInt(32); // Allowed Terrain Slope.
  608. mFieldData.mAlignToTerrain = stream->readFlag(); // Read AlignToTerrain.
  609. mathRead(*stream, &mFieldData.mTerrainAlignment); // Read Terrain Alignment.
  610. mFieldData.mHideReplications = stream->readFlag(); // Hide Replications.
  611. mFieldData.mInteractions = stream->readFlag(); // Read Interactions.
  612. mFieldData.mShowPlacementArea = stream->readFlag(); // Show Placement Area Flag.
  613. mFieldData.mPlacementBandHeight = stream->readInt(32); // Placement Area Height.
  614. stream->read(&mFieldData.mPlaceAreaColour);
  615. // Set Transform.
  616. setTransform(ReplicatorObjectMatrix);
  617. RenewShapes();
  618. }
  619. }