mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-13 07:34:45 +00:00
Engine directory for ticket #1
This commit is contained in:
parent
352279af7a
commit
7dbfe6994d
3795 changed files with 1363358 additions and 0 deletions
208
Engine/source/T3D/fx/cameraFXMgr.cpp
Normal file
208
Engine/source/T3D/fx/cameraFXMgr.cpp
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "T3D/fx/cameraFXMgr.h"
|
||||
|
||||
#include "platform/profiler.h"
|
||||
#include "math/mRandom.h"
|
||||
#include "math/mMatrix.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;
|
||||
remoteControlled = false;
|
||||
isAdded = false;
|
||||
}
|
||||
|
||||
bool CameraShake::isExpired()
|
||||
{
|
||||
if ( remoteControlled )
|
||||
return false;
|
||||
|
||||
return Parent::isExpired();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Update
|
||||
//--------------------------------------------------------------------------
|
||||
void CameraShake::update( F32 dt )
|
||||
{
|
||||
Parent::update( dt );
|
||||
|
||||
if ( !remoteControlled )
|
||||
fadeAmplitude();
|
||||
else
|
||||
mAmp = mStartAmp;
|
||||
|
||||
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.pushFront( newFX );
|
||||
}
|
||||
|
||||
void CameraFXManager::removeFX( CameraFX *fx )
|
||||
{
|
||||
CamFXList::Iterator itr = mFXList.begin();
|
||||
for ( ; itr != mFXList.end(); itr++ )
|
||||
{
|
||||
if ( *itr == fx )
|
||||
{
|
||||
mFXList.erase( itr );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Clear all currently running camera effects
|
||||
//--------------------------------------------------------------------------
|
||||
void CameraFXManager::clear()
|
||||
{
|
||||
for(CamFXList::Iterator i = mFXList.begin(); i != mFXList.end(); ++i)
|
||||
{
|
||||
delete *i;
|
||||
}
|
||||
|
||||
mFXList.clear();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Update camera effects
|
||||
//--------------------------------------------------------------------------
|
||||
void CameraFXManager::update( F32 dt )
|
||||
{
|
||||
PROFILE_SCOPE( CameraFXManager_update );
|
||||
|
||||
mCamFXTrans.identity();
|
||||
|
||||
CamFXList::Iterator cur;
|
||||
for(CamFXList::Iterator i = mFXList.begin(); i != mFXList.end(); /*Trickiness*/)
|
||||
{
|
||||
// Store previous iterator and increment while iterator is still valid.
|
||||
cur = i;
|
||||
++i;
|
||||
CameraFX * curFX = *cur;
|
||||
curFX->update( dt );
|
||||
MatrixF fxTrans = curFX->getTrans();
|
||||
|
||||
mCamFXTrans.mul( fxTrans );
|
||||
|
||||
if( curFX->isExpired() )
|
||||
{
|
||||
delete curFX;
|
||||
mFXList.erase( cur );
|
||||
}
|
||||
}
|
||||
}
|
||||
113
Engine/source/T3D/fx/cameraFXMgr.h
Normal file
113
Engine/source/T3D/fx/cameraFXMgr.h
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _CAMERAFXMGR_H_
|
||||
#define _CAMERAFXMGR_H_
|
||||
|
||||
#ifndef _TORQUE_LIST_
|
||||
#include "core/util/tList.h"
|
||||
#endif
|
||||
#ifndef _MPOINT3_H_
|
||||
#include "math/mPoint3.h"
|
||||
#endif
|
||||
#ifndef _MMATRIX_H_
|
||||
#include "math/mMatrix.h"
|
||||
#endif
|
||||
|
||||
//**************************************************************************
|
||||
// Abstract camera effect template
|
||||
//**************************************************************************
|
||||
class CameraFX
|
||||
{
|
||||
protected:
|
||||
MatrixF mCamFXTrans;
|
||||
F32 mElapsedTime;
|
||||
F32 mDuration;
|
||||
|
||||
public:
|
||||
CameraFX();
|
||||
|
||||
MatrixF & getTrans(){ return mCamFXTrans; }
|
||||
virtual 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:
|
||||
|
||||
/// Is controlled by someone else, ignore duration and do not delete.
|
||||
bool remoteControlled;
|
||||
bool isAdded;
|
||||
|
||||
CameraShake();
|
||||
|
||||
void init();
|
||||
void fadeAmplitude();
|
||||
void setFalloff( F32 falloff ){ mFalloff = falloff; }
|
||||
void setFrequency( VectorF &freq ){ mFreq = freq; }
|
||||
void setAmplitude( VectorF & ){ mStartAmp = amp; }
|
||||
bool isExpired();
|
||||
|
||||
virtual void update( F32 dt );
|
||||
};
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// CameraFXManager
|
||||
//**************************************************************************
|
||||
class CameraFXManager
|
||||
{
|
||||
typedef CameraFX * CameraFXPtr;
|
||||
|
||||
MatrixF mCamFXTrans;
|
||||
typedef Torque::List<CameraFXPtr> CamFXList;
|
||||
CamFXList mFXList;
|
||||
|
||||
public:
|
||||
void addFX( CameraFX *newFX );
|
||||
void removeFX( CameraFX *fx );
|
||||
void clear();
|
||||
MatrixF & getTrans(){ return mCamFXTrans; }
|
||||
void update( F32 dt );
|
||||
|
||||
CameraFXManager();
|
||||
~CameraFXManager();
|
||||
};
|
||||
|
||||
extern CameraFXManager gCamFXMgr;
|
||||
|
||||
|
||||
#endif
|
||||
1269
Engine/source/T3D/fx/explosion.cpp
Normal file
1269
Engine/source/T3D/fx/explosion.cpp
Normal file
File diff suppressed because it is too large
Load diff
199
Engine/source/T3D/fx/explosion.h
Normal file
199
Engine/source/T3D/fx/explosion.h
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _EXPLOSION_H_
|
||||
#define _EXPLOSION_H_
|
||||
|
||||
#ifndef _GAMEBASE_H_
|
||||
#include "T3D/gameBase/gameBase.h"
|
||||
#endif
|
||||
#ifndef _TSSHAPE_H_
|
||||
#include "ts/tsShape.h"
|
||||
#endif
|
||||
#ifndef __RESOURCE_H__
|
||||
#include "core/resource.h"
|
||||
#endif
|
||||
#ifndef _LIGHTINFO_H_
|
||||
#include "lighting/lightInfo.h"
|
||||
#endif
|
||||
|
||||
class ParticleEmitter;
|
||||
class ParticleEmitterData;
|
||||
class TSThread;
|
||||
class SFXTrack;
|
||||
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;
|
||||
|
||||
SFXTrack* soundProfile;
|
||||
ParticleEmitterData* particleEmitter;
|
||||
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;
|
||||
F32 lightStartBrightness;
|
||||
F32 lightEndBrightness;
|
||||
F32 lightNormalOffset;
|
||||
|
||||
ExplosionData();
|
||||
DECLARE_CONOBJECT(ExplosionData);
|
||||
bool onAdd();
|
||||
bool preload(bool server, String &errorStr);
|
||||
static void initPersistFields();
|
||||
virtual void packData(BitStream* stream);
|
||||
virtual void unpackData(BitStream* stream);
|
||||
};
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
class Explosion : public GameBase, public ISceneLight
|
||||
{
|
||||
typedef GameBase Parent;
|
||||
|
||||
private:
|
||||
ExplosionData* mDataBlock;
|
||||
|
||||
TSShapeInstance* mExplosionInstance;
|
||||
TSThread* mExplosionThread;
|
||||
|
||||
SimObjectPtr<ParticleEmitter> mEmitterList[ ExplosionData::EC_NUM_EMITTERS ];
|
||||
SimObjectPtr<ParticleEmitter> mMainEmitter;
|
||||
|
||||
U32 mCurrMS;
|
||||
U32 mEndingMS;
|
||||
F32 mRandAngle;
|
||||
LightInfo* mLight;
|
||||
|
||||
protected:
|
||||
Point3F mInitialNormal;
|
||||
F32 mFade;
|
||||
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:
|
||||
void prepRenderImage( SceneRenderState *state );
|
||||
void prepBatchRender(SceneRenderState *state);
|
||||
void prepModelView(SceneRenderState*);
|
||||
|
||||
public:
|
||||
Explosion();
|
||||
~Explosion();
|
||||
void setInitialState(const Point3F& point, const Point3F& normal, const F32 fade = 1.0);
|
||||
|
||||
// ISceneLight
|
||||
virtual void submitLights( LightManager *lm, bool staticLighting );
|
||||
virtual LightInfo* getLight() { return mLight; }
|
||||
|
||||
bool onNewDataBlock( GameBaseData *dptr, bool reload );
|
||||
void setCollideType( U32 cType ){ mCollideType = cType; }
|
||||
|
||||
DECLARE_CONOBJECT(Explosion);
|
||||
static void initPersistFields();
|
||||
};
|
||||
|
||||
#endif // _H_EXPLOSION
|
||||
|
||||
1818
Engine/source/T3D/fx/fxFoliageReplicator.cpp
Normal file
1818
Engine/source/T3D/fx/fxFoliageReplicator.cpp
Normal file
File diff suppressed because it is too large
Load diff
392
Engine/source/T3D/fx/fxFoliageReplicator.h
Normal file
392
Engine/source/T3D/fx/fxFoliageReplicator.h
Normal file
|
|
@ -0,0 +1,392 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _FOLIAGEREPLICATOR_H_
|
||||
#define _FOLIAGEREPLICATOR_H_
|
||||
|
||||
#ifndef _SCENEOBJECT_H_
|
||||
#include "scene/sceneObject.h"
|
||||
#endif
|
||||
#ifndef _GFXTEXTUREHANDLE_H_
|
||||
#include "gfx/gfxTextureHandle.h"
|
||||
#endif
|
||||
#ifndef _GFXPRIMITIVEBUFFER_H_
|
||||
#include "gfx/gfxPrimitiveBuffer.h"
|
||||
#endif
|
||||
#ifndef _GBITMAP_H_
|
||||
#include "gfx/bitmap/gBitmap.h"
|
||||
#endif
|
||||
#ifndef _RENDERPASSMANAGER_H_
|
||||
#include "renderInstance/renderPassManager.h"
|
||||
#endif
|
||||
#ifndef _MATHUTIL_FRUSTUM_H_
|
||||
#include "math/util/frustum.h"
|
||||
#endif
|
||||
|
||||
#pragma warning( push, 4 )
|
||||
|
||||
#define AREA_ANIMATION_ARC (1.0f / 360.0f)
|
||||
|
||||
#define FXFOLIAGEREPLICATOR_COLLISION_MASK ( TerrainObjectType | \
|
||||
InteriorObjectType | \
|
||||
StaticShapeObjectType | \
|
||||
WaterObjectType )
|
||||
|
||||
#define FXFOLIAGEREPLICATOR_NOWATER_COLLISION_MASK ( TerrainObjectType | \
|
||||
InteriorObjectType | \
|
||||
StaticShapeObjectType )
|
||||
|
||||
|
||||
#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;
|
||||
// Used in DrawIndexPrimitive call.
|
||||
U32 startIndex;
|
||||
U32 primitiveCount;
|
||||
};
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Class: fxFoliageRenderList
|
||||
//------------------------------------------------------------------------------
|
||||
class fxFoliageRenderList
|
||||
{
|
||||
public:
|
||||
|
||||
Box3F mBox; // Clipping Box.
|
||||
Frustum mFrustum; // View frustum.
|
||||
|
||||
Vector<fxFoliageItem*> mVisObjectSet; // Visible Object Set.
|
||||
F32 mHeightLerp; // Height Lerp.
|
||||
|
||||
public:
|
||||
bool IsQuadrantVisible(const Box3F VisBox, const MatrixF& RenderTransform);
|
||||
void SetupClipPlanes(SceneRenderState* state, const F32 FarClipPlane);
|
||||
void DrawQuadBox(const Box3F& QuadBox, const ColorF Colour);
|
||||
};
|
||||
|
||||
|
||||
// Define a vertex
|
||||
GFXDeclareVertexFormat( GFXVertexFoliage )
|
||||
{
|
||||
Point3F point;
|
||||
Point3F normal;
|
||||
Point2F texCoord;
|
||||
Point2F texCoord2;
|
||||
};
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Class: fxFoliageReplicator
|
||||
//------------------------------------------------------------------------------
|
||||
class fxFoliageReplicator : public SceneObject
|
||||
{
|
||||
private:
|
||||
typedef SceneObject Parent;
|
||||
|
||||
protected:
|
||||
|
||||
void CreateFoliage(void);
|
||||
void DestroyFoliage(void);
|
||||
void DestroyFoliageItems();
|
||||
|
||||
|
||||
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;
|
||||
U32 mCurrentFoliageCount;
|
||||
|
||||
Vector<fxFoliageQuadrantNode*> mFoliageQuadTree;
|
||||
Vector<fxFoliageItem*> mReplicatedFoliage;
|
||||
fxFoliageRenderList mFrustumRenderSet;
|
||||
|
||||
GFXVertexBufferHandle<GFXVertexFoliage> mVertexBuffer;
|
||||
GFXPrimitiveBufferHandle mPrimBuffer;
|
||||
GFXShaderRef mShader;
|
||||
ShaderData* mShaderData;
|
||||
GBitmap* mAlphaLookup;
|
||||
|
||||
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.
|
||||
|
||||
// Used for alpha lookup in the pixel shader
|
||||
GFXTexHandle mAlphaTexture;
|
||||
|
||||
GFXStateBlockRef mPlacementSB;
|
||||
GFXStateBlockRef mRenderSB;
|
||||
GFXStateBlockRef mDebugSB;
|
||||
|
||||
GFXShaderConstBufferRef mFoliageShaderConsts;
|
||||
|
||||
GFXShaderConstHandle* mFoliageShaderProjectionSC;
|
||||
GFXShaderConstHandle* mFoliageShaderWorldSC;
|
||||
GFXShaderConstHandle* mFoliageShaderGlobalSwayPhaseSC;
|
||||
GFXShaderConstHandle* mFoliageShaderSwayMagnitudeSideSC;
|
||||
GFXShaderConstHandle* mFoliageShaderSwayMagnitudeFrontSC;
|
||||
GFXShaderConstHandle* mFoliageShaderGlobalLightPhaseSC;
|
||||
GFXShaderConstHandle* mFoliageShaderLuminanceMagnitudeSC;
|
||||
GFXShaderConstHandle* mFoliageShaderLuminanceMidpointSC;
|
||||
GFXShaderConstHandle* mFoliageShaderDistanceRangeSC;
|
||||
GFXShaderConstHandle* mFoliageShaderCameraPosSC;
|
||||
GFXShaderConstHandle* mFoliageShaderTrueBillboardSC;
|
||||
|
||||
//pixel shader
|
||||
GFXShaderConstHandle* mFoliageShaderGroundAlphaSC;
|
||||
GFXShaderConstHandle* mFoliageShaderAmbientColorSC;
|
||||
GFXShaderConstHandle* mDiffuseTextureSC;
|
||||
GFXShaderConstHandle* mAlphaMapTextureSC;
|
||||
|
||||
|
||||
|
||||
bool mDirty;
|
||||
|
||||
void SetupShader();
|
||||
void SetupBuffers();
|
||||
void renderObject(ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance*);
|
||||
void renderBuffers(SceneRenderState* state);
|
||||
void renderArc(const F32 fRadiusX, const F32 fRadiusY);
|
||||
void renderPlacementArea(const F32 ElapsedTime);
|
||||
void renderQuad(fxFoliageQuadrantNode* quadNode, const MatrixF& RenderTransform, const bool UseDebug);
|
||||
void computeAlphaTex();
|
||||
public:
|
||||
fxFoliageReplicator();
|
||||
~fxFoliageReplicator();
|
||||
|
||||
void StartUp(void);
|
||||
void ShowReplication(void);
|
||||
void HideReplication(void);
|
||||
|
||||
// SceneObject
|
||||
virtual void prepRenderImage( SceneRenderState *state );
|
||||
|
||||
// SimObject
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
void inspectPostApply();
|
||||
|
||||
// NetObject
|
||||
U32 packUpdate(NetConnection *conn, U32 mask, BitStream *stream);
|
||||
void unpackUpdate(NetConnection *conn, BitStream *stream);
|
||||
|
||||
// Editor
|
||||
void onGhostAlwaysDone();
|
||||
|
||||
// ConObject.
|
||||
static void initPersistFields();
|
||||
|
||||
// Field Data.
|
||||
class tagFieldData
|
||||
{
|
||||
public:
|
||||
|
||||
bool mUseDebugInfo;
|
||||
F32 mDebugBoxHeight;
|
||||
U32 mSeed;
|
||||
StringTableEntry mFoliageFile;
|
||||
GFXTexHandle 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 mUseTrueBillboards;
|
||||
|
||||
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 = 1376312589;
|
||||
mFoliageFile = StringTable->insert("");
|
||||
mFoliageTexture = GFXTexHandle();
|
||||
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;
|
||||
mUseTrueBillboards = false;
|
||||
|
||||
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);
|
||||
};
|
||||
#pragma warning( pop )
|
||||
#endif // _FOLIAGEREPLICATOR_H_
|
||||
764
Engine/source/T3D/fx/fxShapeReplicator.cpp
Normal file
764
Engine/source/T3D/fx/fxShapeReplicator.cpp
Normal file
|
|
@ -0,0 +1,764 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "T3D/fx/fxShapeReplicator.h"
|
||||
|
||||
#include "gfx/gfxDevice.h"
|
||||
#include "gfx/primBuilder.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "core/stream/bitStream.h"
|
||||
#include "math/mRandom.h"
|
||||
#include "math/mathIO.h"
|
||||
#include "T3D/gameBase/gameConnection.h"
|
||||
#include "scene/sceneManager.h"
|
||||
#include "scene/sceneRenderState.h"
|
||||
#include "renderInstance/renderPassManager.h"
|
||||
#include "console/engineAPI.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// 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);
|
||||
|
||||
ConsoleDocClass( fxShapeReplicator,
|
||||
"@brief An emitter for objects to replicate across an area.\n"
|
||||
"@ingroup Foliage\n"
|
||||
);
|
||||
|
||||
ConsoleDocClass( fxShapeReplicatedStatic,
|
||||
"@brief The object definition for shapes that will be replicated across an area using an fxShapeReplicator.\n"
|
||||
"@ingroup Foliage\n"
|
||||
);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Class: fxShapeReplicator
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
fxShapeReplicator::fxShapeReplicator()
|
||||
{
|
||||
// Setup NetObject.
|
||||
mTypeMask |= StaticObjectType;
|
||||
mNetFlags.set(Ghostable | ScopeAlways);
|
||||
|
||||
// Reset Shape Count.
|
||||
mCurrentShapeCount = 0;
|
||||
|
||||
// Reset Creation Area Angle Animation.
|
||||
mCreationAreaAngle = 0;
|
||||
|
||||
// Reset Last Render Time.
|
||||
mLastRenderTime = 0;
|
||||
|
||||
mPlacementSB = NULL;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
fxShapeReplicator::~fxShapeReplicator()
|
||||
{
|
||||
mPlacementSB = NULL;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void fxShapeReplicator::initPersistFields()
|
||||
{
|
||||
// Add out own persistent fields.
|
||||
addGroup( "Debugging" ); // MM: Added Group Header.
|
||||
addField( "HideReplications", TypeBool, Offset( mFieldData.mHideReplications, fxShapeReplicator ), "Replicated shapes are hidden when set to true." );
|
||||
addField( "ShowPlacementArea", TypeBool, Offset( mFieldData.mShowPlacementArea, fxShapeReplicator ), "Draw placement rings when set to true." );
|
||||
addField( "PlacementAreaHeight", TypeS32, Offset( mFieldData.mPlacementBandHeight, fxShapeReplicator ), "Height of the placement ring in world units." );
|
||||
addField( "PlacementColour", TypeColorF, Offset( mFieldData.mPlaceAreaColour, fxShapeReplicator ), "Color of the placement ring." );
|
||||
endGroup( "Debugging" ); // MM: Added Group Footer.
|
||||
|
||||
addGroup( "Media" ); // MM: Added Group Header.
|
||||
addField( "ShapeFile", TypeShapeFilename, Offset( mFieldData.mShapeFile, fxShapeReplicator ), "Filename of shape to replicate." );
|
||||
endGroup( "Media" ); // MM: Added Group Footer.
|
||||
|
||||
addGroup( "Replications" ); // MM: Added Group Header.
|
||||
addField( "Seed", TypeS32, Offset( mFieldData.mSeed, fxShapeReplicator ), "Random seed for shape placement." );
|
||||
addField( "ShapeCount", TypeS32, Offset( mFieldData.mShapeCount, fxShapeReplicator ), "Maximum shape instance count." );
|
||||
addField( "ShapeRetries", TypeS32, Offset( mFieldData.mShapeRetries, fxShapeReplicator ), "Number of times to try placing a shape instance before giving up." );
|
||||
endGroup( "Replications" ); // MM: Added Group Footer.
|
||||
|
||||
addGroup( "Placement Radius" ); // MM: Added Group Header.
|
||||
addField( "InnerRadiusX", TypeS32, Offset( mFieldData.mInnerRadiusX, fxShapeReplicator ), "Placement area inner radius on the X axis" );
|
||||
addField( "InnerRadiusY", TypeS32, Offset( mFieldData.mInnerRadiusY, fxShapeReplicator ), "Placement area inner radius on the Y axis" );
|
||||
addField( "OuterRadiusX", TypeS32, Offset( mFieldData.mOuterRadiusX, fxShapeReplicator ), "Placement area outer radius on the X axis" );
|
||||
addField( "OuterRadiusY", TypeS32, Offset( mFieldData.mOuterRadiusY, fxShapeReplicator ), "Placement area outer radius on the Y axis" );
|
||||
endGroup( "Placement Radius" ); // MM: Added Group Footer.
|
||||
|
||||
addGroup( "Restraints" ); // MM: Added Group Header.
|
||||
addField( "AllowOnTerrain", TypeBool, Offset( mFieldData.mAllowOnTerrain, fxShapeReplicator ), "Shapes will be placed on terrain when set." );
|
||||
addField( "AllowOnInteriors", TypeBool, Offset( mFieldData.mAllowOnInteriors, fxShapeReplicator ), "Shapes will be placed on InteriorInstances when set." );
|
||||
addField( "AllowOnStatics", TypeBool, Offset( mFieldData.mAllowStatics, fxShapeReplicator ), "Shapes will be placed on Static shapes when set." );
|
||||
addField( "AllowOnWater", TypeBool, Offset( mFieldData.mAllowOnWater, fxShapeReplicator ), "Shapes will be placed on/under water when set." );
|
||||
addField( "AllowWaterSurface", TypeBool, Offset( mFieldData.mAllowWaterSurface, fxShapeReplicator ), "Shapes will be placed on water when set. Requires AllowOnWater." );
|
||||
addField( "AlignToTerrain", TypeBool, Offset( mFieldData.mAlignToTerrain, fxShapeReplicator ), "Align shapes to surface normal when set." );
|
||||
addField( "Interactions", TypeBool, Offset( mFieldData.mInteractions, fxShapeReplicator ), "Allow physics interactions with shapes." );
|
||||
addField( "AllowedTerrainSlope", TypeS32, Offset( mFieldData.mAllowedTerrainSlope, fxShapeReplicator ), "Maximum surface angle allowed for shape instances." );
|
||||
addField( "TerrainAlignment", TypePoint3F, Offset( mFieldData.mTerrainAlignment, fxShapeReplicator ), "Surface normals will be multiplied by these values when AlignToTerrain is enabled." );
|
||||
endGroup( "Restraints" ); // MM: Added Group Footer.
|
||||
|
||||
addGroup( "Object Transforms" ); // MM: Added Group Header.
|
||||
addField( "ShapeScaleMin", TypePoint3F, Offset( mFieldData.mShapeScaleMin, fxShapeReplicator ), "Minimum shape scale." );
|
||||
addField( "ShapeScaleMax", TypePoint3F, Offset( mFieldData.mShapeScaleMax, fxShapeReplicator ), "Maximum shape scale." );
|
||||
addField( "ShapeRotateMin", TypePoint3F, Offset( mFieldData.mShapeRotateMin, fxShapeReplicator ), "Minimum shape rotation angles.");
|
||||
addField( "ShapeRotateMax", TypePoint3F, Offset( mFieldData.mShapeRotateMax, fxShapeReplicator ), "Maximum shape rotation angles." );
|
||||
addField( "OffsetZ", TypeS32, Offset( mFieldData.mOffsetZ, fxShapeReplicator ), "Offset shapes by this amount vertically." );
|
||||
endGroup( "Object Transforms" ); // MM: Added Group Footer.
|
||||
|
||||
// Initialise parents' persistent fields.
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void fxShapeReplicator::CreateShapes(void)
|
||||
{
|
||||
F32 HypX, HypY;
|
||||
F32 Angle;
|
||||
U32 RelocationRetry;
|
||||
Point3F ShapePosition;
|
||||
Point3F ShapeStart;
|
||||
Point3F ShapeEnd;
|
||||
Point3F ShapeScale;
|
||||
EulerF ShapeRotation;
|
||||
QuatF QRotation;
|
||||
bool CollisionResult;
|
||||
RayInfo RayEvent;
|
||||
TSShape* pShape;
|
||||
|
||||
|
||||
// Don't create shapes if we are hiding replications.
|
||||
if (mFieldData.mHideReplications) return;
|
||||
|
||||
// Cannot continue without shapes!
|
||||
if (dStrcmp(mFieldData.mShapeFile, "") == 0) 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.clear();
|
||||
|
||||
// Add shapes.
|
||||
for (U32 idx = 0; idx < mFieldData.mShapeCount; idx++)
|
||||
{
|
||||
fxShapeReplicatedStatic* fxStatic;
|
||||
|
||||
// Create our static shape.
|
||||
fxStatic = new fxShapeReplicatedStatic();
|
||||
|
||||
// Set the 'shapeName' field.
|
||||
fxStatic->setField("shapeName", mFieldData.mShapeFile);
|
||||
|
||||
// Is this Replicator on the Server?
|
||||
if (isServerObject())
|
||||
// Yes, so stop it from Ghosting. (Hack, Hack, Hack!)
|
||||
fxStatic->touchNetFlags(Ghostable, false);
|
||||
else
|
||||
// No, so flag as ghost object. (Another damn Hack!)
|
||||
fxStatic->touchNetFlags(IsGhost, true);
|
||||
|
||||
// Register the Object.
|
||||
if (!fxStatic->registerObject())
|
||||
{
|
||||
// Problem ...
|
||||
Con::warnf(ConsoleLogEntry::General, "[%s] - Could not load shape file '%s'!", getName(), mFieldData.mShapeFile);
|
||||
|
||||
// Destroy Shape.
|
||||
delete fxStatic;
|
||||
|
||||
// Destroy existing hapes.
|
||||
DestroyShapes();
|
||||
|
||||
// Quit.
|
||||
return;
|
||||
}
|
||||
|
||||
// Get Allocated Shape.
|
||||
pShape = fxStatic->getShape();
|
||||
|
||||
// Reset Relocation Retry.
|
||||
RelocationRetry = mFieldData.mShapeRetries;
|
||||
|
||||
// Find it a home ...
|
||||
do
|
||||
{
|
||||
// Get the Replicator Position.
|
||||
ShapePosition = getPosition();
|
||||
|
||||
// Calculate a random offset
|
||||
HypX = RandomGen.randF(mFieldData.mInnerRadiusX, mFieldData.mOuterRadiusX);
|
||||
HypY = RandomGen.randF(mFieldData.mInnerRadiusY, mFieldData.mOuterRadiusY);
|
||||
Angle = RandomGen.randF(0, (F32)M_2PI);
|
||||
|
||||
// Calcualte the new position.
|
||||
ShapePosition.x += HypX * mCos(Angle);
|
||||
ShapePosition.y += HypY * mSin(Angle);
|
||||
|
||||
|
||||
// Initialise RayCast Search Start/End Positions.
|
||||
ShapeStart = ShapeEnd = ShapePosition;
|
||||
ShapeStart.z = 2000.f;
|
||||
ShapeEnd.z= -2000.f;
|
||||
|
||||
// Is this the Server?
|
||||
if (isServerObject())
|
||||
// Perform Ray Cast Collision on Server Terrain.
|
||||
CollisionResult = gServerContainer.castRay(ShapeStart, ShapeEnd, FXREPLICATOR_COLLISION_MASK, &RayEvent);
|
||||
else
|
||||
// Perform Ray Cast Collision on Client Terrain.
|
||||
CollisionResult = gClientContainer.castRay( ShapeStart, ShapeEnd, FXREPLICATOR_COLLISION_MASK, &RayEvent);
|
||||
|
||||
// Did we hit anything?
|
||||
if (CollisionResult)
|
||||
{
|
||||
// For now, let's pretend we didn't get a collision.
|
||||
CollisionResult = false;
|
||||
|
||||
// Yes, so get it's type.
|
||||
U32 CollisionType = RayEvent.object->getTypeMask();
|
||||
|
||||
// Check Illegal Placements.
|
||||
if (((CollisionType & TerrainObjectType) && !mFieldData.mAllowOnTerrain) ||
|
||||
((CollisionType & InteriorObjectType) && !mFieldData.mAllowOnInteriors) ||
|
||||
((CollisionType & StaticShapeObjectType) && !mFieldData.mAllowStatics) ||
|
||||
((CollisionType & WaterObjectType) && !mFieldData.mAllowOnWater) ) continue;
|
||||
|
||||
// If we collided with water and are not allowing on the water surface then let's find the
|
||||
// terrain underneath and pass this on as the original collision else fail.
|
||||
//
|
||||
// NOTE:- We need to do this on the server/client as appropriate.
|
||||
if ((CollisionType & WaterObjectType) && !mFieldData.mAllowWaterSurface)
|
||||
{
|
||||
// Is this the Server?
|
||||
if (isServerObject())
|
||||
{
|
||||
// Yes, so do it on the server container.
|
||||
if (!gServerContainer.castRay( ShapeStart, ShapeEnd, FXREPLICATOR_NOWATER_COLLISION_MASK, &RayEvent)) continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// No, so do it on the client container.
|
||||
if (!gClientContainer.castRay( ShapeStart, ShapeEnd, FXREPLICATOR_NOWATER_COLLISION_MASK, &RayEvent)) continue;
|
||||
}
|
||||
}
|
||||
|
||||
// We passed with flying colours so carry on.
|
||||
CollisionResult = true;
|
||||
}
|
||||
|
||||
// Invalidate if we are below Allowed Terrain Angle.
|
||||
if (RayEvent.normal.z < mSin(mDegToRad(90.0f-mFieldData.mAllowedTerrainSlope))) CollisionResult = false;
|
||||
|
||||
// Wait until we get a collision.
|
||||
} while(!CollisionResult && --RelocationRetry);
|
||||
|
||||
// Check for Relocation Problem.
|
||||
if (RelocationRetry > 0)
|
||||
{
|
||||
// Adjust Impact point.
|
||||
RayEvent.point.z += mFieldData.mOffsetZ;
|
||||
|
||||
// Set New Position.
|
||||
ShapePosition = RayEvent.point;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Warning.
|
||||
Con::warnf(ConsoleLogEntry::General, "[%s] - Could not find satisfactory position for shape '%s' on %s!", getName(), mFieldData.mShapeFile,isServerObject()?"Server":"Client");
|
||||
|
||||
// Unregister Object.
|
||||
fxStatic->unregisterObject();
|
||||
|
||||
// Destroy Shape.
|
||||
delete fxStatic;
|
||||
|
||||
// Skip to next.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get Shape Transform.
|
||||
MatrixF XForm = fxStatic->getTransform();
|
||||
|
||||
// Are we aligning to Terrain?
|
||||
if (mFieldData.mAlignToTerrain)
|
||||
{
|
||||
// Yes, so set rotation to Terrain Impact Normal.
|
||||
ShapeRotation = RayEvent.normal * mFieldData.mTerrainAlignment;
|
||||
}
|
||||
else
|
||||
{
|
||||
// No, so choose a new Rotation (in Radians).
|
||||
ShapeRotation.set( mDegToRad(RandomGen.randF(mFieldData.mShapeRotateMin.x, mFieldData.mShapeRotateMax.x)),
|
||||
mDegToRad(RandomGen.randF(mFieldData.mShapeRotateMin.y, mFieldData.mShapeRotateMax.y)),
|
||||
mDegToRad(RandomGen.randF(mFieldData.mShapeRotateMin.z, mFieldData.mShapeRotateMax.z)));
|
||||
}
|
||||
|
||||
// Set Quaternion Roation.
|
||||
QRotation.set(ShapeRotation);
|
||||
|
||||
// Set Transform Rotation.
|
||||
QRotation.setMatrix(&XForm);
|
||||
|
||||
// Set Position.
|
||||
XForm.setColumn(3, ShapePosition);
|
||||
|
||||
// Set Shape Position / Rotation.
|
||||
fxStatic->setTransform(XForm);
|
||||
|
||||
// Choose a new Scale.
|
||||
ShapeScale.set( RandomGen.randF(mFieldData.mShapeScaleMin.x, mFieldData.mShapeScaleMax.x),
|
||||
RandomGen.randF(mFieldData.mShapeScaleMin.y, mFieldData.mShapeScaleMax.y),
|
||||
RandomGen.randF(mFieldData.mShapeScaleMin.z, mFieldData.mShapeScaleMax.z));
|
||||
|
||||
// Set Shape Scale.
|
||||
fxStatic->setScale(ShapeScale);
|
||||
|
||||
// Lock it.
|
||||
fxStatic->setLocked(true);
|
||||
|
||||
// Store Shape in Replicated Shapes Vector.
|
||||
//mReplicatedShapes[mCurrentShapeCount++] = fxStatic;
|
||||
mReplicatedShapes.push_back(fxStatic);
|
||||
|
||||
}
|
||||
|
||||
mCurrentShapeCount = mReplicatedShapes.size();
|
||||
|
||||
// Take first Timestamp.
|
||||
mLastRenderTime = Platform::getVirtualMilliseconds();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void fxShapeReplicator::DestroyShapes(void)
|
||||
{
|
||||
// Finish if we didn't create any shapes.
|
||||
if (mCurrentShapeCount == 0) return;
|
||||
|
||||
// Remove shapes.
|
||||
for (U32 idx = 0; idx < mCurrentShapeCount; idx++)
|
||||
{
|
||||
fxShapeReplicatedStatic* fxStatic;
|
||||
|
||||
// Fetch the Shape Object.
|
||||
fxStatic = mReplicatedShapes[idx];
|
||||
|
||||
// Got a Shape?
|
||||
if (fxStatic)
|
||||
{
|
||||
// Unlock it.
|
||||
fxStatic->setLocked(false);
|
||||
|
||||
// Unregister the object.
|
||||
fxStatic->unregisterObject();
|
||||
|
||||
// Delete it.
|
||||
delete fxStatic;
|
||||
}
|
||||
}
|
||||
|
||||
// Empty the Replicated Shapes Vector.
|
||||
mReplicatedShapes.clear();
|
||||
|
||||
// Reset Shape Count.
|
||||
mCurrentShapeCount = 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void fxShapeReplicator::RenewShapes(void)
|
||||
{
|
||||
// Destroy any shapes.
|
||||
DestroyShapes();
|
||||
|
||||
// Don't create shapes on the Server if we don't need interactions.
|
||||
if (isServerObject() && !mFieldData.mInteractions) return;
|
||||
|
||||
// Create Shapes.
|
||||
CreateShapes();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void fxShapeReplicator::StartUp(void)
|
||||
{
|
||||
RenewShapes();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool fxShapeReplicator::onAdd()
|
||||
{
|
||||
if(!Parent::onAdd())
|
||||
return(false);
|
||||
|
||||
// Add the Replicator to the Replicator Set.
|
||||
dynamic_cast<SimSet*>(Sim::findObject("fxReplicatorSet"))->addObject(this);
|
||||
|
||||
// Set Default Object Box.
|
||||
mObjBox.minExtents.set( -0.5, -0.5, -0.5 );
|
||||
mObjBox.maxExtents.set( 0.5, 0.5, 0.5 );
|
||||
resetWorldBox();
|
||||
|
||||
// Add to Scene.
|
||||
setRenderTransform(mObjToWorld);
|
||||
addToScene();
|
||||
|
||||
// Register for notification when GhostAlways objects are done loading
|
||||
NetConnection::smGhostAlwaysDone.notify( this, &fxShapeReplicator::onGhostAlwaysDone );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void fxShapeReplicator::onRemove()
|
||||
{
|
||||
// Remove the Replicator from the Replicator Set.
|
||||
dynamic_cast<SimSet*>(Sim::findObject("fxReplicatorSet"))->removeObject(this);
|
||||
|
||||
NetConnection::smGhostAlwaysDone.remove( this, &fxShapeReplicator::onGhostAlwaysDone );
|
||||
|
||||
removeFromScene();
|
||||
|
||||
// Destroy Shapes.
|
||||
DestroyShapes();
|
||||
|
||||
// Do Parent.
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void fxShapeReplicator::onGhostAlwaysDone()
|
||||
{
|
||||
RenewShapes();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void fxShapeReplicator::inspectPostApply()
|
||||
{
|
||||
// Set Parent.
|
||||
Parent::inspectPostApply();
|
||||
|
||||
// Renew Shapes.
|
||||
RenewShapes();
|
||||
|
||||
// Set Replication Mask.
|
||||
setMaskBits(ReplicationMask);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
DefineEngineFunction(StartClientReplication, void, (),, "Activates the shape replicator.\n"
|
||||
"@tsexample\n"
|
||||
"// Call the function\n"
|
||||
"StartClientReplication()\n"
|
||||
"@endtsexample\n"
|
||||
"@ingroup Foliage"
|
||||
)
|
||||
{
|
||||
// Find the Replicator Set.
|
||||
SimSet *fxReplicatorSet = dynamic_cast<SimSet*>(Sim::findObject("fxReplicatorSet"));
|
||||
|
||||
// Return if Error.
|
||||
if (!fxReplicatorSet) return;
|
||||
|
||||
// StartUp Replication Object.
|
||||
for (SimSetIterator itr(fxReplicatorSet); *itr; ++itr)
|
||||
{
|
||||
// Fetch the Replicator Object.
|
||||
fxShapeReplicator* Replicator = static_cast<fxShapeReplicator*>(*itr);
|
||||
// Start Client Objects Only.
|
||||
if (Replicator->isClientObject()) Replicator->StartUp();
|
||||
}
|
||||
// Info ...
|
||||
Con::printf("Client Replication Startup has Happened!");
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void fxShapeReplicator::prepRenderImage( SceneRenderState* state )
|
||||
{
|
||||
ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
|
||||
ri->renderDelegate.bind(this, &fxShapeReplicator::renderObject);
|
||||
// The fxShapeReplicator isn't technically foliage but our debug
|
||||
// effect seems to render best as a Foliage type (translucent,
|
||||
// renders itself, no sorting)
|
||||
ri->type = RenderPassManager::RIT_Foliage;
|
||||
state->getRenderPass()->addInst( ri );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Renders a triangle stripped oval
|
||||
void fxShapeReplicator::renderArc(const F32 fRadiusX, const F32 fRadiusY)
|
||||
{
|
||||
PrimBuild::begin(GFXTriangleStrip, 720);
|
||||
for (U32 Angle = mCreationAreaAngle; Angle < (mCreationAreaAngle+360); Angle++)
|
||||
{
|
||||
F32 XPos, YPos;
|
||||
|
||||
// Calculate Position.
|
||||
XPos = fRadiusX * mCos(mDegToRad(-(F32)Angle));
|
||||
YPos = fRadiusY * mSin(mDegToRad(-(F32)Angle));
|
||||
|
||||
// Set Colour.
|
||||
PrimBuild::color4f(mFieldData.mPlaceAreaColour.red,
|
||||
mFieldData.mPlaceAreaColour.green,
|
||||
mFieldData.mPlaceAreaColour.blue,
|
||||
AREA_ANIMATION_ARC * (Angle-mCreationAreaAngle));
|
||||
|
||||
PrimBuild::vertex3f(XPos, YPos, -(F32)mFieldData.mPlacementBandHeight/2.0f);
|
||||
PrimBuild::vertex3f(XPos, YPos, +(F32)mFieldData.mPlacementBandHeight/2.0f);
|
||||
}
|
||||
PrimBuild::end();
|
||||
}
|
||||
|
||||
// This currently uses the primbuilder, could convert out, but why allocate the buffer if we
|
||||
// never edit the misison?
|
||||
void fxShapeReplicator::renderPlacementArea(const F32 ElapsedTime)
|
||||
{
|
||||
if (gEditingMission && mFieldData.mShowPlacementArea)
|
||||
{
|
||||
GFX->pushWorldMatrix();
|
||||
GFX->multWorld(getTransform());
|
||||
|
||||
if (!mPlacementSB)
|
||||
{
|
||||
GFXStateBlockDesc transparent;
|
||||
transparent.setCullMode(GFXCullNone);
|
||||
transparent.alphaTestEnable = true;
|
||||
transparent.setZReadWrite(true);
|
||||
transparent.zWriteEnable = false;
|
||||
transparent.setBlend(true, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha);
|
||||
mPlacementSB = GFX->createStateBlock( transparent );
|
||||
}
|
||||
|
||||
GFX->setStateBlock(mPlacementSB);
|
||||
|
||||
// Do we need to draw the Outer Radius?
|
||||
if (mFieldData.mOuterRadiusX || mFieldData.mOuterRadiusY)
|
||||
renderArc((F32) mFieldData.mOuterRadiusX, (F32) mFieldData.mOuterRadiusY);
|
||||
// Inner radius?
|
||||
if (mFieldData.mInnerRadiusX || mFieldData.mInnerRadiusY)
|
||||
renderArc((F32) mFieldData.mInnerRadiusX, (F32) mFieldData.mInnerRadiusY);
|
||||
|
||||
GFX->popWorldMatrix();
|
||||
mCreationAreaAngle = (U32)(mCreationAreaAngle + (1000 * ElapsedTime));
|
||||
mCreationAreaAngle = mCreationAreaAngle % 360;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void fxShapeReplicator::renderObject(ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance* overrideMat)
|
||||
{
|
||||
if (overrideMat)
|
||||
return;
|
||||
|
||||
// Return if placement area not needed.
|
||||
if (!mFieldData.mShowPlacementArea)
|
||||
return;
|
||||
|
||||
// Calculate Elapsed Time and take new Timestamp.
|
||||
S32 Time = Platform::getVirtualMilliseconds();
|
||||
F32 ElapsedTime = (Time - mLastRenderTime) * 0.001f;
|
||||
mLastRenderTime = Time;
|
||||
|
||||
renderPlacementArea(ElapsedTime);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
U32 fxShapeReplicator::packUpdate(NetConnection * con, U32 mask, BitStream * stream)
|
||||
{
|
||||
// Pack Parent.
|
||||
U32 retMask = Parent::packUpdate(con, mask, stream);
|
||||
|
||||
// Write Replication Flag.
|
||||
if (stream->writeFlag(mask & ReplicationMask))
|
||||
{
|
||||
stream->writeAffineTransform(mObjToWorld); // Replicator Position.
|
||||
|
||||
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.
|
||||
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);
|
||||
|
||||
// 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.
|
||||
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);
|
||||
|
||||
RenewShapes();
|
||||
}
|
||||
}
|
||||
|
||||
196
Engine/source/T3D/fx/fxShapeReplicator.h
Normal file
196
Engine/source/T3D/fx/fxShapeReplicator.h
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _SHAPEREPLICATOR_H_
|
||||
#define _SHAPEREPLICATOR_H_
|
||||
|
||||
#ifndef _TSSTATIC_H_
|
||||
#include "T3D/tsStatic.h"
|
||||
#endif
|
||||
#ifndef _TSSHAPEINSTANCE_H_
|
||||
#include "ts/tsShapeInstance.h"
|
||||
#endif
|
||||
#ifndef _RENDERPASSMANAGER_H_
|
||||
#include "renderInstance/renderPassManager.h"
|
||||
#endif
|
||||
|
||||
#define AREA_ANIMATION_ARC (1.0f / 360.0f)
|
||||
|
||||
#define FXREPLICATOR_COLLISION_MASK ( TerrainObjectType | \
|
||||
InteriorObjectType | \
|
||||
StaticShapeObjectType | \
|
||||
WaterObjectType )
|
||||
|
||||
#define FXREPLICATOR_NOWATER_COLLISION_MASK ( TerrainObjectType | \
|
||||
InteriorObjectType | \
|
||||
StaticShapeObjectType )
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// 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) };
|
||||
|
||||
U32 mCreationAreaAngle;
|
||||
U32 mCurrentShapeCount;
|
||||
Vector<fxShapeReplicatedStatic*> mReplicatedShapes;
|
||||
MRandomLCG RandomGen;
|
||||
S32 mLastRenderTime;
|
||||
|
||||
|
||||
public:
|
||||
fxShapeReplicator();
|
||||
~fxShapeReplicator();
|
||||
|
||||
|
||||
void StartUp(void);
|
||||
void ShowReplication(void);
|
||||
void HideReplication(void);
|
||||
|
||||
GFXStateBlockRef mPlacementSB;
|
||||
|
||||
void renderObject(ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance*);
|
||||
void renderArc(const F32 fRadiusX, const F32 fRadiusY);
|
||||
void renderPlacementArea(const F32 ElapsedTime);
|
||||
|
||||
// SceneObject
|
||||
virtual void prepRenderImage( SceneRenderState *state );
|
||||
|
||||
// SimObject
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
void inspectPostApply();
|
||||
|
||||
// NetObject
|
||||
U32 packUpdate(NetConnection *conn, U32 mask, BitStream *stream);
|
||||
void unpackUpdate(NetConnection *conn, BitStream *stream);
|
||||
|
||||
// Editor
|
||||
void onGhostAlwaysDone();
|
||||
|
||||
// ConObject.
|
||||
static void initPersistFields();
|
||||
|
||||
// Field Data.
|
||||
class tagFieldData
|
||||
{
|
||||
public:
|
||||
|
||||
U32 mSeed;
|
||||
StringTableEntry mShapeFile;
|
||||
U32 mShapeCount;
|
||||
U32 mShapeRetries;
|
||||
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 = 1376312589;
|
||||
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);
|
||||
|
||||
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_
|
||||
1694
Engine/source/T3D/fx/groundCover.cpp
Normal file
1694
Engine/source/T3D/fx/groundCover.cpp
Normal file
File diff suppressed because it is too large
Load diff
391
Engine/source/T3D/fx/groundCover.h
Normal file
391
Engine/source/T3D/fx/groundCover.h
Normal file
|
|
@ -0,0 +1,391 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _GROUNDCOVER_H_
|
||||
#define _GROUNDCOVER_H_
|
||||
|
||||
#ifndef _SCENEOBJECT_H_
|
||||
#include "scene/sceneObject.h"
|
||||
#endif
|
||||
#ifndef _MATHUTIL_FRUSTUM_H_
|
||||
#include "math/util/frustum.h"
|
||||
#endif
|
||||
#ifndef _GFXTEXTUREHANDLE_H_
|
||||
#include "gfx/gfxTextureHandle.h"
|
||||
#endif
|
||||
#ifndef _GFX_GFXPRIMITIVEBUFFER_H_
|
||||
#include "gfx/gfxPrimitiveBuffer.h"
|
||||
#endif
|
||||
#ifndef _RENDERPASSMANAGER_H_
|
||||
#include "renderInstance/renderPassManager.h"
|
||||
#endif
|
||||
#ifndef _MATTEXTURETARGET_H_
|
||||
#include "materials/matTextureTarget.h"
|
||||
#endif
|
||||
#ifndef _SHADERFEATURE_H_
|
||||
#include "shaderGen/shaderFeature.h"
|
||||
#endif
|
||||
|
||||
class TerrainBlock;
|
||||
class GroundCoverCell;
|
||||
class TSShapeInstance;
|
||||
class Material;
|
||||
class MaterialParameters;
|
||||
class MaterialParameterHandle;
|
||||
|
||||
|
||||
///
|
||||
#define MAX_COVERTYPES 8
|
||||
|
||||
|
||||
GFXDeclareVertexFormat( GCVertex )
|
||||
{
|
||||
Point3F point;
|
||||
|
||||
Point3F normal;
|
||||
|
||||
// .rgb = ambient
|
||||
// .a = corner index
|
||||
GFXVertexColor ambient;
|
||||
|
||||
// .x = size x
|
||||
// .y = size y
|
||||
// .z = type
|
||||
// .w = wind amplitude
|
||||
Point4F params;
|
||||
};
|
||||
|
||||
struct GroundCoverShaderConstData
|
||||
{
|
||||
Point2F fadeInfo;
|
||||
Point3F gustInfo;
|
||||
Point2F turbInfo;
|
||||
Point3F camRight;
|
||||
Point3F camUp;
|
||||
};
|
||||
|
||||
class GroundCover;
|
||||
|
||||
class GroundCoverShaderConstHandles : public ShaderFeatureConstHandles
|
||||
{
|
||||
public:
|
||||
|
||||
GroundCoverShaderConstHandles();
|
||||
|
||||
virtual void init( GFXShader *shader );
|
||||
|
||||
virtual void setConsts( SceneRenderState *state,
|
||||
const SceneData &sgData,
|
||||
GFXShaderConstBuffer *buffer );
|
||||
|
||||
GroundCover *mGroundCover;
|
||||
|
||||
GFXShaderConstHandle *mTypeRectsSC;
|
||||
GFXShaderConstHandle *mFadeSC;
|
||||
GFXShaderConstHandle *mWindDirSC;
|
||||
GFXShaderConstHandle *mGustInfoSC;
|
||||
GFXShaderConstHandle *mTurbInfoSC;
|
||||
GFXShaderConstHandle *mCamRightSC;
|
||||
GFXShaderConstHandle *mCamUpSC;
|
||||
};
|
||||
|
||||
|
||||
class GroundCover : public SceneObject
|
||||
{
|
||||
friend class GroundCoverShaderConstHandles;
|
||||
friend class GroundCoverCell;
|
||||
typedef SceneObject Parent;
|
||||
|
||||
public:
|
||||
|
||||
GroundCover();
|
||||
~GroundCover();
|
||||
|
||||
DECLARE_CONOBJECT(GroundCover);
|
||||
|
||||
static void consoleInit();
|
||||
static void initPersistFields();
|
||||
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
void inspectPostApply();
|
||||
|
||||
// Network
|
||||
U32 packUpdate( NetConnection *, U32 mask, BitStream *stream );
|
||||
void unpackUpdate( NetConnection *, BitStream *stream );
|
||||
|
||||
// Rendering
|
||||
void prepRenderImage( SceneRenderState *state );
|
||||
|
||||
// Editor
|
||||
void onTerrainUpdated( U32 flags, TerrainBlock *tblock, const Point2I& min, const Point2I& max );
|
||||
|
||||
// Misc
|
||||
const GroundCoverShaderConstData& getShaderConstData() const { return mShaderConstData; }
|
||||
|
||||
/// Sets the global ground cover LOD scalar which controls
|
||||
/// the percentage of the maximum designed cover to put down.
|
||||
/// It scales both rendering cost and placement CPU performance.
|
||||
/// Returns the actual value set.
|
||||
static F32 setQualityScale( F32 scale ) { return smDensityScale = mClampF( scale, 0.0f, 1.0f ); }
|
||||
|
||||
/// Returns the current quality scale... see above.
|
||||
static F32 getQualityScale() { return smDensityScale; }
|
||||
|
||||
protected:
|
||||
|
||||
enum MaskBits
|
||||
{
|
||||
TerrainBlockMask = Parent::NextFreeMask << 0,
|
||||
NextFreeMask = Parent::NextFreeMask << 1
|
||||
};
|
||||
|
||||
MaterialParameters *mMatParams;
|
||||
MaterialParameterHandle *mTypeRectsParam;
|
||||
MaterialParameterHandle *mFadeParams;
|
||||
MaterialParameterHandle *mWindDirParam;
|
||||
MaterialParameterHandle *mGustInfoParam;
|
||||
MaterialParameterHandle *mTurbInfoParam;
|
||||
MaterialParameterHandle *mCamRightParam;
|
||||
MaterialParameterHandle *mCamUpParam;
|
||||
|
||||
/// This RNG seed is saved and sent to clients
|
||||
/// for generating the same cover.
|
||||
S32 mRandomSeed;
|
||||
|
||||
/// This is the outer generation radius from
|
||||
/// the current camera position.
|
||||
F32 mRadius;
|
||||
|
||||
// Offset along the Z axis to render the ground cover.
|
||||
F32 mZOffset;
|
||||
|
||||
/// This is less than or equal to mRadius and
|
||||
/// defines when fading of cover elements begins.
|
||||
F32 mFadeRadius;
|
||||
|
||||
/// This is the distance at which DTS elements are
|
||||
/// completely culled out.
|
||||
F32 mShapeCullRadius;
|
||||
|
||||
/// Whether shapes rendered by the GroundCover should cast shadows.
|
||||
bool mShapesCastShadows;
|
||||
|
||||
/// This is used to scale the various culling radii
|
||||
/// when rendering a reflection... typically for water.
|
||||
F32 mReflectRadiusScale;
|
||||
|
||||
/// This is the number of cells per axis in the grid.
|
||||
U32 mGridSize;
|
||||
|
||||
typedef Vector<GroundCoverCell*> CellVector;
|
||||
|
||||
/// This is the allocator for GridCell chunks.
|
||||
CellVector mAllocCellList;
|
||||
CellVector mFreeCellList;
|
||||
|
||||
/// This is the grid of active cells.
|
||||
CellVector mCellGrid;
|
||||
|
||||
/// This is a scratch grid used while updating
|
||||
/// the cell grid.
|
||||
CellVector mScratchGrid;
|
||||
|
||||
/// This is the index to the first grid cell.
|
||||
Point2I mGridIndex;
|
||||
|
||||
/// The maximum amount of cover elements to include in
|
||||
/// the grid at any one time. The actual amount may be
|
||||
/// less than this based on randomization.
|
||||
S32 mMaxPlacement;
|
||||
|
||||
/// Used to detect changes in cell placement count from
|
||||
/// the global quality scale so we can regen the cells.
|
||||
S32 mLastPlacementCount;
|
||||
|
||||
/// Used for culling cells to update and render.
|
||||
Frustum mCuller;
|
||||
|
||||
/// Debug parameter for displaying the grid cells.
|
||||
bool mDebugRenderCells;
|
||||
|
||||
/// Debug parameter for turning off billboard rendering.
|
||||
bool mDebugNoBillboards;
|
||||
|
||||
/// Debug parameter for turning off shape rendering.
|
||||
bool mDebugNoShapes;
|
||||
|
||||
/// Debug parameter for locking the culling frustum which
|
||||
/// will freeze the cover generation.
|
||||
bool mDebugLockFrustum;
|
||||
|
||||
/// Stat for number of rendered cells.
|
||||
static U32 smStatRenderedCells;
|
||||
|
||||
/// Stat for number of rendered billboards.
|
||||
static U32 smStatRenderedBillboards;
|
||||
|
||||
/// Stat for number of rendered billboard batches.
|
||||
static U32 smStatRenderedBatches;
|
||||
|
||||
/// Stat for number of rendered shapes.
|
||||
static U32 smStatRenderedShapes;
|
||||
|
||||
/// The global ground cover LOD scalar which controls
|
||||
/// the percentage of the maximum amount of cover to put
|
||||
/// down. It scales both rendering cost and placement
|
||||
/// CPU performance.
|
||||
static F32 smDensityScale;
|
||||
|
||||
String mMaterialName;
|
||||
Material *mMaterial;
|
||||
BaseMatInstance *mMatInst;
|
||||
|
||||
GroundCoverShaderConstData mShaderConstData;
|
||||
|
||||
/// This is the maximum amout of degrees the billboard will
|
||||
/// tilt down to match the camera.
|
||||
F32 mMaxBillboardTiltAngle;
|
||||
|
||||
/// The probability of one cover type verses another.
|
||||
F32 mProbability[MAX_COVERTYPES];
|
||||
|
||||
/// The minimum random size for each cover type.
|
||||
F32 mSizeMin[MAX_COVERTYPES];
|
||||
|
||||
/// The maximum random size of this cover type.
|
||||
F32 mSizeMax[MAX_COVERTYPES];
|
||||
|
||||
/// An exponent used to bias between the minimum
|
||||
/// and maximum random sizes.
|
||||
F32 mSizeExponent[MAX_COVERTYPES];
|
||||
|
||||
/// The wind effect scale.
|
||||
F32 mWindScale[MAX_COVERTYPES];
|
||||
|
||||
/// The maximum slope angle in degrees for placement.
|
||||
F32 mMaxSlope[MAX_COVERTYPES];
|
||||
|
||||
/// The minimum world space elevation for placement.
|
||||
F32 mMinElevation[MAX_COVERTYPES];
|
||||
|
||||
/// The maximum world space elevation for placement.
|
||||
F32 mMaxElevation[MAX_COVERTYPES];
|
||||
|
||||
/// Terrain material name to limit coverage to, or
|
||||
/// left empty to cover entire terrain.
|
||||
StringTableEntry mLayer[MAX_COVERTYPES];
|
||||
|
||||
/// Inverts the data layer test making the
|
||||
/// layer an exclusion mask.
|
||||
bool mInvertLayer[MAX_COVERTYPES];
|
||||
|
||||
/// The minimum amount of elements in a clump.
|
||||
S32 mMinClumpCount[MAX_COVERTYPES];
|
||||
|
||||
/// The maximum amount of elements in a clump.
|
||||
S32 mMaxClumpCount[MAX_COVERTYPES];
|
||||
|
||||
/// An exponent used to bias between the minimum
|
||||
/// and maximum clump counts for a particular clump.
|
||||
F32 mClumpCountExponent[MAX_COVERTYPES];
|
||||
|
||||
/// The maximum clump radius.
|
||||
F32 mClumpRadius[MAX_COVERTYPES];
|
||||
|
||||
/// This is a cached array of billboard aspect scales
|
||||
/// used to avoid some calculations when generating cells.
|
||||
F32 mBillboardAspectScales[MAX_COVERTYPES];
|
||||
|
||||
RectF mBillboardRects[MAX_COVERTYPES];
|
||||
|
||||
/// The cover shape filenames.
|
||||
StringTableEntry mShapeFilenames[MAX_COVERTYPES];
|
||||
|
||||
/// The cover shape instances.
|
||||
TSShapeInstance* mShapeInstances[MAX_COVERTYPES];
|
||||
|
||||
/// This is the same as mProbability, but normalized for use
|
||||
/// during the cover placement process.
|
||||
F32 mNormalizedProbability[MAX_COVERTYPES];
|
||||
|
||||
/// A shared primitive buffer setup for drawing the maximum amount
|
||||
/// of billboards you could possibly have in a single cell.
|
||||
GFXPrimitiveBufferHandle mPrimBuffer;
|
||||
|
||||
/// The length in meters between peaks in the wind gust.
|
||||
F32 mWindGustLength;
|
||||
|
||||
/// Controls how often the wind gust peaks per second.
|
||||
F32 mWindGustFrequency;
|
||||
|
||||
/// The maximum distance in meters that the peak wind
|
||||
/// gust will displace an element.
|
||||
F32 mWindGustStrength;
|
||||
|
||||
/// The direction of the wind.
|
||||
Point2F mWindDirection;
|
||||
|
||||
/// Controls the overall rapidity of the wind turbulence.
|
||||
F32 mWindTurbulenceFrequency;
|
||||
|
||||
/// The maximum distance in meters that the turbulence can
|
||||
/// displace a ground cover element.
|
||||
F32 mWindTurbulenceStrength;
|
||||
|
||||
void _initMaterial();
|
||||
|
||||
bool _initShader();
|
||||
|
||||
void _initShapes();
|
||||
|
||||
void _deleteShapes();
|
||||
|
||||
/// Called when GroundCover parameters are changed and
|
||||
/// things need to be reinitialized to continue.
|
||||
void _initialize( U32 cellCount, U32 cellPlacementCount );
|
||||
|
||||
/// Updates the cover grid by removing cells that
|
||||
/// have fallen outside of mRadius and adding new
|
||||
/// ones that have come into view.
|
||||
void _updateCoverGrid( const Frustum &culler );
|
||||
|
||||
/// Clears the cell grid, moves all the allocated cells to
|
||||
/// the free list, and deletes excess free cells.
|
||||
void _freeCells();
|
||||
|
||||
/// Clears the cell grid and deletes all the free cells.
|
||||
void _deleteCells();
|
||||
|
||||
/// Returns a cell to the free list.
|
||||
void _recycleCell( GroundCoverCell* cell );
|
||||
|
||||
/// Generates a new cell using the recycle list when possible.
|
||||
GroundCoverCell* _generateCell( const Point2I& index,
|
||||
const Box3F& bounds,
|
||||
U32 placementCount,
|
||||
S32 randSeed );
|
||||
|
||||
void _debugRender( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat );
|
||||
};
|
||||
|
||||
#endif // _GROUNDCOVER_H_
|
||||
1248
Engine/source/T3D/fx/lightning.cpp
Normal file
1248
Engine/source/T3D/fx/lightning.cpp
Normal file
File diff suppressed because it is too large
Load diff
241
Engine/source/T3D/fx/lightning.h
Normal file
241
Engine/source/T3D/fx/lightning.h
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _LIGHTNING_H_
|
||||
#define _LIGHTNING_H_
|
||||
|
||||
#ifndef _GAMEBASE_H_
|
||||
#include "T3D/gameBase/gameBase.h"
|
||||
#endif
|
||||
#ifndef _TORQUE_LIST_
|
||||
#include "core/util/tList.h"
|
||||
#endif
|
||||
#ifndef _COLOR_H_
|
||||
#include "core/color.h"
|
||||
#endif
|
||||
#ifndef _RENDERPASSMANAGER_H_
|
||||
#include "renderInstance/renderPassManager.h"
|
||||
#endif
|
||||
#ifndef _ENGINEAPI_H_
|
||||
#include "console/engineAPI.h"
|
||||
#endif
|
||||
|
||||
#include "gfx/gfxTextureHandle.h"
|
||||
|
||||
|
||||
|
||||
class ShapeBase;
|
||||
class LightningStrikeEvent;
|
||||
class SFXTrack;
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
class LightningData : public GameBaseData
|
||||
{
|
||||
typedef GameBaseData Parent;
|
||||
|
||||
public:
|
||||
enum Constants {
|
||||
MaxThunders = 8,
|
||||
MaxTextures = 8
|
||||
};
|
||||
|
||||
//-------------------------------------- Console set variables
|
||||
public:
|
||||
SFXTrack* thunderSounds[MaxThunders];
|
||||
SFXTrack* strikeSound;
|
||||
StringTableEntry strikeTextureNames[MaxTextures];
|
||||
|
||||
//-------------------------------------- load set variables
|
||||
public:
|
||||
|
||||
GFXTexHandle strikeTextures[MaxTextures];
|
||||
U32 numThunders;
|
||||
|
||||
protected:
|
||||
bool onAdd();
|
||||
|
||||
public:
|
||||
LightningData();
|
||||
~LightningData();
|
||||
|
||||
void packData(BitStream*);
|
||||
void unpackData(BitStream*);
|
||||
bool preload(bool server, String &errorStr);
|
||||
|
||||
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;
|
||||
|
||||
typedef Torque::List<LightningBolt> LightingBoltList;
|
||||
LightingBoltList 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, SceneManager* 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, bool reload );
|
||||
|
||||
DECLARE_CALLBACK( void, applyDamage, ( const Point3F& hitPosition, const Point3F& hitNormal, SceneObject* hitObject ));
|
||||
|
||||
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;
|
||||
|
||||
GFXStateBlockRef mLightningSB;
|
||||
|
||||
protected:
|
||||
|
||||
// Rendering
|
||||
void prepRenderImage(SceneRenderState *state);
|
||||
void renderObject(ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance* );
|
||||
|
||||
// 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 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
|
||||
|
||||
633
Engine/source/T3D/fx/particle.cpp
Normal file
633
Engine/source/T3D/fx/particle.cpp
Normal file
|
|
@ -0,0 +1,633 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "particle.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "core/stream/bitStream.h"
|
||||
#include "math/mRandom.h"
|
||||
#include "math/mathIO.h"
|
||||
#include "console/engineAPI.h"
|
||||
|
||||
IMPLEMENT_CO_DATABLOCK_V1( ParticleData );
|
||||
|
||||
ConsoleDocClass( ParticleData,
|
||||
"@brief Contains information for how specific particles should look and react "
|
||||
"including particle colors, particle imagemap, acceleration value for individual "
|
||||
"particles and spin information.\n"
|
||||
|
||||
"@tsexample\n"
|
||||
"datablock ParticleData( GLWaterExpSmoke )\n"
|
||||
"{\n"
|
||||
" textureName = \"art/shapes/particles/smoke\";\n"
|
||||
" dragCoefficient = 0.4;\n"
|
||||
" gravityCoefficient = -0.25;\n"
|
||||
" inheritedVelFactor = 0.025;\n"
|
||||
" constantAcceleration = -1.1;\n"
|
||||
" lifetimeMS = 1250;\n"
|
||||
" lifetimeVarianceMS = 0;\n"
|
||||
" useInvAlpha = false;\n"
|
||||
" spinSpeed = 1;\n"
|
||||
" spinRandomMin = -200.0;\n"
|
||||
" spinRandomMax = 200.0;\n\n"
|
||||
" colors[0] = \"0.1 0.1 1.0 1.0\";\n"
|
||||
" colors[1] = \"0.4 0.4 1.0 1.0\";\n"
|
||||
" colors[2] = \"0.4 0.4 1.0 0.0\";\n\n"
|
||||
" sizes[0] = 2.0;\n"
|
||||
" sizes[1] = 6.0;\n"
|
||||
" sizes[2] = 2.0;\n\n"
|
||||
" times[0] = 0.0;\n"
|
||||
" times[1] = 0.5;\n"
|
||||
" times[2] = 1.0;\n"
|
||||
"};\n"
|
||||
"@endtsexample\n"
|
||||
|
||||
"@ingroup FX\n"
|
||||
"@see ParticleEmitter\n"
|
||||
"@see ParticleEmitterData\n"
|
||||
"@see ParticleEmitterNode\n"
|
||||
);
|
||||
|
||||
static const float sgDefaultWindCoefficient = 0.0f;
|
||||
static const float sgDefaultConstantAcceleration = 0.f;
|
||||
static const float sgDefaultSpinSpeed = 1.f;
|
||||
static const float sgDefaultSpinRandomMin = 0.f;
|
||||
static const float sgDefaultSpinRandomMax = 0.f;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
ParticleData::ParticleData()
|
||||
{
|
||||
dragCoefficient = 0.0f;
|
||||
windCoefficient = sgDefaultWindCoefficient;
|
||||
gravityCoefficient = 0.0f;
|
||||
inheritedVelFactor = 0.0f;
|
||||
constantAcceleration = sgDefaultConstantAcceleration;
|
||||
lifetimeMS = 1000;
|
||||
lifetimeVarianceMS = 0;
|
||||
spinSpeed = sgDefaultSpinSpeed;
|
||||
spinRandomMin = sgDefaultSpinRandomMin;
|
||||
spinRandomMax = sgDefaultSpinRandomMax;
|
||||
useInvAlpha = false;
|
||||
animateTexture = false;
|
||||
|
||||
numFrames = 1;
|
||||
framesPerSec = numFrames;
|
||||
|
||||
S32 i;
|
||||
for( i=0; i<PDC_NUM_KEYS; i++ )
|
||||
{
|
||||
colors[i].set( 1.0, 1.0, 1.0, 1.0 );
|
||||
sizes[i] = 1.0;
|
||||
}
|
||||
|
||||
times[0] = 0.0f;
|
||||
times[1] = 0.33f;
|
||||
times[2] = 0.66f;
|
||||
times[3] = 1.0f;
|
||||
|
||||
texCoords[0].set(0.0,0.0); // texture coords at 4 corners
|
||||
texCoords[1].set(0.0,1.0); // of particle quad
|
||||
texCoords[2].set(1.0,1.0); // (defaults to entire particle)
|
||||
texCoords[3].set(1.0,0.0);
|
||||
animTexTiling.set(0,0); // tiling dimensions
|
||||
animTexFramesString = NULL; // string of animation frame indices
|
||||
animTexUVs = NULL; // array of tile vertex UVs
|
||||
textureName = NULL; // texture filename
|
||||
textureHandle = NULL; // loaded texture handle
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
ParticleData::~ParticleData()
|
||||
{
|
||||
if (animTexUVs)
|
||||
{
|
||||
delete [] animTexUVs;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// initPersistFields
|
||||
//-----------------------------------------------------------------------------
|
||||
void ParticleData::initPersistFields()
|
||||
{
|
||||
addField( "dragCoefficient", TYPEID< F32 >(), Offset(dragCoefficient, ParticleData),
|
||||
"Particle physics drag amount." );
|
||||
addField( "windCoefficient", TYPEID< F32 >(), Offset(windCoefficient, ParticleData),
|
||||
"Strength of wind on the particles." );
|
||||
addField( "gravityCoefficient", TYPEID< F32 >(), Offset(gravityCoefficient, ParticleData),
|
||||
"Strength of gravity on the particles." );
|
||||
addField( "inheritedVelFactor", TYPEID< F32 >(), Offset(inheritedVelFactor, ParticleData),
|
||||
"Amount of emitter velocity to add to particle initial velocity." );
|
||||
addField( "constantAcceleration", TYPEID< F32 >(), Offset(constantAcceleration, ParticleData),
|
||||
"Constant acceleration to apply to this particle." );
|
||||
addField( "lifetimeMS", TYPEID< S32 >(), Offset(lifetimeMS, ParticleData),
|
||||
"Time in milliseconds before this particle is destroyed." );
|
||||
addField( "lifetimeVarianceMS", TYPEID< S32 >(), Offset(lifetimeVarianceMS, ParticleData),
|
||||
"Variance in lifetime of particle, from 0 - lifetimeMS." );
|
||||
addField( "spinSpeed", TYPEID< F32 >(), Offset(spinSpeed, ParticleData),
|
||||
"Speed at which to spin the particle." );
|
||||
addField( "spinRandomMin", TYPEID< F32 >(), Offset(spinRandomMin, ParticleData),
|
||||
"Minimum allowed spin speed of this particle, between -10000 and spinRandomMax." );
|
||||
addField( "spinRandomMax", TYPEID< F32 >(), Offset(spinRandomMax, ParticleData),
|
||||
"Maximum allowed spin speed of this particle, between spinRandomMin and 10000." );
|
||||
addField( "useInvAlpha", TYPEID< bool >(), Offset(useInvAlpha, ParticleData),
|
||||
"@brief Controls how particles blend with the scene.\n\n"
|
||||
"If true, particles blend like ParticleBlendStyle NORMAL, if false, "
|
||||
"blend like ParticleBlendStyle ADDITIVE.\n"
|
||||
"@note If ParticleEmitterData::blendStyle is set, it will override this value." );
|
||||
addField( "animateTexture", TYPEID< bool >(), Offset(animateTexture, ParticleData),
|
||||
"If true, allow the particle texture to be an animated sprite." );
|
||||
addField( "framesPerSec", TYPEID< S32 >(), Offset(framesPerSec, ParticleData),
|
||||
"If animateTexture is true, this defines the frames per second of the "
|
||||
"sprite animation." );
|
||||
|
||||
addField( "textureCoords", TYPEID< Point2F >(), Offset(texCoords, ParticleData), 4,
|
||||
"@brief 4 element array defining the UV coords into textureName to use "
|
||||
"for this particle.\n\n"
|
||||
"Coords should be set for the first tile only when using animTexTiling; "
|
||||
"coordinates for other tiles will be calculated automatically. \"0 0\" is "
|
||||
"top left and \"1 1\" is bottom right." );
|
||||
addField( "animTexTiling", TYPEID< Point2I >(), Offset(animTexTiling, ParticleData),
|
||||
"@brief The number of frames, in rows and columns stored in textureName "
|
||||
"(when animateTexture is true).\n\n"
|
||||
"A maximum of 256 frames can be stored in a single texture when using "
|
||||
"animTexTiling. Value should be \"NumColumns NumRows\", for example \"4 4\"." );
|
||||
addField( "animTexFrames", TYPEID< StringTableEntry >(), Offset(animTexFramesString,ParticleData),
|
||||
"@brief A list of frames and/or frame ranges to use for particle "
|
||||
"animation if animateTexture is true.\n\n"
|
||||
"Each frame token must be separated by whitespace. A frame token must be "
|
||||
"a positive integer frame number or a range of frame numbers separated "
|
||||
"with a '-'. The range separator, '-', cannot have any whitspace around "
|
||||
"it.\n\n"
|
||||
"Ranges can be specified to move through the frames in reverse as well "
|
||||
"as forward (eg. 19-14). Frame numbers exceeding the number of tiles will "
|
||||
"wrap.\n"
|
||||
"@tsexample\n"
|
||||
"animTexFrames = \"0-16 20 19 18 17 31-21\";\n"
|
||||
"@endtsexample\n" );
|
||||
|
||||
addField( "textureName", TYPEID< StringTableEntry >(), Offset(textureName, ParticleData),
|
||||
"Texture file to use for this particle." );
|
||||
addField( "animTexName", TYPEID< StringTableEntry >(), Offset(textureName, ParticleData),
|
||||
"@brief Texture file to use for this particle if animateTexture is true.\n\n"
|
||||
"Deprecated. Use textureName instead." );
|
||||
|
||||
// Interpolation variables
|
||||
addField( "colors", TYPEID< ColorF >(), Offset(colors, ParticleData), PDC_NUM_KEYS,
|
||||
"@brief Particle RGBA color keyframe values.\n\n"
|
||||
"The particle color will linearly interpolate between the color/time keys "
|
||||
"over the lifetime of the particle." );
|
||||
addField( "sizes", TYPEID< F32 >(), Offset(sizes, ParticleData), PDC_NUM_KEYS,
|
||||
"@brief Particle size keyframe values.\n\n"
|
||||
"The particle size will linearly interpolate between the size/time keys "
|
||||
"over the lifetime of the particle." );
|
||||
addProtectedField( "times", TYPEID< F32 >(), Offset(times, ParticleData), &protectedSetTimes,
|
||||
&defaultProtectedGetFn, PDC_NUM_KEYS,
|
||||
"@brief Time keys used with the colors and sizes keyframes.\n\n"
|
||||
"Values are from 0.0 (particle creation) to 1.0 (end of lifespace)." );
|
||||
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Pack data
|
||||
//-----------------------------------------------------------------------------
|
||||
void ParticleData::packData(BitStream* stream)
|
||||
{
|
||||
Parent::packData(stream);
|
||||
|
||||
stream->writeFloat(dragCoefficient / 5, 10);
|
||||
if( stream->writeFlag(windCoefficient != sgDefaultWindCoefficient ) )
|
||||
stream->write(windCoefficient);
|
||||
if (stream->writeFlag(gravityCoefficient != 0.0f))
|
||||
stream->writeSignedFloat(gravityCoefficient / 10, 12);
|
||||
stream->writeFloat(inheritedVelFactor, 9);
|
||||
if( stream->writeFlag( constantAcceleration != sgDefaultConstantAcceleration ) )
|
||||
stream->write(constantAcceleration);
|
||||
|
||||
stream->write( lifetimeMS );
|
||||
stream->write( lifetimeVarianceMS );
|
||||
|
||||
if( stream->writeFlag( spinSpeed != sgDefaultSpinSpeed ) )
|
||||
stream->write(spinSpeed);
|
||||
if(stream->writeFlag(spinRandomMin != sgDefaultSpinRandomMin || spinRandomMax != sgDefaultSpinRandomMax))
|
||||
{
|
||||
stream->writeInt((S32)(spinRandomMin + 1000), 11);
|
||||
stream->writeInt((S32)(spinRandomMax + 1000), 11);
|
||||
}
|
||||
stream->writeFlag(useInvAlpha);
|
||||
|
||||
S32 i, count;
|
||||
|
||||
// see how many frames there are:
|
||||
for(count = 0; count < 3; count++)
|
||||
if(times[count] >= 1)
|
||||
break;
|
||||
|
||||
count++;
|
||||
|
||||
stream->writeInt(count-1, 2);
|
||||
|
||||
for( i=0; i<count; i++ )
|
||||
{
|
||||
stream->writeFloat( colors[i].red, 7);
|
||||
stream->writeFloat( colors[i].green, 7);
|
||||
stream->writeFloat( colors[i].blue, 7);
|
||||
stream->writeFloat( colors[i].alpha, 7);
|
||||
stream->writeFloat( sizes[i]/MaxParticleSize, 14);
|
||||
stream->writeFloat( times[i], 8);
|
||||
}
|
||||
|
||||
if (stream->writeFlag(textureName && textureName[0]))
|
||||
stream->writeString(textureName);
|
||||
for (i = 0; i < 4; i++)
|
||||
mathWrite(*stream, texCoords[i]);
|
||||
if (stream->writeFlag(animateTexture))
|
||||
{
|
||||
if (stream->writeFlag(animTexFramesString && animTexFramesString[0]))
|
||||
{
|
||||
stream->writeString(animTexFramesString);
|
||||
}
|
||||
mathWrite(*stream, animTexTiling);
|
||||
stream->writeInt(framesPerSec, 8);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Unpack data
|
||||
//-----------------------------------------------------------------------------
|
||||
void ParticleData::unpackData(BitStream* stream)
|
||||
{
|
||||
Parent::unpackData(stream);
|
||||
|
||||
dragCoefficient = stream->readFloat(10) * 5;
|
||||
if(stream->readFlag())
|
||||
stream->read(&windCoefficient);
|
||||
else
|
||||
windCoefficient = sgDefaultWindCoefficient;
|
||||
if (stream->readFlag())
|
||||
gravityCoefficient = stream->readSignedFloat(12)*10;
|
||||
else
|
||||
gravityCoefficient = 0.0f;
|
||||
inheritedVelFactor = stream->readFloat(9);
|
||||
if(stream->readFlag())
|
||||
stream->read(&constantAcceleration);
|
||||
else
|
||||
constantAcceleration = sgDefaultConstantAcceleration;
|
||||
|
||||
stream->read( &lifetimeMS );
|
||||
stream->read( &lifetimeVarianceMS );
|
||||
|
||||
if(stream->readFlag())
|
||||
stream->read(&spinSpeed);
|
||||
else
|
||||
spinSpeed = sgDefaultSpinSpeed;
|
||||
|
||||
if(stream->readFlag())
|
||||
{
|
||||
spinRandomMin = (F32)(stream->readInt(11) - 1000);
|
||||
spinRandomMax = (F32)(stream->readInt(11) - 1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
spinRandomMin = sgDefaultSpinRandomMin;
|
||||
spinRandomMax = sgDefaultSpinRandomMax;
|
||||
}
|
||||
|
||||
useInvAlpha = stream->readFlag();
|
||||
|
||||
S32 i;
|
||||
S32 count = stream->readInt(2) + 1;
|
||||
for(i = 0;i < count; i++)
|
||||
{
|
||||
colors[i].red = stream->readFloat(7);
|
||||
colors[i].green = stream->readFloat(7);
|
||||
colors[i].blue = stream->readFloat(7);
|
||||
colors[i].alpha = stream->readFloat(7);
|
||||
sizes[i] = stream->readFloat(14) * MaxParticleSize;
|
||||
times[i] = stream->readFloat(8);
|
||||
}
|
||||
textureName = (stream->readFlag()) ? stream->readSTString() : 0;
|
||||
for (i = 0; i < 4; i++)
|
||||
mathRead(*stream, &texCoords[i]);
|
||||
|
||||
animateTexture = stream->readFlag();
|
||||
if (animateTexture)
|
||||
{
|
||||
animTexFramesString = (stream->readFlag()) ? stream->readSTString() : 0;
|
||||
mathRead(*stream, &animTexTiling);
|
||||
framesPerSec = stream->readInt(8);
|
||||
}
|
||||
}
|
||||
|
||||
bool ParticleData::protectedSetTimes( void *object, const char *index, const char *data)
|
||||
{
|
||||
ParticleData *pData = static_cast<ParticleData*>( object );
|
||||
F32 val = dAtof(data);
|
||||
U32 i;
|
||||
|
||||
if (!index)
|
||||
i = 0;
|
||||
else
|
||||
i = dAtoui(index);
|
||||
|
||||
pData->times[i] = mClampF( val, 0.f, 1.f );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// onAdd
|
||||
//-----------------------------------------------------------------------------
|
||||
bool ParticleData::onAdd()
|
||||
{
|
||||
if (Parent::onAdd() == false)
|
||||
return false;
|
||||
|
||||
if (dragCoefficient < 0.0) {
|
||||
Con::warnf(ConsoleLogEntry::General, "ParticleData(%s) drag coeff less than 0", getName());
|
||||
dragCoefficient = 0.0f;
|
||||
}
|
||||
if (lifetimeMS < 1) {
|
||||
Con::warnf(ConsoleLogEntry::General, "ParticleData(%s) lifetime < 1 ms", getName());
|
||||
lifetimeMS = 1;
|
||||
}
|
||||
if (lifetimeVarianceMS >= lifetimeMS) {
|
||||
Con::warnf(ConsoleLogEntry::General, "ParticleData(%s) lifetimeVariance >= lifetime", getName());
|
||||
lifetimeVarianceMS = lifetimeMS - 1;
|
||||
}
|
||||
if (spinSpeed > 10000.0 || spinSpeed < -10000.0) {
|
||||
Con::warnf(ConsoleLogEntry::General, "ParticleData(%s) spinSpeed invalid", getName());
|
||||
return false;
|
||||
}
|
||||
if (spinRandomMin > 10000.0 || spinRandomMin < -10000.0) {
|
||||
Con::warnf(ConsoleLogEntry::General, "ParticleData(%s) spinRandomMin invalid", getName());
|
||||
spinRandomMin = -360.0;
|
||||
return false;
|
||||
}
|
||||
if (spinRandomMin > spinRandomMax) {
|
||||
Con::warnf(ConsoleLogEntry::General, "ParticleData(%s) spinRandomMin greater than spinRandomMax", getName());
|
||||
spinRandomMin = spinRandomMax - (spinRandomMin - spinRandomMax );
|
||||
return false;
|
||||
}
|
||||
if (spinRandomMax > 10000.0 || spinRandomMax < -10000.0) {
|
||||
Con::warnf(ConsoleLogEntry::General, "ParticleData(%s) spinRandomMax invalid", getName());
|
||||
spinRandomMax = 360.0;
|
||||
return false;
|
||||
}
|
||||
if (framesPerSec > 255)
|
||||
{
|
||||
Con::warnf(ConsoleLogEntry::General, "ParticleData(%s) framesPerSec > 255, too high", getName());
|
||||
framesPerSec = 255;
|
||||
return false;
|
||||
}
|
||||
|
||||
times[0] = 0.0f;
|
||||
for (U32 i = 1; i < 4; i++) {
|
||||
if (times[i] < times[i-1]) {
|
||||
Con::warnf(ConsoleLogEntry::General, "ParticleData(%s) times[%d] < times[%d]", getName(), i, i-1);
|
||||
times[i] = times[i-1];
|
||||
}
|
||||
}
|
||||
|
||||
// Here we validate parameters
|
||||
if (animateTexture)
|
||||
{
|
||||
// Tiling dimensions must be positive and non-zero
|
||||
if (animTexTiling.x <= 0 || animTexTiling.y <= 0)
|
||||
{
|
||||
Con::warnf(ConsoleLogEntry::General,
|
||||
"ParticleData(%s) bad value(s) for animTexTiling [%d or %d <= 0], invalid datablock",
|
||||
animTexTiling.x, animTexTiling.y, getName());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Indices must fit into a byte so these are also bad
|
||||
if (animTexTiling.x * animTexTiling.y > 256)
|
||||
{
|
||||
Con::warnf(ConsoleLogEntry::General,
|
||||
"ParticleData(%s) bad values for animTexTiling [%d*%d > %d], invalid datablock",
|
||||
animTexTiling.x, animTexTiling.y, 256, getName());
|
||||
return false;
|
||||
}
|
||||
|
||||
// A list of frames is required
|
||||
if (!animTexFramesString || !animTexFramesString[0])
|
||||
{
|
||||
Con::warnf(ConsoleLogEntry::General, "ParticleData(%s) no animTexFrames, invalid datablock", getName());
|
||||
return false;
|
||||
}
|
||||
|
||||
// The frame list cannot be too long.
|
||||
if (animTexFramesString && dStrlen(animTexFramesString) > 255)
|
||||
{
|
||||
Con::errorf(ConsoleLogEntry::General, "ParticleData(%s) animTexFrames string too long [> 255 chars]", getName());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// preload
|
||||
//-----------------------------------------------------------------------------
|
||||
bool ParticleData::preload(bool server, String &errorStr)
|
||||
{
|
||||
if (Parent::preload(server, errorStr) == false)
|
||||
return false;
|
||||
|
||||
bool error = false;
|
||||
if(!server)
|
||||
{
|
||||
// Here we attempt to load the particle's texture if specified. An undefined
|
||||
// texture is *not* an error since the emitter may provide one.
|
||||
if (textureName && textureName[0])
|
||||
{
|
||||
textureHandle = GFXTexHandle(textureName, &GFXDefaultStaticDiffuseProfile, avar("%s() - textureHandle (line %d)", __FUNCTION__, __LINE__));
|
||||
if (!textureHandle)
|
||||
{
|
||||
errorStr = String::ToString("Missing particle texture: %s", textureName);
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (animateTexture)
|
||||
{
|
||||
// Here we parse animTexFramesString into byte-size frame numbers in animTexFrames.
|
||||
// Each frame token must be separated by whitespace.
|
||||
// A frame token must be a positive integer frame number or a range of frame numbers
|
||||
// separated with a '-'.
|
||||
// The range separator, '-', cannot have any whitspace around it.
|
||||
// Ranges can be specified to move through the frames in reverse as well as forward.
|
||||
// Frame numbers exceeding the number of tiles will wrap.
|
||||
// example:
|
||||
// "0-16 20 19 18 17 31-21"
|
||||
|
||||
S32 n_tiles = animTexTiling.x * animTexTiling.y;
|
||||
AssertFatal(n_tiles > 0 && n_tiles <= 256, "Error, bad animTexTiling setting." );
|
||||
|
||||
animTexFrames.clear();
|
||||
|
||||
char* tokCopy = new char[dStrlen(animTexFramesString) + 1];
|
||||
dStrcpy(tokCopy, animTexFramesString);
|
||||
|
||||
char* currTok = dStrtok(tokCopy, " \t");
|
||||
while (currTok != NULL)
|
||||
{
|
||||
char* minus = dStrchr(currTok, '-');
|
||||
if (minus)
|
||||
{
|
||||
// add a range of frames
|
||||
*minus = '\0';
|
||||
S32 range_a = dAtoi(currTok);
|
||||
S32 range_b = dAtoi(minus+1);
|
||||
if (range_b < range_a)
|
||||
{
|
||||
// reverse frame range
|
||||
for (S32 i = range_a; i >= range_b; i--)
|
||||
animTexFrames.push_back((U8)(i % n_tiles));
|
||||
}
|
||||
else
|
||||
{
|
||||
// forward frame range
|
||||
for (S32 i = range_a; i <= range_b; i++)
|
||||
animTexFrames.push_back((U8)(i % n_tiles));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// add one frame
|
||||
animTexFrames.push_back((U8)(dAtoi(currTok) % n_tiles));
|
||||
}
|
||||
currTok = dStrtok(NULL, " \t");
|
||||
}
|
||||
|
||||
// Here we pre-calculate the UVs for each frame tile, which are
|
||||
// tiled inside the UV region specified by texCoords. Since the
|
||||
// UVs are calculated using bilinear interpolation, the texCoords
|
||||
// region does *not* have to be an axis-aligned rectangle.
|
||||
|
||||
if (animTexUVs)
|
||||
delete [] animTexUVs;
|
||||
|
||||
animTexUVs = new Point2F[(animTexTiling.x+1)*(animTexTiling.y+1)];
|
||||
|
||||
// interpolate points on the left and right edge of the uv quadrangle
|
||||
Point2F lf_pt = texCoords[0];
|
||||
Point2F rt_pt = texCoords[3];
|
||||
|
||||
// per-row delta for left and right interpolated points
|
||||
Point2F lf_d = (texCoords[1] - texCoords[0])/(F32)animTexTiling.y;
|
||||
Point2F rt_d = (texCoords[2] - texCoords[3])/(F32)animTexTiling.y;
|
||||
|
||||
S32 idx = 0;
|
||||
for (S32 yy = 0; yy <= animTexTiling.y; yy++)
|
||||
{
|
||||
Point2F p = lf_pt;
|
||||
Point2F dp = (rt_pt - lf_pt)/(F32)animTexTiling.x;
|
||||
for (S32 xx = 0; xx <= animTexTiling.x; xx++)
|
||||
{
|
||||
animTexUVs[idx++] = p;
|
||||
p += dp;
|
||||
}
|
||||
lf_pt += lf_d;
|
||||
rt_pt += rt_d;
|
||||
}
|
||||
|
||||
// cleanup
|
||||
delete [] tokCopy;
|
||||
numFrames = animTexFrames.size();
|
||||
}
|
||||
}
|
||||
|
||||
return !error;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Initialize particle
|
||||
//-----------------------------------------------------------------------------
|
||||
void ParticleData::initializeParticle(Particle* init, const Point3F& inheritVelocity)
|
||||
{
|
||||
init->dataBlock = this;
|
||||
|
||||
// Calculate the constant accleration...
|
||||
init->vel += inheritVelocity * inheritedVelFactor;
|
||||
init->acc = init->vel * constantAcceleration;
|
||||
|
||||
// Calculate this instance's lifetime...
|
||||
init->totalLifetime = lifetimeMS;
|
||||
if (lifetimeVarianceMS != 0)
|
||||
init->totalLifetime += S32(gRandGen.randI() % (2 * lifetimeVarianceMS + 1)) - S32(lifetimeVarianceMS);
|
||||
|
||||
// assign spin amount
|
||||
init->spinSpeed = spinSpeed * gRandGen.randF( spinRandomMin, spinRandomMax );
|
||||
}
|
||||
|
||||
bool ParticleData::reload(char errorBuffer[256])
|
||||
{
|
||||
bool error = false;
|
||||
if (textureName && textureName[0])
|
||||
{
|
||||
textureHandle = GFXTexHandle(textureName, &GFXDefaultStaticDiffuseProfile, avar("%s() - textureHandle (line %d)", __FUNCTION__, __LINE__));
|
||||
if (!textureHandle)
|
||||
{
|
||||
dSprintf(errorBuffer, 256, "Missing particle texture: %s", textureName);
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
/*
|
||||
numFrames = 0;
|
||||
for( int i=0; i<PDC_MAX_TEX; i++ )
|
||||
{
|
||||
if( textureNameList[i] && textureNameList[i][0] )
|
||||
{
|
||||
textureList[i] = TextureHandle( textureNameList[i], MeshTexture );
|
||||
if (!textureList[i].getName())
|
||||
{
|
||||
dSprintf(errorBuffer, 256, "Missing particle texture: %s", textureNameList[i]);
|
||||
error = true;
|
||||
}
|
||||
numFrames++;
|
||||
}
|
||||
}
|
||||
*/
|
||||
return !error;
|
||||
}
|
||||
|
||||
DefineEngineMethod(ParticleData, reload, void, (),,
|
||||
"Reloads this particle.\n"
|
||||
"@tsexample\n"
|
||||
"// Get the editor's current particle\n"
|
||||
"%particle = PE_ParticleEditor.currParticle\n\n"
|
||||
"// Change a particle value\n"
|
||||
"%particle.setFieldValue( %propertyField, %value );\n\n"
|
||||
"// Reload it\n"
|
||||
"%particle.reload();\n"
|
||||
"@endtsexample\n" )
|
||||
{
|
||||
char errorBuffer[256];
|
||||
object->reload(errorBuffer);
|
||||
}
|
||||
128
Engine/source/T3D/fx/particle.h
Normal file
128
Engine/source/T3D/fx/particle.h
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _PARTICLE_H_
|
||||
#define _PARTICLE_H_
|
||||
|
||||
#ifndef _GAMEBASE_H_
|
||||
#include "T3D/gameBase/gameBase.h"
|
||||
#endif
|
||||
#ifndef _GFXTEXTUREHANDLE_H_
|
||||
#include "gfx/gfxTextureHandle.h"
|
||||
#endif
|
||||
|
||||
#define MaxParticleSize 50.0
|
||||
|
||||
struct Particle;
|
||||
|
||||
//*****************************************************************************
|
||||
// Particle Data
|
||||
//*****************************************************************************
|
||||
class ParticleData : public SimDataBlock
|
||||
{
|
||||
typedef SimDataBlock Parent;
|
||||
|
||||
public:
|
||||
enum PDConst
|
||||
{
|
||||
PDC_NUM_KEYS = 4,
|
||||
};
|
||||
|
||||
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 animateTexture;
|
||||
U32 numFrames;
|
||||
U32 framesPerSec;
|
||||
|
||||
ColorF colors[ PDC_NUM_KEYS ];
|
||||
F32 sizes[ PDC_NUM_KEYS ];
|
||||
F32 times[ PDC_NUM_KEYS ];
|
||||
|
||||
Point2F* animTexUVs;
|
||||
Point2F texCoords[4]; // default: {{0.0,0.0}, {0.0,1.0}, {1.0,1.0}, {1.0,0.0}}
|
||||
Point2I animTexTiling;
|
||||
StringTableEntry animTexFramesString;
|
||||
Vector<U8> animTexFrames;
|
||||
StringTableEntry textureName;
|
||||
GFXTexHandle textureHandle;
|
||||
|
||||
static bool protectedSetTimes( void *object, const char *index, const char *data );
|
||||
|
||||
public:
|
||||
ParticleData();
|
||||
~ParticleData();
|
||||
|
||||
// move this procedure to Particle
|
||||
void initializeParticle(Particle*, const Point3F&);
|
||||
|
||||
void packData(BitStream* stream);
|
||||
void unpackData(BitStream* stream);
|
||||
bool onAdd();
|
||||
bool preload(bool server, String &errorStr);
|
||||
DECLARE_CONOBJECT(ParticleData);
|
||||
static void initPersistFields();
|
||||
|
||||
bool reload(char errorBuffer[256]);
|
||||
};
|
||||
|
||||
//*****************************************************************************
|
||||
// Particle
|
||||
//
|
||||
// This structure should be as small as possible.
|
||||
//*****************************************************************************
|
||||
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
|
||||
U32 currentAge;
|
||||
|
||||
|
||||
// are these necessary to store here? - they are interpolated in real time
|
||||
ColorF color;
|
||||
F32 size;
|
||||
|
||||
F32 spinSpeed;
|
||||
Particle * next;
|
||||
};
|
||||
|
||||
|
||||
#endif // _PARTICLE_H_
|
||||
2006
Engine/source/T3D/fx/particleEmitter.cpp
Normal file
2006
Engine/source/T3D/fx/particleEmitter.cpp
Normal file
File diff suppressed because it is too large
Load diff
287
Engine/source/T3D/fx/particleEmitter.h
Normal file
287
Engine/source/T3D/fx/particleEmitter.h
Normal file
|
|
@ -0,0 +1,287 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _H_PARTICLE_EMITTER
|
||||
#define _H_PARTICLE_EMITTER
|
||||
|
||||
#ifndef _GAMEBASE_H_
|
||||
#include "T3D/gameBase/gameBase.h"
|
||||
#endif
|
||||
#ifndef _COLOR_H_
|
||||
#include "core/color.h"
|
||||
#endif
|
||||
#ifndef _GFXPRIMITIVEBUFFER_H_
|
||||
#include "gfx/gfxPrimitiveBuffer.h"
|
||||
#endif
|
||||
#ifndef _GFXVERTEXBUFFER_H_
|
||||
#include "gfx/gfxVertexBuffer.h"
|
||||
#endif
|
||||
#ifndef _PARTICLE_H_
|
||||
#include "T3D/fx/particle.h"
|
||||
#endif
|
||||
|
||||
#if defined(TORQUE_OS_XENON)
|
||||
#include "gfx/D3D9/360/gfx360MemVertexBuffer.h"
|
||||
#endif
|
||||
|
||||
class RenderPassManager;
|
||||
class ParticleData;
|
||||
|
||||
//*****************************************************************************
|
||||
// Particle Emitter Data
|
||||
//*****************************************************************************
|
||||
class ParticleEmitterData : public GameBaseData
|
||||
{
|
||||
typedef GameBaseData Parent;
|
||||
|
||||
static bool _setAlignDirection( void *object, const char *index, const char *data );
|
||||
|
||||
public:
|
||||
|
||||
ParticleEmitterData();
|
||||
DECLARE_CONOBJECT(ParticleEmitterData);
|
||||
static void initPersistFields();
|
||||
void packData(BitStream* stream);
|
||||
void unpackData(BitStream* stream);
|
||||
bool preload(bool server, String &errorStr);
|
||||
bool onAdd();
|
||||
void allocPrimBuffer( S32 overrideSize = -1 );
|
||||
|
||||
public:
|
||||
S32 ejectionPeriodMS; ///< Time, in Milliseconds, 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
|
||||
|
||||
F32 softnessDistance; ///< For soft particles, the distance (in meters) where particles will be faded
|
||||
///< based on the difference in depth between the particle and the scene geometry.
|
||||
|
||||
/// A scalar value used to influence the effect
|
||||
/// of the ambient color on the particle.
|
||||
F32 ambientFactor;
|
||||
|
||||
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
|
||||
bool alignParticles; ///< Particles always face along a particular axis
|
||||
Point3F alignDirection; ///< The direction aligned particles should face
|
||||
|
||||
StringTableEntry particleString; ///< Used to load particle data directly from a string
|
||||
|
||||
Vector<ParticleData*> particleDataBlocks; ///< Particle Datablocks
|
||||
Vector<U32> dataBlockIds; ///< Datablock IDs (parellel array to particleDataBlocks)
|
||||
|
||||
U32 partListInitSize; /// initial size of particle list calc'd from datablock info
|
||||
|
||||
GFXPrimitiveBufferHandle primBuff;
|
||||
|
||||
S32 blendStyle; ///< Pre-define blend factor setting
|
||||
bool sortParticles; ///< Particles are sorted back-to-front
|
||||
bool reverseOrder; ///< reverses draw order
|
||||
StringTableEntry textureName; ///< Emitter texture file to override particle textures
|
||||
GFXTexHandle textureHandle; ///< Emitter texture handle from txrName
|
||||
bool highResOnly; ///< This particle system should not use the mixed-resolution particle rendering
|
||||
bool renderReflection; ///< Enables this emitter to render into reflection passes.
|
||||
|
||||
bool reload();
|
||||
};
|
||||
|
||||
//*****************************************************************************
|
||||
// Particle Emitter
|
||||
//*****************************************************************************
|
||||
class ParticleEmitter : public GameBase
|
||||
{
|
||||
typedef GameBase Parent;
|
||||
|
||||
public:
|
||||
|
||||
#if defined(TORQUE_OS_XENON)
|
||||
typedef GFXVertexPCTT ParticleVertexType;
|
||||
#else
|
||||
typedef GFXVertexPCT ParticleVertexType;
|
||||
#endif
|
||||
|
||||
ParticleEmitter();
|
||||
~ParticleEmitter();
|
||||
|
||||
DECLARE_CONOBJECT(ParticleEmitter);
|
||||
|
||||
static Point3F mWindVelocity;
|
||||
static void setWindVelocity( const Point3F &vel ){ mWindVelocity = vel; }
|
||||
|
||||
ColorF getCollectiveColor();
|
||||
|
||||
/// 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, bool reload );
|
||||
|
||||
/// 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);
|
||||
/// @}
|
||||
|
||||
bool mDead;
|
||||
|
||||
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);
|
||||
|
||||
|
||||
inline void setupBillboard( Particle *part,
|
||||
Point3F *basePts,
|
||||
const MatrixF &camView,
|
||||
const ColorF &ambientColor,
|
||||
ParticleVertexType *lVerts );
|
||||
|
||||
inline void setupOriented( Particle *part,
|
||||
const Point3F &camPos,
|
||||
const ColorF &ambientColor,
|
||||
ParticleVertexType *lVerts );
|
||||
|
||||
inline void setupAligned( const Particle *part,
|
||||
const ColorF &ambientColor,
|
||||
ParticleVertexType *lVerts );
|
||||
|
||||
/// Updates the bounding box for the particle system
|
||||
void updateBBox();
|
||||
|
||||
/// @}
|
||||
protected:
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
|
||||
void processTick(const Move *move);
|
||||
void advanceTime(F32 dt);
|
||||
|
||||
// Rendering
|
||||
protected:
|
||||
void prepRenderImage( SceneRenderState *state );
|
||||
void copyToVB( const Point3F &camPos, const ColorF &ambientColor );
|
||||
|
||||
// PEngine interface
|
||||
private:
|
||||
|
||||
void update( U32 ms );
|
||||
inline void updateKeyData( Particle *part );
|
||||
|
||||
|
||||
private:
|
||||
|
||||
/// Constant used to calculate particle
|
||||
/// rotation from spin and age.
|
||||
static const F32 AgedSpinToRadians;
|
||||
|
||||
ParticleEmitterData* mDataBlock;
|
||||
|
||||
U32 mInternalClock;
|
||||
|
||||
U32 mNextParticleTime;
|
||||
|
||||
Point3F mLastPosition;
|
||||
bool mHasLastPosition;
|
||||
MatrixF mBBObjToWorld;
|
||||
|
||||
bool mDeleteWhenEmpty;
|
||||
bool mDeleteOnTick;
|
||||
|
||||
S32 mLifetimeMS;
|
||||
S32 mElapsedTimeMS;
|
||||
|
||||
F32 sizes[ ParticleData::PDC_NUM_KEYS ];
|
||||
ColorF colors[ ParticleData::PDC_NUM_KEYS ];
|
||||
|
||||
#if defined(TORQUE_OS_XENON)
|
||||
GFX360MemVertexBufferHandle<ParticleVertexType> mVertBuff;
|
||||
#else
|
||||
GFXVertexBufferHandle<ParticleVertexType> mVertBuff;
|
||||
#endif
|
||||
|
||||
// These members are for implementing a link-list of the active emitter
|
||||
// particles. Member part_store contains blocks of particles that can be
|
||||
// chained in a link-list. Usually the first part_store block is large
|
||||
// enough to contain all the particles but it can be expanded in emergency
|
||||
// circumstances.
|
||||
Vector <Particle*> part_store;
|
||||
Particle* part_freelist;
|
||||
Particle part_list_head;
|
||||
S32 n_part_capacity;
|
||||
S32 n_parts;
|
||||
S32 mCurBuffSize;
|
||||
|
||||
};
|
||||
|
||||
#endif // _H_PARTICLE_EMITTER
|
||||
|
||||
419
Engine/source/T3D/fx/particleEmitterNode.cpp
Normal file
419
Engine/source/T3D/fx/particleEmitterNode.cpp
Normal file
|
|
@ -0,0 +1,419 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "particleEmitterNode.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "core/stream/bitStream.h"
|
||||
#include "T3D/fx/particleEmitter.h"
|
||||
#include "math/mathIO.h"
|
||||
#include "sim/netConnection.h"
|
||||
#include "console/engineAPI.h"
|
||||
|
||||
IMPLEMENT_CO_DATABLOCK_V1(ParticleEmitterNodeData);
|
||||
IMPLEMENT_CO_NETOBJECT_V1(ParticleEmitterNode);
|
||||
|
||||
ConsoleDocClass( ParticleEmitterNodeData,
|
||||
"@brief Contains additional data to be associated with a ParticleEmitterNode."
|
||||
"@ingroup FX\n"
|
||||
);
|
||||
|
||||
ConsoleDocClass( ParticleEmitterNode,
|
||||
"@brief A particle emitter object that can be positioned in the world and "
|
||||
"dynamically enabled or disabled.\n\n"
|
||||
|
||||
"@tsexample\n"
|
||||
"datablock ParticleEmitterNodeData( SimpleEmitterNodeData )\n"
|
||||
"{\n"
|
||||
" timeMultiple = 1.0;\n"
|
||||
"};\n\n"
|
||||
|
||||
"%emitter = new ParticleEmitterNode()\n"
|
||||
"{\n"
|
||||
" datablock = SimpleEmitterNodeData;\n"
|
||||
" active = true;\n"
|
||||
" emitter = FireEmitterData;\n"
|
||||
" velocity = 3.5;\n"
|
||||
"};\n\n"
|
||||
|
||||
"// Dynamically change emitter datablock\n"
|
||||
"%emitter.setEmitterDataBlock( DustEmitterData );\n"
|
||||
"@endtsexample\n"
|
||||
|
||||
"@note To change the emitter field dynamically (after the ParticleEmitterNode "
|
||||
"object has been created) you must use the setEmitterDataBlock() method or the "
|
||||
"change will not be replicated to other clients in the game.\n"
|
||||
"Similarly, use the setActive() method instead of changing the active field "
|
||||
"directly. When changing velocity, you need to toggle setActive() on and off "
|
||||
"to force the state change to be transmitted to other clients.\n\n"
|
||||
|
||||
"@ingroup FX\n"
|
||||
"@see ParticleEmitterNodeData\n"
|
||||
"@see ParticleEmitterData\n"
|
||||
);
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ParticleEmitterNodeData
|
||||
//-----------------------------------------------------------------------------
|
||||
ParticleEmitterNodeData::ParticleEmitterNodeData()
|
||||
{
|
||||
timeMultiple = 1.0;
|
||||
}
|
||||
|
||||
ParticleEmitterNodeData::~ParticleEmitterNodeData()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// initPersistFields
|
||||
//-----------------------------------------------------------------------------
|
||||
void ParticleEmitterNodeData::initPersistFields()
|
||||
{
|
||||
addField( "timeMultiple", TYPEID< F32 >(), Offset(timeMultiple, ParticleEmitterNodeData),
|
||||
"@brief Time multiplier for particle emitter nodes.\n\n"
|
||||
"Increasing timeMultiple is like running the emitter at a faster rate - single-shot "
|
||||
"emitters will complete in a shorter time, and continuous emitters will generate "
|
||||
"particles more quickly.\n\n"
|
||||
"Valid range is 0.01 - 100." );
|
||||
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// onAdd
|
||||
//-----------------------------------------------------------------------------
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// preload
|
||||
//-----------------------------------------------------------------------------
|
||||
bool ParticleEmitterNodeData::preload(bool server, String &errorStr)
|
||||
{
|
||||
if( Parent::preload(server, errorStr) == false )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// packData
|
||||
//-----------------------------------------------------------------------------
|
||||
void ParticleEmitterNodeData::packData(BitStream* stream)
|
||||
{
|
||||
Parent::packData(stream);
|
||||
|
||||
stream->write(timeMultiple);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// unpackData
|
||||
//-----------------------------------------------------------------------------
|
||||
void ParticleEmitterNodeData::unpackData(BitStream* stream)
|
||||
{
|
||||
Parent::unpackData(stream);
|
||||
|
||||
stream->read(&timeMultiple);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ParticleEmitterNode
|
||||
//-----------------------------------------------------------------------------
|
||||
ParticleEmitterNode::ParticleEmitterNode()
|
||||
{
|
||||
// Todo: ScopeAlways?
|
||||
mNetFlags.set(Ghostable);
|
||||
mTypeMask |= EnvironmentObjectType;
|
||||
|
||||
mActive = true;
|
||||
|
||||
mDataBlock = NULL;
|
||||
mEmitterDatablock = NULL;
|
||||
mEmitterDatablockId = 0;
|
||||
mEmitter = NULL;
|
||||
mVelocity = 1.0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
ParticleEmitterNode::~ParticleEmitterNode()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// initPersistFields
|
||||
//-----------------------------------------------------------------------------
|
||||
void ParticleEmitterNode::initPersistFields()
|
||||
{
|
||||
addField( "active", TYPEID< bool >(), Offset(mActive,ParticleEmitterNode),
|
||||
"Controls whether particles are emitted from this node." );
|
||||
addField( "emitter", TYPEID< ParticleEmitterData >(), Offset(mEmitterDatablock, ParticleEmitterNode),
|
||||
"Datablock to use when emitting particles." );
|
||||
addField( "velocity", TYPEID< F32 >(), Offset(mVelocity, ParticleEmitterNode),
|
||||
"Velocity to use when emitting particles (in the direction of the "
|
||||
"ParticleEmitterNode object's up (Z) axis)." );
|
||||
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// onAdd
|
||||
//-----------------------------------------------------------------------------
|
||||
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( isClientObject() )
|
||||
{
|
||||
setEmitterDataBlock( mEmitterDatablock );
|
||||
}
|
||||
else
|
||||
{
|
||||
setMaskBits( StateMask | EmitterDBMask );
|
||||
}
|
||||
|
||||
mObjBox.minExtents.set(-0.5, -0.5, -0.5);
|
||||
mObjBox.maxExtents.set( 0.5, 0.5, 0.5);
|
||||
resetWorldBox();
|
||||
addToScene();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// onRemove
|
||||
//-----------------------------------------------------------------------------
|
||||
void ParticleEmitterNode::onRemove()
|
||||
{
|
||||
removeFromScene();
|
||||
if( isClientObject() )
|
||||
{
|
||||
if( mEmitter )
|
||||
{
|
||||
mEmitter->deleteWhenEmpty();
|
||||
mEmitter = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// onNewDataBlock
|
||||
//-----------------------------------------------------------------------------
|
||||
bool ParticleEmitterNode::onNewDataBlock( GameBaseData *dptr, bool reload )
|
||||
{
|
||||
mDataBlock = dynamic_cast<ParticleEmitterNodeData*>( dptr );
|
||||
if ( !mDataBlock || !Parent::onNewDataBlock( dptr, reload ) )
|
||||
return false;
|
||||
|
||||
// Todo: Uncomment if this is a "leaf" class
|
||||
scriptOnNewDataBlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ParticleEmitterNode::inspectPostApply()
|
||||
{
|
||||
Parent::inspectPostApply();
|
||||
setMaskBits(StateMask | EmitterDBMask);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// advanceTime
|
||||
//-----------------------------------------------------------------------------
|
||||
void ParticleEmitterNode::processTick(const Move* move)
|
||||
{
|
||||
Parent::processTick(move);
|
||||
|
||||
if ( isMounted() )
|
||||
{
|
||||
MatrixF mat;
|
||||
mMount.object->getMountTransform( mMount.node, mMount.xfm, &mat );
|
||||
setTransform( mat );
|
||||
}
|
||||
}
|
||||
|
||||
void ParticleEmitterNode::advanceTime(F32 dt)
|
||||
{
|
||||
Parent::advanceTime(dt);
|
||||
|
||||
if(!mActive || mEmitter.isNull() || !mDataBlock)
|
||||
return;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// packUpdate
|
||||
//-----------------------------------------------------------------------------
|
||||
U32 ParticleEmitterNode::packUpdate(NetConnection* con, U32 mask, BitStream* stream)
|
||||
{
|
||||
U32 retMask = Parent::packUpdate(con, mask, stream);
|
||||
|
||||
if ( stream->writeFlag( mask & InitialUpdateMask ) )
|
||||
{
|
||||
mathWrite(*stream, getTransform());
|
||||
mathWrite(*stream, getScale());
|
||||
}
|
||||
|
||||
if ( stream->writeFlag( mask & EmitterDBMask ) )
|
||||
{
|
||||
if( stream->writeFlag(mEmitterDatablock != NULL) )
|
||||
{
|
||||
stream->writeRangedU32(mEmitterDatablock->getId(), DataBlockObjectIdFirst,
|
||||
DataBlockObjectIdLast);
|
||||
}
|
||||
}
|
||||
|
||||
if ( stream->writeFlag( mask & StateMask ) )
|
||||
{
|
||||
stream->writeFlag( mActive );
|
||||
stream->write( mVelocity );
|
||||
}
|
||||
|
||||
return retMask;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// unpackUpdate
|
||||
//-----------------------------------------------------------------------------
|
||||
void ParticleEmitterNode::unpackUpdate(NetConnection* con, BitStream* stream)
|
||||
{
|
||||
Parent::unpackUpdate(con, stream);
|
||||
|
||||
if ( stream->readFlag() )
|
||||
{
|
||||
MatrixF temp;
|
||||
Point3F tempScale;
|
||||
mathRead(*stream, &temp);
|
||||
mathRead(*stream, &tempScale);
|
||||
|
||||
setScale(tempScale);
|
||||
setTransform(temp);
|
||||
}
|
||||
|
||||
if ( stream->readFlag() )
|
||||
{
|
||||
mEmitterDatablockId = stream->readFlag() ?
|
||||
stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast) : 0;
|
||||
|
||||
ParticleEmitterData *emitterDB = NULL;
|
||||
Sim::findObject( mEmitterDatablockId, emitterDB );
|
||||
if ( isProperlyAdded() )
|
||||
setEmitterDataBlock( emitterDB );
|
||||
}
|
||||
|
||||
if ( stream->readFlag() )
|
||||
{
|
||||
mActive = stream->readFlag();
|
||||
stream->read( &mVelocity );
|
||||
}
|
||||
}
|
||||
|
||||
void ParticleEmitterNode::setEmitterDataBlock(ParticleEmitterData* data)
|
||||
{
|
||||
if ( isServerObject() )
|
||||
{
|
||||
setMaskBits( EmitterDBMask );
|
||||
}
|
||||
else
|
||||
{
|
||||
ParticleEmitter* pEmitter = NULL;
|
||||
if ( data )
|
||||
{
|
||||
// Create emitter with new datablock
|
||||
pEmitter = new ParticleEmitter;
|
||||
pEmitter->onNewDataBlock( data, false );
|
||||
if( pEmitter->registerObject() == false )
|
||||
{
|
||||
Con::warnf(ConsoleLogEntry::General, "Could not register base emitter for particle of class: %s", data->getName() ? data->getName() : data->getIdString() );
|
||||
delete pEmitter;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Replace emitter
|
||||
if ( mEmitter )
|
||||
mEmitter->deleteWhenEmpty();
|
||||
|
||||
mEmitter = pEmitter;
|
||||
}
|
||||
|
||||
mEmitterDatablock = data;
|
||||
}
|
||||
|
||||
DefineEngineMethod(ParticleEmitterNode, setEmitterDataBlock, void, (ParticleEmitterData* emitterDatablock), (0),
|
||||
"Assigns the datablock for this emitter node.\n"
|
||||
"@param emitterDatablock ParticleEmitterData datablock to assign\n"
|
||||
"@tsexample\n"
|
||||
"// Assign a new emitter datablock\n"
|
||||
"%emitter.setEmitterDatablock( %emitterDatablock );\n"
|
||||
"@endtsexample\n" )
|
||||
{
|
||||
if ( !emitterDatablock )
|
||||
{
|
||||
Con::errorf("ParticleEmitterData datablock could not be found when calling setEmitterDataBlock in particleEmitterNode.");
|
||||
return;
|
||||
}
|
||||
|
||||
object->setEmitterDataBlock(emitterDatablock);
|
||||
}
|
||||
|
||||
DefineEngineMethod(ParticleEmitterNode, setActive, void, (bool active),,
|
||||
"Turns the emitter on or off.\n"
|
||||
"@param active New emitter state\n" )
|
||||
{
|
||||
object->setActive( active );
|
||||
}
|
||||
118
Engine/source/T3D/fx/particleEmitterNode.h
Normal file
118
Engine/source/T3D/fx/particleEmitterNode.h
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _PARTICLEEMITTERDUMMY_H_
|
||||
#define _PARTICLEEMITTERDUMMY_H_
|
||||
|
||||
#ifndef _GAMEBASE_H_
|
||||
#include "T3D/gameBase/gameBase.h"
|
||||
#endif
|
||||
|
||||
class ParticleEmitterData;
|
||||
class ParticleEmitter;
|
||||
|
||||
//*****************************************************************************
|
||||
// ParticleEmitterNodeData
|
||||
//*****************************************************************************
|
||||
class ParticleEmitterNodeData : public GameBaseData
|
||||
{
|
||||
typedef GameBaseData Parent;
|
||||
|
||||
protected:
|
||||
bool onAdd();
|
||||
|
||||
//-------------------------------------- Console set variables
|
||||
public:
|
||||
F32 timeMultiple;
|
||||
|
||||
//-------------------------------------- load set variables
|
||||
public:
|
||||
|
||||
public:
|
||||
ParticleEmitterNodeData();
|
||||
~ParticleEmitterNodeData();
|
||||
|
||||
void packData(BitStream*);
|
||||
void unpackData(BitStream*);
|
||||
bool preload(bool server, String &errorStr);
|
||||
|
||||
DECLARE_CONOBJECT(ParticleEmitterNodeData);
|
||||
static void initPersistFields();
|
||||
};
|
||||
|
||||
|
||||
//*****************************************************************************
|
||||
// ParticleEmitterNode
|
||||
//*****************************************************************************
|
||||
class ParticleEmitterNode : public GameBase
|
||||
{
|
||||
typedef GameBase Parent;
|
||||
|
||||
enum MaskBits
|
||||
{
|
||||
StateMask = Parent::NextFreeMask << 0,
|
||||
EmitterDBMask = Parent::NextFreeMask << 1,
|
||||
NextFreeMask = Parent::NextFreeMask << 2,
|
||||
};
|
||||
|
||||
private:
|
||||
ParticleEmitterNodeData* mDataBlock;
|
||||
|
||||
protected:
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
bool onNewDataBlock( GameBaseData *dptr, bool reload );
|
||||
void inspectPostApply();
|
||||
|
||||
ParticleEmitterData* mEmitterDatablock;
|
||||
S32 mEmitterDatablockId;
|
||||
|
||||
bool mActive;
|
||||
|
||||
SimObjectPtr<ParticleEmitter> mEmitter;
|
||||
F32 mVelocity;
|
||||
|
||||
public:
|
||||
ParticleEmitterNode();
|
||||
~ParticleEmitterNode();
|
||||
|
||||
ParticleEmitter *getParticleEmitter() {return mEmitter;}
|
||||
|
||||
// Time/Move Management
|
||||
public:
|
||||
void processTick(const Move* move);
|
||||
void advanceTime(F32 dt);
|
||||
|
||||
DECLARE_CONOBJECT(ParticleEmitterNode);
|
||||
static void initPersistFields();
|
||||
|
||||
U32 packUpdate (NetConnection *conn, U32 mask, BitStream* stream);
|
||||
void unpackUpdate(NetConnection *conn, BitStream* stream);
|
||||
|
||||
inline bool getActive( void ) { return mActive; };
|
||||
inline void setActive( bool active ) { mActive = active; setMaskBits( StateMask ); };
|
||||
|
||||
void setEmitterDataBlock(ParticleEmitterData* data);
|
||||
};
|
||||
|
||||
#endif // _H_PARTICLEEMISSIONDUMMY
|
||||
|
||||
1867
Engine/source/T3D/fx/precipitation.cpp
Normal file
1867
Engine/source/T3D/fx/precipitation.cpp
Normal file
File diff suppressed because it is too large
Load diff
287
Engine/source/T3D/fx/precipitation.h
Normal file
287
Engine/source/T3D/fx/precipitation.h
Normal file
|
|
@ -0,0 +1,287 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _PRECIPITATION_H_
|
||||
#define _PRECIPITATION_H_
|
||||
|
||||
#include "gfx/gfxDevice.h"
|
||||
#include "T3D/gameBase/gameBase.h"
|
||||
|
||||
#ifndef _GFXPRIMITIVEBUFFER_H_
|
||||
#include "gfx/gfxPrimitiveBuffer.h"
|
||||
#endif
|
||||
#ifndef _RENDERPASSMANAGER_H_
|
||||
#include "renderInstance/renderPassManager.h"
|
||||
#endif
|
||||
|
||||
class SFXTrack;
|
||||
class SFXSource;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/// Precipitation datablock.
|
||||
class PrecipitationData : public GameBaseData
|
||||
{
|
||||
typedef GameBaseData Parent;
|
||||
|
||||
public:
|
||||
SFXTrack* soundProfile;
|
||||
|
||||
StringTableEntry mDropName; ///< Texture filename for drop particles
|
||||
StringTableEntry mDropShaderName; ///< The name of the shader used for raindrops
|
||||
StringTableEntry mSplashName; ///< Texture filename for splash particles
|
||||
StringTableEntry mSplashShaderName; ///< The name of the shader used for raindrops
|
||||
|
||||
S32 mDropsPerSide; ///< How many drops are on a side of the raindrop texture.
|
||||
S32 mSplashesPerSide; ///< How many splash are on a side of the splash texture.
|
||||
|
||||
PrecipitationData();
|
||||
DECLARE_CONOBJECT(PrecipitationData);
|
||||
bool preload( bool server, String& errorStr );
|
||||
static void initPersistFields();
|
||||
virtual void packData(BitStream* stream);
|
||||
virtual void unpackData(BitStream* stream);
|
||||
};
|
||||
|
||||
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
|
||||
U32 hitType; ///< What kind of object the drop will hit
|
||||
|
||||
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
|
||||
|
||||
Raindrop* next; ///< linked list cruft
|
||||
|
||||
Raindrop()
|
||||
{
|
||||
velocity = 0;
|
||||
time = 0;
|
||||
mass = 1;
|
||||
texCoordIndex = 0;
|
||||
next = NULL;
|
||||
toRender = false;
|
||||
valid = true;
|
||||
nextSplashDrop = NULL;
|
||||
prevSplashDrop = NULL;
|
||||
animStartTime = 0;
|
||||
hitType = 0;
|
||||
hitPos = Point3F(0,0,0);
|
||||
}
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
class Precipitation : public GameBase
|
||||
{
|
||||
protected:
|
||||
|
||||
typedef GameBase Parent;
|
||||
PrecipitationData* mDataBlock;
|
||||
|
||||
Raindrop *mDropHead; ///< Drop linked list head
|
||||
Raindrop *mSplashHead; ///< Splash linked list head
|
||||
|
||||
Point2F* mTexCoords; ///< texture coords for rain texture
|
||||
Point2F* mSplashCoords; ///< texture coordinates for splash texture
|
||||
|
||||
SFXSource* mAmbientSound; ///< Ambient sound
|
||||
|
||||
GFXShaderRef mDropShader; ///< The shader used for raindrops
|
||||
GFXTexHandle mDropHandle; ///< Texture handle for raindrop
|
||||
GFXShaderRef mSplashShader; ///< The shader used for splashes
|
||||
GFXTexHandle mSplashHandle; ///< Texture handle for splash
|
||||
|
||||
U32 mLastRenderFrame; ///< Used to skip processTick when we haven't been visible.
|
||||
|
||||
U32 mDropHitMask; ///< Stores the current drop hit mask.
|
||||
|
||||
//console exposed variables
|
||||
bool mFollowCam; ///< Does the system follow the camera or stay where it's placed.
|
||||
|
||||
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
|
||||
bool mAnimateSplashes; ///< Animate the splashes using the frames in the texture.
|
||||
|
||||
S32 mDropAnimateMS; ///< If greater than zero, will animate the drops from
|
||||
///< the frames in the texture
|
||||
|
||||
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 mUseLighting; ///< This enables shading of the drops and splashes
|
||||
///< by the sun color.
|
||||
|
||||
ColorF mGlowIntensity; ///< Set it to 0 to disable the glow or use it to control
|
||||
///< the intensity of each channel.
|
||||
|
||||
bool mReflect; ///< This enables the precipitation to be rendered
|
||||
///< during reflection passes. This is expensive.
|
||||
|
||||
bool mUseWind; ///< This enables the wind from the sky SceneObject
|
||||
///< to effect the velocitiy of the drops.
|
||||
|
||||
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
|
||||
bool mDropHitPlayers; ///< Should drops collide with players
|
||||
bool mDropHitVehicles; ///< Should drops collide with vehicles
|
||||
|
||||
F32 mFadeDistance; ///< The distance at which fading of the particles begins.
|
||||
F32 mFadeDistanceEnd; ///< The distance at which fading of the particles ends.
|
||||
|
||||
U32 mMaxVBDrops; ///< The maximum drops allowed in one render batch.
|
||||
|
||||
GFXStateBlockRef mDefaultSB;
|
||||
GFXStateBlockRef mDistantSB;
|
||||
|
||||
GFXShaderConstBufferRef mDropShaderConsts;
|
||||
|
||||
GFXShaderConstHandle* mDropShaderModelViewSC;
|
||||
GFXShaderConstHandle* mDropShaderFadeStartEndSC;
|
||||
GFXShaderConstHandle* mDropShaderCameraPosSC;
|
||||
GFXShaderConstHandle* mDropShaderAmbientSC;
|
||||
|
||||
GFXShaderConstBufferRef mSplashShaderConsts;
|
||||
|
||||
GFXShaderConstHandle* mSplashShaderModelViewSC;
|
||||
GFXShaderConstHandle* mSplashShaderFadeStartEndSC;
|
||||
GFXShaderConstHandle* mSplashShaderCameraPosSC;
|
||||
GFXShaderConstHandle* mSplashShaderAmbientSC;
|
||||
|
||||
struct
|
||||
{
|
||||
bool valid;
|
||||
U32 startTime;
|
||||
U32 totalTime;
|
||||
F32 startPct;
|
||||
F32 endPct;
|
||||
|
||||
} mStormData;
|
||||
|
||||
struct
|
||||
{
|
||||
bool valid;
|
||||
U32 startTime;
|
||||
U32 totalTime;
|
||||
F32 startMax;
|
||||
F32 startSpeed;
|
||||
F32 endMax;
|
||||
F32 endSpeed;
|
||||
|
||||
} mTurbulenceData;
|
||||
|
||||
//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 initRenderObjects(); ///< Re-inits the texture coord lookup tables
|
||||
void initMaterials(); ///< Re-inits the textures and shaders
|
||||
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, const Box3F &box, const VectorF &windVel); ///< Casts a ray to see if/when a drop will collide
|
||||
void wrapDrop(Raindrop *drop, const Box3F &box, const U32 currTime, const VectorF &windVel); ///< 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
|
||||
|
||||
GFXPrimitiveBufferHandle mRainIB;
|
||||
GFXVertexBufferHandle<GFXVertexPT> mRainVB;
|
||||
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
|
||||
// Rendering
|
||||
void prepRenderImage( SceneRenderState* state );
|
||||
void renderObject(ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance* );
|
||||
|
||||
void setTransform(const MatrixF &mat);
|
||||
|
||||
public:
|
||||
|
||||
Precipitation();
|
||||
~Precipitation();
|
||||
void inspectPostApply();
|
||||
|
||||
enum
|
||||
{
|
||||
DataMask = Parent::NextFreeMask << 0,
|
||||
PercentageMask = Parent::NextFreeMask << 1,
|
||||
StormMask = Parent::NextFreeMask << 2,
|
||||
TransformMask = Parent::NextFreeMask << 3,
|
||||
TurbulenceMask = Parent::NextFreeMask << 4,
|
||||
NextFreeMask = Parent::NextFreeMask << 5
|
||||
};
|
||||
|
||||
bool onNewDataBlock( GameBaseData *dptr, bool reload );
|
||||
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);
|
||||
|
||||
/// This is used to smoothly change the turbulence
|
||||
/// over a desired time period. Setting ms to zero
|
||||
/// will cause the change to be instantaneous. Setting
|
||||
/// max zero will disable turbulence.
|
||||
void setTurbulence(F32 max, F32 speed, U32 ms);
|
||||
};
|
||||
|
||||
#endif // PRECIPITATION_H_
|
||||
|
||||
698
Engine/source/T3D/fx/splash.cpp
Normal file
698
Engine/source/T3D/fx/splash.cpp
Normal file
|
|
@ -0,0 +1,698 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "T3D/fx/splash.h"
|
||||
|
||||
#include "console/consoleTypes.h"
|
||||
#include "gfx/primBuilder.h"
|
||||
#include "gfx/gfxDrawUtil.h"
|
||||
#include "sfx/sfxSystem.h"
|
||||
#include "sfx/sfxProfile.h"
|
||||
#include "scene/sceneManager.h"
|
||||
#include "scene/sceneRenderState.h"
|
||||
#include "core/stream/bitStream.h"
|
||||
#include "math/mathIO.h"
|
||||
#include "T3D/fx/explosion.h"
|
||||
#include "T3D/fx/particle.h"
|
||||
#include "T3D/fx/particleEmitter.h"
|
||||
#include "T3D/fx/particleEmitterNode.h"
|
||||
#include "T3D/gameBase/gameProcess.h"
|
||||
#include "sim/netConnection.h"
|
||||
#include "renderInstance/renderPassManager.h"
|
||||
#include "console/engineAPI.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
MRandomLCG sgRandom(0xdeadbeef);
|
||||
|
||||
} // namespace {}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
IMPLEMENT_CO_DATABLOCK_V1(SplashData);
|
||||
IMPLEMENT_CO_NETOBJECT_V1(Splash);
|
||||
|
||||
ConsoleDocClass( SplashData,
|
||||
"@brief Acts as the physical point in space in white a Splash is created from.\n"
|
||||
"@ingroup FX\n"
|
||||
);
|
||||
|
||||
ConsoleDocClass( Splash,
|
||||
"@brief Manages the ring used for a Splash effect.\n"
|
||||
"@ingroup FX\n"
|
||||
);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// 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 );
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Init fields
|
||||
//--------------------------------------------------------------------------
|
||||
void SplashData::initPersistFields()
|
||||
{
|
||||
addField("soundProfile", TYPEID< SFXProfile >(), Offset(soundProfile, SplashData), "SFXProfile effect to play.\n");
|
||||
addField("scale", TypePoint3F, Offset(scale, SplashData), "The scale of this splashing effect, defined as the F32 points X, Y, Z.\n");
|
||||
addField("emitter", TYPEID< ParticleEmitterData >(), Offset(emitterList, SplashData), NUM_EMITTERS, "List of particle emitters to create at the point of this Splash effect.\n");
|
||||
addField("delayMS", TypeS32, Offset(delayMS, SplashData), "Time to delay, in milliseconds, before actually starting this effect.\n");
|
||||
addField("delayVariance", TypeS32, Offset(delayVariance, SplashData), "Time variance for delayMS.\n");
|
||||
addField("lifetimeMS", TypeS32, Offset(lifetimeMS, SplashData), "Lifetime for this effect, in milliseconds.\n");
|
||||
addField("lifetimeVariance", TypeS32, Offset(lifetimeVariance, SplashData), "Time variance for lifetimeMS.\n");
|
||||
addField("width", TypeF32, Offset(width, SplashData), "Width for the X and Y coordinates to create this effect within.");
|
||||
addField("numSegments", TypeS32, Offset(numSegments, SplashData), "Number of ejection points in the splash ring.\n");
|
||||
addField("velocity", TypeF32, Offset(velocity, SplashData), "Velocity for the splash effect to travel.\n");
|
||||
addField("height", TypeF32, Offset(height, SplashData), "Height for the splash to reach.\n");
|
||||
addField("acceleration", TypeF32, Offset(acceleration, SplashData), "Constant acceleration value to place upon the splash effect.\n");
|
||||
addField("times", TypeF32, Offset(times, SplashData), NUM_TIME_KEYS, "Times to transition through the splash effect. Up to 4 allowed. Values are 0.0 - 1.0, and corrispond to the life of the particle where 0 is first created and 1 is end of lifespace.\n" );
|
||||
addField("colors", TypeColorF, Offset(colors, SplashData), NUM_TIME_KEYS, "Color values to set the splash effect, rgba. Up to 4 allowed. Will transition through colors based on values set in the times value. Example: colors[0] = \"0.6 1.0 1.0 0.5\".\n" );
|
||||
addField("texture", TypeFilename, Offset(textureName, SplashData), NUM_TEX, "Imagemap file to use as the texture for the splash effect.\n");
|
||||
addField("texWrap", TypeF32, Offset(texWrap, SplashData), "Amount to wrap the texture around the splash ring, 0.0f - 1.0f.\n");
|
||||
addField("texFactor", TypeF32, Offset(texFactor, SplashData), "Factor in which to apply the texture to the splash ring, 0.0f - 1.0f.\n");
|
||||
addField("ejectionFreq", TypeF32, Offset(ejectionFreq, SplashData), "Frequency in which to emit splash rings.\n");
|
||||
addField("ejectionAngle", TypeF32, Offset(ejectionAngle, SplashData), "Rotational angle to create a splash ring.\n");
|
||||
addField("ringLifetime", TypeF32, Offset(ringLifetime, SplashData), "Lifetime, in milliseconds, for a splash ring.\n");
|
||||
addField("startRadius", TypeF32, Offset(startRadius, SplashData), "Starting radius size of a splash ring.\n");
|
||||
addField("explosion", TYPEID< ExplosionData >(), Offset(explosion, SplashData), "ExplosionData object to create at the creation position of this splash effect.\n");
|
||||
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// 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, String &errorStr)
|
||||
{
|
||||
if (Parent::preload(server, errorStr) == 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] = GFXTexHandle(textureName[i], &GFXDefaultStaticDiffuseProfile, avar("%s() - textureHandle[%d] (line %d)", __FUNCTION__, i, __LINE__) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 );
|
||||
|
||||
// Only allocated client side.
|
||||
mNetFlags.set( IsGhost );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// 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;
|
||||
|
||||
for( U32 i=0; i<SplashData::NUM_EMITTERS; i++ )
|
||||
{
|
||||
if( mDataBlock->emitterList[i] != NULL )
|
||||
{
|
||||
ParticleEmitter * pEmitter = new ParticleEmitter;
|
||||
pEmitter->onNewDataBlock( mDataBlock->emitterList[i], false );
|
||||
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.minExtents = Point3F( -1, -1, -1 );
|
||||
mObjBox.maxExtents = Point3F( 1, 1, 1 );
|
||||
resetWorldBox();
|
||||
|
||||
gClientSceneGraph->addObjectToScene(this);
|
||||
|
||||
removeFromProcessList();
|
||||
ClientProcessList::get()->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.clear();
|
||||
|
||||
getSceneManager()->removeObjectFromScene(this);
|
||||
getContainer()->removeObject(this);
|
||||
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// On New Data Block
|
||||
//--------------------------------------------------------------------------
|
||||
bool Splash::onNewDataBlock( GameBaseData *dptr, bool reload )
|
||||
{
|
||||
mDataBlock = dynamic_cast<SplashData*>(dptr);
|
||||
if (!mDataBlock || !Parent::onNewDataBlock(dptr, reload))
|
||||
return false;
|
||||
|
||||
scriptOnNewDataBlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// 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;
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Update color
|
||||
//----------------------------------------------------------------------------
|
||||
void Splash::updateColor()
|
||||
{
|
||||
for(SplashRingList::Iterator ring = ringList.begin(); ring != ringList.end(); ++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.pushBack( ring );
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Update rings
|
||||
//----------------------------------------------------------------------------
|
||||
void Splash::updateRings( F32 dt )
|
||||
{
|
||||
SplashRingList::Iterator ring;
|
||||
for(SplashRingList::Iterator i = ringList.begin(); i != ringList.end(); /*Trickiness*/)
|
||||
{
|
||||
ring = i++;
|
||||
ring->elapsedTime += dt;
|
||||
|
||||
if( !ring->isActive() )
|
||||
{
|
||||
ringList.erase( ring );
|
||||
}
|
||||
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.0f, 0.0f, -9.8f ) * 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, false);
|
||||
|
||||
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 );
|
||||
}
|
||||
}
|
||||
195
Engine/source/T3D/fx/splash.h
Normal file
195
Engine/source/T3D/fx/splash.h
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _SPLASH_H_
|
||||
#define _SPLASH_H_
|
||||
|
||||
#ifndef _GAMEBASE_H_
|
||||
#include "T3D/gameBase/gameBase.h"
|
||||
#endif
|
||||
|
||||
#ifndef _TORQUE_LIST_
|
||||
#include "core/util/tList.h"
|
||||
#endif
|
||||
|
||||
#include "gfx/gfxTextureHandle.h"
|
||||
|
||||
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];
|
||||
GFXTexHandle textureHandle[NUM_TEX];
|
||||
|
||||
ExplosionData* explosion;
|
||||
S32 explosionId;
|
||||
|
||||
SplashData();
|
||||
DECLARE_CONOBJECT(SplashData);
|
||||
bool onAdd();
|
||||
bool preload(bool server, String &errorStr);
|
||||
static void initPersistFields();
|
||||
virtual void packData(BitStream* stream);
|
||||
virtual void unpackData(BitStream* stream);
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Splash
|
||||
//--------------------------------------------------------------------------
|
||||
class Splash : public GameBase
|
||||
{
|
||||
typedef GameBase Parent;
|
||||
|
||||
private:
|
||||
SplashData* mDataBlock;
|
||||
|
||||
SimObjectPtr<ParticleEmitter> mEmitterList[ SplashData::NUM_EMITTERS ];
|
||||
|
||||
typedef Torque::List<SplashRing> SplashRingList;
|
||||
SplashRingList 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 spawnExplosion();
|
||||
|
||||
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, bool reload );
|
||||
DECLARE_CONOBJECT(Splash);
|
||||
};
|
||||
|
||||
|
||||
#endif // _H_SPLASH
|
||||
136
Engine/source/T3D/fx/windEmitter.cpp
Normal file
136
Engine/source/T3D/fx/windEmitter.cpp
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "T3D/fx/windEmitter.h"
|
||||
|
||||
#include "math/mBox.h"
|
||||
#include "core/tAlgorithm.h"
|
||||
#include "platform/profiler.h"
|
||||
|
||||
|
||||
Vector<WindEmitter*> WindEmitter::smAllEmitters;
|
||||
|
||||
|
||||
WindEmitter::WindEmitter()
|
||||
{
|
||||
smAllEmitters.push_back( this );
|
||||
|
||||
mEnabled = true;
|
||||
mScore = 0.0f;
|
||||
mSphere.center.zero();
|
||||
mSphere.radius = 0.0f;
|
||||
mStrength = 0.0f;
|
||||
mTurbulenceFrequency = 0.0f;
|
||||
mTurbulenceStrength = 0.0f;
|
||||
mVelocity.zero();
|
||||
}
|
||||
|
||||
WindEmitter::~WindEmitter()
|
||||
{
|
||||
WindEmitterList::iterator iter = find( smAllEmitters.begin(), smAllEmitters.end(), this );
|
||||
smAllEmitters.erase( iter );
|
||||
}
|
||||
|
||||
void WindEmitter::setPosition( const Point3F& pos )
|
||||
{
|
||||
mSphere.center = pos;
|
||||
}
|
||||
|
||||
void WindEmitter::update( const Point3F& pos, const VectorF& velocity )
|
||||
{
|
||||
mSphere.center = pos;
|
||||
mVelocity = velocity;
|
||||
}
|
||||
|
||||
void WindEmitter::setRadius( F32 radius )
|
||||
{
|
||||
mSphere.radius = radius;
|
||||
}
|
||||
|
||||
void WindEmitter::setStrength( F32 strength )
|
||||
{
|
||||
mStrength = strength;
|
||||
}
|
||||
|
||||
void WindEmitter::setTurbulency( F32 frequency, F32 strength )
|
||||
{
|
||||
mTurbulenceFrequency = frequency;
|
||||
mTurbulenceStrength = strength;
|
||||
}
|
||||
|
||||
S32 QSORT_CALLBACK WindEmitter::_sortByScore(const void* a, const void* b)
|
||||
{
|
||||
return mSign((*(WindEmitter**)b)->mScore - (*(WindEmitter**)a)->mScore);
|
||||
}
|
||||
|
||||
bool WindEmitter::findBest( const Point3F& cameraPos,
|
||||
const VectorF& cameraDir,
|
||||
F32 viewDistance,
|
||||
U32 maxResults,
|
||||
WindEmitterList* results )
|
||||
{
|
||||
PROFILE_START(WindEmitter_findBest);
|
||||
|
||||
// Build a sphere from the camera point.
|
||||
SphereF cameraSphere;
|
||||
cameraSphere.center = cameraPos;
|
||||
cameraSphere.radius = viewDistance;
|
||||
|
||||
// Collect the active spheres within the camera space and score them.
|
||||
WindEmitterList best;
|
||||
WindEmitterList::iterator iter = smAllEmitters.begin();
|
||||
for ( ; iter != smAllEmitters.end(); iter++ )
|
||||
{
|
||||
const SphereF& sphere = *(*iter);
|
||||
|
||||
// Skip any spheres outside of our camera range or that are disabled.
|
||||
if ( !(*iter)->mEnabled || !cameraSphere.isIntersecting( sphere ) )
|
||||
continue;
|
||||
|
||||
// Simple score calculation...
|
||||
//
|
||||
// score = ( radius / distance to camera ) * dot( cameraDir, vector from camera to sphere )
|
||||
//
|
||||
Point3F vect = sphere.center - cameraSphere.center;
|
||||
F32 dist = vect.len();
|
||||
(*iter)->mScore = dist * sphere.radius;
|
||||
vect /= getMax( dist, 0.001f );
|
||||
(*iter)->mScore *= mDot( vect, cameraDir );
|
||||
|
||||
best.push_back( *iter );
|
||||
}
|
||||
|
||||
// Sort the results by score!
|
||||
dQsort( best.address(), best.size(), sizeof(WindEmitter*), &WindEmitter::_sortByScore );
|
||||
|
||||
// Clip the results to the max requested.
|
||||
if ( best.size() > maxResults )
|
||||
best.setSize( maxResults );
|
||||
|
||||
// Merge the results and return.
|
||||
results->merge( best );
|
||||
|
||||
PROFILE_END(); // WindEmitter_findBest
|
||||
|
||||
return best.size() > 0;
|
||||
}
|
||||
96
Engine/source/T3D/fx/windEmitter.h
Normal file
96
Engine/source/T3D/fx/windEmitter.h
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _WINDEMITTER_H_
|
||||
#define _WINDEMITTER_H_
|
||||
|
||||
#ifndef _MPOINT3_H_
|
||||
#include "math/mPoint3.h"
|
||||
#endif
|
||||
#ifndef _MSPHERE_H_
|
||||
#include "math/mSphere.h"
|
||||
#endif
|
||||
#ifndef _TVECTOR_H_
|
||||
#include "core/util/tVector.h"
|
||||
#endif
|
||||
|
||||
class WindEmitter;
|
||||
|
||||
/// A vector of WindEmitter pointers.
|
||||
typedef Vector<WindEmitter*> WindEmitterList;
|
||||
|
||||
|
||||
class WindEmitter
|
||||
{
|
||||
public:
|
||||
WindEmitter();
|
||||
~WindEmitter();
|
||||
|
||||
operator const SphereF&() const { return mSphere; }
|
||||
|
||||
void update( const Point3F& pos, const VectorF& velocity );
|
||||
|
||||
void setPosition( const Point3F& pos );
|
||||
|
||||
void setRadius( F32 radius );
|
||||
|
||||
void setStrength( F32 strength );
|
||||
|
||||
void setTurbulency( F32 frequency, F32 strength );
|
||||
|
||||
const Point3F& getCenter() const { return mSphere.center; }
|
||||
|
||||
F32 getRadius() const { return mSphere.radius; }
|
||||
|
||||
F32 getStrength() const { return mStrength; }
|
||||
|
||||
F32 getTurbulenceFrequency() const { return mTurbulenceFrequency; }
|
||||
|
||||
F32 getTurbulenceStrength() const { return mTurbulenceStrength; }
|
||||
|
||||
const VectorF& getVelocity() const { return mVelocity; }
|
||||
|
||||
|
||||
static bool findBest( const Point3F& cameraPos,
|
||||
const VectorF& cameraDir,
|
||||
F32 viewDistance,
|
||||
U32 maxResults,
|
||||
WindEmitterList* results );
|
||||
|
||||
protected:
|
||||
SphereF mSphere;
|
||||
|
||||
VectorF mVelocity;
|
||||
|
||||
F32 mStrength;
|
||||
F32 mTurbulenceFrequency;
|
||||
F32 mTurbulenceStrength;
|
||||
F32 mScore;
|
||||
|
||||
bool mEnabled;
|
||||
|
||||
static WindEmitterList smAllEmitters;
|
||||
|
||||
static S32 QSORT_CALLBACK _sortByScore( const void* a, const void* b );
|
||||
};
|
||||
|
||||
#endif // _WINDEMITTER_H_
|
||||
Loading…
Add table
Add a link
Reference in a new issue