Torque3D Documentation / _generateds / fxShapeReplicator.cpp

fxShapeReplicator.cpp

Engine/source/T3D/fx/fxShapeReplicator.cpp

More...

Public Variables

bool

For frame signal.

Public Functions

ConsoleDocClass(fxShapeReplicatedStatic , "@brief The object definition <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> shapes that will be replicated across an area using an <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">fxShapeReplicator.\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Foliage\n</a>" )
ConsoleDocClass(fxShapeReplicator , "@brief An emitter <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> objects <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> replicate across an <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">area.\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Foliage\n</a>" )
DefineEngineFunction(StartClientReplication , void , () , "Activates the shape <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">replicator.\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "// Call the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">function\n</a>" "StartClientReplication()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n</a>" "@ingroup Foliage" )

Detailed Description

Public Variables

bool gEditingMission 

For frame signal.

Public Functions

ConsoleDocClass(fxShapeReplicatedStatic , "@brief The object definition <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> shapes that will be replicated across an area using an <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">fxShapeReplicator.\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Foliage\n</a>" )

ConsoleDocClass(fxShapeReplicator , "@brief An emitter <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> objects <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> replicate across an <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">area.\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Foliage\n</a>" )

DefineEngineFunction(StartClientReplication , void , () , "Activates the shape <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">replicator.\n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "// Call the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">function\n</a>" "StartClientReplication()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n</a>" "@ingroup Foliage" )

IMPLEMENT_CO_NETOBJECT_V1(fxShapeReplicatedStatic )

IMPLEMENT_CO_NETOBJECT_V1(fxShapeReplicator )

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