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();
|
|
}
|
|
}
|
|
|