tge/engine/game/debris.cc
2025-02-17 23:17:30 -06:00

955 lines
29 KiB
C++
Executable File

//-----------------------------------------------------------------------------
// 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;
}