fxShapeReplicator.cpp 29 KB

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