1 //-----------------------------------------------------------------------------
2 // Copyright (c) 2012 GarageGames, LLC
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to
6 // deal in the Software without restriction, including without limitation the
7 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 // sell copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 //-----------------------------------------------------------------------------
23 #include "platform/platform.h"
24 #include "T3D/debris.h"
26 #include "core/stream/bitStream.h"
27 #include "math/mathUtils.h"
28 #include "console/consoleTypes.h"
29 #include "console/consoleObject.h"
30 #include "sim/netConnection.h"
31 #include "scene/sceneRenderState.h"
32 #include "scene/sceneManager.h"
33 #include "ts/tsShapeInstance.h"
34 #include "ts/tsPartInstance.h"
35 #include "T3D/fx/particleEmitter.h"
36 #include "T3D/fx/explosion.h"
37 #include "T3D/gameBase/gameProcess.h"
38 #include "core/resourceManager.h"
39 #include "gfx/gfxTransformSaver.h"
40 #include "console/engineAPI.h"
41 #include "lighting/lightQuery.h"
44 const U32 csmStaticCollisionMask
= TerrainObjectType
| StaticShapeObjectType
| StaticObjectType
;
46 IMPLEMENT_CO_DATABLOCK_V1(DebrisData
);
48 ConsoleDocClass( DebrisData
,
49 "@brief Stores properties for an individual debris type.\n\n"
51 "DebrisData defines the base properties for a Debris object. Typically you'll want a Debris object to consist of "
52 "a shape and possibly up to two particle emitters. The DebrisData datablock provides the definition for these items, "
53 "along with physical properties and how a Debris object will react to other game objects, such as water and terrain.\n"
56 "datablock DebrisData(GrenadeDebris)\n"
58 " shapeFile = \"art/shapes/weapons/ramrifle/debris.dts\";\n"
59 " emitters[0] = GrenadeDebrisFireEmitter;\n"
60 " elasticity = 0.4;\n"
63 " bounceVariance = 1;\n"
64 " explodeOnMaxBounce = false;\n"
65 " staticOnMaxBounce = false;\n"
66 " snapOnMaxBounce = false;\n"
67 " minSpinSpeed = 200;\n"
68 " maxSpinSpeed = 600;\n"
70 " lifetimeVariance = 1.5;\n"
72 " velocityVariance = 5;\n"
74 " useRadiusMass = true;\n"
75 " baseRadius = 0.3;\n"
76 " gravModifier = 1.0;\n"
77 " terminalVelocity = 20;\n"
78 " ignoreWater = false;\n"
85 DebrisData::DebrisData()
87 dMemset( emitterList
, 0, sizeof( emitterList
) );
88 dMemset( emitterIDList
, 0, sizeof( emitterIDList
) );
94 velocityVariance
= 0.0;
99 staticOnMaxBounce
= false;
100 explodeOnMaxBounce
= false;
101 snapOnMaxBounce
= false;
103 lifetimeVariance
= 0.0f
;
109 useRadiusMass
= false;
112 terminalVelocity
= 0.0f
;
116 bool DebrisData::onAdd()
121 for( S32 i
=0; i
<DDC_NUM_EMITTERS
; i
++ )
123 if( !emitterList
[i
] && emitterIDList
[i
] != 0 )
125 if( Sim::findObject( emitterIDList
[i
], emitterList
[i
] ) == false)
127 Con::errorf( ConsoleLogEntry::General
, "DebrisData::onAdd: Invalid packet, bad datablockId(emitter): 0x%x", emitterIDList
[i
]);
132 if (!explosion
&& explosionId
!= 0)
134 if (!Sim::findObject( SimObjectId( explosionId
), explosion
))
135 Con::errorf( ConsoleLogEntry::General
, "DebrisData::onAdd: Invalid packet, bad datablockId(particle emitter): 0x%x", explosionId
);
140 if( velocityVariance
> velocity
)
142 Con::warnf(ConsoleLogEntry::General
, "DebrisData(%s)::onAdd: velocityVariance invalid", getName());
143 velocityVariance
= velocity
;
145 if( friction
< -10.0f
|| friction
> 10.0f
)
147 Con::warnf(ConsoleLogEntry::General
, "DebrisData(%s)::onAdd: friction invalid", getName());
150 if( elasticity
< -10.0f
|| elasticity
> 10.0f
)
152 Con::warnf(ConsoleLogEntry::General
, "DebrisData(%s)::onAdd: elasticity invalid", getName());
155 if( lifetime
< 0.0f
|| lifetime
> 1000.0f
)
157 Con::warnf(ConsoleLogEntry::General
, "DebrisData(%s)::onAdd: lifetime invalid", getName());
160 if( lifetimeVariance
< 0.0f
|| lifetimeVariance
> lifetime
)
162 Con::warnf(ConsoleLogEntry::General
, "DebrisData(%s)::onAdd: lifetimeVariance invalid", getName());
163 lifetimeVariance
= 0.0f
;
165 if( numBounces
< 0 || numBounces
> 10000 )
167 Con::warnf(ConsoleLogEntry::General
, "DebrisData(%s)::onAdd: numBounces invalid", getName());
170 if( bounceVariance
< 0 || bounceVariance
> numBounces
)
172 Con::warnf(ConsoleLogEntry::General
, "DebrisData(%s)::onAdd: bounceVariance invalid", getName());
175 if( minSpinSpeed
< -10000.0f
|| minSpinSpeed
> 10000.0f
|| minSpinSpeed
> maxSpinSpeed
)
177 Con::warnf(ConsoleLogEntry::General
, "DebrisData(%s)::onAdd: minSpinSpeed invalid", getName());
178 minSpinSpeed
= maxSpinSpeed
- 1.0f
;
180 if( maxSpinSpeed
< -10000.0f
|| maxSpinSpeed
> 10000.0f
)
182 Con::warnf(ConsoleLogEntry::General
, "DebrisData(%s)::onAdd: maxSpinSpeed invalid", getName());
189 bool DebrisData::preload(bool server
, String
&errorStr
)
191 if (Parent::preload(server
, errorStr
) == false)
194 if( server
) return true;
196 if( shapeName
&& shapeName
[0] != '\0' && !bool(shape
) )
198 shape
= ResourceManager::get().load(shapeName
);
199 if( bool(shape
) == false )
201 errorStr
= String::ToString("DebrisData::load: Couldn't load shape \"%s\"", shapeName
);
206 TSShapeInstance
* pDummy
= new TSShapeInstance(shape
, !server
);
215 void DebrisData::initPersistFields()
218 addField("texture", TypeString
, Offset(textureName
, DebrisData
),
219 "@brief Texture imagemap to use for this debris object.\n\nNot used any more.\n");
220 addField("shapeFile", TypeShapeFilename
, Offset(shapeName
, DebrisData
),
221 "@brief Object model to use for this debris object.\n\nThis shape is optional. You could have Debris made up of only particles.\n");
224 addGroup("Datablocks");
225 addField("emitters", TYPEID
< ParticleEmitterData
>(), Offset(emitterList
, DebrisData
), DDC_NUM_EMITTERS
,
226 "@brief List of particle emitters to spawn along with this debris object.\n\nThese are optional. You could have Debris made up of only a shape.\n");
227 addField("explosion", TYPEID
< ExplosionData
>(), Offset(explosion
, DebrisData
),
228 "@brief ExplosionData to spawn along with this debris object.\n\nThis is optional as not all Debris explode.\n");
229 endGroup("Datablocks");
231 addGroup("Physical Properties");
232 addField("elasticity", TypeF32
, Offset(elasticity
, DebrisData
),
233 "@brief A floating-point value specifying how 'bouncy' this object is.\n\nMust be in the range of -10 to 10.\n");
234 addField("friction", TypeF32
, Offset(friction
, DebrisData
),
235 "@brief A floating-point value specifying how much velocity is lost to impact and sliding friction.\n\nMust be in the range of -10 to 10.\n");
236 addField("numBounces", TypeS32
, Offset(numBounces
, DebrisData
),
237 "@brief How many times to allow this debris object to bounce until it either explodes, becomes static or snaps (defined in explodeOnMaxBounce, staticOnMaxBounce, snapOnMaxBounce).\n\n"
238 "Must be within the range of 0 to 10000.\n"
239 "@see bounceVariance\n");
240 addField("bounceVariance", TypeS32
, Offset(bounceVariance
, DebrisData
),
241 "@brief Allowed variance in the value of numBounces.\n\nMust be less than numBounces.\n@see numBounces\n");
242 addField("minSpinSpeed", TypeF32
, Offset(minSpinSpeed
, DebrisData
),
243 "@brief Minimum speed that this debris object will rotate.\n\nMust be in the range of -10000 to 1000, and must be less than maxSpinSpeed.\n@see maxSpinSpeed\n");
244 addField("maxSpinSpeed", TypeF32
, Offset(maxSpinSpeed
, DebrisData
),
245 "@brief Maximum speed that this debris object will rotate.\n\nMust be in the range of -10000 to 10000.\n@see minSpinSpeed\n");
246 addField("gravModifier", TypeF32
, Offset(gravModifier
, DebrisData
), "How much gravity affects debris.");
247 addField("terminalVelocity", TypeF32
, Offset(terminalVelocity
, DebrisData
), "Max velocity magnitude.");
248 addField("velocity", TypeF32
, Offset(velocity
, DebrisData
),
249 "@brief Speed at which this debris object will move.\n\n@see velocityVariance\n");
250 addField("velocityVariance", TypeF32
, Offset(velocityVariance
, DebrisData
),
251 "@brief Allowed variance in the value of velocity\n\nMust be less than velocity.\n@see velocity\n");
252 addField("lifetime", TypeF32
, Offset(lifetime
, DebrisData
),
253 "@brief Amount of time until this debris object is destroyed.\n\nMust be in the range of 0 to 1000.\n@see lifetimeVariance");
254 addField("lifetimeVariance", TypeF32
, Offset(lifetimeVariance
, DebrisData
),
255 "@brief Allowed variance in the value of lifetime.\n\nMust be less than lifetime.\n@see lifetime\n");
256 addField("useRadiusMass", TypeBool
, Offset(useRadiusMass
, DebrisData
),
257 "@brief Use mass calculations based on radius.\n\nAllows for the adjustment of elasticity and friction based on the Debris size.\n@see baseRadius\n");
258 addField("baseRadius", TypeF32
, Offset(baseRadius
, DebrisData
),
259 "@brief Radius at which the standard elasticity and friction apply.\n\nOnly used when useRaduisMass is true.\n@see useRadiusMass.\n");
260 endGroup("Physical Properties");
262 addGroup("Behavior");
263 addField("explodeOnMaxBounce", TypeBool
, Offset(explodeOnMaxBounce
, DebrisData
),
264 "@brief If true, this debris object will explode after it has bounced max times.\n\nBe sure to provide an ExplosionData datablock for this to take effect.\n@see explosion\n");
265 addField("staticOnMaxBounce", TypeBool
, Offset(staticOnMaxBounce
, DebrisData
), "If true, this debris object becomes static after it has bounced max times.");
266 addField("snapOnMaxBounce", TypeBool
, Offset(snapOnMaxBounce
, DebrisData
), "If true, this debris object will snap into a resting position on the last bounce.");
267 addField("fade", TypeBool
, Offset(fade
, DebrisData
),
268 "@brief If true, this debris object will fade out when destroyed.\n\nThis fade occurs over the last second of the Debris' lifetime.\n");
269 addField("ignoreWater", TypeBool
, Offset(ignoreWater
, DebrisData
), "If true, this debris object will not collide with water, acting as if the water is not there.");
270 endGroup("Behavior");
272 Parent::initPersistFields();
275 void DebrisData::packData(BitStream
* stream
)
277 Parent::packData(stream
);
279 stream
->write(elasticity
);
280 stream
->write(friction
);
281 stream
->write(numBounces
);
282 stream
->write(bounceVariance
);
283 stream
->write(minSpinSpeed
);
284 stream
->write(maxSpinSpeed
);
285 stream
->write(explodeOnMaxBounce
);
286 stream
->write(staticOnMaxBounce
);
287 stream
->write(snapOnMaxBounce
);
288 stream
->write(lifetime
);
289 stream
->write(lifetimeVariance
);
290 stream
->write(velocity
);
291 stream
->write(velocityVariance
);
293 stream
->write(useRadiusMass
);
294 stream
->write(baseRadius
);
295 stream
->write(gravModifier
);
296 stream
->write(terminalVelocity
);
297 stream
->write(ignoreWater
);
299 stream
->writeString( textureName
);
300 stream
->writeString( shapeName
);
302 for( S32 i
=0; i
<DDC_NUM_EMITTERS
; i
++ )
304 if( stream
->writeFlag( emitterList
[i
] != NULL
) )
306 stream
->writeRangedU32( emitterList
[i
]->getId(), DataBlockObjectIdFirst
, DataBlockObjectIdLast
);
310 if( stream
->writeFlag( explosion
) )
312 stream
->writeRangedU32(packed
? SimObjectId((uintptr_t)explosion
):
313 explosion
->getId(),DataBlockObjectIdFirst
,DataBlockObjectIdLast
);
318 void DebrisData::unpackData(BitStream
* stream
)
320 Parent::unpackData(stream
);
322 stream
->read(&elasticity
);
323 stream
->read(&friction
);
324 stream
->read(&numBounces
);
325 stream
->read(&bounceVariance
);
326 stream
->read(&minSpinSpeed
);
327 stream
->read(&maxSpinSpeed
);
328 stream
->read(&explodeOnMaxBounce
);
329 stream
->read(&staticOnMaxBounce
);
330 stream
->read(&snapOnMaxBounce
);
331 stream
->read(&lifetime
);
332 stream
->read(&lifetimeVariance
);
333 stream
->read(&velocity
);
334 stream
->read(&velocityVariance
);
336 stream
->read(&useRadiusMass
);
337 stream
->read(&baseRadius
);
338 stream
->read(&gravModifier
);
339 stream
->read(&terminalVelocity
);
340 stream
->read(&ignoreWater
);
342 textureName
= stream
->readSTString();
343 shapeName
= stream
->readSTString();
345 for( S32 i
=0; i
<DDC_NUM_EMITTERS
; i
++ )
347 if( stream
->readFlag() )
349 emitterIDList
[i
] = stream
->readRangedU32( DataBlockObjectIdFirst
, DataBlockObjectIdLast
);
353 if(stream
->readFlag())
355 explosionId
= (S32
)stream
->readRangedU32(DataBlockObjectIdFirst
, DataBlockObjectIdLast
);
365 IMPLEMENT_CO_NETOBJECT_V1(Debris
);
367 ConsoleDocClass( Debris
,
368 "@brief Base debris class. Uses the DebrisData datablock for properties of individual debris objects.\n\n"
370 "Debris is typically made up of a shape and up to two particle emitters. In most cases Debris objects are "
371 "not created directly. They are usually produced automatically by other means, such as through the Explosion "
372 "class. When an explosion goes off, its ExplosionData datablock determines what Debris to emit.\n"
375 "datablock ExplosionData(GrenadeLauncherExplosion)\n"
377 " // Assiging debris data\n"
378 " debris = GrenadeDebris;\n\n"
379 " // Adjust how debris is ejected\n"
380 " debrisThetaMin = 10;\n"
381 " debrisThetaMax = 60;\n"
383 " debrisNumVariance = 2;\n"
384 " debrisVelocity = 25;\n"
385 " debrisVelocityVariance = 5;\n\n"
386 " // Note: other ExplosionData properties are not listed for this example\n"
390 "@note Debris are client side only objects.\n"
393 "@see ExplosionData\n"
399 DefineEngineMethod(Debris
, init
, bool, (const char* inputPosition
, const char* inputVelocity
),
400 ("1.0 1.0 1.0", "1.0 0.0 0.0"),
401 "@brief Manually set this piece of debris at the given position with the given velocity.\n\n"
403 "Usually you do not manually create Debris objects as they are generated through other means, "
404 "such as an Explosion. This method exists when you do manually create a Debris object and "
405 "want to have it start moving.\n"
407 "@param inputPosition Position to place the debris.\n"
408 "@param inputVelocity Velocity to move the debris after it has been placed.\n"
409 "@return Always returns true.\n"
412 "// Define the position\n"
413 "%position = \"1.0 1.0 1.0\";\n\n"
414 "// Define the velocity\n"
415 "%velocity = \"1.0 0.0 0.0\";\n\n"
416 "// Inform the debris object of its new position and velocity\n"
417 "%debris.init(%position,%velocity);\n"
421 dSscanf( inputPosition
, "%f %f %f", &pos
.x
, &pos
.y
, &pos
.z
);
424 dSscanf( inputVelocity
, "%f %f %f", &vel
.x
, &vel
.y
, &vel
.z
);
426 object
->init( pos
, vel
);
433 mTypeMask
|= DebrisObjectType
| DynamicShapeObjectType
;
435 mVelocity
= Point3F( 0.0f
, 0.0f
, 4.0f
);
436 mLifetime
= gRandGen
.randF( 1.0f
, 10.0f
);
437 mLastPos
= getPosition();
438 mNumBounces
= gRandGen
.randI( 0, 1 );
446 mInitialTrans
.identity();
450 dMemset( mEmitterList
, 0, sizeof( mEmitterList
) );
452 // Only allocated client side.
453 mNetFlags
.set( IsGhost
);
471 void Debris::initPersistFields()
473 addGroup( "Debris" );
475 addField( "lifetime", TypeF32
, Offset(mLifetime
, Debris
),
476 "@brief Length of time for this debris object to exist. When expired, the object will be deleted.\n\n"
477 "The initial lifetime value comes from the DebrisData datablock.\n"
478 "@see DebrisData::lifetime\n"
479 "@see DebrisData::lifetimeVariance\n");
481 endGroup( "Debris" );
483 Parent::initPersistFields();
486 void Debris::init( const Point3F
&position
, const Point3F
&velocity
)
488 setPosition( position
);
489 setVelocity( velocity
);
492 bool Debris::onNewDataBlock( GameBaseData
*dptr
, bool reload
)
494 mDataBlock
= dynamic_cast< DebrisData
* >( dptr
);
495 if( !mDataBlock
|| !Parent::onNewDataBlock( dptr
, reload
) )
498 scriptOnNewDataBlock();
505 if( !Parent::onAdd() )
512 Con::errorf("Debris::onAdd - Fail - No datablock");
517 for( S32 i
=0; i
<DebrisData::DDC_NUM_EMITTERS
; i
++ )
519 if( mDataBlock
->emitterList
[i
] != NULL
)
521 ParticleEmitter
* pEmitter
= new ParticleEmitter
;
522 pEmitter
->onNewDataBlock( mDataBlock
->emitterList
[i
], false );
523 if( !pEmitter
->registerObject() )
525 Con::warnf( ConsoleLogEntry::General
, "Could not register emitter for particle of class: %s", mDataBlock
->getName() );
529 mEmitterList
[i
] = pEmitter
;
533 // set particle sizes based on debris size
534 F32 sizeList
[ParticleData::PDC_NUM_KEYS
];
536 if( mEmitterList
[0] )
538 sizeList
[0] = mSize
* 0.5;
540 sizeList
[2] = mSize
* 1.5;
542 mEmitterList
[0]->setSizes( sizeList
);
545 if( mEmitterList
[1] )
548 sizeList
[1] = mSize
* 0.5;
551 mEmitterList
[1]->setSizes( sizeList
);
554 S32 bounceVar
= (S32
)mDataBlock
->bounceVariance
;
555 bounceVar
= gRandGen
.randI( -bounceVar
, bounceVar
);
556 mNumBounces
= mDataBlock
->numBounces
+ bounceVar
;
558 F32 lifeVar
= (mDataBlock
->lifetimeVariance
* 2.0f
* gRandGen
.randF(-1.0,1.0)) - mDataBlock
->lifetimeVariance
;
559 mLifetime
= mDataBlock
->lifetime
+ lifeVar
;
561 F32 xRotSpeed
= gRandGen
.randF( mDataBlock
->minSpinSpeed
, mDataBlock
->maxSpinSpeed
);
562 F32 zRotSpeed
= gRandGen
.randF( mDataBlock
->minSpinSpeed
, mDataBlock
->maxSpinSpeed
);
563 zRotSpeed
*= gRandGen
.randF( 0.1f
, 0.5f
);
565 mRotAngles
.set( xRotSpeed
, 0.0f
, zRotSpeed
);
567 mElasticity
= mDataBlock
->elasticity
;
568 mFriction
= mDataBlock
->friction
;
570 // Setup our bounding box
571 if( mDataBlock
->shape
)
573 mObjBox
= mDataBlock
->shape
->bounds
;
577 mObjBox
= Box3F(Point3F(-1, -1, -1), Point3F(1, 1, 1));
580 if( mDataBlock
->shape
)
582 mShape
= new TSShapeInstance( mDataBlock
->shape
, true);
587 // use half radius becuase we want debris to stick in ground
588 mRadius
= mPart
->getRadius() * 0.5;
589 mObjBox
= mPart
->getBounds();
594 mInitialTrans
= getTransform();
596 if( mDataBlock
->velocity
!= 0.0 )
598 F32 velocity
= mDataBlock
->velocity
+ gRandGen
.randF( -mDataBlock
->velocityVariance
, mDataBlock
->velocityVariance
);
600 mVelocity
.normalizeSafe();
601 mVelocity
*= velocity
;
605 if( mDataBlock
->useRadiusMass
)
607 if( mRadius
< mDataBlock
->baseRadius
)
609 mRadius
= mDataBlock
->baseRadius
;
613 F32 multFactor
= mDataBlock
->baseRadius
/ mRadius
;
615 mElasticity
*= multFactor
;
616 mFriction
*= multFactor
;
617 mRotAngles
*= multFactor
;
621 // tell engine the debris exists
622 gClientSceneGraph
->addObjectToScene(this);
624 removeFromProcessList();
625 ClientProcessList::get()->addObject(this);
627 NetConnection
* pNC
= NetConnection::getConnectionToServer();
628 AssertFatal(pNC
!= NULL
, "Error, must have a connection to the server!");
629 pNC
->addObject(this);
634 void Debris::onRemove()
636 for( S32 i
=0; i
<DebrisData::DDC_NUM_EMITTERS
; i
++ )
638 if( mEmitterList
[i
] )
640 mEmitterList
[i
]->deleteWhenEmpty();
641 mEmitterList
[i
] = NULL
;
647 TSShapeInstance
*ss
= mPart
->getSourceShapeInstance();
650 ss
->decDebrisRefCount();
651 if( ss
->getDebrisRefCount() == 0 )
663 void Debris::processTick(const Move
*)
665 if (mLifetime
<= 0.0)
669 void Debris::advanceTime( F32 dt
)
674 if( mLifetime
<= 0.0 )
680 mLastPos
= getPosition();
686 Point3F nextPos
= getPosition();
687 computeNewState( nextPos
, mVelocity
, dt
);
689 if( bounce( nextPos
, dt
) )
692 if( mNumBounces
<= 0 )
694 if( mDataBlock
->explodeOnMaxBounce
)
699 if( mDataBlock
->snapOnMaxBounce
)
701 // orient debris so it's flat
702 MatrixF stat
= getTransform();
705 stat
.getColumn( 1, &dir
);
708 MatrixF newTrans
= MathUtils::createOrientFromDir( dir
);
710 // hack for shell casings to get them above ground. Need something better - bramage
711 newTrans
.setPosition( getPosition() + Point3F( 0.0f
, 0.0f
, 0.10f
) );
713 setTransform( newTrans
);
715 if( mDataBlock
->staticOnMaxBounce
)
723 setPosition( nextPos
);
727 Point3F
pos( getPosition( ) );
728 updateEmitters( pos
, mVelocity
, (U32
)(dt
* 1000.0));
732 void Debris::rotate( F32 dt
)
734 MatrixF curTrans
= getTransform();
735 curTrans
.setPosition( Point3F(0.0f
, 0.0f
, 0.0f
) );
737 Point3F curAngles
= mRotAngles
* dt
* M_PI_F
/180.0f
;
738 MatrixF
rotMatrix( EulerF( curAngles
.x
, curAngles
.y
, curAngles
.z
) );
740 curTrans
.mul( rotMatrix
);
741 curTrans
.setPosition( getPosition() );
742 setTransform( curTrans
);
745 bool Debris::bounce( const Point3F
&nextPos
, F32 dt
)
747 Point3F curPos
= getPosition();
749 Point3F dir
= nextPos
- curPos
;
750 if( dir
.magnitudeSafe() == 0.0f
) return false;
752 Point3F extent
= nextPos
+ dir
* mRadius
;
753 F32 totalDist
= Point3F( extent
- curPos
).magnitudeSafe();
754 F32 moveDist
= Point3F( nextPos
- curPos
).magnitudeSafe();
755 F32 movePercent
= (moveDist
/ totalDist
);
758 U32 collisionMask
= csmStaticCollisionMask
;
759 if( !mDataBlock
->ignoreWater
)
761 collisionMask
|= WaterObjectType
;
764 if( getContainer()->castRay( curPos
, extent
, collisionMask
, &rayInfo
) )
767 Point3F reflection
= mVelocity
- rayInfo
.normal
* (mDot( mVelocity
, rayInfo
.normal
) * 2.0f
);
768 mVelocity
= reflection
;
770 Point3F tangent
= reflection
- rayInfo
.normal
* mDot( reflection
, rayInfo
.normal
);
771 mVelocity
-= tangent
* mFriction
;
773 Point3F velDir
= mVelocity
;
774 velDir
.normalizeSafe();
776 mVelocity
*= mElasticity
;
778 Point3F bouncePos
= curPos
+ dir
* rayInfo
.t
* movePercent
;
779 bouncePos
+= mVelocity
* dt
;
781 setPosition( bouncePos
);
783 mRotAngles
*= mElasticity
;
793 void Debris::explode()
796 if( !mDataBlock
->explosion
) return;
798 Point3F explosionPos
= getPosition();
800 Explosion
* pExplosion
= new Explosion
;
801 pExplosion
->onNewDataBlock(mDataBlock
->explosion
, false);
803 MatrixF
trans( true );
804 trans
.setPosition( getPosition() );
806 pExplosion
->setTransform( trans
);
807 pExplosion
->setInitialState( explosionPos
, VectorF(0,0,1), 1);
808 if (!pExplosion
->registerObject())
812 void Debris::computeNewState( Point3F
&newPos
, Point3F
&newVel
, F32 dt
)
815 Point3F force
= Point3F(0, 0, -9.81 * mDataBlock
->gravModifier
);
817 if( mDataBlock
->terminalVelocity
> 0.0001 )
819 if( newVel
.magnitudeSafe() > mDataBlock
->terminalVelocity
)
821 newVel
.normalizeSafe();
822 newVel
*= mDataBlock
->terminalVelocity
;
826 newVel
+= force
* dt
;
831 newVel
+= force
* dt
;
834 newPos
+= newVel
* dt
;
838 void Debris::updateEmitters( Point3F
&pos
, Point3F
&vel
, U32 ms
)
843 if( axis
.magnitudeSafe() == 0.0 )
845 axis
= Point3F( 0.0, 0.0, 1.0 );
847 axis
.normalizeSafe();
850 Point3F lastPos
= mLastPos
;
852 for( S32 i
=0; i
<DebrisData::DDC_NUM_EMITTERS
; i
++ )
854 if( mEmitterList
[i
] )
856 mEmitterList
[i
]->emitParticles( lastPos
, pos
, axis
, vel
, ms
);
862 void Debris::prepRenderImage( SceneRenderState
*state
)
864 if( !mPart
&& !mShape
)
867 Point3F cameraOffset
;
868 mObjToWorld
.getColumn(3,&cameraOffset
);
869 cameraOffset
-= state
->getDiffuseCameraPosition();
870 F32 dist
= cameraOffset
.len();
871 F32 invScale
= (1.0f
/getMax(getMax(mObjScale
.x
,mObjScale
.y
),mObjScale
.z
));
875 mShape
->setDetailFromDistance( state
, dist
* invScale
);
876 if( mShape
->getCurrentDetail() < 0 )
882 // get the shapeInstance that we are using for the debris parts
883 TSShapeInstance
*si
= mPart
->getSourceShapeInstance();
885 si
->setDetailFromDistance( state
, dist
* invScale
);
888 prepBatchRender( state
);
891 void Debris::prepBatchRender( SceneRenderState
*state
)
893 if ( !mShape
&& !mPart
)
896 GFXTransformSaver saver
;
899 if( mDataBlock
->fade
)
901 if( mLifetime
< 1.0 ) alpha
= mLifetime
;
904 Point3F cameraOffset
;
905 mObjToWorld
.getColumn(3,&cameraOffset
);
906 cameraOffset
-= state
->getCameraPosition();
908 // Set up our TS render state.
910 rdata
.setSceneState( state
);
912 // We might have some forward lit materials
913 // so pass down a query to gather lights.
915 query
.init( getWorldSphere() );
916 rdata
.setLightQuery( &query
);
920 MatrixF mat
= getRenderTransform();
921 GFX
->setWorldMatrix( mat
);
923 rdata
.setFadeOverride( alpha
);
924 mShape
->render( rdata
);
928 if (mPart
->getCurrentObjectDetail() != -1)
930 MatrixF mat
= getRenderTransform();
931 GFX
->setWorldMatrix( mat
);
933 rdata
.setFadeOverride( alpha
);
934 mPart
->render( rdata
);
939 void Debris::setSize( F32 size
)