mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-04-23 13:25:36 +00:00
Merge branch 'development' into style-cleanup
Conflicts: Engine/source/console/astNodes.cpp Engine/source/console/codeBlock.cpp Engine/source/console/compiledEval.cpp Engine/source/ts/collada/colladaAppMesh.cpp Engine/source/ts/tsShape.cpp Engine/source/ts/tsShapeConstruct.cpp
This commit is contained in:
commit
33ff180593
2053 changed files with 172002 additions and 69530 deletions
|
|
@ -457,8 +457,9 @@ ConsoleMethod( AIClient, getAimLocation, const char *, 2, 2, "ai.getAimLocation(
|
|||
AIClient *ai = static_cast<AIClient *>( object );
|
||||
Point3F aimPoint = ai->getAimLocation();
|
||||
|
||||
char *returnBuffer = Con::getReturnBuffer( 256 );
|
||||
dSprintf( returnBuffer, 256, "%f %f %f", aimPoint.x, aimPoint.y, aimPoint.z );
|
||||
static const U32 bufSize = 256;
|
||||
char *returnBuffer = Con::getReturnBuffer( bufSize );
|
||||
dSprintf( returnBuffer, bufSize, "%f %f %f", aimPoint.x, aimPoint.y, aimPoint.z );
|
||||
|
||||
return returnBuffer;
|
||||
}
|
||||
|
|
@ -470,8 +471,9 @@ ConsoleMethod( AIClient, getMoveDestination, const char *, 2, 2, "ai.getMoveDest
|
|||
AIClient *ai = static_cast<AIClient *>( object );
|
||||
Point3F movePoint = ai->getMoveDestination();
|
||||
|
||||
char *returnBuffer = Con::getReturnBuffer( 256 );
|
||||
dSprintf( returnBuffer, 256, "%f %f %f", movePoint.x, movePoint.y, movePoint.z );
|
||||
static const U32 bufSize = 256;
|
||||
char *returnBuffer = Con::getReturnBuffer( bufSize );
|
||||
dSprintf( returnBuffer, bufSize, "%f %f %f", movePoint.x, movePoint.y, movePoint.z );
|
||||
|
||||
return returnBuffer;
|
||||
}
|
||||
|
|
@ -522,8 +524,9 @@ ConsoleMethod( AIClient, getLocation, const char *, 2, 2, "ai.getLocation();" )
|
|||
AIClient *ai = static_cast<AIClient *>( object );
|
||||
Point3F locPoint = ai->getLocation();
|
||||
|
||||
char *returnBuffer = Con::getReturnBuffer( 256 );
|
||||
dSprintf( returnBuffer, 256, "%f %f %f", locPoint.x, locPoint.y, locPoint.z );
|
||||
static const U32 bufSize = 256;
|
||||
char *returnBuffer = Con::getReturnBuffer( bufSize );
|
||||
dSprintf( returnBuffer, bufSize, "%f %f %f", locPoint.x, locPoint.y, locPoint.z );
|
||||
|
||||
return returnBuffer;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -147,6 +147,7 @@ ConsoleFunction(aiConnect, S32 , 2, 20, "(...)"
|
|||
// Make sure and leav args[1] empty.
|
||||
const char* args[21];
|
||||
args[0] = "onConnect";
|
||||
args[1] = NULL; // Filled in later
|
||||
for (S32 i = 1; i < argc; i++)
|
||||
args[i + 1] = argv[i];
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@
|
|||
#include "T3D/gameBase/moveManager.h"
|
||||
#include "console/engineAPI.h"
|
||||
|
||||
static U32 sAIPlayerLoSMask = TerrainObjectType | StaticShapeObjectType | StaticObjectType;
|
||||
|
||||
IMPLEMENT_CO_NETOBJECT_V1(AIPlayer);
|
||||
|
||||
ConsoleDocClass( AIPlayer,
|
||||
|
|
@ -417,28 +419,21 @@ bool AIPlayer::getAIMove(Move *movePtr)
|
|||
// Test for target location in sight if it's an object. The LOS is
|
||||
// run from the eye position to the center of the object's bounding,
|
||||
// which is not very accurate.
|
||||
if (mAimObject) {
|
||||
MatrixF eyeMat;
|
||||
getEyeTransform(&eyeMat);
|
||||
eyeMat.getColumn(3,&location);
|
||||
Point3F targetLoc = mAimObject->getBoxCenter();
|
||||
|
||||
// This ray ignores non-static shapes. Cast Ray returns true
|
||||
// if it hit something.
|
||||
RayInfo dummy;
|
||||
if (getContainer()->castRay( location, targetLoc,
|
||||
StaticShapeObjectType | StaticObjectType |
|
||||
TerrainObjectType, &dummy)) {
|
||||
if (mTargetInLOS) {
|
||||
throwCallback( "onTargetExitLOS" );
|
||||
mTargetInLOS = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (!mTargetInLOS) {
|
||||
throwCallback( "onTargetEnterLOS" );
|
||||
if (mAimObject)
|
||||
{
|
||||
if (checkInLos(mAimObject.getPointer()))
|
||||
{
|
||||
if (!mTargetInLOS)
|
||||
{
|
||||
throwCallback("onTargetEnterLOS");
|
||||
mTargetInLOS = true;
|
||||
}
|
||||
}
|
||||
else if (mTargetInLOS)
|
||||
{
|
||||
throwCallback("onTargetExitLOS");
|
||||
mTargetInLOS = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Replicate the trigger state into the move so that
|
||||
|
|
@ -610,3 +605,112 @@ DefineEngineMethod( AIPlayer, getAimObject, S32, (),,
|
|||
GameBase* obj = object->getAimObject();
|
||||
return obj? obj->getId(): -1;
|
||||
}
|
||||
|
||||
bool AIPlayer::checkInLos(GameBase* target, bool _useMuzzle, bool _checkEnabled)
|
||||
{
|
||||
if (!isServerObject()) return false;
|
||||
if (!target)
|
||||
{
|
||||
target = mAimObject.getPointer();
|
||||
if (!target)
|
||||
return false;
|
||||
}
|
||||
if (_checkEnabled)
|
||||
{
|
||||
if (target->getTypeMask() & ShapeBaseObjectType)
|
||||
{
|
||||
ShapeBase *shapeBaseCheck = static_cast<ShapeBase *>(target);
|
||||
if (shapeBaseCheck)
|
||||
if (shapeBaseCheck->getDamageState() != Enabled) return false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
RayInfo ri;
|
||||
|
||||
disableCollision();
|
||||
|
||||
S32 mountCount = target->getMountedObjectCount();
|
||||
for (S32 i = 0; i < mountCount; i++)
|
||||
{
|
||||
target->getMountedObject(i)->disableCollision();
|
||||
}
|
||||
|
||||
Point3F checkPoint ;
|
||||
if (_useMuzzle)
|
||||
getMuzzlePointAI(0, &checkPoint );
|
||||
else
|
||||
{
|
||||
MatrixF eyeMat;
|
||||
getEyeTransform(&eyeMat);
|
||||
eyeMat.getColumn(3, &checkPoint );
|
||||
}
|
||||
|
||||
bool hit = !gServerContainer.castRay(checkPoint, target->getBoxCenter(), sAIPlayerLoSMask, &ri);
|
||||
enableCollision();
|
||||
|
||||
for (S32 i = 0; i < mountCount; i++)
|
||||
{
|
||||
target->getMountedObject(i)->enableCollision();
|
||||
}
|
||||
return hit;
|
||||
}
|
||||
|
||||
DefineEngineMethod(AIPlayer, checkInLos, bool, (ShapeBase* obj, bool useMuzzle, bool checkEnabled),(NULL, false, false),
|
||||
"@brief Check whether an object is in line of sight.\n"
|
||||
"@obj Object to check. (If blank, it will check the current target).\n"
|
||||
"@useMuzzle Use muzzle position. Otherwise use eye position. (defaults to false).\n"
|
||||
"@checkEnabled check whether the object can take damage and if so is still alive.(Defaults to false)\n")
|
||||
{
|
||||
return object->checkInLos(obj, useMuzzle, checkEnabled);
|
||||
}
|
||||
|
||||
bool AIPlayer::checkInFoV(GameBase* target, F32 camFov, bool _checkEnabled)
|
||||
{
|
||||
if (!isServerObject()) return false;
|
||||
if (!target)
|
||||
{
|
||||
target = mAimObject.getPointer();
|
||||
if (!target)
|
||||
return false;
|
||||
}
|
||||
if (_checkEnabled)
|
||||
{
|
||||
if (target->getTypeMask() & ShapeBaseObjectType)
|
||||
{
|
||||
ShapeBase *shapeBaseCheck = static_cast<ShapeBase *>(target);
|
||||
if (shapeBaseCheck)
|
||||
if (shapeBaseCheck->getDamageState() != Enabled) return false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
MatrixF cam = getTransform();
|
||||
Point3F camPos;
|
||||
VectorF camDir;
|
||||
|
||||
cam.getColumn(3, &camPos);
|
||||
cam.getColumn(1, &camDir);
|
||||
|
||||
camFov = mDegToRad(camFov) / 2;
|
||||
|
||||
Point3F shapePos = target->getBoxCenter();
|
||||
VectorF shapeDir = shapePos - camPos;
|
||||
// Test to see if it's within our viewcone, this test doesn't
|
||||
// actually match the viewport very well, should consider
|
||||
// projection and box test.
|
||||
shapeDir.normalize();
|
||||
F32 dot = mDot(shapeDir, camDir);
|
||||
return (dot > camFov);
|
||||
}
|
||||
|
||||
DefineEngineMethod(AIPlayer, checkInFoV, bool, (ShapeBase* obj, F32 fov, bool checkEnabled), (NULL, 45.0f, false),
|
||||
"@brief Check whether an object is within a specified veiw cone.\n"
|
||||
"@obj Object to check. (If blank, it will check the current target).\n"
|
||||
"@fov view angle in degrees.(Defaults to 45)\n"
|
||||
"@checkEnabled check whether the object can take damage and if so is still alive.(Defaults to false)\n")
|
||||
{
|
||||
return object->checkInFoV(obj, fov, checkEnabled);
|
||||
}
|
||||
|
|
@ -80,6 +80,8 @@ public:
|
|||
void setAimLocation( const Point3F &location );
|
||||
Point3F getAimLocation() const { return mAimLocation; }
|
||||
void clearAim();
|
||||
bool checkInLos(GameBase* target = NULL, bool _useMuzzle = false, bool _checkEnabled = false);
|
||||
bool checkInFoV(GameBase* target = NULL, F32 camFov = 45.0f, bool _checkEnabled = false);
|
||||
|
||||
// Movement sets/gets
|
||||
void setMoveSpeed( const F32 speed );
|
||||
|
|
|
|||
|
|
@ -214,7 +214,7 @@ void CameraSpline::renderTimeMap()
|
|||
|
||||
// Render the buffer
|
||||
GFX->pushWorldMatrix();
|
||||
GFX->disableShaders();
|
||||
GFX->setupGenericShaders();
|
||||
GFX->setVertexBuffer(vb);
|
||||
GFX->drawPrimitive(GFXLineStrip,0,index);
|
||||
GFX->popWorldMatrix();
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@
|
|||
#include "lighting/lightQuery.h"
|
||||
|
||||
|
||||
const U32 csmStaticCollisionMask = TerrainObjectType;
|
||||
const U32 csmStaticCollisionMask = TerrainObjectType | StaticShapeObjectType | StaticObjectType;
|
||||
|
||||
const U32 csmDynamicCollisionMask = StaticShapeObjectType;
|
||||
|
||||
|
|
@ -99,7 +99,6 @@ DebrisData::DebrisData()
|
|||
friction = 0.2f;
|
||||
numBounces = 0;
|
||||
bounceVariance = 0;
|
||||
minSpinSpeed = maxSpinSpeed = 0.0;
|
||||
staticOnMaxBounce = false;
|
||||
explodeOnMaxBounce = false;
|
||||
snapOnMaxBounce = false;
|
||||
|
|
@ -511,6 +510,12 @@ bool Debris::onAdd()
|
|||
return false;
|
||||
}
|
||||
|
||||
if( !mDataBlock )
|
||||
{
|
||||
Con::errorf("Debris::onAdd - Fail - No datablock");
|
||||
return false;
|
||||
}
|
||||
|
||||
// create emitters
|
||||
for( S32 i=0; i<DebrisData::DDC_NUM_EMITTERS; i++ )
|
||||
{
|
||||
|
|
@ -653,8 +658,7 @@ void Debris::onRemove()
|
|||
}
|
||||
}
|
||||
|
||||
getSceneManager()->removeObjectFromScene(this);
|
||||
getContainer()->removeObject(this);
|
||||
removeFromScene();
|
||||
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ protected:
|
|||
|
||||
public:
|
||||
CameraFX();
|
||||
virtual ~CameraFX() { }
|
||||
|
||||
MatrixF & getTrans(){ return mCamFXTrans; }
|
||||
virtual bool isExpired(){ return mElapsedTime >= mDuration; }
|
||||
|
|
|
|||
|
|
@ -749,9 +749,9 @@ bool ExplosionData::preload(bool server, String &errorStr)
|
|||
|
||||
if( !server )
|
||||
{
|
||||
String errorStr;
|
||||
if( !sfxResolve( &soundProfile, errorStr ) )
|
||||
Con::errorf(ConsoleLogEntry::General, "Error, unable to load sound profile for explosion datablock: %s", errorStr.c_str());
|
||||
String sfxErrorStr;
|
||||
if( !sfxResolve( &soundProfile, sfxErrorStr ) )
|
||||
Con::errorf(ConsoleLogEntry::General, "Error, unable to load sound profile for explosion datablock: %s", sfxErrorStr.c_str());
|
||||
if (!particleEmitter && particleEmitterId != 0)
|
||||
if (Sim::findObject(particleEmitterId, particleEmitter) == false)
|
||||
Con::errorf(ConsoleLogEntry::General, "Error, unable to load particle emitter for explosion datablock");
|
||||
|
|
@ -784,6 +784,7 @@ bool ExplosionData::preload(bool server, String &errorStr)
|
|||
//--------------------------------------
|
||||
//
|
||||
Explosion::Explosion()
|
||||
: mDataBlock( NULL )
|
||||
{
|
||||
mTypeMask |= ExplosionObjectType | LightObjectType;
|
||||
|
||||
|
|
@ -844,6 +845,12 @@ bool Explosion::onAdd()
|
|||
if ( !conn || !Parent::onAdd() )
|
||||
return false;
|
||||
|
||||
if( !mDataBlock )
|
||||
{
|
||||
Con::errorf("Explosion::onAdd - Fail - No datablok");
|
||||
return false;
|
||||
}
|
||||
|
||||
mDelayMS = mDataBlock->delayMS + sgRandom.randI( -mDataBlock->delayVariance, mDataBlock->delayVariance );
|
||||
mEndingMS = mDataBlock->lifetimeMS + sgRandom.randI( -mDataBlock->lifetimeVariance, mDataBlock->lifetimeVariance );
|
||||
|
||||
|
|
@ -957,10 +964,7 @@ void Explosion::onRemove()
|
|||
mMainEmitter = NULL;
|
||||
}
|
||||
|
||||
if (getSceneManager() != NULL)
|
||||
getSceneManager()->removeObjectFromScene(this);
|
||||
if (getContainer() != NULL)
|
||||
getContainer()->removeObject(this);
|
||||
removeFromScene();
|
||||
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -287,14 +287,14 @@ bool LightningData::preload(bool server, String &errorStr)
|
|||
|
||||
if (server == false)
|
||||
{
|
||||
String errorStr;
|
||||
String sfxErrorStr;
|
||||
for (U32 i = 0; i < MaxThunders; i++) {
|
||||
if( !sfxResolve( &thunderSounds[ i ], errorStr ) )
|
||||
Con::errorf(ConsoleLogEntry::General, "LightningData::preload: Invalid packet: %s", errorStr.c_str());
|
||||
if( !sfxResolve( &thunderSounds[ i ], sfxErrorStr ) )
|
||||
Con::errorf(ConsoleLogEntry::General, "LightningData::preload: Invalid packet: %s", sfxErrorStr.c_str());
|
||||
}
|
||||
|
||||
if( !sfxResolve( &strikeSound, errorStr ) )
|
||||
Con::errorf(ConsoleLogEntry::General, "LightningData::preload: Invalid packet: %s", errorStr.c_str());
|
||||
if( !sfxResolve( &strikeSound, sfxErrorStr ) )
|
||||
Con::errorf(ConsoleLogEntry::General, "LightningData::preload: Invalid packet: %s", sfxErrorStr.c_str());
|
||||
|
||||
for (U32 i = 0; i < MaxTextures; i++)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1168,9 +1168,7 @@ void Precipitation::destroySplash(Raindrop *drop)
|
|||
PROFILE_START(PrecipDestroySplash);
|
||||
if (drop == mSplashHead)
|
||||
{
|
||||
mSplashHead = NULL;
|
||||
PROFILE_END();
|
||||
return;
|
||||
mSplashHead = mSplashHead->nextSplashDrop;
|
||||
}
|
||||
|
||||
if (drop->nextSplashDrop)
|
||||
|
|
@ -1668,7 +1666,7 @@ void Precipitation::renderObject(ObjectRenderInst *ri, SceneRenderState *state,
|
|||
}
|
||||
else
|
||||
{
|
||||
GFX->disableShaders();
|
||||
GFX->setupGenericShaders(GFXDevice::GSTexture);
|
||||
|
||||
// We don't support distance fade or lighting without shaders.
|
||||
GFX->setStateBlock(mDistantSB);
|
||||
|
|
@ -1801,7 +1799,7 @@ void Precipitation::renderObject(ObjectRenderInst *ri, SceneRenderState *state,
|
|||
GFX->setShaderConstBuffer(mSplashShaderConsts);
|
||||
}
|
||||
else
|
||||
GFX->disableShaders();
|
||||
GFX->setupGenericShaders(GFXDevice::GSTexture);
|
||||
|
||||
while (curr)
|
||||
{
|
||||
|
|
|
|||
707
Engine/source/T3D/fx/ribbon.cpp
Normal file
707
Engine/source/T3D/fx/ribbon.cpp
Normal file
|
|
@ -0,0 +1,707 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2014 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 "console/consoleTypes.h"
|
||||
#include "console/typeValidators.h"
|
||||
#include "core/stream/bitStream.h"
|
||||
#include "T3D/shapeBase.h"
|
||||
#include "ts/tsShapeInstance.h"
|
||||
#include "T3D/fx/ribbon.h"
|
||||
#include "math/mathUtils.h"
|
||||
#include "math/mathIO.h"
|
||||
#include "sim/netConnection.h"
|
||||
#include "gfx/primBuilder.h"
|
||||
#include "gfx/gfxDrawUtil.h"
|
||||
#include "materials/sceneData.h"
|
||||
#include "materials/matInstance.h"
|
||||
#include "gui/3d/guiTSControl.h"
|
||||
#include "materials/materialManager.h"
|
||||
#include "materials/processedShaderMaterial.h"
|
||||
#include "gfx/gfxTransformSaver.h"
|
||||
|
||||
|
||||
IMPLEMENT_CO_DATABLOCK_V1(RibbonData);
|
||||
IMPLEMENT_CO_NETOBJECT_V1(Ribbon);
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
RibbonData::RibbonData()
|
||||
{
|
||||
for (U8 i = 0; i < NumFields; i++) {
|
||||
mSizes[i] = 0.0f;
|
||||
mColours[i].set(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
mTimes[i] = -1.0f;
|
||||
}
|
||||
|
||||
mRibbonLength = 0;
|
||||
mUseFadeOut = false;
|
||||
mFadeAwayStep = 0.032f;
|
||||
segmentsPerUpdate = 1;
|
||||
mMatName = StringTable->insert("");
|
||||
mTileScale = 1.0f;
|
||||
mFixedTexcoords = false;
|
||||
mSegmentSkipAmount = 0;
|
||||
mTexcoordsRelativeToDistance = false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void RibbonData::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
|
||||
addGroup("Ribbon");
|
||||
|
||||
addField("size", TypeF32, Offset(mSizes, RibbonData), NumFields,
|
||||
"The size of the ribbon at the specified keyframe.");
|
||||
addField("color", TypeColorF, Offset(mColours, RibbonData), NumFields,
|
||||
"The colour of the ribbon at the specified keyframe.");
|
||||
addField("position", TypeF32, Offset(mTimes, RibbonData), NumFields,
|
||||
"The position of the keyframe along the lifetime of the ribbon.");
|
||||
|
||||
addField("ribbonLength", TypeS32, Offset(mRibbonLength, RibbonData),
|
||||
"The amount of segments the Ribbon can maximally have in length.");
|
||||
addField("segmentsPerUpdate", TypeS32, Offset(segmentsPerUpdate, RibbonData),
|
||||
"How many segments to add each update.");
|
||||
addField("skipAmount", TypeS32, Offset(mSegmentSkipAmount, RibbonData),
|
||||
"The amount of segments to skip each update.");
|
||||
|
||||
addField("useFadeOut", TypeBool, Offset(mUseFadeOut, RibbonData),
|
||||
"If true, the ribbon will fade away after deletion.");
|
||||
addField("fadeAwayStep", TypeF32, Offset(mFadeAwayStep, RibbonData),
|
||||
"How much to fade the ribbon with each update, after deletion.");
|
||||
addField("ribbonMaterial", TypeString, Offset(mMatName, RibbonData),
|
||||
"The material the ribbon uses for rendering.");
|
||||
addField("tileScale", TypeF32, Offset(mTileScale, RibbonData),
|
||||
"How much to scale each 'tile' with, where 1 means the material is stretched"
|
||||
"across the whole ribbon. (If TexcoordsRelativeToDistance is true, this is in meters.)");
|
||||
addField("fixedTexcoords", TypeBool, Offset(mFixedTexcoords, RibbonData),
|
||||
"If true, this prevents 'floating' texture coordinates.");
|
||||
addField("texcoordsRelativeToDistance", TypeBool, Offset(mTexcoordsRelativeToDistance, RibbonData),
|
||||
"If true, texture coordinates are scaled relative to distance, this prevents"
|
||||
"'stretched' textures.");
|
||||
|
||||
endGroup("Ribbon");
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool RibbonData::onAdd()
|
||||
{
|
||||
if(!Parent::onAdd())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool RibbonData::preload(bool server, String &errorBuffer)
|
||||
{
|
||||
if (Parent::preload(server, errorBuffer) == false)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void RibbonData::packData(BitStream* stream)
|
||||
{
|
||||
Parent::packData(stream);
|
||||
|
||||
for (U8 i = 0; i < NumFields; i++) {
|
||||
stream->write(mSizes[i]);
|
||||
stream->write(mColours[i]);
|
||||
stream->write(mTimes[i]);
|
||||
}
|
||||
|
||||
stream->write(mRibbonLength);
|
||||
stream->writeString(mMatName);
|
||||
stream->writeFlag(mUseFadeOut);
|
||||
stream->write(mFadeAwayStep);
|
||||
stream->write(segmentsPerUpdate);
|
||||
stream->write(mTileScale);
|
||||
stream->writeFlag(mFixedTexcoords);
|
||||
stream->writeFlag(mTexcoordsRelativeToDistance);
|
||||
}
|
||||
|
||||
void RibbonData::unpackData(BitStream* stream)
|
||||
{
|
||||
Parent::unpackData(stream);
|
||||
|
||||
for (U8 i = 0; i < NumFields; i++) {
|
||||
stream->read(&mSizes[i]);
|
||||
stream->read(&mColours[i]);
|
||||
stream->read(&mTimes[i]);
|
||||
}
|
||||
|
||||
stream->read(&mRibbonLength);
|
||||
mMatName = StringTable->insert(stream->readSTString());
|
||||
mUseFadeOut = stream->readFlag();
|
||||
stream->read(&mFadeAwayStep);
|
||||
stream->read(&segmentsPerUpdate);
|
||||
stream->read(&mTileScale);
|
||||
mFixedTexcoords = stream->readFlag();
|
||||
mTexcoordsRelativeToDistance = stream->readFlag();
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//--------------------------------------
|
||||
//
|
||||
Ribbon::Ribbon()
|
||||
{
|
||||
mTypeMask |= StaticObjectType;
|
||||
|
||||
VECTOR_SET_ASSOCIATION(mSegmentPoints);
|
||||
mSegmentPoints.clear();
|
||||
|
||||
mRibbonMat = NULL;
|
||||
|
||||
mUpdateBuffers = true;
|
||||
mDeleteOnEnd = false;
|
||||
mUseFadeOut = false;
|
||||
mFadeAwayStep = 1.0f;
|
||||
mFadeOut = 1.0f;
|
||||
|
||||
mNetFlags.clear(Ghostable);
|
||||
mNetFlags.set(IsGhost);
|
||||
|
||||
mRadiusSC = NULL;
|
||||
mRibbonProjSC = NULL;
|
||||
|
||||
mSegmentOffset = 0;
|
||||
mSegmentIdx = 0;
|
||||
|
||||
mTravelledDistance = 0;
|
||||
}
|
||||
|
||||
Ribbon::~Ribbon()
|
||||
{
|
||||
//Make sure we cleanup
|
||||
SAFE_DELETE(mRibbonMat);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void Ribbon::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
bool Ribbon::onAdd()
|
||||
{
|
||||
if(!Parent::onAdd())
|
||||
return false;
|
||||
|
||||
// add to client side mission cleanup
|
||||
SimGroup *cleanup = dynamic_cast<SimGroup *>( Sim::findObject( "ClientMissionCleanup") );
|
||||
if( cleanup != NULL )
|
||||
{
|
||||
cleanup->addObject( this );
|
||||
}
|
||||
else
|
||||
{
|
||||
AssertFatal( false, "Error, could not find ClientMissionCleanup group" );
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isServerObject()) {
|
||||
|
||||
if(GFX->getPixelShaderVersion() >= 1.1 && dStrlen(mDataBlock->mMatName) > 0 )
|
||||
{
|
||||
mRibbonMat = MATMGR->createMatInstance( mDataBlock->mMatName );
|
||||
GFXStateBlockDesc desc;
|
||||
desc.setZReadWrite( true, false );
|
||||
desc.cullDefined = true;
|
||||
desc.cullMode = GFXCullNone;
|
||||
desc.setBlend(true, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha);
|
||||
|
||||
desc.samplersDefined = true;
|
||||
|
||||
GFXSamplerStateDesc sDesc(GFXSamplerStateDesc::getClampLinear());
|
||||
sDesc.addressModeV = GFXAddressWrap;
|
||||
|
||||
desc.samplers[0] = sDesc;
|
||||
|
||||
mRibbonMat->addStateBlockDesc( desc );
|
||||
mRibbonMat->init(MATMGR->getDefaultFeatures(), getGFXVertexFormat<GFXVertexPCNTT>());
|
||||
|
||||
mRadiusSC = mRibbonMat->getMaterialParameterHandle( "$radius" );
|
||||
mRibbonProjSC = mRibbonMat->getMaterialParameterHandle( "$ribbonProj" );
|
||||
|
||||
} else {
|
||||
Con::warnf( "Invalid Material name: %s: for Ribbon", mDataBlock->mMatName );
|
||||
#ifdef TORQUE_DEBUG
|
||||
Con::warnf( "- This could be caused by having the shader data datablocks in server-only code." );
|
||||
#endif
|
||||
mRibbonMat = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
mObjBox.minExtents.set( 1.0f, 1.0f, 1.0f );
|
||||
mObjBox.maxExtents.set( 2.0f, 2.0f, 2.0f );
|
||||
// Reset the World Box.
|
||||
resetWorldBox();
|
||||
// Set the Render Transform.
|
||||
setRenderTransform(mObjToWorld);
|
||||
|
||||
addToScene();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Ribbon::onRemove()
|
||||
{
|
||||
|
||||
removeFromScene();
|
||||
SAFE_DELETE(mRibbonMat);
|
||||
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
||||
|
||||
bool Ribbon::onNewDataBlock(GameBaseData* dptr, bool reload)
|
||||
{
|
||||
mDataBlock = dynamic_cast<RibbonData*>(dptr);
|
||||
if (!mDataBlock || !Parent::onNewDataBlock(dptr, reload))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Ribbon::processTick(const Move* move)
|
||||
{
|
||||
Parent::processTick(move);
|
||||
|
||||
if (mDeleteOnEnd) {
|
||||
|
||||
if (mUseFadeOut) {
|
||||
|
||||
if (mFadeOut <= 0.0f) {
|
||||
mFadeOut = 0.0f;
|
||||
//delete this class
|
||||
mDeleteOnEnd = false;
|
||||
safeDeleteObject();
|
||||
return;
|
||||
}
|
||||
mFadeOut -= mFadeAwayStep;
|
||||
if (mFadeOut < 0.0f) {
|
||||
mFadeOut = 0.0f;
|
||||
}
|
||||
|
||||
mUpdateBuffers = true;
|
||||
|
||||
} else {
|
||||
//if (mSegmentPoints.size() == 0) {
|
||||
//delete this class
|
||||
mDeleteOnEnd = false;
|
||||
safeDeleteObject();
|
||||
return;
|
||||
//}
|
||||
//mSegmentPoints.pop_back();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void Ribbon::advanceTime(F32 dt)
|
||||
{
|
||||
Parent::advanceTime(dt);
|
||||
}
|
||||
|
||||
void Ribbon::interpolateTick(F32 delta)
|
||||
{
|
||||
Parent::interpolateTick(delta);
|
||||
}
|
||||
|
||||
void Ribbon::addSegmentPoint(Point3F &point, MatrixF &mat) {
|
||||
|
||||
//update our position
|
||||
setRenderTransform(mat);
|
||||
MatrixF xform(true);
|
||||
xform.setColumn(3, point);
|
||||
setTransform(xform);
|
||||
|
||||
if(mSegmentIdx < mDataBlock->mSegmentSkipAmount)
|
||||
{
|
||||
mSegmentIdx++;
|
||||
return;
|
||||
}
|
||||
|
||||
mSegmentIdx = 0;
|
||||
|
||||
U32 segmentsToDelete = checkRibbonDistance(mDataBlock->segmentsPerUpdate);
|
||||
|
||||
for (U32 i = 0; i < segmentsToDelete; i++) {
|
||||
U32 last = mSegmentPoints.size() - 1;
|
||||
if (last < 0)
|
||||
break;
|
||||
mTravelledDistance += last ? (mSegmentPoints[last] - mSegmentPoints[last-1]).len() : 0;
|
||||
mSegmentPoints.pop_back();
|
||||
mUpdateBuffers = true;
|
||||
mSegmentOffset++;
|
||||
}
|
||||
|
||||
//If there is no other points, just add a new one.
|
||||
if (mSegmentPoints.size() == 0) {
|
||||
|
||||
mSegmentPoints.push_front(point);
|
||||
mUpdateBuffers = true;
|
||||
return;
|
||||
}
|
||||
|
||||
Point3F startPoint = mSegmentPoints[0];
|
||||
|
||||
//add X points based on how many segments Per Update from last point to current point
|
||||
for (U32 i = 0; i < mDataBlock->segmentsPerUpdate; i++) {
|
||||
|
||||
F32 interp = (F32(i+1) / (F32)mDataBlock->segmentsPerUpdate);
|
||||
//(end - start) * percentage) + start
|
||||
Point3F derivedPoint = ((point - startPoint) * interp) + startPoint;
|
||||
|
||||
mSegmentPoints.push_front(derivedPoint);
|
||||
mUpdateBuffers = true;
|
||||
}
|
||||
|
||||
if (mSegmentPoints.size() > 1) {
|
||||
|
||||
Point3F pointA = mSegmentPoints[mSegmentPoints.size()-1];
|
||||
Point3F pointB = mSegmentPoints[0];
|
||||
|
||||
Point3F diffSize = pointA - pointB;
|
||||
|
||||
if (diffSize.x == 0.0f)
|
||||
diffSize.x = 1.0f;
|
||||
|
||||
if (diffSize.y == 0.0f)
|
||||
diffSize.y = 1.0f;
|
||||
|
||||
if (diffSize.z == 0.0f)
|
||||
diffSize.z = 1.0f;
|
||||
|
||||
Box3F objBox;
|
||||
objBox.minExtents.set( diffSize * -1 );
|
||||
objBox.maxExtents.set( diffSize );
|
||||
|
||||
if (objBox.minExtents.x > objBox.maxExtents.x) {
|
||||
F32 tmp = objBox.minExtents.x;
|
||||
objBox.minExtents.x = objBox.maxExtents.x;
|
||||
objBox.maxExtents.x = tmp;
|
||||
}
|
||||
if (objBox.minExtents.y > objBox.maxExtents.y) {
|
||||
F32 tmp = objBox.minExtents.y;
|
||||
objBox.minExtents.y = objBox.maxExtents.y;
|
||||
objBox.maxExtents.y = tmp;
|
||||
}
|
||||
if (objBox.minExtents.z > objBox.maxExtents.z) {
|
||||
F32 tmp = objBox.minExtents.z;
|
||||
objBox.minExtents.z = objBox.maxExtents.z;
|
||||
objBox.maxExtents.z = tmp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (objBox.isValidBox()) {
|
||||
mObjBox = objBox;
|
||||
// Reset the World Box.
|
||||
resetWorldBox();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Ribbon::deleteOnEnd() {
|
||||
|
||||
mDeleteOnEnd = true;
|
||||
mUseFadeOut = mDataBlock->mUseFadeOut;
|
||||
mFadeAwayStep = mDataBlock->mFadeAwayStep;
|
||||
|
||||
}
|
||||
|
||||
U32 Ribbon::checkRibbonDistance(S32 segments) {
|
||||
|
||||
S32 len = mSegmentPoints.size();
|
||||
S32 difference = (mDataBlock->mRibbonLength/(mDataBlock->mSegmentSkipAmount+1)) - len;
|
||||
|
||||
if (difference < 0)
|
||||
return mAbs(difference);
|
||||
|
||||
return 0; //do not delete any points
|
||||
}
|
||||
|
||||
void Ribbon::setShaderParams() {
|
||||
|
||||
F32 numSegments = (F32)mSegmentPoints.size();
|
||||
F32 length = (F32)mDataBlock->mRibbonLength;
|
||||
Point3F radius(numSegments / length, numSegments, length);
|
||||
MaterialParameters* matParams = mRibbonMat->getMaterialParameters();
|
||||
matParams->setSafe( mRadiusSC, radius );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//U32 Ribbon::packUpdate(NetConnection* con, U32 mask, BitStream* stream)
|
||||
//{
|
||||
// U32 retMask = Parent::packUpdate(con, mask, stream);
|
||||
// return retMask;
|
||||
//}
|
||||
//
|
||||
//void Ribbon::unpackUpdate(NetConnection* con, BitStream* stream)
|
||||
//{
|
||||
// Parent::unpackUpdate(con, stream);
|
||||
//}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
void Ribbon::prepRenderImage(SceneRenderState *state)
|
||||
{
|
||||
if (mFadeOut == 0.0f)
|
||||
return;
|
||||
|
||||
if(!mRibbonMat)
|
||||
return;
|
||||
|
||||
if (mDeleteOnEnd == true && mUseFadeOut == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We only render during the normal diffuse render pass.
|
||||
if( !state->isDiffusePass() )
|
||||
return;
|
||||
|
||||
U32 segments = mSegmentPoints.size();
|
||||
if (segments < 2)
|
||||
return;
|
||||
|
||||
MeshRenderInst *ri = state->getRenderPass()->allocInst<MeshRenderInst>();
|
||||
ri->type = RenderPassManager::RIT_Translucent;
|
||||
ri->translucentSort = true;
|
||||
ri->sortDistSq = ( mSegmentPoints[0] - state->getCameraPosition() ).lenSquared();
|
||||
|
||||
RenderPassManager *renderPass = state->getRenderPass();
|
||||
MatrixF *proj = renderPass->allocUniqueXform(MatrixF( true ));
|
||||
proj->mul(GFX->getProjectionMatrix());
|
||||
proj->mul(GFX->getWorldMatrix());
|
||||
ri->objectToWorld = &MatrixF::Identity;
|
||||
ri->worldToCamera = &MatrixF::Identity;
|
||||
ri->projection = proj;
|
||||
ri->matInst = mRibbonMat;
|
||||
|
||||
// Set up our vertex buffer and primitive buffer
|
||||
if(mUpdateBuffers)
|
||||
createBuffers(state, verts, primBuffer, segments);
|
||||
|
||||
ri->vertBuff = &verts;
|
||||
ri->primBuff = &primBuffer;
|
||||
ri->visibility = 1.0f;
|
||||
|
||||
ri->prim = renderPass->allocPrim();
|
||||
ri->prim->type = GFXTriangleList;
|
||||
ri->prim->minIndex = 0;
|
||||
ri->prim->startIndex = 0;
|
||||
ri->prim->numPrimitives = (segments-1) * 2;
|
||||
ri->prim->startVertex = 0;
|
||||
ri->prim->numVertices = segments * 2;
|
||||
|
||||
if (mRibbonMat) {
|
||||
ri->defaultKey = mRibbonMat->getStateHint();
|
||||
} else {
|
||||
ri->defaultKey = 1;
|
||||
}
|
||||
ri->defaultKey2 = (U32)ri->vertBuff; // Not 64bit safe!
|
||||
|
||||
state->getRenderPass()->addInst(ri);
|
||||
}
|
||||
|
||||
void Ribbon::createBuffers(SceneRenderState *state, GFXVertexBufferHandle<GFXVertexPCNTT> &verts, GFXPrimitiveBufferHandle &pb, U32 segments) {
|
||||
PROFILE_SCOPE( Ribbon_createBuffers );
|
||||
Point3F cameraPos = state->getCameraPosition();
|
||||
U32 count = 0;
|
||||
U32 indexCount = 0;
|
||||
verts.set(GFX, (segments*2), GFXBufferTypeDynamic);
|
||||
|
||||
// create index buffer based on that size
|
||||
U32 indexListSize = (segments-1) * 6;
|
||||
pb.set( GFX, indexListSize, 0, GFXBufferTypeDynamic );
|
||||
U16 *indices = NULL;
|
||||
|
||||
verts.lock();
|
||||
pb.lock( &indices );
|
||||
F32 totalLength = 0;
|
||||
if(mDataBlock->mTexcoordsRelativeToDistance)
|
||||
{
|
||||
for (U32 i = 0; i < segments; i++)
|
||||
if (i != 0)
|
||||
totalLength += (mSegmentPoints[i] - mSegmentPoints[i-1]).len();
|
||||
}
|
||||
|
||||
U8 fixedAppend = 0;
|
||||
F32 curLength = 0;
|
||||
for (U32 i = 0; i < segments; i++) {
|
||||
|
||||
F32 interpol = ((F32)i / (F32)(segments-1));
|
||||
Point3F leftvert = mSegmentPoints[i];
|
||||
Point3F rightvert = mSegmentPoints[i];
|
||||
F32 tRadius = mDataBlock->mSizes[0];
|
||||
ColorF tColor = mDataBlock->mColours[0];
|
||||
|
||||
for (U8 j = 0; j < RibbonData::NumFields-1; j++) {
|
||||
|
||||
F32 curPosition = mDataBlock->mTimes[j];
|
||||
F32 curRadius = mDataBlock->mSizes[j];
|
||||
ColorF curColor = mDataBlock->mColours[j];
|
||||
F32 nextPosition = mDataBlock->mTimes[j+1];
|
||||
F32 nextRadius = mDataBlock->mSizes[j+1];
|
||||
ColorF nextColor = mDataBlock->mColours[j+1];
|
||||
|
||||
if ( curPosition < 0
|
||||
|| curPosition > interpol )
|
||||
break;
|
||||
F32 positionDiff = (interpol - curPosition) / (nextPosition - curPosition);
|
||||
|
||||
tRadius = curRadius + (nextRadius - curRadius) * positionDiff;
|
||||
tColor.interpolate(curColor, nextColor, positionDiff);
|
||||
}
|
||||
|
||||
Point3F diff;
|
||||
F32 length;
|
||||
if (i == 0) {
|
||||
diff = mSegmentPoints[i+1] - mSegmentPoints[i];
|
||||
length = 0;
|
||||
} else if (i == segments-1) {
|
||||
diff = mSegmentPoints[i] - mSegmentPoints[i-1];
|
||||
length = diff.len();
|
||||
} else {
|
||||
diff = mSegmentPoints[i+1] - mSegmentPoints[i-1];
|
||||
length = (mSegmentPoints[i] - mSegmentPoints[i-1]).len();
|
||||
}
|
||||
|
||||
//left point
|
||||
Point3F eyeMinPos = cameraPos - leftvert;
|
||||
Point3F perpendicular = mCross(diff, eyeMinPos);
|
||||
perpendicular.normalize();
|
||||
perpendicular = perpendicular * tRadius * -1.0f;
|
||||
perpendicular += mSegmentPoints[i];
|
||||
|
||||
verts[count].point.set(perpendicular);
|
||||
ColorF color = tColor;
|
||||
|
||||
if (mDataBlock->mUseFadeOut)
|
||||
color.alpha *= mFadeOut;
|
||||
|
||||
F32 texCoords;
|
||||
if(mDataBlock->mFixedTexcoords && !mDataBlock->mTexcoordsRelativeToDistance)
|
||||
{
|
||||
U32 fixedIdx = (i+mDataBlock->mRibbonLength-mSegmentOffset)%mDataBlock->mRibbonLength;
|
||||
if(fixedIdx == 0 && i > 0)
|
||||
fixedAppend++;
|
||||
F32 fixedInterpol = (F32)fixedIdx / (F32)(mDataBlock->mRibbonLength);
|
||||
fixedInterpol += fixedAppend;
|
||||
texCoords = (1.0f - fixedInterpol)*mDataBlock->mTileScale;
|
||||
}
|
||||
else if(mDataBlock->mTexcoordsRelativeToDistance)
|
||||
texCoords = (mTravelledDistance + (totalLength - (curLength + length)))*mDataBlock->mTileScale;
|
||||
else
|
||||
texCoords = (1.0f - interpol)*mDataBlock->mTileScale;
|
||||
|
||||
verts[count].color = color;
|
||||
verts[count].texCoord[1] = Point2F(interpol, 0);
|
||||
verts[count].texCoord[0] = Point2F(0.0f, texCoords);
|
||||
verts[count].normal.set(diff);
|
||||
|
||||
//Triangle strip style indexing, so grab last 2
|
||||
if (count > 1) {
|
||||
indices[indexCount] = count-2;
|
||||
indexCount++;
|
||||
indices[indexCount] = count;
|
||||
indexCount++;
|
||||
indices[indexCount] = count-1;
|
||||
indexCount++;
|
||||
}
|
||||
count++;
|
||||
|
||||
eyeMinPos = cameraPos - rightvert;
|
||||
perpendicular = mCross(diff, eyeMinPos);
|
||||
perpendicular.normalize();
|
||||
perpendicular = perpendicular * tRadius;
|
||||
perpendicular += mSegmentPoints[i];
|
||||
|
||||
verts[count].point.set(perpendicular);
|
||||
color = tColor;
|
||||
|
||||
if (mDataBlock->mUseFadeOut)
|
||||
color.alpha *= mFadeOut;
|
||||
|
||||
verts[count].color = color;
|
||||
verts[count].texCoord[1] = Point2F(interpol, 1);
|
||||
verts[count].texCoord[0] = Point2F(1.0f, texCoords);
|
||||
verts[count].normal.set(diff);
|
||||
|
||||
//Triangle strip style indexing, so grab last 2
|
||||
if (count > 1) {
|
||||
indices[indexCount] = count-2;
|
||||
indexCount++;
|
||||
indices[indexCount] = count-1;
|
||||
indexCount++;
|
||||
indices[indexCount] = count;
|
||||
indexCount++;
|
||||
}
|
||||
count++;
|
||||
curLength += length;
|
||||
}
|
||||
|
||||
Point3F pointA = verts[count-1].point;
|
||||
Point3F pointB = verts[0].point;
|
||||
|
||||
pb.unlock();
|
||||
verts.unlock();
|
||||
|
||||
Point3F diffSize = pointA - pointB;
|
||||
|
||||
Box3F objBox;
|
||||
objBox.minExtents.set( diffSize * -1 );
|
||||
objBox.maxExtents.set( diffSize );
|
||||
|
||||
if (objBox.minExtents.x > objBox.maxExtents.x) {
|
||||
F32 tmp = objBox.minExtents.x;
|
||||
objBox.minExtents.x = objBox.maxExtents.x;
|
||||
objBox.maxExtents.x = tmp;
|
||||
}
|
||||
if (objBox.minExtents.y > objBox.maxExtents.y) {
|
||||
F32 tmp = objBox.minExtents.y;
|
||||
objBox.minExtents.y = objBox.maxExtents.y;
|
||||
objBox.maxExtents.y = tmp;
|
||||
}
|
||||
if (objBox.minExtents.z > objBox.maxExtents.z) {
|
||||
F32 tmp = objBox.minExtents.z;
|
||||
objBox.minExtents.z = objBox.maxExtents.z;
|
||||
objBox.maxExtents.z = tmp;
|
||||
}
|
||||
|
||||
if (objBox.isValidBox()) {
|
||||
mObjBox = objBox;
|
||||
// Reset the World Box.
|
||||
resetWorldBox();
|
||||
}
|
||||
|
||||
mUpdateBuffers = false;
|
||||
}
|
||||
142
Engine/source/T3D/fx/ribbon.h
Normal file
142
Engine/source/T3D/fx/ribbon.h
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2014 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 _RIBBON_H_
|
||||
#define _RIBBON_H_
|
||||
|
||||
#ifndef _GAMEBASE_H_
|
||||
#include "T3D/gameBase/gameBase.h"
|
||||
#endif
|
||||
|
||||
#ifndef _GFXPRIMITIVEBUFFER_H_
|
||||
#include "gfx/gfxPrimitiveBuffer.h"
|
||||
#endif
|
||||
|
||||
#ifndef _GFXVERTEXBUFFER_H_
|
||||
#include "gfx/gfxVertexBuffer.h"
|
||||
#endif
|
||||
|
||||
#include "materials/materialParameters.h"
|
||||
#include "math/util/matrixSet.h"
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
class RibbonData : public GameBaseData
|
||||
{
|
||||
typedef GameBaseData Parent;
|
||||
|
||||
protected:
|
||||
bool onAdd();
|
||||
|
||||
public:
|
||||
|
||||
enum Constants
|
||||
{
|
||||
NumFields = 4
|
||||
};
|
||||
|
||||
F32 mSizes[NumFields]; ///< The radius for each keyframe.
|
||||
ColorF mColours[NumFields]; ///< The colour of the ribbon for each keyframe.
|
||||
F32 mTimes[NumFields]; ///< The relative time for each keyframe.
|
||||
|
||||
U32 mRibbonLength; ///< The amount of segments that will make up the ribbon.
|
||||
S32 segmentsPerUpdate; ///< Amount of segments to add each update.
|
||||
S32 mSegmentSkipAmount; ///< The amount of segments to skip each time segments are added.
|
||||
|
||||
bool mUseFadeOut; ///< If true, the ribbon will fade away after deletion.
|
||||
F32 mFadeAwayStep; ///< How quickly the ribbons is faded away after deletion.
|
||||
StringTableEntry mMatName; ///< The material for the ribbon.
|
||||
F32 mTileScale; ///< A scalar to scale the texcoord.
|
||||
bool mFixedTexcoords; ///< If true, texcoords will stay the same over the lifetime for each segment.
|
||||
bool mTexcoordsRelativeToDistance; ///< If true, texcoords will not be stretched if the distance between 2 segments are long.
|
||||
|
||||
RibbonData();
|
||||
|
||||
void packData(BitStream*);
|
||||
void unpackData(BitStream*);
|
||||
bool preload(bool server, String &errorBuffer);
|
||||
|
||||
static void initPersistFields();
|
||||
DECLARE_CONOBJECT(RibbonData);
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
class Ribbon : public GameBase
|
||||
{
|
||||
typedef GameBase Parent;
|
||||
|
||||
RibbonData* mDataBlock;
|
||||
|
||||
bool mDeleteOnEnd; ///< If true, the ribbon should delete itself as soon as the last segment is deleted
|
||||
bool mUseFadeOut; ///< If true, the ribbon will fade away upon deletion
|
||||
F32 mFadeAwayStep; ///< How quickly the ribbons is faded away after deletion.
|
||||
F32 mFadeOut;
|
||||
F32 mTravelledDistance; ///< How far the ribbon has travelled in it's lifetime.
|
||||
|
||||
Vector<Point3F> mSegmentPoints; ///< The points in space where the ribbon has spawned segments.
|
||||
U32 mSegmentOffset;
|
||||
U32 mSegmentIdx;
|
||||
|
||||
bool mUpdateBuffers; ///< If true, the vertex buffers need to be updated.
|
||||
BaseMatInstance *mRibbonMat;
|
||||
MaterialParameterHandle* mRadiusSC;
|
||||
MaterialParameterHandle* mRibbonProjSC;
|
||||
GFXPrimitiveBufferHandle primBuffer;
|
||||
GFXVertexBufferHandle<GFXVertexPCNTT> verts;
|
||||
|
||||
protected:
|
||||
|
||||
bool onAdd();
|
||||
void processTick(const Move*);
|
||||
void advanceTime(F32);
|
||||
void interpolateTick(F32 delta);
|
||||
|
||||
// Rendering
|
||||
void prepRenderImage(SceneRenderState *state);
|
||||
void setShaderParams();
|
||||
|
||||
///Checks to see if ribbon is too long
|
||||
U32 checkRibbonDistance(S32 segments);
|
||||
|
||||
/// Construct the vertex and primitive buffers
|
||||
void createBuffers(SceneRenderState *state, GFXVertexBufferHandle<GFXVertexPCNTT> &verts, GFXPrimitiveBufferHandle &pb, U32 segments);
|
||||
|
||||
public:
|
||||
Ribbon();
|
||||
~Ribbon();
|
||||
|
||||
DECLARE_CONOBJECT(Ribbon);
|
||||
static void initPersistFields();
|
||||
bool onNewDataBlock(GameBaseData*,bool);
|
||||
void onRemove();
|
||||
|
||||
/// Used to add another segment to the ribbon.
|
||||
void addSegmentPoint(Point3F &point, MatrixF &mat);
|
||||
|
||||
/// Delete all segments.
|
||||
void clearSegments() { mSegmentPoints.clear(); }
|
||||
|
||||
/// Delete the ribbon when all segments have been deleted.
|
||||
void deleteOnEnd();
|
||||
};
|
||||
|
||||
#endif // _H_RIBBON
|
||||
|
||||
324
Engine/source/T3D/fx/ribbonNode.cpp
Normal file
324
Engine/source/T3D/fx/ribbonNode.cpp
Normal file
|
|
@ -0,0 +1,324 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2014 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 "ribbonNode.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "core/stream/bitStream.h"
|
||||
#include "T3D/fx/ribbon.h"
|
||||
#include "math/mathIO.h"
|
||||
#include "sim/netConnection.h"
|
||||
#include "console/engineAPI.h"
|
||||
|
||||
IMPLEMENT_CO_DATABLOCK_V1(RibbonNodeData);
|
||||
IMPLEMENT_CO_NETOBJECT_V1(RibbonNode);
|
||||
|
||||
ConsoleDocClass( RibbonNodeData,
|
||||
"@brief Contains additional data to be associated with a RibbonNode."
|
||||
"@ingroup FX\n"
|
||||
);
|
||||
|
||||
ConsoleDocClass( RibbonNode, ""
|
||||
);
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// RibbonNodeData
|
||||
//-----------------------------------------------------------------------------
|
||||
RibbonNodeData::RibbonNodeData()
|
||||
{
|
||||
}
|
||||
|
||||
RibbonNodeData::~RibbonNodeData()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// initPersistFields
|
||||
//-----------------------------------------------------------------------------
|
||||
void RibbonNodeData::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// RibbonNode
|
||||
//-----------------------------------------------------------------------------
|
||||
RibbonNode::RibbonNode()
|
||||
{
|
||||
// Todo: ScopeAlways?
|
||||
mNetFlags.set(Ghostable);
|
||||
mTypeMask |= EnvironmentObjectType;
|
||||
|
||||
mActive = true;
|
||||
|
||||
mDataBlock = NULL;
|
||||
mRibbonDatablock = NULL;
|
||||
mRibbonDatablockId = 0;
|
||||
mRibbon = NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
RibbonNode::~RibbonNode()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// initPersistFields
|
||||
//-----------------------------------------------------------------------------
|
||||
void RibbonNode::initPersistFields()
|
||||
{
|
||||
addField( "active", TYPEID< bool >(), Offset(mActive,RibbonNode),
|
||||
"Controls whether ribbon is emitted from this node." );
|
||||
addField( "ribbon", TYPEID< RibbonData >(), Offset(mRibbonDatablock, RibbonNode),
|
||||
"Datablock to use for the ribbon." );
|
||||
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// onAdd
|
||||
//-----------------------------------------------------------------------------
|
||||
bool RibbonNode::onAdd()
|
||||
{
|
||||
if( !Parent::onAdd() )
|
||||
return false;
|
||||
|
||||
if( !mRibbonDatablock && mRibbonDatablockId != 0 )
|
||||
{
|
||||
if( Sim::findObject(mRibbonDatablockId, mRibbonDatablock) == false )
|
||||
Con::errorf(ConsoleLogEntry::General, "RibbonNode::onAdd: Invalid packet, bad datablockId(mRibbonDatablock): %d", mRibbonDatablockId);
|
||||
}
|
||||
|
||||
if( isClientObject() )
|
||||
{
|
||||
setRibbonDatablock( mRibbonDatablock );
|
||||
}
|
||||
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 RibbonNode::onRemove()
|
||||
{
|
||||
removeFromScene();
|
||||
if( isClientObject() )
|
||||
{
|
||||
if( mRibbon )
|
||||
{
|
||||
mRibbon->deleteOnEnd();
|
||||
mRibbon = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// onNewDataBlock
|
||||
//-----------------------------------------------------------------------------
|
||||
bool RibbonNode::onNewDataBlock( GameBaseData *dptr, bool reload )
|
||||
{
|
||||
mDataBlock = dynamic_cast<RibbonNodeData*>( dptr );
|
||||
if ( !mDataBlock || !Parent::onNewDataBlock( dptr, reload ) )
|
||||
return false;
|
||||
|
||||
// Todo: Uncomment if this is a "leaf" class
|
||||
scriptOnNewDataBlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void RibbonNode::inspectPostApply()
|
||||
{
|
||||
Parent::inspectPostApply();
|
||||
setMaskBits(StateMask | EmitterDBMask);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// processTick
|
||||
//-----------------------------------------------------------------------------
|
||||
void RibbonNode::processTick(const Move* move)
|
||||
{
|
||||
Parent::processTick(move);
|
||||
|
||||
if ( isMounted() )
|
||||
{
|
||||
MatrixF mat;
|
||||
mMount.object->getMountTransform( mMount.node, mMount.xfm, &mat );
|
||||
setTransform( mat );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// advanceTime
|
||||
//-----------------------------------------------------------------------------
|
||||
void RibbonNode::advanceTime(F32 dt)
|
||||
{
|
||||
Parent::advanceTime(dt);
|
||||
|
||||
if(!mActive || mRibbon.isNull() || !mDataBlock)
|
||||
return;
|
||||
|
||||
MatrixF trans(getTransform());
|
||||
Point3F pos = getPosition();
|
||||
mRibbon->addSegmentPoint(pos, trans);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// packUpdate
|
||||
//-----------------------------------------------------------------------------
|
||||
U32 RibbonNode::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(mRibbonDatablock != NULL) )
|
||||
{
|
||||
stream->writeRangedU32(mRibbonDatablock->getId(), DataBlockObjectIdFirst,
|
||||
DataBlockObjectIdLast);
|
||||
}
|
||||
}
|
||||
|
||||
if ( stream->writeFlag( mask & StateMask ) )
|
||||
{
|
||||
stream->writeFlag( mActive );
|
||||
}
|
||||
|
||||
return retMask;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// unpackUpdate
|
||||
//-----------------------------------------------------------------------------
|
||||
void RibbonNode::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() )
|
||||
{
|
||||
mRibbonDatablockId = stream->readFlag() ?
|
||||
stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast) : 0;
|
||||
|
||||
RibbonData *emitterDB = NULL;
|
||||
Sim::findObject( mRibbonDatablockId, emitterDB );
|
||||
if ( isProperlyAdded() )
|
||||
setRibbonDatablock( emitterDB );
|
||||
}
|
||||
|
||||
if ( stream->readFlag() )
|
||||
{
|
||||
mActive = stream->readFlag();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// setRibbonDatablock
|
||||
//-----------------------------------------------------------------------------
|
||||
void RibbonNode::setRibbonDatablock(RibbonData* data)
|
||||
{
|
||||
if ( isServerObject() )
|
||||
{
|
||||
setMaskBits( EmitterDBMask );
|
||||
}
|
||||
else
|
||||
{
|
||||
Ribbon* pRibbon = NULL;
|
||||
if ( data )
|
||||
{
|
||||
// Create emitter with new datablock
|
||||
pRibbon = new Ribbon;
|
||||
pRibbon->onNewDataBlock( data, false );
|
||||
if( pRibbon->registerObject() == false )
|
||||
{
|
||||
Con::warnf(ConsoleLogEntry::General, "Could not register base ribbon of class: %s", data->getName() ? data->getName() : data->getIdString() );
|
||||
delete pRibbon;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Replace emitter
|
||||
if ( mRibbon )
|
||||
mRibbon->deleteOnEnd();
|
||||
|
||||
mRibbon = pRibbon;
|
||||
}
|
||||
|
||||
mRibbonDatablock = data;
|
||||
}
|
||||
|
||||
DefineEngineMethod(RibbonNode, setRibbonDatablock, void, (RibbonData* ribbonDatablock), (0),
|
||||
"Assigns the datablock for this ribbon node.\n"
|
||||
"@param ribbonDatablock RibbonData datablock to assign\n"
|
||||
"@tsexample\n"
|
||||
"// Assign a new emitter datablock\n"
|
||||
"%emitter.setRibbonDatablock( %ribbonDatablock );\n"
|
||||
"@endtsexample\n" )
|
||||
{
|
||||
if ( !ribbonDatablock )
|
||||
{
|
||||
Con::errorf("RibbonData datablock could not be found when calling setRibbonDataBlock in ribbonNode.");
|
||||
return;
|
||||
}
|
||||
|
||||
object->setRibbonDatablock(ribbonDatablock);
|
||||
}
|
||||
|
||||
DefineEngineMethod(RibbonNode, setActive, void, (bool active),,
|
||||
"Turns the ribbon on or off.\n"
|
||||
"@param active New ribbon state\n" )
|
||||
{
|
||||
object->setActive( active );
|
||||
}
|
||||
105
Engine/source/T3D/fx/ribbonNode.h
Normal file
105
Engine/source/T3D/fx/ribbonNode.h
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2014 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 _RIBBON_NODE_H_
|
||||
#define _RIBBON_NODE_H_
|
||||
|
||||
#ifndef _GAMEBASE_H_
|
||||
#include "T3D/gameBase/gameBase.h"
|
||||
#endif
|
||||
|
||||
class RibbonData;
|
||||
class Ribbon;
|
||||
|
||||
//*****************************************************************************
|
||||
// ParticleEmitterNodeData
|
||||
//*****************************************************************************
|
||||
class RibbonNodeData : public GameBaseData
|
||||
{
|
||||
typedef GameBaseData Parent;
|
||||
|
||||
public:
|
||||
F32 timeMultiple;
|
||||
|
||||
public:
|
||||
RibbonNodeData();
|
||||
~RibbonNodeData();
|
||||
|
||||
DECLARE_CONOBJECT(RibbonNodeData);
|
||||
static void initPersistFields();
|
||||
};
|
||||
|
||||
|
||||
//*****************************************************************************
|
||||
// ParticleEmitterNode
|
||||
//*****************************************************************************
|
||||
class RibbonNode : public GameBase
|
||||
{
|
||||
typedef GameBase Parent;
|
||||
|
||||
enum MaskBits
|
||||
{
|
||||
StateMask = Parent::NextFreeMask << 0,
|
||||
EmitterDBMask = Parent::NextFreeMask << 1,
|
||||
NextFreeMask = Parent::NextFreeMask << 2,
|
||||
};
|
||||
|
||||
RibbonNodeData* mDataBlock;
|
||||
|
||||
protected:
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
bool onNewDataBlock( GameBaseData *dptr, bool reload );
|
||||
void inspectPostApply();
|
||||
|
||||
RibbonData* mRibbonDatablock;
|
||||
S32 mRibbonDatablockId;
|
||||
|
||||
SimObjectPtr<Ribbon> mRibbon;
|
||||
|
||||
bool mActive;
|
||||
|
||||
public:
|
||||
RibbonNode();
|
||||
~RibbonNode();
|
||||
|
||||
Ribbon *getRibbonEmitter() {return mRibbon;}
|
||||
|
||||
// Time/Move Management
|
||||
|
||||
void processTick(const Move* move);
|
||||
void advanceTime(F32 dt);
|
||||
|
||||
DECLARE_CONOBJECT(RibbonNode);
|
||||
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 setRibbonDatablock(RibbonData* data);
|
||||
};
|
||||
|
||||
#endif // _RIBBON_NODE_H_
|
||||
|
||||
|
|
@ -303,6 +303,7 @@ bool SplashData::preload(bool server, String &errorStr)
|
|||
// Splash
|
||||
//--------------------------------------------------------------------------
|
||||
Splash::Splash()
|
||||
: mDataBlock( NULL )
|
||||
{
|
||||
dMemset( mEmitterList, 0, sizeof( mEmitterList ) );
|
||||
|
||||
|
|
@ -353,6 +354,12 @@ bool Splash::onAdd()
|
|||
if(!conn || !Parent::onAdd())
|
||||
return false;
|
||||
|
||||
if( !mDataBlock )
|
||||
{
|
||||
Con::errorf("Splash::onAdd - Fail - No datablock");
|
||||
return false;
|
||||
}
|
||||
|
||||
mDelayMS = mDataBlock->delayMS + sgRandom.randI( -mDataBlock->delayVariance, mDataBlock->delayVariance );
|
||||
mEndingMS = mDataBlock->lifetimeMS + sgRandom.randI( -mDataBlock->lifetimeVariance, mDataBlock->lifetimeVariance );
|
||||
|
||||
|
|
@ -408,8 +415,7 @@ void Splash::onRemove()
|
|||
|
||||
ringList.clear();
|
||||
|
||||
getSceneManager()->removeObjectFromScene(this);
|
||||
getContainer()->removeObject(this);
|
||||
removeFromScene();
|
||||
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -281,7 +281,8 @@ ConsoleMethod(GameConnection, setConnectArgs, void, 3, 17,
|
|||
|
||||
"@see GameConnection::onConnect()\n\n")
|
||||
{
|
||||
object->setConnectArgs(argc - 2, argv + 2);
|
||||
StringStackWrapper args(argc - 2, argv + 2);
|
||||
object->setConnectArgs(args.count(), args);
|
||||
}
|
||||
|
||||
void GameConnection::onTimedOut()
|
||||
|
|
@ -323,6 +324,7 @@ void GameConnection::onConnectionEstablished(bool isInitiator)
|
|||
|
||||
const char *argv[MaxConnectArgs + 2];
|
||||
argv[0] = "onConnect";
|
||||
argv[1] = NULL; // Filled in later
|
||||
for(U32 i = 0; i < mConnectArgc; i++)
|
||||
argv[i + 2] = mConnectArgv[i];
|
||||
// NOTE: Need to fallback to Con::execute() as IMPLEMENT_CALLBACK does not
|
||||
|
|
@ -442,7 +444,7 @@ bool GameConnection::readConnectRequest(BitStream *stream, const char **errorStr
|
|||
*errorString = "CR_INVALID_ARGS";
|
||||
return false;
|
||||
}
|
||||
const char *connectArgv[MaxConnectArgs + 3];
|
||||
ConsoleValueRef connectArgv[MaxConnectArgs + 3];
|
||||
for(U32 i = 0; i < mConnectArgc; i++)
|
||||
{
|
||||
char argString[256];
|
||||
|
|
@ -451,6 +453,7 @@ bool GameConnection::readConnectRequest(BitStream *stream, const char **errorStr
|
|||
connectArgv[i + 3] = mConnectArgv[i];
|
||||
}
|
||||
connectArgv[0] = "onConnectRequest";
|
||||
connectArgv[1] = NULL;
|
||||
char buffer[256];
|
||||
Net::addressToString(getNetAddress(), buffer);
|
||||
connectArgv[2] = buffer;
|
||||
|
|
@ -974,7 +977,7 @@ bool GameConnection::readDemoStartBlock(BitStream *stream)
|
|||
|
||||
void GameConnection::demoPlaybackComplete()
|
||||
{
|
||||
static const char *demoPlaybackArgv[1] = { "demoPlaybackComplete" };
|
||||
static ConsoleValueRef demoPlaybackArgv[1] = { "demoPlaybackComplete" };
|
||||
Sim::postCurrentEvent(Sim::getRootGroup(), new SimConsoleEvent(1, demoPlaybackArgv, false));
|
||||
Parent::demoPlaybackComplete();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -145,9 +145,10 @@ ConsoleFunction(containerFindFirst, const char*, 6, 6, "(int mask, Point3F point
|
|||
|
||||
//return the first element
|
||||
sgServerQueryIndex = 0;
|
||||
char *buff = Con::getReturnBuffer(100);
|
||||
static const U32 bufSize = 100;
|
||||
char *buff = Con::getReturnBuffer(bufSize);
|
||||
if (sgServerQueryList.mList.size())
|
||||
dSprintf(buff, 100, "%d", sgServerQueryList.mList[sgServerQueryIndex++]->getId());
|
||||
dSprintf(buff, bufSize, "%d", sgServerQueryList.mList[sgServerQueryIndex++]->getId());
|
||||
else
|
||||
buff[0] = '\0';
|
||||
|
||||
|
|
@ -162,9 +163,10 @@ ConsoleFunction( containerFindNext, const char*, 1, 1, "()"
|
|||
"@ingroup Game")
|
||||
{
|
||||
//return the next element
|
||||
char *buff = Con::getReturnBuffer(100);
|
||||
static const U32 bufSize = 100;
|
||||
char *buff = Con::getReturnBuffer(bufSize);
|
||||
if (sgServerQueryIndex < sgServerQueryList.mList.size())
|
||||
dSprintf(buff, 100, "%d", sgServerQueryList.mList[sgServerQueryIndex++]->getId());
|
||||
dSprintf(buff, bufSize, "%d", sgServerQueryList.mList[sgServerQueryIndex++]->getId());
|
||||
else
|
||||
buff[0] = '\0';
|
||||
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ GuiObjectView::GuiObjectView()
|
|||
{
|
||||
mCameraMatrix.identity();
|
||||
mCameraRot.set( 0.0f, 0.0f, 3.9f );
|
||||
mCameraPos.set( 0.0f, 1.75f, 1.25f );
|
||||
mCameraPos.set( 0.0f, 0.0f, 0.0f );
|
||||
mCameraMatrix.setColumn( 3, mCameraPos );
|
||||
mOrbitPos.set( 0.0f, 0.0f, 0.0f );
|
||||
|
||||
|
|
@ -520,9 +520,9 @@ void GuiObjectView::renderWorld( const RectI& updateRect )
|
|||
(
|
||||
gClientSceneGraph,
|
||||
SPT_Diffuse,
|
||||
SceneCameraState( GFX->getViewport(), frust, GFX->getWorldMatrix(), GFX->getProjectionMatrix() ),
|
||||
SceneCameraState( GFX->getViewport(), frust, MatrixF::Identity, GFX->getProjectionMatrix() ),
|
||||
renderPass,
|
||||
false
|
||||
true
|
||||
);
|
||||
|
||||
// Set up our TS render state here.
|
||||
|
|
|
|||
|
|
@ -1241,9 +1241,10 @@ DefineEngineMethod( Item, getLastStickyPos, const char*, (),,
|
|||
"@note Server side only.\n"
|
||||
)
|
||||
{
|
||||
char* ret = Con::getReturnBuffer(256);
|
||||
static const U32 bufSize = 256;
|
||||
char* ret = Con::getReturnBuffer(bufSize);
|
||||
if (object->isServerObject())
|
||||
dSprintf(ret, 255, "%g %g %g",
|
||||
dSprintf(ret, bufSize, "%g %g %g",
|
||||
object->mStickyCollisionPos.x,
|
||||
object->mStickyCollisionPos.y,
|
||||
object->mStickyCollisionPos.z);
|
||||
|
|
@ -1263,9 +1264,10 @@ DefineEngineMethod( Item, getLastStickyNormal, const char *, (),,
|
|||
"@note Server side only.\n"
|
||||
)
|
||||
{
|
||||
char* ret = Con::getReturnBuffer(256);
|
||||
static const U32 bufSize = 256;
|
||||
char* ret = Con::getReturnBuffer(bufSize);
|
||||
if (object->isServerObject())
|
||||
dSprintf(ret, 255, "%g %g %g",
|
||||
dSprintf(ret, bufSize, "%g %g %g",
|
||||
object->mStickyCollisionNormal.x,
|
||||
object->mStickyCollisionNormal.y,
|
||||
object->mStickyCollisionNormal.z);
|
||||
|
|
|
|||
|
|
@ -439,7 +439,7 @@ ConsoleMethod( LightBase, playAnimation, void, 2, 3, "( [LightAnimData anim] )\t
|
|||
LightAnimData *animData;
|
||||
if ( !Sim::findObject( argv[2], animData ) )
|
||||
{
|
||||
Con::errorf( "LightBase::playAnimation() - Invalid LightAnimData '%s'.", argv[2] );
|
||||
Con::errorf( "LightBase::playAnimation() - Invalid LightAnimData '%s'.", (const char*)argv[2] );
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -481,4 +481,4 @@ void LightBase::pauseAnimation( void )
|
|||
mAnimState.active = false;
|
||||
setMaskBits( UpdateMask );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -176,10 +176,11 @@ DefineEngineFunction(getMissionAreaServerObject, MissionArea*, (),,
|
|||
DefineEngineMethod( MissionArea, getArea, const char *, (),,
|
||||
"Returns 4 fields: starting x, starting y, extents x, extents y.\n")
|
||||
{
|
||||
char* returnBuffer = Con::getReturnBuffer(48);
|
||||
static const U32 bufSize = 48;
|
||||
char* returnBuffer = Con::getReturnBuffer(bufSize);
|
||||
|
||||
RectI area = object->getArea();
|
||||
dSprintf(returnBuffer, sizeof(returnBuffer), "%d %d %d %d", area.point.x, area.point.y, area.extent.x, area.extent.y);
|
||||
dSprintf(returnBuffer, bufSize, "%d %d %d %d", area.point.x, area.point.y, area.extent.x, area.extent.y);
|
||||
return(returnBuffer);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -223,12 +223,6 @@ ConsoleDocClass( WayPoint,
|
|||
"@ingroup enviroMisc\n"
|
||||
);
|
||||
|
||||
WayPointTeam::WayPointTeam()
|
||||
{
|
||||
mTeamId = 0;
|
||||
mWayPoint = 0;
|
||||
}
|
||||
|
||||
WayPoint::WayPoint()
|
||||
{
|
||||
mName = StringTable->insert("");
|
||||
|
|
@ -252,7 +246,6 @@ bool WayPoint::onAdd()
|
|||
Sim::getWayPointSet()->addObject(this);
|
||||
else
|
||||
{
|
||||
mTeam.mWayPoint = this;
|
||||
setMaskBits(UpdateNameMask|UpdateTeamMask);
|
||||
}
|
||||
|
||||
|
|
@ -272,8 +265,6 @@ U32 WayPoint::packUpdate(NetConnection * con, U32 mask, BitStream * stream)
|
|||
U32 retMask = Parent::packUpdate(con, mask, stream);
|
||||
if(stream->writeFlag(mask & UpdateNameMask))
|
||||
stream->writeString(mName);
|
||||
if(stream->writeFlag(mask & UpdateTeamMask))
|
||||
stream->write(mTeam.mTeamId);
|
||||
if(stream->writeFlag(mask & UpdateHiddenMask))
|
||||
stream->writeFlag(isHidden());
|
||||
return(retMask);
|
||||
|
|
@ -284,47 +275,17 @@ void WayPoint::unpackUpdate(NetConnection * con, BitStream * stream)
|
|||
Parent::unpackUpdate(con, stream);
|
||||
if(stream->readFlag())
|
||||
mName = stream->readSTString(true);
|
||||
if(stream->readFlag())
|
||||
stream->read(&mTeam.mTeamId);
|
||||
if(stream->readFlag())
|
||||
setHidden(stream->readFlag());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// TypeWayPointTeam
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
IMPLEMENT_STRUCT( WayPointTeam, WayPointTeam,,
|
||||
"" )
|
||||
END_IMPLEMENT_STRUCT;
|
||||
|
||||
//FIXME: this should work but does not; need to check the stripping down to base types within TYPE
|
||||
//ConsoleType( WayPointTeam, TypeWayPointTeam, WayPointTeam* )
|
||||
ConsoleType( WayPointTeam, TypeWayPointTeam, WayPointTeam )
|
||||
|
||||
ConsoleGetType( TypeWayPointTeam )
|
||||
{
|
||||
char * buf = Con::getReturnBuffer(32);
|
||||
dSprintf(buf, 32, "%d", ((WayPointTeam*)dptr)->mTeamId);
|
||||
return(buf);
|
||||
}
|
||||
|
||||
ConsoleSetType( TypeWayPointTeam )
|
||||
{
|
||||
WayPointTeam * pTeam = (WayPointTeam*)dptr;
|
||||
pTeam->mTeamId = dAtoi(argv[0]);
|
||||
|
||||
if(pTeam->mWayPoint && pTeam->mWayPoint->isServerObject())
|
||||
pTeam->mWayPoint->setMaskBits(WayPoint::UpdateTeamMask);
|
||||
}
|
||||
|
||||
void WayPoint::initPersistFields()
|
||||
{
|
||||
addGroup("Misc");
|
||||
addField("markerName", TypeCaseString, Offset(mName, WayPoint), "Unique name representing this waypoint");
|
||||
addField("team", TypeWayPointTeam, Offset(mTeam, WayPoint), "Unique numerical ID assigned to this waypoint, or set of waypoints");
|
||||
endGroup("Misc");
|
||||
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
|
|
@ -554,7 +515,7 @@ ConsoleMethod(SpawnSphere, spawnObject, S32, 2, 3,
|
|||
String additionalProps;
|
||||
|
||||
if (argc == 3)
|
||||
additionalProps = String(argv[2]);
|
||||
additionalProps = (const char*)argv[2];
|
||||
|
||||
SimObject* obj = object->spawnObject(additionalProps);
|
||||
|
||||
|
|
|
|||
|
|
@ -92,17 +92,6 @@ class MissionMarker : public ShapeBase
|
|||
// Class: WayPoint
|
||||
//------------------------------------------------------------------------------
|
||||
class WayPoint;
|
||||
class WayPointTeam
|
||||
{
|
||||
public:
|
||||
WayPointTeam();
|
||||
|
||||
S32 mTeamId;
|
||||
WayPoint * mWayPoint;
|
||||
};
|
||||
|
||||
DECLARE_STRUCT( WayPointTeam );
|
||||
DefineConsoleType( TypeWayPointTeam, WayPointTeam * );
|
||||
|
||||
class WayPoint : public MissionMarker
|
||||
{
|
||||
|
|
@ -132,7 +121,6 @@ class WayPoint : public MissionMarker
|
|||
|
||||
// field data
|
||||
StringTableEntry mName;
|
||||
WayPointTeam mTeam;
|
||||
|
||||
static void initPersistFields();
|
||||
|
||||
|
|
|
|||
|
|
@ -311,7 +311,8 @@ PhysicsDebris* PhysicsDebris::create( PhysicsDebrisData *datablock,
|
|||
}
|
||||
|
||||
PhysicsDebris::PhysicsDebris()
|
||||
: mLifetime( 0.0f ),
|
||||
: mDataBlock( NULL ),
|
||||
mLifetime( 0.0f ),
|
||||
mShapeInstance( NULL ),
|
||||
mWorld( NULL ),
|
||||
mInitialLinVel( Point3F::Zero )
|
||||
|
|
@ -342,6 +343,12 @@ bool PhysicsDebris::onAdd()
|
|||
if ( !Parent::onAdd() )
|
||||
return false;
|
||||
|
||||
if( !mDataBlock )
|
||||
{
|
||||
Con::errorf("PhysicsDebris::onAdd - Fail - No datablock");
|
||||
return false;
|
||||
}
|
||||
|
||||
// If it has a fixed lifetime then calculate it.
|
||||
if ( mDataBlock->lifetime > 0.0f )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -147,13 +147,13 @@ ConsoleFunction( physicsDestroy, void, 1, 1, "physicsDestroy()" )
|
|||
|
||||
ConsoleFunction( physicsInitWorld, bool, 2, 2, "physicsInitWorld( String worldName )" )
|
||||
{
|
||||
return PHYSICSMGR && PHYSICSMGR->createWorld( String( argv[1] ) );
|
||||
return PHYSICSMGR && PHYSICSMGR->createWorld( (const char*)argv[1] );
|
||||
}
|
||||
|
||||
ConsoleFunction( physicsDestroyWorld, void, 2, 2, "physicsDestroyWorld( String worldName )" )
|
||||
{
|
||||
if ( PHYSICSMGR )
|
||||
PHYSICSMGR->destroyWorld( String( argv[1] ) );
|
||||
PHYSICSMGR->destroyWorld( (const char*)argv[1] );
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -162,13 +162,13 @@ ConsoleFunction( physicsDestroyWorld, void, 2, 2, "physicsDestroyWorld( String w
|
|||
ConsoleFunction( physicsStartSimulation, void, 2, 2, "physicsStartSimulation( String worldName )" )
|
||||
{
|
||||
if ( PHYSICSMGR )
|
||||
PHYSICSMGR->enableSimulation( String( argv[1] ), true );
|
||||
PHYSICSMGR->enableSimulation( (const char*)argv[1], true );
|
||||
}
|
||||
|
||||
ConsoleFunction( physicsStopSimulation, void, 2, 2, "physicsStopSimulation( String worldName )" )
|
||||
{
|
||||
if ( PHYSICSMGR )
|
||||
PHYSICSMGR->enableSimulation( String( argv[1] ), false );
|
||||
PHYSICSMGR->enableSimulation( (const char*)argv[1], false );
|
||||
}
|
||||
|
||||
ConsoleFunction( physicsSimulationEnabled, bool, 1, 1, "physicsSimulationEnabled()" )
|
||||
|
|
@ -182,7 +182,7 @@ ConsoleFunction( physicsSimulationEnabled, bool, 1, 1, "physicsSimulationEnabled
|
|||
ConsoleFunction( physicsSetTimeScale, void, 2, 2, "physicsSetTimeScale( F32 scale )" )
|
||||
{
|
||||
if ( PHYSICSMGR )
|
||||
PHYSICSMGR->setTimeScale( dAtof( argv[1] ) );
|
||||
PHYSICSMGR->setTimeScale( argv[1] );
|
||||
}
|
||||
|
||||
// Get the currently set time scale.
|
||||
|
|
@ -212,5 +212,5 @@ ConsoleFunction( physicsRestoreState, void, 1, 1, "physicsRestoreState()" )
|
|||
ConsoleFunction( physicsDebugDraw, void, 2, 2, "physicsDebugDraw( bool enable )" )
|
||||
{
|
||||
if ( PHYSICSMGR )
|
||||
PHYSICSMGR->enableDebugDraw( dAtoi( argv[1] ) );
|
||||
}
|
||||
PHYSICSMGR->enableDebugDraw( (S32)argv[1] );
|
||||
}
|
||||
|
|
|
|||
|
|
@ -448,9 +448,8 @@ void PxWorld::releaseActor( NxActor &actor )
|
|||
// Clear the userdata.
|
||||
actor.userData = NULL;
|
||||
|
||||
// If the scene is not simulating then we have the
|
||||
// write lock and can safely delete it now.
|
||||
if ( !mIsSimulating )
|
||||
// actors are one of the few objects that are stable removing this way in physx 2.8
|
||||
if (mScene->isWritable() )
|
||||
{
|
||||
mScene->releaseActor( actor );
|
||||
}
|
||||
|
|
|
|||
53
Engine/source/T3D/physics/physx3/px3.h
Normal file
53
Engine/source/T3D/physics/physx3/px3.h
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _PHYSX3_H_
|
||||
#define _PHYSX3_H_
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//defines to keep PhysX happy and compiling
|
||||
#if defined(TORQUE_OS_MAC) && !defined(__APPLE__)
|
||||
#define __APPLE__
|
||||
#elif defined(TORQUE_OS_LINUX) && !defined(LINUX)
|
||||
#define LINUX
|
||||
#elif defined(TORQUE_OS_WIN) && !defined(WIN32)
|
||||
#define WIN32
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
#include <PxPhysicsAPI.h>
|
||||
#include <PxExtensionsAPI.h>
|
||||
#include <PxDefaultErrorCallback.h>
|
||||
#include <PxDefaultAllocator.h>
|
||||
#include <PxDefaultSimulationFilterShader.h>
|
||||
#include <PxDefaultCpuDispatcher.h>
|
||||
#include <PxShapeExt.h>
|
||||
#include <PxSimpleFactory.h>
|
||||
#include <PxFoundation.h>
|
||||
#include <PxController.h>
|
||||
#include <PxIO.h>
|
||||
|
||||
|
||||
extern physx::PxPhysics* gPhysics3SDK;
|
||||
|
||||
#endif // _PHYSX3_
|
||||
419
Engine/source/T3D/physics/physx3/px3Body.cpp
Normal file
419
Engine/source/T3D/physics/physx3/px3Body.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 "platform/platform.h"
|
||||
#include "T3D/physics/physx3/px3Body.h"
|
||||
|
||||
#include "T3D/physics/physx3/px3.h"
|
||||
#include "T3D/physics/physx3/px3Casts.h"
|
||||
#include "T3D/physics/physx3/px3World.h"
|
||||
#include "T3D/physics/physx3/px3Collision.h"
|
||||
|
||||
#include "console/console.h"
|
||||
#include "console/consoleTypes.h"
|
||||
|
||||
|
||||
Px3Body::Px3Body() :
|
||||
mActor( NULL ),
|
||||
mMaterial( NULL ),
|
||||
mWorld( NULL ),
|
||||
mBodyFlags( 0 ),
|
||||
mIsEnabled( true ),
|
||||
mIsStatic(false)
|
||||
{
|
||||
}
|
||||
|
||||
Px3Body::~Px3Body()
|
||||
{
|
||||
_releaseActor();
|
||||
}
|
||||
|
||||
void Px3Body::_releaseActor()
|
||||
{
|
||||
if ( !mActor )
|
||||
return;
|
||||
|
||||
mWorld->releaseWriteLock();
|
||||
|
||||
mActor->userData = NULL;
|
||||
|
||||
mActor->release();
|
||||
mActor = NULL;
|
||||
mBodyFlags = 0;
|
||||
|
||||
if ( mMaterial )
|
||||
{
|
||||
mMaterial->release();
|
||||
}
|
||||
|
||||
mColShape = NULL;
|
||||
}
|
||||
|
||||
bool Px3Body::init( PhysicsCollision *shape,
|
||||
F32 mass,
|
||||
U32 bodyFlags,
|
||||
SceneObject *obj,
|
||||
PhysicsWorld *world )
|
||||
{
|
||||
AssertFatal( obj, "Px3Body::init - Got a null scene object!" );
|
||||
AssertFatal( world, "Px3Body::init - Got a null world!" );
|
||||
AssertFatal( dynamic_cast<Px3World*>( world ), "Px3Body::init - The world is the wrong type!" );
|
||||
AssertFatal( shape, "Px3Body::init - Got a null collision shape!" );
|
||||
AssertFatal( dynamic_cast<Px3Collision*>( shape ), "Px3Body::init - The collision shape is the wrong type!" );
|
||||
AssertFatal( !((Px3Collision*)shape)->getShapes().empty(), "Px3Body::init - Got empty collision shape!" );
|
||||
|
||||
// Cleanup any previous actor.
|
||||
_releaseActor();
|
||||
|
||||
mWorld = (Px3World*)world;
|
||||
mColShape = (Px3Collision*)shape;
|
||||
mBodyFlags = bodyFlags;
|
||||
|
||||
const bool isKinematic = mBodyFlags & BF_KINEMATIC;
|
||||
const bool isTrigger = mBodyFlags & BF_TRIGGER;
|
||||
const bool isDebris = mBodyFlags & BF_DEBRIS;
|
||||
|
||||
if ( isKinematic )
|
||||
{
|
||||
mActor = gPhysics3SDK->createRigidDynamic(physx::PxTransform(physx::PxIDENTITY()));
|
||||
physx::PxRigidDynamic *actor = mActor->is<physx::PxRigidDynamic>();
|
||||
actor->setRigidDynamicFlag(physx::PxRigidDynamicFlag::eKINEMATIC, true);
|
||||
actor->setMass(getMax( mass, 1.0f ));
|
||||
}
|
||||
else if ( mass > 0.0f )
|
||||
{
|
||||
mActor = gPhysics3SDK->createRigidDynamic(physx::PxTransform(physx::PxIDENTITY()));
|
||||
}
|
||||
else
|
||||
{
|
||||
mActor = gPhysics3SDK->createRigidStatic(physx::PxTransform(physx::PxIDENTITY()));
|
||||
mIsStatic = true;
|
||||
}
|
||||
|
||||
mMaterial = gPhysics3SDK->createMaterial(0.6f,0.4f,0.1f);
|
||||
|
||||
// Add all the shapes.
|
||||
const Vector<Px3CollisionDesc*> &shapes = mColShape->getShapes();
|
||||
for ( U32 i=0; i < shapes.size(); i++ )
|
||||
{
|
||||
Px3CollisionDesc* desc = shapes[i];
|
||||
if( mass > 0.0f )
|
||||
{
|
||||
if(desc->pGeometry->getType() == physx::PxGeometryType::eTRIANGLEMESH)
|
||||
{
|
||||
Con::errorf("PhysX3 Dynamic Triangle Mesh is not supported.");
|
||||
}
|
||||
}
|
||||
physx::PxShape * pShape = mActor->createShape(*desc->pGeometry,*mMaterial);
|
||||
physx::PxFilterData colData;
|
||||
if(isDebris)
|
||||
colData.word0 = PX3_DEBRIS;
|
||||
else if(isTrigger)
|
||||
colData.word0 = PX3_TRIGGER;
|
||||
else
|
||||
colData.word0 = PX3_DEFAULT;
|
||||
|
||||
//set local pose - actor->createShape with a local pose is deprecated in physx 3.3
|
||||
pShape->setLocalPose(desc->pose);
|
||||
//set the skin width
|
||||
pShape->setContactOffset(0.01f);
|
||||
pShape->setFlag(physx::PxShapeFlag::eSIMULATION_SHAPE, !isTrigger);
|
||||
pShape->setFlag(physx::PxShapeFlag::eSCENE_QUERY_SHAPE,true);
|
||||
pShape->setSimulationFilterData(colData);
|
||||
pShape->setQueryFilterData(colData);
|
||||
}
|
||||
|
||||
//mass & intertia has to be set after creating the shape
|
||||
if ( mass > 0.0f )
|
||||
{
|
||||
physx::PxRigidDynamic *actor = mActor->is<physx::PxRigidDynamic>();
|
||||
physx::PxRigidBodyExt::setMassAndUpdateInertia(*actor,mass);
|
||||
}
|
||||
|
||||
// This sucks, but it has to happen if we want
|
||||
// to avoid write lock errors from PhysX right now.
|
||||
mWorld->releaseWriteLock();
|
||||
|
||||
mWorld->getScene()->addActor(*mActor);
|
||||
mIsEnabled = true;
|
||||
|
||||
if ( isDebris )
|
||||
mActor->setDominanceGroup( 31 );
|
||||
|
||||
mUserData.setObject( obj );
|
||||
mUserData.setBody( this );
|
||||
mActor->userData = &mUserData;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Px3Body::setMaterial( F32 restitution,
|
||||
F32 friction,
|
||||
F32 staticFriction )
|
||||
{
|
||||
AssertFatal( mActor, "Px3Body::setMaterial - The actor is null!" );
|
||||
|
||||
if ( isDynamic() )
|
||||
{
|
||||
physx::PxRigidDynamic *actor = mActor->is<physx::PxRigidDynamic>();
|
||||
actor->wakeUp();
|
||||
}
|
||||
|
||||
mMaterial->setRestitution(restitution);
|
||||
mMaterial->setStaticFriction(staticFriction);
|
||||
mMaterial->setDynamicFriction(friction);
|
||||
|
||||
}
|
||||
|
||||
void Px3Body::setSleepThreshold( F32 linear, F32 angular )
|
||||
{
|
||||
AssertFatal( mActor, "Px3Body::setSleepThreshold - The actor is null!" );
|
||||
|
||||
if(mIsStatic)
|
||||
return;
|
||||
|
||||
physx::PxRigidDynamic *actor = mActor->is<physx::PxRigidDynamic>();
|
||||
physx::PxF32 massNormalized= (linear*linear+angular*angular)/2.0f;
|
||||
actor->setSleepThreshold(massNormalized);
|
||||
}
|
||||
|
||||
void Px3Body::setDamping( F32 linear, F32 angular )
|
||||
{
|
||||
AssertFatal( mActor, "Px3Body::setDamping - The actor is null!" );
|
||||
if(mIsStatic)
|
||||
return;
|
||||
|
||||
physx::PxRigidDynamic *actor = mActor->is<physx::PxRigidDynamic>();
|
||||
actor->setLinearDamping( linear );
|
||||
actor->setAngularDamping( angular );
|
||||
}
|
||||
|
||||
void Px3Body::getState( PhysicsState *outState )
|
||||
{
|
||||
AssertFatal( mActor, "Px3Body::getState - The actor is null!" );
|
||||
AssertFatal( isDynamic(), "Px3Body::getState - This call is only for dynamics!" );
|
||||
|
||||
outState->position = px3Cast<Point3F>( mActor->getGlobalPose().p );
|
||||
outState->orientation = px3Cast<QuatF>( mActor->getGlobalPose().q );
|
||||
|
||||
physx::PxRigidDynamic *actor = mActor->is<physx::PxRigidDynamic>();
|
||||
outState->linVelocity = px3Cast<Point3F>( actor->getLinearVelocity() );
|
||||
outState->angVelocity = px3Cast<Point3F>( actor->getAngularVelocity() );
|
||||
outState->sleeping = actor->isSleeping();
|
||||
outState->momentum = px3Cast<Point3F>( (1.0f/actor->getMass()) * actor->getLinearVelocity() );
|
||||
|
||||
}
|
||||
|
||||
F32 Px3Body::getMass() const
|
||||
{
|
||||
AssertFatal( mActor, "PxBody::getCMassPosition - The actor is null!" );
|
||||
if(mIsStatic)
|
||||
return 0;
|
||||
|
||||
const physx::PxRigidDynamic *actor = mActor->is<physx::PxRigidDynamic>();
|
||||
return actor->getMass();
|
||||
}
|
||||
|
||||
Point3F Px3Body::getCMassPosition() const
|
||||
{
|
||||
AssertFatal( mActor, "Px3Body::getCMassPosition - The actor is null!" );
|
||||
if(mIsStatic)
|
||||
return px3Cast<Point3F>(mActor->getGlobalPose().p);
|
||||
|
||||
physx::PxRigidDynamic *actor = mActor->is<physx::PxRigidDynamic>();
|
||||
physx::PxTransform pose = actor->getGlobalPose() * actor->getCMassLocalPose();
|
||||
return px3Cast<Point3F>(pose.p);
|
||||
}
|
||||
|
||||
void Px3Body::setLinVelocity( const Point3F &vel )
|
||||
{
|
||||
AssertFatal( mActor, "Px3Body::setLinVelocity - The actor is null!" );
|
||||
AssertFatal( isDynamic(), "Px3Body::setLinVelocity - This call is only for dynamics!" );
|
||||
|
||||
physx::PxRigidDynamic *actor = mActor->is<physx::PxRigidDynamic>();
|
||||
actor->setLinearVelocity( px3Cast<physx::PxVec3>( vel ) );
|
||||
}
|
||||
|
||||
void Px3Body::setAngVelocity( const Point3F &vel )
|
||||
{
|
||||
AssertFatal( mActor, "Px3Body::setAngVelocity - The actor is null!" );
|
||||
AssertFatal( isDynamic(), "Px3Body::setAngVelocity - This call is only for dynamics!" );
|
||||
|
||||
physx::PxRigidDynamic *actor = mActor->is<physx::PxRigidDynamic>();
|
||||
actor->setAngularVelocity(px3Cast<physx::PxVec3>( vel ) );
|
||||
}
|
||||
|
||||
Point3F Px3Body::getLinVelocity() const
|
||||
{
|
||||
AssertFatal( mActor, "Px3Body::getLinVelocity - The actor is null!" );
|
||||
AssertFatal( isDynamic(), "Px3Body::getLinVelocity - This call is only for dynamics!" );
|
||||
|
||||
physx::PxRigidDynamic *actor = mActor->is<physx::PxRigidDynamic>();
|
||||
return px3Cast<Point3F>( actor->getLinearVelocity() );
|
||||
}
|
||||
|
||||
Point3F Px3Body::getAngVelocity() const
|
||||
{
|
||||
AssertFatal( mActor, "Px3Body::getAngVelocity - The actor is null!" );
|
||||
AssertFatal( isDynamic(), "Px3Body::getAngVelocity - This call is only for dynamics!" );
|
||||
|
||||
physx::PxRigidDynamic *actor = mActor->is<physx::PxRigidDynamic>();
|
||||
return px3Cast<Point3F>( actor->getAngularVelocity() );
|
||||
}
|
||||
|
||||
void Px3Body::setSleeping( bool sleeping )
|
||||
{
|
||||
AssertFatal( mActor, "Px3Body::setSleeping - The actor is null!" );
|
||||
AssertFatal( isDynamic(), "Px3Body::setSleeping - This call is only for dynamics!" );
|
||||
|
||||
physx::PxRigidDynamic *actor = mActor->is<physx::PxRigidDynamic>();
|
||||
if ( sleeping )
|
||||
actor->putToSleep();
|
||||
else
|
||||
actor->wakeUp();
|
||||
}
|
||||
|
||||
bool Px3Body::isDynamic() const
|
||||
{
|
||||
AssertFatal( mActor, "PxBody::isDynamic - The actor is null!" );
|
||||
return !mIsStatic && ( mBodyFlags & BF_KINEMATIC ) == 0;
|
||||
}
|
||||
|
||||
PhysicsWorld* Px3Body::getWorld()
|
||||
{
|
||||
return mWorld;
|
||||
}
|
||||
|
||||
PhysicsCollision* Px3Body::getColShape()
|
||||
{
|
||||
return mColShape;
|
||||
}
|
||||
|
||||
MatrixF& Px3Body::getTransform( MatrixF *outMatrix )
|
||||
{
|
||||
AssertFatal( mActor, "Px3Body::getTransform - The actor is null!" );
|
||||
|
||||
*outMatrix = px3Cast<MatrixF>(mActor->getGlobalPose());
|
||||
return *outMatrix;
|
||||
}
|
||||
|
||||
Box3F Px3Body::getWorldBounds()
|
||||
{
|
||||
AssertFatal( mActor, "Px3Body::getTransform - The actor is null!" );
|
||||
|
||||
physx::PxBounds3 bounds;
|
||||
bounds.setEmpty();
|
||||
physx::PxBounds3 shapeBounds;
|
||||
|
||||
|
||||
U32 shapeCount = mActor->getNbShapes();
|
||||
physx::PxShape **shapes = new physx::PxShape*[shapeCount];
|
||||
mActor->getShapes(shapes, shapeCount);
|
||||
for ( U32 i = 0; i < shapeCount; i++ )
|
||||
{
|
||||
// Get the shape's bounds.
|
||||
shapeBounds = physx::PxShapeExt::getWorldBounds(*shapes[i],*mActor);
|
||||
// Combine them into the total bounds.
|
||||
bounds.include( shapeBounds );
|
||||
}
|
||||
|
||||
delete [] shapes;
|
||||
|
||||
return px3Cast<Box3F>( bounds );
|
||||
}
|
||||
|
||||
void Px3Body::setSimulationEnabled( bool enabled )
|
||||
{
|
||||
if ( mIsEnabled == enabled )
|
||||
return;
|
||||
|
||||
//Don't need to enable/disable eSIMULATION_SHAPE for trigger,it's disabled permanently
|
||||
if(mBodyFlags & BF_TRIGGER)
|
||||
return;
|
||||
|
||||
// This sucks, but it has to happen if we want
|
||||
// to avoid write lock errors from PhysX right now.
|
||||
mWorld->releaseWriteLock();
|
||||
|
||||
U32 shapeCount = mActor->getNbShapes();
|
||||
physx::PxShape **shapes = new physx::PxShape*[shapeCount];
|
||||
mActor->getShapes(shapes, shapeCount);
|
||||
for ( S32 i = 0; i < mActor->getNbShapes(); i++ )
|
||||
{
|
||||
shapes[i]->setFlag(physx::PxShapeFlag::eSIMULATION_SHAPE,!mIsEnabled);//?????
|
||||
}
|
||||
|
||||
delete [] shapes;
|
||||
}
|
||||
void Px3Body::setTransform( const MatrixF &transform )
|
||||
{
|
||||
AssertFatal( mActor, "Px3Body::setTransform - The actor is null!" );
|
||||
|
||||
|
||||
// This sucks, but it has to happen if we want
|
||||
// to avoid write lock errors from PhysX right now.
|
||||
mWorld->releaseWriteLock();
|
||||
|
||||
|
||||
mActor->setGlobalPose(px3Cast<physx::PxTransform>(transform),false);
|
||||
|
||||
if(mIsStatic)
|
||||
return;
|
||||
|
||||
physx::PxRigidDynamic *actor = mActor->is<physx::PxRigidDynamic>();
|
||||
bool kinematic = actor->getRigidDynamicFlags() & physx::PxRigidDynamicFlag::eKINEMATIC;
|
||||
// If its dynamic we have more to do.
|
||||
if ( isDynamic() && !kinematic )
|
||||
{
|
||||
actor->setLinearVelocity( physx::PxVec3(0) );
|
||||
actor->setAngularVelocity( physx::PxVec3(0) );
|
||||
actor->wakeUp();
|
||||
}
|
||||
}
|
||||
|
||||
void Px3Body::applyCorrection( const MatrixF &transform )
|
||||
{
|
||||
AssertFatal( mActor, "Px3Body::applyCorrection - The actor is null!" );
|
||||
AssertFatal( isDynamic(), "Px3Body::applyCorrection - This call is only for dynamics!" );
|
||||
|
||||
// This sucks, but it has to happen if we want
|
||||
// to avoid write lock errors from PhysX right now.
|
||||
mWorld->releaseWriteLock();
|
||||
|
||||
mActor->setGlobalPose( px3Cast<physx::PxTransform>(transform) );
|
||||
}
|
||||
|
||||
void Px3Body::applyImpulse( const Point3F &origin, const Point3F &force )
|
||||
{
|
||||
AssertFatal( mActor, "Px3Body::applyImpulse - The actor is null!" );
|
||||
|
||||
// This sucks, but it has to happen if we want
|
||||
// to avoid write lock errors from PhysX right now.
|
||||
mWorld->releaseWriteLock();
|
||||
physx::PxRigidDynamic *actor = mActor->is<physx::PxRigidDynamic>();
|
||||
if ( mIsEnabled && isDynamic() )
|
||||
physx::PxRigidBodyExt::addForceAtPos(*actor,px3Cast<physx::PxVec3>(force),
|
||||
px3Cast<physx::PxVec3>(origin),
|
||||
physx::PxForceMode::eIMPULSE);
|
||||
|
||||
}
|
||||
|
||||
122
Engine/source/T3D/physics/physx3/px3Body.h
Normal file
122
Engine/source/T3D/physics/physx3/px3Body.h
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _PX3BODY_H_
|
||||
#define _PX3BODY_H_
|
||||
|
||||
#ifndef _T3D_PHYSICS_PHYSICSBODY_H_
|
||||
#include "T3D/physics/physicsBody.h"
|
||||
#endif
|
||||
#ifndef _PHYSICS_PHYSICSUSERDATA_H_
|
||||
#include "T3D/physics/physicsUserData.h"
|
||||
#endif
|
||||
#ifndef _REFBASE_H_
|
||||
#include "core/util/refBase.h"
|
||||
#endif
|
||||
#ifndef _MMATRIX_H_
|
||||
#include "math/mMatrix.h"
|
||||
#endif
|
||||
|
||||
class Px3World;
|
||||
class Px3Collision;
|
||||
struct Px3CollisionDesc;
|
||||
|
||||
namespace physx{
|
||||
class PxRigidActor;
|
||||
class PxMaterial;
|
||||
class PxShape;
|
||||
}
|
||||
|
||||
|
||||
class Px3Body : public PhysicsBody
|
||||
{
|
||||
protected:
|
||||
|
||||
/// The physics world we are in.
|
||||
Px3World *mWorld;
|
||||
|
||||
/// The physics actor.
|
||||
physx::PxRigidActor *mActor;
|
||||
|
||||
/// The unshared local material used on all the
|
||||
/// shapes on this actor.
|
||||
physx::PxMaterial *mMaterial;
|
||||
|
||||
/// We hold the collision reference as it contains
|
||||
/// allocated objects that we own and must free.
|
||||
StrongRefPtr<Px3Collision> mColShape;
|
||||
|
||||
///
|
||||
MatrixF mInternalTransform;
|
||||
|
||||
/// The body flags set at creation time.
|
||||
U32 mBodyFlags;
|
||||
|
||||
/// Is true if this body is enabled and active
|
||||
/// in the simulation of the scene.
|
||||
bool mIsEnabled;
|
||||
bool mIsStatic;
|
||||
|
||||
///
|
||||
void _releaseActor();
|
||||
|
||||
|
||||
public:
|
||||
|
||||
Px3Body();
|
||||
virtual ~Px3Body();
|
||||
|
||||
// PhysicsObject
|
||||
virtual PhysicsWorld* getWorld();
|
||||
virtual void setTransform( const MatrixF &xfm );
|
||||
virtual MatrixF& getTransform( MatrixF *outMatrix );
|
||||
virtual Box3F getWorldBounds();
|
||||
virtual void setSimulationEnabled( bool enabled );
|
||||
virtual bool isSimulationEnabled() { return mIsEnabled; }
|
||||
|
||||
// PhysicsBody
|
||||
virtual bool init( PhysicsCollision *shape,
|
||||
F32 mass,
|
||||
U32 bodyFlags,
|
||||
SceneObject *obj,
|
||||
PhysicsWorld *world );
|
||||
|
||||
virtual bool isDynamic() const;
|
||||
virtual PhysicsCollision* getColShape();
|
||||
virtual void setSleepThreshold( F32 linear, F32 angular );
|
||||
virtual void setDamping( F32 linear, F32 angular );
|
||||
virtual void getState( PhysicsState *outState );
|
||||
virtual F32 getMass() const;
|
||||
virtual Point3F getCMassPosition() const;
|
||||
virtual void setLinVelocity( const Point3F &vel );
|
||||
virtual void setAngVelocity( const Point3F &vel );
|
||||
virtual Point3F getLinVelocity() const;
|
||||
virtual Point3F getAngVelocity() const;
|
||||
virtual void setSleeping( bool sleeping );
|
||||
virtual void setMaterial( F32 restitution,
|
||||
F32 friction,
|
||||
F32 staticFriction );
|
||||
virtual void applyCorrection( const MatrixF &xfm );
|
||||
virtual void applyImpulse( const Point3F &origin, const Point3F &force );
|
||||
};
|
||||
|
||||
#endif // _PX3BODY_H_
|
||||
137
Engine/source/T3D/physics/physx3/px3Casts.h
Normal file
137
Engine/source/T3D/physics/physx3/px3Casts.h
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _PX3CASTS_H_
|
||||
#define _PX3CASTS_H_
|
||||
|
||||
#ifndef _MPOINT3_H_
|
||||
#include "math/mPoint3.h"
|
||||
#endif
|
||||
#ifndef _MMATRIX_H_
|
||||
#include "math/mMatrix.h"
|
||||
#endif
|
||||
#ifndef _MBOX_H_
|
||||
#include "math/mBox.h"
|
||||
#endif
|
||||
#ifndef _MQUAT_H_
|
||||
#include "math/mQuat.h"
|
||||
#endif
|
||||
#ifndef _MTRANSFORM_H_
|
||||
#include "math/mTransform.h"
|
||||
#endif
|
||||
|
||||
|
||||
template <class T, class F> inline T px3Cast( const F &from );
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
template<>
|
||||
inline Point3F px3Cast( const physx::PxVec3 &vec )
|
||||
{
|
||||
return Point3F( vec.x, vec.y, vec.z );
|
||||
}
|
||||
|
||||
template<>
|
||||
inline physx::PxVec3 px3Cast( const Point3F &point )
|
||||
{
|
||||
return physx::PxVec3( point.x, point.y, point.z );
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
template<>
|
||||
inline QuatF px3Cast( const physx::PxQuat &quat )
|
||||
{
|
||||
/// The Torque quat has the opposite winding order.
|
||||
return QuatF( -quat.x, -quat.y, -quat.z, quat.w );
|
||||
}
|
||||
|
||||
template<>
|
||||
inline physx::PxQuat px3Cast( const QuatF &quat )
|
||||
{
|
||||
/// The Torque quat has the opposite winding order.
|
||||
physx::PxQuat result( -quat.x, -quat.y, -quat.z, quat.w );
|
||||
return result;
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
template<>
|
||||
inline physx::PxExtendedVec3 px3Cast( const Point3F &point )
|
||||
{
|
||||
return physx::PxExtendedVec3( point.x, point.y, point.z );
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Point3F px3Cast( const physx::PxExtendedVec3 &xvec )
|
||||
{
|
||||
return Point3F( xvec.x, xvec.y, xvec.z );
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
template<>
|
||||
inline physx::PxBounds3 px3Cast( const Box3F &box )
|
||||
{
|
||||
physx::PxBounds3 bounds(px3Cast<physx::PxVec3>(box.minExtents),
|
||||
px3Cast<physx::PxVec3>(box.maxExtents));
|
||||
return bounds;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Box3F px3Cast( const physx::PxBounds3 &bounds )
|
||||
{
|
||||
return Box3F( bounds.minimum.x,
|
||||
bounds.minimum.y,
|
||||
bounds.minimum.z,
|
||||
bounds.maximum.x,
|
||||
bounds.maximum.y,
|
||||
bounds.maximum.z );
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
template<>
|
||||
inline physx::PxTransform px3Cast( const MatrixF &xfm )
|
||||
{
|
||||
physx::PxTransform out;
|
||||
QuatF q;
|
||||
q.set(xfm);
|
||||
out.q = px3Cast<physx::PxQuat>(q);
|
||||
out.p = px3Cast<physx::PxVec3>(xfm.getPosition());
|
||||
return out;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline TransformF px3Cast(const physx::PxTransform &xfm)
|
||||
{
|
||||
TransformF out(px3Cast<Point3F>(xfm.p),AngAxisF(px3Cast<QuatF>(xfm.q)));
|
||||
return out;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline MatrixF px3Cast( const physx::PxTransform &xfm )
|
||||
{
|
||||
MatrixF out;
|
||||
TransformF t = px3Cast<TransformF>(xfm);
|
||||
out = t.getMatrix();
|
||||
return out;
|
||||
}
|
||||
|
||||
#endif //_PX3CASTS_H_
|
||||
217
Engine/source/T3D/physics/physx3/px3Collision.cpp
Normal file
217
Engine/source/T3D/physics/physx3/px3Collision.cpp
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/physics/physx3/px3Collision.h"
|
||||
|
||||
#include "math/mPoint3.h"
|
||||
#include "math/mMatrix.h"
|
||||
#include "T3D/physics/physx3/px3.h"
|
||||
#include "T3D/physics/physx3/px3Casts.h"
|
||||
#include "T3D/physics/physx3/px3World.h"
|
||||
#include "T3D/physics/physx3/px3Stream.h"
|
||||
|
||||
|
||||
Px3Collision::Px3Collision()
|
||||
{
|
||||
}
|
||||
|
||||
Px3Collision::~Px3Collision()
|
||||
{
|
||||
|
||||
for ( U32 i=0; i < mColShapes.size(); i++ )
|
||||
{
|
||||
Px3CollisionDesc *desc = mColShapes[i];
|
||||
delete desc->pGeometry;
|
||||
// Delete the descriptor.
|
||||
delete desc;
|
||||
}
|
||||
|
||||
mColShapes.clear();
|
||||
}
|
||||
|
||||
void Px3Collision::addPlane( const PlaneF &plane )
|
||||
{
|
||||
physx::PxVec3 pos = px3Cast<physx::PxVec3>(plane.getPosition());
|
||||
Px3CollisionDesc *desc = new Px3CollisionDesc;
|
||||
desc->pGeometry = new physx::PxPlaneGeometry();
|
||||
desc->pose = physx::PxTransform(pos, physx::PxQuat(physx::PxHalfPi, physx::PxVec3(0.0f, -1.0f, 0.0f)));
|
||||
mColShapes.push_back(desc);
|
||||
}
|
||||
|
||||
void Px3Collision::addBox( const Point3F &halfWidth,const MatrixF &localXfm )
|
||||
{
|
||||
Px3CollisionDesc *desc = new Px3CollisionDesc;
|
||||
desc->pGeometry = new physx::PxBoxGeometry(px3Cast<physx::PxVec3>(halfWidth));
|
||||
desc->pose = px3Cast<physx::PxTransform>(localXfm);
|
||||
mColShapes.push_back(desc);
|
||||
}
|
||||
|
||||
void Px3Collision::addSphere( F32 radius,
|
||||
const MatrixF &localXfm )
|
||||
{
|
||||
Px3CollisionDesc *desc = new Px3CollisionDesc;
|
||||
desc->pGeometry = new physx::PxSphereGeometry(radius);
|
||||
desc->pose = px3Cast<physx::PxTransform>(localXfm);
|
||||
mColShapes.push_back(desc);
|
||||
}
|
||||
|
||||
void Px3Collision::addCapsule( F32 radius,
|
||||
F32 height,
|
||||
const MatrixF &localXfm )
|
||||
{
|
||||
Px3CollisionDesc *desc = new Px3CollisionDesc;
|
||||
desc->pGeometry = new physx::PxCapsuleGeometry(radius,height*0.5);//uses half height
|
||||
desc->pose = px3Cast<physx::PxTransform>(localXfm);
|
||||
mColShapes.push_back(desc);
|
||||
}
|
||||
|
||||
bool Px3Collision::addConvex( const Point3F *points,
|
||||
U32 count,
|
||||
const MatrixF &localXfm )
|
||||
{
|
||||
physx::PxCooking *cooking = Px3World::getCooking();
|
||||
physx::PxConvexMeshDesc convexDesc;
|
||||
convexDesc.points.data = points;
|
||||
convexDesc.points.stride = sizeof(Point3F);
|
||||
convexDesc.points.count = count;
|
||||
convexDesc.flags = physx::PxConvexFlag::eFLIPNORMALS|physx::PxConvexFlag::eCOMPUTE_CONVEX | physx::PxConvexFlag::eINFLATE_CONVEX;
|
||||
|
||||
Px3MemOutStream stream;
|
||||
if(!cooking->cookConvexMesh(convexDesc,stream))
|
||||
return false;
|
||||
|
||||
physx::PxConvexMesh* convexMesh;
|
||||
Px3MemInStream in(stream.getData(), stream.getSize());
|
||||
convexMesh = gPhysics3SDK->createConvexMesh(in);
|
||||
|
||||
Px3CollisionDesc *desc = new Px3CollisionDesc;
|
||||
physx::PxVec3 scale = px3Cast<physx::PxVec3>(localXfm.getScale());
|
||||
physx::PxQuat rotation = px3Cast<physx::PxQuat>(QuatF(localXfm));
|
||||
physx::PxMeshScale meshScale(scale,rotation);
|
||||
desc->pGeometry = new physx::PxConvexMeshGeometry(convexMesh,meshScale);
|
||||
desc->pose = px3Cast<physx::PxTransform>(localXfm);
|
||||
mColShapes.push_back(desc);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Px3Collision::addTriangleMesh( const Point3F *vert,
|
||||
U32 vertCount,
|
||||
const U32 *index,
|
||||
U32 triCount,
|
||||
const MatrixF &localXfm )
|
||||
{
|
||||
physx::PxCooking *cooking = Px3World::getCooking();
|
||||
physx::PxTriangleMeshDesc meshDesc;
|
||||
meshDesc.points.count = vertCount;
|
||||
meshDesc.points.data = vert;
|
||||
meshDesc.points.stride = sizeof(Point3F);
|
||||
|
||||
meshDesc.triangles.count = triCount;
|
||||
meshDesc.triangles.data = index;
|
||||
meshDesc.triangles.stride = 3*sizeof(U32);
|
||||
meshDesc.flags = physx::PxMeshFlag::eFLIPNORMALS;
|
||||
|
||||
Px3MemOutStream stream;
|
||||
if(!cooking->cookTriangleMesh(meshDesc,stream))
|
||||
return false;
|
||||
|
||||
physx::PxTriangleMesh *mesh;
|
||||
Px3MemInStream in(stream.getData(), stream.getSize());
|
||||
mesh = gPhysics3SDK->createTriangleMesh(in);
|
||||
|
||||
Px3CollisionDesc *desc = new Px3CollisionDesc;
|
||||
desc->pGeometry = new physx::PxTriangleMeshGeometry(mesh);
|
||||
desc->pose = px3Cast<physx::PxTransform>(localXfm);
|
||||
mColShapes.push_back(desc);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Px3Collision::addHeightfield( const U16 *heights,
|
||||
const bool *holes,
|
||||
U32 blockSize,
|
||||
F32 metersPerSample,
|
||||
const MatrixF &localXfm )
|
||||
{
|
||||
const F32 heightScale = 0.03125f;
|
||||
physx::PxHeightFieldSample* samples = (physx::PxHeightFieldSample*) new physx::PxHeightFieldSample[blockSize*blockSize];
|
||||
memset(samples,0,blockSize*blockSize*sizeof(physx::PxHeightFieldSample));
|
||||
|
||||
physx::PxHeightFieldDesc heightFieldDesc;
|
||||
heightFieldDesc.nbColumns = blockSize;
|
||||
heightFieldDesc.nbRows = blockSize;
|
||||
heightFieldDesc.thickness = -10.f;
|
||||
heightFieldDesc.convexEdgeThreshold = 0;
|
||||
heightFieldDesc.format = physx::PxHeightFieldFormat::eS16_TM;
|
||||
heightFieldDesc.samples.data = samples;
|
||||
heightFieldDesc.samples.stride = sizeof(physx::PxHeightFieldSample);
|
||||
|
||||
physx::PxU8 *currentByte = (physx::PxU8*)heightFieldDesc.samples.data;
|
||||
for ( U32 row = 0; row < blockSize; row++ )
|
||||
{
|
||||
const U32 tess = ( row + 1 ) % 2;
|
||||
|
||||
for ( U32 column = 0; column < blockSize; column++ )
|
||||
{
|
||||
physx::PxHeightFieldSample *currentSample = (physx::PxHeightFieldSample*)currentByte;
|
||||
|
||||
U32 index = ( blockSize - row - 1 ) + ( column * blockSize );
|
||||
currentSample->height = (physx::PxI16)heights[ index ];
|
||||
|
||||
|
||||
if ( holes && holes[ getMax( (S32)index - 1, 0 ) ] ) // row index for holes adjusted so PhysX collision shape better matches rendered terrain
|
||||
{
|
||||
currentSample->materialIndex0 = physx::PxHeightFieldMaterial::eHOLE;
|
||||
currentSample->materialIndex1 = physx::PxHeightFieldMaterial::eHOLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentSample->materialIndex0 = 0;
|
||||
currentSample->materialIndex1 = 0;
|
||||
}
|
||||
|
||||
int flag = ( column + tess ) % 2;
|
||||
if(flag)
|
||||
currentSample->clearTessFlag();
|
||||
else
|
||||
currentSample->setTessFlag();
|
||||
|
||||
currentByte += heightFieldDesc.samples.stride;
|
||||
}
|
||||
}
|
||||
|
||||
physx::PxHeightField * hf = gPhysics3SDK->createHeightField(heightFieldDesc);
|
||||
physx::PxHeightFieldGeometry *geom = new physx::PxHeightFieldGeometry(hf,physx::PxMeshGeometryFlags(),heightScale,metersPerSample,metersPerSample);
|
||||
|
||||
physx::PxTransform pose= physx::PxTransform(physx::PxQuat(Float_HalfPi, physx::PxVec3(1, 0, 0 )));
|
||||
physx::PxTransform pose1= physx::PxTransform(physx::PxQuat(Float_Pi, physx::PxVec3(0, 0, 1 )));
|
||||
physx::PxTransform pose2 = pose1 * pose;
|
||||
pose2.p = physx::PxVec3(( blockSize - 1 ) * metersPerSample, 0, 0 );
|
||||
Px3CollisionDesc *desc = new Px3CollisionDesc;
|
||||
desc->pGeometry = geom;
|
||||
desc->pose = pose2;
|
||||
|
||||
mColShapes.push_back(desc);
|
||||
|
||||
SAFE_DELETE(samples);
|
||||
return true;
|
||||
}
|
||||
87
Engine/source/T3D/physics/physx3/px3Collision.h
Normal file
87
Engine/source/T3D/physics/physx3/px3Collision.h
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _PX3COLLISION_H_
|
||||
#define _PX3COLLISION_H_
|
||||
|
||||
#ifndef _T3D_PHYSICS_PHYSICSCOLLISION_H_
|
||||
#include "T3D/physics/physicsCollision.h"
|
||||
#endif
|
||||
#ifndef _TVECTOR_H_
|
||||
#include "core/util/tVector.h"
|
||||
#endif
|
||||
#ifndef _MMATRIX_H_
|
||||
#include "math/mMatrix.h"
|
||||
#endif
|
||||
|
||||
#include <foundation/PxTransform.h>
|
||||
|
||||
//forward declare
|
||||
namespace physx{class PxGeometry;}
|
||||
|
||||
|
||||
struct Px3CollisionDesc
|
||||
{
|
||||
physx::PxGeometry *pGeometry;
|
||||
physx::PxTransform pose;
|
||||
};
|
||||
|
||||
class Px3Collision : public PhysicsCollision
|
||||
{
|
||||
typedef Vector<Px3CollisionDesc*> Px3CollisionList;
|
||||
protected:
|
||||
/// The collision representation.
|
||||
Px3CollisionList mColShapes;
|
||||
|
||||
public:
|
||||
|
||||
Px3Collision();
|
||||
virtual ~Px3Collision();
|
||||
|
||||
/// Return the PhysX shape descriptions.
|
||||
const Px3CollisionList& getShapes() const { return mColShapes; }
|
||||
|
||||
// PhysicsCollision
|
||||
virtual void addPlane( const PlaneF &plane );
|
||||
virtual void addBox( const Point3F &halfWidth,
|
||||
const MatrixF &localXfm );
|
||||
virtual void addSphere( F32 radius,
|
||||
const MatrixF &localXfm );
|
||||
virtual void addCapsule( F32 radius,
|
||||
F32 height,
|
||||
const MatrixF &localXfm );
|
||||
virtual bool addConvex( const Point3F *points,
|
||||
U32 count,
|
||||
const MatrixF &localXfm );
|
||||
virtual bool addTriangleMesh( const Point3F *vert,
|
||||
U32 vertCount,
|
||||
const U32 *index,
|
||||
U32 triCount,
|
||||
const MatrixF &localXfm );
|
||||
virtual bool addHeightfield( const U16 *heights,
|
||||
const bool *holes,
|
||||
U32 blockSize,
|
||||
F32 metersPerSample,
|
||||
const MatrixF &localXfm );
|
||||
};
|
||||
|
||||
#endif // _PX3COLLISION_H_
|
||||
331
Engine/source/T3D/physics/physx3/px3Player.cpp
Normal file
331
Engine/source/T3D/physics/physx3/px3Player.cpp
Normal file
|
|
@ -0,0 +1,331 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/physics/physx3/px3Player.h"
|
||||
#include "T3D/physics/physicsPlugin.h"
|
||||
#include "T3D/physics/physx3/px3World.h"
|
||||
#include "T3D/physics/physx3/px3Casts.h"
|
||||
#include "T3D/physics/physx3/px3Utils.h"
|
||||
#include "collision/collision.h"
|
||||
|
||||
|
||||
Px3Player::Px3Player()
|
||||
: PhysicsPlayer(),
|
||||
mController( NULL ),
|
||||
mWorld( NULL ),
|
||||
mObject( NULL ),
|
||||
mSkinWidth( 0.05f ),
|
||||
mOriginOffset( 0.0f ),
|
||||
mElapsed(0)
|
||||
{
|
||||
PHYSICSMGR->getPhysicsResetSignal().notify( this, &Px3Player::_onPhysicsReset );
|
||||
}
|
||||
|
||||
Px3Player::~Px3Player()
|
||||
{
|
||||
_releaseController();
|
||||
PHYSICSMGR->getPhysicsResetSignal().remove( this, &Px3Player::_onPhysicsReset );
|
||||
}
|
||||
|
||||
void Px3Player::_releaseController()
|
||||
{
|
||||
if ( mController )
|
||||
{
|
||||
mController->getActor()->userData = NULL;
|
||||
mWorld->getStaticChangedSignal().remove( this, &Px3Player::_onStaticChanged );
|
||||
mController->release();
|
||||
}
|
||||
}
|
||||
|
||||
void Px3Player::init( const char *type,
|
||||
const Point3F &size,
|
||||
F32 runSurfaceCos,
|
||||
F32 stepHeight,
|
||||
SceneObject *obj,
|
||||
PhysicsWorld *world )
|
||||
{
|
||||
AssertFatal( obj, "Px3Player::init - Got a null scene object!" );
|
||||
AssertFatal( world, "Px3Player::init - Got a null world!" );
|
||||
AssertFatal( dynamic_cast<Px3World*>( world ), "Px3Player::init - The world is the wrong type!" );
|
||||
|
||||
// Cleanup any previous controller.
|
||||
_releaseController();
|
||||
|
||||
mObject = obj;
|
||||
mWorld = (Px3World*)world;
|
||||
mOriginOffset = size.z * 0.5f;
|
||||
|
||||
physx::PxCapsuleControllerDesc desc;
|
||||
desc.contactOffset = mSkinWidth;
|
||||
desc.radius = getMax( size.x, size.y ) * 0.5f;
|
||||
desc.radius -= mSkinWidth;
|
||||
desc.height = size.z - ( desc.radius * 2.0f );
|
||||
desc.height -= mSkinWidth * 2.0f;
|
||||
desc.climbingMode = physx::PxCapsuleClimbingMode::eCONSTRAINED;
|
||||
desc.position.set( 0, 0, 0 );
|
||||
desc.upDirection = physx::PxVec3(0,0,1);
|
||||
desc.reportCallback = this;
|
||||
desc.slopeLimit = runSurfaceCos;
|
||||
desc.stepOffset = stepHeight;
|
||||
desc.behaviorCallback = NULL;
|
||||
desc.material = gPhysics3SDK->createMaterial(0.1f, 0.1f, 0.2f);
|
||||
|
||||
mController = mWorld->createController( desc );
|
||||
|
||||
mWorld->getStaticChangedSignal().notify( this, &Px3Player::_onStaticChanged );
|
||||
physx::PxRigidDynamic *kineActor = mController->getActor();
|
||||
|
||||
//player only has one shape
|
||||
physx::PxShape *shape = px3GetFirstShape(kineActor);
|
||||
physx::PxFilterData colData;
|
||||
colData.word0 = PX3_PLAYER;
|
||||
shape->setSimulationFilterData(colData);
|
||||
shape->setQueryFilterData(colData);
|
||||
|
||||
//store geometry for later use in findContact calls
|
||||
shape->getCapsuleGeometry(mGeometry);
|
||||
|
||||
mUserData.setObject( obj );
|
||||
kineActor->userData = &mUserData;
|
||||
|
||||
}
|
||||
|
||||
void Px3Player::_onStaticChanged()
|
||||
{
|
||||
if(mController)
|
||||
mController->invalidateCache();
|
||||
}
|
||||
|
||||
void Px3Player::_onPhysicsReset( PhysicsResetEvent reset )
|
||||
{
|
||||
if(mController)
|
||||
mController->invalidateCache();
|
||||
}
|
||||
|
||||
Point3F Px3Player::move( const VectorF &disp, CollisionList &outCol )
|
||||
{
|
||||
AssertFatal( mController, "Px3Player::move - The controller is null!" );
|
||||
|
||||
// Return the last position if the simulation is stopped.
|
||||
//
|
||||
// See PxPlayer::_onPhysicsReset
|
||||
if ( !mWorld->isEnabled() )
|
||||
{
|
||||
Point3F newPos = px3Cast<Point3F>( mController->getPosition() );
|
||||
newPos.z -= mOriginOffset;
|
||||
return newPos;
|
||||
}
|
||||
|
||||
mWorld->releaseWriteLock();
|
||||
|
||||
mCollisionList = &outCol;
|
||||
|
||||
physx::PxVec3 dispNx( disp.x, disp.y, disp.z );
|
||||
if (mIsZero(disp.z))
|
||||
dispNx.z = 0.0f;
|
||||
|
||||
U32 groups = 0xffffffff;
|
||||
groups &= ~( PX3_TRIGGER ); // No trigger shapes!
|
||||
groups &= ~( PX3_DEBRIS);
|
||||
physx::PxControllerFilters filter;
|
||||
physx::PxFilterData data;
|
||||
data.word0=groups;
|
||||
filter.mFilterData = &data;
|
||||
filter.mFilterFlags = physx::PxSceneQueryFilterFlags(physx::PxControllerFlag::eCOLLISION_DOWN|physx::PxControllerFlag::eCOLLISION_SIDES|physx::PxControllerFlag::eCOLLISION_UP);
|
||||
|
||||
mController->move( dispNx,0.0001f,0, filter );
|
||||
|
||||
Point3F newPos = px3Cast<Point3F>( mController->getPosition() );
|
||||
newPos.z -= mOriginOffset;
|
||||
|
||||
mCollisionList = NULL;
|
||||
|
||||
return newPos;
|
||||
}
|
||||
|
||||
void Px3Player::onShapeHit( const physx::PxControllerShapeHit& hit )
|
||||
{
|
||||
if (!mCollisionList || mCollisionList->getCount() >= CollisionList::MaxCollisions)
|
||||
return;
|
||||
|
||||
physx::PxRigidActor *actor = hit.actor;
|
||||
PhysicsUserData *userData = PhysicsUserData::cast( actor->userData );
|
||||
|
||||
// Fill out the Collision
|
||||
// structure for use later.
|
||||
Collision &col = mCollisionList->increment();
|
||||
dMemset( &col, 0, sizeof( col ) );
|
||||
|
||||
col.normal = px3Cast<Point3F>( hit.worldNormal );
|
||||
col.point = px3Cast<Point3F>( hit.worldPos );
|
||||
col.distance = hit.length;
|
||||
if ( userData )
|
||||
col.object = userData->getObject();
|
||||
|
||||
if (mIsZero(hit.dir.z))
|
||||
{
|
||||
if (col.normal.z > 0.0f)
|
||||
{
|
||||
col.normal.z = 0.0f;
|
||||
col.normal.normalizeSafe();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
col.normal.set(0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void Px3Player::onControllerHit( const physx::PxControllersHit& hit )
|
||||
{
|
||||
if (!mCollisionList || mCollisionList->getCount() >= CollisionList::MaxCollisions)
|
||||
return;
|
||||
|
||||
physx::PxRigidActor *actor = hit.other->getActor();
|
||||
PhysicsUserData *userData = PhysicsUserData::cast( actor->userData );
|
||||
|
||||
// For controller-to-controller hit we don't have an actual hit point, so all
|
||||
// we can do is set the hit object.
|
||||
Collision &col = mCollisionList->increment();
|
||||
dMemset( &col, 0, sizeof( col ) );
|
||||
if ( userData )
|
||||
col.object = userData->getObject();
|
||||
|
||||
}
|
||||
|
||||
void Px3Player::findContact( SceneObject **contactObject,
|
||||
VectorF *contactNormal,
|
||||
Vector<SceneObject*> *outOverlapObjects ) const
|
||||
{
|
||||
// Calculate the sweep motion...
|
||||
F32 halfCapSize = mOriginOffset;
|
||||
F32 halfSmallCapSize = halfCapSize * 0.8f;
|
||||
F32 diff = halfCapSize - halfSmallCapSize;
|
||||
|
||||
F32 distance = diff + mSkinWidth + 0.01f;
|
||||
physx::PxVec3 dir(0,0,-1);
|
||||
|
||||
physx::PxScene *scene = mWorld->getScene();
|
||||
physx::PxHitFlags hitFlags(physx::PxHitFlag::eDEFAULT);
|
||||
physx::PxQueryFilterData filterData(physx::PxQueryFlag::eDYNAMIC|physx::PxQueryFlag::eSTATIC);
|
||||
filterData.data.word0 = PX3_DEFAULT;
|
||||
physx::PxSweepHit sweepHit;
|
||||
physx::PxRigidDynamic *actor= mController->getActor();
|
||||
physx::PxU32 shapeIndex;
|
||||
|
||||
bool hit = physx::PxRigidBodyExt::linearSweepSingle(*actor,*scene,dir,distance,hitFlags,sweepHit,shapeIndex,filterData);
|
||||
if ( hit )
|
||||
{
|
||||
PhysicsUserData *data = PhysicsUserData::cast( sweepHit.actor->userData);
|
||||
if ( data )
|
||||
{
|
||||
*contactObject = data->getObject();
|
||||
*contactNormal = px3Cast<Point3F>( sweepHit.normal );
|
||||
}
|
||||
}
|
||||
|
||||
// Check for overlapped objects ( triggers )
|
||||
|
||||
if ( !outOverlapObjects )
|
||||
return;
|
||||
|
||||
filterData.data.word0 = PX3_TRIGGER;
|
||||
|
||||
const physx::PxU32 bufferSize = 10;
|
||||
physx::PxOverlapBufferN<bufferSize> hitBuffer;
|
||||
hit = scene->overlap(mGeometry,actor->getGlobalPose(),hitBuffer,filterData);
|
||||
if(hit)
|
||||
{
|
||||
for ( U32 i = 0; i < hitBuffer.nbTouches; i++ )
|
||||
{
|
||||
PhysicsUserData *data = PhysicsUserData::cast( hitBuffer.touches[i].actor->userData );
|
||||
if ( data )
|
||||
outOverlapObjects->push_back( data->getObject() );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Px3Player::enableCollision()
|
||||
{
|
||||
AssertFatal( mController, "Px3Player::enableCollision - The controller is null!" );
|
||||
|
||||
mWorld->releaseWriteLock();
|
||||
px3GetFirstShape(mController->getActor())->setFlag(physx::PxShapeFlag::eSIMULATION_SHAPE,true);
|
||||
}
|
||||
|
||||
void Px3Player::disableCollision()
|
||||
{
|
||||
AssertFatal( mController, "Px3Player::disableCollision - The controller is null!" );
|
||||
|
||||
mWorld->releaseWriteLock();
|
||||
px3GetFirstShape(mController->getActor())->setFlag(physx::PxShapeFlag::eSIMULATION_SHAPE,false);
|
||||
}
|
||||
|
||||
PhysicsWorld* Px3Player::getWorld()
|
||||
{
|
||||
return mWorld;
|
||||
}
|
||||
|
||||
void Px3Player::setTransform( const MatrixF &transform )
|
||||
{
|
||||
AssertFatal( mController, "Px3Player::setTransform - The controller is null!" );
|
||||
|
||||
mWorld->releaseWriteLock();
|
||||
|
||||
Point3F newPos = transform.getPosition();
|
||||
newPos.z += mOriginOffset;
|
||||
|
||||
const Point3F &curPos = px3Cast<Point3F>(mController->getPosition());
|
||||
|
||||
if ( !(newPos - curPos ).isZero() )
|
||||
mController->setPosition( px3Cast<physx::PxExtendedVec3>(newPos) );
|
||||
}
|
||||
|
||||
MatrixF& Px3Player::getTransform( MatrixF *outMatrix )
|
||||
{
|
||||
AssertFatal( mController, "Px3Player::getTransform - The controller is null!" );
|
||||
|
||||
Point3F newPos = px3Cast<Point3F>( mController->getPosition() );
|
||||
newPos.z -= mOriginOffset;
|
||||
outMatrix->setPosition( newPos );
|
||||
|
||||
return *outMatrix;
|
||||
}
|
||||
|
||||
void Px3Player::setScale( const Point3F &scale )
|
||||
{
|
||||
//Ignored
|
||||
}
|
||||
|
||||
Box3F Px3Player::getWorldBounds()
|
||||
{
|
||||
physx::PxBounds3 bounds;
|
||||
physx::PxRigidDynamic *actor = mController->getActor();
|
||||
physx::PxShape *shape = px3GetFirstShape(actor);
|
||||
bounds = physx::PxShapeExt::getWorldBounds(*shape,*actor);
|
||||
return px3Cast<Box3F>( bounds );
|
||||
}
|
||||
|
||||
104
Engine/source/T3D/physics/physx3/px3Player.h
Normal file
104
Engine/source/T3D/physics/physx3/px3Player.h
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _PX3PLAYER_H
|
||||
#define _PX3PLAYER_H
|
||||
|
||||
#ifndef _PHYSX3_H_
|
||||
#include "T3D/physics/physx3/px3.h"
|
||||
#endif
|
||||
#ifndef _T3D_PHYSICS_PHYSICSPLAYER_H_
|
||||
#include "T3D/physics/physicsPlayer.h"
|
||||
#endif
|
||||
#ifndef _T3D_PHYSICSCOMMON_H_
|
||||
#include "T3D/physics/physicsCommon.h"
|
||||
#endif
|
||||
|
||||
class Px3World;
|
||||
|
||||
class Px3Player : public PhysicsPlayer, public physx::PxUserControllerHitReport
|
||||
{
|
||||
protected:
|
||||
|
||||
physx::PxController *mController;
|
||||
physx::PxCapsuleGeometry mGeometry;
|
||||
F32 mSkinWidth;
|
||||
|
||||
Px3World *mWorld;
|
||||
|
||||
SceneObject *mObject;
|
||||
|
||||
/// Used to get collision info out of the
|
||||
/// PxUserControllerHitReport callbacks.
|
||||
CollisionList *mCollisionList;
|
||||
|
||||
///
|
||||
F32 mOriginOffset;
|
||||
|
||||
///
|
||||
F32 mStepHeight;
|
||||
U32 mElapsed;
|
||||
///
|
||||
void _releaseController();
|
||||
|
||||
|
||||
virtual void onShapeHit( const physx::PxControllerShapeHit &hit );
|
||||
virtual void onControllerHit( const physx::PxControllersHit &hit );
|
||||
virtual void onObstacleHit(const physx::PxControllerObstacleHit &){}
|
||||
|
||||
void _findContact( SceneObject **contactObject, VectorF *contactNormal ) const;
|
||||
|
||||
void _onPhysicsReset( PhysicsResetEvent reset );
|
||||
|
||||
void _onStaticChanged();
|
||||
|
||||
public:
|
||||
|
||||
Px3Player();
|
||||
virtual ~Px3Player();
|
||||
|
||||
// PhysicsObject
|
||||
virtual PhysicsWorld* getWorld();
|
||||
virtual void setTransform( const MatrixF &transform );
|
||||
virtual MatrixF& getTransform( MatrixF *outMatrix );
|
||||
virtual void setScale( const Point3F &scale );
|
||||
virtual Box3F getWorldBounds();
|
||||
virtual void setSimulationEnabled( bool enabled ) {}
|
||||
virtual bool isSimulationEnabled() { return true; }
|
||||
|
||||
// PhysicsPlayer
|
||||
virtual void init( const char *type,
|
||||
const Point3F &size,
|
||||
F32 runSurfaceCos,
|
||||
F32 stepHeight,
|
||||
SceneObject *obj,
|
||||
PhysicsWorld *world );
|
||||
virtual Point3F move( const VectorF &displacement, CollisionList &outCol );
|
||||
virtual void findContact( SceneObject **contactObject, VectorF *contactNormal, Vector<SceneObject*> *outOverlapObjects ) const;
|
||||
virtual bool testSpacials( const Point3F &nPos, const Point3F &nSize ) const { return true; }
|
||||
virtual void setSpacials( const Point3F &nPos, const Point3F &nSize ) {}
|
||||
virtual void enableCollision();
|
||||
virtual void disableCollision();
|
||||
};
|
||||
|
||||
|
||||
#endif // _PX3PLAYER_H_
|
||||
226
Engine/source/T3D/physics/physx3/px3Plugin.cpp
Normal file
226
Engine/source/T3D/physics/physx3/px3Plugin.cpp
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "console/consoleTypes.h"
|
||||
#include "T3D/physics/physx3/px3World.h"
|
||||
#include "T3D/physics/physx3/px3Plugin.h"
|
||||
#include "T3D/physics/physx3/px3Collision.h"
|
||||
#include "T3D/physics/physx3/px3Body.h"
|
||||
#include "T3D/physics/physx3/px3Player.h"
|
||||
|
||||
#include "T3D/physics/physicsShape.h"
|
||||
#include "T3D/gameBase/gameProcess.h"
|
||||
#include "core/util/tNamedFactory.h"
|
||||
|
||||
|
||||
AFTER_MODULE_INIT( Sim )
|
||||
{
|
||||
NamedFactory<PhysicsPlugin>::add( "PhysX3", &Px3Plugin::create );
|
||||
|
||||
#if defined(TORQUE_OS_WIN) || defined(TORQUE_OS_XBOX) || defined(TORQUE_OS_XENON)
|
||||
NamedFactory<PhysicsPlugin>::add( "default", &Px3Plugin::create );
|
||||
#endif
|
||||
}
|
||||
|
||||
PhysicsPlugin* Px3Plugin::create()
|
||||
{
|
||||
// Only create the plugin if it hasn't been set up AND
|
||||
// the PhysX world is successfully initialized.
|
||||
bool success = Px3World::restartSDK( false );
|
||||
if ( success )
|
||||
return new Px3Plugin();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Px3Plugin::Px3Plugin()
|
||||
{
|
||||
}
|
||||
|
||||
Px3Plugin::~Px3Plugin()
|
||||
{
|
||||
}
|
||||
|
||||
void Px3Plugin::destroyPlugin()
|
||||
{
|
||||
// Cleanup any worlds that are still kicking.
|
||||
Map<StringNoCase, PhysicsWorld*>::Iterator iter = mPhysicsWorldLookup.begin();
|
||||
for ( ; iter != mPhysicsWorldLookup.end(); iter++ )
|
||||
{
|
||||
iter->value->destroyWorld();
|
||||
delete iter->value;
|
||||
}
|
||||
mPhysicsWorldLookup.clear();
|
||||
|
||||
Px3World::restartSDK( true );
|
||||
|
||||
delete this;
|
||||
}
|
||||
|
||||
void Px3Plugin::reset()
|
||||
{
|
||||
// First delete all the cleanup objects.
|
||||
if ( getPhysicsCleanup() )
|
||||
getPhysicsCleanup()->deleteAllObjects();
|
||||
|
||||
getPhysicsResetSignal().trigger( PhysicsResetEvent_Restore );
|
||||
|
||||
// Now let each world reset itself.
|
||||
Map<StringNoCase, PhysicsWorld*>::Iterator iter = mPhysicsWorldLookup.begin();
|
||||
for ( ; iter != mPhysicsWorldLookup.end(); iter++ )
|
||||
iter->value->reset();
|
||||
}
|
||||
|
||||
PhysicsCollision* Px3Plugin::createCollision()
|
||||
{
|
||||
return new Px3Collision();
|
||||
}
|
||||
|
||||
PhysicsBody* Px3Plugin::createBody()
|
||||
{
|
||||
return new Px3Body();
|
||||
}
|
||||
|
||||
PhysicsPlayer* Px3Plugin::createPlayer()
|
||||
{
|
||||
return new Px3Player();
|
||||
}
|
||||
|
||||
bool Px3Plugin::isSimulationEnabled() const
|
||||
{
|
||||
bool ret = false;
|
||||
Px3World *world = static_cast<Px3World*>( getWorld( smClientWorldName ) );
|
||||
if ( world )
|
||||
{
|
||||
ret = world->isEnabled();
|
||||
return ret;
|
||||
}
|
||||
|
||||
world = static_cast<Px3World*>( getWorld( smServerWorldName ) );
|
||||
if ( world )
|
||||
{
|
||||
ret = world->isEnabled();
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Px3Plugin::enableSimulation( const String &worldName, bool enable )
|
||||
{
|
||||
Px3World *world = static_cast<Px3World*>( getWorld( worldName ) );
|
||||
if ( world )
|
||||
world->setEnabled( enable );
|
||||
}
|
||||
|
||||
void Px3Plugin::setTimeScale( const F32 timeScale )
|
||||
{
|
||||
// Grab both the client and
|
||||
// server worlds and set their time
|
||||
// scales to the passed value.
|
||||
Px3World *world = static_cast<Px3World*>( getWorld( smClientWorldName ) );
|
||||
if ( world )
|
||||
world->setEditorTimeScale( timeScale );
|
||||
|
||||
world = static_cast<Px3World*>( getWorld( smServerWorldName ) );
|
||||
if ( world )
|
||||
world->setEditorTimeScale( timeScale );
|
||||
}
|
||||
|
||||
const F32 Px3Plugin::getTimeScale() const
|
||||
{
|
||||
// Grab both the client and
|
||||
// server worlds and call
|
||||
// setEnabled( true ) on them.
|
||||
Px3World *world = static_cast<Px3World*>( getWorld( smClientWorldName ) );
|
||||
if ( !world )
|
||||
{
|
||||
world = static_cast<Px3World*>( getWorld( smServerWorldName ) );
|
||||
if ( !world )
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
return world->getEditorTimeScale();
|
||||
}
|
||||
|
||||
bool Px3Plugin::createWorld( const String &worldName )
|
||||
{
|
||||
Map<StringNoCase, PhysicsWorld*>::Iterator iter = mPhysicsWorldLookup.find( worldName );
|
||||
PhysicsWorld *world = NULL;
|
||||
|
||||
iter != mPhysicsWorldLookup.end() ? world = (*iter).value : world = NULL;
|
||||
|
||||
if ( world )
|
||||
{
|
||||
Con::errorf( "Px3Plugin::createWorld - %s world already exists!", worldName.c_str() );
|
||||
return false;
|
||||
}
|
||||
|
||||
world = new Px3World();
|
||||
|
||||
if ( worldName.equal( smClientWorldName, String::NoCase ) )
|
||||
world->initWorld( false, ClientProcessList::get() );
|
||||
else
|
||||
world->initWorld( true, ServerProcessList::get() );
|
||||
|
||||
mPhysicsWorldLookup.insert( worldName, world );
|
||||
|
||||
return world != NULL;
|
||||
}
|
||||
|
||||
void Px3Plugin::destroyWorld( const String &worldName )
|
||||
{
|
||||
Map<StringNoCase, PhysicsWorld*>::Iterator iter = mPhysicsWorldLookup.find( worldName );
|
||||
if ( iter == mPhysicsWorldLookup.end() )
|
||||
return;
|
||||
|
||||
PhysicsWorld *world = (*iter).value;
|
||||
world->destroyWorld();
|
||||
delete world;
|
||||
|
||||
mPhysicsWorldLookup.erase( iter );
|
||||
}
|
||||
|
||||
PhysicsWorld* Px3Plugin::getWorld( const String &worldName ) const
|
||||
{
|
||||
if ( mPhysicsWorldLookup.isEmpty() )
|
||||
return NULL;
|
||||
|
||||
Map<StringNoCase, PhysicsWorld*>::ConstIterator iter = mPhysicsWorldLookup.find( worldName );
|
||||
|
||||
return iter != mPhysicsWorldLookup.end() ? (*iter).value : NULL;
|
||||
}
|
||||
|
||||
PhysicsWorld* Px3Plugin::getWorld() const
|
||||
{
|
||||
if ( mPhysicsWorldLookup.size() == 0 )
|
||||
return NULL;
|
||||
|
||||
Map<StringNoCase, PhysicsWorld*>::ConstIterator iter = mPhysicsWorldLookup.begin();
|
||||
return iter->value;
|
||||
}
|
||||
|
||||
U32 Px3Plugin::getWorldCount() const
|
||||
{
|
||||
return mPhysicsWorldLookup.size();
|
||||
}
|
||||
59
Engine/source/T3D/physics/physx3/px3Plugin.h
Normal file
59
Engine/source/T3D/physics/physx3/px3Plugin.h
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _PX3PLUGIN_H_
|
||||
#define _PX3PLUGIN_H_
|
||||
|
||||
#ifndef _T3D_PHYSICS_PHYSICSPLUGIN_H_
|
||||
#include "T3D/physics/physicsPlugin.h"
|
||||
#endif
|
||||
|
||||
class Px3ClothShape;
|
||||
|
||||
class Px3Plugin : public PhysicsPlugin
|
||||
{
|
||||
public:
|
||||
|
||||
Px3Plugin();
|
||||
~Px3Plugin();
|
||||
|
||||
/// Create function for factory.
|
||||
static PhysicsPlugin* create();
|
||||
|
||||
// PhysicsPlugin
|
||||
virtual void destroyPlugin();
|
||||
virtual void reset();
|
||||
virtual PhysicsCollision* createCollision();
|
||||
virtual PhysicsBody* createBody();
|
||||
virtual PhysicsPlayer* createPlayer();
|
||||
virtual bool isSimulationEnabled() const;
|
||||
virtual void enableSimulation( const String &worldName, bool enable );
|
||||
virtual void setTimeScale( const F32 timeScale );
|
||||
virtual const F32 getTimeScale() const;
|
||||
virtual bool createWorld( const String &worldName );
|
||||
virtual void destroyWorld( const String &worldName );
|
||||
virtual PhysicsWorld* getWorld( const String &worldName ) const;
|
||||
virtual PhysicsWorld* getWorld() const;
|
||||
virtual U32 getWorldCount() const;
|
||||
};
|
||||
|
||||
#endif // _PX3PLUGIN_H_
|
||||
92
Engine/source/T3D/physics/physx3/px3Stream.cpp
Normal file
92
Engine/source/T3D/physics/physx3/px3Stream.cpp
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/physics/physx3/px3Stream.h"
|
||||
|
||||
#include "console/console.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "core/strings/stringFunctions.h"
|
||||
|
||||
|
||||
Px3MemOutStream::Px3MemOutStream() : mMemStream(1024)
|
||||
{
|
||||
}
|
||||
|
||||
Px3MemOutStream::~Px3MemOutStream()
|
||||
{
|
||||
}
|
||||
|
||||
physx::PxU32 Px3MemOutStream::write(const void *src, physx::PxU32 count)
|
||||
{
|
||||
physx::PxU32 out=0;
|
||||
if(!mMemStream.write(count,src))
|
||||
return out;
|
||||
|
||||
out = count;
|
||||
return out;
|
||||
}
|
||||
|
||||
Px3MemInStream::Px3MemInStream(physx::PxU8* data, physx::PxU32 length):mMemStream(length,data)
|
||||
{
|
||||
}
|
||||
|
||||
physx::PxU32 Px3MemInStream::read(void* dest, physx::PxU32 count)
|
||||
{
|
||||
physx::PxU32 read =0;
|
||||
if(!mMemStream.read(count,dest))
|
||||
return read;
|
||||
|
||||
read = count;
|
||||
return read;
|
||||
}
|
||||
|
||||
void Px3MemInStream::seek(physx::PxU32 pos)
|
||||
{
|
||||
mMemStream.setPosition(pos);
|
||||
}
|
||||
|
||||
physx::PxU32 Px3MemInStream::getLength() const
|
||||
{
|
||||
return mMemStream.getStreamSize();
|
||||
}
|
||||
|
||||
physx::PxU32 Px3MemInStream::tell() const
|
||||
{
|
||||
return mMemStream.getPosition();
|
||||
}
|
||||
|
||||
Px3ConsoleStream::Px3ConsoleStream()
|
||||
{
|
||||
}
|
||||
|
||||
Px3ConsoleStream::~Px3ConsoleStream()
|
||||
{
|
||||
}
|
||||
|
||||
void Px3ConsoleStream::reportError( physx::PxErrorCode code, const char *message, const char* file, int line )
|
||||
{
|
||||
UTF8 info[1024];
|
||||
dSprintf( info, 1024, "File: %s\nLine: %d\n%s", file, line, message );
|
||||
Platform::AlertOK( "PhysX Error", info );
|
||||
// Con::printf( "PhysX Error:\n %s(%d) : %s\n", file, line, message );
|
||||
}
|
||||
77
Engine/source/T3D/physics/physx3/px3Stream.h
Normal file
77
Engine/source/T3D/physics/physx3/px3Stream.h
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _PX3STREAM_H_
|
||||
#define _PX3STREAM_H_
|
||||
|
||||
#ifndef _PHYSX3_H_
|
||||
#include "T3D/physics/physx3/px3.h"
|
||||
#endif
|
||||
#ifndef _MEMSTREAM_H_
|
||||
#include "core/stream/memStream.h"
|
||||
#endif
|
||||
|
||||
|
||||
class Px3MemOutStream : public physx::PxOutputStream
|
||||
{
|
||||
public:
|
||||
|
||||
Px3MemOutStream();
|
||||
virtual ~Px3MemOutStream();
|
||||
|
||||
void resetPosition();
|
||||
|
||||
virtual physx::PxU32 write(const void *src, physx::PxU32 count);
|
||||
physx::PxU32 getSize() const {return mMemStream.getStreamSize();}
|
||||
physx::PxU8* getData() const {return (physx::PxU8*)mMemStream.getBuffer();}
|
||||
|
||||
protected:
|
||||
|
||||
mutable MemStream mMemStream;
|
||||
};
|
||||
|
||||
class Px3MemInStream: public physx::PxInputData
|
||||
{
|
||||
public:
|
||||
Px3MemInStream(physx::PxU8* data, physx::PxU32 length);
|
||||
virtual physx::PxU32 read(void* dest, physx::PxU32 count);
|
||||
physx::PxU32 getLength() const;
|
||||
virtual void seek(physx::PxU32 pos);
|
||||
virtual physx::PxU32 tell() const;
|
||||
protected:
|
||||
mutable MemStream mMemStream;
|
||||
|
||||
};
|
||||
|
||||
class Px3ConsoleStream : public physx::PxDefaultErrorCallback
|
||||
{
|
||||
protected:
|
||||
|
||||
virtual void reportError( physx::PxErrorCode code, const char *message, const char* file, int line );
|
||||
|
||||
public:
|
||||
|
||||
Px3ConsoleStream();
|
||||
virtual ~Px3ConsoleStream();
|
||||
};
|
||||
|
||||
#endif // _PX3STREAM_H_
|
||||
32
Engine/source/T3D/physics/physx3/px3Utils.cpp
Normal file
32
Engine/source/T3D/physics/physx3/px3Utils.cpp
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/physics/physx3/px3Utils.h"
|
||||
#include "T3D/physics/physx3/px3.h"
|
||||
|
||||
physx::PxShape* px3GetFirstShape(physx::PxRigidActor *actor)
|
||||
{
|
||||
physx::PxShape *shapes[1];
|
||||
actor->getShapes(shapes, 1);
|
||||
return shapes[0];
|
||||
}
|
||||
34
Engine/source/T3D/physics/physx3/px3Utils.h
Normal file
34
Engine/source/T3D/physics/physx3/px3Utils.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _PX3UTILS_H_
|
||||
#define _PX3UTILS_H_
|
||||
|
||||
namespace physx
|
||||
{
|
||||
class PxRigidActor;
|
||||
class PxShape;
|
||||
}
|
||||
|
||||
extern physx::PxShape* px3GetFirstShape(physx::PxRigidActor *actor);
|
||||
|
||||
#endif // _PX3UTILS_H_
|
||||
565
Engine/source/T3D/physics/physx3/px3World.cpp
Normal file
565
Engine/source/T3D/physics/physx3/px3World.cpp
Normal file
|
|
@ -0,0 +1,565 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/physics/physx3/px3World.h"
|
||||
|
||||
#include "T3D/physics/physx3/px3.h"
|
||||
#include "T3D/physics/physx3/px3Plugin.h"
|
||||
#include "T3D/physics/physx3/px3Casts.h"
|
||||
#include "T3D/physics/physx3/px3Stream.h"
|
||||
#include "T3D/physics/physicsUserData.h"
|
||||
|
||||
#include "console/engineAPI.h"
|
||||
#include "core/stream/bitStream.h"
|
||||
#include "platform/profiler.h"
|
||||
#include "sim/netConnection.h"
|
||||
#include "console/console.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "core/util/safeDelete.h"
|
||||
#include "collision/collision.h"
|
||||
#include "T3D/gameBase/gameProcess.h"
|
||||
#include "gfx/sim/debugDraw.h"
|
||||
#include "gfx/primBuilder.h"
|
||||
|
||||
|
||||
physx::PxPhysics* gPhysics3SDK = NULL;
|
||||
physx::PxCooking* Px3World::smCooking = NULL;
|
||||
physx::PxFoundation* Px3World::smFoundation = NULL;
|
||||
physx::PxProfileZoneManager* Px3World::smProfileZoneManager = NULL;
|
||||
physx::PxDefaultCpuDispatcher* Px3World::smCpuDispatcher=NULL;
|
||||
Px3ConsoleStream* Px3World::smErrorCallback = NULL;
|
||||
physx::PxVisualDebuggerConnection* Px3World::smPvdConnection=NULL;
|
||||
physx::PxDefaultAllocator Px3World::smMemoryAlloc;
|
||||
//Physics timing
|
||||
F32 Px3World::smPhysicsStepTime = 1.0f/(F32)TickMs;
|
||||
U32 Px3World::smPhysicsMaxIterations = 4;
|
||||
|
||||
Px3World::Px3World(): mScene( NULL ),
|
||||
mProcessList( NULL ),
|
||||
mIsSimulating( false ),
|
||||
mErrorReport( false ),
|
||||
mTickCount( 0 ),
|
||||
mIsEnabled( false ),
|
||||
mEditorTimeScale( 1.0f ),
|
||||
mAccumulator( 0 ),
|
||||
mControllerManager( NULL )
|
||||
{
|
||||
}
|
||||
|
||||
Px3World::~Px3World()
|
||||
{
|
||||
}
|
||||
|
||||
physx::PxCooking *Px3World::getCooking()
|
||||
{
|
||||
return smCooking;
|
||||
}
|
||||
|
||||
void Px3World::setTiming(F32 stepTime,U32 maxIterations)
|
||||
{
|
||||
smPhysicsStepTime = stepTime;
|
||||
smPhysicsMaxIterations = maxIterations;
|
||||
}
|
||||
|
||||
bool Px3World::restartSDK( bool destroyOnly, Px3World *clientWorld, Px3World *serverWorld)
|
||||
{
|
||||
// If either the client or the server still exist
|
||||
// then we cannot reset the SDK.
|
||||
if ( clientWorld || serverWorld )
|
||||
return false;
|
||||
|
||||
if(smPvdConnection)
|
||||
smPvdConnection->release();
|
||||
|
||||
if(smCooking)
|
||||
smCooking->release();
|
||||
|
||||
if(smCpuDispatcher)
|
||||
smCpuDispatcher->release();
|
||||
|
||||
// Destroy the existing SDK.
|
||||
if ( gPhysics3SDK )
|
||||
{
|
||||
PxCloseExtensions();
|
||||
gPhysics3SDK->release();
|
||||
}
|
||||
|
||||
if(smErrorCallback)
|
||||
{
|
||||
SAFE_DELETE(smErrorCallback);
|
||||
}
|
||||
|
||||
if(smFoundation)
|
||||
{
|
||||
smFoundation->release();
|
||||
SAFE_DELETE(smErrorCallback);
|
||||
}
|
||||
|
||||
// If we're not supposed to restart... return.
|
||||
if ( destroyOnly )
|
||||
return true;
|
||||
|
||||
bool memTrack = false;
|
||||
#ifdef TORQUE_DEBUG
|
||||
memTrack = true;
|
||||
#endif
|
||||
|
||||
smErrorCallback = new Px3ConsoleStream;
|
||||
smFoundation = PxCreateFoundation(PX_PHYSICS_VERSION, smMemoryAlloc, *smErrorCallback);
|
||||
smProfileZoneManager = &physx::PxProfileZoneManager::createProfileZoneManager(smFoundation);
|
||||
gPhysics3SDK = PxCreatePhysics(PX_PHYSICS_VERSION, *smFoundation, physx::PxTolerancesScale(),memTrack,smProfileZoneManager);
|
||||
|
||||
if ( !gPhysics3SDK )
|
||||
{
|
||||
Con::errorf( "PhysX3 failed to initialize!" );
|
||||
Platform::messageBox( Con::getVariable( "$appName" ),
|
||||
avar("PhysX3 could not be started!\r\n"),
|
||||
MBOk, MIStop );
|
||||
Platform::forceShutdown( -1 );
|
||||
|
||||
// We shouldn't get here, but this shuts up
|
||||
// source diagnostic tools.
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!PxInitExtensions(*gPhysics3SDK))
|
||||
{
|
||||
Con::errorf( "PhysX3 failed to initialize extensions!" );
|
||||
Platform::messageBox( Con::getVariable( "$appName" ),
|
||||
avar("PhysX3 could not be started!\r\n"),
|
||||
MBOk, MIStop );
|
||||
Platform::forceShutdown( -1 );
|
||||
return false;
|
||||
}
|
||||
|
||||
smCooking = PxCreateCooking(PX_PHYSICS_VERSION, *smFoundation, physx::PxCookingParams(physx::PxTolerancesScale()));
|
||||
if(!smCooking)
|
||||
{
|
||||
Con::errorf( "PhysX3 failed to initialize cooking!" );
|
||||
Platform::messageBox( Con::getVariable( "$appName" ),
|
||||
avar("PhysX3 could not be started!\r\n"),
|
||||
MBOk, MIStop );
|
||||
Platform::forceShutdown( -1 );
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef TORQUE_DEBUG
|
||||
physx::PxVisualDebuggerConnectionFlags connectionFlags(physx::PxVisualDebuggerExt::getAllConnectionFlags());
|
||||
smPvdConnection = physx::PxVisualDebuggerExt::createConnection(gPhysics3SDK->getPvdConnectionManager(),
|
||||
"localhost", 5425, 100, connectionFlags);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Px3World::destroyWorld()
|
||||
{
|
||||
getPhysicsResults();
|
||||
|
||||
// Release the tick processing signals.
|
||||
if ( mProcessList )
|
||||
{
|
||||
mProcessList->preTickSignal().remove( this, &Px3World::getPhysicsResults );
|
||||
mProcessList->postTickSignal().remove( this, &Px3World::tickPhysics );
|
||||
mProcessList = NULL;
|
||||
}
|
||||
|
||||
if(mControllerManager)
|
||||
{
|
||||
mControllerManager->release();
|
||||
mControllerManager = NULL;
|
||||
}
|
||||
|
||||
// Destroy the scene.
|
||||
if ( mScene )
|
||||
{
|
||||
// Release the scene.
|
||||
mScene->release();
|
||||
mScene = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool Px3World::initWorld( bool isServer, ProcessList *processList )
|
||||
{
|
||||
if ( !gPhysics3SDK )
|
||||
{
|
||||
Con::errorf( "Physx3World::init - PhysXSDK not initialized!" );
|
||||
return false;
|
||||
}
|
||||
|
||||
mIsServer = isServer;
|
||||
|
||||
physx::PxSceneDesc sceneDesc(gPhysics3SDK->getTolerancesScale());
|
||||
|
||||
sceneDesc.gravity = px3Cast<physx::PxVec3>(mGravity);
|
||||
sceneDesc.userData = this;
|
||||
if(!sceneDesc.cpuDispatcher)
|
||||
{
|
||||
smCpuDispatcher = physx::PxDefaultCpuDispatcherCreate(PHYSICSMGR->getThreadCount());
|
||||
sceneDesc.cpuDispatcher = smCpuDispatcher;
|
||||
Con::printf("PhysX3 using Cpu: %d workers", smCpuDispatcher->getWorkerCount());
|
||||
}
|
||||
|
||||
|
||||
sceneDesc.flags |= physx::PxSceneFlag::eENABLE_CCD;
|
||||
sceneDesc.flags |= physx::PxSceneFlag::eENABLE_ACTIVETRANSFORMS;
|
||||
sceneDesc.filterShader = physx::PxDefaultSimulationFilterShader;
|
||||
|
||||
mScene = gPhysics3SDK->createScene(sceneDesc);
|
||||
|
||||
physx::PxDominanceGroupPair debrisDominance( 0.0f, 1.0f );
|
||||
mScene->setDominanceGroupPair(0,31,debrisDominance);
|
||||
|
||||
mControllerManager = PxCreateControllerManager(*mScene);
|
||||
|
||||
AssertFatal( processList, "Px3World::init() - We need a process list to create the world!" );
|
||||
mProcessList = processList;
|
||||
mProcessList->preTickSignal().notify( this, &Px3World::getPhysicsResults );
|
||||
mProcessList->postTickSignal().notify( this, &Px3World::tickPhysics, 1000.0f );
|
||||
|
||||
return true;
|
||||
}
|
||||
// Most of this borrowed from bullet physics library, see btDiscreteDynamicsWorld.cpp
|
||||
bool Px3World::_simulate(const F32 dt)
|
||||
{
|
||||
int numSimulationSubSteps = 0;
|
||||
//fixed timestep with interpolation
|
||||
mAccumulator += dt;
|
||||
if (mAccumulator >= smPhysicsStepTime)
|
||||
{
|
||||
numSimulationSubSteps = int(mAccumulator / smPhysicsStepTime);
|
||||
mAccumulator -= numSimulationSubSteps * smPhysicsStepTime;
|
||||
}
|
||||
if (numSimulationSubSteps)
|
||||
{
|
||||
//clamp the number of substeps, to prevent simulation grinding spiralling down to a halt
|
||||
int clampedSimulationSteps = (numSimulationSubSteps > smPhysicsMaxIterations)? smPhysicsMaxIterations : numSimulationSubSteps;
|
||||
|
||||
for (int i=0;i<clampedSimulationSteps;i++)
|
||||
{
|
||||
mScene->fetchResults(true);
|
||||
mScene->simulate(smPhysicsStepTime);
|
||||
}
|
||||
}
|
||||
|
||||
mIsSimulating = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Px3World::tickPhysics( U32 elapsedMs )
|
||||
{
|
||||
if ( !mScene || !mIsEnabled )
|
||||
return;
|
||||
|
||||
// Did we forget to call getPhysicsResults somewhere?
|
||||
AssertFatal( !mIsSimulating, "PhysX3World::tickPhysics() - Already simulating!" );
|
||||
|
||||
// The elapsed time should be non-zero and
|
||||
// a multiple of TickMs!
|
||||
AssertFatal( elapsedMs != 0 &&
|
||||
( elapsedMs % TickMs ) == 0 , "PhysX3World::tickPhysics() - Got bad elapsed time!" );
|
||||
|
||||
PROFILE_SCOPE(Px3World_TickPhysics);
|
||||
|
||||
// Convert it to seconds.
|
||||
const F32 elapsedSec = (F32)elapsedMs * 0.001f;
|
||||
mIsSimulating = _simulate(elapsedSec * mEditorTimeScale);
|
||||
|
||||
//Con::printf( "%s PhysX3World::tickPhysics!", mIsServer ? "Client" : "Server" );
|
||||
}
|
||||
|
||||
void Px3World::getPhysicsResults()
|
||||
{
|
||||
if ( !mScene || !mIsSimulating )
|
||||
return;
|
||||
|
||||
PROFILE_SCOPE(Px3World_GetPhysicsResults);
|
||||
|
||||
// Get results from scene.
|
||||
mScene->fetchResults(true);
|
||||
mIsSimulating = false;
|
||||
mTickCount++;
|
||||
|
||||
// Con::printf( "%s PhysXWorld::getPhysicsResults!", this == smClientWorld ? "Client" : "Server" );
|
||||
}
|
||||
|
||||
void Px3World::releaseWriteLocks()
|
||||
{
|
||||
Px3World *world = dynamic_cast<Px3World*>( PHYSICSMGR->getWorld( "server" ) );
|
||||
|
||||
if ( world )
|
||||
world->releaseWriteLock();
|
||||
|
||||
world = dynamic_cast<Px3World*>( PHYSICSMGR->getWorld( "client" ) );
|
||||
|
||||
if ( world )
|
||||
world->releaseWriteLock();
|
||||
}
|
||||
|
||||
void Px3World::releaseWriteLock()
|
||||
{
|
||||
if ( !mScene || !mIsSimulating )
|
||||
return;
|
||||
|
||||
PROFILE_SCOPE(PxWorld_ReleaseWriteLock);
|
||||
|
||||
// We use checkResults here to release the write lock
|
||||
// but we do not change the simulation flag or increment
|
||||
// the tick count... we may have gotten results, but the
|
||||
// simulation hasn't really ticked!
|
||||
mScene->checkResults( true );
|
||||
//AssertFatal( mScene->isWritable(), "PhysX3World::releaseWriteLock() - We should have been writable now!" );
|
||||
}
|
||||
|
||||
bool Px3World::castRay( const Point3F &startPnt, const Point3F &endPnt, RayInfo *ri, const Point3F &impulse )
|
||||
{
|
||||
|
||||
physx::PxVec3 orig = px3Cast<physx::PxVec3>( startPnt );
|
||||
physx::PxVec3 dir = px3Cast<physx::PxVec3>( endPnt - startPnt );
|
||||
physx::PxF32 maxDist = dir.magnitude();
|
||||
dir.normalize();
|
||||
|
||||
U32 groups = 0xffffffff;
|
||||
groups &= ~( PX3_TRIGGER ); // No trigger shapes!
|
||||
|
||||
physx::PxHitFlags outFlags(physx::PxHitFlag::eDISTANCE | physx::PxHitFlag::eIMPACT | physx::PxHitFlag::eNORMAL);
|
||||
physx::PxQueryFilterData filterData(physx::PxQueryFlag::eSTATIC|physx::PxQueryFlag::eDYNAMIC);
|
||||
filterData.data.word0 = groups;
|
||||
physx::PxRaycastBuffer buf;
|
||||
|
||||
if(!mScene->raycast(orig,dir,maxDist,buf,outFlags,filterData))
|
||||
return false;
|
||||
if(!buf.hasBlock)
|
||||
return false;
|
||||
|
||||
const physx::PxRaycastHit hit = buf.block;
|
||||
physx::PxRigidActor *actor = hit.actor;
|
||||
PhysicsUserData *userData = PhysicsUserData::cast( actor->userData );
|
||||
|
||||
if ( ri )
|
||||
{
|
||||
ri->object = ( userData != NULL ) ? userData->getObject() : NULL;
|
||||
|
||||
if ( ri->object == NULL )
|
||||
|
||||
ri->distance = hit.distance;
|
||||
ri->normal = px3Cast<Point3F>( hit.normal );
|
||||
ri->point = px3Cast<Point3F>( hit.position );
|
||||
ri->t = maxDist / hit.distance;
|
||||
}
|
||||
|
||||
if ( impulse.isZero() ||
|
||||
!actor->isRigidDynamic() ||
|
||||
actor->is<physx::PxRigidDynamic>()->getRigidDynamicFlags() & physx::PxRigidDynamicFlag::eKINEMATIC )
|
||||
return true;
|
||||
|
||||
physx::PxRigidBody *body = actor->is<physx::PxRigidBody>();
|
||||
physx::PxVec3 force = px3Cast<physx::PxVec3>( impulse );
|
||||
physx::PxRigidBodyExt::addForceAtPos(*body,force,hit.position,physx::PxForceMode::eIMPULSE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
PhysicsBody* Px3World::castRay( const Point3F &start, const Point3F &end, U32 bodyTypes )
|
||||
{
|
||||
physx::PxVec3 orig = px3Cast<physx::PxVec3>( start );
|
||||
physx::PxVec3 dir = px3Cast<physx::PxVec3>( end - start );
|
||||
physx::PxF32 maxDist = dir.magnitude();
|
||||
dir.normalize();
|
||||
|
||||
U32 groups = 0xFFFFFFFF;
|
||||
if ( !( bodyTypes & BT_Player ) )
|
||||
groups &= ~( PX3_PLAYER );
|
||||
|
||||
// TODO: For now always skip triggers and debris,
|
||||
// but we should consider how game specifc this API
|
||||
// should be in the future.
|
||||
groups &= ~( PX3_TRIGGER ); // triggers
|
||||
groups &= ~( PX3_DEBRIS ); // debris
|
||||
|
||||
physx::PxHitFlags outFlags(physx::PxHitFlag::eDISTANCE | physx::PxHitFlag::eIMPACT | physx::PxHitFlag::eNORMAL);
|
||||
physx::PxQueryFilterData filterData;
|
||||
if(bodyTypes & BT_Static)
|
||||
filterData.flags |= physx::PxQueryFlag::eSTATIC;
|
||||
if(bodyTypes & BT_Dynamic)
|
||||
filterData.flags |= physx::PxQueryFlag::eDYNAMIC;
|
||||
|
||||
filterData.data.word0 = groups;
|
||||
physx::PxRaycastBuffer buf;
|
||||
|
||||
if( !mScene->raycast(orig,dir,maxDist,buf,outFlags,filterData) )
|
||||
return NULL;
|
||||
if(!buf.hasBlock)
|
||||
return NULL;
|
||||
|
||||
physx::PxRigidActor *actor = buf.block.actor;
|
||||
PhysicsUserData *userData = PhysicsUserData::cast( actor->userData );
|
||||
if( !userData )
|
||||
return NULL;
|
||||
|
||||
return userData->getBody();
|
||||
}
|
||||
|
||||
void Px3World::explosion( const Point3F &pos, F32 radius, F32 forceMagnitude )
|
||||
{
|
||||
physx::PxVec3 nxPos = px3Cast<physx::PxVec3>( pos );
|
||||
const physx::PxU32 bufferSize = 10;
|
||||
physx::PxSphereGeometry worldSphere(radius);
|
||||
physx::PxTransform pose(nxPos);
|
||||
physx::PxOverlapBufferN<bufferSize> buffer;
|
||||
|
||||
if(!mScene->overlap(worldSphere,pose,buffer))
|
||||
return;
|
||||
|
||||
for ( physx::PxU32 i = 0; i < buffer.nbTouches; i++ )
|
||||
{
|
||||
physx::PxRigidActor *actor = buffer.touches[i].actor;
|
||||
|
||||
bool dynamic = actor->isRigidDynamic();
|
||||
|
||||
if ( !dynamic )
|
||||
continue;
|
||||
|
||||
bool kinematic = actor->is<physx::PxRigidDynamic>()->getRigidDynamicFlags() & physx::PxRigidDynamicFlag::eKINEMATIC;
|
||||
|
||||
if ( kinematic )
|
||||
continue;
|
||||
|
||||
physx::PxVec3 force = actor->getGlobalPose().p - nxPos;
|
||||
force.normalize();
|
||||
force *= forceMagnitude;
|
||||
|
||||
physx::PxRigidBody *body = actor->is<physx::PxRigidBody>();
|
||||
physx::PxRigidBodyExt::addForceAtPos(*body,force,nxPos,physx::PxForceMode::eIMPULSE);
|
||||
}
|
||||
}
|
||||
|
||||
void Px3World::setEnabled( bool enabled )
|
||||
{
|
||||
mIsEnabled = enabled;
|
||||
|
||||
if ( !mIsEnabled )
|
||||
getPhysicsResults();
|
||||
}
|
||||
|
||||
physx::PxController* Px3World::createController( physx::PxControllerDesc &desc )
|
||||
{
|
||||
if ( !mScene )
|
||||
return NULL;
|
||||
|
||||
// We need the writelock!
|
||||
releaseWriteLock();
|
||||
physx::PxController* pController = mControllerManager->createController(desc);
|
||||
AssertFatal( pController, "Px3World::createController - Got a null!" );
|
||||
return pController;
|
||||
}
|
||||
|
||||
static ColorI getDebugColor( physx::PxU32 packed )
|
||||
{
|
||||
ColorI col;
|
||||
col.blue = (packed)&0xff;
|
||||
col.green = (packed>>8)&0xff;
|
||||
col.red = (packed>>16)&0xff;
|
||||
col.alpha = 255;
|
||||
|
||||
return col;
|
||||
}
|
||||
|
||||
void Px3World::onDebugDraw( const SceneRenderState *state )
|
||||
{
|
||||
if ( !mScene )
|
||||
return;
|
||||
|
||||
mScene->setVisualizationParameter(physx::PxVisualizationParameter::eSCALE,1.0f);
|
||||
mScene->setVisualizationParameter(physx::PxVisualizationParameter::eBODY_AXES,1.0f);
|
||||
mScene->setVisualizationParameter(physx::PxVisualizationParameter::eCOLLISION_SHAPES,1.0f);
|
||||
|
||||
const physx::PxRenderBuffer *renderBuffer = &mScene->getRenderBuffer();
|
||||
|
||||
if(!renderBuffer)
|
||||
return;
|
||||
|
||||
// Render points
|
||||
{
|
||||
physx::PxU32 numPoints = renderBuffer->getNbPoints();
|
||||
const physx::PxDebugPoint *points = renderBuffer->getPoints();
|
||||
|
||||
PrimBuild::begin( GFXPointList, numPoints );
|
||||
|
||||
while ( numPoints-- )
|
||||
{
|
||||
PrimBuild::color( getDebugColor(points->color) );
|
||||
PrimBuild::vertex3fv(px3Cast<Point3F>(points->pos));
|
||||
points++;
|
||||
}
|
||||
|
||||
PrimBuild::end();
|
||||
}
|
||||
|
||||
// Render lines
|
||||
{
|
||||
physx::PxU32 numLines = renderBuffer->getNbLines();
|
||||
const physx::PxDebugLine *lines = renderBuffer->getLines();
|
||||
|
||||
PrimBuild::begin( GFXLineList, numLines * 2 );
|
||||
|
||||
while ( numLines-- )
|
||||
{
|
||||
PrimBuild::color( getDebugColor( lines->color0 ) );
|
||||
PrimBuild::vertex3fv( px3Cast<Point3F>(lines->pos0));
|
||||
PrimBuild::color( getDebugColor( lines->color1 ) );
|
||||
PrimBuild::vertex3fv( px3Cast<Point3F>(lines->pos1));
|
||||
lines++;
|
||||
}
|
||||
|
||||
PrimBuild::end();
|
||||
}
|
||||
|
||||
// Render triangles
|
||||
{
|
||||
physx::PxU32 numTris = renderBuffer->getNbTriangles();
|
||||
const physx::PxDebugTriangle *triangles = renderBuffer->getTriangles();
|
||||
|
||||
PrimBuild::begin( GFXTriangleList, numTris * 3 );
|
||||
|
||||
while ( numTris-- )
|
||||
{
|
||||
PrimBuild::color( getDebugColor( triangles->color0 ) );
|
||||
PrimBuild::vertex3fv( px3Cast<Point3F>(triangles->pos0) );
|
||||
PrimBuild::color( getDebugColor( triangles->color1 ) );
|
||||
PrimBuild::vertex3fv( px3Cast<Point3F>(triangles->pos1));
|
||||
PrimBuild::color( getDebugColor( triangles->color2 ) );
|
||||
PrimBuild::vertex3fv( px3Cast<Point3F>(triangles->pos2) );
|
||||
triangles++;
|
||||
}
|
||||
|
||||
PrimBuild::end();
|
||||
}
|
||||
|
||||
}
|
||||
//set simulation timing via script
|
||||
DefineEngineFunction( physx3SetSimulationTiming, void, ( F32 stepTime, U32 maxSteps ),, "Set simulation timing of the PhysX 3 plugin" )
|
||||
{
|
||||
Px3World::setTiming(stepTime,maxSteps);
|
||||
}
|
||||
106
Engine/source/T3D/physics/physx3/px3World.h
Normal file
106
Engine/source/T3D/physics/physx3/px3World.h
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _PX3WORLD_H_
|
||||
#define _PX3WORLD_H_
|
||||
|
||||
#ifndef _T3D_PHYSICS_PHYSICSWORLD_H_
|
||||
#include "T3D/physics/physicsWorld.h"
|
||||
#endif
|
||||
#ifndef _MMATH_H_
|
||||
#include "math/mMath.h"
|
||||
#endif
|
||||
#ifndef _PHYSX3_H_
|
||||
#include "T3D/physics/physx3/px3.h"
|
||||
#endif
|
||||
#ifndef _TVECTOR_H_
|
||||
#include "core/util/tVector.h"
|
||||
#endif
|
||||
|
||||
class Px3ConsoleStream;
|
||||
class Px3ContactReporter;
|
||||
class FixedStepper;
|
||||
|
||||
enum Px3CollisionGroup
|
||||
{
|
||||
PX3_DEFAULT = BIT(0),
|
||||
PX3_PLAYER = BIT(1),
|
||||
PX3_DEBRIS = BIT(2),
|
||||
PX3_TRIGGER = BIT(3),
|
||||
};
|
||||
|
||||
class Px3World : public PhysicsWorld
|
||||
{
|
||||
protected:
|
||||
|
||||
physx::PxScene* mScene;
|
||||
bool mIsEnabled;
|
||||
bool mIsSimulating;
|
||||
bool mIsServer;
|
||||
U32 mTickCount;
|
||||
ProcessList *mProcessList;
|
||||
F32 mEditorTimeScale;
|
||||
bool mErrorReport;
|
||||
physx::PxControllerManager* mControllerManager;
|
||||
static Px3ConsoleStream *smErrorCallback;
|
||||
static physx::PxDefaultAllocator smMemoryAlloc;
|
||||
static physx::PxFoundation* smFoundation;
|
||||
static physx::PxCooking *smCooking;
|
||||
static physx::PxProfileZoneManager* smProfileZoneManager;
|
||||
static physx::PxDefaultCpuDispatcher* smCpuDispatcher;
|
||||
static physx::PxVisualDebuggerConnection* smPvdConnection;
|
||||
static F32 smPhysicsStepTime;
|
||||
static U32 smPhysicsMaxIterations;
|
||||
F32 mAccumulator;
|
||||
bool _simulate(const F32 dt);
|
||||
|
||||
public:
|
||||
|
||||
Px3World();
|
||||
virtual ~Px3World();
|
||||
|
||||
virtual bool initWorld( bool isServer, ProcessList *processList );
|
||||
virtual void destroyWorld();
|
||||
virtual void onDebugDraw( const SceneRenderState *state );
|
||||
virtual void reset() {}
|
||||
virtual bool castRay( const Point3F &startPnt, const Point3F &endPnt, RayInfo *ri, const Point3F &impulse );
|
||||
virtual PhysicsBody* castRay( const Point3F &start, const Point3F &end, U32 bodyTypes = BT_All );
|
||||
virtual void explosion( const Point3F &pos, F32 radius, F32 forceMagnitude );
|
||||
virtual bool isEnabled() const { return mIsEnabled; }
|
||||
physx::PxScene* getScene(){ return mScene;}
|
||||
void setEnabled( bool enabled );
|
||||
U32 getTick() { return mTickCount; }
|
||||
void tickPhysics( U32 elapsedMs );
|
||||
void getPhysicsResults();
|
||||
void setEditorTimeScale( F32 timeScale ) { mEditorTimeScale = timeScale; }
|
||||
const F32 getEditorTimeScale() const { return mEditorTimeScale; }
|
||||
void releaseWriteLock();
|
||||
bool isServer(){return mIsServer;}
|
||||
physx::PxController* createController( physx::PxControllerDesc &desc );
|
||||
//static
|
||||
static bool restartSDK( bool destroyOnly = false, Px3World *clientWorld = NULL, Px3World *serverWorld = NULL );
|
||||
static void releaseWriteLocks();
|
||||
static physx::PxCooking *getCooking();
|
||||
static void setTiming(F32 stepTime,U32 maxIterations);
|
||||
};
|
||||
|
||||
#endif // _PX3WORLD_H_
|
||||
|
|
@ -356,6 +356,7 @@ PlayerData::PlayerData()
|
|||
decalID = 0;
|
||||
decalOffset = 0.0f;
|
||||
|
||||
actionCount = 0;
|
||||
lookAction = 0;
|
||||
|
||||
// size of bounding box
|
||||
|
|
@ -427,9 +428,9 @@ bool PlayerData::preload(bool server, String &errorStr)
|
|||
{
|
||||
for( U32 i = 0; i < MaxSounds; ++ i )
|
||||
{
|
||||
String errorStr;
|
||||
if( !sfxResolve( &sound[ i ], errorStr ) )
|
||||
Con::errorf( "PlayerData::preload: %s", errorStr.c_str() );
|
||||
String sfxErrorStr;
|
||||
if( !sfxResolve( &sound[ i ], sfxErrorStr ) )
|
||||
Con::errorf( "PlayerData::preload: %s", sfxErrorStr.c_str() );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -487,10 +488,6 @@ bool PlayerData::preload(bool server, String &errorStr)
|
|||
dp->death = false;
|
||||
if (dp->sequence != -1)
|
||||
getGroundInfo(si,thread,dp);
|
||||
|
||||
// No real reason to spam the console about a missing jet animation
|
||||
if (dStricmp(sp->name, "jet") != 0)
|
||||
AssertWarn(dp->sequence != -1, avar("PlayerData::preload - Unable to find named animation sequence '%s'!", sp->name));
|
||||
}
|
||||
for (S32 b = 0; b < mShape->mSequences.size(); b++)
|
||||
{
|
||||
|
|
@ -586,7 +583,10 @@ bool PlayerData::preload(bool server, String &errorStr)
|
|||
Torque::FS::FileNodeRef fileRef = Torque::FS::GetFileNode(mShapeFP[i].getPath());
|
||||
|
||||
if (!fileRef)
|
||||
{
|
||||
errorStr = String::ToString("PlayerData: Mounted image %d loading failed, shape \"%s\" is not found.",i,mShapeFP[i].getPath().getFullPath().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if(server)
|
||||
mCRCFP[i] = fileRef->getChecksum();
|
||||
|
|
@ -2952,7 +2952,7 @@ void Player::updateMove(const Move* move)
|
|||
|
||||
// Clamp acceleration.
|
||||
F32 maxAcc = (mDataBlock->swimForce / getMass()) * TickSec;
|
||||
if ( false && swimSpeed > maxAcc )
|
||||
if ( swimSpeed > maxAcc )
|
||||
swimAcc *= maxAcc / swimSpeed;
|
||||
|
||||
acc += swimAcc;
|
||||
|
|
@ -3692,7 +3692,7 @@ bool Player::setActionThread(const char* sequence,bool hold,bool wait,bool fsp)
|
|||
|
||||
void Player::setActionThread(U32 action,bool forward,bool hold,bool wait,bool fsp, bool forceSet)
|
||||
{
|
||||
if (!mDataBlock || (mActionAnimation.action == action && mActionAnimation.forward == forward && !forceSet))
|
||||
if (!mDataBlock || !mDataBlock->actionCount || (mActionAnimation.action == action && mActionAnimation.forward == forward && !forceSet))
|
||||
return;
|
||||
|
||||
if (action >= PlayerData::NumActionAnims)
|
||||
|
|
@ -6507,8 +6507,9 @@ DefineEngineMethod( Player, getDamageLocation, const char*, ( Point3F pos ),,
|
|||
|
||||
object->getDamageLocation(pos, buffer1, buffer2);
|
||||
|
||||
char *buff = Con::getReturnBuffer(128);
|
||||
dSprintf(buff, 128, "%s %s", buffer1, buffer2);
|
||||
static const U32 bufSize = 128;
|
||||
char *buff = Con::getReturnBuffer(bufSize);
|
||||
dSprintf(buff, bufSize, "%s %s", buffer1, buffer2);
|
||||
return buff;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -320,9 +320,9 @@ bool ProjectileData::preload(bool server, String &errorStr)
|
|||
if (Sim::findObject(decalId, decal) == false)
|
||||
Con::errorf(ConsoleLogEntry::General, "ProjectileData::preload: Invalid packet, bad datablockId(decal): %d", decalId);
|
||||
|
||||
String errorStr;
|
||||
if( !sfxResolve( &sound, errorStr ) )
|
||||
Con::errorf(ConsoleLogEntry::General, "ProjectileData::preload: Invalid packet: %s", errorStr.c_str());
|
||||
String sfxErrorStr;
|
||||
if( !sfxResolve( &sound, sfxErrorStr ) )
|
||||
Con::errorf(ConsoleLogEntry::General, "ProjectileData::preload: Invalid packet: %s", sfxErrorStr.c_str());
|
||||
|
||||
if (!lightDesc && lightDescId != 0)
|
||||
if (Sim::findObject(lightDescId, lightDesc) == false)
|
||||
|
|
@ -550,6 +550,7 @@ S32 ProjectileData::scaleValue( S32 value, bool down )
|
|||
//
|
||||
Projectile::Projectile()
|
||||
: mPhysicsWorld( NULL ),
|
||||
mDataBlock( NULL ),
|
||||
mCurrPosition( 0, 0, 0 ),
|
||||
mCurrVelocity( 0, 0, 1 ),
|
||||
mSourceObjectId( -1 ),
|
||||
|
|
@ -697,6 +698,12 @@ bool Projectile::onAdd()
|
|||
if(!Parent::onAdd())
|
||||
return false;
|
||||
|
||||
if( !mDataBlock )
|
||||
{
|
||||
Con::errorf("Projectile::onAdd - Fail - Not datablock");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isServerObject())
|
||||
{
|
||||
ShapeBase* ptr;
|
||||
|
|
@ -1011,7 +1018,7 @@ void Projectile::explode( const Point3F &p, const Point3F &n, const U32 collideT
|
|||
|
||||
// Client (impact) decal.
|
||||
if ( mDataBlock->decal )
|
||||
gDecalManager->addDecal( p, n, 0.0f, mDataBlock->decal );
|
||||
gDecalManager->addDecal(p, n, mRandF(0.0f, M_2PI_F), mDataBlock->decal);
|
||||
|
||||
// Client object
|
||||
updateSound();
|
||||
|
|
|
|||
|
|
@ -136,11 +136,11 @@ bool ProximityMineData::preload( bool server, String& errorStr )
|
|||
if ( !server )
|
||||
{
|
||||
// Resolve sounds
|
||||
String errorStr;
|
||||
if( !sfxResolve( &armingSound, errorStr ) )
|
||||
Con::errorf( ConsoleLogEntry::General, "ProximityMineData::preload: Invalid packet: %s", errorStr.c_str() );
|
||||
if( !sfxResolve( &triggerSound, errorStr ) )
|
||||
Con::errorf( ConsoleLogEntry::General, "ProximityMineData::preload: Invalid packet: %s", errorStr.c_str() );
|
||||
String sfxErrorStr;
|
||||
if( !sfxResolve( &armingSound, sfxErrorStr ) )
|
||||
Con::errorf( ConsoleLogEntry::General, "ProximityMineData::preload: Invalid packet: %s", sfxErrorStr.c_str() );
|
||||
if( !sfxResolve( &triggerSound, sfxErrorStr ) )
|
||||
Con::errorf( ConsoleLogEntry::General, "ProximityMineData::preload: Invalid packet: %s", sfxErrorStr.c_str() );
|
||||
}
|
||||
|
||||
if ( mShape )
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ ConsoleDocClass( RigidShapeData,
|
|||
"@see RigidShape\n"
|
||||
"@see ShapeBase\n\n"
|
||||
|
||||
"@ingroup Platform\n"
|
||||
"@ingroup Physics\n"
|
||||
);
|
||||
|
||||
|
||||
|
|
@ -149,7 +149,7 @@ ConsoleDocClass( RigidShape,
|
|||
"@see RigidShapeData\n"
|
||||
"@see ShapeBase\n\n"
|
||||
|
||||
"@ingroup Platform\n"
|
||||
"@ingroup Physics\n"
|
||||
);
|
||||
|
||||
|
||||
|
|
@ -302,6 +302,7 @@ bool RigidShapeData::preload(bool server, String &errorStr)
|
|||
if (!collisionDetails.size() || collisionDetails[0] == -1)
|
||||
{
|
||||
Con::errorf("RigidShapeData::preload failed: Rigid shapes must define a collision-1 detail");
|
||||
errorStr = String::ToString("RigidShapeData: Couldn't load shape \"%s\"",shapeName);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1140,11 +1141,11 @@ void RigidShape::updatePos(F32 dt)
|
|||
|
||||
void RigidShape::updateForces(F32 /*dt*/)
|
||||
{
|
||||
if (mDisableMove) return;
|
||||
Point3F gravForce(0, 0, sRigidShapeGravity * mRigid.mass * mGravityMod);
|
||||
|
||||
MatrixF currTransform;
|
||||
mRigid.getTransform(&currTransform);
|
||||
mRigid.atRest = false;
|
||||
|
||||
Point3F torque(0, 0, 0);
|
||||
Point3F force(0, 0, 0);
|
||||
|
|
|
|||
|
|
@ -91,7 +91,9 @@ void SFX3DObject::getEarTransform( MatrixF& transform ) const
|
|||
if ( !shapeInstance )
|
||||
{
|
||||
// Just in case.
|
||||
transform = mObject->getTransform();
|
||||
GameConnection* connection = dynamic_cast<GameConnection *>(NetConnection::getConnectionToServer());
|
||||
if ( !connection || !connection->getControlCameraTransform( 0.0f, &transform ) )
|
||||
transform = mObject->getTransform();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -114,11 +114,12 @@ IMPLEMENT_CALLBACK( ShapeBaseData, onTrigger, void, ( ShapeBase* obj, S32 index,
|
|||
"@param index Index of the trigger that changed\n"
|
||||
"@param state New state of the trigger\n" );
|
||||
|
||||
IMPLEMENT_CALLBACK( ShapeBaseData, onEndSequence, void, ( ShapeBase* obj, S32 slot ), ( obj, slot ),
|
||||
IMPLEMENT_CALLBACK(ShapeBaseData, onEndSequence, void, (ShapeBase* obj, S32 slot, const char* name), (obj, slot, name),
|
||||
"@brief Called when a thread playing a non-cyclic sequence reaches the end of the "
|
||||
"sequence.\n\n"
|
||||
"@param obj The ShapeBase object\n"
|
||||
"@param slot Thread slot that finished playing\n" );
|
||||
"@param slot Thread slot that finished playing\n"
|
||||
"@param name Thread name that finished playing\n");
|
||||
|
||||
IMPLEMENT_CALLBACK( ShapeBaseData, onForceUncloak, void, ( ShapeBase* obj, const char* reason ), ( obj, reason ),
|
||||
"@brief Called when the object is forced to uncloak.\n\n"
|
||||
|
|
@ -306,7 +307,10 @@ bool ShapeBaseData::preload(bool server, String &errorStr)
|
|||
Torque::FS::FileNodeRef fileRef = Torque::FS::GetFileNode(mShape.getPath());
|
||||
|
||||
if (!fileRef)
|
||||
{
|
||||
errorStr = String::ToString("ShapeBaseData: Couldn't load shape \"%s\"",shapeName);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(server)
|
||||
mCRC = fileRef->getChecksum();
|
||||
|
|
@ -928,7 +932,6 @@ ShapeBase::ShapeBase()
|
|||
for (i = 0; i < MaxScriptThreads; i++) {
|
||||
mScriptThread[i].sequence = -1;
|
||||
mScriptThread[i].thread = 0;
|
||||
mScriptThread[i].sound = 0;
|
||||
mScriptThread[i].state = Thread::Stop;
|
||||
mScriptThread[i].atEnd = false;
|
||||
mScriptThread[i].timescale = 1.f;
|
||||
|
|
@ -2152,14 +2155,13 @@ bool ShapeBase::setThreadSequence(U32 slot, S32 seq, bool reset)
|
|||
if (reset) {
|
||||
st.state = Thread::Play;
|
||||
st.atEnd = false;
|
||||
st.timescale = 1.f;
|
||||
st.position = 0.f;
|
||||
st.timescale = 1.f;
|
||||
st.position = 0.f;
|
||||
}
|
||||
if (mShapeInstance) {
|
||||
if (!st.thread)
|
||||
st.thread = mShapeInstance->addThread();
|
||||
mShapeInstance->setSequence(st.thread,seq,0);
|
||||
stopThreadSound(st);
|
||||
mShapeInstance->setSequence(st.thread,seq,st.position);
|
||||
updateThread(st);
|
||||
}
|
||||
return true;
|
||||
|
|
@ -2174,19 +2176,12 @@ void ShapeBase::updateThread(Thread& st)
|
|||
case Thread::Stop:
|
||||
{
|
||||
mShapeInstance->setTimeScale( st.thread, 1.f );
|
||||
mShapeInstance->setPos( st.thread, ( st.timescale > 0.f ) ? 0.0f : 1.0f );
|
||||
mShapeInstance->setPos( st.thread, ( st.timescale > 0.f ) ? 1.0f : 0.0f );
|
||||
} // Drop through to pause state
|
||||
|
||||
case Thread::Pause:
|
||||
{
|
||||
if ( st.position != -1.f )
|
||||
{
|
||||
mShapeInstance->setTimeScale( st.thread, 1.f );
|
||||
mShapeInstance->setPos( st.thread, st.position );
|
||||
}
|
||||
|
||||
mShapeInstance->setTimeScale( st.thread, 0.f );
|
||||
stopThreadSound( st );
|
||||
} break;
|
||||
|
||||
case Thread::Play:
|
||||
|
|
@ -2196,7 +2191,6 @@ void ShapeBase::updateThread(Thread& st)
|
|||
mShapeInstance->setTimeScale(st.thread,1);
|
||||
mShapeInstance->setPos( st.thread, ( st.timescale > 0.f ) ? 1.0f : 0.0f );
|
||||
mShapeInstance->setTimeScale(st.thread,0);
|
||||
stopThreadSound(st);
|
||||
st.state = Thread::Stop;
|
||||
}
|
||||
else
|
||||
|
|
@ -2208,16 +2202,11 @@ void ShapeBase::updateThread(Thread& st)
|
|||
}
|
||||
|
||||
mShapeInstance->setTimeScale(st.thread, st.timescale );
|
||||
if (!st.sound)
|
||||
{
|
||||
startSequenceSound(st);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case Thread::Destroy:
|
||||
{
|
||||
stopThreadSound(st);
|
||||
st.atEnd = true;
|
||||
st.sequence = -1;
|
||||
if(st.thread)
|
||||
|
|
@ -2325,19 +2314,6 @@ bool ShapeBase::setThreadTimeScale( U32 slot, F32 timeScale )
|
|||
return false;
|
||||
}
|
||||
|
||||
void ShapeBase::stopThreadSound(Thread& thread)
|
||||
{
|
||||
if (thread.sound) {
|
||||
}
|
||||
}
|
||||
|
||||
void ShapeBase::startSequenceSound(Thread& thread)
|
||||
{
|
||||
if (!isGhost() || !thread.thread)
|
||||
return;
|
||||
stopThreadSound(thread);
|
||||
}
|
||||
|
||||
void ShapeBase::advanceThreads(F32 dt)
|
||||
{
|
||||
for (U32 i = 0; i < MaxScriptThreads; i++) {
|
||||
|
|
@ -2349,7 +2325,7 @@ void ShapeBase::advanceThreads(F32 dt)
|
|||
st.atEnd = true;
|
||||
updateThread(st);
|
||||
if (!isGhost()) {
|
||||
mDataBlock->onEndSequence_callback( this, i );
|
||||
mDataBlock->onEndSequence_callback(this, i, this->getThreadSequenceName(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2358,6 +2334,7 @@ void ShapeBase::advanceThreads(F32 dt)
|
|||
if(st.thread)
|
||||
{
|
||||
mShapeInstance->advanceTime(dt,st.thread);
|
||||
st.position = mShapeInstance->getPos(st.thread);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3058,9 +3035,9 @@ void ShapeBase::unpackUpdate(NetConnection *con, BitStream *stream)
|
|||
if (stream->readFlag()) {
|
||||
Thread& st = mScriptThread[i];
|
||||
U32 seq = stream->readInt(ThreadSequenceBits);
|
||||
st.state = stream->readInt(2);
|
||||
stream->read( &st.timescale );
|
||||
stream->read( &st.position );
|
||||
st.state = Thread::State(stream->readInt(2));
|
||||
stream->read( &st.timescale );
|
||||
stream->read( &st.position );
|
||||
st.atEnd = stream->readFlag();
|
||||
if (st.sequence != seq && st.state != Thread::Destroy)
|
||||
setThreadSequence(i,seq,false);
|
||||
|
|
|
|||
|
|
@ -648,7 +648,7 @@ public:
|
|||
DECLARE_CALLBACK( void, onCollision, ( ShapeBase* obj, SceneObject* collObj, VectorF vec, F32 len ) );
|
||||
DECLARE_CALLBACK( void, onDamage, ( ShapeBase* obj, F32 delta ) );
|
||||
DECLARE_CALLBACK( void, onTrigger, ( ShapeBase* obj, S32 index, bool state ) );
|
||||
DECLARE_CALLBACK( void, onEndSequence, ( ShapeBase* obj, S32 slot ) );
|
||||
DECLARE_CALLBACK(void, onEndSequence, (ShapeBase* obj, S32 slot, const char* name));
|
||||
DECLARE_CALLBACK( void, onForceUncloak, ( ShapeBase* obj, const char* reason ) );
|
||||
/// @}
|
||||
};
|
||||
|
|
@ -729,12 +729,9 @@ protected:
|
|||
Play, Stop, Pause, Destroy
|
||||
};
|
||||
TSThread* thread; ///< Pointer to 3space data.
|
||||
U32 state; ///< State of the thread
|
||||
///
|
||||
/// @see Thread::State
|
||||
State state; ///< State of the thread
|
||||
S32 sequence; ///< The animation sequence which is running in this thread.
|
||||
F32 timescale; ///< Timescale
|
||||
U32 sound; ///< Handle to sound.
|
||||
F32 timescale; ///< Timescale
|
||||
bool atEnd; ///< Are we at the end of this thread?
|
||||
F32 position;
|
||||
};
|
||||
|
|
@ -1354,14 +1351,6 @@ public:
|
|||
/// @param timescale Timescale
|
||||
bool setThreadTimeScale( U32 slot, F32 timeScale );
|
||||
|
||||
/// Start the sound associated with an animation thread
|
||||
/// @param thread Thread
|
||||
void startSequenceSound(Thread& thread);
|
||||
|
||||
/// Stop the sound associated with an animation thread
|
||||
/// @param thread Thread
|
||||
void stopThreadSound(Thread& thread);
|
||||
|
||||
/// Advance all animation threads attached to this shapebase
|
||||
/// @param dt Change in time from last call to this function
|
||||
void advanceThreads(F32 dt);
|
||||
|
|
|
|||
|
|
@ -462,7 +462,10 @@ bool ShapeBaseImageData::preload(bool server, String &errorStr)
|
|||
Torque::FS::FileNodeRef fileRef = Torque::FS::GetFileNode(shape[i].getPath());
|
||||
|
||||
if (!fileRef)
|
||||
{
|
||||
errorStr = String::ToString("ShapeBaseImageData: Couldn't load shape \"%s\"",name);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(server)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -259,8 +259,9 @@ ConsoleGetType( TypeTriggerPolyhedron )
|
|||
AssertFatal(currVec == 3, "Internal error: Bad trigger polyhedron");
|
||||
|
||||
// Build output string.
|
||||
char* retBuf = Con::getReturnBuffer(1024);
|
||||
dSprintf(retBuf, 1023, "%7.7f %7.7f %7.7f %7.7f %7.7f %7.7f %7.7f %7.7f %7.7f %7.7f %7.7f %7.7f",
|
||||
static const U32 bufSize = 1024;
|
||||
char* retBuf = Con::getReturnBuffer(bufSize);
|
||||
dSprintf(retBuf, bufSize, "%7.7f %7.7f %7.7f %7.7f %7.7f %7.7f %7.7f %7.7f %7.7f %7.7f %7.7f %7.7f",
|
||||
origin.x, origin.y, origin.z,
|
||||
vecs[0].x, vecs[0].y, vecs[0].z,
|
||||
vecs[2].x, vecs[2].y, vecs[2].z,
|
||||
|
|
|
|||
|
|
@ -111,6 +111,11 @@ TSStatic::TSStatic()
|
|||
mMeshCulling = false;
|
||||
mUseOriginSort = false;
|
||||
|
||||
mUseAlphaFade = false;
|
||||
mAlphaFadeStart = 100.0f;
|
||||
mAlphaFadeEnd = 150.0f;
|
||||
mInvertAlphaFade = false;
|
||||
mAlphaFade = 1.0f;
|
||||
mPhysicsRep = NULL;
|
||||
|
||||
mCollisionType = CollisionMesh;
|
||||
|
|
@ -192,6 +197,13 @@ void TSStatic::initPersistFields()
|
|||
|
||||
endGroup("Collision");
|
||||
|
||||
addGroup( "AlphaFade" );
|
||||
addField( "Alpha Fade Enable", TypeBool, Offset(mUseAlphaFade, TSStatic), "Turn on/off Alpha Fade" );
|
||||
addField( "Alpha Fade Start", TypeF32, Offset(mAlphaFadeStart, TSStatic), "Distance of start Alpha Fade" );
|
||||
addField( "Alpha Fade End", TypeF32, Offset(mAlphaFadeEnd, TSStatic), "Distance of end Alpha Fade" );
|
||||
addField( "Alpha Fade Inverse", TypeBool, Offset(mInvertAlphaFade, TSStatic), "Invert Alpha Fade's Start & End Distance" );
|
||||
endGroup( "AlphaFade" );
|
||||
|
||||
addGroup("Debug");
|
||||
|
||||
addField( "renderNormals", TypeF32, Offset( mRenderNormalScalar, TSStatic ),
|
||||
|
|
@ -502,6 +514,36 @@ void TSStatic::prepRenderImage( SceneRenderState* state )
|
|||
if (dist < 0.01f)
|
||||
dist = 0.01f;
|
||||
|
||||
if (mUseAlphaFade)
|
||||
{
|
||||
mAlphaFade = 1.0f;
|
||||
if ((mAlphaFadeStart < mAlphaFadeEnd) && mAlphaFadeStart > 0.1f)
|
||||
{
|
||||
if (mInvertAlphaFade)
|
||||
{
|
||||
if (dist <= mAlphaFadeStart)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (dist < mAlphaFadeEnd)
|
||||
{
|
||||
mAlphaFade = ((dist - mAlphaFadeStart) / (mAlphaFadeEnd - mAlphaFadeStart));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dist >= mAlphaFadeEnd)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (dist > mAlphaFadeStart)
|
||||
{
|
||||
mAlphaFade -= ((dist - mAlphaFadeStart) / (mAlphaFadeEnd - mAlphaFadeStart));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
F32 invScale = (1.0f/getMax(getMax(mObjScale.x,mObjScale.y),mObjScale.z));
|
||||
|
||||
if ( mForceDetail == -1 )
|
||||
|
|
@ -545,6 +587,19 @@ void TSStatic::prepRenderImage( SceneRenderState* state )
|
|||
GFX->setWorldMatrix( mat );
|
||||
|
||||
mShapeInstance->animate();
|
||||
if(mShapeInstance)
|
||||
{
|
||||
if (mUseAlphaFade)
|
||||
{
|
||||
mShapeInstance->setAlphaAlways(mAlphaFade);
|
||||
S32 s = mShapeInstance->mMeshObjects.size();
|
||||
|
||||
for(S32 x = 0; x < s; x++)
|
||||
{
|
||||
mShapeInstance->mMeshObjects[x].visible = mAlphaFade;
|
||||
}
|
||||
}
|
||||
}
|
||||
mShapeInstance->render( rdata );
|
||||
|
||||
if ( mRenderNormalScalar > 0 )
|
||||
|
|
@ -625,6 +680,13 @@ U32 TSStatic::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
|
|||
|
||||
stream->writeFlag( mPlayAmbient );
|
||||
|
||||
if ( stream->writeFlag(mUseAlphaFade) )
|
||||
{
|
||||
stream->write(mAlphaFadeStart);
|
||||
stream->write(mAlphaFadeEnd);
|
||||
stream->write(mInvertAlphaFade);
|
||||
}
|
||||
|
||||
if ( mLightPlugin )
|
||||
retMask |= mLightPlugin->packUpdate(this, AdvancedStaticOptionsMask, con, mask, stream);
|
||||
|
||||
|
|
@ -682,6 +744,14 @@ void TSStatic::unpackUpdate(NetConnection *con, BitStream *stream)
|
|||
|
||||
mPlayAmbient = stream->readFlag();
|
||||
|
||||
mUseAlphaFade = stream->readFlag();
|
||||
if (mUseAlphaFade)
|
||||
{
|
||||
stream->read(&mAlphaFadeStart);
|
||||
stream->read(&mAlphaFadeEnd);
|
||||
stream->read(&mInvertAlphaFade);
|
||||
}
|
||||
|
||||
if ( mLightPlugin )
|
||||
{
|
||||
mLightPlugin->unpackUpdate(this, con, stream);
|
||||
|
|
@ -702,41 +772,9 @@ bool TSStatic::castRay(const Point3F &start, const Point3F &end, RayInfo* info)
|
|||
|
||||
if ( mCollisionType == Bounds )
|
||||
{
|
||||
F32 st, et, fst = 0.0f, fet = 1.0f;
|
||||
F32 *bmin = &mObjBox.minExtents.x;
|
||||
F32 *bmax = &mObjBox.maxExtents.x;
|
||||
F32 const *si = &start.x;
|
||||
F32 const *ei = &end.x;
|
||||
|
||||
for ( U32 i = 0; i < 3; i++ )
|
||||
{
|
||||
if (*si < *ei)
|
||||
{
|
||||
if ( *si > *bmax || *ei < *bmin )
|
||||
return false;
|
||||
F32 di = *ei - *si;
|
||||
st = ( *si < *bmin ) ? ( *bmin - *si ) / di : 0.0f;
|
||||
et = ( *ei > *bmax ) ? ( *bmax - *si ) / di : 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( *ei > *bmax || *si < *bmin )
|
||||
return false;
|
||||
F32 di = *ei - *si;
|
||||
st = ( *si > *bmax ) ? ( *bmax - *si ) / di : 0.0f;
|
||||
et = ( *ei < *bmin ) ? ( *bmin - *si ) / di : 1.0f;
|
||||
}
|
||||
if ( st > fst ) fst = st;
|
||||
if ( et < fet ) fet = et;
|
||||
if ( fet < fst )
|
||||
return false;
|
||||
bmin++; bmax++;
|
||||
si++; ei++;
|
||||
}
|
||||
|
||||
info->normal = start - end;
|
||||
info->normal.normalizeSafe();
|
||||
getTransform().mulV( info->normal );
|
||||
F32 fst;
|
||||
if (!mObjBox.collideLine(start, end, &fst, &info->normal))
|
||||
return false;
|
||||
|
||||
info->t = fst;
|
||||
info->object = this;
|
||||
|
|
|
|||
|
|
@ -97,6 +97,13 @@ class TSStatic : public SceneObject
|
|||
};
|
||||
|
||||
public:
|
||||
void setAlphaFade(bool enable, F32 start, F32 end, bool inverse)
|
||||
{
|
||||
mUseAlphaFade = enable;
|
||||
mAlphaFadeStart = start;
|
||||
mAlphaFadeEnd = end;
|
||||
mInvertAlphaFade = inverse;
|
||||
}
|
||||
|
||||
/// The different types of mesh data types
|
||||
enum MeshType
|
||||
|
|
@ -108,6 +115,11 @@ public:
|
|||
};
|
||||
|
||||
protected:
|
||||
bool mUseAlphaFade;
|
||||
F32 mAlphaFadeStart;
|
||||
F32 mAlphaFadeEnd;
|
||||
F32 mAlphaFade;
|
||||
bool mInvertAlphaFade;
|
||||
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
|
|
|
|||
|
|
@ -892,7 +892,7 @@ void AITurretShape::_trackTarget(F32 dt)
|
|||
//if (pitch > M_PI_F)
|
||||
// pitch = -(pitch - M_2PI_F);
|
||||
|
||||
Point3F rot(pitch, 0.0f, -yaw);
|
||||
Point3F rot(-pitch, 0.0f, yaw);
|
||||
|
||||
// If we have a rotation rate make sure we follow it
|
||||
if (mHeadingRate > 0)
|
||||
|
|
|
|||
|
|
@ -1155,7 +1155,7 @@ void TurretShape::unpackUpdate(NetConnection *connection, BitStream *stream)
|
|||
void TurretShape::getWeaponMountTransform( S32 index, const MatrixF &xfm, MatrixF *outMat )
|
||||
{
|
||||
// Returns mount point to world space transform
|
||||
if ( index >= 0 && index < SceneObject::NumMountPoints) {
|
||||
if ( index >= 0 && index < ShapeBase::MaxMountedImages) {
|
||||
S32 ni = mDataBlock->weaponMountNode[index];
|
||||
if (ni != -1) {
|
||||
MatrixF mountTransform = mShapeInstance->mNodeTransforms[ni];
|
||||
|
|
@ -1180,7 +1180,7 @@ void TurretShape::getWeaponMountTransform( S32 index, const MatrixF &xfm, Matrix
|
|||
void TurretShape::getRenderWeaponMountTransform( F32 delta, S32 mountPoint, const MatrixF &xfm, MatrixF *outMat )
|
||||
{
|
||||
// Returns mount point to world space transform
|
||||
if ( mountPoint >= 0 && mountPoint < SceneObject::NumMountPoints) {
|
||||
if ( mountPoint >= 0 && mountPoint < ShapeBase::MaxMountedImages) {
|
||||
S32 ni = mDataBlock->weaponMountNode[mountPoint];
|
||||
if (ni != -1) {
|
||||
MatrixF mountTransform = mShapeInstance->mNodeTransforms[ni];
|
||||
|
|
|
|||
|
|
@ -218,6 +218,7 @@ bool VehicleData::preload(bool server, String &errorStr)
|
|||
if (!collisionDetails.size() || collisionDetails[0] == -1)
|
||||
{
|
||||
Con::errorf("VehicleData::preload failed: Vehicle models must define a collision-1 detail");
|
||||
errorStr = String::ToString("VehicleData: Couldn't load shape \"%s\"",shapeName);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -71,6 +71,12 @@ bool VehicleBlocker::onAdd()
|
|||
|
||||
mObjBox.minExtents.set(-mDimensions.x, -mDimensions.y, 0);
|
||||
mObjBox.maxExtents.set( mDimensions.x, mDimensions.y, mDimensions.z);
|
||||
if( !mObjBox.isValidBox() )
|
||||
{
|
||||
Con::errorf("VehicleBlocker::onAdd - Fail - No valid object box");
|
||||
return false;
|
||||
}
|
||||
|
||||
resetWorldBox();
|
||||
setRenderTransform(mObjToWorld);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue