added everything
This commit is contained in:
154
engine/game/fx/cameraFXMgr.cc
Executable file
154
engine/game/fx/cameraFXMgr.cc
Executable file
@ -0,0 +1,154 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "game/fx/cameraFXMgr.h"
|
||||
|
||||
#include "math/mRandom.h"
|
||||
#include "math/mMatrix.h"
|
||||
#include "dgl/dgl.h"
|
||||
|
||||
// global cam fx
|
||||
CameraFXManager gCamFXMgr;
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// Camera effect
|
||||
//**************************************************************************
|
||||
CameraFX::CameraFX()
|
||||
{
|
||||
mElapsedTime = 0.0;
|
||||
mDuration = 1.0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Update
|
||||
//--------------------------------------------------------------------------
|
||||
void CameraFX::update( F32 dt )
|
||||
{
|
||||
mElapsedTime += dt;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// Camera shake effect
|
||||
//**************************************************************************
|
||||
CameraShake::CameraShake()
|
||||
{
|
||||
mFreq.zero();
|
||||
mAmp.zero();
|
||||
mStartAmp.zero();
|
||||
mTimeOffset.zero();
|
||||
mCamFXTrans.identity();
|
||||
mFalloff = 10.0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Update
|
||||
//--------------------------------------------------------------------------
|
||||
void CameraShake::update( F32 dt )
|
||||
{
|
||||
Parent::update( dt );
|
||||
|
||||
fadeAmplitude();
|
||||
|
||||
VectorF camOffset;
|
||||
camOffset.x = mAmp.x * sin( M_2PI * (mTimeOffset.x + mElapsedTime) * mFreq.x );
|
||||
camOffset.y = mAmp.y * sin( M_2PI * (mTimeOffset.y + mElapsedTime) * mFreq.y );
|
||||
camOffset.z = mAmp.z * sin( M_2PI * (mTimeOffset.z + mElapsedTime) * mFreq.z );
|
||||
|
||||
VectorF rotAngles;
|
||||
rotAngles.x = camOffset.x * 10.0 * M_PI/180.0;
|
||||
rotAngles.y = camOffset.y * 10.0 * M_PI/180.0;
|
||||
rotAngles.z = camOffset.z * 10.0 * M_PI/180.0;
|
||||
MatrixF rotMatrix( EulerF( rotAngles.x, rotAngles.y, rotAngles.z ) );
|
||||
|
||||
mCamFXTrans = rotMatrix;
|
||||
mCamFXTrans.setPosition( camOffset );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Fade out the amplitude over time
|
||||
//--------------------------------------------------------------------------
|
||||
void CameraShake::fadeAmplitude()
|
||||
{
|
||||
F32 percentDone = (mElapsedTime / mDuration);
|
||||
if( percentDone > 1.0 ) percentDone = 1.0;
|
||||
|
||||
F32 time = 1 + percentDone * mFalloff;
|
||||
time = 1 / (time * time);
|
||||
|
||||
mAmp = mStartAmp * time;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Initialize
|
||||
//--------------------------------------------------------------------------
|
||||
void CameraShake::init()
|
||||
{
|
||||
mTimeOffset.x = 0.0;
|
||||
mTimeOffset.y = gRandGen.randF();
|
||||
mTimeOffset.z = gRandGen.randF();
|
||||
}
|
||||
|
||||
//**************************************************************************
|
||||
// CameraFXManager
|
||||
//**************************************************************************
|
||||
CameraFXManager::CameraFXManager()
|
||||
{
|
||||
mCamFXTrans.identity();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Destructor
|
||||
//--------------------------------------------------------------------------
|
||||
CameraFXManager::~CameraFXManager()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Add new effect to currently running list
|
||||
//--------------------------------------------------------------------------
|
||||
void CameraFXManager::addFX( CameraFX *newFX )
|
||||
{
|
||||
mFXList.link( newFX );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Clear all currently running camera effects
|
||||
//--------------------------------------------------------------------------
|
||||
void CameraFXManager::clear()
|
||||
{
|
||||
mFXList.free();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Update camera effects
|
||||
//--------------------------------------------------------------------------
|
||||
void CameraFXManager::update( F32 dt )
|
||||
{
|
||||
CameraFXPtr *cur = NULL;
|
||||
mCamFXTrans.identity();
|
||||
|
||||
for( cur = mFXList.next( cur ); cur; cur = mFXList.next( cur ) )
|
||||
{
|
||||
CameraFX * curFX = *cur;
|
||||
curFX->update( dt );
|
||||
MatrixF fxTrans = curFX->getTrans();
|
||||
|
||||
mCamFXTrans.mul( fxTrans );
|
||||
|
||||
if( curFX->isExpired() )
|
||||
{
|
||||
CameraFXPtr *prev = mFXList.prev( cur );
|
||||
mFXList.free( cur );
|
||||
cur = prev;
|
||||
}
|
||||
}
|
||||
}
|
89
engine/game/fx/cameraFXMgr.h
Executable file
89
engine/game/fx/cameraFXMgr.h
Executable file
@ -0,0 +1,89 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _CAMERAFXMGR_H_
|
||||
#define _CAMERAFXMGR_H_
|
||||
|
||||
#ifndef _LLIST_H_
|
||||
#include "core/llist.h"
|
||||
#endif
|
||||
#ifndef _MPOINT_H_
|
||||
#include "math/mPoint.h"
|
||||
#endif
|
||||
#ifndef _MMATRIX_H_
|
||||
#include "math/mMatrix.h"
|
||||
#endif
|
||||
|
||||
//**************************************************************************
|
||||
// Abstract camera effect template
|
||||
//**************************************************************************
|
||||
class CameraFX
|
||||
{
|
||||
protected:
|
||||
F32 mElapsedTime;
|
||||
F32 mDuration;
|
||||
MatrixF mCamFXTrans;
|
||||
|
||||
public:
|
||||
CameraFX();
|
||||
|
||||
MatrixF & getTrans(){ return mCamFXTrans; }
|
||||
bool isExpired(){ return mElapsedTime >= mDuration; }
|
||||
void setDuration( F32 duration ){ mDuration = duration; }
|
||||
|
||||
virtual void update( F32 dt );
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Camera shake effect
|
||||
//--------------------------------------------------------------------------
|
||||
class CameraShake : public CameraFX
|
||||
{
|
||||
typedef CameraFX Parent;
|
||||
|
||||
VectorF mFreq; // these are vectors to represent these values in 3D
|
||||
VectorF mStartAmp;
|
||||
VectorF mAmp;
|
||||
VectorF mTimeOffset;
|
||||
F32 mFalloff;
|
||||
|
||||
public:
|
||||
CameraShake();
|
||||
|
||||
void init();
|
||||
void fadeAmplitude();
|
||||
void setFalloff( F32 falloff ){ mFalloff = falloff; }
|
||||
void setFrequency( VectorF &freq ){ mFreq = freq; }
|
||||
void setAmplitude( VectorF & ){ mStartAmp = amp; }
|
||||
|
||||
virtual void update( F32 dt );
|
||||
};
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// CameraFXManager
|
||||
//**************************************************************************
|
||||
class CameraFXManager
|
||||
{
|
||||
typedef CameraFX * CameraFXPtr;
|
||||
|
||||
LList< CameraFXPtr > mFXList;
|
||||
MatrixF mCamFXTrans;
|
||||
|
||||
public:
|
||||
void addFX( CameraFX *newFX );
|
||||
void clear();
|
||||
MatrixF & getTrans(){ return mCamFXTrans; }
|
||||
void update( F32 dt );
|
||||
|
||||
CameraFXManager();
|
||||
~CameraFXManager();
|
||||
|
||||
};
|
||||
|
||||
extern CameraFXManager gCamFXMgr;
|
||||
|
||||
|
||||
#endif
|
1126
engine/game/fx/explosion.cc
Executable file
1126
engine/game/fx/explosion.cc
Executable file
File diff suppressed because it is too large
Load Diff
172
engine/game/fx/explosion.h
Executable file
172
engine/game/fx/explosion.h
Executable file
@ -0,0 +1,172 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _EXPLOSION_H_
|
||||
#define _EXPLOSION_H_
|
||||
|
||||
#ifndef _GAMEBASE_H_
|
||||
#include "game/gameBase.h"
|
||||
#endif
|
||||
#ifndef _TSSHAPE_H_
|
||||
#include "ts/tsShape.h"
|
||||
#endif
|
||||
|
||||
class ParticleEmitter;
|
||||
class ParticleEmitterData;
|
||||
class TSThread;
|
||||
class AudioProfile;
|
||||
struct DebrisData;
|
||||
class ShockwaveData;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
class ExplosionData : public GameBaseData {
|
||||
public:
|
||||
typedef GameBaseData Parent;
|
||||
|
||||
enum ExplosionConsts
|
||||
{
|
||||
EC_NUM_DEBRIS_TYPES = 1,
|
||||
EC_NUM_EMITTERS = 4,
|
||||
EC_MAX_SUB_EXPLOSIONS = 5,
|
||||
EC_NUM_TIME_KEYS = 4,
|
||||
};
|
||||
|
||||
public:
|
||||
StringTableEntry dtsFileName;
|
||||
|
||||
bool faceViewer;
|
||||
|
||||
S32 particleDensity;
|
||||
F32 particleRadius;
|
||||
|
||||
AudioProfile* soundProfile;
|
||||
ParticleEmitterData* particleEmitter;
|
||||
S32 soundProfileId;
|
||||
S32 particleEmitterId;
|
||||
|
||||
Point3F explosionScale;
|
||||
F32 playSpeed;
|
||||
|
||||
Resource<TSShape> explosionShape;
|
||||
S32 explosionAnimation;
|
||||
|
||||
ParticleEmitterData* emitterList[EC_NUM_EMITTERS];
|
||||
S32 emitterIDList[EC_NUM_EMITTERS];
|
||||
|
||||
ShockwaveData * shockwave;
|
||||
S32 shockwaveID;
|
||||
bool shockwaveOnTerrain;
|
||||
|
||||
DebrisData * debrisList[EC_NUM_DEBRIS_TYPES];
|
||||
S32 debrisIDList[EC_NUM_DEBRIS_TYPES];
|
||||
|
||||
F32 debrisThetaMin;
|
||||
F32 debrisThetaMax;
|
||||
F32 debrisPhiMin;
|
||||
F32 debrisPhiMax;
|
||||
S32 debrisNum;
|
||||
S32 debrisNumVariance;
|
||||
F32 debrisVelocity;
|
||||
F32 debrisVelocityVariance;
|
||||
|
||||
// sub - explosions
|
||||
ExplosionData* explosionList[EC_MAX_SUB_EXPLOSIONS];
|
||||
S32 explosionIDList[EC_MAX_SUB_EXPLOSIONS];
|
||||
|
||||
S32 delayMS;
|
||||
S32 delayVariance;
|
||||
S32 lifetimeMS;
|
||||
S32 lifetimeVariance;
|
||||
|
||||
F32 offset;
|
||||
Point3F sizes[ EC_NUM_TIME_KEYS ];
|
||||
F32 times[ EC_NUM_TIME_KEYS ];
|
||||
|
||||
// camera shake data
|
||||
bool shakeCamera;
|
||||
VectorF camShakeFreq;
|
||||
VectorF camShakeAmp;
|
||||
F32 camShakeDuration;
|
||||
F32 camShakeRadius;
|
||||
F32 camShakeFalloff;
|
||||
|
||||
// Dynamic Lighting. The light is smoothly
|
||||
// interpolated from start to end time.
|
||||
F32 lightStartRadius;
|
||||
F32 lightEndRadius;
|
||||
ColorF lightStartColor;
|
||||
ColorF lightEndColor;
|
||||
|
||||
ExplosionData();
|
||||
DECLARE_CONOBJECT(ExplosionData);
|
||||
bool onAdd();
|
||||
bool preload(bool server, char errorBuffer[256]);
|
||||
static void initPersistFields();
|
||||
virtual void packData(BitStream* stream);
|
||||
virtual void unpackData(BitStream* stream);
|
||||
};
|
||||
DECLARE_CONSOLETYPE(ExplosionData)
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
class Explosion : public GameBase
|
||||
{
|
||||
typedef GameBase Parent;
|
||||
|
||||
private:
|
||||
ExplosionData* mDataBlock;
|
||||
|
||||
TSShapeInstance* mExplosionInstance;
|
||||
TSThread* mExplosionThread;
|
||||
|
||||
ParticleEmitter * mEmitterList[ ExplosionData::EC_NUM_EMITTERS ];
|
||||
|
||||
U32 mCurrMS;
|
||||
U32 mEndingMS;
|
||||
F32 mRandAngle;
|
||||
LightInfo mLight;
|
||||
|
||||
protected:
|
||||
Point3F mInitialNormal;
|
||||
F32 mFade;
|
||||
F32 mFog;
|
||||
bool mActive;
|
||||
S32 mDelayMS;
|
||||
F32 mRandomVal;
|
||||
U32 mCollideType;
|
||||
|
||||
protected:
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
bool explode();
|
||||
|
||||
void processTick(const Move *move);
|
||||
void advanceTime(F32 dt);
|
||||
void updateEmitters( F32 dt );
|
||||
void launchDebris( Point3F &axis );
|
||||
void spawnSubExplosions();
|
||||
void setCurrentScale();
|
||||
|
||||
// Rendering
|
||||
protected:
|
||||
bool prepRenderImage(SceneState *state, const U32 stateKey, const U32 startZone, const bool modifyBaseZoneState);
|
||||
void renderObject(SceneState *state, SceneRenderImage *image);
|
||||
void prepModelView(SceneState*);
|
||||
void registerLights(LightManager * lm, bool lightingScene);
|
||||
|
||||
public:
|
||||
Explosion();
|
||||
~Explosion();
|
||||
void setInitialState(const Point3F& point, const Point3F& normal, const F32 fade = 1.0);
|
||||
|
||||
bool onNewDataBlock(GameBaseData* dptr);
|
||||
void setCollideType( U32 cType ){ mCollideType = cType; }
|
||||
|
||||
DECLARE_CONOBJECT(Explosion);
|
||||
static void initPersistFields();
|
||||
};
|
||||
|
||||
#endif // _H_EXPLOSION
|
||||
|
1802
engine/game/fx/fxFoliageReplicator.cc
Executable file
1802
engine/game/fx/fxFoliageReplicator.cc
Executable file
File diff suppressed because it is too large
Load Diff
308
engine/game/fx/fxFoliageReplicator.h
Executable file
308
engine/game/fx/fxFoliageReplicator.h
Executable file
@ -0,0 +1,308 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Written by Melvyn May, 4th August 2002.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _FOLIAGEREPLICATOR_H_
|
||||
#define _FOLIAGEREPLICATOR_H_
|
||||
|
||||
#ifndef _SCENEOBJECT_H_
|
||||
#include "sim/sceneObject.h"
|
||||
#endif
|
||||
|
||||
#define AREA_ANIMATION_ARC (1.0f / 360.0f)
|
||||
|
||||
#define FXFOLIAGEREPLICATOR_COLLISION_MASK ( TerrainObjectType | \
|
||||
InteriorObjectType | \
|
||||
StaticObjectType | \
|
||||
WaterObjectType )
|
||||
|
||||
#define FXFOLIAGEREPLICATOR_NOWATER_COLLISION_MASK ( TerrainObjectType | \
|
||||
InteriorObjectType | \
|
||||
StaticObjectType )
|
||||
|
||||
|
||||
#define FXFOLIAGE_ALPHA_EPSILON 1e-4
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Class: fxFoliageItem
|
||||
//------------------------------------------------------------------------------
|
||||
class fxFoliageItem
|
||||
{
|
||||
public:
|
||||
MatrixF Transform;
|
||||
F32 Width;
|
||||
F32 Height;
|
||||
Box3F FoliageBox;
|
||||
bool Flipped;
|
||||
F32 SwayPhase;
|
||||
F32 SwayTimeRatio;
|
||||
F32 LightPhase;
|
||||
F32 LightTimeRatio;
|
||||
U32 LastFrameSerialID;
|
||||
};
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Class: fxFoliageCulledList
|
||||
//------------------------------------------------------------------------------
|
||||
class fxFoliageCulledList
|
||||
{
|
||||
public:
|
||||
fxFoliageCulledList() {};
|
||||
fxFoliageCulledList(Box3F SearchBox, fxFoliageCulledList* InVec);
|
||||
~fxFoliageCulledList() {};
|
||||
|
||||
void FindCandidates(Box3F SearchBox, fxFoliageCulledList* InVec);
|
||||
|
||||
U32 GetListCount(void) { return mCulledObjectSet.size(); };
|
||||
fxFoliageItem* GetElement(U32 index) { return mCulledObjectSet[index]; };
|
||||
|
||||
Vector<fxFoliageItem*> mCulledObjectSet; // Culled Object Set.
|
||||
};
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Class: fxFoliageQuadNode
|
||||
//------------------------------------------------------------------------------
|
||||
class fxFoliageQuadrantNode
|
||||
{
|
||||
public:
|
||||
U32 Level;
|
||||
Box3F QuadrantBox;
|
||||
fxFoliageQuadrantNode* QuadrantChildNode[4];
|
||||
Vector<fxFoliageItem*> RenderList;
|
||||
|
||||
fxFoliageQuadrantNode()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Class: fxFoliageRenderList
|
||||
//------------------------------------------------------------------------------
|
||||
class fxFoliageRenderList
|
||||
{
|
||||
public:
|
||||
Point3F FarPosLeftUp; // View Frustum.
|
||||
Point3F FarPosLeftDown;
|
||||
Point3F FarPosRightUp;
|
||||
Point3F FarPosRightDown;
|
||||
Point3F CameraPosition; // Camera Position.
|
||||
Box3F mBox; // Clipping Box.
|
||||
PlaneF ViewPlanes[5]; // Clipping View-Planes.
|
||||
|
||||
Vector<fxFoliageItem*> mVisObjectSet; // Visible Object Set.
|
||||
F32 mHeightLerp; // Height Lerp.
|
||||
|
||||
public:
|
||||
bool IsQuadrantVisible(const Box3F VisBox, const MatrixF& RenderTransform);
|
||||
void SetupClipPlanes(SceneState* state, const F32 FarClipPlane);
|
||||
void CompileVisibleSet(const fxFoliageQuadrantNode* pNode, const MatrixF& RenderTransform, const bool UseDebug);
|
||||
void DrawQuadBox(const Box3F& QuadBox, const ColorF Colour);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Class: fxFoliageReplicator
|
||||
//------------------------------------------------------------------------------
|
||||
class fxFoliageReplicator : public SceneObject
|
||||
{
|
||||
private:
|
||||
typedef SceneObject Parent;
|
||||
|
||||
protected:
|
||||
|
||||
void CreateFoliage(void);
|
||||
void DestroyFoliage(void);
|
||||
|
||||
void SyncFoliageReplicators(void);
|
||||
|
||||
Box3F FetchQuadrant(Box3F Box, U32 Quadrant);
|
||||
void ProcessQuadrant(fxFoliageQuadrantNode* pParentNode, fxFoliageCulledList* pCullList, U32 Quadrant);
|
||||
void ProcessNodeChildren(fxFoliageQuadrantNode* pParentNode, fxFoliageCulledList* pCullList);
|
||||
|
||||
enum { FoliageReplicationMask = (1 << 0) };
|
||||
|
||||
|
||||
U32 mCreationAreaAngle;
|
||||
bool mClientReplicationStarted;
|
||||
bool mAddedToScene;
|
||||
U32 mCurrentFoliageCount;
|
||||
|
||||
Vector<fxFoliageQuadrantNode*> mFoliageQuadTree;
|
||||
Vector<fxFoliageItem*> mReplicatedFoliage;
|
||||
fxFoliageRenderList mFrustumRenderSet;
|
||||
|
||||
MRandomLCG RandomGen;
|
||||
F32 mFadeInGradient;
|
||||
F32 mFadeOutGradient;
|
||||
S32 mLastRenderTime;
|
||||
F32 mGlobalSwayPhase;
|
||||
F32 mGlobalSwayTimeRatio;
|
||||
F32 mGlobalLightPhase;
|
||||
F32 mGlobalLightTimeRatio;
|
||||
U32 mFrameSerialID;
|
||||
|
||||
U32 mQuadTreeLevels; // Quad-Tree Levels.
|
||||
U32 mPotentialFoliageNodes; // Potential Foliage Nodes.
|
||||
U32 mNextAllocatedNodeIdx; // Next Allocated Node Index.
|
||||
U32 mBillboardsAcquired; // Billboards Acquired.
|
||||
|
||||
public:
|
||||
fxFoliageReplicator();
|
||||
~fxFoliageReplicator();
|
||||
|
||||
void StartUp(void);
|
||||
void ShowReplication(void);
|
||||
void HideReplication(void);
|
||||
|
||||
// SceneObject
|
||||
void renderObject(SceneState *state, SceneRenderImage *image);
|
||||
virtual bool prepRenderImage(SceneState *state, const U32 stateKey, const U32 startZone,
|
||||
const bool modifyBaseZoneState = false);
|
||||
|
||||
// SimObject
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
void onEditorEnable();
|
||||
void onEditorDisable();
|
||||
void inspectPostApply();
|
||||
|
||||
// NetObject
|
||||
U32 packUpdate(NetConnection *conn, U32 mask, BitStream *stream);
|
||||
void unpackUpdate(NetConnection *conn, BitStream *stream);
|
||||
|
||||
// ConObject.
|
||||
static void initPersistFields();
|
||||
|
||||
// Field Data.
|
||||
class tagFieldData
|
||||
{
|
||||
public:
|
||||
|
||||
bool mUseDebugInfo;
|
||||
F32 mDebugBoxHeight;
|
||||
U32 mSeed;
|
||||
StringTableEntry mFoliageFile;
|
||||
TextureHandle mFoliageTexture;
|
||||
U32 mFoliageCount;
|
||||
U32 mFoliageRetries;
|
||||
|
||||
U32 mInnerRadiusX;
|
||||
U32 mInnerRadiusY;
|
||||
U32 mOuterRadiusX;
|
||||
U32 mOuterRadiusY;
|
||||
|
||||
F32 mMinWidth;
|
||||
F32 mMaxWidth;
|
||||
F32 mMinHeight;
|
||||
F32 mMaxHeight;
|
||||
bool mFixAspectRatio;
|
||||
bool mFixSizeToMax;
|
||||
F32 mOffsetZ;
|
||||
bool mRandomFlip;
|
||||
|
||||
bool mUseCulling;
|
||||
U32 mCullResolution;
|
||||
F32 mViewDistance;
|
||||
F32 mViewClosest;
|
||||
F32 mFadeInRegion;
|
||||
F32 mFadeOutRegion;
|
||||
F32 mAlphaCutoff;
|
||||
F32 mGroundAlpha;
|
||||
|
||||
bool mSwayOn;
|
||||
bool mSwaySync;
|
||||
F32 mSwayMagnitudeSide;
|
||||
F32 mSwayMagnitudeFront;
|
||||
F32 mMinSwayTime;
|
||||
F32 mMaxSwayTime;
|
||||
|
||||
bool mLightOn;
|
||||
bool mLightSync;
|
||||
F32 mMinLuminance;
|
||||
F32 mMaxLuminance;
|
||||
F32 mLightTime;
|
||||
|
||||
bool mAllowOnTerrain;
|
||||
bool mAllowOnInteriors;
|
||||
bool mAllowStatics;
|
||||
bool mAllowOnWater;
|
||||
bool mAllowWaterSurface;
|
||||
S32 mAllowedTerrainSlope;
|
||||
|
||||
bool mHideFoliage;
|
||||
bool mShowPlacementArea;
|
||||
U32 mPlacementBandHeight;
|
||||
ColorF mPlaceAreaColour;
|
||||
|
||||
tagFieldData()
|
||||
{
|
||||
// Set Defaults.
|
||||
mUseDebugInfo = false;
|
||||
mDebugBoxHeight = 1.0f;
|
||||
mSeed = gRandGen.randI(0, 1000000000);;
|
||||
mFoliageFile = StringTable->insert("");
|
||||
mFoliageTexture = TextureHandle();
|
||||
mFoliageCount = 10;
|
||||
mFoliageRetries = 100;
|
||||
|
||||
mInnerRadiusX = 0;
|
||||
mInnerRadiusY = 0;
|
||||
mOuterRadiusX = 128;
|
||||
mOuterRadiusY = 128;
|
||||
|
||||
mMinWidth = 1;
|
||||
mMaxWidth = 3;
|
||||
mMinHeight = 1;
|
||||
mMaxHeight = 5;
|
||||
mFixAspectRatio = true;
|
||||
mFixSizeToMax = false;
|
||||
mOffsetZ = 0;
|
||||
mRandomFlip = true;
|
||||
|
||||
mUseCulling = true;
|
||||
mCullResolution = 64;
|
||||
mViewDistance = 50.0f;
|
||||
mViewClosest = 1.0f;
|
||||
mFadeInRegion = 10.0f;
|
||||
mFadeOutRegion = 1.0f;
|
||||
mAlphaCutoff = 0.2f;
|
||||
mGroundAlpha = 1.0f;
|
||||
|
||||
mSwayOn = false;
|
||||
mSwaySync = false;
|
||||
mSwayMagnitudeSide = 0.1f;
|
||||
mSwayMagnitudeFront = 0.2f;
|
||||
mMinSwayTime = 3.0f;
|
||||
mMaxSwayTime = 10.0f;
|
||||
|
||||
mLightOn = false;
|
||||
mLightSync = false;
|
||||
mMinLuminance = 0.7f;
|
||||
mMaxLuminance = 1.0f;
|
||||
mLightTime = 5.0f;
|
||||
|
||||
mAllowOnTerrain = true;
|
||||
mAllowOnInteriors = true;
|
||||
mAllowStatics = true;
|
||||
mAllowOnWater = false;
|
||||
mAllowWaterSurface = false;
|
||||
mAllowedTerrainSlope = 90;
|
||||
|
||||
mHideFoliage = false;
|
||||
mShowPlacementArea = true;
|
||||
mPlacementBandHeight = 25;
|
||||
mPlaceAreaColour .set(0.4f, 0, 0.8f);
|
||||
}
|
||||
|
||||
} mFieldData;
|
||||
|
||||
// Declare Console Object.
|
||||
DECLARE_CONOBJECT(fxFoliageReplicator);
|
||||
};
|
||||
|
||||
#endif // _FOLIAGEREPLICATOR_H_
|
1659
engine/game/fx/fxLight.cc
Executable file
1659
engine/game/fx/fxLight.cc
Executable file
File diff suppressed because it is too large
Load Diff
248
engine/game/fx/fxLight.h
Executable file
248
engine/game/fx/fxLight.h
Executable file
@ -0,0 +1,248 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine - fxLight
|
||||
//
|
||||
// Written by Melvyn May, 4th May 2002.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _FXLIGHTDB_H_
|
||||
#define _FXLIGHTDB_H_
|
||||
|
||||
#ifndef _GAMEBASE_H_
|
||||
#include "game/gameBase.h"
|
||||
#endif
|
||||
#ifndef _SCENEOBJECT_H_
|
||||
#include "sim/sceneObject.h"
|
||||
#endif
|
||||
|
||||
#define FXLIGHTDBICONTEXTURE "common/lighting/fxlighticon.png"
|
||||
|
||||
|
||||
class fxLightData : public GameBaseData
|
||||
{
|
||||
public:
|
||||
typedef GameBaseData Parent;
|
||||
|
||||
fxLightData();
|
||||
|
||||
bool onAdd();
|
||||
static void initPersistFields();
|
||||
virtual void packData(BitStream* stream);
|
||||
virtual void unpackData(BitStream* stream);
|
||||
|
||||
// Datablock Flare.
|
||||
StringTableEntry mFlareTextureName; // Flare Texture Name.
|
||||
|
||||
// Datablock Light.
|
||||
bool mLightOn; // Light On Flag.
|
||||
F32 mRadius; // Radius.
|
||||
F32 mBrightness; // Brightness.
|
||||
ColorF mColour; // Colour.
|
||||
|
||||
// Datablock Flare.
|
||||
bool mFlareOn; // Flare On Flag.
|
||||
bool mFlareTP; // Flare Third Person Flag.
|
||||
ColorF mFlareColour; // Flare Colour.
|
||||
bool mConstantSizeOn; // Flare Use Constant Size Flag.
|
||||
F32 mConstantSize; // Flare Constant Size.
|
||||
F32 mNearSize; // Near Size.
|
||||
F32 mFarSize; // Far Size.
|
||||
F32 mNearDistance; // Near Distance.
|
||||
F32 mFarDistance; // Far Distance.
|
||||
F32 mFadeTime; // Fade Time.
|
||||
U32 mBlendMode; // Blend Mode.
|
||||
bool mLinkFlare; // Link Flare Animation.
|
||||
bool mLinkFlareSize; // Link Flare Size Animation.
|
||||
|
||||
// Datablock Animation.
|
||||
ColorF mMinColour; // Minimum Colour.
|
||||
ColorF mMaxColour; // Maximum Colour.
|
||||
F32 mMinBrightness; // Minimum Brightness.
|
||||
F32 mMaxBrightness; // Maximum Brightness.
|
||||
F32 mMinRadius; // Minimum Radius.
|
||||
F32 mMaxRadius; // Maximum Radius.
|
||||
Point3F mStartOffset; // Start Offset.
|
||||
Point3F mEndOffset; // Stop Offset.
|
||||
F32 mMinRotation; // Minimum Rotation.
|
||||
F32 mMaxRotation; // Maximum Rotation.
|
||||
bool mSingleColourKeys; // Single-Channel Colour Keys.
|
||||
StringTableEntry mRedKeys; // Red Animation Keys.
|
||||
StringTableEntry mGreenKeys; // Green Animation Keys.
|
||||
StringTableEntry mBlueKeys; // Blue Animation Keys.
|
||||
StringTableEntry mBrightnessKeys; // Brightness Animation Keys.
|
||||
StringTableEntry mRadiusKeys; // Radius Animation Keys.
|
||||
StringTableEntry mOffsetKeys; // Offset Animation Keys.
|
||||
StringTableEntry mRotationKeys; // Rotation Animation Keys.
|
||||
F32 mColourTime; // Colour Time (Seconds).
|
||||
F32 mBrightnessTime; // Brightness Time.
|
||||
F32 mRadiusTime; // Radius Time.
|
||||
F32 mOffsetTime; // Offset Time.
|
||||
F32 mRotationTime; // Rotation Time.
|
||||
bool mLerpColour; // Lerp Colour Flag.
|
||||
bool mLerpBrightness; // Lerp Brightness Flag.
|
||||
bool mLerpRadius; // Lerp Radius Flag.
|
||||
bool mLerpOffset; // Lerp Offset Flag.
|
||||
bool mLerpRotation; // Lerp Rotation Flag.
|
||||
bool mUseColour; // Use Colour Flag.
|
||||
bool mUseBrightness; // Use Brightness Flag.
|
||||
bool mUseRadius; // Use Radius Flag.
|
||||
bool mUseOffsets; // Use Position Offsets Flag.
|
||||
bool mUseRotation; // Use Rotation Flag.
|
||||
|
||||
|
||||
DECLARE_CONOBJECT(fxLightData);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Class: fxLight
|
||||
//------------------------------------------------------------------------------
|
||||
class fxLight : public GameBase
|
||||
{
|
||||
private:
|
||||
typedef GameBase Parent;
|
||||
fxLightData* mDataBlock;
|
||||
protected:
|
||||
|
||||
U32 CheckKeySyntax(StringTableEntry Key);
|
||||
void CheckAnimationKeys(void);
|
||||
F32 GetLerpKey(StringTableEntry Key, U32 PosFrom, U32 PosTo, F32 ValueFrom, F32 ValueTo, F32 Lerp);
|
||||
void AnimateLight(void);
|
||||
void InitialiseAnimation(void);
|
||||
void ResetAnimation(void);
|
||||
bool TestLOS(const Point3F& ObjectPosition, SceneObject* AttachedObj);
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
enum {
|
||||
fxLightConfigChangeMask = BIT(0),
|
||||
fxLightAttachChange = BIT(1)
|
||||
};
|
||||
|
||||
bool mAddedToScene;
|
||||
|
||||
MRandomLCG RandomGen;
|
||||
|
||||
// Textures.
|
||||
TextureHandle mIconTextureHandle;
|
||||
TextureHandle mFlareTextureHandle;
|
||||
|
||||
LightInfo mLight;
|
||||
U32 mLastAnimateTime;
|
||||
U32 mLastRenderTime;
|
||||
F32 mFlareScale;
|
||||
bool mAttached;
|
||||
//GameBase* mpAttachedObject;
|
||||
//bool mAttachWait;
|
||||
//bool mAttachValid;
|
||||
|
||||
public:
|
||||
fxLight();
|
||||
~fxLight();
|
||||
|
||||
|
||||
U32 mountPoint;
|
||||
MatrixF mountTransform;
|
||||
virtual void buildObjectBox()
|
||||
{
|
||||
Point3F Min, Max;
|
||||
Min.set(0,0,0);
|
||||
Max.set(0,0,0);
|
||||
// Calculate Extents.
|
||||
Min.setMin(mAnimationOffset);
|
||||
Max.setMax(mAnimationOffset);
|
||||
Min += Point3F(-0.5f, -0.5f, -0.5f);
|
||||
Max += Point3F(+0.5f, +0.5f, +0.5f);
|
||||
mObjBox.min.set(Min);
|
||||
mObjBox.max.set(Max);
|
||||
resetWorldBox();
|
||||
}
|
||||
virtual void calculateLightPosition()
|
||||
{
|
||||
// Yes, so set to attached position.
|
||||
//mAnimationPosition = mpAttachedObject->getPosition();
|
||||
|
||||
// Set Current Position.
|
||||
//setPosition(mAnimationPosition);
|
||||
}
|
||||
virtual SceneObject *getAttachedObject() {return NULL;}
|
||||
|
||||
|
||||
// *********************************
|
||||
// Configuration Interface.
|
||||
// *********************************
|
||||
|
||||
// Light.
|
||||
void setEnable(bool Status);
|
||||
void setFlareBitmap(const char* Name);
|
||||
|
||||
// Misc,
|
||||
void reset(void);
|
||||
//void attachToObject(const char* ObjectName);
|
||||
//void detachFromObject(void);
|
||||
|
||||
// GameBase.
|
||||
bool onNewDataBlock(GameBaseData* dptr);
|
||||
void processTick(const Move*);
|
||||
|
||||
// SceneObject
|
||||
bool prepRenderImage(SceneState* state, const U32 stateKey, const U32 startZone, const bool modifyBaseZoneState);
|
||||
void renderObject(SceneState *state, SceneRenderImage *image);
|
||||
|
||||
// SimObject
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
//void onDeleteNotify(SimObject*);
|
||||
|
||||
void inspectPostApply();
|
||||
void registerLights(LightManager * lightManager, bool lightingScene);
|
||||
|
||||
// NetObject
|
||||
U32 packUpdate(NetConnection *, U32, BitStream *);
|
||||
void unpackUpdate(NetConnection *, BitStream *);
|
||||
|
||||
// ConObject.
|
||||
static void initPersistFields();
|
||||
|
||||
// Field Data.
|
||||
|
||||
bool mEnable; // Light Enable.
|
||||
|
||||
// Basis Light.
|
||||
F32 mIconSize; // Icon Size.
|
||||
|
||||
// Current Animation.
|
||||
ColorF mAnimationColour; // Current Colour.
|
||||
F32 mAnimationBrightness; // Current Brightness.
|
||||
F32 mAnimationRadius; // Current Radius.
|
||||
Point3F mAnimationPosition; // Current Position.
|
||||
Point3F mAnimationOffset; // Current Offset.
|
||||
F32 mAnimationRotation; // Current Rotation.
|
||||
|
||||
// Elapsed Times.
|
||||
F32 mColourElapsedTime; // Colour Elapsed Time.
|
||||
F32 mBrightnessElapsedTime; // Brightness Elapsed Time.
|
||||
F32 mRadiusElapsedTime; // Radius Elapsed Time.
|
||||
F32 mOffsetElapsedTime; // Offset Elapsed Time.
|
||||
F32 mRotationElapsedTime; // Rotation Elapsed Time.
|
||||
|
||||
// Time Scales.
|
||||
F32 mColourTimeScale; // Colour Time Scale.
|
||||
F32 mBrightnessTimeScale; // Brightness Time Scale.
|
||||
F32 mRadiusTimeScale; // Radius Time Scale.
|
||||
F32 mOffsetTimeScale; // Offset Time Scale.
|
||||
F32 mRotationTimeScale; // Rotation Time Scale.
|
||||
|
||||
// Key Lengths (Validity).
|
||||
U32 mRedKeysLength; // Red Keys Length.
|
||||
U32 mGreenKeysLength; // Green Keys Length.
|
||||
U32 mBlueKeysLength; // Blue Keys Length.
|
||||
U32 mBrightnessKeysLength; // Brightness Keys Length.
|
||||
U32 mRadiusKeysLength; // Radius Keys Length.
|
||||
U32 mOffsetKeysLength; // Offset Keys Length.
|
||||
U32 mRotationKeysLength; // Rotation Keys Length.
|
||||
|
||||
// Declare Console Object.
|
||||
DECLARE_CONOBJECT(fxLight);
|
||||
};
|
||||
|
||||
#endif // _FXLIGHTDB_H_
|
749
engine/game/fx/fxRenderObject.cc
Executable file
749
engine/game/fx/fxRenderObject.cc
Executable file
@ -0,0 +1,749 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
//
|
||||
// Written by Melvyn May, Started on 9th September 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.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//$foo = new fxRenderObject() { position = LocalClientConnection.player.getPosition(); Texture = "starter.fps/data/water/water.png"; };
|
||||
|
||||
#include "dgl/dgl.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "core/bitStream.h"
|
||||
#include "math/mathIO.h"
|
||||
#include "game/gameConnection.h"
|
||||
#include "console/simBase.h"
|
||||
#include "sceneGraph/sceneGraph.h"
|
||||
#include "sceneGraph/sgUtil.h"
|
||||
#include "fxRenderObject.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Okay, here's the wordy-wordy explanation of what's going on here.
|
||||
//
|
||||
// The object is inheriting from the core SceneObject. It is essential that
|
||||
// you inherit from at least this object to be able to add your object into
|
||||
// the SceneGraph.
|
||||
//
|
||||
// DECLARE_CONOBJECT(fxRenderObject);
|
||||
// IMPLEMENT_CO_NETOBJECT_V1(fxRenderObject);
|
||||
//
|
||||
// The lines above are vitally important when creating these network objects.
|
||||
// They register the object with the engine and you can't proceed without them.
|
||||
// The DECLARE goes in your class definition and the IMPLEMENT goes into your
|
||||
// implementation. Anyone who has used MFC should recognise this procedure.
|
||||
//
|
||||
//
|
||||
// *** CONSTRUCTOR ***
|
||||
//
|
||||
// In the constructor you will notice that I set the mTypeMask. This is used
|
||||
// as a standard way of identifing object 'types'. It's called a mask because
|
||||
// you can merge multiple types. One of the most common uses for this is
|
||||
// the collision detection system. The collision detection system allows you
|
||||
// to include certain types when searching. It's these flags here that are
|
||||
// used. You can create your own but be careful as there are only so many
|
||||
// available. Normally you wouldn't do this as you should find one that fits
|
||||
// into what you are doing but the option is always there.
|
||||
//
|
||||
// I also set the net flags. These are a bunch of flags that signify some
|
||||
// important aspects of the object. You should really look at the networking
|
||||
// documentation on the GG site for a basic explanation of ghosts and scoping
|
||||
// as it's a bit much to explain here. The default settings should suffice
|
||||
// unless you are doing something weird (like my fxShapeReplicator)!
|
||||
//
|
||||
// I'm also resetting the mLastRenderTime variable as I used this as a
|
||||
// timestamp. Subtracting the current time from the last obviously gives
|
||||
// me the elapsed time and it's this value that can be used to create
|
||||
// frame-independant animation.
|
||||
//
|
||||
// I also reset most other stuff here to their defaults. It is vitally
|
||||
// important to note that even on a single machine there are two objects
|
||||
// created, one on the server and one on the client. The client could
|
||||
// potentially be on another machine but Torque handles that for you.
|
||||
//
|
||||
// The constructor will be called for both the server and client objects and
|
||||
// so this is a great place to initialise stuff. Try not to allocate memory
|
||||
// in the constructor though, this goes for OOP everywhere though!
|
||||
//
|
||||
//
|
||||
// *** DESTRUCTOR ***
|
||||
//
|
||||
// My destructor is empty because I don't need to do anything for shutdown.
|
||||
// If I had textures allocated then the variable holding that texture
|
||||
// reference will go out of scope and the resource manager will remove the
|
||||
// reference and possibly destroy the texture (if no other objects have
|
||||
// a reference to the same texture object).
|
||||
//
|
||||
//
|
||||
// *** InitPersistFields ***
|
||||
//
|
||||
// It's here that we add our custom fields. Note that this gets called
|
||||
// when the engine is starting up and *not* when the object is created.
|
||||
// What you are essentially doing here is registering with the engine, the
|
||||
// fields that objects of this 'class' will have. Don't put any
|
||||
// object-instance specific code in here otherwise you will be disappointed!
|
||||
//
|
||||
// Use the addField function to define your fields but be careful not to
|
||||
// use duplicate fieldnames or ones with spaces in them. You can happily
|
||||
// use underscores though.
|
||||
//
|
||||
// If you've merged with the [HEAD] then you can used my new field-grouping
|
||||
// which enables you to group blocks of fields that are related. They look
|
||||
// much nicer in the editor when they are grouped and most things become
|
||||
// easier to find. You can use addGroup("MyGroup1")/endGroup("MyGroup1")
|
||||
// entries around you field-blocks. I have left an example in the code for
|
||||
// you to look at (commented-out).
|
||||
//
|
||||
//
|
||||
// *** OnAdd ***
|
||||
//
|
||||
// After the object is built (either from you creating one in the editor or
|
||||
// upon mission start-up) this function is called by the engine to allow the
|
||||
// object to add itself into the scene and setup scene specific attributes.
|
||||
//
|
||||
// First-up always try to call parent functions if they are there.
|
||||
//
|
||||
// Next I setup the object box. This is an object-space box that defines the
|
||||
// region which the object occupies. It is important that you get this correct
|
||||
// as the SceneTraversal routines uses this box to see if the object is in the
|
||||
// view. Setting it too small results in the object not being rendered when
|
||||
// in-fact it should be. Too big and the objects render function will get
|
||||
// called when it's not on the screen which is just wasted processing. If the
|
||||
// object dynamically changes shape during gameplay then you can either create
|
||||
// an object-box at start-up that completely encapsulates its' volume or you
|
||||
// can dynamically change the object-box. Remember though, that if you must
|
||||
// reset the world box and set the render transform after doing so and that
|
||||
// you must do this client-side as well.
|
||||
//
|
||||
// After you've set the object-space box you *must always* reset the world-box.
|
||||
// What this does is calculate, using the current objects position, the
|
||||
// world-space coordinates of this box. It also calculates the world-sphere
|
||||
// which is a sphere that encapsulates the specified box.
|
||||
// Also, you must set the render transform. Failure to do this can result in
|
||||
// weird and hard to track results in animations and editor manipulation.
|
||||
//
|
||||
// Finally we add the object to the scene with the simple call "addToScene()".
|
||||
//
|
||||
// Returning true here confirms that everything was okay. If you return false
|
||||
// then the server will assume that there has been a problem and will
|
||||
// disconnect the client informing them that this resource failed to load and
|
||||
// that you may have incorrect resources or wrong engine version, so watch out!
|
||||
//
|
||||
//
|
||||
// *** onRemove ***
|
||||
//
|
||||
// This one's dead easy. "removeFromScene()" does exactly that. Again, call
|
||||
// the parent functions where needed.
|
||||
//
|
||||
//
|
||||
// *** inspectPostApply ***
|
||||
//
|
||||
// This is an interesting function as it's called (Server-Side only) when the
|
||||
// user hits the "Apply" button when editing the object. We respond by doing
|
||||
// the nice thing and calling the parent and then signalling which bits of data
|
||||
// need to get transferred to the client.
|
||||
//
|
||||
// We do this using "setMaskBits(fxRenderObjectMask)". Doing this will result
|
||||
// in the "packUpdate(...)" (see below) function being called. Essentially,
|
||||
// the mask you specify here is your customised mask you created in the header
|
||||
// of the object.
|
||||
//
|
||||
// Quite often you will only have one and it will trigger all the object data
|
||||
// being sent. This can be wasteful and if your object does this alot during
|
||||
// gameplay then you would want to send only the data that has changed or at
|
||||
// least only relevant groups of data that has changed. I explain these masks
|
||||
// more in the "packUpdate" section below.
|
||||
//
|
||||
//
|
||||
// *** onEditorEnable / onEditorDisable ***
|
||||
//
|
||||
// I left these functions in as they can be extremely useful when you want your
|
||||
// object to act differently when you know the editor is on. For instance, I
|
||||
// used this in my fxShapeReplicator to signal that the editor was on. When it
|
||||
// was I would additionally draw a sweeping arc defining the replication area.
|
||||
//
|
||||
//
|
||||
// *** prepRenderImage ***
|
||||
//
|
||||
// Let me just say before I start an explanation here that this function should
|
||||
// work without modification for most objects you will want to create and so if
|
||||
// I loose you then just skip it. ;)
|
||||
//
|
||||
// Let me open-up the inner workings of the engine a little...
|
||||
//
|
||||
// After an object has been created client-side, it's "OnAdd" function is called
|
||||
// (see above) and it adds itself to the scene. But what does this mean?
|
||||
//
|
||||
// Well the engine has lots of structures (believe me lots) one of which is a
|
||||
// container. This, as it's name implies, can contain objects. You've heard
|
||||
// me throw the term SceneGraph around but what does it do? Well, in Torque, all
|
||||
// client-side objects are in a Container named "gClientContainer". Similarly,
|
||||
// all server-side objects are in a Container named "gServerContainer" but let's
|
||||
// focus on the client-side here as it's ultimately the client-side rendering we
|
||||
// are interested in for this discussion.
|
||||
//
|
||||
// A container isn't just a big ol' list of objects, it's more than that. You may
|
||||
// have seen various error messages like "Object is not out of the bins" etc?
|
||||
//
|
||||
// The Container splits up the world into cubes called bins. When an object is
|
||||
// added to the scene, it's bounding-box is used to find which of these bins it
|
||||
// belongs in. Basically it identifies a box in the world. If the object is too
|
||||
// big then it gets put into a linear list called the overflow bin (where naughty
|
||||
// objects go).
|
||||
//
|
||||
// When you do a CastRay using the engine it basically checks which of these
|
||||
// bins it intersects. It then calls all the objects in turn that reside in these
|
||||
// bins. The objects can then do their own, perhaps more detailed, collision check
|
||||
// that may be polygon perfect or just the bounding-box, it's entirely upto the
|
||||
// object itself.
|
||||
//
|
||||
// Where is this going you say? Well, this system is also used to determine what
|
||||
// objects are in the view. The viewing frustum defines a region that can be
|
||||
// checked to see which bins it intersects (plus the naughty objects in the overflow
|
||||
// bin). Using this, these objects "in-scope" have their "prepRenderImage" called
|
||||
// to allow them to do exactly that, prepare a render image.
|
||||
//
|
||||
// Phew! Well what's a render image you say? Boy am I glad you asked that!
|
||||
//
|
||||
// A "SceneRenderImage" is simply a structure that defines the rendering attributes
|
||||
// of the object that control the way the SceneTraversal routines handle it.
|
||||
// Important factors such as is the object translucent (in which case it needs
|
||||
// sorted back->front) can be specified here.
|
||||
//
|
||||
// In my example, you will see me dynamically allocating a "SceneRenderImage",
|
||||
// populating relevant fields and then inserting it into the SceneState. You don't
|
||||
// need to destroy it, the SceneGraph will do that after the frame is complete.
|
||||
//
|
||||
// There are lots of fields that I just haven't got the energy to go into here but
|
||||
// two important ones I will. The "isTranslucent" field tells the SceneGraph that
|
||||
// at least one portion of your object has transparency. If you didn't already
|
||||
// know it, rendering transparent objects requires that objects be rendered from
|
||||
// back to front (far to near) order to look correct. I won't go into why this is
|
||||
// so because then I'm getting into imaging and then I'll really bore you. ;)
|
||||
//
|
||||
// The second important field is "sortType" which allows you to specify the way
|
||||
// the object is handled by the scene. You can use the following ...
|
||||
//
|
||||
// Non-translucent objects ...
|
||||
//
|
||||
// Sky - Specialised for Sky object only.
|
||||
// Terrain - Specialised for Terrain object only.
|
||||
// Normal - Standard one to use for non-translucent objects.
|
||||
//
|
||||
// Translucent objects only ...
|
||||
//
|
||||
// Point - Object is a point defined by state->poly[0]
|
||||
// Plane - Object is a plane defined by state->poly[0-3]
|
||||
// EndSort - Object should appear after everything else has rendered
|
||||
// BeginSort - Object should appear before everything else has rendered
|
||||
//
|
||||
// The "EndSort" is useful for rendering lens flares which need to be rendered
|
||||
// after everything else has been rendered.
|
||||
//
|
||||
// The "BeginSort" is handy for rendering stuff behind the terrain but after
|
||||
// the Sky like my fxSunLight object which renders a remote object and a local
|
||||
// object.
|
||||
//
|
||||
// This brings me to an interesting point. You can insert more than one
|
||||
// SceneRenderImage into the SceneState during the call to "prepRenderImage"
|
||||
// which results in the "renderObject" being called more than once at the
|
||||
// point defined by the "SceneRenderImage"s attributes. I do this with the
|
||||
// fxSunLight but be sure you know what you are doing with this as you can
|
||||
// significantly reduce your framerate by causing the same objects to be
|
||||
// rendered multiple times.
|
||||
//
|
||||
// Why this complexity? Well, it's a very powerful method to use because you
|
||||
// do all sorts of wizardry by traversing scene portals, clipping the frustum
|
||||
// and iterating the new frustum upto a specified depth to give you the
|
||||
// ability to create mirrors, water reflections and other portal effects.
|
||||
//
|
||||
//
|
||||
// *** renderObject ***
|
||||
//
|
||||
// Alrighty then! The SceneTraversal is stuffed with "SceneRenderImage"s, it
|
||||
// then does all the sorting it needs and then proceeds to actually act on them.
|
||||
//
|
||||
// Because each "SceneRenderImage" has a reference to the object (notice the line
|
||||
// that adds "state->obj = this", it then calls the "renderObject" for each object.
|
||||
//
|
||||
// Now we are nearly ready to render. When you enter the "renderObjec" function
|
||||
// we are in what is known as the Canonical state. It's just another way of
|
||||
// saying a standard state or a consistent state that is guaranteed everytime
|
||||
// we get to this position. This is handy for many reason but mostly because
|
||||
// you reduce the possibilty of other objects' state settings interacting with
|
||||
// your functions. Imagine having to reset every possible state setting that could
|
||||
// possibly affect you, nightmare!
|
||||
//
|
||||
// It's always good to check for this state with an AssertFatal at the beginning
|
||||
// and end of this function.
|
||||
//
|
||||
// First-up, we get the current timestamp. We use "getVirtualMilliseconds" here
|
||||
// that gives us the virtual game timeslice timestamp and we calculate the
|
||||
// elapsed time since our last render. This is useful because we can use it by
|
||||
// multiplying it with our changes to give us a frame-rate independant animation.
|
||||
// This is also handy as you can normalise your object attributes in units/second.
|
||||
//
|
||||
// We then check the texture handle in the example, we can't render without it.
|
||||
// This is specific to this example and can be ignored for you own object if you wish.
|
||||
// Note though, that as soon as you have changed the rendering state in any way
|
||||
// then you should restore the canonical state before returning otherwise you
|
||||
// will get a fatal assertion further on down the line!
|
||||
//
|
||||
// I'm not going to explain the rendering pipeline here because there are many
|
||||
// books which do the same. Drop me an email and I'll recommend one, I think
|
||||
// I've personally got them all!!
|
||||
//
|
||||
// We *must* save the PROJECTION and MODELVIEW matrices plus the VIEWPORT so
|
||||
// that we can restore them to our nice and friendly canonical state before exit.
|
||||
//
|
||||
// With everything saved, we multiply the MODELVIEW by our objects transform
|
||||
// to effectively move our origin to the objects' position. All our graphical
|
||||
// commands are then in object-space (or at-least relative to the objects origin).
|
||||
//
|
||||
// I won't explain the rest of the function because it's just OpenGL (possibly
|
||||
// translated into DirectX) and I'm not here to teach you that!
|
||||
//
|
||||
// Before we exit we restore canonical state which is really important. As I
|
||||
// stated above, I do an assertion to double-check this. You can never be to
|
||||
// cautious with this and it goes away in the RELEASE build anyway.
|
||||
//
|
||||
//
|
||||
// *** packUpdate ***
|
||||
//
|
||||
// Right, we are back to the networking. Remember above (inspectPostApply) when
|
||||
// we made a call to "setMaskBits(...)"?
|
||||
//
|
||||
// After we did that, this function gets called. Remember that we are now
|
||||
// server-side. This function effectively queues-up a bit-stream to be sent
|
||||
// to the client (irrelevant of whether the client is on the same PC or half-way
|
||||
// around the world).
|
||||
//
|
||||
// First-up we call the parent so that it can get any data it owns sent-out.
|
||||
//
|
||||
// We then do something a little clever. When the function was called, it was
|
||||
// passed the mask that we sent using the "setMaskBits(...)" function.
|
||||
//
|
||||
// When designing your objects you can split the data up into groups that
|
||||
// you can get sent using the appropriate mask(s).
|
||||
//
|
||||
// For each group you *always* write a flag signalling whether the group has
|
||||
// data to send. The client will check this and know whether the following
|
||||
// data is the rest of the group data or another group flag.
|
||||
//
|
||||
// In the example I have only one group controlled by the mask,
|
||||
// "fxRenderObjectMask". Because I do a boolean "AND" against the passed-in
|
||||
// mask I effectively send whether the group is being sent or not. The
|
||||
// "writeFlag" function is also kind enough to return the result of this
|
||||
// masking so that you can use it as a condition in an if(cond) statement as
|
||||
// I do.
|
||||
//
|
||||
// Within this block you can call a multitude of functions from the BitStream
|
||||
// class that allow you to write-out your data to the network.
|
||||
//
|
||||
// The return value here is important as it becomes the new state mask used by
|
||||
// the networking code. If you manage to send all your data then you should
|
||||
// return a zero. Returning any other mask value results in the "packUpdate"
|
||||
// function being called again with the returned mask. Typically you would
|
||||
// return the value from the "Parent::packUpdate" function" which which returns
|
||||
// zero. If there are 'blocks' of data that you couldn't pack for any reason
|
||||
// and you want to try again next time then you should return something like
|
||||
// "mask & ~(state flags sent)". To cut a long story short though, returning
|
||||
// zero indicates that you send all your data and the story ends there unless
|
||||
// you are doing something a little more technical!
|
||||
//
|
||||
//
|
||||
// *** unpackUpdate ***
|
||||
//
|
||||
// If you've understood the above then you shouldn't have any problems here.
|
||||
//
|
||||
// You should also know that we are now client-side.
|
||||
//
|
||||
// Eventually, after the "packUpdate" function was called (for each client),
|
||||
// the data is sent out to respective clients. It is important to note that
|
||||
// the "packUpdate" function is called once for each client connected and that
|
||||
// each client maintains it's own state mask.
|
||||
//
|
||||
// First-up here is to do the friendly thing and call the parents "unpackUpdate"
|
||||
// routine to allow it to load it's data from the stream.
|
||||
//
|
||||
// We then call "readFlag" which should correspond to the flag we wrote in the
|
||||
// "packUpdate" function. If it's true then we know that the group data follows
|
||||
// and we proceed to read it.
|
||||
//
|
||||
// It's using this "readFlag" then reading group data that we can control exactly
|
||||
// what data elements get sent/received. You could do a mask per data item but that
|
||||
// would be overkill. If you look deeper you find that the stream read/write
|
||||
// commands also let you save bandwidth by allowing you to specify bit-lengths
|
||||
// of data items but be sure you know what you are doing with these.
|
||||
//
|
||||
// Another interesting note is that after the data has been loaded I load-up
|
||||
// any specified textures here. Most of the standard engine objects *don't* do
|
||||
// this and only load them up in the "onAdd()" function (see above) which
|
||||
// obviously only gets called once at startup. This accounts for why you need
|
||||
// to restart the mission to see your changes. I recently modified the "Sky"
|
||||
// object by adding the "loadDML()" call into the client-side "unpackUpdate"
|
||||
// function.
|
||||
//
|
||||
// Also, note that you should never load texture resources on the server as the
|
||||
// server doesn't actually do any rendering and so it's pointless.
|
||||
//
|
||||
// Also, because some functions are called server-side *and* client-side you need a
|
||||
// method of knowing which side you are on and doing an appropriate action.
|
||||
// You can do this with the calls "isClientObject()" and "isServerObject()".
|
||||
//
|
||||
// ******************
|
||||
//
|
||||
// Well, I hope you found this informative and I'm sorry if I didn't go into
|
||||
// some areas in enough detail but I had to limit this somehow.
|
||||
//
|
||||
// If you have any specific questions then drop me an email to...
|
||||
//
|
||||
// melv.may@btinternet.com
|
||||
//
|
||||
// All the best everyone,
|
||||
//
|
||||
// - Melv.
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Put the function in /example/common/editor/ObjectBuilderGui.gui [around line 458] ...
|
||||
//
|
||||
// function ObjectBuilderGui::buildfxRenderObject(%this)
|
||||
// {
|
||||
// %this.className = "fxRenderObject";
|
||||
// %this.process();
|
||||
// }
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Put this in /example/common/editor/EditorGui.cs in [function Creator::init( %this )]
|
||||
//
|
||||
// %Environment_Item[ next free entry ] = "fxRenderObject"; <-- ADD THIS.
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
extern bool gEditingMission;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
IMPLEMENT_CO_NETOBJECT_V1(fxRenderObject);
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Class: fxRenderObject
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
fxRenderObject::fxRenderObject()
|
||||
{
|
||||
// Setup NetObject.
|
||||
mTypeMask |= StaticObjectType | StaticTSObjectType | StaticRenderedObjectType;
|
||||
mNetFlags.set(Ghostable);
|
||||
|
||||
// Reset Last Render Time.
|
||||
mLastRenderTime = 0;
|
||||
|
||||
// Texture Handle.
|
||||
mTextureHandle = NULL;
|
||||
// Flare Texture Name.
|
||||
mTextureName = StringTable->insert("");
|
||||
|
||||
// Reset Quad Size.
|
||||
mQuadSize = 5.0f;
|
||||
// Reset Quad Rotate Speed.
|
||||
mQuadRotateSpeed = 90.0f;
|
||||
|
||||
// Reset Current Angle.
|
||||
mCurrentAngle = 0.0f;
|
||||
|
||||
mObjColor = ColorI(255, 0, 0);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
fxRenderObject::~fxRenderObject()
|
||||
{
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void fxRenderObject::initPersistFields()
|
||||
{
|
||||
// Initialise parents' persistent fields.
|
||||
Parent::initPersistFields();
|
||||
|
||||
// Add out own persistent fields.
|
||||
//addGroup( "MyFirstGroup1" );
|
||||
addField( "QuadSize", TypeF32, Offset( mQuadSize, fxRenderObject ) );
|
||||
addField( "QuadRotateSpeed",TypeF32, Offset( mQuadRotateSpeed, fxRenderObject ) );
|
||||
addField( "Texture", TypeFilename, Offset( mTextureName, fxRenderObject ) );
|
||||
addField( "ObjColor", TypeColorI, Offset( mObjColor, fxRenderObject ) );
|
||||
//enddGroup( "MyFirstGroup1" );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool fxRenderObject::onAdd()
|
||||
{
|
||||
if(!Parent::onAdd()) return(false);
|
||||
|
||||
// Calculate Quad Radius.
|
||||
F32 QuadHalfSize = mQuadSize / 2.0f;
|
||||
|
||||
// Set initial bounding box.
|
||||
//
|
||||
// NOTE:- Set this box to completely encapsulate your object.
|
||||
// You must reset the world box and set the render transform
|
||||
// after changing this.
|
||||
mObjBox.min.set( -QuadHalfSize, -0.5f, -QuadHalfSize );
|
||||
mObjBox.max.set( QuadHalfSize, +0.5f, QuadHalfSize );
|
||||
// Reset the World Box.
|
||||
resetWorldBox();
|
||||
// Set the Render Transform.
|
||||
setRenderTransform(mObjToWorld);
|
||||
|
||||
// Add to Scene.
|
||||
addToScene();
|
||||
|
||||
// Return OK.
|
||||
return(true);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void fxRenderObject::onRemove()
|
||||
{
|
||||
// Remove from Scene.
|
||||
removeFromScene();
|
||||
|
||||
// Do Parent.
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void fxRenderObject::inspectPostApply()
|
||||
{
|
||||
// Set Parent.
|
||||
Parent::inspectPostApply();
|
||||
|
||||
// Set fxPortal Mask.
|
||||
setMaskBits(fxRenderObjectMask);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void fxRenderObject::onEditorEnable()
|
||||
{
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void fxRenderObject::onEditorDisable()
|
||||
{
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool fxRenderObject::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->isTranslucent = false;
|
||||
image->sortType = SceneRenderImage::Normal;
|
||||
|
||||
// Insert it into the scene images.
|
||||
state->insertRenderImage(image);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void fxRenderObject::renderObject(SceneState* state, SceneRenderImage*)
|
||||
{
|
||||
// Check we are in Canonical State.
|
||||
AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on entry");
|
||||
|
||||
// Calculate Elapsed Time and take new Timestamp.
|
||||
S32 Time = Platform::getVirtualMilliseconds();
|
||||
F32 ElapsedTime = (Time - mLastRenderTime) * 0.001f;
|
||||
mLastRenderTime = Time;
|
||||
|
||||
// Return if we don't have a texture.
|
||||
if (!mTextureHandle) return;
|
||||
|
||||
// Save state.
|
||||
RectI viewport;
|
||||
|
||||
// Save Projection Matrix so we can restore Canonical state at exit.
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
|
||||
// Save Viewport so we can restore Canonical state at exit.
|
||||
dglGetViewport(&viewport);
|
||||
|
||||
// Setup the projection to the current frustum.
|
||||
//
|
||||
// NOTE:- You should let the SceneGraph drive the frustum as it
|
||||
// determines portal clipping etc.
|
||||
// It also leaves us with the MODELVIEW current.
|
||||
//
|
||||
state->setupBaseProjection();
|
||||
|
||||
// Save ModelView Matrix so we can restore Canonical state at exit.
|
||||
glPushMatrix();
|
||||
|
||||
// Transform by the objects' transform e.g move it.
|
||||
dglMultMatrix(&getTransform());
|
||||
|
||||
// Rotate by Rotate Speed.
|
||||
//
|
||||
// NOTE:- We use the elapsed time as a coeficient,
|
||||
// that way we get consistent rotational speed
|
||||
// independant of frame-rate.
|
||||
//
|
||||
mCurrentAngle += mFmod(mQuadRotateSpeed * ElapsedTime, 360);
|
||||
|
||||
// Rotate Quad by current roation.
|
||||
glRotatef(mCurrentAngle, 0,0,1);
|
||||
|
||||
// Setup our rendering state (alpha blending).
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
// Enable Texturing.
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
// Select the objects' texture.
|
||||
glBindTexture(GL_TEXTURE_2D, mTextureHandle.getGLName());
|
||||
|
||||
// Set Colour/Alpha.
|
||||
glColor4f(1,1,1,1);
|
||||
|
||||
// Calculate Quad Radius.
|
||||
F32 QuadHalfSize = mQuadSize / 2.0f;
|
||||
|
||||
// Draw a Quad.
|
||||
//
|
||||
// NOTE:- We draw in object space here and *not* world-space.
|
||||
// Notice that Z is UP in this system and XY lie on the terrain plane.
|
||||
//
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(0,0);
|
||||
glVertex3f(-QuadHalfSize,0,+QuadHalfSize);
|
||||
glTexCoord2f(1,0);
|
||||
glVertex3f(+QuadHalfSize,0,+QuadHalfSize);
|
||||
glTexCoord2f(1,1);
|
||||
glVertex3f(+QuadHalfSize,0,-QuadHalfSize);
|
||||
glTexCoord2f(0,1);
|
||||
glVertex3f(-QuadHalfSize,0,-QuadHalfSize);
|
||||
glEnd();
|
||||
|
||||
// Restore our canonical rendering state.
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
// Restore our canonical matrix state.
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
// Restore our canonical viewport state.
|
||||
dglSetViewport(viewport);
|
||||
|
||||
// Check we have restored Canonical State.
|
||||
AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on exit");
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
U32 fxRenderObject::packUpdate(NetConnection * con, U32 mask, BitStream * stream)
|
||||
{
|
||||
// Pack Parent.
|
||||
U32 retMask = Parent::packUpdate(con, mask, stream);
|
||||
|
||||
// Write fxPortal Mask Flag.
|
||||
if (stream->writeFlag(mask & fxRenderObjectMask))
|
||||
{
|
||||
// Write Object Transform.
|
||||
stream->writeAffineTransform(mObjToWorld);
|
||||
// Write Texture Name.
|
||||
stream->writeString(mTextureName);
|
||||
// Write Quad Size.
|
||||
stream->write(mQuadSize);
|
||||
// Write Quad Rotate Speed.
|
||||
stream->write(mQuadRotateSpeed);
|
||||
// Write Object Color
|
||||
stream->write( mObjColor );
|
||||
}
|
||||
|
||||
// Were done ...
|
||||
return(retMask);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void fxRenderObject::unpackUpdate(NetConnection * con, BitStream * stream)
|
||||
{
|
||||
// Unpack Parent.
|
||||
Parent::unpackUpdate(con, stream);
|
||||
|
||||
// Read fxPortal Mask Flag.
|
||||
if(stream->readFlag())
|
||||
{
|
||||
MatrixF ObjectMatrix;
|
||||
|
||||
// Read Object Transform.
|
||||
stream->readAffineTransform(&ObjectMatrix);
|
||||
// Read Texture Name.
|
||||
mTextureName = StringTable->insert(stream->readSTString());
|
||||
// Read Quad Size.
|
||||
stream->read(&mQuadSize);
|
||||
// Read Quad Rotate Speed.
|
||||
stream->read(&mQuadRotateSpeed);
|
||||
// Read Object Color
|
||||
stream->read( &mObjColor );
|
||||
|
||||
|
||||
// Set Transform.
|
||||
setTransform(ObjectMatrix);
|
||||
|
||||
// Reset our previous texture handle.
|
||||
mTextureHandle = NULL;
|
||||
// Load the texture (if we've got one)
|
||||
if (*mTextureName) mTextureHandle = TextureHandle(mTextureName, BitmapTexture, true);
|
||||
|
||||
// Calculate Quad Radius.
|
||||
F32 QuadHalfSize = mQuadSize / 2.0f;
|
||||
|
||||
// Set bounding box.
|
||||
//
|
||||
// NOTE:- Set this box to completely encapsulate your object.
|
||||
// You must reset the world box and set the render transform
|
||||
// after changing this.
|
||||
mObjBox.min.set( -QuadHalfSize, -0.5f, -QuadHalfSize );
|
||||
mObjBox.max.set( QuadHalfSize, +0.5f, QuadHalfSize );
|
||||
// Reset the World Box.
|
||||
resetWorldBox();
|
||||
// Set the Render Transform.
|
||||
setRenderTransform(mObjToWorld);
|
||||
}
|
||||
}
|
77
engine/game/fx/fxRenderObject.h
Executable file
77
engine/game/fx/fxRenderObject.h
Executable file
@ -0,0 +1,77 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
//
|
||||
// Written by Melvyn May, 9th September 2002.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _FXRENDEROBJECT_H_
|
||||
#define _FXRENDEROBJECT_H_
|
||||
|
||||
#ifndef _SCENEOBJECT_H_
|
||||
#include "sim/sceneObject.h"
|
||||
#endif
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Class: fxRenderObject
|
||||
//------------------------------------------------------------------------------
|
||||
class fxRenderObject : public SceneObject
|
||||
{
|
||||
private:
|
||||
typedef SceneObject Parent;
|
||||
|
||||
protected:
|
||||
|
||||
// Create and use these to specify custom events.
|
||||
//
|
||||
// NOTE:- Using these allows you to group the changes into related
|
||||
// events. No need to change everything if something minor
|
||||
// changes. Only really important if you have *lots* of these
|
||||
// objects at start-up or you send alot of changes whilst the
|
||||
// game is in progress.
|
||||
//
|
||||
// Use "setMaskBits(fxRenderObjectMask)" to signal.
|
||||
|
||||
enum { fxRenderObjectMask = (1 << 0),
|
||||
fxRenderObjectAnother = (1 << 1) };
|
||||
|
||||
S32 mLastRenderTime;
|
||||
TextureHandle mTextureHandle;
|
||||
F32 mCurrentAngle;
|
||||
|
||||
// Fields.
|
||||
F32 mQuadSize;
|
||||
F32 mQuadRotateSpeed;
|
||||
StringTableEntry mTextureName;
|
||||
ColorI mObjColor;
|
||||
|
||||
|
||||
|
||||
public:
|
||||
fxRenderObject();
|
||||
~fxRenderObject();
|
||||
|
||||
// SceneObject
|
||||
void renderObject(SceneState*, SceneRenderImage*);
|
||||
virtual bool prepRenderImage(SceneState*, const U32 stateKey, const U32 startZone,
|
||||
const bool modifyBaseZoneState = false);
|
||||
|
||||
// SimObject
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
void onEditorEnable();
|
||||
void onEditorDisable();
|
||||
void inspectPostApply();
|
||||
|
||||
// NetObject
|
||||
U32 packUpdate(NetConnection *, U32, BitStream *);
|
||||
void unpackUpdate(NetConnection *, BitStream *);
|
||||
|
||||
// ConObject.
|
||||
static void initPersistFields();
|
||||
|
||||
// Declare Console Object.
|
||||
DECLARE_CONOBJECT(fxRenderObject);
|
||||
};
|
||||
|
||||
#endif // _FXRENDEROBJECT_H_
|
905
engine/game/fx/fxShapeReplicator.cc
Executable file
905
engine/game/fx/fxShapeReplicator.cc
Executable file
@ -0,0 +1,905 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
|
183
engine/game/fx/fxShapeReplicator.h
Executable file
183
engine/game/fx/fxShapeReplicator.h
Executable file
@ -0,0 +1,183 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Written by Melvyn May, 13th March 2002.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _SHAPEREPLICATOR_H_
|
||||
#define _SHAPEREPLICATOR_H_
|
||||
|
||||
#ifndef _SCENEOBJECT_H_
|
||||
#include "sim/sceneObject.h"
|
||||
#endif
|
||||
#ifndef _TSSTATIC_H_
|
||||
#include "game/tsStatic.h"
|
||||
#endif
|
||||
|
||||
#ifndef _TSSHAPEINSTANCE_H_
|
||||
#include "ts/tsShapeInstance.h"
|
||||
#endif
|
||||
|
||||
#define AREA_ANIMATION_ARC (1.0f / 360.0f)
|
||||
|
||||
#define FXREPLICATOR_COLLISION_MASK ( TerrainObjectType | \
|
||||
InteriorObjectType | \
|
||||
StaticObjectType | \
|
||||
WaterObjectType )
|
||||
|
||||
#define FXREPLICATOR_NOWATER_COLLISION_MASK ( TerrainObjectType | \
|
||||
InteriorObjectType | \
|
||||
StaticObjectType )
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Class: fxShapeReplicatedStatic
|
||||
//------------------------------------------------------------------------------
|
||||
class fxShapeReplicatedStatic : public TSStatic
|
||||
{
|
||||
private:
|
||||
typedef SceneObject Parent;
|
||||
|
||||
public:
|
||||
fxShapeReplicatedStatic() {};
|
||||
~fxShapeReplicatedStatic() {};
|
||||
void touchNetFlags(const U32 m, bool setflag = true) { if (setflag) mNetFlags.set(m); else mNetFlags.clear(m); };
|
||||
TSShape* getShape(void) { return mShapeInstance->getShape(); };
|
||||
void setTransform(const MatrixF & mat) { Parent::setTransform(mat); setRenderTransform(mat); };
|
||||
|
||||
DECLARE_CONOBJECT(fxShapeReplicatedStatic);
|
||||
};
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Class: fxShapeReplicator
|
||||
//------------------------------------------------------------------------------
|
||||
class fxShapeReplicator : public SceneObject
|
||||
{
|
||||
private:
|
||||
typedef SceneObject Parent;
|
||||
|
||||
protected:
|
||||
|
||||
void CreateShapes(void);
|
||||
void DestroyShapes(void);
|
||||
void RenewShapes(void);
|
||||
|
||||
enum
|
||||
{
|
||||
ReplicationMask = (1 << 0),
|
||||
advancedStaticOptionsMask = ReplicationMask << 1,
|
||||
NextFreeMask = ReplicationMask << 2
|
||||
};
|
||||
|
||||
U32 mCreationAreaAngle;
|
||||
bool mClientReplicationStarted;
|
||||
bool mAddedToScene;
|
||||
U32 mCurrentShapeCount;
|
||||
Vector<fxShapeReplicatedStatic*> mReplicatedShapes;
|
||||
MRandomLCG RandomGen;
|
||||
|
||||
|
||||
public:
|
||||
fxShapeReplicator();
|
||||
~fxShapeReplicator();
|
||||
|
||||
|
||||
void StartUp(void);
|
||||
void ShowReplication(void);
|
||||
void HideReplication(void);
|
||||
|
||||
// SceneObject
|
||||
void renderObject(SceneState *state, SceneRenderImage *image);
|
||||
virtual bool prepRenderImage(SceneState *state, const U32 stateKey, const U32 startZone,
|
||||
const bool modifyBaseZoneState = false);
|
||||
|
||||
// SimObject
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
void onEditorEnable();
|
||||
void onEditorDisable();
|
||||
void inspectPostApply();
|
||||
|
||||
// NetObject
|
||||
U32 packUpdate(NetConnection *conn, U32 mask, BitStream *stream);
|
||||
void unpackUpdate(NetConnection *conn, BitStream *stream);
|
||||
|
||||
// ConObject.
|
||||
static void initPersistFields();
|
||||
|
||||
// Field Data.
|
||||
class tagFieldData
|
||||
{
|
||||
public:
|
||||
|
||||
U32 mSeed;
|
||||
StringTableEntry mShapeFile;
|
||||
U32 mShapeCount;
|
||||
U32 mShapeRetries;
|
||||
bool mFixShapeAspect;
|
||||
Point3F mShapeScaleMin;
|
||||
Point3F mShapeScaleMax;
|
||||
Point3F mShapeRotateMin;
|
||||
Point3F mShapeRotateMax;
|
||||
U32 mInnerRadiusX;
|
||||
U32 mInnerRadiusY;
|
||||
U32 mOuterRadiusX;
|
||||
U32 mOuterRadiusY;
|
||||
S32 mOffsetZ;
|
||||
bool mAllowOnTerrain;
|
||||
bool mAllowOnInteriors;
|
||||
bool mAllowStatics;
|
||||
bool mAllowOnWater;
|
||||
S32 mAllowedTerrainSlope;
|
||||
bool mAlignToTerrain;
|
||||
bool mAllowWaterSurface;
|
||||
Point3F mTerrainAlignment;
|
||||
bool mInteractions;
|
||||
bool mHideReplications;
|
||||
bool mShowPlacementArea;
|
||||
U32 mPlacementBandHeight;
|
||||
ColorF mPlaceAreaColour;
|
||||
|
||||
tagFieldData()
|
||||
{
|
||||
// Set Defaults.
|
||||
mSeed = gRandGen.randI(0, 1000000000);
|
||||
mShapeFile = StringTable->insert("");
|
||||
mShapeCount = 10;
|
||||
mShapeRetries = 100;
|
||||
mInnerRadiusX = 0;
|
||||
mInnerRadiusY = 0;
|
||||
mOuterRadiusX = 100;
|
||||
mOuterRadiusY = 100;
|
||||
mOffsetZ = 0;
|
||||
|
||||
mAllowOnTerrain = true;
|
||||
mAllowOnInteriors = true;
|
||||
mAllowStatics = true;
|
||||
mAllowOnWater = false;
|
||||
mAllowWaterSurface = false;
|
||||
mAllowedTerrainSlope= 90;
|
||||
mAlignToTerrain = false;
|
||||
mInteractions = true;
|
||||
|
||||
mHideReplications = false;
|
||||
|
||||
mShowPlacementArea = true;
|
||||
mPlacementBandHeight = 25;
|
||||
mPlaceAreaColour .set(0.4f, 0, 0.8f);
|
||||
|
||||
mFixShapeAspect = false;
|
||||
mShapeScaleMin .set(1, 1, 1);
|
||||
mShapeScaleMax .set(1, 1, 1);
|
||||
mShapeRotateMin .set(0, 0, 0);
|
||||
mShapeRotateMax .set(0, 0, 0);
|
||||
mTerrainAlignment .set(1, 1, 1);
|
||||
}
|
||||
|
||||
} mFieldData;
|
||||
|
||||
// Declare Console Object.
|
||||
DECLARE_CONOBJECT(fxShapeReplicator);
|
||||
};
|
||||
|
||||
#endif // _SHAPEREPLICATOR_H_
|
2176
engine/game/fx/fxSunLight.cc
Executable file
2176
engine/game/fx/fxSunLight.cc
Executable file
File diff suppressed because it is too large
Load Diff
252
engine/game/fx/fxSunLight.h
Executable file
252
engine/game/fx/fxSunLight.h
Executable file
@ -0,0 +1,252 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine - fxLight
|
||||
//
|
||||
// Written by Melvyn May, 27th August 2002.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _FXSUNLIGHT_H_
|
||||
#define _FXSUNLIGHT_H_
|
||||
|
||||
#ifndef _SCENEOBJECT_H_
|
||||
#include "sim/sceneObject.h"
|
||||
#endif
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Class: fxSunLight
|
||||
//------------------------------------------------------------------------------
|
||||
class fxSunLight : public SceneObject
|
||||
{
|
||||
private:
|
||||
typedef SceneObject Parent;
|
||||
|
||||
U32 CheckKeySyntax(StringTableEntry Key);
|
||||
void CheckAnimationKeys(void);
|
||||
F32 GetLerpKey(StringTableEntry Key, U32 PosFrom, U32 PosTo, F32 ValueFrom, F32 ValueTo, F32 Lerp);
|
||||
void AnimateSun(F32 ElapsedTime);
|
||||
void InitialiseAnimation(void);
|
||||
void ResetAnimation(void);
|
||||
bool TestLOS(const Point3F& Pos);
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
enum { fxSunLightConfigChangeMask = BIT(0) };
|
||||
|
||||
bool mAddedToScene;
|
||||
|
||||
MRandomLCG RandomGen;
|
||||
|
||||
// Textures.
|
||||
TextureHandle mLocalFlareTextureHandle;
|
||||
TextureHandle mRemoteFlareTextureHandle;
|
||||
|
||||
F32 mElapsedTime;
|
||||
S32 mLastRenderTime;
|
||||
F32 mLocalFlareScale;
|
||||
Point3F mSunlightPosition; // Sunlight Frame Position.
|
||||
|
||||
public:
|
||||
fxSunLight();
|
||||
~fxSunLight();
|
||||
|
||||
// *********************************
|
||||
// Configuration Interface.
|
||||
// *********************************
|
||||
|
||||
// Debugging.
|
||||
void setEnable(bool Status);
|
||||
|
||||
// Media.
|
||||
void setFlareBitmaps(const char* LocalName, const char* RemoteName);
|
||||
|
||||
// Sun Orbit.
|
||||
void setSunAzimuth(F32 Azimuth);
|
||||
void setSunElevation(F32 Elevation);
|
||||
|
||||
// Flare.
|
||||
void setFlareTP(bool Status);
|
||||
void setFlareColour(ColorF Colour);
|
||||
void setFlareBrightness(F32 Brightness);
|
||||
void setFlareSize(F32 Size);
|
||||
void setFadeTime(F32 Time);
|
||||
void setBlendMode(U32 Mode);
|
||||
|
||||
// Animation Options.
|
||||
void setUseColour(bool Status);
|
||||
void setUseBrightness(bool Status);
|
||||
void setUseRotation(bool Status);
|
||||
void setUseSize(bool Status);
|
||||
void setUseAzimuth(bool Status);
|
||||
void setUseElevation(bool Status);
|
||||
void setLerpColour(bool Status);
|
||||
void setLerpBrightness(bool Status);
|
||||
void setLerpRotation(bool Status);
|
||||
void setLerpSize(bool Status);
|
||||
void setLerpAzimuth(bool Status);
|
||||
void setLerpElevation(bool Status);
|
||||
void setLinkFlareSize(bool Status);
|
||||
void setSingleColourKeys(bool Status);
|
||||
|
||||
// Animation Extents.
|
||||
void setMinColour(ColorF Colour);
|
||||
void setMaxColour(ColorF Colour);
|
||||
void setMinBrightness(F32 Brightness);
|
||||
void setMaxBrightness(F32 Brightness);
|
||||
void setMinRotation(F32 Rotation);
|
||||
void setMaxRotation(F32 Rotation);
|
||||
void setMinSize(F32 Size);
|
||||
void setMaxSize(F32 Size);
|
||||
void setMinAzimuth(F32 Azimuth);
|
||||
void setMaxAzimuth(F32 Azimuth);
|
||||
void setMinElevation(F32 Elevation);
|
||||
void setMaxElevation(F32 Elevation);
|
||||
|
||||
// Animation Keys.
|
||||
void setRedKeys(const char* Keys);
|
||||
void setGreenKeys(const char* Keys);
|
||||
void setBlueKeys(const char* Keys);
|
||||
void setBrightnessKeys(const char* Keys);
|
||||
void setRotationKeys(const char* Keys);
|
||||
void setSizeKeys(const char* Keys);
|
||||
void setAzimuthKeys(const char* Keys);
|
||||
void setElevationKeys(const char* Keys);
|
||||
|
||||
// Animation Times.
|
||||
void setColourTime(F32 Time);
|
||||
void setBrightnessTime(F32 Time);
|
||||
void setRotationTime(F32 Time);
|
||||
void setSizeTime(F32 Time);
|
||||
void setAzimuthTime(F32 Time);
|
||||
void setElevationTime(F32 Time);
|
||||
|
||||
// Misc,
|
||||
void reset(void);
|
||||
|
||||
// SceneObject
|
||||
bool prepRenderImage(SceneState* state, const U32 stateKey, const U32 startZone, const bool modifyBaseZoneState);
|
||||
void renderObject(SceneState *state, SceneRenderImage *image);
|
||||
|
||||
// SimObject
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
void inspectPostApply();
|
||||
|
||||
// NetObject
|
||||
U32 packUpdate(NetConnection *conn, U32 mask, BitStream *stream);
|
||||
void unpackUpdate(NetConnection *conn, BitStream *stream);
|
||||
|
||||
// ConObject.
|
||||
static void initPersistFields();
|
||||
|
||||
bool mDoneSunLock;
|
||||
|
||||
// Field Data.
|
||||
|
||||
// Debugging.
|
||||
bool mEnable; // Light Enable.
|
||||
|
||||
// Media.
|
||||
StringTableEntry mLocalFlareTextureName; // Local Flare Texture Name.
|
||||
StringTableEntry mRemoteFlareTextureName; // Remote Flare Texture Name.
|
||||
|
||||
// Sun Orbit.
|
||||
F32 mSunAzimuth;
|
||||
F32 mSunElevation;
|
||||
bool mLockToRealSun; // Lock to Real Sun Flag.
|
||||
|
||||
// Flare.
|
||||
bool mFlareTP; // Flare Third Person Flag.
|
||||
ColorF mFlareColour; // Flare Colour.
|
||||
F32 mFlareBrightness; // Brightness.
|
||||
F32 mFlareSize; // Flare Size.
|
||||
F32 mFadeTime; // Fade Time.
|
||||
U32 mBlendMode; // Blend Mode.
|
||||
|
||||
// Animation Options.
|
||||
bool mUseColour; // Use Colour Flag.
|
||||
bool mUseBrightness; // Use Brightness Flag.
|
||||
bool mUseRotation; // Use Rotation Flag.
|
||||
bool mUseSize; // Use Size Flag.
|
||||
bool mUseAzimuth; // Use Azimuth Flag.
|
||||
bool mUseElevation; // Use Elevation Flag.
|
||||
bool mLerpColour; // Lerp Colour Flag.
|
||||
bool mLerpBrightness; // Lerp Brightness Flag.
|
||||
bool mLerpRotation; // Lerp Rotation Flag.
|
||||
bool mLerpSize; // Lerp Size Flag.
|
||||
bool mLerpAzimuth; // Lerp Azimuth Flag.
|
||||
bool mLerpElevation; // Lerp Elevation Flag.
|
||||
bool mLinkFlareSize; // Link Flare Size Animation.
|
||||
bool mSingleColourKeys; // Single-Channel Colour Keys.
|
||||
|
||||
// Animation Extents.
|
||||
ColorF mMinColour; // Minimum Colour.
|
||||
ColorF mMaxColour; // Maximum Colour.
|
||||
F32 mMinBrightness; // Minimum Brightness.
|
||||
F32 mMaxBrightness; // Maximum Brightness.
|
||||
F32 mMinRotation; // Minimum Rotation.
|
||||
F32 mMaxRotation; // Maximum Rotation.
|
||||
F32 mMinSize; // Minimum Size.
|
||||
F32 mMaxSize; // Maximum Size.
|
||||
F32 mMinAzimuth; // Minimum Azimuth.
|
||||
F32 mMaxAzimuth; // Maximum Azimuth.
|
||||
F32 mMinElevation; // Minimum Elevation.
|
||||
F32 mMaxElevation; // Maximum Elevation.
|
||||
|
||||
// Animation Keys.
|
||||
StringTableEntry mRedKeys; // Red Animation Keys.
|
||||
StringTableEntry mGreenKeys; // Green Animation Keys.
|
||||
StringTableEntry mBlueKeys; // Blue Animation Keys.
|
||||
StringTableEntry mBrightnessKeys; // Brightness Animation Keys.
|
||||
StringTableEntry mRotationKeys; // Rotation Animation Keys.
|
||||
StringTableEntry mSizeKeys; // Size Animation Keys.
|
||||
StringTableEntry mAzimuthKeys; // Size Azimuth Keys.
|
||||
StringTableEntry mElevationKeys; // Size Elevation Keys.
|
||||
|
||||
// Animation Times.
|
||||
F32 mColourTime; // Colour Time (Seconds).
|
||||
F32 mBrightnessTime; // Brightness Time.
|
||||
F32 mRotationTime; // Rotation Time.
|
||||
F32 mSizeTime; // Size Time.
|
||||
F32 mAzimuthTime; // Azimuth Time.
|
||||
F32 mElevationTime; // Elevation Time.
|
||||
|
||||
// Current Animation.
|
||||
ColorF mAnimationColour; // Current Colour.
|
||||
F32 mAnimationBrightness; // Current Brightness.
|
||||
F32 mAnimationRotation; // Current Rotation.
|
||||
F32 mAnimationSize; // Current Size.
|
||||
F32 mAnimationAzimuth; // Current Azimuth.
|
||||
F32 mAnimationElevation; // Current Elevation.
|
||||
|
||||
// Elapsed Times.
|
||||
F32 mColourElapsedTime; // Colour Elapsed Time.
|
||||
F32 mBrightnessElapsedTime; // Brightness Elapsed Time.
|
||||
F32 mRotationElapsedTime; // Rotation Elapsed Time.
|
||||
F32 mSizeElapsedTime; // Size Elapsed Time.
|
||||
F32 mAzimuthElapsedTime; // Azimuth Elapsed Time.
|
||||
F32 mElevationElapsedTime; // Elevation Elapsed Time.
|
||||
|
||||
// Time Scales.
|
||||
F32 mColourTimeScale; // Colour Time Scale.
|
||||
F32 mBrightnessTimeScale; // Brightness Time Scale.
|
||||
F32 mRotationTimeScale; // Rotation Time Scale.
|
||||
F32 mSizeTimeScale; // Size Time Scale.
|
||||
F32 mAzimuthTimeScale; // Azimuth Time Scale.
|
||||
F32 mElevationTimeScale; // Elevation Time Scale.
|
||||
|
||||
// Key Lengths (Validity).
|
||||
U32 mRedKeysLength; // Red Keys Length.
|
||||
U32 mGreenKeysLength; // Green Keys Length.
|
||||
U32 mBlueKeysLength; // Blue Keys Length.
|
||||
U32 mBrightnessKeysLength; // Brightness Keys Length.
|
||||
U32 mRotationKeysLength; // Rotation Keys Length.
|
||||
U32 mSizeKeysLength; // Size Keys Length.
|
||||
U32 mAzimuthKeysLength; // Azimuth Keys Length.
|
||||
U32 mElevationKeysLength; // Elevation Keys Length.
|
||||
|
||||
// Declare Console Object.
|
||||
DECLARE_CONOBJECT(fxSunLight);
|
||||
};
|
||||
|
||||
#endif // _FXSUNLIGHT_H_
|
1229
engine/game/fx/lightning.cc
Executable file
1229
engine/game/fx/lightning.cc
Executable file
File diff suppressed because it is too large
Load Diff
214
engine/game/fx/lightning.h
Executable file
214
engine/game/fx/lightning.h
Executable file
@ -0,0 +1,214 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _LIGHTNING_H_
|
||||
#define _LIGHTNING_H_
|
||||
|
||||
#ifndef _GAMEBASE_H_
|
||||
#include "game/gameBase.h"
|
||||
#endif
|
||||
#ifndef _GTEXMANAGER_H_
|
||||
#include "dgl/gTexManager.h"
|
||||
#endif
|
||||
#ifndef _LLIST_H_
|
||||
#include "core/llist.h"
|
||||
#endif
|
||||
#ifndef _COLOR_H_
|
||||
#include "core/color.h"
|
||||
#endif
|
||||
|
||||
class ShapeBase;
|
||||
class LightningStrikeEvent;
|
||||
class AudioProfile;
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
class LightningData : public GameBaseData
|
||||
{
|
||||
typedef GameBaseData Parent;
|
||||
|
||||
public:
|
||||
enum Constants {
|
||||
MaxThunders = 8,
|
||||
MaxTextures = 8
|
||||
};
|
||||
|
||||
//-------------------------------------- Console set variables
|
||||
public:
|
||||
AudioProfile* thunderSounds[MaxThunders];
|
||||
AudioProfile* strikeSound;
|
||||
StringTableEntry strikeTextureNames[MaxTextures];
|
||||
|
||||
//-------------------------------------- load set variables
|
||||
public:
|
||||
S32 thunderSoundIds[MaxThunders];
|
||||
S32 strikeSoundID;
|
||||
|
||||
TextureHandle strikeTextures[MaxTextures];
|
||||
U32 numThunders;
|
||||
|
||||
protected:
|
||||
bool onAdd();
|
||||
|
||||
|
||||
public:
|
||||
LightningData();
|
||||
~LightningData();
|
||||
|
||||
void packData(BitStream*);
|
||||
void unpackData(BitStream*);
|
||||
bool preload(bool server, char errorBuffer[256]);
|
||||
|
||||
DECLARE_CONOBJECT(LightningData);
|
||||
static void initPersistFields();
|
||||
};
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
struct LightningBolt
|
||||
{
|
||||
|
||||
struct Node
|
||||
{
|
||||
Point3F point;
|
||||
VectorF dirToMainLine;
|
||||
};
|
||||
|
||||
struct NodeManager
|
||||
{
|
||||
Node nodeList[10];
|
||||
|
||||
Point3F startPoint;
|
||||
Point3F endPoint;
|
||||
U32 numNodes;
|
||||
F32 maxAngle;
|
||||
|
||||
void generateNodes();
|
||||
};
|
||||
|
||||
NodeManager mMajorNodes;
|
||||
Vector< NodeManager > mMinorNodes;
|
||||
LList< LightningBolt > splitList;
|
||||
|
||||
F32 lifetime;
|
||||
F32 elapsedTime;
|
||||
F32 fadeTime;
|
||||
bool isFading;
|
||||
F32 percentFade;
|
||||
bool startRender;
|
||||
F32 renderTime;
|
||||
|
||||
F32 width;
|
||||
F32 chanceOfSplit;
|
||||
Point3F startPoint;
|
||||
Point3F endPoint;
|
||||
|
||||
U32 numMajorNodes;
|
||||
F32 maxMajorAngle;
|
||||
U32 numMinorNodes;
|
||||
F32 maxMinorAngle;
|
||||
|
||||
LightningBolt();
|
||||
~LightningBolt();
|
||||
|
||||
void createSplit( const Point3F &startPoint, const Point3F &endPoint, U32 depth, F32 width );
|
||||
F32 findHeight( Point3F &point, SceneGraph* sceneManager );
|
||||
void render( const Point3F &camPos );
|
||||
void renderSegment( NodeManager &segment, const Point3F &camPos, bool renderLastPoint );
|
||||
void generate();
|
||||
void generateMinorNodes();
|
||||
void startSplits();
|
||||
void update( F32 dt );
|
||||
|
||||
};
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
class Lightning : public GameBase
|
||||
{
|
||||
typedef GameBase Parent;
|
||||
|
||||
protected:
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
bool onNewDataBlock(GameBaseData* dptr);
|
||||
|
||||
struct Strike {
|
||||
F32 xVal; // Position in cloud layer of strike
|
||||
F32 yVal; // top
|
||||
|
||||
bool targetedStrike; // Is this a targeted strike?
|
||||
U32 targetGID;
|
||||
|
||||
F32 deathAge; // Age at which this strike expires
|
||||
F32 currentAge; // Current age of this strike (updated by advanceTime)
|
||||
|
||||
LightningBolt bolt[3];
|
||||
|
||||
Strike* next;
|
||||
};
|
||||
struct Thunder {
|
||||
F32 tRemaining;
|
||||
Thunder* next;
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
//-------------------------------------- Console set variables
|
||||
public:
|
||||
|
||||
U32 strikesPerMinute;
|
||||
F32 strikeWidth;
|
||||
F32 chanceToHitTarget;
|
||||
F32 strikeRadius;
|
||||
F32 boltStartRadius;
|
||||
ColorF color;
|
||||
ColorF fadeColor;
|
||||
bool useFog;
|
||||
|
||||
// Rendering
|
||||
protected:
|
||||
bool prepRenderImage(SceneState *state, const U32 stateKey, const U32 startZone, const bool modifyBaseZoneState);
|
||||
void renderObject(SceneState *state, SceneRenderImage *image);
|
||||
|
||||
// Time management
|
||||
void processTick(const Move *move);
|
||||
void interpolateTick(F32 delta);
|
||||
void advanceTime(F32 dt);
|
||||
|
||||
// Strike management
|
||||
void scheduleThunder(Strike*);
|
||||
|
||||
// Data members
|
||||
private:
|
||||
LightningData* mDataBlock;
|
||||
|
||||
protected:
|
||||
U32 mLastThink; // Valid only on server
|
||||
|
||||
Strike* mStrikeListHead; // Valid on on the client
|
||||
Thunder* mThunderListHead;
|
||||
|
||||
static const U32 csmTargetMask;
|
||||
|
||||
public:
|
||||
Lightning();
|
||||
~Lightning();
|
||||
|
||||
void applyDamage( const Point3F& hitPosition, const Point3F& hitNormal, SceneObject* hitObject );
|
||||
void warningFlashes();
|
||||
void strikeRandomPoint();
|
||||
void strikeObject(ShapeBase*);
|
||||
void processEvent(LightningStrikeEvent*);
|
||||
|
||||
DECLARE_CONOBJECT(Lightning);
|
||||
static void initPersistFields();
|
||||
|
||||
U32 packUpdate (NetConnection *conn, U32 mask, BitStream *stream);
|
||||
void unpackUpdate(NetConnection *conn, BitStream *stream);
|
||||
};
|
||||
|
||||
#endif // _H_LIGHTNING
|
||||
|
262
engine/game/fx/particleEmitter.cc
Executable file
262
engine/game/fx/particleEmitter.cc
Executable file
@ -0,0 +1,262 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "console/consoleTypes.h"
|
||||
#include "core/bitStream.h"
|
||||
#include "game/fx/particleEmitter.h"
|
||||
#include "game/fx/particleEngine.h"
|
||||
#include "math/mathIO.h"
|
||||
|
||||
IMPLEMENT_CO_DATABLOCK_V1(ParticleEmitterNodeData);
|
||||
IMPLEMENT_CO_NETOBJECT_V1(ParticleEmitterNode);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//--------------------------------------
|
||||
//
|
||||
ParticleEmitterNodeData::ParticleEmitterNodeData()
|
||||
{
|
||||
timeMultiple = 1.0;
|
||||
}
|
||||
|
||||
ParticleEmitterNodeData::~ParticleEmitterNodeData()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void ParticleEmitterNodeData::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
|
||||
addField("timeMultiple", TypeF32, Offset(timeMultiple, ParticleEmitterNodeData));
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool ParticleEmitterNodeData::onAdd()
|
||||
{
|
||||
if(!Parent::onAdd())
|
||||
return false;
|
||||
|
||||
if (timeMultiple < 0.01 || timeMultiple > 100) {
|
||||
Con::warnf("ParticleEmitterNodeData::onAdd(%s): timeMultiple must be between 0.01 and 100", getName());
|
||||
timeMultiple = timeMultiple < 0.01 ? 0.01 : 100;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool ParticleEmitterNodeData::preload(bool server, char errorBuffer[256])
|
||||
{
|
||||
if (Parent::preload(server, errorBuffer) == false)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void ParticleEmitterNodeData::packData(BitStream* stream)
|
||||
{
|
||||
Parent::packData(stream);
|
||||
|
||||
stream->write(timeMultiple);
|
||||
}
|
||||
|
||||
void ParticleEmitterNodeData::unpackData(BitStream* stream)
|
||||
{
|
||||
Parent::unpackData(stream);
|
||||
|
||||
stream->read(&timeMultiple);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//--------------------------------------
|
||||
//
|
||||
ParticleEmitterNode::ParticleEmitterNode()
|
||||
{
|
||||
// Todo: ScopeAlways?
|
||||
mNetFlags.set(Ghostable);
|
||||
mTypeMask |= EnvironmentObjectType;
|
||||
|
||||
mEmitterDatablock = NULL;
|
||||
mEmitterDatablockId = 0;
|
||||
mEmitter = NULL;
|
||||
mVelocity = 1.0;
|
||||
}
|
||||
|
||||
ParticleEmitterNode::~ParticleEmitterNode()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void ParticleEmitterNode::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
addField("emitter", TypeParticleEmitterDataPtr, Offset(mEmitterDatablock, ParticleEmitterNode));
|
||||
addField("velocity", TypeF32, Offset(mVelocity, ParticleEmitterNode));
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool ParticleEmitterNode::onAdd()
|
||||
{
|
||||
if(!Parent::onAdd())
|
||||
return false;
|
||||
|
||||
if (!mEmitterDatablock && mEmitterDatablockId != 0)
|
||||
{
|
||||
if (Sim::findObject(mEmitterDatablockId, mEmitterDatablock) == false)
|
||||
Con::errorf(ConsoleLogEntry::General, "ParticleEmitterNode::onAdd: Invalid packet, bad datablockId(mEmitterDatablock): %d", mEmitterDatablockId);
|
||||
}
|
||||
|
||||
if (mEmitterDatablock == NULL)
|
||||
return false;
|
||||
|
||||
if (isClientObject())
|
||||
{
|
||||
ParticleEmitter* pEmitter = new ParticleEmitter;
|
||||
pEmitter->onNewDataBlock(mEmitterDatablock);
|
||||
if (pEmitter->registerObject() == false)
|
||||
{
|
||||
Con::warnf(ConsoleLogEntry::General, "Could not register base emitter for particle of class: %s", mDataBlock->getName());
|
||||
delete pEmitter;
|
||||
return false;
|
||||
}
|
||||
mEmitter = pEmitter;
|
||||
}
|
||||
|
||||
mObjBox.min.set(-0.5, -0.5, -0.5);
|
||||
mObjBox.max.set( 0.5, 0.5, 0.5);
|
||||
resetWorldBox();
|
||||
addToScene();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void ParticleEmitterNode::onRemove()
|
||||
{
|
||||
removeFromScene();
|
||||
|
||||
if (isClientObject())
|
||||
{
|
||||
mEmitter->deleteWhenEmpty();
|
||||
mEmitter = NULL;
|
||||
}
|
||||
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
||||
void ParticleEmitterNode::onGroupAdd()
|
||||
{
|
||||
Parent::onGroupAdd();
|
||||
|
||||
// To make sure that we don't orphan our emitter on mission end,
|
||||
// let's add it to our parent group, so it will get cleaned up.
|
||||
SimGroup* myGroup = getGroup();
|
||||
if (myGroup && mEmitter)
|
||||
myGroup->addObject(mEmitter);
|
||||
}
|
||||
|
||||
bool ParticleEmitterNode::onNewDataBlock(GameBaseData* dptr)
|
||||
{
|
||||
mDataBlock = dynamic_cast<ParticleEmitterNodeData*>(dptr);
|
||||
if (!mDataBlock || !Parent::onNewDataBlock(dptr))
|
||||
return false;
|
||||
|
||||
// Todo: Uncomment if this is a "leaf" class
|
||||
scriptOnNewDataBlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void ParticleEmitterNode::advanceTime(F32 dt)
|
||||
{
|
||||
Parent::advanceTime(dt);
|
||||
|
||||
Point3F emitPoint, emitVelocity;
|
||||
Point3F emitAxis(0, 0, 1);
|
||||
getTransform().mulV(emitAxis);
|
||||
getTransform().getColumn(3, &emitPoint);
|
||||
emitVelocity = emitAxis * mVelocity;
|
||||
|
||||
mEmitter->emitParticles(emitPoint, emitPoint,
|
||||
emitAxis,
|
||||
emitVelocity, (U32)(dt * mDataBlock->timeMultiple * 1000.0f));
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
U32 ParticleEmitterNode::packUpdate(NetConnection* con, U32 mask, BitStream* stream)
|
||||
{
|
||||
U32 retMask = Parent::packUpdate(con, mask, stream);
|
||||
|
||||
mathWrite(*stream, getTransform());
|
||||
mathWrite(*stream, getScale());
|
||||
if (stream->writeFlag(mEmitterDatablock != NULL)) {
|
||||
stream->writeRangedU32(mEmitterDatablock->getId(), DataBlockObjectIdFirst,
|
||||
DataBlockObjectIdLast);
|
||||
}
|
||||
|
||||
return retMask;
|
||||
}
|
||||
|
||||
void ParticleEmitterNode::unpackUpdate(NetConnection* con, BitStream* stream)
|
||||
{
|
||||
Parent::unpackUpdate(con, stream);
|
||||
|
||||
MatrixF temp;
|
||||
Point3F tempScale;
|
||||
mathRead(*stream, &temp);
|
||||
mathRead(*stream, &tempScale);
|
||||
|
||||
if (stream->readFlag()) {
|
||||
mEmitterDatablockId = stream->readRangedU32(DataBlockObjectIdFirst,
|
||||
DataBlockObjectIdLast);
|
||||
} else {
|
||||
mEmitterDatablockId = 0;
|
||||
}
|
||||
|
||||
setScale(tempScale);
|
||||
setTransform(temp);
|
||||
}
|
||||
|
||||
void ParticleEmitterNode::setEmitterDataBlock(ParticleEmitterData* data)
|
||||
{
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
if (mEmitter)
|
||||
{
|
||||
mEmitterDatablock = data;
|
||||
ParticleEmitter* pEmitter = new ParticleEmitter;
|
||||
pEmitter->onNewDataBlock(mEmitterDatablock);
|
||||
if (pEmitter->registerObject() == false) {
|
||||
Con::warnf(ConsoleLogEntry::General, "Could not register base emitter for particle of class: %s", mDataBlock->getName());
|
||||
delete pEmitter;
|
||||
pEmitter = NULL;
|
||||
}
|
||||
if (pEmitter)
|
||||
{
|
||||
mEmitter->deleteWhenEmpty();
|
||||
mEmitter = pEmitter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ConsoleMethod(ParticleEmitterNode, setEmitterDataBlock, void, 3, 3, "(data)")
|
||||
{
|
||||
ParticleEmitterData* data = dynamic_cast<ParticleEmitterData*>(Sim::findObject(dAtoi(argv[2])));
|
||||
if (!data)
|
||||
data = dynamic_cast<ParticleEmitterData*>(Sim::findObject(argv[2]));
|
||||
|
||||
if (data)
|
||||
object->setEmitterDataBlock(data);
|
||||
}
|
84
engine/game/fx/particleEmitter.h
Executable file
84
engine/game/fx/particleEmitter.h
Executable file
@ -0,0 +1,84 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _PARTICLEEMITTERDUMMY_H_
|
||||
#define _PARTICLEEMITTERDUMMY_H_
|
||||
|
||||
#ifndef _GAMEBASE_H_
|
||||
#include "game/gameBase.h"
|
||||
#endif
|
||||
|
||||
class ParticleEmitterData;
|
||||
class ParticleEmitter;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
class ParticleEmitterNodeData : public GameBaseData
|
||||
{
|
||||
typedef GameBaseData Parent;
|
||||
|
||||
protected:
|
||||
bool onAdd();
|
||||
|
||||
//-------------------------------------- Console set variables
|
||||
public:
|
||||
F32 timeMultiple;
|
||||
|
||||
//-------------------------------------- load set variables
|
||||
public:
|
||||
|
||||
ParticleEmitterNodeData();
|
||||
~ParticleEmitterNodeData();
|
||||
|
||||
void packData(BitStream*);
|
||||
void unpackData(BitStream*);
|
||||
bool preload(bool server, char errorBuffer[256]);
|
||||
|
||||
DECLARE_CONOBJECT(ParticleEmitterNodeData);
|
||||
static void initPersistFields();
|
||||
};
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
class ParticleEmitterNode : public GameBase
|
||||
{
|
||||
typedef GameBase Parent;
|
||||
|
||||
private:
|
||||
ParticleEmitterNodeData* mDataBlock;
|
||||
|
||||
protected:
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
bool onNewDataBlock(GameBaseData *dptr);
|
||||
|
||||
ParticleEmitterData* mEmitterDatablock;
|
||||
S32 mEmitterDatablockId;
|
||||
|
||||
ParticleEmitter* mEmitter;
|
||||
F32 mVelocity;
|
||||
|
||||
public:
|
||||
ParticleEmitterNode();
|
||||
~ParticleEmitterNode();
|
||||
|
||||
// Time/Move Management
|
||||
public:
|
||||
void advanceTime(F32 dt);
|
||||
void setEmitterDataBlock(ParticleEmitterData* data);
|
||||
|
||||
|
||||
ParticleEmitter *getParticleEmitter() {return mEmitter;}
|
||||
|
||||
DECLARE_CONOBJECT(ParticleEmitterNode);
|
||||
static void initPersistFields();
|
||||
|
||||
U32 packUpdate (NetConnection *conn, U32 mask, BitStream* stream);
|
||||
void unpackUpdate(NetConnection *conn, BitStream* stream);
|
||||
|
||||
virtual void onGroupAdd();
|
||||
};
|
||||
|
||||
#endif // _H_PARTICLEEMISSIONDUMMY
|
||||
|
1733
engine/game/fx/particleEngine.cc
Executable file
1733
engine/game/fx/particleEngine.cc
Executable file
File diff suppressed because it is too large
Load Diff
335
engine/game/fx/particleEngine.h
Executable file
335
engine/game/fx/particleEngine.h
Executable file
@ -0,0 +1,335 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _PARTICLEEMITTER_H_
|
||||
#define _PARTICLEEMITTER_H_
|
||||
|
||||
#ifndef _GAMEBASE_H_
|
||||
#include "game/gameBase.h"
|
||||
#endif
|
||||
#ifndef _COLOR_H_
|
||||
#include "core/color.h"
|
||||
#endif
|
||||
|
||||
//-------------------------------------- Engine initialization...
|
||||
//
|
||||
namespace ParticleEngine {
|
||||
|
||||
enum ParticleConsts
|
||||
{
|
||||
PC_COLOR_KEYS = 4,
|
||||
PC_SIZE_KEYS = 4,
|
||||
};
|
||||
|
||||
/// Initalize the particle engine
|
||||
void init();
|
||||
|
||||
/// Destroy the particle engine
|
||||
void destroy();
|
||||
|
||||
extern Point3F windVelocity; ///< Global wind velocity for all particles
|
||||
|
||||
/// Sets the wind velocity for all particles
|
||||
/// @param vel Velocity
|
||||
inline void setWindVelocity(const Point3F & vel) { windVelocity = vel; }
|
||||
|
||||
/// Returns the wind velocity
|
||||
inline Point3F getWindVelocity() { return windVelocity; }
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//-------------------------------------- The data and the Emitter class
|
||||
// are all that the game should deal
|
||||
// with (other than initializing the
|
||||
// global engine pointer of course)
|
||||
//
|
||||
struct Particle;
|
||||
class ParticleData;
|
||||
|
||||
|
||||
class ParticleEmitter;
|
||||
|
||||
class ParticleData : public SimDataBlock
|
||||
{
|
||||
typedef SimDataBlock Parent;
|
||||
|
||||
enum PDConst
|
||||
{
|
||||
PDC_MAX_TEX = 50,
|
||||
};
|
||||
|
||||
public:
|
||||
F32 dragCoefficient;
|
||||
F32 windCoefficient;
|
||||
F32 gravityCoefficient;
|
||||
|
||||
F32 inheritedVelFactor;
|
||||
F32 constantAcceleration;
|
||||
|
||||
S32 lifetimeMS;
|
||||
S32 lifetimeVarianceMS;
|
||||
|
||||
F32 spinSpeed; // degrees per second
|
||||
F32 spinRandomMin;
|
||||
F32 spinRandomMax;
|
||||
|
||||
bool useInvAlpha;
|
||||
|
||||
|
||||
bool allowLighting;
|
||||
|
||||
|
||||
bool animateTexture;
|
||||
U32 numFrames;
|
||||
U32 framesPerSec;
|
||||
|
||||
ColorF colors[ParticleEngine::PC_COLOR_KEYS];
|
||||
F32 sizes[ParticleEngine::PC_SIZE_KEYS];
|
||||
F32 times[4];
|
||||
|
||||
StringTableEntry textureNameList[PDC_MAX_TEX];
|
||||
TextureHandle textureList[PDC_MAX_TEX];
|
||||
|
||||
public:
|
||||
ParticleData();
|
||||
~ParticleData();
|
||||
|
||||
void initializeParticle(Particle*, const Point3F&);
|
||||
|
||||
void packData(BitStream* stream);
|
||||
void unpackData(BitStream* stream);
|
||||
bool onAdd();
|
||||
bool preload(bool server, char errorBuffer[256]);
|
||||
bool loadParameters();
|
||||
bool reload(char errorBuffer[256]);
|
||||
DECLARE_CONOBJECT(ParticleData);
|
||||
static void initPersistFields();
|
||||
};
|
||||
|
||||
struct Particle
|
||||
{
|
||||
Point3F pos; // current instantaneous position
|
||||
Point3F vel; // " " velocity
|
||||
Point3F acc; // Constant acceleration
|
||||
Point3F orientDir; // direction particle should go if using oriented particles
|
||||
|
||||
U32 totalLifetime; // Total ms that this instance should be "live"
|
||||
ParticleData* dataBlock; // datablock that contains global parameters for
|
||||
// this instance
|
||||
|
||||
Particle* nextInList; // Managed by the current owning emitter
|
||||
U32 currentAge;
|
||||
|
||||
Particle* nextInEngine; // Managed by the global engine object
|
||||
ParticleEmitter* currentOwner;
|
||||
ColorF color;
|
||||
F32 size;
|
||||
F32 spinSpeed;
|
||||
};
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
class ParticleEmitterData : public GameBaseData
|
||||
{
|
||||
typedef GameBaseData Parent;
|
||||
|
||||
public:
|
||||
ParticleEmitterData();
|
||||
DECLARE_CONOBJECT(ParticleEmitterData);
|
||||
static void initPersistFields();
|
||||
void packData(BitStream* stream);
|
||||
void unpackData(BitStream* stream);
|
||||
bool preload(bool server, char errorBuffer[256]);
|
||||
|
||||
bool onAdd();
|
||||
|
||||
bool loadParameters();
|
||||
bool reload();
|
||||
|
||||
public:
|
||||
S32 ejectionPeriodMS; ///< Time, in Miliseconds, between particle ejection
|
||||
S32 periodVarianceMS; ///< Varience in ejection peroid between 0 and n
|
||||
|
||||
F32 ejectionVelocity; ///< Ejection velocity
|
||||
F32 velocityVariance; ///< Variance for velocity between 0 and n
|
||||
F32 ejectionOffset; ///< Z offset from emitter point to eject from
|
||||
|
||||
F32 thetaMin; ///< Minimum angle, from the horizontal plane, to eject from
|
||||
F32 thetaMax; ///< Maximum angle, from the horizontal plane, to eject from
|
||||
|
||||
F32 phiReferenceVel; ///< Reference angle, from the verticle plane, to eject from
|
||||
F32 phiVariance; ///< Varience from the reference angle, from 0 to n
|
||||
|
||||
U32 lifetimeMS; ///< Lifetime of particles
|
||||
U32 lifetimeVarianceMS; ///< Varience in lifetime from 0 to n
|
||||
|
||||
bool overrideAdvance; ///<
|
||||
bool orientParticles; ///< Particles always face the screen
|
||||
bool orientOnVelocity; ///< Particles face the screen at the start
|
||||
bool useEmitterSizes; ///< Use emitter specified sizes instead of datablock sizes
|
||||
bool useEmitterColors; ///< Use emitter specified colors instead of datablock colors
|
||||
|
||||
StringTableEntry particleString; ///< Used to load particle data directly from a string
|
||||
Vector<ParticleData*> particleDataBlocks; ///< Datablocks for particle emissions
|
||||
Vector<U32> dataBlockIds; ///< Datablock IDs which corospond to the particleDataBlocks
|
||||
};
|
||||
DECLARE_CONSOLETYPE(ParticleEmitterData)
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
class ParticleEmitter : public GameBase
|
||||
{
|
||||
typedef GameBase Parent;
|
||||
friend class PEngine;
|
||||
|
||||
public:
|
||||
ParticleEmitter();
|
||||
~ParticleEmitter();
|
||||
|
||||
bool allowLighting;
|
||||
bool lastLightingValue;
|
||||
TextureHandle whiteTexture;
|
||||
void setupParticleLighting(bool allowlighting);
|
||||
void resetParticleLighting();
|
||||
void lightParticle(const Particle &part);
|
||||
ColorF getCollectiveColor()
|
||||
{
|
||||
U32 count = 0;
|
||||
ColorF color(0.0f, 0.0f, 0.0f);
|
||||
Particle *particle = mParticleListHead;
|
||||
|
||||
while(particle)
|
||||
{
|
||||
color += particle->color;
|
||||
particle = particle->nextInList;
|
||||
count++;
|
||||
}
|
||||
|
||||
if(count > 0)
|
||||
color /= count;
|
||||
return color;
|
||||
}
|
||||
|
||||
/// Sets sizes of particles based on sizelist provided
|
||||
/// @param sizeList List of sizes
|
||||
void setSizes( F32 *sizeList );
|
||||
|
||||
/// Sets colors for particles based on color list provided
|
||||
/// @param colorList List of colors
|
||||
void setColors( ColorF *colorList );
|
||||
|
||||
ParticleEmitterData *getDataBlock(){ return mDataBlock; }
|
||||
bool onNewDataBlock(GameBaseData* dptr);
|
||||
|
||||
/// By default, a particle renderer will wait for it's owner to delete it. When this
|
||||
/// is turned on, it will delete itself as soon as it's particle count drops to zero.
|
||||
void deleteWhenEmpty();
|
||||
|
||||
/// @name Particle Emission
|
||||
/// Main interface for creating particles. The emitter does _not_ track changes
|
||||
/// in axis or velocity over the course of a single update, so this should be called
|
||||
/// at a fairly fine grain. The emitter will potentially track the last particle
|
||||
/// to be created into the next call to this function in order to create a uniformly
|
||||
/// random time distribution of the particles. If the object to which the emitter is
|
||||
/// attached is in motion, it should try to ensure that for call (n+1) to this
|
||||
/// function, start is equal to the end from call (n). This will ensure a uniform
|
||||
/// spatial distribution.
|
||||
/// @{
|
||||
|
||||
void emitParticles(const Point3F& start,
|
||||
const Point3F& end,
|
||||
const Point3F& axis,
|
||||
const Point3F& velocity,
|
||||
const U32 numMilliseconds);
|
||||
void emitParticles(const Point3F& point,
|
||||
const bool useLastPosition,
|
||||
const Point3F& axis,
|
||||
const Point3F& velocity,
|
||||
const U32 numMilliseconds);
|
||||
void emitParticles(const Point3F& rCenter,
|
||||
const Point3F& rNormal,
|
||||
const F32 radius,
|
||||
const Point3F& velocity,
|
||||
S32 count);
|
||||
/// @}
|
||||
|
||||
virtual void setTransform(const MatrixF & mat);
|
||||
|
||||
protected:
|
||||
/// @name Internal interface
|
||||
/// @{
|
||||
|
||||
/// Adds a particle
|
||||
/// @param pos Initial position of particle
|
||||
/// @param axis
|
||||
/// @param vel Initial velocity
|
||||
/// @param axisx
|
||||
void addParticle(const Point3F &pos, const Point3F &axis, const Point3F &vel, const Point3F &axisx);
|
||||
|
||||
/// Renders a particle facing the camera with a spin factor
|
||||
/// @param part Particle
|
||||
/// @param basePnts Base points for the quad the particle is rendered on
|
||||
/// @param camView Camera view matrix
|
||||
/// @param spinFactor 0.0-1.0 modifyer for
|
||||
void renderBillboardParticle( const Particle &part, const Point3F *basePnts, const MatrixF &camView, const F32 spinFactor );
|
||||
|
||||
/// Renders a particle which will face the camera but spin itself to look
|
||||
/// like it is facing a particular velocity.
|
||||
/// @param part Particle
|
||||
/// @param camPos Camera position
|
||||
void renderOrientedParticle( const Particle &part, const Point3F &camPos );
|
||||
|
||||
/// Updates the bounding box for the particle system
|
||||
bool updateBBox(const Point3F &position);
|
||||
|
||||
/// @}
|
||||
protected:
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
|
||||
void processTick(const Move *move);
|
||||
void advanceTime(F32 dt);
|
||||
|
||||
// Rendering
|
||||
protected:
|
||||
bool prepRenderImage(SceneState *state, const U32 stateKey, const U32 startZone, const bool modifyBaseZoneState);
|
||||
void renderObject(SceneState *state, SceneRenderImage *image);
|
||||
|
||||
// PEngine interface
|
||||
private:
|
||||
/// Removes the provided particle from the system and lets the caller of the
|
||||
/// function assume control of it
|
||||
/// @param part Particle
|
||||
void stealParticle(Particle *part);
|
||||
|
||||
private:
|
||||
ParticleEmitterData* mDataBlock;
|
||||
|
||||
/// This is used so we only update our transform/bounding box
|
||||
/// on ticks, to minimize calls to setTransform.
|
||||
bool mNeedTransformUpdate;
|
||||
|
||||
Particle* mParticleListHead;
|
||||
|
||||
U32 mInternalClock;
|
||||
|
||||
U32 mNextParticleTime;
|
||||
|
||||
Point3F mLastPosition;
|
||||
bool mHasLastPosition;
|
||||
|
||||
bool mDeleteWhenEmpty;
|
||||
bool mDeleteOnTick;
|
||||
|
||||
S32 mLifetimeMS;
|
||||
S32 mElapsedTimeMS;
|
||||
|
||||
F32 sizes[ParticleEngine::PC_SIZE_KEYS];
|
||||
ColorF colors[ParticleEngine::PC_COLOR_KEYS];
|
||||
};
|
||||
|
||||
#endif // _H_PARTICLEEMITTER
|
||||
|
1133
engine/game/fx/precipitation.cc
Executable file
1133
engine/game/fx/precipitation.cc
Executable file
File diff suppressed because it is too large
Load Diff
187
engine/game/fx/precipitation.h
Executable file
187
engine/game/fx/precipitation.h
Executable file
@ -0,0 +1,187 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _PRECIPITATION_H_
|
||||
#define _PRECIPITATION_H_
|
||||
|
||||
#include "game/gameBase.h"
|
||||
#include "audio/audioDataBlock.h"
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/// Precipitation datablock.
|
||||
class PrecipitationData : public GameBaseData {
|
||||
typedef GameBaseData Parent;
|
||||
|
||||
public:
|
||||
AudioProfile* soundProfile;
|
||||
S32 soundProfileId; ///< Ambient sound
|
||||
|
||||
StringTableEntry mDropName; ///< Texture filename for raindrop
|
||||
StringTableEntry mSplashName; ///< Texture filename for splash
|
||||
|
||||
F32 mDropSize; ///< Droplet billboard size
|
||||
F32 mSplashSize; ///< Splash billboard size
|
||||
bool mUseTrueBillboards; ///< True to use true billboards, false for axis-aligned billboards
|
||||
S32 mSplashMS; ///< How long in milliseconds a splash will last
|
||||
|
||||
PrecipitationData();
|
||||
DECLARE_CONOBJECT(PrecipitationData);
|
||||
bool onAdd();
|
||||
static void initPersistFields();
|
||||
virtual void packData(BitStream* stream);
|
||||
virtual void unpackData(BitStream* stream);
|
||||
};
|
||||
DECLARE_CONSOLETYPE(PrecipitationData)
|
||||
|
||||
struct Raindrop
|
||||
{
|
||||
F32 velocity; ///< How fast the drop is falling downwards
|
||||
Point3F position; ///< Position of the drop
|
||||
Point3F renderPosition; ///< Interpolated render-position of the drop
|
||||
F32 time; ///< Time into the turbulence function
|
||||
F32 mass; ///< Mass of drop used for how much turbulence/wind effects the drop
|
||||
|
||||
U32 texCoordIndex; ///< Which piece of the material will be used
|
||||
|
||||
bool toRender; ///< Don't want to render all drops, just the ones that pass a few tests
|
||||
bool valid; ///< Drop becomes invalid after hitting something. Just keep updating
|
||||
///< the position of it, but don't render until it hits the bottom
|
||||
///< of the renderbox and respawns
|
||||
|
||||
Point3F hitPos; ///< Point at which the drop will collide with something
|
||||
|
||||
Raindrop *nextSplashDrop; ///< Linked list cruft for easily adding/removing stuff from the splash list
|
||||
Raindrop *prevSplashDrop; ///< Same as next but previous!
|
||||
SimTime animStartTime; ///< Animation time tracker
|
||||
U32 splashIndex; ///< Texture index for which frame of the splash to render
|
||||
U32 hitType; ///< What kind of object the drop will hit
|
||||
|
||||
Raindrop* next; ///< linked list cruft
|
||||
|
||||
Raindrop()
|
||||
: velocity( 0.0f ),
|
||||
time( 0.0f ),
|
||||
mass( 1.0f ),
|
||||
texCoordIndex( 0 ),
|
||||
toRender( false ),
|
||||
valid( true ),
|
||||
hitPos( 0.0f, 0.0f, 0.0f ),
|
||||
nextSplashDrop( NULL ),
|
||||
prevSplashDrop( NULL ),
|
||||
animStartTime( 0 ),
|
||||
splashIndex( 0 ),
|
||||
hitType( 0 ),
|
||||
next( NULL )
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
class Precipitation : public GameBase
|
||||
{
|
||||
private:
|
||||
|
||||
typedef GameBase Parent;
|
||||
PrecipitationData* mDataBlock;
|
||||
|
||||
const static U32 csmDropsPerSide; ///< How many drops are on a side of the material texture
|
||||
const static F32 csmDropsPerSideF; ///< How many drops are on a side of the material texture
|
||||
const static U32 csmFramesPerSide; ///< How many frames are on a side of a splash animation
|
||||
const static F32 csmFramesPerSideF; ///< How many frames are on a side of a splash animation
|
||||
|
||||
Raindrop *mDropHead; ///< Drop linked list head
|
||||
Raindrop *mSplashHead; ///< Splash linked list head
|
||||
Point2F *texCoords; ///< texture coords for rain texture
|
||||
Point2F *splashCoords; ///< texture coordinates for splash texture
|
||||
|
||||
AUDIOHANDLE mAudioHandle; ///< Ambient sound handle
|
||||
TextureHandle mDropHandle; ///< Texture handle for raindrop
|
||||
TextureHandle mSplashHandle; ///< Texture handle for splash
|
||||
|
||||
//console exposed variables
|
||||
S32 mNumDrops; ///< Number of drops in the scene
|
||||
F32 mPercentage; ///< Server-side set var (NOT exposed to console)
|
||||
///< which controls how many drops are present [0,1]
|
||||
|
||||
F32 mMinSpeed; ///< Minimum downward speed of drops
|
||||
F32 mMaxSpeed; ///< Maximum downward speed of drops
|
||||
|
||||
F32 mMinMass; ///< Minimum mass of drops
|
||||
F32 mMaxMass; ///< Maximum mass of drops
|
||||
|
||||
F32 mBoxWidth; ///< How far away in the x and y directions drops will render
|
||||
F32 mBoxHeight; ///< How high drops will render
|
||||
|
||||
F32 mMaxTurbulence; ///< Coefficient to sin/cos for adding turbulence
|
||||
F32 mTurbulenceSpeed; ///< How fast the turbulence wraps in a circle
|
||||
bool mUseTurbulence; ///< Whether to use turbulence or not (MAY EFFECT PERFORMANCE)
|
||||
|
||||
bool mRotateWithCamVel; ///< Rotate the drops relative to the camera velocity
|
||||
///< This is useful for "streak" type drops
|
||||
|
||||
bool mDoCollision; ///< Whether or not to do collision
|
||||
|
||||
struct
|
||||
{
|
||||
bool valid;
|
||||
U32 startTime;
|
||||
U32 totalTime;
|
||||
F32 startPct;
|
||||
F32 endPct;
|
||||
} mStormData;
|
||||
|
||||
//other functions...
|
||||
void processTick(const Move*);
|
||||
void interpolateTick(F32 delta);
|
||||
|
||||
VectorF getWindVelocity();
|
||||
void fillDropList(); ///< Adds/removes drops from the list to have the right # of drops
|
||||
void killDropList(); ///< Deletes the entire drop list
|
||||
void spawnDrop(Raindrop *drop); ///< Fills drop info with random velocity, x/y positions, and mass
|
||||
void spawnNewDrop(Raindrop *drop); ///< Same as spawnDrop except also does z position
|
||||
void findDropCutoff(Raindrop *drop); ///< Casts a ray to see if/when a drop will collide
|
||||
inline void wrapDrop(Raindrop *drop, Box3F &box); ///< Wraps a drop within the specified box
|
||||
|
||||
void createSplash(Raindrop *drop); ///< Adds a drop to the splash list
|
||||
void destroySplash(Raindrop *drop); ///< Removes a drop from the splash list
|
||||
|
||||
|
||||
protected:
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
|
||||
// Rendering
|
||||
bool prepRenderImage(SceneState*, const U32, const U32, const bool);
|
||||
void renderObject(SceneState*, SceneRenderImage*);
|
||||
void renderPrecip(SceneState *state);
|
||||
void renderSplashes(SceneState *state);
|
||||
|
||||
public:
|
||||
|
||||
Precipitation();
|
||||
~Precipitation();
|
||||
void inspectPostApply();
|
||||
|
||||
enum
|
||||
{
|
||||
DataMask = Parent::NextFreeMask << 0,
|
||||
PercentageMask = Parent::NextFreeMask << 1,
|
||||
StormMask = Parent::NextFreeMask << 2,
|
||||
NextFreeMask = Parent::NextFreeMask << 3
|
||||
};
|
||||
|
||||
bool onNewDataBlock(GameBaseData* dptr);
|
||||
DECLARE_CONOBJECT(Precipitation);
|
||||
static void initPersistFields();
|
||||
|
||||
U32 packUpdate(NetConnection*, U32 mask, BitStream* stream);
|
||||
void unpackUpdate(NetConnection*, BitStream* stream);
|
||||
|
||||
void setPercentage(F32 pct);
|
||||
void modifyStorm(F32 pct, U32 ms);
|
||||
};
|
||||
|
||||
#endif // PRECIPITATION_H_
|
||||
|
818
engine/game/fx/splash.cc
Executable file
818
engine/game/fx/splash.cc
Executable file
@ -0,0 +1,818 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "game/fx/splash.h"
|
||||
|
||||
#include "console/consoleTypes.h"
|
||||
#include "dgl/dgl.h"
|
||||
#include "platform/platformAudio.h"
|
||||
#include "audio/audioDataBlock.h"
|
||||
#include "sceneGraph/sceneGraph.h"
|
||||
#include "sceneGraph/sceneState.h"
|
||||
#include "core/bitStream.h"
|
||||
#include "math/mathIO.h"
|
||||
#include "terrain/terrData.h"
|
||||
#include "game/fx/explosion.h"
|
||||
#include "game/fx/particleEngine.h"
|
||||
#include "sim/netConnection.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
MRandomLCG sgRandom(0xdeadbeef);
|
||||
|
||||
} // namespace {}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
IMPLEMENT_CO_DATABLOCK_V1(SplashData);
|
||||
IMPLEMENT_CO_NETOBJECT_V1(Splash);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Splash Data
|
||||
//--------------------------------------------------------------------------
|
||||
SplashData::SplashData()
|
||||
{
|
||||
soundProfile = NULL;
|
||||
soundProfileId = 0;
|
||||
|
||||
scale.set(1, 1, 1);
|
||||
|
||||
dMemset( emitterList, 0, sizeof( emitterList ) );
|
||||
dMemset( emitterIDList, 0, sizeof( emitterIDList ) );
|
||||
|
||||
delayMS = 0;
|
||||
delayVariance = 0;
|
||||
lifetimeMS = 1000;
|
||||
lifetimeVariance = 0;
|
||||
width = 4.0;
|
||||
numSegments = 10;
|
||||
velocity = 5.0;
|
||||
height = 0.0;
|
||||
acceleration = 0.0;
|
||||
texWrap = 1.0;
|
||||
texFactor = 3.0;
|
||||
ejectionFreq = 5;
|
||||
ejectionAngle = 45.0;
|
||||
ringLifetime = 1.0;
|
||||
startRadius = 0.5;
|
||||
explosion = NULL;
|
||||
explosionId = 0;
|
||||
|
||||
dMemset( textureName, 0, sizeof( textureName ) );
|
||||
|
||||
U32 i;
|
||||
for( i=0; i<NUM_TIME_KEYS; i++ )
|
||||
times[i] = 1.0;
|
||||
|
||||
times[0] = 0.0;
|
||||
|
||||
for( i=0; i<NUM_TIME_KEYS; i++ )
|
||||
colors[i].set( 1.0, 1.0, 1.0, 1.0 );
|
||||
|
||||
}
|
||||
|
||||
IMPLEMENT_CONSOLETYPE(SplashData)
|
||||
IMPLEMENT_SETDATATYPE(SplashData)
|
||||
IMPLEMENT_GETDATATYPE(SplashData)
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Init fields
|
||||
//--------------------------------------------------------------------------
|
||||
void SplashData::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
|
||||
addField("soundProfile", TypeAudioProfilePtr, Offset(soundProfile, SplashData));
|
||||
addField("scale", TypePoint3F, Offset(scale, SplashData));
|
||||
addField("emitter", TypeParticleEmitterDataPtr, Offset(emitterList, SplashData), NUM_EMITTERS);
|
||||
addField("delayMS", TypeS32, Offset(delayMS, SplashData));
|
||||
addField("delayVariance", TypeS32, Offset(delayVariance, SplashData));
|
||||
addField("lifetimeMS", TypeS32, Offset(lifetimeMS, SplashData));
|
||||
addField("lifetimeVariance", TypeS32, Offset(lifetimeVariance, SplashData));
|
||||
addField("width", TypeF32, Offset(width, SplashData));
|
||||
addField("numSegments", TypeS32, Offset(numSegments, SplashData));
|
||||
addField("velocity", TypeF32, Offset(velocity, SplashData));
|
||||
addField("height", TypeF32, Offset(height, SplashData));
|
||||
addField("acceleration", TypeF32, Offset(acceleration, SplashData));
|
||||
addField("times", TypeF32, Offset(times, SplashData), NUM_TIME_KEYS);
|
||||
addField("colors", TypeColorF, Offset(colors, SplashData), NUM_TIME_KEYS);
|
||||
addField("texture", TypeFilename, Offset(textureName, SplashData), NUM_TEX);
|
||||
addField("texWrap", TypeF32, Offset(texWrap, SplashData));
|
||||
addField("texFactor", TypeF32, Offset(texFactor, SplashData));
|
||||
addField("ejectionFreq", TypeF32, Offset(ejectionFreq, SplashData));
|
||||
addField("ejectionAngle", TypeF32, Offset(ejectionAngle, SplashData));
|
||||
addField("ringLifetime", TypeF32, Offset(ringLifetime, SplashData));
|
||||
addField("startRadius", TypeF32, Offset(startRadius, SplashData));
|
||||
addField("explosion", TypeExplosionDataPtr, Offset(explosion, SplashData));
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// On add - verify data settings
|
||||
//--------------------------------------------------------------------------
|
||||
bool SplashData::onAdd()
|
||||
{
|
||||
if (Parent::onAdd() == false)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Pack data
|
||||
//--------------------------------------------------------------------------
|
||||
void SplashData::packData(BitStream* stream)
|
||||
{
|
||||
Parent::packData(stream);
|
||||
|
||||
mathWrite(*stream, scale);
|
||||
stream->write(delayMS);
|
||||
stream->write(delayVariance);
|
||||
stream->write(lifetimeMS);
|
||||
stream->write(lifetimeVariance);
|
||||
stream->write(width);
|
||||
stream->write(numSegments);
|
||||
stream->write(velocity);
|
||||
stream->write(height);
|
||||
stream->write(acceleration);
|
||||
stream->write(texWrap);
|
||||
stream->write(texFactor);
|
||||
stream->write(ejectionFreq);
|
||||
stream->write(ejectionAngle);
|
||||
stream->write(ringLifetime);
|
||||
stream->write(startRadius);
|
||||
|
||||
if( stream->writeFlag( explosion ) )
|
||||
{
|
||||
stream->writeRangedU32(explosion->getId(), DataBlockObjectIdFirst, DataBlockObjectIdLast);
|
||||
}
|
||||
|
||||
S32 i;
|
||||
for( i=0; i<NUM_EMITTERS; i++ )
|
||||
{
|
||||
if( stream->writeFlag( emitterList[i] != NULL ) )
|
||||
{
|
||||
stream->writeRangedU32( emitterList[i]->getId(), DataBlockObjectIdFirst, DataBlockObjectIdLast );
|
||||
}
|
||||
}
|
||||
|
||||
for( i=0; i<NUM_TIME_KEYS; i++ )
|
||||
{
|
||||
stream->write( colors[i] );
|
||||
}
|
||||
|
||||
for( i=0; i<NUM_TIME_KEYS; i++ )
|
||||
{
|
||||
stream->write( times[i] );
|
||||
}
|
||||
|
||||
for( i=0; i<NUM_TEX; i++ )
|
||||
{
|
||||
stream->writeString(textureName[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Unpack data
|
||||
//--------------------------------------------------------------------------
|
||||
void SplashData::unpackData(BitStream* stream)
|
||||
{
|
||||
Parent::unpackData(stream);
|
||||
|
||||
mathRead(*stream, &scale);
|
||||
stream->read(&delayMS);
|
||||
stream->read(&delayVariance);
|
||||
stream->read(&lifetimeMS);
|
||||
stream->read(&lifetimeVariance);
|
||||
stream->read(&width);
|
||||
stream->read(&numSegments);
|
||||
stream->read(&velocity);
|
||||
stream->read(&height);
|
||||
stream->read(&acceleration);
|
||||
stream->read(&texWrap);
|
||||
stream->read(&texFactor);
|
||||
stream->read(&ejectionFreq);
|
||||
stream->read(&ejectionAngle);
|
||||
stream->read(&ringLifetime);
|
||||
stream->read(&startRadius);
|
||||
|
||||
if( stream->readFlag() )
|
||||
{
|
||||
explosionId = stream->readRangedU32( DataBlockObjectIdFirst, DataBlockObjectIdLast );
|
||||
}
|
||||
|
||||
U32 i;
|
||||
for( i=0; i<NUM_EMITTERS; i++ )
|
||||
{
|
||||
if( stream->readFlag() )
|
||||
{
|
||||
emitterIDList[i] = stream->readRangedU32( DataBlockObjectIdFirst, DataBlockObjectIdLast );
|
||||
}
|
||||
}
|
||||
|
||||
for( i=0; i<NUM_TIME_KEYS; i++ )
|
||||
{
|
||||
stream->read( &colors[i] );
|
||||
}
|
||||
|
||||
for( i=0; i<NUM_TIME_KEYS; i++ )
|
||||
{
|
||||
stream->read( ×[i] );
|
||||
}
|
||||
|
||||
for( i=0; i<NUM_TEX; i++ )
|
||||
{
|
||||
textureName[i] = stream->readSTString();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Preload data - load resources
|
||||
//--------------------------------------------------------------------------
|
||||
bool SplashData::preload(bool server, char errorBuffer[256])
|
||||
{
|
||||
if (Parent::preload(server, errorBuffer) == false)
|
||||
return false;
|
||||
|
||||
if (!server)
|
||||
{
|
||||
S32 i;
|
||||
for( i=0; i<NUM_EMITTERS; i++ )
|
||||
{
|
||||
if( !emitterList[i] && emitterIDList[i] != 0 )
|
||||
{
|
||||
if( Sim::findObject( emitterIDList[i], emitterList[i] ) == false)
|
||||
{
|
||||
Con::errorf( ConsoleLogEntry::General, "SplashData::onAdd: Invalid packet, bad datablockId(particle emitter): 0x%x", emitterIDList[i] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for( i=0; i<NUM_TEX; i++ )
|
||||
{
|
||||
if (textureName[i] && textureName[i][0])
|
||||
{
|
||||
textureHandle[i] = TextureHandle(textureName[i], MeshTexture );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( !explosion && explosionId != 0 )
|
||||
{
|
||||
if( !Sim::findObject(explosionId, explosion) )
|
||||
{
|
||||
Con::errorf(ConsoleLogEntry::General, "SplashData::preload: Invalid packet, bad datablockId(explosion): %d", explosionId);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Splash
|
||||
//--------------------------------------------------------------------------
|
||||
Splash::Splash()
|
||||
{
|
||||
dMemset( mEmitterList, 0, sizeof( mEmitterList ) );
|
||||
|
||||
mDelayMS = 0;
|
||||
mCurrMS = 0;
|
||||
mEndingMS = 1000;
|
||||
mActive = false;
|
||||
mRadius = 0.0;
|
||||
mVelocity = 1.0;
|
||||
mHeight = 0.0;
|
||||
mTimeSinceLastRing = 0.0;
|
||||
mDead = false;
|
||||
mElapsedTime = 0.0;
|
||||
|
||||
mInitialNormal.set( 0.0, 0.0, 1.0 );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Destructor
|
||||
//--------------------------------------------------------------------------
|
||||
Splash::~Splash()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Set initial state
|
||||
//--------------------------------------------------------------------------
|
||||
void Splash::setInitialState(const Point3F& point, const Point3F& normal, const F32 fade)
|
||||
{
|
||||
mInitialPosition = point;
|
||||
mInitialNormal = normal;
|
||||
mFade = fade;
|
||||
mFog = 0.0f;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// OnAdd
|
||||
//--------------------------------------------------------------------------
|
||||
bool Splash::onAdd()
|
||||
{
|
||||
// first check if we have a server connection, if we dont then this is on the server
|
||||
// and we should exit, then check if the parent fails to add the object
|
||||
NetConnection* conn = NetConnection::getConnectionToServer();
|
||||
if(!conn || !Parent::onAdd())
|
||||
return false;
|
||||
|
||||
mDelayMS = mDataBlock->delayMS + sgRandom.randI( -mDataBlock->delayVariance, mDataBlock->delayVariance );
|
||||
mEndingMS = mDataBlock->lifetimeMS + sgRandom.randI( -mDataBlock->lifetimeVariance, mDataBlock->lifetimeVariance );
|
||||
|
||||
mVelocity = mDataBlock->velocity;
|
||||
mHeight = mDataBlock->height;
|
||||
mTimeSinceLastRing = 1.0 / mDataBlock->ejectionFreq;
|
||||
|
||||
|
||||
if( isClientObject() )
|
||||
{
|
||||
for( U32 i=0; i<SplashData::NUM_EMITTERS; i++ )
|
||||
{
|
||||
if( mDataBlock->emitterList[i] != NULL )
|
||||
{
|
||||
ParticleEmitter * pEmitter = new ParticleEmitter;
|
||||
pEmitter->onNewDataBlock( mDataBlock->emitterList[i] );
|
||||
if( !pEmitter->registerObject() )
|
||||
{
|
||||
Con::warnf( ConsoleLogEntry::General, "Could not register emitter for particle of class: %s", mDataBlock->getName() );
|
||||
delete pEmitter;
|
||||
pEmitter = NULL;
|
||||
}
|
||||
mEmitterList[i] = pEmitter;
|
||||
}
|
||||
}
|
||||
|
||||
spawnExplosion();
|
||||
}
|
||||
|
||||
|
||||
mObjBox.min = Point3F( -1, -1, -1 );
|
||||
mObjBox.max = Point3F( 1, 1, 1 );
|
||||
resetWorldBox();
|
||||
|
||||
gClientContainer.addObject(this);
|
||||
gClientSceneGraph->addObjectToScene(this);
|
||||
|
||||
removeFromProcessList();
|
||||
gClientProcessList.addObject(this);
|
||||
|
||||
conn->addObject(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// OnRemove
|
||||
//--------------------------------------------------------------------------
|
||||
void Splash::onRemove()
|
||||
{
|
||||
for( U32 i=0; i<SplashData::NUM_EMITTERS; i++ )
|
||||
{
|
||||
if( mEmitterList[i] )
|
||||
{
|
||||
mEmitterList[i]->deleteWhenEmpty();
|
||||
mEmitterList[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ringList.free();
|
||||
|
||||
mSceneManager->removeObjectFromScene(this);
|
||||
getContainer()->removeObject(this);
|
||||
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// On New Data Block
|
||||
//--------------------------------------------------------------------------
|
||||
bool Splash::onNewDataBlock(GameBaseData* dptr)
|
||||
{
|
||||
mDataBlock = dynamic_cast<SplashData*>(dptr);
|
||||
if (!mDataBlock || !Parent::onNewDataBlock(dptr))
|
||||
return false;
|
||||
|
||||
scriptOnNewDataBlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Prep render image
|
||||
//--------------------------------------------------------------------------
|
||||
bool Splash::prepRenderImage(SceneState* state, const U32 stateKey,
|
||||
const U32 /*startZone*/, const bool /*modifyBaseState*/)
|
||||
{
|
||||
if (isLastState(state, stateKey))
|
||||
return false;
|
||||
setLastState(state, stateKey);
|
||||
|
||||
// This should be sufficient for most objects that don't manage zones, and
|
||||
// don't need to return a specialized RenderImage...
|
||||
if (state->isObjectRendered(this))
|
||||
{
|
||||
mFog = 0.0;
|
||||
|
||||
SceneRenderImage* image = new SceneRenderImage;
|
||||
image->obj = this;
|
||||
image->isTranslucent = true;
|
||||
image->sortType = SceneRenderImage::Point;
|
||||
image->textureSortKey = (U32)(dsize_t)mDataBlock;
|
||||
state->setImageRefPoint(this, image);
|
||||
state->insertRenderImage(image);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Render
|
||||
//--------------------------------------------------------------------------
|
||||
void Splash::renderObject(SceneState* state, SceneRenderImage*)
|
||||
{
|
||||
AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on entry");
|
||||
|
||||
RectI viewport;
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
dglGetViewport(&viewport);
|
||||
|
||||
state->setupObjectProjection(this);
|
||||
|
||||
render();
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
dglSetViewport(viewport);
|
||||
|
||||
AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on exit");
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Process tick
|
||||
//--------------------------------------------------------------------------
|
||||
void Splash::processTick(const Move*)
|
||||
{
|
||||
mCurrMS += TickMs;
|
||||
|
||||
if( isServerObject() )
|
||||
{
|
||||
if( mCurrMS >= mEndingMS )
|
||||
{
|
||||
mDead = true;
|
||||
if( mCurrMS >= (mEndingMS + mDataBlock->ringLifetime * 1000) )
|
||||
{
|
||||
deleteObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( mCurrMS >= mEndingMS )
|
||||
{
|
||||
mDead = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Advance time
|
||||
//--------------------------------------------------------------------------
|
||||
void Splash::advanceTime(F32 dt)
|
||||
{
|
||||
if (dt == 0.0)
|
||||
return;
|
||||
|
||||
mElapsedTime += dt;
|
||||
|
||||
updateColor();
|
||||
updateWave( dt );
|
||||
updateEmitters( dt );
|
||||
updateRings( dt );
|
||||
|
||||
if( !mDead )
|
||||
{
|
||||
emitRings( dt );
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Update emitters
|
||||
//----------------------------------------------------------------------------
|
||||
void Splash::updateEmitters( F32 dt )
|
||||
{
|
||||
Point3F pos = getPosition();
|
||||
|
||||
for( U32 i=0; i<SplashData::NUM_EMITTERS; i++ )
|
||||
{
|
||||
if( mEmitterList[i] )
|
||||
{
|
||||
mEmitterList[i]->emitParticles( pos, pos, mInitialNormal, Point3F( 0.0, 0.0, 0.0 ), (S32) (dt * 1000) );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Update wave
|
||||
//----------------------------------------------------------------------------
|
||||
void Splash::updateWave( F32 dt )
|
||||
{
|
||||
mVelocity += mDataBlock->acceleration * dt;
|
||||
mRadius += mVelocity * dt;
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Render splash
|
||||
//----------------------------------------------------------------------------
|
||||
void Splash::render()
|
||||
{
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDepthMask(GL_FALSE);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
||||
|
||||
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
|
||||
SplashRing *ring = NULL;
|
||||
|
||||
U32 i=0;
|
||||
while( bool( ring = ringList.next( ring ) ) )
|
||||
{
|
||||
SplashRing *next = ringList.next( ring );
|
||||
|
||||
if( !next )
|
||||
break;
|
||||
|
||||
renderSegment( *ring, *next );
|
||||
i++;
|
||||
}
|
||||
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisable(GL_BLEND);
|
||||
glDepthMask(GL_TRUE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Render horizontal segment created from 2 sets of points that are the
|
||||
// top and bottom rings of the segment.
|
||||
//----------------------------------------------------------------------------
|
||||
void Splash::renderSegment( SplashRing &top, SplashRing &bottom )
|
||||
{
|
||||
F32 texFactor = mDataBlock->texWrap;
|
||||
|
||||
glBindTexture( GL_TEXTURE_2D, mDataBlock->textureHandle[0].getGLName() );
|
||||
|
||||
F32 topAlpha = top.elapsedTime / top.lifetime;
|
||||
F32 bottomAlpha = bottom.elapsedTime / bottom.lifetime;
|
||||
|
||||
if( topAlpha < 0.5 )
|
||||
topAlpha *= 2.0;
|
||||
else
|
||||
topAlpha = 1.0 - topAlpha;
|
||||
|
||||
if( bottomAlpha < 0.5 )
|
||||
bottomAlpha *= 2.0;
|
||||
else
|
||||
bottomAlpha = 1.0 - bottomAlpha;
|
||||
|
||||
top.color.alpha = topAlpha;
|
||||
bottom.color.alpha = bottomAlpha;
|
||||
|
||||
|
||||
glBegin( GL_QUAD_STRIP );
|
||||
{
|
||||
for( U32 i=0; i<top.points.size(); i++ )
|
||||
{
|
||||
F32 t = F32(i) / F32(top.points.size());
|
||||
|
||||
glTexCoord2f( t * texFactor, top.v );
|
||||
glColor4fv( top.color );
|
||||
glVertex3fv( top.points[i].position );
|
||||
|
||||
glTexCoord2f( t * texFactor, bottom.v );
|
||||
glColor4fv( bottom.color );
|
||||
glVertex3fv( bottom.points[i].position );
|
||||
}
|
||||
|
||||
glTexCoord2f( 1.0 * texFactor, top.v );
|
||||
glColor4fv( top.color );
|
||||
glVertex3fv( top.points[0].position );
|
||||
|
||||
glTexCoord2f( 1.0 * texFactor, bottom.v );
|
||||
glColor4fv( bottom.color );
|
||||
glVertex3fv( bottom.points[0].position );
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Update color
|
||||
//----------------------------------------------------------------------------
|
||||
void Splash::updateColor()
|
||||
{
|
||||
SplashRing *ring = NULL;
|
||||
|
||||
while( bool( ring = ringList.next( ring ) ) )
|
||||
{
|
||||
F32 t = F32(ring->elapsedTime) / F32(ring->lifetime);
|
||||
|
||||
for( U32 i = 1; i < SplashData::NUM_TIME_KEYS; i++ )
|
||||
{
|
||||
if( mDataBlock->times[i] >= t )
|
||||
{
|
||||
F32 firstPart = t - mDataBlock->times[i-1];
|
||||
F32 total = (mDataBlock->times[i] -
|
||||
mDataBlock->times[i-1]);
|
||||
|
||||
firstPart /= total;
|
||||
|
||||
ring->color.interpolate( mDataBlock->colors[i-1],
|
||||
mDataBlock->colors[i],
|
||||
firstPart);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Create ring
|
||||
//----------------------------------------------------------------------------
|
||||
SplashRing Splash::createRing()
|
||||
{
|
||||
SplashRing ring;
|
||||
U32 numPoints = mDataBlock->numSegments + 1;
|
||||
|
||||
Point3F ejectionAxis( 0.0, 0.0, 1.0 );
|
||||
|
||||
Point3F axisx;
|
||||
if (mFabs(ejectionAxis.z) < 0.999f)
|
||||
mCross(ejectionAxis, Point3F(0, 0, 1), &axisx);
|
||||
else
|
||||
mCross(ejectionAxis, Point3F(0, 1, 0), &axisx);
|
||||
axisx.normalize();
|
||||
|
||||
for( U32 i=0; i<numPoints; i++ )
|
||||
{
|
||||
F32 t = F32(i) / F32(numPoints);
|
||||
|
||||
AngAxisF thetaRot( axisx, mDataBlock->ejectionAngle * (M_PI / 180.0));
|
||||
AngAxisF phiRot( ejectionAxis, t * (M_PI * 2.0));
|
||||
|
||||
Point3F pointAxis = ejectionAxis;
|
||||
|
||||
MatrixF temp;
|
||||
thetaRot.setMatrix(&temp);
|
||||
temp.mulP(pointAxis);
|
||||
phiRot.setMatrix(&temp);
|
||||
temp.mulP(pointAxis);
|
||||
|
||||
Point3F startOffset = axisx;
|
||||
temp.mulV( startOffset );
|
||||
startOffset *= mDataBlock->startRadius;
|
||||
|
||||
SplashRingPoint point;
|
||||
point.position = getPosition() + startOffset;
|
||||
point.velocity = pointAxis * mDataBlock->velocity;
|
||||
|
||||
ring.points.push_back( point );
|
||||
}
|
||||
|
||||
ring.color = mDataBlock->colors[0];
|
||||
ring.lifetime = mDataBlock->ringLifetime;
|
||||
ring.elapsedTime = 0.0;
|
||||
ring.v = mDataBlock->texFactor * mFmod( mElapsedTime, 1.0 );
|
||||
|
||||
return ring;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Emit rings
|
||||
//----------------------------------------------------------------------------
|
||||
void Splash::emitRings( F32 dt )
|
||||
{
|
||||
mTimeSinceLastRing += dt;
|
||||
|
||||
S32 numNewRings = (S32) (mTimeSinceLastRing * F32(mDataBlock->ejectionFreq));
|
||||
|
||||
mTimeSinceLastRing -= numNewRings / mDataBlock->ejectionFreq;
|
||||
|
||||
for( S32 i=numNewRings-1; i>=0; i-- )
|
||||
{
|
||||
F32 t = F32(i) / F32(numNewRings);
|
||||
t *= dt;
|
||||
t += mTimeSinceLastRing;
|
||||
|
||||
SplashRing ring = createRing();
|
||||
updateRing( &ring, t );
|
||||
|
||||
ringList.link( ring );
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Update rings
|
||||
//----------------------------------------------------------------------------
|
||||
void Splash::updateRings( F32 dt )
|
||||
{
|
||||
SplashRing *ring = NULL;
|
||||
while( bool( ring = ringList.next( ring ) ) )
|
||||
{
|
||||
ring->elapsedTime += dt;
|
||||
|
||||
if( !ring->isActive() )
|
||||
{
|
||||
SplashRing *inactiveRing = ring;
|
||||
ring = ringList.prev( ring );
|
||||
ringList.free( inactiveRing );
|
||||
}
|
||||
else
|
||||
{
|
||||
updateRing( ring, dt );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Update ring
|
||||
//----------------------------------------------------------------------------
|
||||
void Splash::updateRing( SplashRing *ring, F32 dt )
|
||||
{
|
||||
for( U32 i=0; i<ring->points.size(); i++ )
|
||||
{
|
||||
if( mDead )
|
||||
{
|
||||
Point3F vel = ring->points[i].velocity;
|
||||
vel.normalize();
|
||||
vel *= mDataBlock->acceleration;
|
||||
ring->points[i].velocity += vel * dt;
|
||||
}
|
||||
|
||||
ring->points[i].velocity += Point3F( 0.0, 0.0, -9.8 ) * dt;
|
||||
ring->points[i].position += ring->points[i].velocity * dt;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Explode
|
||||
//----------------------------------------------------------------------------
|
||||
void Splash::spawnExplosion()
|
||||
{
|
||||
if( !mDataBlock->explosion ) return;
|
||||
|
||||
Explosion* pExplosion = new Explosion;
|
||||
pExplosion->onNewDataBlock(mDataBlock->explosion);
|
||||
|
||||
MatrixF trans = getTransform();
|
||||
trans.setPosition( getPosition() );
|
||||
|
||||
pExplosion->setTransform( trans );
|
||||
pExplosion->setInitialState( trans.getPosition(), VectorF(0,0,1), 1);
|
||||
if (!pExplosion->registerObject())
|
||||
delete pExplosion;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// packUpdate
|
||||
//--------------------------------------------------------------------------
|
||||
U32 Splash::packUpdate(NetConnection* con, U32 mask, BitStream* stream)
|
||||
{
|
||||
U32 retMask = Parent::packUpdate(con, mask, stream);
|
||||
|
||||
if( stream->writeFlag(mask & GameBase::InitialUpdateMask) )
|
||||
{
|
||||
mathWrite(*stream, mInitialPosition);
|
||||
}
|
||||
|
||||
return retMask;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// unpackUpdate
|
||||
//--------------------------------------------------------------------------
|
||||
void Splash::unpackUpdate(NetConnection* con, BitStream* stream)
|
||||
{
|
||||
Parent::unpackUpdate(con, stream);
|
||||
|
||||
if( stream->readFlag() )
|
||||
{
|
||||
mathRead(*stream, &mInitialPosition);
|
||||
setPosition( mInitialPosition );
|
||||
}
|
||||
}
|
183
engine/game/fx/splash.h
Executable file
183
engine/game/fx/splash.h
Executable file
@ -0,0 +1,183 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _SPLASH_H_
|
||||
#define _SPLASH_H_
|
||||
|
||||
#ifndef _GAMEBASE_H_
|
||||
#include "game/gameBase.h"
|
||||
#endif
|
||||
|
||||
#ifndef _LLIST_H_
|
||||
#include "core/llist.h"
|
||||
#endif
|
||||
|
||||
class ParticleEmitter;
|
||||
class ParticleEmitterData;
|
||||
class AudioProfile;
|
||||
class ExplosionData;
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Ring Point
|
||||
//--------------------------------------------------------------------------
|
||||
struct SplashRingPoint
|
||||
{
|
||||
Point3F position;
|
||||
Point3F velocity;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Splash Ring
|
||||
//--------------------------------------------------------------------------
|
||||
struct SplashRing
|
||||
{
|
||||
Vector <SplashRingPoint> points;
|
||||
ColorF color;
|
||||
F32 lifetime;
|
||||
F32 elapsedTime;
|
||||
F32 v;
|
||||
|
||||
SplashRing()
|
||||
{
|
||||
color.set( 0.0, 0.0, 0.0, 1.0 );
|
||||
lifetime = 0.0;
|
||||
elapsedTime = 0.0;
|
||||
v = 0.0;
|
||||
}
|
||||
|
||||
bool isActive()
|
||||
{
|
||||
return elapsedTime < lifetime;
|
||||
}
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Splash Data
|
||||
//--------------------------------------------------------------------------
|
||||
class SplashData : public GameBaseData
|
||||
{
|
||||
public:
|
||||
typedef GameBaseData Parent;
|
||||
|
||||
enum Constants
|
||||
{
|
||||
NUM_EMITTERS = 3,
|
||||
NUM_TIME_KEYS = 4,
|
||||
NUM_TEX = 2,
|
||||
};
|
||||
|
||||
public:
|
||||
AudioProfile* soundProfile;
|
||||
S32 soundProfileId;
|
||||
|
||||
ParticleEmitterData* emitterList[NUM_EMITTERS];
|
||||
S32 emitterIDList[NUM_EMITTERS];
|
||||
|
||||
S32 delayMS;
|
||||
S32 delayVariance;
|
||||
S32 lifetimeMS;
|
||||
S32 lifetimeVariance;
|
||||
Point3F scale;
|
||||
F32 width;
|
||||
F32 height;
|
||||
U32 numSegments;
|
||||
F32 velocity;
|
||||
F32 acceleration;
|
||||
F32 texWrap;
|
||||
F32 texFactor;
|
||||
|
||||
F32 ejectionFreq;
|
||||
F32 ejectionAngle;
|
||||
F32 ringLifetime;
|
||||
F32 startRadius;
|
||||
|
||||
F32 times[ NUM_TIME_KEYS ];
|
||||
ColorF colors[ NUM_TIME_KEYS ];
|
||||
|
||||
StringTableEntry textureName[NUM_TEX];
|
||||
TextureHandle textureHandle[NUM_TEX];
|
||||
|
||||
ExplosionData* explosion;
|
||||
S32 explosionId;
|
||||
|
||||
SplashData();
|
||||
DECLARE_CONOBJECT(SplashData);
|
||||
bool onAdd();
|
||||
bool preload(bool server, char errorBuffer[256]);
|
||||
static void initPersistFields();
|
||||
virtual void packData(BitStream* stream);
|
||||
virtual void unpackData(BitStream* stream);
|
||||
};
|
||||
DECLARE_CONSOLETYPE(SplashData)
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Splash
|
||||
//--------------------------------------------------------------------------
|
||||
class Splash : public GameBase
|
||||
{
|
||||
typedef GameBase Parent;
|
||||
|
||||
private:
|
||||
SplashData* mDataBlock;
|
||||
|
||||
ParticleEmitter * mEmitterList[ SplashData::NUM_EMITTERS ];
|
||||
|
||||
LList <SplashRing> ringList;
|
||||
|
||||
U32 mCurrMS;
|
||||
U32 mEndingMS;
|
||||
F32 mRandAngle;
|
||||
F32 mRadius;
|
||||
F32 mVelocity;
|
||||
F32 mHeight;
|
||||
ColorF mColor;
|
||||
F32 mTimeSinceLastRing;
|
||||
bool mDead;
|
||||
F32 mElapsedTime;
|
||||
|
||||
protected:
|
||||
Point3F mInitialPosition;
|
||||
Point3F mInitialNormal;
|
||||
F32 mFade;
|
||||
F32 mFog;
|
||||
bool mActive;
|
||||
S32 mDelayMS;
|
||||
|
||||
protected:
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
void processTick(const Move *move);
|
||||
void advanceTime(F32 dt);
|
||||
void updateEmitters( F32 dt );
|
||||
void updateWave( F32 dt );
|
||||
void updateColor();
|
||||
SplashRing createRing();
|
||||
void updateRings( F32 dt );
|
||||
void updateRing( SplashRing *ring, F32 dt );
|
||||
void emitRings( F32 dt );
|
||||
void render();
|
||||
void renderSegment( SplashRing &top, SplashRing &bottom );
|
||||
void spawnExplosion();
|
||||
|
||||
// Rendering
|
||||
protected:
|
||||
bool prepRenderImage ( SceneState *state, const U32 stateKey, const U32 startZone, const bool modifyBaseZoneState=false);
|
||||
void renderObject ( SceneState *state, SceneRenderImage *image);
|
||||
|
||||
public:
|
||||
Splash();
|
||||
~Splash();
|
||||
void setInitialState(const Point3F& point, const Point3F& normal, const F32 fade = 1.0);
|
||||
|
||||
U32 packUpdate (NetConnection *conn, U32 mask, BitStream* stream);
|
||||
void unpackUpdate(NetConnection *conn, BitStream* stream);
|
||||
|
||||
bool onNewDataBlock(GameBaseData* dptr);
|
||||
DECLARE_CONOBJECT(Splash);
|
||||
};
|
||||
|
||||
|
||||
#endif // _H_SPLASH
|
142
engine/game/fx/underLava.cc
Executable file
142
engine/game/fx/underLava.cc
Executable file
@ -0,0 +1,142 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "game/fx/underLava.h"
|
||||
|
||||
#include "dgl/dgl.h"
|
||||
#include "math/mRect.h"
|
||||
#include "dgl/gTexManager.h"
|
||||
#include "terrain/waterBlock.h"
|
||||
#include "math/mConstants.h"
|
||||
|
||||
UnderLavaFX gLavaFX;
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// Under lava FX - "Lava - With pumice!"
|
||||
//**************************************************************************
|
||||
UnderLavaFX::UnderLavaFX()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Init
|
||||
//--------------------------------------------------------------------------
|
||||
void UnderLavaFX::init()
|
||||
{
|
||||
RectI viewport;
|
||||
dglGetViewport( &viewport );
|
||||
|
||||
mViewSize = viewport.extent;
|
||||
|
||||
mTexFrequency.x = F32(viewport.extent.x / viewport.extent.y);
|
||||
mTexFrequency.y = 1.0;
|
||||
|
||||
mNumPoints.x = (S32)(50 * F32(viewport.extent.x / viewport.extent.y));
|
||||
mNumPoints.y = 50;
|
||||
|
||||
mWave[0].amplitude = 0.02;
|
||||
mWave[0].frequency = 2.0;
|
||||
mWave[0].velocity = Sim::getCurrentTime() / 1000.0 * 2.0;
|
||||
|
||||
mMoveSpeed = Sim::getCurrentTime() / 1000.0 * 0.025;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Render
|
||||
//--------------------------------------------------------------------------
|
||||
void UnderLavaFX::render()
|
||||
{
|
||||
init();
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
// TextureHandle lavaTex = WaterBlock::getSubmergeTexture(0);
|
||||
glBindTexture(GL_TEXTURE_2D, WaterBlock::getSubmergeTexture(0).getGLName());
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDepthMask(GL_FALSE);
|
||||
glColor4f(1.0, 1.0, 1.0, 0.5);
|
||||
|
||||
if( WaterBlock::getSubmergeTexture(0) )
|
||||
{
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
|
||||
// render layer 1
|
||||
for( U32 i=0; i<mNumPoints.y; i++ )
|
||||
{
|
||||
renderRow( i, mNumPoints.y-1, mNumPoints.x-1 );
|
||||
}
|
||||
}
|
||||
|
||||
// give second layer a different phase
|
||||
mWave[0].velocity += 10.0;
|
||||
|
||||
// lavaTex = WaterBlock::getSubmergeTexture(1);
|
||||
|
||||
if( WaterBlock::getSubmergeTexture(1) )
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, WaterBlock::getSubmergeTexture(1).getGLName());
|
||||
|
||||
// render layer 2
|
||||
for( U32 i=0; i<mNumPoints.y; i++ )
|
||||
{
|
||||
renderRow( i, mNumPoints.y-1, mNumPoints.x-1 );
|
||||
}
|
||||
}
|
||||
|
||||
glDepthMask(GL_TRUE);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Render row (triangle strip)
|
||||
//--------------------------------------------------------------------------
|
||||
void UnderLavaFX::renderRow( U32 row, U32 numRows, U32 numColumns )
|
||||
{
|
||||
|
||||
F32 xMult = F32(2.0) / F32(numColumns);
|
||||
F32 yMult = F32(2.0) / F32(numRows);
|
||||
|
||||
glBegin( GL_TRIANGLE_STRIP );
|
||||
|
||||
for( U32 i=0; i<numColumns+1; i++ )
|
||||
{
|
||||
F32 u = F32(i) / F32(numColumns) * mTexFrequency.x;
|
||||
F32 v = F32(row) / F32(numRows) * mTexFrequency.y;
|
||||
|
||||
u += mMoveSpeed + mWave[0].amplitude * mSin( u * M_2PI * mWave[0].frequency + mWave[0].velocity );
|
||||
v += mMoveSpeed + mWave[0].amplitude * mSin( v * M_2PI * mWave[0].frequency + mWave[0].velocity );
|
||||
|
||||
glTexCoord2f( u, v );
|
||||
glVertex2f( -1.0 + i * xMult, -1.0 + row * yMult );
|
||||
|
||||
v = F32(row+1) / F32(numRows) * mTexFrequency.y;
|
||||
v += mMoveSpeed + mWave[0].amplitude * mSin( v * M_2PI * mWave[0].frequency + mWave[0].velocity );
|
||||
|
||||
glTexCoord2f( u, v );
|
||||
glVertex2f( -1.0 + i * xMult, -1.0 + (row+1) * yMult );
|
||||
|
||||
}
|
||||
|
||||
glEnd();
|
||||
|
||||
}
|
56
engine/game/fx/underLava.h
Executable file
56
engine/game/fx/underLava.h
Executable file
@ -0,0 +1,56 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _UNDERLAVA_H_
|
||||
#define _UNDERLAVA_H_
|
||||
|
||||
#ifndef _MPOINT_H_
|
||||
#include "math/mPoint.h"
|
||||
#endif
|
||||
|
||||
//**************************************************************************
|
||||
// Data
|
||||
//**************************************************************************
|
||||
struct LavaVertex
|
||||
{
|
||||
Point2I pnt;
|
||||
Point2F texPnt;
|
||||
|
||||
};
|
||||
|
||||
struct LavaWave
|
||||
{
|
||||
F32 frequency;
|
||||
F32 amplitude;
|
||||
F32 velocity;
|
||||
|
||||
};
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// Under lava FX
|
||||
//**************************************************************************
|
||||
class UnderLavaFX
|
||||
{
|
||||
private:
|
||||
Point2F mTexFrequency;
|
||||
Point2I mNumPoints;
|
||||
Point2I mViewSize;
|
||||
LavaWave mWave[2];
|
||||
F32 mMoveSpeed;
|
||||
|
||||
void renderRow( U32 row, U32 numRows, U32 numColumns );
|
||||
|
||||
public:
|
||||
UnderLavaFX();
|
||||
|
||||
void init();
|
||||
void render();
|
||||
|
||||
};
|
||||
|
||||
extern UnderLavaFX gLavaFX;
|
||||
|
||||
#endif
|
715
engine/game/fx/weatherLightning.cpp
Executable file
715
engine/game/fx/weatherLightning.cpp
Executable file
@ -0,0 +1,715 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "dgl/dgl.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "math/mathIO.h"
|
||||
#include "math/mRandom.h"
|
||||
#include "sceneGraph/sceneState.h"
|
||||
#include "audio/audioDataBlock.h"
|
||||
#include "game/fx/weatherLightning.h"
|
||||
|
||||
IMPLEMENT_CO_CLIENTEVENT_V1(WeatherLightningStrikeEvent);
|
||||
IMPLEMENT_CO_DATABLOCK_V1(WeatherLightningData);
|
||||
IMPLEMENT_CO_NETOBJECT_V1(WeatherLightning);
|
||||
|
||||
MRandomLCG sgRandomGen;
|
||||
|
||||
S32 QSORT_CALLBACK cmpWLSounds(const void* p1, const void* p2)
|
||||
{
|
||||
U32 i1 = *((const S32*)p1);
|
||||
U32 i2 = *((const S32*)p2);
|
||||
|
||||
if (i1 < i2) {
|
||||
return 1;
|
||||
} else if (i1 > i2) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
S32 QSORT_CALLBACK cmpWLTextures(const void* t1, const void* t2)
|
||||
{
|
||||
StringTableEntry ta = *(StringTableEntry*)t1;
|
||||
StringTableEntry tb = *(StringTableEntry*)t2;
|
||||
|
||||
if(ta && ta[0] != '\0')
|
||||
{
|
||||
if(tb && tb[0] != '\0')
|
||||
return dStricmp(ta, tb);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(tb && tb[0] != '\0')
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
WeatherLightningStrikeEvent::WeatherLightningStrikeEvent()
|
||||
{
|
||||
mLightning = NULL;
|
||||
}
|
||||
|
||||
WeatherLightningStrikeEvent::~WeatherLightningStrikeEvent()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void WeatherLightningStrikeEvent::pack(NetConnection* con, BitStream* stream)
|
||||
{
|
||||
if(!mLightning)
|
||||
{
|
||||
stream->writeFlag(false);
|
||||
return;
|
||||
}
|
||||
|
||||
S32 ghostIndex = con->getGhostIndex(mLightning);
|
||||
if(ghostIndex == -1)
|
||||
{
|
||||
stream->writeFlag(false);
|
||||
return;
|
||||
}
|
||||
|
||||
stream->writeFlag(true);
|
||||
stream->writeRangedU32(U32(ghostIndex), 0, NetConnection::MaxGhostCount);
|
||||
stream->writeFloat(mStart.x, PositionalBits);
|
||||
stream->writeFloat(mStart.y, PositionalBits);
|
||||
}
|
||||
|
||||
void WeatherLightningStrikeEvent::unpack(NetConnection* con, BitStream* stream)
|
||||
{
|
||||
if(!stream->readFlag())
|
||||
return;
|
||||
S32 ghostIndex = stream->readRangedU32(0, NetConnection::MaxGhostCount);
|
||||
mLightning = NULL;
|
||||
NetObject* pObject = con->resolveGhost(ghostIndex);
|
||||
if(pObject)
|
||||
mLightning = dynamic_cast<WeatherLightning*>(pObject);
|
||||
|
||||
mStart.x = stream->readFloat(PositionalBits);
|
||||
mStart.y = stream->readFloat(PositionalBits);
|
||||
}
|
||||
|
||||
void WeatherLightningStrikeEvent::process(NetConnection*)
|
||||
{
|
||||
if (mLightning)
|
||||
mLightning->processEvent(this);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
WeatherLightningData::WeatherLightningData()
|
||||
{
|
||||
dMemset(strikeTextureNames, 0, sizeof(strikeTextureNames));
|
||||
dMemset(flashTextureNames, 0, sizeof(flashTextureNames));
|
||||
dMemset(fuzzyTextureNames, 0, sizeof(fuzzyTextureNames));
|
||||
|
||||
dMemset(strikeTextures, 0, sizeof(strikeTextures));
|
||||
dMemset(flashTextures, 0, sizeof(flashTextures));
|
||||
dMemset(fuzzyTextures, 0, sizeof(fuzzyTextures));
|
||||
|
||||
strikeSoundId = -1;
|
||||
strikeSound = NULL_AUDIOHANDLE;
|
||||
for(U32 i = 0; i < MaxSounds; i++)
|
||||
{
|
||||
thunderSoundIds[i] = -1;
|
||||
thunderSounds[i] = NULL_AUDIOHANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
WeatherLightningData::~WeatherLightningData()
|
||||
{
|
||||
//
|
||||
};
|
||||
|
||||
void WeatherLightningData::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
|
||||
addField("strikeTextures", TypeFilename, Offset(strikeTextureNames, WeatherLightningData), MaxStrikeTextures);
|
||||
addField("flashTextures", TypeFilename, Offset(flashTextureNames, WeatherLightningData), MaxFlashTextures);
|
||||
addField("fuzzyTextures", TypeFilename, Offset(fuzzyTextureNames, WeatherLightningData), MaxFuzzyTextures);
|
||||
|
||||
addField("strikeSound", TypeAudioProfilePtr, Offset(strikeSound, WeatherLightningData));
|
||||
addField("thunderSounds", TypeAudioProfilePtr, Offset(thunderSounds, WeatherLightningData), MaxSounds);
|
||||
}
|
||||
|
||||
bool WeatherLightningData::onAdd()
|
||||
{
|
||||
if(!Parent::onAdd())
|
||||
return false;
|
||||
|
||||
if(!strikeSound && strikeSoundId != -1)
|
||||
{
|
||||
if(Sim::findObject(strikeSoundId, strikeSound) == false)
|
||||
Con::errorf(ConsoleLogEntry::General, "WeatherLightningData::onAdd: Invalid packet, bad datablockId(sound: %d", strikeSound);
|
||||
}
|
||||
|
||||
for(U32 i = 0; i < MaxSounds; i++)
|
||||
{
|
||||
if(!thunderSounds[i] && thunderSoundIds[i] != -1)
|
||||
{
|
||||
if(Sim::findObject(thunderSoundIds[i], thunderSounds[i]) == false)
|
||||
Con::errorf(ConsoleLogEntry::General, "WeahterLightningData::onAdd: Invalid packet, bad datablockId(sound: %d", thunderSounds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WeatherLightningData::preload(bool server, char errorBuffer[256])
|
||||
{
|
||||
if(Parent::preload(server, errorBuffer) == false)
|
||||
return false;
|
||||
|
||||
dQsort(strikeTextureNames, MaxStrikeTextures, sizeof(StringTableEntry), cmpWLTextures);
|
||||
dQsort(flashTextureNames, MaxFlashTextures, sizeof(StringTableEntry), cmpWLTextures);
|
||||
dQsort(fuzzyTextureNames, MaxFuzzyTextures, sizeof(StringTableEntry), cmpWLTextures);
|
||||
|
||||
if(!server)
|
||||
{
|
||||
for(numStrikes = 0; numStrikes < MaxStrikeTextures; numStrikes++)
|
||||
{
|
||||
if(strikeTextureNames[numStrikes] && strikeTextureNames[numStrikes][0] != '\0')
|
||||
strikeTextures[numStrikes] = TextureHandle(strikeTextureNames[numStrikes], MeshTexture);
|
||||
else
|
||||
break;
|
||||
}
|
||||
for(numFlashes = 0; numFlashes < MaxFlashTextures && flashTextureNames[numFlashes] != NULL; numFlashes++)
|
||||
{
|
||||
if(flashTextureNames[numFlashes] && flashTextureNames[numFlashes][0] != '\0')
|
||||
flashTextures[numFlashes] = TextureHandle(flashTextureNames[numFlashes], MeshTexture);
|
||||
else
|
||||
break;
|
||||
}
|
||||
for(numFuzzes = 0; numFuzzes < MaxFuzzyTextures && fuzzyTextureNames[numFuzzes] != NULL; numFuzzes++)
|
||||
{
|
||||
if(fuzzyTextureNames[numFuzzes] && fuzzyTextureNames[numFuzzes][0] != '\0')
|
||||
fuzzyTextures[numFuzzes] = TextureHandle(fuzzyTextureNames[numFuzzes], MeshTexture);
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dQsort(thunderSounds, MaxSounds, sizeof(AudioProfile*), cmpWLSounds);
|
||||
for(numSounds = 0; numSounds < MaxSounds && thunderSounds[numSounds] != NULL_AUDIOHANDLE; numSounds++) {
|
||||
//
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void WeatherLightningData::packData(BitStream* stream)
|
||||
{
|
||||
Parent::packData(stream);
|
||||
|
||||
U32 i;
|
||||
for (i = 0; i < MaxStrikeTextures; i++)
|
||||
stream->writeString(strikeTextureNames[i]);
|
||||
for(i = 0; i < MaxFlashTextures; i++)
|
||||
stream->writeString(flashTextureNames[i]);
|
||||
for(i = 0; i < MaxFuzzyTextures; i++)
|
||||
stream->writeString(fuzzyTextureNames[i]);
|
||||
|
||||
if(stream->writeFlag(strikeSound != NULL_AUDIOHANDLE))
|
||||
stream->writeRangedU32(strikeSound->getId(), DataBlockObjectIdFirst,
|
||||
DataBlockObjectIdLast);
|
||||
|
||||
for(i = 0; i < MaxSounds; i++)
|
||||
{
|
||||
if(stream->writeFlag(thunderSounds[i] != NULL_AUDIOHANDLE))
|
||||
stream->writeRangedU32(thunderSounds[i]->getId(), DataBlockObjectIdFirst,
|
||||
DataBlockObjectIdLast);
|
||||
}
|
||||
}
|
||||
|
||||
void WeatherLightningData::unpackData(BitStream* stream)
|
||||
{
|
||||
Parent::unpackData(stream);
|
||||
|
||||
U32 i;
|
||||
for(i = 0; i < MaxStrikeTextures; i++)
|
||||
strikeTextureNames[i] = stream->readSTString();
|
||||
for(i = 0; i < MaxFlashTextures; i++)
|
||||
flashTextureNames[i] = stream->readSTString();
|
||||
for(i = 0; i < MaxFuzzyTextures; i++)
|
||||
fuzzyTextureNames[i] = stream->readSTString();
|
||||
|
||||
if(stream->readFlag())
|
||||
strikeSoundId = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
|
||||
else
|
||||
strikeSoundId = -1;
|
||||
|
||||
for(i = 0; i < MaxSounds; i++)
|
||||
{
|
||||
if(stream->readFlag())
|
||||
thunderSoundIds[i] = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
|
||||
else
|
||||
thunderSoundIds[i] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
WeatherLightning::WeatherLightning()
|
||||
{
|
||||
mNetFlags.set(Ghostable | ScopeAlways);
|
||||
mTypeMask |= StaticObjectType|EnvironmentObjectType;
|
||||
|
||||
lastThink = 0;
|
||||
strikesPerMinute = 9;
|
||||
boltDeathAge = 1.5;
|
||||
}
|
||||
|
||||
WeatherLightning::~WeatherLightning()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
void WeatherLightning::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
|
||||
addNamedField(strikesPerMinute, TypeS32, WeatherLightning);
|
||||
addNamedField(boltDeathAge, TypeF32, WeatherLightning);
|
||||
}
|
||||
|
||||
bool WeatherLightning::onAdd()
|
||||
{
|
||||
if(!Parent::onAdd())
|
||||
return false;
|
||||
|
||||
mObjBox.min.set( -0.5, -0.5, -0.5 );
|
||||
mObjBox.max.set( 0.5, 0.5, 0.5 );
|
||||
resetWorldBox();
|
||||
|
||||
addToScene();
|
||||
return true;
|
||||
}
|
||||
|
||||
void WeatherLightning::onRemove()
|
||||
{
|
||||
while(mActiveBolts.size())
|
||||
{
|
||||
WeatherLightningBolt* bolt = mActiveBolts[0];
|
||||
delete bolt;
|
||||
mActiveBolts.erase_fast(U32(0));
|
||||
}
|
||||
while(mSoundEvents.size())
|
||||
mSoundEvents.erase_fast(U32(0));
|
||||
|
||||
removeFromScene();
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
||||
bool WeatherLightning::onNewDataBlock(GameBaseData* dptr)
|
||||
{
|
||||
mDataBlock = dynamic_cast<WeatherLightningData*>(dptr);
|
||||
if(!mDataBlock || !Parent::onNewDataBlock(dptr))
|
||||
return false;
|
||||
|
||||
scriptOnNewDataBlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WeatherLightning::prepRenderImage(SceneState* state, const U32 stateKey, const U32, const bool)
|
||||
{
|
||||
if(isLastState(state, stateKey))
|
||||
return false;
|
||||
setLastState(state, stateKey);
|
||||
|
||||
// This should be sufficient for most objects that don't manage zones, and
|
||||
// don't need to return a specialized RenderImage...
|
||||
if(state->isObjectRendered(this))
|
||||
{
|
||||
SceneRenderImage* image = new SceneRenderImage;
|
||||
image->obj = this;
|
||||
image->isTranslucent = true;
|
||||
image->sortType = SceneRenderImage::EndSort;
|
||||
state->insertRenderImage(image);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void WeatherLightningBolt::render(const Point3F &camPos)
|
||||
{
|
||||
Point3F perpVec;
|
||||
Point3F lightUp = startPoint - endPoint;
|
||||
mCross(camPos - endPoint, lightUp, &perpVec);
|
||||
perpVec.normalize();
|
||||
|
||||
Point3F frontVec;
|
||||
mCross(perpVec, lightUp, &frontVec);
|
||||
frontVec.normalize();
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthMask(GL_FALSE);
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
|
||||
//
|
||||
// strike texture
|
||||
//
|
||||
|
||||
// setup alpha value
|
||||
F32 strikeAlpha;
|
||||
if(currentAge < (strikeTime / 3.0))
|
||||
{
|
||||
strikeAlpha = currentAge / (strikeTime / 3.0);
|
||||
strikeAlpha = mPow(strikeAlpha, F32(1.0 / 3.0));
|
||||
}
|
||||
else if(currentAge < (2.0 * strikeTime / 3.0))
|
||||
strikeAlpha = 1.0;
|
||||
else
|
||||
strikeAlpha = 1.0 - ((currentAge - (2.0 * strikeTime / 3.0)) / (strikeTime / 3.0));
|
||||
glColor4f(1.0f, 1.0f, 1.0f, strikeAlpha);
|
||||
|
||||
// generate texture coords
|
||||
Point3F points[4];
|
||||
F32 width = ((startPoint.z - endPoint.z) * 0.125f);
|
||||
points[0] = startPoint - perpVec * width;
|
||||
points[1] = startPoint + perpVec * width;
|
||||
points[2] = endPoint + perpVec * width;
|
||||
points[3] = endPoint - perpVec * width;
|
||||
|
||||
// bind and draw texture
|
||||
glBindTexture(GL_TEXTURE_2D, strikeTexture->getGLName());
|
||||
glBegin(GL_TRIANGLE_FAN);
|
||||
glTexCoord2f(0, 0); glVertex3fv(points[0]);
|
||||
glTexCoord2f(0, 1); glVertex3fv(points[1]);
|
||||
glTexCoord2f(1, 1); glVertex3fv(points[2]);
|
||||
glTexCoord2f(1, 0); glVertex3fv(points[3]);
|
||||
//glTexCoord2f(0, 0); glVertex3fv(points[0]);
|
||||
//glTexCoord2f(1, 0); glVertex3fv(points[1]);
|
||||
//glTexCoord2f(1, 1); glVertex3fv(points[2]);
|
||||
//glTexCoord2f(0, 1); glVertex3fv(points[3]);
|
||||
glEnd();
|
||||
|
||||
//
|
||||
// fuzzy texture
|
||||
//
|
||||
|
||||
// setup alpha value
|
||||
F32 constAlpha;
|
||||
if(currentAge < strikeTime / 2.0)
|
||||
constAlpha = currentAge / (strikeTime / 2.0);
|
||||
else if(currentAge < (2.0 * strikeTime / 3.0))
|
||||
constAlpha = 1.0 - ((currentAge - (strikeTime / 2.0)) / (strikeTime / 6.0));
|
||||
else
|
||||
constAlpha = 0.0;
|
||||
glColor4f(1.0, 1.0, 1.0, constAlpha);
|
||||
|
||||
// generate texture coords
|
||||
width *= 4;
|
||||
points[0] = startPoint - perpVec * width;
|
||||
points[1] = startPoint + perpVec * width;
|
||||
points[2] = endPoint + perpVec * width;
|
||||
points[3] = endPoint - perpVec * width;
|
||||
|
||||
if(constAlpha != 0.0)
|
||||
{
|
||||
// bind and draw texture
|
||||
glBindTexture(GL_TEXTURE_2D, fuzzyTexture->getGLName());
|
||||
glBegin(GL_TRIANGLE_FAN);
|
||||
glTexCoord2f(0, 0); glVertex3fv(points[0]);
|
||||
glTexCoord2f(0, 1); glVertex3fv(points[1]);
|
||||
glTexCoord2f(1, 1); glVertex3fv(points[2]);
|
||||
glTexCoord2f(1, 0); glVertex3fv(points[3]);
|
||||
//glTexCoord2f(0, 0); glVertex3fv(points[0]);
|
||||
//glTexCoord2f(1, 0); glVertex3fv(points[1]);
|
||||
//glTexCoord2f(1, 1); glVertex3fv(points[2]);
|
||||
//glTexCoord2f(0, 1); glVertex3fv(points[3]);
|
||||
glEnd();
|
||||
|
||||
glDepthMask(GL_TRUE);
|
||||
}
|
||||
|
||||
//
|
||||
// flash texture
|
||||
//
|
||||
|
||||
// setup alpha value
|
||||
glColor4f(1.0f, 1.0f, 1.0f, strikeAlpha);
|
||||
|
||||
// generate texture coords
|
||||
points[0] = startPoint - perpVec * width + frontVec * width;
|
||||
points[1] = startPoint - perpVec * width - frontVec * width;
|
||||
points[2] = startPoint + perpVec * width - frontVec * width;
|
||||
points[3] = startPoint + perpVec * width + frontVec * width;
|
||||
|
||||
// bind and draw texture
|
||||
glBindTexture(GL_TEXTURE_2D, flashTexture->getGLName());
|
||||
glBegin(GL_TRIANGLE_FAN);
|
||||
glTexCoord2f(0, 0); glVertex3fv(points[0]);
|
||||
glTexCoord2f(0, 1); glVertex3fv(points[1]);
|
||||
glTexCoord2f(1, 1); glVertex3fv(points[2]);
|
||||
glTexCoord2f(1, 0); glVertex3fv(points[3]);
|
||||
//glTexCoord2f(0, 0); glVertex3fv(points[0]);
|
||||
//glTexCoord2f(1, 0); glVertex3fv(points[1]);
|
||||
//glTexCoord2f(1, 1); glVertex3fv(points[2]);
|
||||
//glTexCoord2f(0, 1); glVertex3fv(points[3]);
|
||||
glEnd();
|
||||
|
||||
//
|
||||
// finished
|
||||
//
|
||||
glDepthMask(GL_TRUE);
|
||||
}
|
||||
|
||||
void WeatherLightning::renderObject(SceneState* state, SceneRenderImage*)
|
||||
{
|
||||
if(mActiveBolts.size())
|
||||
{
|
||||
AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on entry");
|
||||
|
||||
RectI viewport;
|
||||
F64 farPlane;
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
|
||||
dglGetViewport(&viewport);
|
||||
farPlane = state->getFarPlane();
|
||||
const Point3F &camPos = state->getCameraPosition();
|
||||
|
||||
// adjust far clip plane
|
||||
F64 distance = (getPosition() - camPos).lenSquared();
|
||||
state->setFarPlane(getMax(farPlane, distance));
|
||||
|
||||
state->setupObjectProjection(this);
|
||||
|
||||
glDisable(GL_CULL_FACE);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
|
||||
for(U32 i = 0; i < mActiveBolts.size(); i++)
|
||||
mActiveBolts[i]->render(camPos);
|
||||
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
state->setFarPlane(farPlane);
|
||||
dglSetViewport(viewport);
|
||||
|
||||
AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on exit");
|
||||
}
|
||||
}
|
||||
|
||||
void WeatherLightning::processTick(const Move *move)
|
||||
{
|
||||
Parent::processTick(move);
|
||||
|
||||
if (isServerObject())
|
||||
{
|
||||
S32 msBetweenStrikes = (S32)(60.0 / strikesPerMinute * 1000.0);
|
||||
|
||||
lastThink += TickMs;
|
||||
if( lastThink > msBetweenStrikes )
|
||||
{
|
||||
strikeRandomPoint();
|
||||
lastThink -= msBetweenStrikes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WeatherLightning::advanceTime(F32 dt)
|
||||
{
|
||||
Parent::advanceTime(dt);
|
||||
|
||||
U32 i;
|
||||
|
||||
// loop through and erase any dead bolts
|
||||
for(i = 0; i < mActiveBolts.size();)
|
||||
{
|
||||
WeatherLightningBolt* bolt = mActiveBolts[i];
|
||||
bolt->currentAge += dt;
|
||||
if(bolt->currentAge > bolt->deathAge)
|
||||
{
|
||||
delete bolt;
|
||||
mActiveBolts.erase_fast(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
// loop through and find any pending sound events
|
||||
for(i = 0; i < mSoundEvents.size();)
|
||||
{
|
||||
SoundEvent *sEvent = &mSoundEvents[i];
|
||||
sEvent->time -= dt;
|
||||
if(sEvent->time <= 0.0)
|
||||
{
|
||||
// fire off the sound
|
||||
if(sEvent->soundBlockId != -1)
|
||||
alxPlay(mDataBlock->thunderSounds[sEvent->soundBlockId], &sEvent->position);
|
||||
mSoundEvents.erase_fast(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void WeatherLightning::strikeRandomPoint()
|
||||
{
|
||||
// choose random strike point within object bounds
|
||||
Point2F strikePoint;
|
||||
strikePoint.x = sgRandomGen.randF( 0.0, 1.0 );
|
||||
strikePoint.y = sgRandomGen.randF( 0.0, 1.0 );
|
||||
|
||||
SimGroup* pClientGroup = Sim::getClientGroup();
|
||||
for (SimGroup::iterator itr = pClientGroup->begin(); itr != pClientGroup->end(); itr++)
|
||||
{
|
||||
NetConnection* nc = static_cast<NetConnection*>(*itr);
|
||||
|
||||
WeatherLightningStrikeEvent* wlEvent = new WeatherLightningStrikeEvent;
|
||||
wlEvent->mLightning = this;
|
||||
wlEvent->mStart = strikePoint;
|
||||
|
||||
nc->postNetEvent(wlEvent);
|
||||
}
|
||||
}
|
||||
|
||||
TextureHandle* WeatherLightning::getRandomStrike()
|
||||
{
|
||||
U32 strike = (U32)(mCeil(mDataBlock->numStrikes * sgRandomGen.randF()) - 1.0f);
|
||||
return &mDataBlock->strikeTextures[strike];
|
||||
}
|
||||
|
||||
TextureHandle* WeatherLightning::getRandomFlash()
|
||||
{
|
||||
U32 flash = (U32)(mCeil(mDataBlock->numFlashes * sgRandomGen.randF()) - 1.0f);
|
||||
return &mDataBlock->flashTextures[flash];
|
||||
}
|
||||
|
||||
TextureHandle* WeatherLightning::getRandomFuzzy()
|
||||
{
|
||||
U32 fuzzy = (U32)(mCeil(mDataBlock->numFuzzes * sgRandomGen.randF()) - 1.0f);
|
||||
return &mDataBlock->fuzzyTextures[fuzzy];
|
||||
}
|
||||
|
||||
S32 WeatherLightning::getRandomSound()
|
||||
{
|
||||
U32 sound = (U32)(mCeil(mDataBlock->numSounds * sgRandomGen.randF()) - 1.0f);
|
||||
if(mDataBlock->thunderSounds[sound] != NULL_AUDIOHANDLE)
|
||||
return sound;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void WeatherLightning::processEvent(WeatherLightningStrikeEvent* wlEvent)
|
||||
{
|
||||
AssertFatal(wlEvent->mStart.x >= 0 && wlEvent->mStart.x <= 1.0, "Out of bounds coord!");
|
||||
|
||||
mActiveBolts.push_back(new WeatherLightningBolt);
|
||||
WeatherLightningBolt* bolt = mActiveBolts.last();
|
||||
|
||||
Point3F strikePoint(0.0, 0.0, 0.0);
|
||||
strikePoint.x = wlEvent->mStart.x;
|
||||
strikePoint.y = wlEvent->mStart.y;
|
||||
strikePoint *= mObjScale;
|
||||
strikePoint += getPosition();
|
||||
strikePoint += Point3F( -mObjScale.x * 0.5, -mObjScale.y * 0.5, 0.0 );
|
||||
|
||||
RayInfo rayInfo;
|
||||
Point3F start = strikePoint;
|
||||
start.z = mObjScale.z * 0.5 + getPosition().z;
|
||||
strikePoint.z += -mObjScale.z * 0.5;
|
||||
bool rayHit = gClientContainer.castRay(start, strikePoint, (STATIC_COLLISION_MASK | WaterObjectType), &rayInfo);
|
||||
if(rayHit)
|
||||
strikePoint.z = rayInfo.point.z;
|
||||
|
||||
F32 height = mObjScale.z * 0.5 + getPosition().z;
|
||||
|
||||
bolt->startPoint = Point3F(strikePoint.x, strikePoint.y, height);
|
||||
bolt->endPoint = strikePoint;
|
||||
|
||||
bolt->currentAge = 0.0f;
|
||||
bolt->deathAge = boltDeathAge;
|
||||
bolt->strikeTime = 0.35;
|
||||
|
||||
bolt->strikeTexture = getRandomStrike();
|
||||
bolt->flashTexture = getRandomFlash();
|
||||
bolt->fuzzyTexture = getRandomFuzzy();
|
||||
|
||||
// setup a thunder sound event
|
||||
Point3F listener;
|
||||
alxGetListenerPoint3F(AL_POSITION, &listener);
|
||||
|
||||
mSoundEvents.increment();
|
||||
SoundEvent& sEvent = mSoundEvents.last();
|
||||
|
||||
// find the length to the closest point on the bolt
|
||||
Point3F dHat = bolt->startPoint - bolt->endPoint;
|
||||
F32 boltLength = dHat.len();
|
||||
dHat /= boltLength;
|
||||
F32 distAlong = mDot((listener - bolt->endPoint), dHat);
|
||||
|
||||
Point3F contactPoint;
|
||||
if(distAlong >= boltLength)
|
||||
contactPoint = bolt->startPoint;
|
||||
else if(distAlong <= 0.0)
|
||||
contactPoint = bolt->endPoint;
|
||||
else
|
||||
contactPoint = bolt->endPoint + dHat * distAlong;
|
||||
|
||||
F32 delayDist = (listener - contactPoint).len();
|
||||
U32 delayTime = U32((delayDist / 330.0f) * 100.0f);
|
||||
|
||||
MatrixF trans(true);
|
||||
trans.setPosition(contactPoint);
|
||||
|
||||
sEvent.soundBlockId = getRandomSound();
|
||||
sEvent.position = trans;
|
||||
sEvent.time = delayTime;
|
||||
|
||||
// play strike sound
|
||||
trans.setPosition(strikePoint);
|
||||
if(mDataBlock->strikeSound)
|
||||
alxPlay(mDataBlock->strikeSound, &trans);
|
||||
}
|
||||
|
||||
U32 WeatherLightning::packUpdate(NetConnection *conn, U32 mask, BitStream *stream)
|
||||
{
|
||||
U32 retMask = Parent::packUpdate(conn, mask, stream);
|
||||
|
||||
// Only write data if this is the initial packet or we've been inspected.
|
||||
if (stream->writeFlag(mask & (InitialUpdateMask | ExtendedInfoMask)))
|
||||
{
|
||||
// Initial update
|
||||
mathWrite(*stream, getPosition());
|
||||
mathWrite(*stream, mObjScale);
|
||||
}
|
||||
|
||||
return retMask;
|
||||
}
|
||||
|
||||
void WeatherLightning::unpackUpdate(NetConnection *conn, BitStream *stream)
|
||||
{
|
||||
Parent::unpackUpdate(conn, stream);
|
||||
|
||||
if (stream->readFlag())
|
||||
{
|
||||
// Initial update
|
||||
Point3F pos;
|
||||
mathRead(*stream, &pos);
|
||||
setPosition( pos );
|
||||
|
||||
mathRead(*stream, &mObjScale);
|
||||
}
|
||||
}
|
171
engine/game/fx/weatherLightning.h
Executable file
171
engine/game/fx/weatherLightning.h
Executable file
@ -0,0 +1,171 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _WEATHER_LIGHTNING_H_
|
||||
#define _WEATHER_LIGHTNING_H_
|
||||
|
||||
#ifndef _NETCONNECTION_H_
|
||||
#include "sim/netConnection.h"
|
||||
#endif
|
||||
#ifndef _GAMEBASE_H_
|
||||
#include "game/gameBase.h"
|
||||
#endif
|
||||
|
||||
#include "lightingSystem/sgLightManager.h"
|
||||
|
||||
class AudioProfile;
|
||||
class WeatherLightning;
|
||||
|
||||
class WeatherLightningStrikeEvent : public NetEvent
|
||||
{
|
||||
typedef NetEvent Parent;
|
||||
|
||||
public:
|
||||
enum Constants {
|
||||
PositionalBits = 10
|
||||
};
|
||||
|
||||
Point2F mStart;
|
||||
WeatherLightning* mLightning;
|
||||
|
||||
public:
|
||||
WeatherLightningStrikeEvent();
|
||||
~WeatherLightningStrikeEvent();
|
||||
|
||||
void pack(NetConnection*, BitStream*);
|
||||
void write(NetConnection*, BitStream*){}
|
||||
void unpack(NetConnection*, BitStream*);
|
||||
void process(NetConnection*);
|
||||
|
||||
DECLARE_CONOBJECT(WeatherLightningStrikeEvent);
|
||||
};
|
||||
|
||||
class WeatherLightningData : public GameBaseData
|
||||
{
|
||||
typedef GameBaseData Parent;
|
||||
|
||||
protected:
|
||||
bool onAdd();
|
||||
|
||||
public:
|
||||
enum {
|
||||
MaxSounds = 4,
|
||||
MaxStrikeTextures = 6,//8,
|
||||
MaxFlashTextures = 4, //6,
|
||||
MaxFuzzyTextures = 2, //4,
|
||||
};
|
||||
|
||||
// primary strike texture
|
||||
U32 numStrikes;
|
||||
StringTableEntry strikeTextureNames[MaxStrikeTextures];
|
||||
TextureHandle strikeTextures[MaxStrikeTextures];
|
||||
|
||||
// flash texture
|
||||
U32 numFlashes;
|
||||
StringTableEntry flashTextureNames[MaxFlashTextures];
|
||||
TextureHandle flashTextures[MaxFlashTextures];
|
||||
|
||||
// fuzzy/stretch texture
|
||||
U32 numFuzzes;
|
||||
StringTableEntry fuzzyTextureNames[MaxFuzzyTextures];
|
||||
TextureHandle fuzzyTextures[MaxFuzzyTextures];
|
||||
|
||||
//strike sound
|
||||
S32 strikeSoundId;
|
||||
AudioProfile* strikeSound;
|
||||
|
||||
// thunder sounds
|
||||
U32 numSounds;
|
||||
S32 thunderSoundIds[MaxSounds];
|
||||
AudioProfile* thunderSounds[MaxSounds];
|
||||
|
||||
public:
|
||||
WeatherLightningData();
|
||||
~WeatherLightningData();
|
||||
|
||||
void packData(BitStream*);
|
||||
void unpackData(BitStream*);
|
||||
bool preload(bool server, char errorBuffer[256]);
|
||||
|
||||
DECLARE_CONOBJECT(WeatherLightningData);
|
||||
static void initPersistFields();
|
||||
};
|
||||
|
||||
struct WeatherLightningBolt
|
||||
{
|
||||
Point3F startPoint;
|
||||
Point3F endPoint;
|
||||
|
||||
F32 currentAge;
|
||||
F32 deathAge;
|
||||
F32 strikeTime;
|
||||
|
||||
TextureHandle* strikeTexture;
|
||||
TextureHandle* flashTexture;
|
||||
TextureHandle* fuzzyTexture;
|
||||
|
||||
void render(const Point3F &camPos);
|
||||
};
|
||||
|
||||
class WeatherLightning : public GameBase
|
||||
{
|
||||
typedef GameBase Parent;
|
||||
|
||||
// datablock
|
||||
WeatherLightningData* mDataBlock;
|
||||
|
||||
U32 lastThink;
|
||||
U32 strikesPerMinute;
|
||||
U32 boltDeathAge;
|
||||
|
||||
struct SoundEvent {
|
||||
S32 soundBlockId;
|
||||
MatrixF position;
|
||||
U32 time;
|
||||
};
|
||||
|
||||
// only active on client
|
||||
VectorPtr<WeatherLightningBolt*> mActiveBolts;
|
||||
Vector<SoundEvent> mSoundEvents;
|
||||
|
||||
protected:
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
bool onNewDataBlock(GameBaseData* dptr);
|
||||
|
||||
// rendering
|
||||
bool prepRenderImage(SceneState *state, const U32 stateKey, const U32 startZone, const bool modifyBaseZoneState);
|
||||
void renderObject(SceneState *state, SceneRenderImage *image);
|
||||
|
||||
// simulation
|
||||
void processTick(const Move *move);
|
||||
void advanceTime(F32 dt);
|
||||
|
||||
// grab random textures
|
||||
TextureHandle* getRandomStrike();
|
||||
TextureHandle* getRandomFlash();
|
||||
TextureHandle* getRandomFuzzy();
|
||||
|
||||
// grab random sounds
|
||||
S32 getRandomSound();
|
||||
|
||||
public:
|
||||
WeatherLightning();
|
||||
~WeatherLightning();
|
||||
|
||||
// strike random point within object box
|
||||
void strikeRandomPoint();
|
||||
|
||||
// receive lightning event and create lightning bolt
|
||||
void processEvent(WeatherLightningStrikeEvent*);
|
||||
|
||||
U32 packUpdate (NetConnection *conn, U32 mask, BitStream *stream);
|
||||
void unpackUpdate(NetConnection *conn, BitStream *stream);
|
||||
|
||||
DECLARE_CONOBJECT(WeatherLightning);
|
||||
static void initPersistFields();
|
||||
};
|
||||
|
||||
#endif // _WEATHER_LIGHTNING_H_
|
Reference in New Issue
Block a user