fxShapeReplicator.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759
  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( "AllowOnStatics", TypeBool, Offset( mFieldData.mAllowStatics, fxShapeReplicator ), "Shapes will be placed on Static shapes when set." );
  148. addField( "AllowOnWater", TypeBool, Offset( mFieldData.mAllowOnWater, fxShapeReplicator ), "Shapes will be placed on/under water when set." );
  149. addField( "AllowWaterSurface", TypeBool, Offset( mFieldData.mAllowWaterSurface, fxShapeReplicator ), "Shapes will be placed on water when set. Requires AllowOnWater." );
  150. addField( "AlignToTerrain", TypeBool, Offset( mFieldData.mAlignToTerrain, fxShapeReplicator ), "Align shapes to surface normal when set." );
  151. addField( "Interactions", TypeBool, Offset( mFieldData.mInteractions, fxShapeReplicator ), "Allow physics interactions with shapes." );
  152. addField( "AllowedTerrainSlope", TypeS32, Offset( mFieldData.mAllowedTerrainSlope, fxShapeReplicator ), "Maximum surface angle allowed for shape instances." );
  153. addField( "TerrainAlignment", TypePoint3F, Offset( mFieldData.mTerrainAlignment, fxShapeReplicator ), "Surface normals will be multiplied by these values when AlignToTerrain is enabled." );
  154. endGroup( "Restraints" ); // MM: Added Group Footer.
  155. addGroup( "Object Transforms" ); // MM: Added Group Header.
  156. addField( "ShapeScaleMin", TypePoint3F, Offset( mFieldData.mShapeScaleMin, fxShapeReplicator ), "Minimum shape scale." );
  157. addField( "ShapeScaleMax", TypePoint3F, Offset( mFieldData.mShapeScaleMax, fxShapeReplicator ), "Maximum shape scale." );
  158. addField( "ShapeRotateMin", TypePoint3F, Offset( mFieldData.mShapeRotateMin, fxShapeReplicator ), "Minimum shape rotation angles.");
  159. addField( "ShapeRotateMax", TypePoint3F, Offset( mFieldData.mShapeRotateMax, fxShapeReplicator ), "Maximum shape rotation angles." );
  160. addField( "OffsetZ", TypeS32, Offset( mFieldData.mOffsetZ, fxShapeReplicator ), "Offset shapes by this amount vertically." );
  161. endGroup( "Object Transforms" ); // MM: Added Group Footer.
  162. // Initialise parents' persistent fields.
  163. Parent::initPersistFields();
  164. }
  165. //------------------------------------------------------------------------------
  166. void fxShapeReplicator::CreateShapes(void)
  167. {
  168. F32 HypX, HypY;
  169. F32 Angle;
  170. U32 RelocationRetry;
  171. Point3F ShapePosition;
  172. Point3F ShapeStart;
  173. Point3F ShapeEnd;
  174. Point3F ShapeScale;
  175. EulerF ShapeRotation;
  176. QuatF QRotation;
  177. bool CollisionResult;
  178. RayInfo RayEvent;
  179. TSShape* pShape;
  180. // Don't create shapes if we are hiding replications.
  181. if (mFieldData.mHideReplications) return;
  182. // Cannot continue without shapes!
  183. if (dStrcmp(mFieldData.mShapeFile, "") == 0) return;
  184. // Check that we can position somewhere!
  185. if (!( mFieldData.mAllowOnTerrain ||
  186. mFieldData.mAllowStatics ||
  187. mFieldData.mAllowOnWater))
  188. {
  189. // Problem ...
  190. Con::warnf(ConsoleLogEntry::General, "[%s] - Could not place object, All alloweds are off!", getName());
  191. // Return here.
  192. return;
  193. }
  194. // Check Shapes.
  195. AssertFatal(mCurrentShapeCount==0,"Shapes already present, this should not be possible!");
  196. // Check that we have a shape...
  197. if (!mFieldData.mShapeFile) return;
  198. // Set Seed.
  199. RandomGen.setSeed(mFieldData.mSeed);
  200. // Set shape vector.
  201. mReplicatedShapes.clear();
  202. // Add shapes.
  203. for (U32 idx = 0; idx < mFieldData.mShapeCount; idx++)
  204. {
  205. fxShapeReplicatedStatic* fxStatic;
  206. // Create our static shape.
  207. fxStatic = new fxShapeReplicatedStatic();
  208. // Set the 'shapeName' field.
  209. fxStatic->setField("shapeName", mFieldData.mShapeFile);
  210. // Is this Replicator on the Server?
  211. if (isServerObject())
  212. // Yes, so stop it from Ghosting. (Hack, Hack, Hack!)
  213. fxStatic->touchNetFlags(Ghostable, false);
  214. else
  215. // No, so flag as ghost object. (Another damn Hack!)
  216. fxStatic->touchNetFlags(IsGhost, true);
  217. // Register the Object.
  218. if (!fxStatic->registerObject())
  219. {
  220. // Problem ...
  221. Con::warnf(ConsoleLogEntry::General, "[%s] - Could not load shape file '%s'!", getName(), mFieldData.mShapeFile);
  222. // Destroy Shape.
  223. delete fxStatic;
  224. // Destroy existing hapes.
  225. DestroyShapes();
  226. // Quit.
  227. return;
  228. }
  229. // Get Allocated Shape.
  230. pShape = fxStatic->getShape();
  231. // Reset Relocation Retry.
  232. RelocationRetry = mFieldData.mShapeRetries;
  233. // Find it a home ...
  234. do
  235. {
  236. // Get the Replicator Position.
  237. ShapePosition = getPosition();
  238. // Calculate a random offset
  239. HypX = RandomGen.randF(mFieldData.mInnerRadiusX, mFieldData.mOuterRadiusX);
  240. HypY = RandomGen.randF(mFieldData.mInnerRadiusY, mFieldData.mOuterRadiusY);
  241. Angle = RandomGen.randF(0, (F32)M_2PI);
  242. // Calcualte the new position.
  243. ShapePosition.x += HypX * mCos(Angle);
  244. ShapePosition.y += HypY * mSin(Angle);
  245. // Initialise RayCast Search Start/End Positions.
  246. ShapeStart = ShapeEnd = ShapePosition;
  247. ShapeStart.z = 2000.f;
  248. ShapeEnd.z= -2000.f;
  249. // Is this the Server?
  250. if (isServerObject())
  251. // Perform Ray Cast Collision on Server Terrain.
  252. CollisionResult = gServerContainer.castRay(ShapeStart, ShapeEnd, FXREPLICATOR_COLLISION_MASK, &RayEvent);
  253. else
  254. // Perform Ray Cast Collision on Client Terrain.
  255. CollisionResult = gClientContainer.castRay( ShapeStart, ShapeEnd, FXREPLICATOR_COLLISION_MASK, &RayEvent);
  256. // Did we hit anything?
  257. if (CollisionResult)
  258. {
  259. // For now, let's pretend we didn't get a collision.
  260. CollisionResult = false;
  261. // Yes, so get it's type.
  262. U32 CollisionType = RayEvent.object->getTypeMask();
  263. // Check Illegal Placements.
  264. if (((CollisionType & TerrainObjectType) && !mFieldData.mAllowOnTerrain) ||
  265. ((CollisionType & StaticShapeObjectType) && !mFieldData.mAllowStatics) ||
  266. ((CollisionType & WaterObjectType) && !mFieldData.mAllowOnWater) ) continue;
  267. // If we collided with water and are not allowing on the water surface then let's find the
  268. // terrain underneath and pass this on as the original collision else fail.
  269. //
  270. // NOTE:- We need to do this on the server/client as appropriate.
  271. if ((CollisionType & WaterObjectType) && !mFieldData.mAllowWaterSurface)
  272. {
  273. // Is this the Server?
  274. if (isServerObject())
  275. {
  276. // Yes, so do it on the server container.
  277. if (!gServerContainer.castRay( ShapeStart, ShapeEnd, FXREPLICATOR_NOWATER_COLLISION_MASK, &RayEvent)) continue;
  278. }
  279. else
  280. {
  281. // No, so do it on the client container.
  282. if (!gClientContainer.castRay( ShapeStart, ShapeEnd, FXREPLICATOR_NOWATER_COLLISION_MASK, &RayEvent)) continue;
  283. }
  284. }
  285. // We passed with flying colours so carry on.
  286. CollisionResult = true;
  287. }
  288. // Invalidate if we are below Allowed Terrain Angle.
  289. if (RayEvent.normal.z < mSin(mDegToRad(90.0f-mFieldData.mAllowedTerrainSlope))) CollisionResult = false;
  290. // Wait until we get a collision.
  291. } while(!CollisionResult && --RelocationRetry);
  292. // Check for Relocation Problem.
  293. if (RelocationRetry > 0)
  294. {
  295. // Adjust Impact point.
  296. RayEvent.point.z += mFieldData.mOffsetZ;
  297. // Set New Position.
  298. ShapePosition = RayEvent.point;
  299. }
  300. else
  301. {
  302. // Warning.
  303. Con::warnf(ConsoleLogEntry::General, "[%s] - Could not find satisfactory position for shape '%s' on %s!", getName(), mFieldData.mShapeFile,isServerObject()?"Server":"Client");
  304. // Unregister Object.
  305. fxStatic->unregisterObject();
  306. // Destroy Shape.
  307. delete fxStatic;
  308. // Skip to next.
  309. continue;
  310. }
  311. // Get Shape Transform.
  312. MatrixF XForm = fxStatic->getTransform();
  313. // Are we aligning to Terrain?
  314. if (mFieldData.mAlignToTerrain)
  315. {
  316. // Yes, so set rotation to Terrain Impact Normal.
  317. ShapeRotation = RayEvent.normal * mFieldData.mTerrainAlignment;
  318. }
  319. else
  320. {
  321. // No, so choose a new Rotation (in Radians).
  322. ShapeRotation.set( mDegToRad(RandomGen.randF(mFieldData.mShapeRotateMin.x, mFieldData.mShapeRotateMax.x)),
  323. mDegToRad(RandomGen.randF(mFieldData.mShapeRotateMin.y, mFieldData.mShapeRotateMax.y)),
  324. mDegToRad(RandomGen.randF(mFieldData.mShapeRotateMin.z, mFieldData.mShapeRotateMax.z)));
  325. }
  326. // Set Quaternion Roation.
  327. QRotation.set(ShapeRotation);
  328. // Set Transform Rotation.
  329. QRotation.setMatrix(&XForm);
  330. // Set Position.
  331. XForm.setColumn(3, ShapePosition);
  332. // Set Shape Position / Rotation.
  333. fxStatic->setTransform(XForm);
  334. // Choose a new Scale.
  335. ShapeScale.set( RandomGen.randF(mFieldData.mShapeScaleMin.x, mFieldData.mShapeScaleMax.x),
  336. RandomGen.randF(mFieldData.mShapeScaleMin.y, mFieldData.mShapeScaleMax.y),
  337. RandomGen.randF(mFieldData.mShapeScaleMin.z, mFieldData.mShapeScaleMax.z));
  338. // Set Shape Scale.
  339. fxStatic->setScale(ShapeScale);
  340. // Lock it.
  341. fxStatic->setLocked(true);
  342. // Store Shape in Replicated Shapes Vector.
  343. //mReplicatedShapes[mCurrentShapeCount++] = fxStatic;
  344. mReplicatedShapes.push_back(fxStatic);
  345. }
  346. mCurrentShapeCount = mReplicatedShapes.size();
  347. // Take first Timestamp.
  348. mLastRenderTime = Platform::getVirtualMilliseconds();
  349. }
  350. //------------------------------------------------------------------------------
  351. void fxShapeReplicator::DestroyShapes(void)
  352. {
  353. // Finish if we didn't create any shapes.
  354. if (mCurrentShapeCount == 0) return;
  355. // Remove shapes.
  356. for (U32 idx = 0; idx < mCurrentShapeCount; idx++)
  357. {
  358. fxShapeReplicatedStatic* fxStatic;
  359. // Fetch the Shape Object.
  360. fxStatic = mReplicatedShapes[idx];
  361. // Got a Shape?
  362. if (fxStatic)
  363. {
  364. // Unlock it.
  365. fxStatic->setLocked(false);
  366. // Unregister the object.
  367. fxStatic->unregisterObject();
  368. // Delete it.
  369. delete fxStatic;
  370. }
  371. }
  372. // Empty the Replicated Shapes Vector.
  373. mReplicatedShapes.clear();
  374. // Reset Shape Count.
  375. mCurrentShapeCount = 0;
  376. }
  377. //------------------------------------------------------------------------------
  378. void fxShapeReplicator::RenewShapes(void)
  379. {
  380. // Destroy any shapes.
  381. DestroyShapes();
  382. // Don't create shapes on the Server if we don't need interactions.
  383. if (isServerObject() && !mFieldData.mInteractions) return;
  384. // Create Shapes.
  385. CreateShapes();
  386. }
  387. //------------------------------------------------------------------------------
  388. void fxShapeReplicator::StartUp(void)
  389. {
  390. RenewShapes();
  391. }
  392. //------------------------------------------------------------------------------
  393. bool fxShapeReplicator::onAdd()
  394. {
  395. if(!Parent::onAdd())
  396. return(false);
  397. // Add the Replicator to the Replicator Set.
  398. dynamic_cast<SimSet*>(Sim::findObject("fxReplicatorSet"))->addObject(this);
  399. // Set Default Object Box.
  400. mObjBox.minExtents.set( -0.5, -0.5, -0.5 );
  401. mObjBox.maxExtents.set( 0.5, 0.5, 0.5 );
  402. resetWorldBox();
  403. // Add to Scene.
  404. setRenderTransform(mObjToWorld);
  405. addToScene();
  406. // Register for notification when GhostAlways objects are done loading
  407. NetConnection::smGhostAlwaysDone.notify( this, &fxShapeReplicator::onGhostAlwaysDone );
  408. return true;
  409. }
  410. //------------------------------------------------------------------------------
  411. void fxShapeReplicator::onRemove()
  412. {
  413. // Remove the Replicator from the Replicator Set.
  414. dynamic_cast<SimSet*>(Sim::findObject("fxReplicatorSet"))->removeObject(this);
  415. NetConnection::smGhostAlwaysDone.remove( this, &fxShapeReplicator::onGhostAlwaysDone );
  416. removeFromScene();
  417. // Destroy Shapes.
  418. DestroyShapes();
  419. // Do Parent.
  420. Parent::onRemove();
  421. }
  422. //------------------------------------------------------------------------------
  423. void fxShapeReplicator::onGhostAlwaysDone()
  424. {
  425. RenewShapes();
  426. }
  427. //------------------------------------------------------------------------------
  428. void fxShapeReplicator::inspectPostApply()
  429. {
  430. // Set Parent.
  431. Parent::inspectPostApply();
  432. // Renew Shapes.
  433. RenewShapes();
  434. // Set Replication Mask.
  435. setMaskBits(ReplicationMask);
  436. }
  437. //------------------------------------------------------------------------------
  438. DefineEngineFunction(StartClientReplication, void, (),, "Activates the shape replicator.\n"
  439. "@tsexample\n"
  440. "// Call the function\n"
  441. "StartClientReplication()\n"
  442. "@endtsexample\n"
  443. "@ingroup Foliage"
  444. )
  445. {
  446. // Find the Replicator Set.
  447. SimSet *fxReplicatorSet = dynamic_cast<SimSet*>(Sim::findObject("fxReplicatorSet"));
  448. // Return if Error.
  449. if (!fxReplicatorSet) return;
  450. // StartUp Replication Object.
  451. for (SimSetIterator itr(fxReplicatorSet); *itr; ++itr)
  452. {
  453. // Fetch the Replicator Object.
  454. fxShapeReplicator* Replicator = static_cast<fxShapeReplicator*>(*itr);
  455. // Start Client Objects Only.
  456. if (Replicator->isClientObject()) Replicator->StartUp();
  457. }
  458. // Info ...
  459. Con::printf("Client Replication Startup has Happened!");
  460. }
  461. //------------------------------------------------------------------------------
  462. void fxShapeReplicator::prepRenderImage( SceneRenderState* state )
  463. {
  464. ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
  465. ri->renderDelegate.bind(this, &fxShapeReplicator::renderObject);
  466. // The fxShapeReplicator isn't technically foliage but our debug
  467. // effect seems to render best as a Foliage type (translucent,
  468. // renders itself, no sorting)
  469. ri->type = RenderPassManager::RIT_Foliage;
  470. state->getRenderPass()->addInst( ri );
  471. }
  472. //------------------------------------------------------------------------------
  473. // Renders a triangle stripped oval
  474. void fxShapeReplicator::renderArc(const F32 fRadiusX, const F32 fRadiusY)
  475. {
  476. PrimBuild::begin(GFXTriangleStrip, 720);
  477. for (U32 Angle = mCreationAreaAngle; Angle < (mCreationAreaAngle+360); Angle++)
  478. {
  479. F32 XPos, YPos;
  480. // Calculate Position.
  481. XPos = fRadiusX * mCos(mDegToRad(-(F32)Angle));
  482. YPos = fRadiusY * mSin(mDegToRad(-(F32)Angle));
  483. // Set Colour.
  484. PrimBuild::color4f(mFieldData.mPlaceAreaColour.red,
  485. mFieldData.mPlaceAreaColour.green,
  486. mFieldData.mPlaceAreaColour.blue,
  487. AREA_ANIMATION_ARC * (Angle-mCreationAreaAngle));
  488. PrimBuild::vertex3f(XPos, YPos, -(F32)mFieldData.mPlacementBandHeight/2.0f);
  489. PrimBuild::vertex3f(XPos, YPos, +(F32)mFieldData.mPlacementBandHeight/2.0f);
  490. }
  491. PrimBuild::end();
  492. }
  493. // This currently uses the primbuilder, could convert out, but why allocate the buffer if we
  494. // never edit the misison?
  495. void fxShapeReplicator::renderPlacementArea(const F32 ElapsedTime)
  496. {
  497. if (gEditingMission && mFieldData.mShowPlacementArea)
  498. {
  499. GFX->pushWorldMatrix();
  500. GFX->multWorld(getTransform());
  501. if (!mPlacementSB)
  502. {
  503. GFXStateBlockDesc transparent;
  504. transparent.setCullMode(GFXCullNone);
  505. transparent.alphaTestEnable = true;
  506. transparent.setZReadWrite(true);
  507. transparent.zWriteEnable = false;
  508. transparent.setBlend(true, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha);
  509. mPlacementSB = GFX->createStateBlock( transparent );
  510. }
  511. GFX->setStateBlock(mPlacementSB);
  512. // Do we need to draw the Outer Radius?
  513. if (mFieldData.mOuterRadiusX || mFieldData.mOuterRadiusY)
  514. renderArc((F32) mFieldData.mOuterRadiusX, (F32) mFieldData.mOuterRadiusY);
  515. // Inner radius?
  516. if (mFieldData.mInnerRadiusX || mFieldData.mInnerRadiusY)
  517. renderArc((F32) mFieldData.mInnerRadiusX, (F32) mFieldData.mInnerRadiusY);
  518. GFX->popWorldMatrix();
  519. mCreationAreaAngle = (U32)(mCreationAreaAngle + (1000 * ElapsedTime));
  520. mCreationAreaAngle = mCreationAreaAngle % 360;
  521. }
  522. }
  523. //------------------------------------------------------------------------------
  524. void fxShapeReplicator::renderObject(ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance* overrideMat)
  525. {
  526. if (overrideMat)
  527. return;
  528. // Return if placement area not needed.
  529. if (!mFieldData.mShowPlacementArea)
  530. return;
  531. // Calculate Elapsed Time and take new Timestamp.
  532. S32 Time = Platform::getVirtualMilliseconds();
  533. F32 ElapsedTime = (Time - mLastRenderTime) * 0.001f;
  534. mLastRenderTime = Time;
  535. renderPlacementArea(ElapsedTime);
  536. }
  537. //------------------------------------------------------------------------------
  538. U32 fxShapeReplicator::packUpdate(NetConnection * con, U32 mask, BitStream * stream)
  539. {
  540. // Pack Parent.
  541. U32 retMask = Parent::packUpdate(con, mask, stream);
  542. // Write Replication Flag.
  543. if (stream->writeFlag(mask & ReplicationMask))
  544. {
  545. stream->writeAffineTransform(mObjToWorld); // Replicator Position.
  546. stream->writeInt(mFieldData.mSeed, 32); // Replicator Seed.
  547. stream->writeInt(mFieldData.mShapeCount, 32); // Shapes Count.
  548. stream->writeInt(mFieldData.mShapeRetries, 32); // Shapes Retries.
  549. stream->writeString(mFieldData.mShapeFile);
  550. stream->writeInt(mFieldData.mInnerRadiusX, 32); // Shapes Inner Radius X.
  551. stream->writeInt(mFieldData.mInnerRadiusY, 32); // Shapes Inner Radius Y.
  552. stream->writeInt(mFieldData.mOuterRadiusX, 32); // Shapes Outer Radius X.
  553. stream->writeInt(mFieldData.mOuterRadiusY, 32); // Shapes Outer Radius Y.
  554. mathWrite(*stream, mFieldData.mShapeScaleMin); // Shapes Scale Min.
  555. mathWrite(*stream, mFieldData.mShapeScaleMax); // Shapes Scale Max.
  556. mathWrite(*stream, mFieldData.mShapeRotateMin); // Shapes Rotate Min.
  557. mathWrite(*stream, mFieldData.mShapeRotateMax); // Shapes Rotate Max.
  558. stream->writeSignedInt(mFieldData.mOffsetZ, 32); // Shapes Offset Z.
  559. stream->writeFlag(mFieldData.mAllowOnTerrain); // Allow on Terrain.
  560. stream->writeFlag(mFieldData.mAllowStatics); // Allow on Statics.
  561. stream->writeFlag(mFieldData.mAllowOnWater); // Allow on Water.
  562. stream->writeFlag(mFieldData.mAllowWaterSurface); // Allow on Water Surface.
  563. stream->writeSignedInt(mFieldData.mAllowedTerrainSlope, 32); // Shapes Offset Z.
  564. stream->writeFlag(mFieldData.mAlignToTerrain); // Shapes AlignToTerrain.
  565. mathWrite(*stream, mFieldData.mTerrainAlignment); // Write Terrain Alignment.
  566. stream->writeFlag(mFieldData.mHideReplications); // Hide Replications.
  567. stream->writeFlag(mFieldData.mInteractions); // Shape Interactions.
  568. stream->writeFlag(mFieldData.mShowPlacementArea); // Show Placement Area Flag.
  569. stream->writeInt(mFieldData.mPlacementBandHeight, 32); // Placement Area Height.
  570. stream->write(mFieldData.mPlaceAreaColour);
  571. }
  572. // Were done ...
  573. return(retMask);
  574. }
  575. //------------------------------------------------------------------------------
  576. void fxShapeReplicator::unpackUpdate(NetConnection * con, BitStream * stream)
  577. {
  578. // Unpack Parent.
  579. Parent::unpackUpdate(con, stream);
  580. // Read Replication Details.
  581. if(stream->readFlag())
  582. {
  583. MatrixF ReplicatorObjectMatrix;
  584. stream->readAffineTransform(&ReplicatorObjectMatrix); // Replication Position.
  585. mFieldData.mSeed = stream->readInt(32); // Replicator Seed.
  586. mFieldData.mShapeCount = stream->readInt(32); // Shapes Count.
  587. mFieldData.mShapeRetries = stream->readInt(32); // Shapes Retries.
  588. mFieldData.mShapeFile = stream->readSTString(); // Shape File.
  589. mFieldData.mInnerRadiusX = stream->readInt(32); // Shapes Inner Radius X.
  590. mFieldData.mInnerRadiusY = stream->readInt(32); // Shapes Inner Radius Y.
  591. mFieldData.mOuterRadiusX = stream->readInt(32); // Shapes Outer Radius X.
  592. mFieldData.mOuterRadiusY = stream->readInt(32); // Shapes Outer Radius Y.
  593. mathRead(*stream, &mFieldData.mShapeScaleMin); // Shapes Scale Min.
  594. mathRead(*stream, &mFieldData.mShapeScaleMax); // Shapes Scale Max.
  595. mathRead(*stream, &mFieldData.mShapeRotateMin); // Shapes Rotate Min.
  596. mathRead(*stream, &mFieldData.mShapeRotateMax); // Shapes Rotate Max.
  597. mFieldData.mOffsetZ = stream->readSignedInt(32); // Shapes Offset Z.
  598. mFieldData.mAllowOnTerrain = stream->readFlag(); // Allow on Terrain.
  599. mFieldData.mAllowStatics = stream->readFlag(); // Allow on Statics.
  600. mFieldData.mAllowOnWater = stream->readFlag(); // Allow on Water.
  601. mFieldData.mAllowWaterSurface = stream->readFlag(); // Allow on Water Surface.
  602. mFieldData.mAllowedTerrainSlope = stream->readSignedInt(32); // Allowed Terrain Slope.
  603. mFieldData.mAlignToTerrain = stream->readFlag(); // Read AlignToTerrain.
  604. mathRead(*stream, &mFieldData.mTerrainAlignment); // Read Terrain Alignment.
  605. mFieldData.mHideReplications = stream->readFlag(); // Hide Replications.
  606. mFieldData.mInteractions = stream->readFlag(); // Read Interactions.
  607. mFieldData.mShowPlacementArea = stream->readFlag(); // Show Placement Area Flag.
  608. mFieldData.mPlacementBandHeight = stream->readInt(32); // Placement Area Height.
  609. stream->read(&mFieldData.mPlaceAreaColour);
  610. // Set Transform.
  611. setTransform(ReplicatorObjectMatrix);
  612. RenewShapes();
  613. }
  614. }