fxShapeReplicator.cpp
Engine/source/T3D/fx/fxShapeReplicator.cpp
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