906 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			906 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
| //-----------------------------------------------------------------------------
 | |
| // Torque Game Engine
 | |
| // Written by Melvyn May, Started on 13th March 2002, finished 27th March 2002.
 | |
| //
 | |
| // "My code is written for the Torque community, so do your worst with it,
 | |
| //  just don't rip-it-off and call it your own without even thanking me".
 | |
| //
 | |
| //  - Melv (working hard to become an associate ... hint).
 | |
| //
 | |
| //-----------------------------------------------------------------------------
 | |
| 
 | |
| #include "dgl/dgl.h"
 | |
| #include "console/consoleTypes.h"
 | |
| #include "core/bitStream.h"
 | |
| #include "math/mRandom.h"
 | |
| #include "math/mathIO.h"
 | |
| #include "terrain/terrData.h"
 | |
| #include "game/gameConnection.h"
 | |
| #include "console/simBase.h"
 | |
| #include "sceneGraph/sceneGraph.h"
 | |
| #include "fxShapeReplicator.h"
 | |
| #include "sim/netConnection.h"
 | |
| #include "lightingSystem/sgLighting.h"
 | |
| #include "platform/profiler.h"
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| //
 | |
| //  Put this in /example/common/editor/editor.cs in function [Editor::create()] (around line 66).
 | |
| //
 | |
| //   // Ignore Replicated fxStatic Instances.
 | |
| //   EWorldEditor.ignoreObjClass("fxShapeReplicatedStatic");
 | |
| //
 | |
| //------------------------------------------------------------------------------
 | |
| //
 | |
| //  Put this in /example/common/editor/EditorGui.cs in [function Creator::init( %this )]
 | |
| //
 | |
| //   %Environment_Item[8] = "fxShapeReplicator";  <-- ADD THIS.
 | |
| //
 | |
| //------------------------------------------------------------------------------
 | |
| //
 | |
| //  Put the function in /example/common/editor/ObjectBuilderGui.gui [around line 458] ...
 | |
| //
 | |
| //  function ObjectBuilderGui::buildfxShapeReplicator(%this)
 | |
| //  {
 | |
| //      %this.className = "fxShapeReplicator";
 | |
| //      %this.process();
 | |
| //  }
 | |
| //
 | |
| //------------------------------------------------------------------------------
 | |
| //
 | |
| //  Put this in /example/common/client/missionDownload.cs in [function clientCmdMissionStartPhase3(%seq,%missionName)] (line 65)
 | |
| //  after codeline 'onPhase2Complete();'.
 | |
| //
 | |
| //  StartClientReplication();
 | |
| //
 | |
| //------------------------------------------------------------------------------
 | |
| //
 | |
| //  Put this in /engine/console/simBase.h (around line 509) in
 | |
| //
 | |
| //  namespace Sim
 | |
| //  {
 | |
| //     DeclareNamedSet(fxReplicatorSet)  <-- ADD THIS (Note no semi-colon).
 | |
| //
 | |
| //------------------------------------------------------------------------------
 | |
| //
 | |
| //  Put this in /engine/console/simBase.cc (around line 19) in
 | |
| //
 | |
| //  ImplementNamedSet(fxReplicatorSet)  <-- ADD THIS
 | |
| //
 | |
| //------------------------------------------------------------------------------
 | |
| //
 | |
| //  Put this in /engine/console/simManager.cc [function void init()] (around line 269).
 | |
| //
 | |
| //  namespace Sim
 | |
| //  {
 | |
| //      InstantiateNamedSet(fxReplicatorSet);  <-- ADD THIS
 | |
| //
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| extern bool gEditingMission;
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| IMPLEMENT_CO_NETOBJECT_V1(fxShapeReplicator);
 | |
| IMPLEMENT_CO_NETOBJECT_V1(fxShapeReplicatedStatic);
 | |
| 
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| // Class: fxShapeReplicator
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| fxShapeReplicator::fxShapeReplicator()
 | |
| {
 | |
|     // Setup NetObject.
 | |
|     mTypeMask |= StaticObjectType | StaticTSObjectType | StaticRenderedObjectType;
 | |
|     mAddedToScene = false;
 | |
|     mNetFlags.set(Ghostable | ScopeAlways);
 | |
| 
 | |
|     // Reset Client Replication Started.
 | |
|     mClientReplicationStarted = false;
 | |
| 
 | |
|     // Reset Shape Count.
 | |
|     mCurrentShapeCount = 0;
 | |
| 
 | |
|     // Reset Creation Area Angle Animation.
 | |
|     mCreationAreaAngle = 0;
 | |
| }
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| fxShapeReplicator::~fxShapeReplicator()
 | |
| {
 | |
| }
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| void fxShapeReplicator::initPersistFields()
 | |
| {
 | |
|     // Initialise parents' persistent fields.
 | |
|     Parent::initPersistFields();
 | |
| 
 | |
|     // Add out own persistent fields.
 | |
|     addGroup( "Debugging" );
 | |
|     addField( "HideReplications",   TypeBool,       Offset( mFieldData.mHideReplications,       fxShapeReplicator ) );
 | |
|     addField( "ShowPlacementArea",  TypeBool,       Offset( mFieldData.mShowPlacementArea,      fxShapeReplicator ) );
 | |
|     addField( "PlacementAreaHeight",TypeS32,        Offset( mFieldData.mPlacementBandHeight,    fxShapeReplicator ) );
 | |
|     addField( "PlacementColour",    TypeColorF,     Offset( mFieldData.mPlaceAreaColour,        fxShapeReplicator ) );
 | |
|     endGroup( "Debugging" );
 | |
| 
 | |
|     addGroup( "Media" );
 | |
|     addField( "ShapeFile",          TypeFilename,   Offset( mFieldData.mShapeFile,              fxShapeReplicator ) );
 | |
|     endGroup( "Media" );
 | |
| 
 | |
|     addGroup( "Replications" ); 
 | |
|     addField( "Seed",               TypeS32,        Offset( mFieldData.mSeed,                   fxShapeReplicator ) );
 | |
|     addField( "ShapeCount",         TypeS32,        Offset( mFieldData.mShapeCount,             fxShapeReplicator ) );
 | |
|     addField( "ShapeRetries",       TypeS32,        Offset( mFieldData.mShapeRetries,           fxShapeReplicator ) );
 | |
|     endGroup( "Replications" ); 
 | |
| 
 | |
|     addGroup( "Placement Radius" ); 
 | |
|     addField( "InnerRadiusX",       TypeS32,        Offset( mFieldData.mInnerRadiusX,           fxShapeReplicator ) );
 | |
|     addField( "InnerRadiusY",       TypeS32,        Offset( mFieldData.mInnerRadiusY,           fxShapeReplicator ) );
 | |
|     addField( "OuterRadiusX",       TypeS32,        Offset( mFieldData.mOuterRadiusX,           fxShapeReplicator ) );
 | |
|     addField( "OuterRadiusY",       TypeS32,        Offset( mFieldData.mOuterRadiusY,           fxShapeReplicator ) );
 | |
|     endGroup( "Placement Radius" ); 
 | |
| 
 | |
|     addGroup( "Restraints" );
 | |
|     addField( "AllowOnTerrain",     TypeBool,       Offset( mFieldData.mAllowOnTerrain,         fxShapeReplicator ) );
 | |
|     addField( "AllowOnInteriors",   TypeBool,       Offset( mFieldData.mAllowOnInteriors,       fxShapeReplicator ) );
 | |
|     addField( "AllowOnStatics",     TypeBool,       Offset( mFieldData.mAllowStatics,           fxShapeReplicator ) );
 | |
|     addField( "AllowOnWater",       TypeBool,       Offset( mFieldData.mAllowOnWater,           fxShapeReplicator ) );
 | |
|     addField( "AllowWaterSurface",  TypeBool,       Offset( mFieldData.mAllowWaterSurface,      fxShapeReplicator ) );
 | |
|     addField( "AlignToTerrain",     TypeBool,       Offset( mFieldData.mAlignToTerrain,         fxShapeReplicator ) );
 | |
|     addField( "Interactions",       TypeBool,       Offset( mFieldData.mInteractions,           fxShapeReplicator ) );
 | |
|     addField( "AllowedTerrainSlope",TypeS32,        Offset( mFieldData.mAllowedTerrainSlope,    fxShapeReplicator ) );
 | |
|     addField( "TerrainAlignment",   TypePoint3F,    Offset( mFieldData.mTerrainAlignment,       fxShapeReplicator ) );
 | |
|     endGroup( "Restraints" );
 | |
| 
 | |
|     addGroup( "Object Transforms" );
 | |
|     addField( "FixShapeAspect",     TypeBool,       Offset( mFieldData.mFixShapeAspect,         fxShapeReplicator ) );
 | |
|     addField( "ShapeScaleMin",      TypePoint3F,    Offset( mFieldData.mShapeScaleMin,          fxShapeReplicator ) );
 | |
|     addField( "ShapeScaleMax",      TypePoint3F,    Offset( mFieldData.mShapeScaleMax,          fxShapeReplicator ) );
 | |
|     addField( "ShapeRotateMin",     TypePoint3F,    Offset( mFieldData.mShapeRotateMin,         fxShapeReplicator ) );
 | |
|     addField( "ShapeRotateMax",     TypePoint3F,    Offset( mFieldData.mShapeRotateMax,         fxShapeReplicator ) );
 | |
|     addField( "OffsetZ",            TypeS32,        Offset( mFieldData.mOffsetZ,                fxShapeReplicator ) );
 | |
|     endGroup( "Object Transforms" );
 | |
| 
 | |
|    addGroup("Lighting");
 | |
|    addField("receiveSunLight", TypeBool, Offset(receiveSunLight, SceneObject));
 | |
|    addField("receiveLMLighting", TypeBool, Offset(receiveLMLighting, SceneObject));
 | |
|    addField("useAdaptiveSelfIllumination", TypeBool, Offset(useAdaptiveSelfIllumination, SceneObject));
 | |
|    addField("useCustomAmbientLighting", TypeBool, Offset(useCustomAmbientLighting, SceneObject));
 | |
|    addField("customAmbientSelfIllumination", TypeBool, Offset(customAmbientForSelfIllumination, SceneObject));
 | |
|    addField("customAmbientLighting", TypeColorF, Offset(customAmbientLighting, SceneObject));
 | |
|    addField("lightGroupName", TypeString, Offset(lightGroupName, SceneObject));
 | |
|    addField("useLightingOcclusion", TypeBool, Offset(useLightingOcclusion, SceneObject));
 | |
|    endGroup("Lighting");
 | |
| }
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| void fxShapeReplicator::CreateShapes(void)
 | |
| {
 | |
|     F32             HypX, HypY;
 | |
|     F32             Angle;
 | |
|     U32             RelocationRetry;
 | |
|     Point3F         ShapePosition;
 | |
|     Point3F         ShapeStart;
 | |
|     Point3F         ShapeEnd;
 | |
|     Point3F         ShapeScale;
 | |
|     EulerF          ShapeRotation;
 | |
|     QuatF           QRotation;
 | |
|     bool            CollisionResult;
 | |
|     RayInfo         RayEvent;
 | |
|     TSShape*        pShape;
 | |
|     Container*      pContainer;
 | |
| 
 | |
| 
 | |
|     // Don't create shapes if we are hiding replications.
 | |
|     if (mFieldData.mHideReplications) return;
 | |
| 
 | |
|     // Cannot continue without shapes!
 | |
|     if (mFieldData.mShapeFile == "") return;
 | |
| 
 | |
|     // Check that we can position somewhere!
 | |
|     if (!(  mFieldData.mAllowOnTerrain ||
 | |
|             mFieldData.mAllowOnInteriors ||
 | |
|             mFieldData.mAllowStatics ||
 | |
|             mFieldData.mAllowOnWater))
 | |
|     {
 | |
|         // Problem ...
 | |
|         Con::warnf(ConsoleLogEntry::General, "[%s] - Could not place object, All alloweds are off!", getName());
 | |
| 
 | |
|         // Return here.
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     // Check Shapes.
 | |
|     AssertFatal(mCurrentShapeCount==0,"Shapes already present, this should not be possible!")
 | |
| 
 | |
|     // Check that we have a shape...
 | |
|     if (!mFieldData.mShapeFile) return;
 | |
| 
 | |
|     // Set Seed.
 | |
|     RandomGen.setSeed(mFieldData.mSeed);
 | |
| 
 | |
|     // Set shape vector.
 | |
|     mReplicatedShapes.reserve(mFieldData.mShapeCount);
 | |
| 
 | |
|     // Add shapes.
 | |
|     for (U32 idx = 0; idx < mFieldData.mShapeCount; idx++)
 | |
|     {
 | |
|         fxShapeReplicatedStatic*    fxStatic;
 | |
| 
 | |
|         // Create our static shape.
 | |
|         fxStatic = new fxShapeReplicatedStatic();
 | |
| 
 | |
| 		fxStatic->receiveLMLighting = receiveLMLighting;
 | |
| 		fxStatic->receiveSunLight = receiveSunLight;
 | |
| 		fxStatic->useAdaptiveSelfIllumination = useAdaptiveSelfIllumination;
 | |
| 		fxStatic->useCustomAmbientLighting = useCustomAmbientLighting;
 | |
| 		fxStatic->customAmbientForSelfIllumination = customAmbientForSelfIllumination;
 | |
| 		fxStatic->customAmbientLighting = customAmbientLighting;
 | |
| 		fxStatic->lightGroupName = lightGroupName;
 | |
|       fxStatic->useLightingOcclusion = useLightingOcclusion;
 | |
| 		
 | |
|         // Set the 'shapeName' field.
 | |
|         fxStatic->setField("shapeName", mFieldData.mShapeFile);
 | |
| 
 | |
|         // Is this Replicator on the Server?
 | |
|         if (isServerObject())
 | |
|             // Yes, so stop it from Ghosting. (Hack, Hack, Hack!)
 | |
|             fxStatic->touchNetFlags(Ghostable, false);
 | |
|         else
 | |
|             // No, so flag as ghost object. (Another damn Hack!)
 | |
|             fxStatic->touchNetFlags(IsGhost, true);
 | |
| 
 | |
|         // Register the Object.
 | |
|         if (!fxStatic->registerObject())
 | |
|         {
 | |
|             // Problem ...
 | |
|             Con::warnf(ConsoleLogEntry::General, "[%s] - Could not load shape file '%s'!", getName(), mFieldData.mShapeFile);
 | |
| 
 | |
|             // Destroy Shape.
 | |
|             delete fxStatic;
 | |
| 
 | |
|             // Destroy existing hapes.
 | |
|             DestroyShapes();
 | |
| 
 | |
|             // Quit.
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         // Get Allocated Shape.
 | |
|         pShape = fxStatic->getShape();
 | |
| 
 | |
|         // Reset Relocation Retry.
 | |
|         RelocationRetry = mFieldData.mShapeRetries;
 | |
| 
 | |
|         // Find it a home ...
 | |
|         do
 | |
|         {
 | |
| 
 | |
|             // Calculate a random offset
 | |
|             HypX   = RandomGen.randF(mFieldData.mInnerRadiusX, mFieldData.mOuterRadiusX);
 | |
|             HypY   = RandomGen.randF(mFieldData.mInnerRadiusY, mFieldData.mOuterRadiusY);
 | |
|             Angle   = RandomGen.randF(0, M_2PI);
 | |
| 
 | |
|             // Calculate the new random position (in local space).
 | |
|             Point3F randomShapePosLocal;
 | |
|             randomShapePosLocal.x = HypX * mCos(Angle);
 | |
|             randomShapePosLocal.y = HypY * mSin(Angle);
 | |
| 
 | |
|             // Transform into world space coordinates
 | |
|             Point3F shapePosWorld;
 | |
|             MatrixF objToWorld = getRenderTransform();
 | |
|             objToWorld.mulP(randomShapePosLocal, &shapePosWorld);
 | |
| 			ShapePosition = shapePosWorld;
 | |
| 
 | |
|             // Initialise RayCast Search Start/End Positions.
 | |
|             ShapeStart = ShapeEnd = ShapePosition;
 | |
|             ShapeStart.z = 2000.f;
 | |
|             ShapeEnd.z= -2000.f;
 | |
| 
 | |
|             // Is this the Server?
 | |
|             if (isServerObject())
 | |
|                 // Perform Ray Cast Collision on Server Terrain.
 | |
|                 CollisionResult = gServerContainer.castRay(ShapeStart, ShapeEnd, FXREPLICATOR_COLLISION_MASK, &RayEvent);
 | |
|             else
 | |
|                 // Perform Ray Cast Collision on Client Terrain.
 | |
|                 CollisionResult = gClientContainer.castRay( ShapeStart, ShapeEnd, FXREPLICATOR_COLLISION_MASK, &RayEvent);
 | |
| 
 | |
|             // Did we hit anything?
 | |
|             if (CollisionResult)
 | |
|             {
 | |
|                 // For now, let's pretend we didn't get a collision.
 | |
|                 CollisionResult = false;
 | |
| 
 | |
|                 // Yes, so get it's type.
 | |
|                 U32 CollisionType = RayEvent.object->getTypeMask();
 | |
| 
 | |
|                 // Check Illegal Placements.
 | |
|                 if (((CollisionType & TerrainObjectType) && !mFieldData.mAllowOnTerrain)    ||
 | |
|                     ((CollisionType & InteriorObjectType) && !mFieldData.mAllowOnInteriors) ||
 | |
|                     ((CollisionType & StaticTSObjectType) && !mFieldData.mAllowStatics) ||
 | |
|                     ((CollisionType & WaterObjectType) && !mFieldData.mAllowOnWater) ) continue;
 | |
| 
 | |
|                 // If we collided with water and are not allowing on the water surface then let's find the
 | |
|                 // terrain underneath and pass this on as the original collision else fail.
 | |
|                 //
 | |
|                 // NOTE:- We need to do this on the server/client as appropriate.
 | |
|                 if ((CollisionType & WaterObjectType) && !mFieldData.mAllowWaterSurface)
 | |
|                 {
 | |
|                     // Is this the Server?
 | |
|                     if (isServerObject())
 | |
|                     {
 | |
|                         // Yes, so do it on the server container.
 | |
|                         if (!gServerContainer.castRay( ShapeStart, ShapeEnd, FXREPLICATOR_NOWATER_COLLISION_MASK, &RayEvent)) continue;
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         // No, so do it on the client container.
 | |
|                         if (!gClientContainer.castRay( ShapeStart, ShapeEnd, FXREPLICATOR_NOWATER_COLLISION_MASK, &RayEvent)) continue;
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 // We passed with flying colours so carry on.
 | |
|                 CollisionResult = true;
 | |
|             }
 | |
| 
 | |
|             // Invalidate if we are below Allowed Terrain Angle.
 | |
|             if (RayEvent.normal.z < mSin(mDegToRad(90.0f-mFieldData.mAllowedTerrainSlope))) CollisionResult = false;
 | |
| 
 | |
|         // Wait until we get a collision.
 | |
|         } while(!CollisionResult && --RelocationRetry);
 | |
| 
 | |
|         // Check for Relocation Problem.
 | |
|         if (RelocationRetry > 0)
 | |
|         {
 | |
|             // Adjust Impact point.
 | |
|             RayEvent.point.z += mFieldData.mOffsetZ;
 | |
| 
 | |
|             // Set New Position.
 | |
|             ShapePosition = RayEvent.point;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             // Warning.
 | |
|            Con::warnf(ConsoleLogEntry::General, "[%s: %d] - Could not find satisfactory position for shape '%s' on %s!", getName(), getId(), mFieldData.mShapeFile,isServerObject()?"Server":"Client");
 | |
| 
 | |
|             // Unregister Object.
 | |
|             fxStatic->unregisterObject();
 | |
| 
 | |
|             // Destroy Shape.
 | |
|             delete fxStatic;
 | |
| 
 | |
|             // Skip to next.
 | |
|             continue;
 | |
|         }
 | |
| 
 | |
|         // Get Shape Transform.
 | |
|         MatrixF XForm = fxStatic->getTransform();
 | |
| 
 | |
|         // Are we aligning to Terrain?
 | |
|         if (mFieldData.mAlignToTerrain)
 | |
|         {
 | |
|             // Yes, so set rotation to Terrain Impact Normal.
 | |
|             ShapeRotation = RayEvent.normal * mFieldData.mTerrainAlignment;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             // No, so choose a new Rotation (in Radians).
 | |
|             ShapeRotation.set(  mDegToRad(RandomGen.randF(mFieldData.mShapeRotateMin.x, mFieldData.mShapeRotateMax.x)),
 | |
|                                 mDegToRad(RandomGen.randF(mFieldData.mShapeRotateMin.y, mFieldData.mShapeRotateMax.y)),
 | |
|                                 mDegToRad(RandomGen.randF(mFieldData.mShapeRotateMin.z, mFieldData.mShapeRotateMax.z)));
 | |
|         }
 | |
| 
 | |
|         // Set Quaternion Roation.
 | |
|         QRotation.set(ShapeRotation);
 | |
| 
 | |
|         // Set Transform Rotation.
 | |
|         QRotation.setMatrix(&XForm);
 | |
| 
 | |
|         // Set Position.
 | |
|         XForm.setColumn(3, ShapePosition);
 | |
| 
 | |
|         // Set Shape Position / Rotation.
 | |
|         fxStatic->setTransform(XForm);
 | |
| 
 | |
|         // Choose a new Scale.
 | |
|         F32 scaleX, scaleY, scaleZ;
 | |
| 
 | |
|         // Choose a random X-Scale.
 | |
|         scaleX = RandomGen.randF(mFieldData.mShapeScaleMin.x, mFieldData.mShapeScaleMax.x);
 | |
| 
 | |
|         // Fix Shape Aspect?
 | |
|         if ( mFieldData.mFixShapeAspect )
 | |
|         {
 | |
|             // Yes, so use Scale-X for all axis.
 | |
|             scaleY = scaleZ = scaleX;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             // No, so choose Scale-Y/Z.
 | |
|             scaleY = RandomGen.randF(mFieldData.mShapeScaleMin.y, mFieldData.mShapeScaleMax.y);
 | |
|             scaleZ = RandomGen.randF(mFieldData.mShapeScaleMin.z, mFieldData.mShapeScaleMax.z);
 | |
|         }
 | |
| 
 | |
|         // Set Shape Scale.
 | |
|         ShapeScale.set( scaleX, scaleY, scaleZ );
 | |
| 
 | |
|         // Set Shape Scale.
 | |
|         fxStatic->setScale(ShapeScale);
 | |
| 
 | |
|         // Lock it.
 | |
|         fxStatic->setLocked(true);
 | |
| 
 | |
|         // Store Shape in Replicated Shapes Vector.
 | |
|         mReplicatedShapes[mCurrentShapeCount++] = fxStatic;
 | |
| 
 | |
|     }
 | |
| }
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| void fxShapeReplicator::DestroyShapes(void)
 | |
| {
 | |
|     // Finish if we didn't create any shapes.
 | |
|     if (mCurrentShapeCount == 0) return;
 | |
| 
 | |
|     // Remove shapes.
 | |
|     for (U32 idx = 0; idx < mCurrentShapeCount; idx++)
 | |
|     {
 | |
|         fxShapeReplicatedStatic* fxStatic;
 | |
| 
 | |
|         // Fetch the Shape Object.
 | |
|         fxStatic = mReplicatedShapes[idx];
 | |
| 
 | |
|         // Got a Shape?
 | |
|         if (fxStatic)
 | |
|         {
 | |
|             // Unlock it.
 | |
|             fxStatic->setLocked(false);
 | |
| 
 | |
|             // Unregister the object.
 | |
|             fxStatic->unregisterObject();
 | |
| 
 | |
|             // Delete it.
 | |
|             delete fxStatic;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // Empty the Replicated Shapes Vector.
 | |
|     mReplicatedShapes.empty();
 | |
| 
 | |
|     // Reset Shape Count.
 | |
|     mCurrentShapeCount = 0;
 | |
| }
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| void fxShapeReplicator::RenewShapes(void)
 | |
| {
 | |
|     // Destroy any shapes.
 | |
|     DestroyShapes();
 | |
| 
 | |
|     // Don't create shapes on the Server if we don't need interactions.
 | |
|     if (isServerObject() && !mFieldData.mInteractions) return;
 | |
| 
 | |
|     // Create Shapes.
 | |
|     CreateShapes();
 | |
| }
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| void fxShapeReplicator::StartUp(void)
 | |
| {
 | |
|     // Flag, Client Replication Started.
 | |
|     mClientReplicationStarted = true;
 | |
| 
 | |
|     // Renew shapes.
 | |
|     RenewShapes();
 | |
| }
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| bool fxShapeReplicator::onAdd()
 | |
| {
 | |
|     if(!Parent::onAdd()) return(false);
 | |
| 
 | |
|     // Add the Replicator to the Replicator Set.
 | |
|     dynamic_cast<SimSet*>(Sim::findObject("fxReplicatorSet"))->addObject(this);
 | |
| 
 | |
|     // Set Default Object Box.
 | |
|     mObjBox.min.set( -0.5, -0.5, -0.5 );
 | |
|     mObjBox.max.set(  0.5,  0.5,  0.5 );
 | |
| 
 | |
|     // Reset the World Box.
 | |
|     resetWorldBox();
 | |
| 
 | |
|     // Are we editing the Mission?
 | |
|     if(gEditingMission)
 | |
|     {
 | |
|         // Yes, so set the Render Transform.
 | |
|         setRenderTransform(mObjToWorld);
 | |
| 
 | |
|         // Add to Scene.
 | |
|         addToScene();
 | |
|         mAddedToScene = true;
 | |
| 
 | |
|         // If we are in the editor and we are on the client then
 | |
|         // we can manually startup replication.
 | |
|         if (isClientObject()) mClientReplicationStarted = true;
 | |
|     }
 | |
| 
 | |
|     // Renew shapes on Server.
 | |
|     if (isServerObject()) RenewShapes();
 | |
| 
 | |
|     // Return OK.
 | |
|     return(true);
 | |
| }
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| void fxShapeReplicator::onRemove()
 | |
| {
 | |
|     // Remove the Replicator from the Replicator Set.
 | |
|     dynamic_cast<SimSet*>(Sim::findObject("fxReplicatorSet"))->removeObject(this);
 | |
| 
 | |
|     // Are we editing the Mission?
 | |
|     if(gEditingMission)
 | |
|     {
 | |
|         // Yes, so remove from Scene.
 | |
|         removeFromScene();
 | |
|         mAddedToScene = false;
 | |
|     }
 | |
| 
 | |
|     // Destroy Shapes.
 | |
|     DestroyShapes();
 | |
| 
 | |
|     // Do Parent.
 | |
|     Parent::onRemove();
 | |
| }
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| void fxShapeReplicator::inspectPostApply()
 | |
| {
 | |
|     // Set Parent.
 | |
|     Parent::inspectPostApply();
 | |
| 
 | |
| #if defined( TORQUE_OS_WIN32 ) && (_MSC_VER < 1400 && _MSC_VER >= 1310)
 | |
|    // This little oddity is here because of a bug which is thought to be a codegen bug with VS2003.
 | |
|    // Apparently doing this printf fixes it...
 | |
|    Con::printf( "Ignore this message." );
 | |
| #endif
 | |
|    
 | |
|     // Renew Shapes.
 | |
|     RenewShapes();
 | |
| 
 | |
|     // Set Replication Mask.
 | |
|     setMaskBits(ReplicationMask | advancedStaticOptionsMask);
 | |
| }
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| void fxShapeReplicator::onEditorEnable()
 | |
| {
 | |
|     // Are we in the Scene?
 | |
|     if(!mAddedToScene)
 | |
|     {
 | |
|         // No, so add to scene.
 | |
|         addToScene();
 | |
|         mAddedToScene = true;
 | |
|     }
 | |
| }
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| void fxShapeReplicator::onEditorDisable()
 | |
| {
 | |
|     // Are we in the Scene?
 | |
|     if(mAddedToScene)
 | |
|     {
 | |
|         // Yes, so remove from scene.
 | |
|         removeFromScene();
 | |
|         mAddedToScene = false;
 | |
|     }
 | |
| }
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| ConsoleFunction(StartClientReplication, void, 1, 1, "StartClientReplication()")
 | |
| {
 | |
|     // Find the Replicator Set.
 | |
|     SimSet *fxReplicatorSet = dynamic_cast<SimSet*>(Sim::findObject("fxReplicatorSet"));
 | |
| 
 | |
|     // Return if Error.
 | |
|     if (!fxReplicatorSet) return;
 | |
| 
 | |
|     // StartUp Replication Object.
 | |
|     for (SimSetIterator itr(fxReplicatorSet); *itr; ++itr)
 | |
|     {
 | |
|         // Fetch the Replicator Object.
 | |
|         fxShapeReplicator* Replicator = static_cast<fxShapeReplicator*>(*itr);
 | |
|         // Start Client Objects Only.
 | |
|         if (Replicator->isClientObject()) Replicator->StartUp();
 | |
|     }
 | |
|     // Info ...
 | |
|     Con::printf("Client Replication Startup has Happened!");
 | |
| }
 | |
| 
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| bool fxShapeReplicator::prepRenderImage(SceneState* state, const U32 stateKey, const U32 startZone,
 | |
|                                 const bool modifyBaseZoneState)
 | |
| {
 | |
|     // Return if last state.
 | |
|     if (isLastState(state, stateKey)) return false;
 | |
|     // Set Last State.
 | |
|     setLastState(state, stateKey);
 | |
| 
 | |
|    // Is Object Rendered?
 | |
|    if (state->isObjectRendered(this))
 | |
|    {
 | |
|         // Yes, so get a SceneRenderImage.
 | |
|         SceneRenderImage* image = new SceneRenderImage;
 | |
|         // Populate it.
 | |
|         image->obj = this;
 | |
|         image->sortType = SceneRenderImage::Normal;
 | |
|         // Insert it into the scene images.
 | |
|         state->insertRenderImage(image);
 | |
|    }
 | |
| 
 | |
|    return false;
 | |
| }
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| void fxShapeReplicator::renderObject(SceneState* state, SceneRenderImage*)
 | |
| {
 | |
|     // Return if placement area not needed.
 | |
|     if (!mFieldData.mShowPlacementArea) return;
 | |
| 
 | |
|     PROFILE_START(ShapeReplicator_renderObject);
 | |
| 
 | |
|     // Check we are in Canonical State.
 | |
|     AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on entry");
 | |
| 
 | |
|     // Setup out the Projection Matrix/Viewport.
 | |
|     RectI viewport;
 | |
|     glMatrixMode(GL_PROJECTION);
 | |
|     glPushMatrix();
 | |
|     dglGetViewport(&viewport);
 | |
|     state->setupBaseProjection();
 | |
| 
 | |
|     // Setup our rendering state.
 | |
|     glPushMatrix();
 | |
|     dglMultMatrix(&getTransform());
 | |
|     glEnable(GL_BLEND);
 | |
|     glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
 | |
| 
 | |
|     // Do we need to draw the Inner Radius?
 | |
|     if (mFieldData.mInnerRadiusX || mFieldData.mInnerRadiusY)
 | |
|     {
 | |
|         // Yes, so draw Inner Radius.
 | |
|         glBegin(GL_TRIANGLE_STRIP);
 | |
|         for (U32 Angle = mCreationAreaAngle; Angle < (mCreationAreaAngle+360); Angle++)
 | |
|         {
 | |
|             F32     XPos, YPos;
 | |
| 
 | |
|             // Calculate Position.
 | |
|             XPos = mFieldData.mInnerRadiusX * mCos(mDegToRad(-(F32)Angle));
 | |
|             YPos = mFieldData.mInnerRadiusY * mSin(mDegToRad(-(F32)Angle));
 | |
| 
 | |
|             // Set Colour.
 | |
|             glColor4f(  mFieldData.mPlaceAreaColour.red,
 | |
|                         mFieldData.mPlaceAreaColour.green,
 | |
|                         mFieldData.mPlaceAreaColour.blue,
 | |
|                         AREA_ANIMATION_ARC * (Angle-mCreationAreaAngle));
 | |
| 
 | |
|             // Draw Arc Line.
 | |
|             glVertex3f( XPos, YPos, -(F32)mFieldData.mPlacementBandHeight/2.0f);
 | |
|             glVertex3f( XPos, YPos, +(F32)mFieldData.mPlacementBandHeight/2.0f);
 | |
| 
 | |
|         }
 | |
|         glEnd();
 | |
|     }
 | |
| 
 | |
|     // Do we need to draw the Outer Radius?
 | |
|     if (mFieldData.mOuterRadiusX || mFieldData.mOuterRadiusY)
 | |
|     {
 | |
|         // Yes, so draw Outer Radius.
 | |
|         glBegin(GL_TRIANGLE_STRIP);
 | |
|         for (U32 Angle = mCreationAreaAngle; Angle < (mCreationAreaAngle+360); Angle++)
 | |
|         {
 | |
|             F32     XPos, YPos;
 | |
| 
 | |
|             // Calculate Position.
 | |
|             XPos = mFieldData.mOuterRadiusX * mCos(mDegToRad(-(F32)Angle));
 | |
|             YPos = mFieldData.mOuterRadiusY * mSin(mDegToRad(-(F32)Angle));
 | |
| 
 | |
|             // Set Colour.
 | |
|             glColor4f(  mFieldData.mPlaceAreaColour.red,
 | |
|                         mFieldData.mPlaceAreaColour.green,
 | |
|                         mFieldData.mPlaceAreaColour.blue,
 | |
|                         AREA_ANIMATION_ARC * (Angle-mCreationAreaAngle));
 | |
| 
 | |
|             // Draw Arc Line.
 | |
|             glVertex3f( XPos, YPos, -(F32)mFieldData.mPlacementBandHeight/2.0f);
 | |
|             glVertex3f( XPos, YPos, +(F32)mFieldData.mPlacementBandHeight/2.0f);
 | |
| 
 | |
|         }
 | |
|         glEnd();
 | |
|     }
 | |
| 
 | |
|     // Restore rendering state.
 | |
|     glDisable(GL_BLEND);
 | |
|     glPopMatrix();
 | |
| 
 | |
|     // Animate Area Selection.
 | |
|     mCreationAreaAngle += 20;
 | |
|     mCreationAreaAngle = mCreationAreaAngle % 360;
 | |
| 
 | |
|     // Restore out nice and friendly canonical state.
 | |
|     glMatrixMode(GL_PROJECTION);
 | |
|     glPopMatrix();
 | |
|     glMatrixMode(GL_MODELVIEW);
 | |
|     dglSetViewport(viewport);
 | |
| 
 | |
|     // Check we have restored Canonical State.
 | |
|     AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on exit");
 | |
| 
 | |
|     PROFILE_END();
 | |
| }
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| U32 fxShapeReplicator::packUpdate(NetConnection * con, U32 mask, BitStream * stream)
 | |
| {
 | |
|     // Pack Parent.
 | |
|     U32 retMask = Parent::packUpdate(con, mask, stream);
 | |
| 
 | |
|    if(stream->writeFlag(mask & advancedStaticOptionsMask))
 | |
|    {
 | |
| 	   stream->writeFlag(receiveSunLight);
 | |
| 	   stream->writeFlag(useAdaptiveSelfIllumination);
 | |
| 	   stream->writeFlag(useCustomAmbientLighting);
 | |
| 	   stream->writeFlag(customAmbientForSelfIllumination);
 | |
| 	   stream->write(customAmbientLighting);
 | |
| 	   stream->writeFlag(receiveLMLighting);
 | |
|       stream->writeFlag(useLightingOcclusion);
 | |
| 
 | |
| 	   if(isServerObject())
 | |
| 	   {
 | |
| 		   lightIds.clear();
 | |
| 		   findLightGroup(con);
 | |
| 
 | |
| 		   U32 maxcount = getMin(lightIds.size(), SG_TSSTATIC_MAX_LIGHTS);
 | |
| 		   stream->writeInt(maxcount, SG_TSSTATIC_MAX_LIGHT_SHIFT);
 | |
| 		   for(U32 i=0; i<maxcount; i++)
 | |
| 		   {
 | |
| 			   stream->writeInt(lightIds[i], NetConnection::GhostIdBitSize);
 | |
| 		   }
 | |
| 	   }
 | |
| 	   else
 | |
| 	   {
 | |
| 		   // recording demo...
 | |
| 		   U32 maxcount = getMin(lightIds.size(), SG_TSSTATIC_MAX_LIGHTS);
 | |
| 		   stream->writeInt(maxcount, SG_TSSTATIC_MAX_LIGHT_SHIFT);
 | |
| 		   for(U32 i=0; i<maxcount; i++)
 | |
| 		   {
 | |
| 			   stream->writeInt(lightIds[i], NetConnection::GhostIdBitSize);
 | |
| 		   }
 | |
| 	   }
 | |
|    }
 | |
|    
 | |
|     // Write Replication Flag.
 | |
|     if (stream->writeFlag(mask & ReplicationMask))
 | |
|     {
 | |
|         stream->writeAffineTransform(mObjToWorld);                      // Replicator Position.
 | |
| 
 | |
|         stream->writeInt(mFieldData.mSeed, 32);                         // Replicator Seed.
 | |
|         stream->writeInt(mFieldData.mShapeCount, 32);                   // Shapes Count.
 | |
|         stream->writeInt(mFieldData.mShapeRetries, 32);                 // Shapes Retries.
 | |
|         stream->writeString(mFieldData.mShapeFile);
 | |
|         stream->writeInt(mFieldData.mInnerRadiusX, 32);                 // Shapes Inner Radius X.
 | |
|         stream->writeInt(mFieldData.mInnerRadiusY, 32);                 // Shapes Inner Radius Y.
 | |
|         stream->writeInt(mFieldData.mOuterRadiusX, 32);                 // Shapes Outer Radius X.
 | |
|         stream->writeInt(mFieldData.mOuterRadiusY, 32);                 // Shapes Outer Radius Y.
 | |
|         stream->writeFlag(mFieldData.mFixShapeAspect);                  // Lock the aspect ratio for scaling
 | |
|         mathWrite(*stream, mFieldData.mShapeScaleMin);                  // Shapes Scale Min.
 | |
|         mathWrite(*stream, mFieldData.mShapeScaleMax);                  // Shapes Scale Max.
 | |
|         mathWrite(*stream, mFieldData.mShapeRotateMin);                 // Shapes Rotate Min.
 | |
|         mathWrite(*stream, mFieldData.mShapeRotateMax);                 // Shapes Rotate Max.
 | |
|         stream->writeSignedInt(mFieldData.mOffsetZ, 32);                // Shapes Offset Z.
 | |
|         stream->writeFlag(mFieldData.mAllowOnTerrain);                  // Allow on Terrain.
 | |
|         stream->writeFlag(mFieldData.mAllowOnInteriors);                // Allow on Interiors.
 | |
|         stream->writeFlag(mFieldData.mAllowStatics);                    // Allow on Statics.
 | |
|         stream->writeFlag(mFieldData.mAllowOnWater);                    // Allow on Water.
 | |
|         stream->writeFlag(mFieldData.mAllowWaterSurface);               // Allow on Water Surface.
 | |
|         stream->writeSignedInt(mFieldData.mAllowedTerrainSlope, 32);    // Shapes Offset Z.
 | |
|         stream->writeFlag(mFieldData.mAlignToTerrain);                  // Shapes AlignToTerrain.
 | |
|         mathWrite(*stream, mFieldData.mTerrainAlignment);               // Write Terrain Alignment.
 | |
|         stream->writeFlag(mFieldData.mHideReplications);                // Hide Replications.
 | |
|         stream->writeFlag(mFieldData.mInteractions);                    // Shape Interactions.
 | |
|         stream->writeFlag(mFieldData.mShowPlacementArea);               // Show Placement Area Flag.
 | |
|         stream->writeInt(mFieldData.mPlacementBandHeight, 32);          // Placement Area Height.
 | |
|         stream->write(mFieldData.mPlaceAreaColour);
 | |
|     }
 | |
| 
 | |
|     // Were done ...
 | |
|     return(retMask);
 | |
| }
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| void fxShapeReplicator::unpackUpdate(NetConnection * con, BitStream * stream)
 | |
| {
 | |
|     // Unpack Parent.
 | |
|     Parent::unpackUpdate(con, stream);
 | |
| 
 | |
|    if(stream->readFlag())
 | |
|    {
 | |
| 	   receiveSunLight = stream->readFlag();
 | |
| 	   useAdaptiveSelfIllumination = stream->readFlag();
 | |
| 	   useCustomAmbientLighting = stream->readFlag();
 | |
| 	   customAmbientForSelfIllumination = stream->readFlag();
 | |
| 	   stream->read(&customAmbientLighting);
 | |
| 	   receiveLMLighting = stream->readFlag();
 | |
|       useLightingOcclusion = stream->readFlag();
 | |
| 
 | |
| 	   U32 count = stream->readInt(SG_TSSTATIC_MAX_LIGHT_SHIFT);
 | |
| 	   lightIds.clear();
 | |
| 	   for(U32 i=0; i<count; i++)
 | |
| 	   {
 | |
| 		   S32 id = stream->readInt(NetConnection::GhostIdBitSize);
 | |
| 		   lightIds.push_back(id);
 | |
| 	   }
 | |
|    }
 | |
|    
 | |
|     // Read Replication Details.
 | |
|     if(stream->readFlag())
 | |
|     {
 | |
|         MatrixF     ReplicatorObjectMatrix;
 | |
| 
 | |
|         stream->readAffineTransform(&ReplicatorObjectMatrix);               // Replication Position.
 | |
| 
 | |
|         mFieldData.mSeed                    = stream->readInt(32);          // Replicator Seed.
 | |
|         mFieldData.mShapeCount              = stream->readInt(32);          // Shapes Count.
 | |
|         mFieldData.mShapeRetries            = stream->readInt(32);          // Shapes Retries.
 | |
|         mFieldData.mShapeFile               = stream->readSTString();       // Shape File.
 | |
|         mFieldData.mInnerRadiusX            = stream->readInt(32);          // Shapes Inner Radius X.
 | |
|         mFieldData.mInnerRadiusY            = stream->readInt(32);          // Shapes Inner Radius Y.
 | |
|         mFieldData.mOuterRadiusX            = stream->readInt(32);          // Shapes Outer Radius X.
 | |
|         mFieldData.mOuterRadiusY            = stream->readInt(32);          // Shapes Outer Radius Y.
 | |
|         mFieldData.mFixShapeAspect          = stream->readFlag();           // Lock the aspect ratio for scaling
 | |
|         mathRead(*stream, &mFieldData.mShapeScaleMin);                      // Shapes Scale Min.
 | |
|         mathRead(*stream, &mFieldData.mShapeScaleMax);                      // Shapes Scale Max.
 | |
|         mathRead(*stream, &mFieldData.mShapeRotateMin);                     // Shapes Rotate Min.
 | |
|         mathRead(*stream, &mFieldData.mShapeRotateMax);                     // Shapes Rotate Max.
 | |
|         mFieldData.mOffsetZ                 = stream->readSignedInt(32);    // Shapes Offset Z.
 | |
|         mFieldData.mAllowOnTerrain          = stream->readFlag();           // Allow on Terrain.
 | |
|         mFieldData.mAllowOnInteriors        = stream->readFlag();           // Allow on Interiors.
 | |
|         mFieldData.mAllowStatics            = stream->readFlag();           // Allow on Statics.
 | |
|         mFieldData.mAllowOnWater            = stream->readFlag();           // Allow on Water.
 | |
|         mFieldData.mAllowWaterSurface       = stream->readFlag();           // Allow on Water Surface.
 | |
|         mFieldData.mAllowedTerrainSlope     = stream->readSignedInt(32);    // Allowed Terrain Slope.
 | |
|         mFieldData.mAlignToTerrain          = stream->readFlag();           // Read AlignToTerrain.
 | |
|         mathRead(*stream, &mFieldData.mTerrainAlignment);                   // Read Terrain Alignment.
 | |
|         mFieldData.mHideReplications        = stream->readFlag();           // Hide Replications.
 | |
|         mFieldData.mInteractions            = stream->readFlag();           // Read Interactions.
 | |
|         mFieldData.mShowPlacementArea   = stream->readFlag();               // Show Placement Area Flag.
 | |
|         mFieldData.mPlacementBandHeight = stream->readInt(32);              // Placement Area Height.
 | |
|         stream->read(&mFieldData.mPlaceAreaColour);
 | |
| 
 | |
|         // Set Transform.
 | |
|         setTransform(ReplicatorObjectMatrix);
 | |
| 
 | |
|         // Renew Shapes (only if replication has started).
 | |
|         if (mClientReplicationStarted) RenewShapes();
 | |
|     }
 | |
| }
 | |
| 
 | 
