Initial commit
This commit is contained in:
954
Torque/SDK/engine/game/debris.cc
Normal file
954
Torque/SDK/engine/game/debris.cc
Normal file
@@ -0,0 +1,954 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "game/debris.h"
|
||||
#include "dgl/dgl.h"
|
||||
#include "core/bitStream.h"
|
||||
#include "math/mathUtils.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "console/consoleObject.h"
|
||||
#include "sim/netConnection.h"
|
||||
#include "sceneGraph/sceneState.h"
|
||||
#include "sceneGraph/sceneGraph.h"
|
||||
#include "sceneGraph/detailManager.h"
|
||||
#include "ts/tsShapeInstance.h"
|
||||
#include "ts/tsPartInstance.h"
|
||||
#include "game/fx/particleEngine.h"
|
||||
#include "game/fx/explosion.h"
|
||||
|
||||
const U32 csmStaticCollisionMask = TerrainObjectType |
|
||||
InteriorObjectType;
|
||||
|
||||
const U32 csmDynamicCollisionMask = StaticShapeObjectType;
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// Debris Data
|
||||
//**************************************************************************
|
||||
|
||||
IMPLEMENT_CO_DATABLOCK_V1(DebrisData);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Constructor
|
||||
//--------------------------------------------------------------------------
|
||||
DebrisData::DebrisData()
|
||||
{
|
||||
dMemset( emitterList, 0, sizeof( emitterList ) );
|
||||
dMemset( emitterIDList, 0, sizeof( emitterIDList ) );
|
||||
|
||||
explosion = NULL;
|
||||
explosionId = 0;
|
||||
|
||||
velocity = 0.0;
|
||||
velocityVariance = 0.0;
|
||||
elasticity = 0.3;
|
||||
friction = 0.2;
|
||||
numBounces = 0;
|
||||
bounceVariance = 0;
|
||||
minSpinSpeed = maxSpinSpeed = 0.0;
|
||||
render2D = false;
|
||||
staticOnMaxBounce = false;
|
||||
explodeOnMaxBounce = false;
|
||||
snapOnMaxBounce = false;
|
||||
lifetime = 3.0;
|
||||
lifetimeVariance = 0.0;
|
||||
minSpinSpeed = 0.0;
|
||||
maxSpinSpeed = 0.0;
|
||||
textureName = NULL;
|
||||
mTypeMask |= DebrisObjectType;
|
||||
shapeName = NULL;
|
||||
fade = true;
|
||||
useRadiusMass = false;
|
||||
baseRadius = 1.0;
|
||||
gravModifier = 1.0;
|
||||
terminalVelocity = 0.0;
|
||||
ignoreWater = true;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Initialize - Check data
|
||||
//--------------------------------------------------------------------------
|
||||
bool DebrisData::onAdd()
|
||||
{
|
||||
if(!Parent::onAdd())
|
||||
return false;
|
||||
|
||||
for( int i=0; i<DDC_NUM_EMITTERS; i++ )
|
||||
{
|
||||
if( !emitterList[i] && emitterIDList[i] != 0 )
|
||||
{
|
||||
if( Sim::findObject( emitterIDList[i], emitterList[i] ) == false)
|
||||
{
|
||||
Con::errorf( ConsoleLogEntry::General, "DebrisData::onAdd: Invalid packet, bad datablockId(emitter): 0x%x", emitterIDList[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!explosion && explosionId != 0)
|
||||
{
|
||||
if (!Sim::findObject( SimObjectId( explosionId ), explosion ))
|
||||
Con::errorf( ConsoleLogEntry::General, "DebrisData::onAdd: Invalid packet, bad datablockId(particle emitter): 0x%x", explosionId);
|
||||
}
|
||||
|
||||
if( textureName )
|
||||
{
|
||||
texture = TextureHandle( textureName, MeshTexture );
|
||||
}
|
||||
else
|
||||
{
|
||||
texture = TextureHandle(); // set default NULL tex
|
||||
}
|
||||
|
||||
|
||||
// validate data
|
||||
|
||||
if( velocityVariance > velocity )
|
||||
{
|
||||
Con::warnf(ConsoleLogEntry::General, "DebrisData(%s)::onAdd: velocityVariance invalid", getName());
|
||||
velocityVariance = velocity;
|
||||
}
|
||||
if( friction < -10.0 || friction > 10.0 )
|
||||
{
|
||||
Con::warnf(ConsoleLogEntry::General, "DebrisData(%s)::onAdd: friction invalid", getName());
|
||||
friction = 0.2;
|
||||
}
|
||||
if( elasticity < -10.0 || elasticity > 10.0 )
|
||||
{
|
||||
Con::warnf(ConsoleLogEntry::General, "DebrisData(%s)::onAdd: elasticity invalid", getName());
|
||||
elasticity = 0.2;
|
||||
}
|
||||
if( lifetime < 0.0 || lifetime > 1000.0 )
|
||||
{
|
||||
Con::warnf(ConsoleLogEntry::General, "DebrisData(%s)::onAdd: lifetime invalid", getName());
|
||||
lifetime = 3.0;
|
||||
}
|
||||
if( lifetimeVariance < 0.0 || lifetimeVariance > lifetime )
|
||||
{
|
||||
Con::warnf(ConsoleLogEntry::General, "DebrisData(%s)::onAdd: lifetimeVariance invalid", getName());
|
||||
lifetimeVariance = 0.0;
|
||||
}
|
||||
if( numBounces < 0 || numBounces > 10000 )
|
||||
{
|
||||
Con::warnf(ConsoleLogEntry::General, "DebrisData(%s)::onAdd: numBounces invalid", getName());
|
||||
numBounces = 3;
|
||||
}
|
||||
if( bounceVariance < 0 || bounceVariance > numBounces )
|
||||
{
|
||||
Con::warnf(ConsoleLogEntry::General, "DebrisData(%s)::onAdd: bounceVariance invalid", getName());
|
||||
bounceVariance = 0;
|
||||
}
|
||||
if( minSpinSpeed < -10000.0 || minSpinSpeed > 10000.0 || minSpinSpeed > maxSpinSpeed )
|
||||
{
|
||||
Con::warnf(ConsoleLogEntry::General, "DebrisData(%s)::onAdd: minSpinSpeed invalid", getName());
|
||||
minSpinSpeed = maxSpinSpeed - 1.0;
|
||||
}
|
||||
if( maxSpinSpeed < -10000.0 || maxSpinSpeed > 10000.0 )
|
||||
{
|
||||
Con::warnf(ConsoleLogEntry::General, "DebrisData(%s)::onAdd: maxSpinSpeed invalid", getName());
|
||||
maxSpinSpeed = 0.0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Preload
|
||||
//--------------------------------------------------------------------------
|
||||
bool DebrisData::preload(bool server, char errorBuffer[256])
|
||||
{
|
||||
if (Parent::preload(server, errorBuffer) == false)
|
||||
return false;
|
||||
|
||||
if( server )
|
||||
return true;
|
||||
|
||||
if( shapeName && shapeName[0] != '\0' && !bool(shape) )
|
||||
{
|
||||
shape = ResourceManager->load(shapeName);
|
||||
if( bool(shape) == false )
|
||||
{
|
||||
dSprintf(errorBuffer, sizeof(errorBuffer), "DebrisData::load: Couldn't load shape \"%s\"", shapeName);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
TSShapeInstance* pDummy = new TSShapeInstance(shape, !server);
|
||||
delete pDummy;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Initialize console fields (static)
|
||||
//--------------------------------------------------------------------------
|
||||
IMPLEMENT_CONSOLETYPE(DebrisData)
|
||||
IMPLEMENT_SETDATATYPE(DebrisData)
|
||||
IMPLEMENT_GETDATATYPE(DebrisData)
|
||||
|
||||
void DebrisData::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
|
||||
addGroup("Display");
|
||||
addField("texture", TypeFilename, Offset(textureName, DebrisData));
|
||||
addField("shapeFile", TypeFilename, Offset(shapeName, DebrisData));
|
||||
addField("render2D", TypeBool, Offset(render2D, DebrisData));
|
||||
endGroup("Display");
|
||||
|
||||
addGroup("Datablocks");
|
||||
addField("emitters", TypeParticleEmitterDataPtr, Offset(emitterList, DebrisData), DDC_NUM_EMITTERS);
|
||||
addField("explosion", TypeExplosionDataPtr, Offset(explosion, DebrisData));
|
||||
endGroup("Datablocks");
|
||||
|
||||
addGroup("Physical Properties");
|
||||
addField("elasticity", TypeF32, Offset(elasticity, DebrisData));
|
||||
addField("friction", TypeF32, Offset(friction, DebrisData));
|
||||
addField("numBounces", TypeS32, Offset(numBounces, DebrisData));
|
||||
addField("bounceVariance", TypeS32, Offset(bounceVariance, DebrisData));
|
||||
addField("minSpinSpeed", TypeF32, Offset(minSpinSpeed, DebrisData));
|
||||
addField("maxSpinSpeed", TypeF32, Offset(maxSpinSpeed, DebrisData));
|
||||
addField("gravModifier", TypeF32, Offset(gravModifier, DebrisData));
|
||||
addField("terminalVelocity", TypeF32, Offset(terminalVelocity, DebrisData));
|
||||
addField("velocity", TypeF32, Offset(velocity, DebrisData));
|
||||
addField("velocityVariance", TypeF32, Offset(velocityVariance, DebrisData));
|
||||
addField("lifetime", TypeF32, Offset(lifetime, DebrisData));
|
||||
addField("lifetimeVariance", TypeF32, Offset(lifetimeVariance, DebrisData));
|
||||
addField("useRadiusMass", TypeBool, Offset(useRadiusMass, DebrisData));
|
||||
addField("baseRadius", TypeF32, Offset(baseRadius, DebrisData));
|
||||
endGroup("Physical Properties");
|
||||
|
||||
addGroup("Behavior");
|
||||
addField("explodeOnMaxBounce", TypeBool, Offset(explodeOnMaxBounce, DebrisData));
|
||||
addField("staticOnMaxBounce", TypeBool, Offset(staticOnMaxBounce, DebrisData));
|
||||
addField("snapOnMaxBounce", TypeBool, Offset(snapOnMaxBounce, DebrisData));
|
||||
addField("fade", TypeBool, Offset(fade, DebrisData));
|
||||
addField("ignoreWater", TypeBool, Offset(ignoreWater, DebrisData));
|
||||
endGroup("Behavior");
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Pack data
|
||||
//--------------------------------------------------------------------------
|
||||
void DebrisData::packData(BitStream* stream)
|
||||
{
|
||||
Parent::packData(stream);
|
||||
|
||||
stream->write(elasticity);
|
||||
stream->write(friction);
|
||||
stream->write(numBounces);
|
||||
stream->write(bounceVariance);
|
||||
stream->write(minSpinSpeed);
|
||||
stream->write(maxSpinSpeed);
|
||||
stream->write(render2D);
|
||||
stream->write(explodeOnMaxBounce);
|
||||
stream->write(staticOnMaxBounce);
|
||||
stream->write(snapOnMaxBounce);
|
||||
stream->write(lifetime);
|
||||
stream->write(lifetimeVariance);
|
||||
stream->write(minSpinSpeed);
|
||||
stream->write(maxSpinSpeed);
|
||||
stream->write(velocity);
|
||||
stream->write(velocityVariance);
|
||||
stream->write(fade);
|
||||
stream->write(useRadiusMass);
|
||||
stream->write(baseRadius);
|
||||
stream->write(gravModifier);
|
||||
stream->write(terminalVelocity);
|
||||
stream->write(ignoreWater);
|
||||
|
||||
stream->writeString( textureName );
|
||||
stream->writeString( shapeName );
|
||||
|
||||
for( int i=0; i<DDC_NUM_EMITTERS; i++ )
|
||||
{
|
||||
if( stream->writeFlag( emitterList[i] != NULL ) )
|
||||
{
|
||||
stream->writeRangedU32( emitterList[i]->getId(), DataBlockObjectIdFirst, DataBlockObjectIdLast );
|
||||
}
|
||||
}
|
||||
|
||||
if( stream->writeFlag( explosion ) )
|
||||
{
|
||||
stream->writeRangedU32(packed? SimObjectId(explosion):
|
||||
explosion->getId(),DataBlockObjectIdFirst,DataBlockObjectIdLast);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Unpack data
|
||||
//--------------------------------------------------------------------------
|
||||
void DebrisData::unpackData(BitStream* stream)
|
||||
{
|
||||
Parent::unpackData(stream);
|
||||
|
||||
stream->read(&elasticity);
|
||||
stream->read(&friction);
|
||||
stream->read(&numBounces);
|
||||
stream->read(&bounceVariance);
|
||||
stream->read(&minSpinSpeed);
|
||||
stream->read(&maxSpinSpeed);
|
||||
stream->read(&render2D);
|
||||
stream->read(&explodeOnMaxBounce);
|
||||
stream->read(&staticOnMaxBounce);
|
||||
stream->read(&snapOnMaxBounce);
|
||||
stream->read(&lifetime);
|
||||
stream->read(&lifetimeVariance);
|
||||
stream->read(&minSpinSpeed);
|
||||
stream->read(&maxSpinSpeed);
|
||||
stream->read(&velocity);
|
||||
stream->read(&velocityVariance);
|
||||
stream->read(&fade);
|
||||
stream->read(&useRadiusMass);
|
||||
stream->read(&baseRadius);
|
||||
stream->read(&gravModifier);
|
||||
stream->read(&terminalVelocity);
|
||||
stream->read(&ignoreWater);
|
||||
|
||||
textureName = stream->readSTString();
|
||||
shapeName = stream->readSTString();
|
||||
|
||||
for( int i=0; i<DDC_NUM_EMITTERS; i++ )
|
||||
{
|
||||
if( stream->readFlag() )
|
||||
{
|
||||
emitterIDList[i] = stream->readRangedU32( DataBlockObjectIdFirst, DataBlockObjectIdLast );
|
||||
}
|
||||
}
|
||||
|
||||
if(stream->readFlag())
|
||||
{
|
||||
explosionId = (S32)stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
|
||||
}
|
||||
else
|
||||
{
|
||||
explosionId = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// Debris
|
||||
//**************************************************************************
|
||||
|
||||
IMPLEMENT_CO_NETOBJECT_V1(Debris);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Initialize debris piece
|
||||
//----------------------------------------------------------------------------
|
||||
ConsoleMethod( Debris, init, bool, 4, 4, "(Point3F position, Point3F velocity)"
|
||||
"Set this piece of debris at the given position with the given velocity.")
|
||||
{
|
||||
Point3F pos;
|
||||
dSscanf( argv[2], "%g %g %g", &pos.x, &pos.y, &pos.z );
|
||||
|
||||
Point3F vel;
|
||||
dSscanf( argv[3], "%g %g %g", &vel.x, &vel.y, &vel.z );
|
||||
|
||||
object->init( pos, vel );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Constructor
|
||||
//----------------------------------------------------------------------------
|
||||
Debris::Debris()
|
||||
{
|
||||
mTypeMask |= DebrisObjectType;
|
||||
|
||||
mVelocity = Point3F( 0.0, 0.0, 4.0 );
|
||||
mLifetime = gRandGen.randF( 1.0, 10.0 );
|
||||
mLastPos = getPosition();
|
||||
mNumBounces = gRandGen.randI( 0, 1 );
|
||||
mSize = 2.0;
|
||||
mElapsedTime = 0.0;
|
||||
mShape = NULL;
|
||||
mPart = NULL;
|
||||
mXRotSpeed = 0.0;
|
||||
mZRotSpeed = 0.0;
|
||||
mInitialTrans.identity();
|
||||
mRadius = 0.2;
|
||||
mStatic = false;
|
||||
|
||||
dMemset( mEmitterList, 0, sizeof( mEmitterList ) );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Destructor
|
||||
//----------------------------------------------------------------------------
|
||||
Debris::~Debris()
|
||||
{
|
||||
if( mShape )
|
||||
{
|
||||
delete mShape;
|
||||
mShape = NULL;
|
||||
}
|
||||
|
||||
if( mPart )
|
||||
{
|
||||
delete mPart;
|
||||
mPart = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Init class (static)
|
||||
//----------------------------------------------------------------------------
|
||||
void Debris::initPersistFields()
|
||||
{
|
||||
addGroup("Misc");
|
||||
addField("lifetime", TypeF32, Offset(mLifetime, Debris));
|
||||
endGroup("Misc");
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Init
|
||||
//----------------------------------------------------------------------------
|
||||
void Debris::init( const Point3F &position, const Point3F &velocity )
|
||||
{
|
||||
setPosition( position );
|
||||
setVelocity( velocity );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// On new data block
|
||||
//----------------------------------------------------------------------------
|
||||
bool Debris::onNewDataBlock( GameBaseData* dptr )
|
||||
{
|
||||
mDataBlock = dynamic_cast< DebrisData* >( dptr );
|
||||
if( !mDataBlock || !Parent::onNewDataBlock( dptr ) )
|
||||
return false;
|
||||
|
||||
scriptOnNewDataBlock();
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// On Add
|
||||
//----------------------------------------------------------------------------
|
||||
bool Debris::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;
|
||||
|
||||
F32 lifeVar = (mDataBlock->lifetimeVariance * 2.0f * gRandGen.randF(-1.0,1.0)) - mDataBlock->lifetimeVariance;
|
||||
mLifetime = mDataBlock->lifetime + lifeVar;
|
||||
|
||||
// create emitters
|
||||
for( int i=0; i<DebrisData::DDC_NUM_EMITTERS; i++ )
|
||||
{
|
||||
if( mDataBlock->emitterList[i] != NULL )
|
||||
{
|
||||
ParticleEmitter * pEmitter = new ParticleEmitter;
|
||||
pEmitter->onNewDataBlock( mDataBlock->emitterList[i] );
|
||||
if( !pEmitter->registerObject() )
|
||||
{
|
||||
Con::warnf( ConsoleLogEntry::General, "Could not register emitter for particle of class: %s", mDataBlock->getName() );
|
||||
delete pEmitter;
|
||||
pEmitter = NULL;
|
||||
}
|
||||
mEmitterList[i] = pEmitter;
|
||||
}
|
||||
}
|
||||
|
||||
// set particle sizes based on debris size
|
||||
F32 sizeList[ParticleEngine::PC_SIZE_KEYS];
|
||||
|
||||
if( mEmitterList[0] )
|
||||
{
|
||||
sizeList[0] = mSize * 0.5;
|
||||
sizeList[1] = mSize;
|
||||
sizeList[2] = mSize * 1.5;
|
||||
|
||||
mEmitterList[0]->setSizes( sizeList );
|
||||
}
|
||||
|
||||
if( mEmitterList[1] )
|
||||
{
|
||||
sizeList[0] = 0.0;
|
||||
sizeList[1] = mSize * 0.5;
|
||||
sizeList[2] = mSize;
|
||||
|
||||
mEmitterList[1]->setSizes( sizeList );
|
||||
}
|
||||
|
||||
S32 bounceVar = gRandGen.randI( -mDataBlock->bounceVariance, mDataBlock->bounceVariance );
|
||||
mNumBounces = mDataBlock->numBounces + bounceVar;
|
||||
|
||||
F32 xRotSpeed = gRandGen.randF( mDataBlock->minSpinSpeed, mDataBlock->maxSpinSpeed );
|
||||
F32 zRotSpeed = gRandGen.randF( mDataBlock->minSpinSpeed, mDataBlock->maxSpinSpeed );
|
||||
zRotSpeed *= gRandGen.randF( 0.1, 0.5 );
|
||||
|
||||
mRotAngles.set( xRotSpeed, 0.0, zRotSpeed );
|
||||
|
||||
mElasticity = mDataBlock->elasticity;
|
||||
mFriction = mDataBlock->friction;
|
||||
|
||||
// Setup our bounding box
|
||||
if( mDataBlock->shape )
|
||||
{
|
||||
mObjBox = mDataBlock->shape->bounds;
|
||||
}
|
||||
else
|
||||
{
|
||||
mObjBox = Box3F(Point3F(-1, -1, -1), Point3F(1, 1, 1));
|
||||
}
|
||||
|
||||
if( mDataBlock->shape )
|
||||
{
|
||||
mShape = new TSShapeInstance( mDataBlock->shape, true);
|
||||
}
|
||||
|
||||
if( mPart )
|
||||
{
|
||||
// use half radius becuase we want debris to stick in ground
|
||||
mRadius = mPart->getRadius() * 0.5;
|
||||
mObjBox = mPart->getBounds();
|
||||
}
|
||||
|
||||
resetWorldBox();
|
||||
|
||||
mInitialTrans = getTransform();
|
||||
|
||||
if( mDataBlock->velocity != 0.0 )
|
||||
{
|
||||
F32 velocity = mDataBlock->velocity + gRandGen.randF( -mDataBlock->velocityVariance, mDataBlock->velocityVariance );
|
||||
|
||||
mVelocity.normalizeSafe();
|
||||
mVelocity *= velocity;
|
||||
}
|
||||
|
||||
// mass calculations
|
||||
if( mDataBlock->useRadiusMass )
|
||||
{
|
||||
if( mRadius < mDataBlock->baseRadius )
|
||||
mRadius = mDataBlock->baseRadius;
|
||||
|
||||
// linear falloff
|
||||
F32 multFactor = mDataBlock->baseRadius / mRadius;
|
||||
|
||||
mElasticity *= multFactor;
|
||||
mFriction *= multFactor;
|
||||
mRotAngles *= multFactor;
|
||||
}
|
||||
|
||||
// tell engine the debris exists
|
||||
gClientContainer.addObject(this);
|
||||
gClientSceneGraph->addObjectToScene(this);
|
||||
|
||||
removeFromProcessList();
|
||||
gClientProcessList.addObject(this);
|
||||
|
||||
conn->addObject(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// On Remove
|
||||
//----------------------------------------------------------------------------
|
||||
void Debris::onRemove()
|
||||
{
|
||||
for( int i=0; i<DebrisData::DDC_NUM_EMITTERS; i++ )
|
||||
{
|
||||
if( mEmitterList[i] )
|
||||
{
|
||||
mEmitterList[i]->deleteWhenEmpty();
|
||||
mEmitterList[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if( mPart )
|
||||
{
|
||||
TSShapeInstance *ss = mPart->getSourceShapeInstance();
|
||||
if( ss )
|
||||
{
|
||||
ss->decDebrisRefCount();
|
||||
if( ss->getDebrisRefCount() == 0 )
|
||||
{
|
||||
delete ss;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mSceneManager->removeObjectFromScene(this);
|
||||
getContainer()->removeObject(this);
|
||||
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Process tick
|
||||
//----------------------------------------------------------------------------
|
||||
void Debris::processTick(const Move*)
|
||||
{
|
||||
// Update real position info.
|
||||
setTransform(getRenderTransform());
|
||||
|
||||
if (mLifetime <= 0.0)
|
||||
deleteObject();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Advance Time
|
||||
//----------------------------------------------------------------------------
|
||||
void Debris::advanceTime( F32 dt )
|
||||
{
|
||||
mElapsedTime += dt;
|
||||
|
||||
mLifetime -= dt;
|
||||
if( mLifetime <= 0.0 )
|
||||
{
|
||||
mLifetime = 0.0;
|
||||
return;
|
||||
}
|
||||
|
||||
mLastPos = getRenderPosition();
|
||||
|
||||
if( !mStatic )
|
||||
{
|
||||
rotate( dt );
|
||||
|
||||
Point3F nextPos = getRenderPosition();
|
||||
computeNewState( nextPos, mVelocity, dt );
|
||||
|
||||
if( bounce( nextPos, dt ) )
|
||||
{
|
||||
--mNumBounces;
|
||||
if( mNumBounces <= 0 )
|
||||
{
|
||||
if( mDataBlock->explodeOnMaxBounce )
|
||||
{
|
||||
explode();
|
||||
mLifetime = 0.0;
|
||||
}
|
||||
|
||||
if( mDataBlock->snapOnMaxBounce )
|
||||
{
|
||||
// orient debris so it's flat
|
||||
MatrixF stat = getRenderTransform();
|
||||
|
||||
Point3F dir;
|
||||
stat.getColumn( 1, &dir );
|
||||
dir.z = 0.0;
|
||||
|
||||
MatrixF newTrans = MathUtils::createOrientFromDir( dir );
|
||||
|
||||
// hack for shell casings to get them above ground. Need something better - bramage
|
||||
newTrans.setPosition( getPosition() + Point3F( 0.0, 0.0, 0.10 ) );
|
||||
|
||||
setRenderTransform( newTrans );
|
||||
}
|
||||
if( mDataBlock->staticOnMaxBounce )
|
||||
{
|
||||
mStatic = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MatrixF tmp = getRenderTransform();
|
||||
tmp.setPosition( nextPos );
|
||||
setRenderTransform(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
updateEmitters( (Point3F&)*getRenderPosition(), mVelocity, (U32)(dt * 1000.0));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Rotate debris
|
||||
//----------------------------------------------------------------------------
|
||||
void Debris::rotate( F32 dt )
|
||||
{
|
||||
MatrixF curTrans = getRenderTransform();
|
||||
curTrans.setPosition( Point3F(0.0, 0.0, 0.0) );
|
||||
|
||||
Point3F curAngles = mRotAngles * dt * M_PI/180.0;
|
||||
MatrixF rotMatrix( EulerF( curAngles.x, curAngles.y, curAngles.z ) );
|
||||
|
||||
curTrans.mul( rotMatrix );
|
||||
curTrans.setPosition( getRenderPosition() );
|
||||
setRenderTransform( curTrans );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Bounce the debris - returns true if debris bounces
|
||||
//----------------------------------------------------------------------------
|
||||
bool Debris::bounce( const Point3F &nextPos, F32 dt )
|
||||
{
|
||||
Point3F curPos = getRenderPosition();
|
||||
|
||||
Point3F dir = nextPos - curPos;
|
||||
if( dir.magnitudeSafe() == 0.0 )
|
||||
return false;
|
||||
|
||||
dir.normalizeSafe();
|
||||
|
||||
Point3F extent = nextPos + dir * mRadius;
|
||||
F32 totalDist = Point3F( extent - curPos ).magnitudeSafe();
|
||||
F32 moveDist = Point3F( nextPos - curPos ).magnitudeSafe();
|
||||
F32 movePercent = (moveDist / totalDist);
|
||||
|
||||
RayInfo rayInfo;
|
||||
U32 collisionMask = csmStaticCollisionMask;
|
||||
if( !mDataBlock->ignoreWater )
|
||||
collisionMask |= WaterObjectType;
|
||||
|
||||
if( getContainer()->castRay( curPos, extent, collisionMask, &rayInfo ) )
|
||||
{
|
||||
|
||||
Point3F reflection = mVelocity - rayInfo.normal * (mDot( mVelocity, rayInfo.normal ) * 2.0);
|
||||
mVelocity = reflection;
|
||||
|
||||
Point3F tangent = reflection - rayInfo.normal * mDot( reflection, rayInfo.normal );
|
||||
mVelocity -= tangent * mFriction;
|
||||
|
||||
Point3F velDir = mVelocity;
|
||||
velDir.normalizeSafe();
|
||||
|
||||
mVelocity *= mElasticity;
|
||||
|
||||
Point3F bouncePos = curPos + dir * rayInfo.t * movePercent;
|
||||
bouncePos += mVelocity * dt;
|
||||
|
||||
MatrixF tmp = getRenderTransform();
|
||||
tmp.setPosition( bouncePos );
|
||||
setRenderTransform(tmp);
|
||||
|
||||
mRotAngles *= mElasticity;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Explode
|
||||
//----------------------------------------------------------------------------
|
||||
void Debris::explode()
|
||||
{
|
||||
if( !mDataBlock->explosion )
|
||||
return;
|
||||
|
||||
const Point3F explosionPos = getRenderPosition();
|
||||
|
||||
Explosion* pExplosion = new Explosion;
|
||||
pExplosion->onNewDataBlock(mDataBlock->explosion);
|
||||
|
||||
MatrixF trans( true );
|
||||
trans.setPosition( explosionPos );
|
||||
|
||||
pExplosion->setTransform( trans );
|
||||
pExplosion->setInitialState( explosionPos, VectorF(0,0,1), 1);
|
||||
if (!pExplosion->registerObject())
|
||||
delete pExplosion;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Compute state of debris as if it hasn't collided with anything
|
||||
//----------------------------------------------------------------------------
|
||||
void Debris::computeNewState( Point3F &newPos, Point3F &newVel, F32 dt )
|
||||
{
|
||||
// apply gravity
|
||||
Point3F force = Point3F(0, 0, -9.81 * mDataBlock->gravModifier );
|
||||
|
||||
if( mDataBlock->terminalVelocity > 0.0001 && newVel.magnitudeSafe() > mDataBlock->terminalVelocity )
|
||||
{
|
||||
newVel.normalizeSafe();
|
||||
newVel *= mDataBlock->terminalVelocity;
|
||||
}
|
||||
else
|
||||
{
|
||||
newVel += force * dt;
|
||||
}
|
||||
|
||||
newPos += newVel * dt;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Update emitters
|
||||
//----------------------------------------------------------------------------
|
||||
void Debris::updateEmitters( Point3F &pos, Point3F &vel, U32 ms )
|
||||
{
|
||||
Point3F axis = -vel;
|
||||
Point3F lastPos = mLastPos;
|
||||
|
||||
if( axis.magnitudeSafe() == 0.0 )
|
||||
axis = Point3F( 0.0, 0.0, 1.0 );
|
||||
|
||||
axis.normalizeSafe();
|
||||
|
||||
for( int i=0; i<DebrisData::DDC_NUM_EMITTERS; i++ )
|
||||
{
|
||||
if( mEmitterList[i] )
|
||||
{
|
||||
mEmitterList[i]->emitParticles( lastPos, pos, axis, vel, ms );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Render debris
|
||||
//----------------------------------------------------------------------------
|
||||
bool Debris::prepRenderImage(SceneState* state, const U32 stateKey,
|
||||
const U32 /*startZone*/, const bool /*modifyBaseState*/)
|
||||
{
|
||||
if (isLastState(state, stateKey))
|
||||
return false;
|
||||
setLastState(state, stateKey);
|
||||
|
||||
// This should be sufficient for most objects that don't manage zones, and
|
||||
// don't need to return a specialized RenderImage...
|
||||
if( state->isObjectRendered(this) && (mPart || mShape) )
|
||||
{
|
||||
Point3F cameraOffset;
|
||||
mObjToWorld.getColumn(3,&cameraOffset);
|
||||
cameraOffset -= state->getCameraPosition();
|
||||
F32 dist = cameraOffset.len();
|
||||
F32 invScale = (1.0f/getMax(getMax(mObjScale.x,mObjScale.y),mObjScale.z));
|
||||
|
||||
if( mShape )
|
||||
{
|
||||
DetailManager::selectPotentialDetails(mShape,dist,invScale);
|
||||
if( mShape->getCurrentDetail() < 0 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if( mPart )
|
||||
{
|
||||
DetailManager::selectPotentialDetails(mPart,dist,invScale);
|
||||
}
|
||||
|
||||
SceneRenderImage* image = new SceneRenderImage;
|
||||
image->obj = this;
|
||||
image->isTranslucent = true;
|
||||
image->sortType = SceneRenderImage::Point;
|
||||
state->setImageRefPoint(this, image);
|
||||
|
||||
state->insertRenderImage(image);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Render Object
|
||||
//----------------------------------------------------------------------------
|
||||
void Debris::renderObject(SceneState* state, SceneRenderImage* )
|
||||
{
|
||||
AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on entry");
|
||||
|
||||
RectI viewport;
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
dglGetViewport(&viewport);
|
||||
|
||||
// Uncomment this if this is a "simple" (non-zone managing) object
|
||||
state->setupObjectProjection(this);
|
||||
|
||||
F32 alpha = 1.0;
|
||||
if( mDataBlock->fade && mLifetime < 1.0 )
|
||||
alpha = mLifetime;
|
||||
|
||||
if( (mShape && DetailManager::selectCurrentDetail(mShape)) ||
|
||||
(mPart && DetailManager::selectCurrentDetail(mPart)) )
|
||||
{
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
dglMultMatrix(&mObjToWorld);
|
||||
glScalef(mObjScale.x, mObjScale.y, mObjScale.z);
|
||||
|
||||
installLights();
|
||||
|
||||
Point3F cameraOffset;
|
||||
mObjToWorld.getColumn(3,&cameraOffset);
|
||||
cameraOffset -= state->getCameraPosition();
|
||||
F32 fogAmount = state->getHazeAndFog(cameraOffset.len(),cameraOffset.z);
|
||||
|
||||
if( mShape )
|
||||
{
|
||||
TSMesh::setOverrideFade( alpha );
|
||||
mShape->setupFog(fogAmount, state->getFogColor());
|
||||
mShape->render();
|
||||
TSMesh::setOverrideFade( 1.0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mPart->getCurrentObjectDetail() != -1)
|
||||
{
|
||||
TSShapeInstance *parent = mPart->getSourceShapeInstance();
|
||||
|
||||
parent->setupFog(fogAmount, state->getFogColor());
|
||||
TSMesh::setOverrideFade( alpha );
|
||||
mPart->render();
|
||||
TSMesh::setOverrideFade( 1.0 );
|
||||
}
|
||||
}
|
||||
|
||||
uninstallLights();
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
render2D();
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
dglSetViewport(viewport);
|
||||
|
||||
dglSetCanonicalState();
|
||||
AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on exit");
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Render 2D debris
|
||||
//----------------------------------------------------------------------------
|
||||
void Debris::render2D()
|
||||
{
|
||||
if( !mDataBlock->render2D )
|
||||
return;
|
||||
|
||||
glBindTexture( GL_TEXTURE_2D, mDataBlock->texture.getGLName() );
|
||||
glColor4f( 1.0, 1.0, 1.0, 1.0 );
|
||||
|
||||
glDisable(GL_CULL_FACE);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
dglDrawBillboard( getPosition(), 0.1, 0.0 );
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisable(GL_BLEND);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Set size
|
||||
//----------------------------------------------------------------------------
|
||||
void Debris::setSize( F32 size )
|
||||
{
|
||||
mSize = size;
|
||||
}
|
||||
Reference in New Issue
Block a user