2012-09-19 15:15:01 +00:00
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
# include "platform/platform.h"
# include "T3D/fx/fxShapeReplicator.h"
# include "gfx/gfxDevice.h"
# include "gfx/primBuilder.h"
# include "console/consoleTypes.h"
# include "core/stream/bitStream.h"
# include "math/mRandom.h"
# include "math/mathIO.h"
# include "T3D/gameBase/gameConnection.h"
# include "scene/sceneManager.h"
# include "scene/sceneRenderState.h"
# include "renderInstance/renderPassManager.h"
# include "console/engineAPI.h"
//------------------------------------------------------------------------------
//
2020-12-12 15:54:16 +00:00
// Put this in /example/common/editor/editor.tscript in function [Editor::create()] (around line 66).
2012-09-19 15:15:01 +00:00
//
// // Ignore Replicated fxStatic Instances.
// EWorldEditor.ignoreObjClass("fxShapeReplicatedStatic");
//
//------------------------------------------------------------------------------
//
2020-12-12 15:54:16 +00:00
// Put this in /example/common/editor/EditorGui.tscript in [function Creator::init( %this )]
2012-09-19 15:15:01 +00:00
//
// %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();
// }
//
//------------------------------------------------------------------------------
//
2020-12-12 15:54:16 +00:00
// Put this in /example/common/client/missionDownload.tscript in [function clientCmdMissionStartPhase3(%seq,%missionName)] (line 65)
2012-09-19 15:15:01 +00:00
// 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 ) ;
ConsoleDocClass ( fxShapeReplicator ,
" @brief An emitter for objects to replicate across an area. \n "
" @ingroup Foliage \n "
) ;
ConsoleDocClass ( fxShapeReplicatedStatic ,
" @brief The object definition for shapes that will be replicated across an area using an fxShapeReplicator. \n "
" @ingroup Foliage \n "
) ;
//------------------------------------------------------------------------------
// Class: fxShapeReplicator
//------------------------------------------------------------------------------
fxShapeReplicator : : fxShapeReplicator ( )
{
// Setup NetObject.
mTypeMask | = StaticObjectType ;
mNetFlags . set ( Ghostable | ScopeAlways ) ;
// Reset Shape Count.
mCurrentShapeCount = 0 ;
// Reset Creation Area Angle Animation.
mCreationAreaAngle = 0 ;
// Reset Last Render Time.
mLastRenderTime = 0 ;
mPlacementSB = NULL ;
}
//------------------------------------------------------------------------------
fxShapeReplicator : : ~ fxShapeReplicator ( )
{
mPlacementSB = NULL ;
}
//------------------------------------------------------------------------------
void fxShapeReplicator : : initPersistFields ( )
{
2023-01-27 07:13:15 +00:00
docsURL ;
2012-09-19 15:15:01 +00:00
// Add out own persistent fields.
addGroup ( " Debugging " ) ; // MM: Added Group Header.
addField ( " HideReplications " , TypeBool , Offset ( mFieldData . mHideReplications , fxShapeReplicator ) , " Replicated shapes are hidden when set to true. " ) ;
addField ( " ShowPlacementArea " , TypeBool , Offset ( mFieldData . mShowPlacementArea , fxShapeReplicator ) , " Draw placement rings when set to true. " ) ;
addField ( " PlacementAreaHeight " , TypeS32 , Offset ( mFieldData . mPlacementBandHeight , fxShapeReplicator ) , " Height of the placement ring in world units. " ) ;
addField ( " PlacementColour " , TypeColorF , Offset ( mFieldData . mPlaceAreaColour , fxShapeReplicator ) , " Color of the placement ring. " ) ;
endGroup ( " Debugging " ) ; // MM: Added Group Footer.
addGroup ( " Media " ) ; // MM: Added Group Header.
addField ( " ShapeFile " , TypeShapeFilename , Offset ( mFieldData . mShapeFile , fxShapeReplicator ) , " Filename of shape to replicate. " ) ;
endGroup ( " Media " ) ; // MM: Added Group Footer.
addGroup ( " Replications " ) ; // MM: Added Group Header.
addField ( " Seed " , TypeS32 , Offset ( mFieldData . mSeed , fxShapeReplicator ) , " Random seed for shape placement. " ) ;
addField ( " ShapeCount " , TypeS32 , Offset ( mFieldData . mShapeCount , fxShapeReplicator ) , " Maximum shape instance count. " ) ;
addField ( " ShapeRetries " , TypeS32 , Offset ( mFieldData . mShapeRetries , fxShapeReplicator ) , " Number of times to try placing a shape instance before giving up. " ) ;
endGroup ( " Replications " ) ; // MM: Added Group Footer.
addGroup ( " Placement Radius " ) ; // MM: Added Group Header.
addField ( " InnerRadiusX " , TypeS32 , Offset ( mFieldData . mInnerRadiusX , fxShapeReplicator ) , " Placement area inner radius on the X axis " ) ;
addField ( " InnerRadiusY " , TypeS32 , Offset ( mFieldData . mInnerRadiusY , fxShapeReplicator ) , " Placement area inner radius on the Y axis " ) ;
addField ( " OuterRadiusX " , TypeS32 , Offset ( mFieldData . mOuterRadiusX , fxShapeReplicator ) , " Placement area outer radius on the X axis " ) ;
addField ( " OuterRadiusY " , TypeS32 , Offset ( mFieldData . mOuterRadiusY , fxShapeReplicator ) , " Placement area outer radius on the Y axis " ) ;
endGroup ( " Placement Radius " ) ; // MM: Added Group Footer.
addGroup ( " Restraints " ) ; // MM: Added Group Header.
addField ( " AllowOnTerrain " , TypeBool , Offset ( mFieldData . mAllowOnTerrain , fxShapeReplicator ) , " Shapes will be placed on terrain when set. " ) ;
addField ( " AllowOnStatics " , TypeBool , Offset ( mFieldData . mAllowStatics , fxShapeReplicator ) , " Shapes will be placed on Static shapes when set. " ) ;
addField ( " AllowOnWater " , TypeBool , Offset ( mFieldData . mAllowOnWater , fxShapeReplicator ) , " Shapes will be placed on/under water when set. " ) ;
addField ( " AllowWaterSurface " , TypeBool , Offset ( mFieldData . mAllowWaterSurface , fxShapeReplicator ) , " Shapes will be placed on water when set. Requires AllowOnWater. " ) ;
addField ( " AlignToTerrain " , TypeBool , Offset ( mFieldData . mAlignToTerrain , fxShapeReplicator ) , " Align shapes to surface normal when set. " ) ;
addField ( " Interactions " , TypeBool , Offset ( mFieldData . mInteractions , fxShapeReplicator ) , " Allow physics interactions with shapes. " ) ;
addField ( " AllowedTerrainSlope " , TypeS32 , Offset ( mFieldData . mAllowedTerrainSlope , fxShapeReplicator ) , " Maximum surface angle allowed for shape instances. " ) ;
addField ( " TerrainAlignment " , TypePoint3F , Offset ( mFieldData . mTerrainAlignment , fxShapeReplicator ) , " Surface normals will be multiplied by these values when AlignToTerrain is enabled. " ) ;
endGroup ( " Restraints " ) ; // MM: Added Group Footer.
addGroup ( " Object Transforms " ) ; // MM: Added Group Header.
addField ( " ShapeScaleMin " , TypePoint3F , Offset ( mFieldData . mShapeScaleMin , fxShapeReplicator ) , " Minimum shape scale. " ) ;
addField ( " ShapeScaleMax " , TypePoint3F , Offset ( mFieldData . mShapeScaleMax , fxShapeReplicator ) , " Maximum shape scale. " ) ;
addField ( " ShapeRotateMin " , TypePoint3F , Offset ( mFieldData . mShapeRotateMin , fxShapeReplicator ) , " Minimum shape rotation angles. " ) ;
addField ( " ShapeRotateMax " , TypePoint3F , Offset ( mFieldData . mShapeRotateMax , fxShapeReplicator ) , " Maximum shape rotation angles. " ) ;
addField ( " OffsetZ " , TypeS32 , Offset ( mFieldData . mOffsetZ , fxShapeReplicator ) , " Offset shapes by this amount vertically. " ) ;
endGroup ( " Object Transforms " ) ; // MM: Added Group Footer.
// Initialise parents' persistent fields.
Parent : : initPersistFields ( ) ;
}
//------------------------------------------------------------------------------
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 ;
// Don't create shapes if we are hiding replications.
if ( mFieldData . mHideReplications ) return ;
// Cannot continue without shapes!
2020-10-03 12:37:55 +00:00
if ( String : : compare ( mFieldData . mShapeFile , " " ) = = 0 ) return ;
2012-09-19 15:15:01 +00:00
// Check that we can position somewhere!
if ( ! ( mFieldData . mAllowOnTerrain | |
mFieldData . mAllowStatics | |
mFieldData . mAllowOnWater ) )
{
// Problem ...
Con : : warnf ( ConsoleLogEntry : : General , " [%s] - Could not place object, All alloweds are off! " , getName ( ) ) ;
// Return here.
return ;
}
// Check Shapes.
2015-02-02 23:24:01 +00:00
AssertFatal ( mCurrentShapeCount = = 0 , " Shapes already present, this should not be possible! " ) ;
2012-09-19 15:15:01 +00:00
// Check that we have a shape...
if ( ! mFieldData . mShapeFile ) return ;
// Set Seed.
RandomGen . setSeed ( mFieldData . mSeed ) ;
// Set shape vector.
mReplicatedShapes . clear ( ) ;
// Add shapes.
for ( U32 idx = 0 ; idx < mFieldData . mShapeCount ; idx + + )
{
fxShapeReplicatedStatic * fxStatic ;
// Create our static shape.
fxStatic = new fxShapeReplicatedStatic ( ) ;
// 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
{
// Get the Replicator Position.
ShapePosition = getPosition ( ) ;
// Calculate a random offset
HypX = RandomGen . randF ( mFieldData . mInnerRadiusX , mFieldData . mOuterRadiusX ) ;
HypY = RandomGen . randF ( mFieldData . mInnerRadiusY , mFieldData . mOuterRadiusY ) ;
Angle = RandomGen . randF ( 0 , ( F32 ) M_2PI ) ;
// Calcualte the new position.
ShapePosition . x + = HypX * mCos ( Angle ) ;
ShapePosition . y + = HypY * mSin ( Angle ) ;
// 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 & StaticShapeObjectType ) & & ! 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] - Could not find satisfactory position for shape '%s' on %s! " , getName ( ) , 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.
ShapeScale . set ( RandomGen . randF ( mFieldData . mShapeScaleMin . x , mFieldData . mShapeScaleMax . x ) ,
RandomGen . randF ( mFieldData . mShapeScaleMin . y , mFieldData . mShapeScaleMax . y ) ,
RandomGen . randF ( mFieldData . mShapeScaleMin . z , mFieldData . mShapeScaleMax . z ) ) ;
// Set Shape Scale.
fxStatic - > setScale ( ShapeScale ) ;
// Lock it.
fxStatic - > setLocked ( true ) ;
// Store Shape in Replicated Shapes Vector.
//mReplicatedShapes[mCurrentShapeCount++] = fxStatic;
mReplicatedShapes . push_back ( fxStatic ) ;
}
mCurrentShapeCount = mReplicatedShapes . size ( ) ;
// Take first Timestamp.
mLastRenderTime = Platform : : getVirtualMilliseconds ( ) ;
}
//------------------------------------------------------------------------------
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 . clear ( ) ;
// 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 )
{
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 . minExtents . set ( - 0.5 , - 0.5 , - 0.5 ) ;
mObjBox . maxExtents . set ( 0.5 , 0.5 , 0.5 ) ;
resetWorldBox ( ) ;
// Add to Scene.
setRenderTransform ( mObjToWorld ) ;
addToScene ( ) ;
// Register for notification when GhostAlways objects are done loading
NetConnection : : smGhostAlwaysDone . notify ( this , & fxShapeReplicator : : onGhostAlwaysDone ) ;
return true ;
}
//------------------------------------------------------------------------------
void fxShapeReplicator : : onRemove ( )
{
// Remove the Replicator from the Replicator Set.
dynamic_cast < SimSet * > ( Sim : : findObject ( " fxReplicatorSet " ) ) - > removeObject ( this ) ;
NetConnection : : smGhostAlwaysDone . remove ( this , & fxShapeReplicator : : onGhostAlwaysDone ) ;
removeFromScene ( ) ;
// Destroy Shapes.
DestroyShapes ( ) ;
// Do Parent.
Parent : : onRemove ( ) ;
}
//------------------------------------------------------------------------------
void fxShapeReplicator : : onGhostAlwaysDone ( )
{
RenewShapes ( ) ;
}
//------------------------------------------------------------------------------
void fxShapeReplicator : : inspectPostApply ( )
{
// Set Parent.
Parent : : inspectPostApply ( ) ;
// Renew Shapes.
RenewShapes ( ) ;
// Set Replication Mask.
setMaskBits ( ReplicationMask ) ;
}
//------------------------------------------------------------------------------
DefineEngineFunction ( StartClientReplication , void , ( ) , , " Activates the shape replicator. \n "
" @tsexample \n "
" // Call the function \n "
" StartClientReplication() \n "
" @endtsexample \n "
" @ingroup Foliage "
)
{
// 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! " ) ;
}
//------------------------------------------------------------------------------
void fxShapeReplicator : : prepRenderImage ( SceneRenderState * state )
{
ObjectRenderInst * ri = state - > getRenderPass ( ) - > allocInst < ObjectRenderInst > ( ) ;
ri - > renderDelegate . bind ( this , & fxShapeReplicator : : renderObject ) ;
// The fxShapeReplicator isn't technically foliage but our debug
// effect seems to render best as a Foliage type (translucent,
// renders itself, no sorting)
ri - > type = RenderPassManager : : RIT_Foliage ;
state - > getRenderPass ( ) - > addInst ( ri ) ;
}
//------------------------------------------------------------------------------
// Renders a triangle stripped oval
void fxShapeReplicator : : renderArc ( const F32 fRadiusX , const F32 fRadiusY )
{
PrimBuild : : begin ( GFXTriangleStrip , 720 ) ;
for ( U32 Angle = mCreationAreaAngle ; Angle < ( mCreationAreaAngle + 360 ) ; Angle + + )
{
F32 XPos , YPos ;
// Calculate Position.
XPos = fRadiusX * mCos ( mDegToRad ( - ( F32 ) Angle ) ) ;
YPos = fRadiusY * mSin ( mDegToRad ( - ( F32 ) Angle ) ) ;
// Set Colour.
PrimBuild : : color4f ( mFieldData . mPlaceAreaColour . red ,
mFieldData . mPlaceAreaColour . green ,
mFieldData . mPlaceAreaColour . blue ,
AREA_ANIMATION_ARC * ( Angle - mCreationAreaAngle ) ) ;
PrimBuild : : vertex3f ( XPos , YPos , - ( F32 ) mFieldData . mPlacementBandHeight / 2.0f ) ;
PrimBuild : : vertex3f ( XPos , YPos , + ( F32 ) mFieldData . mPlacementBandHeight / 2.0f ) ;
}
PrimBuild : : end ( ) ;
}
// This currently uses the primbuilder, could convert out, but why allocate the buffer if we
// never edit the misison?
void fxShapeReplicator : : renderPlacementArea ( const F32 ElapsedTime )
{
if ( gEditingMission & & mFieldData . mShowPlacementArea )
{
GFX - > pushWorldMatrix ( ) ;
GFX - > multWorld ( getTransform ( ) ) ;
if ( ! mPlacementSB )
{
GFXStateBlockDesc transparent ;
transparent . setCullMode ( GFXCullNone ) ;
transparent . alphaTestEnable = true ;
transparent . setZReadWrite ( true ) ;
transparent . zWriteEnable = false ;
transparent . setBlend ( true , GFXBlendSrcAlpha , GFXBlendInvSrcAlpha ) ;
mPlacementSB = GFX - > createStateBlock ( transparent ) ;
}
GFX - > setStateBlock ( mPlacementSB ) ;
// Do we need to draw the Outer Radius?
if ( mFieldData . mOuterRadiusX | | mFieldData . mOuterRadiusY )
renderArc ( ( F32 ) mFieldData . mOuterRadiusX , ( F32 ) mFieldData . mOuterRadiusY ) ;
// Inner radius?
if ( mFieldData . mInnerRadiusX | | mFieldData . mInnerRadiusY )
renderArc ( ( F32 ) mFieldData . mInnerRadiusX , ( F32 ) mFieldData . mInnerRadiusY ) ;
GFX - > popWorldMatrix ( ) ;
mCreationAreaAngle = ( U32 ) ( mCreationAreaAngle + ( 1000 * ElapsedTime ) ) ;
mCreationAreaAngle = mCreationAreaAngle % 360 ;
}
}
//------------------------------------------------------------------------------
void fxShapeReplicator : : renderObject ( ObjectRenderInst * ri , SceneRenderState * state , BaseMatInstance * overrideMat )
{
if ( overrideMat )
return ;
// Return if placement area not needed.
if ( ! mFieldData . mShowPlacementArea )
return ;
// Calculate Elapsed Time and take new Timestamp.
S32 Time = Platform : : getVirtualMilliseconds ( ) ;
F32 ElapsedTime = ( Time - mLastRenderTime ) * 0.001f ;
mLastRenderTime = Time ;
renderPlacementArea ( ElapsedTime ) ;
}
//------------------------------------------------------------------------------
U32 fxShapeReplicator : : packUpdate ( NetConnection * con , U32 mask , BitStream * stream )
{
// Pack Parent.
U32 retMask = Parent : : packUpdate ( con , mask , stream ) ;
// Write Replication Flag.
if ( stream - > writeFlag ( mask & ReplicationMask ) )
{
stream - > writeAffineTransform ( mObjToWorld ) ; // Replicator Position.
2025-03-09 16:53:23 +00:00
stream - > write ( mFieldData . mSeed ) ; // Replicator Seed.
stream - > write ( mFieldData . mShapeCount ) ; // Shapes Count.
stream - > write ( mFieldData . mShapeRetries ) ; // Shapes Retries.
2012-09-19 15:15:01 +00:00
stream - > writeString ( mFieldData . mShapeFile ) ;
2025-03-09 16:53:23 +00:00
stream - > write ( mFieldData . mInnerRadiusX ) ; // Shapes Inner Radius X.
stream - > write ( mFieldData . mInnerRadiusY ) ; // Shapes Inner Radius Y.
stream - > write ( mFieldData . mOuterRadiusX ) ; // Shapes Outer Radius X.
stream - > write ( mFieldData . mOuterRadiusY ) ; // Shapes Outer Radius Y.
2012-09-19 15:15:01 +00:00
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.
2025-03-09 16:53:23 +00:00
stream - > write ( mFieldData . mOffsetZ ) ; // Shapes Offset Z.
2012-09-19 15:15:01 +00:00
stream - > writeFlag ( mFieldData . mAllowOnTerrain ) ; // Allow on Terrain.
stream - > writeFlag ( mFieldData . mAllowStatics ) ; // Allow on Statics.
stream - > writeFlag ( mFieldData . mAllowOnWater ) ; // Allow on Water.
stream - > writeFlag ( mFieldData . mAllowWaterSurface ) ; // Allow on Water Surface.
2025-03-09 16:53:23 +00:00
stream - > write ( mFieldData . mAllowedTerrainSlope ) ; // Shapes Offset Z.
2012-09-19 15:15:01 +00:00
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.
2025-03-09 16:53:23 +00:00
stream - > write ( mFieldData . mPlacementBandHeight ) ; // Placement Area Height.
2012-09-19 15:15:01 +00:00
stream - > write ( mFieldData . mPlaceAreaColour ) ;
}
// Were done ...
return ( retMask ) ;
}
//------------------------------------------------------------------------------
void fxShapeReplicator : : unpackUpdate ( NetConnection * con , BitStream * stream )
{
// Unpack Parent.
Parent : : unpackUpdate ( con , stream ) ;
// Read Replication Details.
if ( stream - > readFlag ( ) )
{
MatrixF ReplicatorObjectMatrix ;
stream - > readAffineTransform ( & ReplicatorObjectMatrix ) ; // Replication Position.
2025-03-09 16:53:23 +00:00
stream - > read ( & mFieldData . mSeed ) ; // Replicator Seed.
stream - > read ( & mFieldData . mShapeCount ) ; // Shapes Count.
stream - > read ( & mFieldData . mShapeRetries ) ; // Shapes Retries.
2012-09-19 15:15:01 +00:00
mFieldData . mShapeFile = stream - > readSTString ( ) ; // Shape File.
2025-03-09 16:53:23 +00:00
stream - > read ( & mFieldData . mInnerRadiusX ) ; // Shapes Inner Radius X.
stream - > read ( & mFieldData . mInnerRadiusY ) ; // Shapes Inner Radius Y.
stream - > read ( & mFieldData . mOuterRadiusX ) ; // Shapes Outer Radius X.
stream - > read ( & mFieldData . mOuterRadiusY ) ; // Shapes Outer Radius Y.
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.
stream - > read ( & mFieldData . mOffsetZ ) ; // Shapes Offset Z.
2012-09-19 15:15:01 +00:00
mFieldData . mAllowOnTerrain = stream - > readFlag ( ) ; // Allow on Terrain.
mFieldData . mAllowStatics = stream - > readFlag ( ) ; // Allow on Statics.
mFieldData . mAllowOnWater = stream - > readFlag ( ) ; // Allow on Water.
mFieldData . mAllowWaterSurface = stream - > readFlag ( ) ; // Allow on Water Surface.
2025-03-09 16:53:23 +00:00
stream - > read ( & mFieldData . mAllowedTerrainSlope ) ; // Allowed Terrain Slope.
2012-09-19 15:15:01 +00:00
mFieldData . mAlignToTerrain = stream - > readFlag ( ) ; // Read AlignToTerrain.
2025-03-09 16:53:23 +00:00
mathRead ( * stream , & mFieldData . mTerrainAlignment ) ; // Read Terrain Alignment.
2012-09-19 15:15:01 +00:00
mFieldData . mHideReplications = stream - > readFlag ( ) ; // Hide Replications.
mFieldData . mInteractions = stream - > readFlag ( ) ; // Read Interactions.
mFieldData . mShowPlacementArea = stream - > readFlag ( ) ; // Show Placement Area Flag.
2025-03-09 16:53:23 +00:00
stream - > read ( & mFieldData . mPlacementBandHeight ) ; // Placement Area Height.
2012-09-19 15:15:01 +00:00
stream - > read ( & mFieldData . mPlaceAreaColour ) ;
// Set Transform.
setTransform ( ReplicatorObjectMatrix ) ;
RenewShapes ( ) ;
}
}