Merge branch 'development' into walkabout

Conflicts:
	Templates/Empty/game/tools/worldEditor/scripts/editors/creator.ed.cs
	Templates/Full/game/tools/worldEditor/scripts/editors/creator.ed.cs
This commit is contained in:
Daniel Buckmaster 2015-01-02 14:45:20 +11:00
commit 7ab6731f51
1453 changed files with 95576 additions and 14818 deletions

View file

@ -0,0 +1,349 @@
//-----------------------------------------------------------------------------
// 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/accumulationVolume.h"
#include "scene/sceneManager.h"
#include "scene/sceneRenderState.h"
#include "gfx/gfxDevice.h"
#include "gfx/gfxDrawUtil.h"
#include "gfx/sim/debugDraw.h"
#include "util/tempAlloc.h"
#include "materials/materialDefinition.h"
#include "materials/materialManager.h"
#include "materials/materialFeatureTypes.h"
#include "materials/matInstance.h"
#include "console/consoleTypes.h"
#include "core/stream/bitStream.h"
#include "gfx/gfxDevice.h"
#include "console/console.h"
#include "console/engineAPI.h"
#include "gfx/gfxTextureHandle.h"
#include "scene/sceneContainer.h"
#include "math/mPolyhedron.impl.h"
Vector< SimObjectPtr<SceneObject> > AccumulationVolume::smAccuObjects;
Vector< SimObjectPtr<AccumulationVolume> > AccumulationVolume::smAccuVolumes;
//#define DEBUG_DRAW
IMPLEMENT_CO_NETOBJECT_V1( AccumulationVolume );
ConsoleDocClass( AccumulationVolume,
"@brief An invisible shape that allow objects within it to have an accumulation map.\n\n"
"AccumulationVolume is used to add additional realism to a scene. It's main use is in outdoor scenes "
" where objects could benefit from overlaying environment accumulation textures such as sand, snow, etc.\n\n"
"Objects within the volume must have accumulation enabled in their material. \n\n"
"@ingroup enviroMisc"
);
//-----------------------------------------------------------------------------
AccumulationVolume::AccumulationVolume()
: mTransformDirty( true ),
mSilhouetteExtractor( mPolyhedron )
{
VECTOR_SET_ASSOCIATION( mWSPoints );
VECTOR_SET_ASSOCIATION( mVolumeQueryList );
//mObjectFlags.set( VisualOccluderFlag );
mNetFlags.set( Ghostable | ScopeAlways );
mObjScale.set( 1.f, 1.f, 1.f );
mObjBox.set(
Point3F( -0.5f, -0.5f, -0.5f ),
Point3F( 0.5f, 0.5f, 0.5f )
);
mObjToWorld.identity();
mWorldToObj.identity();
// Accumulation Texture.
mTextureName = "";
mAccuTexture = NULL;
resetWorldBox();
}
AccumulationVolume::~AccumulationVolume()
{
mAccuTexture = NULL;
}
void AccumulationVolume::initPersistFields()
{
addProtectedField( "texture", TypeStringFilename, Offset( mTextureName, AccumulationVolume ),
&_setTexture, &defaultProtectedGetFn, "Accumulation texture." );
Parent::initPersistFields();
}
//-----------------------------------------------------------------------------
void AccumulationVolume::consoleInit()
{
// Disable rendering of occlusion volumes by default.
getStaticClassRep()->mIsRenderEnabled = false;
}
//-----------------------------------------------------------------------------
bool AccumulationVolume::onAdd()
{
if( !Parent::onAdd() )
return false;
// Prepare some client side things.
if ( isClientObject() )
{
smAccuVolumes.push_back(this);
refreshVolumes();
}
// Set up the silhouette extractor.
mSilhouetteExtractor = SilhouetteExtractorType( mPolyhedron );
return true;
}
void AccumulationVolume::onRemove()
{
if ( isClientObject() )
{
smAccuVolumes.remove(this);
refreshVolumes();
}
Parent::onRemove();
}
//-----------------------------------------------------------------------------
void AccumulationVolume::_renderObject( ObjectRenderInst* ri, SceneRenderState* state, BaseMatInstance* overrideMat )
{
Parent::_renderObject( ri, state, overrideMat );
#ifdef DEBUG_DRAW
if( state->isDiffusePass() )
DebugDrawer::get()->drawPolyhedronDebugInfo( mPolyhedron, getTransform(), getScale() );
#endif
}
//-----------------------------------------------------------------------------
void AccumulationVolume::setTransform( const MatrixF& mat )
{
Parent::setTransform( mat );
mTransformDirty = true;
refreshVolumes();
}
//-----------------------------------------------------------------------------
void AccumulationVolume::buildSilhouette( const SceneCameraState& cameraState, Vector< Point3F >& outPoints )
{
// Extract the silhouette of the polyhedron. This works differently
// depending on whether we project orthogonally or in perspective.
TempAlloc< U32 > indices( mPolyhedron.getNumPoints() );
U32 numPoints;
if( cameraState.getFrustum().isOrtho() )
{
// Transform the view direction into object space.
Point3F osViewDir;
getWorldTransform().mulV( cameraState.getViewDirection(), &osViewDir );
// And extract the silhouette.
SilhouetteExtractorOrtho< PolyhedronType > extractor( mPolyhedron );
numPoints = extractor.extractSilhouette( osViewDir, indices, indices.size );
}
else
{
// Create a transform to go from view space to object space.
MatrixF camView( true );
camView.scale( Point3F( 1.0f / getScale().x, 1.0f / getScale().y, 1.0f / getScale().z ) );
camView.mul( getRenderWorldTransform() );
camView.mul( cameraState.getViewWorldMatrix() );
// Do a perspective-correct silhouette extraction.
numPoints = mSilhouetteExtractor.extractSilhouette(
camView,
indices, indices.size );
}
// If we haven't yet, transform the polyhedron's points
// to world space.
if( mTransformDirty )
{
const U32 numPoints = mPolyhedron.getNumPoints();
const PolyhedronType::PointType* points = getPolyhedron().getPoints();
mWSPoints.setSize( numPoints );
for( U32 i = 0; i < numPoints; ++ i )
{
Point3F p = points[ i ];
p.convolve( getScale() );
getTransform().mulP( p, &mWSPoints[ i ] );
}
mTransformDirty = false;
}
// Now store the points.
outPoints.setSize( numPoints );
for( U32 i = 0; i < numPoints; ++ i )
outPoints[ i ] = mWSPoints[ indices[ i ] ];
}
//-----------------------------------------------------------------------------
U32 AccumulationVolume::packUpdate( NetConnection *connection, U32 mask, BitStream *stream )
{
U32 retMask = Parent::packUpdate( connection, mask, stream );
if (stream->writeFlag(mask & InitialUpdateMask))
{
stream->write( mTextureName );
}
return retMask;
}
void AccumulationVolume::unpackUpdate( NetConnection *connection, BitStream *stream )
{
Parent::unpackUpdate( connection, stream );
if (stream->readFlag())
{
stream->read( &mTextureName );
setTexture(mTextureName);
}
}
//-----------------------------------------------------------------------------
void AccumulationVolume::inspectPostApply()
{
Parent::inspectPostApply();
setMaskBits(U32(-1) );
}
void AccumulationVolume::setTexture( const String& name )
{
mTextureName = name;
if ( isClientObject() && mTextureName.isNotEmpty() )
{
mAccuTexture.set(mTextureName, &GFXDefaultStaticDiffuseProfile, "AccumulationVolume::mAccuTexture");
if ( mAccuTexture.isNull() )
Con::warnf( "AccumulationVolume::setTexture - Unable to load texture: %s", mTextureName.c_str() );
}
refreshVolumes();
}
//-----------------------------------------------------------------------------
// Static Functions
//-----------------------------------------------------------------------------
bool AccumulationVolume::_setTexture( void *object, const char *index, const char *data )
{
AccumulationVolume* volume = reinterpret_cast< AccumulationVolume* >( object );
volume->setTexture( data );
return false;
}
void AccumulationVolume::refreshVolumes()
{
// This function tests each accumulation object to
// see if it's within the bounds of an accumulation
// volume. If so, it will pass on the accumulation
// texture of the volume to the object.
// This function should only be called when something
// global like change of volume or material occurs.
// Clear old data.
for (S32 n = 0; n < smAccuObjects.size(); ++n)
{
SimObjectPtr<SceneObject> object = smAccuObjects[n];
if ( object.isValid() )
object->mAccuTex = GFXTexHandle::ZERO;
}
//
for (S32 i = 0; i < smAccuVolumes.size(); ++i)
{
SimObjectPtr<AccumulationVolume> volume = smAccuVolumes[i];
if ( volume.isNull() ) continue;
for (S32 n = 0; n < smAccuObjects.size(); ++n)
{
SimObjectPtr<SceneObject> object = smAccuObjects[n];
if ( object.isNull() ) continue;
if ( volume->containsPoint(object->getPosition()) )
object->mAccuTex = volume->mAccuTexture;
}
}
}
// Accumulation Object Management.
void AccumulationVolume::addObject(SimObjectPtr<SceneObject> object)
{
smAccuObjects.push_back(object);
refreshVolumes();
}
void AccumulationVolume::removeObject(SimObjectPtr<SceneObject> object)
{
smAccuObjects.remove(object);
refreshVolumes();
}
void AccumulationVolume::updateObject(SceneObject* object)
{
// This function is called when an individual object
// has been moved. Tests to see if it's in any of the
// accumulation volumes.
// We use ZERO instead of NULL so the accumulation
// texture will be updated in renderMeshMgr.
object->mAccuTex = GFXTexHandle::ZERO;
for (S32 i = 0; i < smAccuVolumes.size(); ++i)
{
SimObjectPtr<AccumulationVolume> volume = smAccuVolumes[i];
if ( volume.isNull() ) continue;
if ( volume->containsPoint(object->getPosition()) )
object->mAccuTex = volume->mAccuTexture;
}
}

View 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 _ACCUMULATIONVOLUME_H_
#define _ACCUMULATIONVOLUME_H_
#ifndef _SCENEPOLYHEDRALSPACE_H_
#include "scene/scenePolyhedralSpace.h"
#endif
#ifndef _MSILHOUETTEEXTRACTOR_H_
#include "math/mSilhouetteExtractor.h"
#endif
#ifndef _GFXDEVICE_H_
#include "gfx/gfxDevice.h"
#endif
/// A volume in space that blocks visibility.
class AccumulationVolume : public ScenePolyhedralSpace
{
public:
typedef ScenePolyhedralSpace Parent;
protected:
typedef SilhouetteExtractorPerspective< PolyhedronType > SilhouetteExtractorType;
/// Whether the volume's transform has changed and we need to recompute
/// transform-based data.
bool mTransformDirty;
/// World-space points of the volume's polyhedron.
Vector< Point3F > mWSPoints;
/// Silhouette extractor when using perspective projections.
SilhouetteExtractorType mSilhouetteExtractor;
mutable Vector< SceneObject* > mVolumeQueryList;
// Name (path) of the accumulation texture.
String mTextureName;
// SceneSpace.
virtual void _renderObject( ObjectRenderInst* ri, SceneRenderState* state, BaseMatInstance* overrideMat );
public:
GFXTexHandle mAccuTexture;
AccumulationVolume();
~AccumulationVolume();
// SimObject.
DECLARE_CONOBJECT( AccumulationVolume );
DECLARE_DESCRIPTION( "Allows objects in an area to have accumulation effect applied." );
DECLARE_CATEGORY( "3D Scene" );
virtual bool onAdd();
virtual void onRemove();
void inspectPostApply();
void setTexture( const String& name );
// Static Functions.
static void consoleInit();
static void initPersistFields();
static Vector< SimObjectPtr<SceneObject> > smAccuObjects;
static Vector< SimObjectPtr<AccumulationVolume> > smAccuVolumes;
static void addObject(SimObjectPtr<SceneObject> object);
static void removeObject(SimObjectPtr<SceneObject> object);
static void refreshVolumes();
static bool _setTexture( void *object, const char *index, const char *data );
static void updateObject(SceneObject* object);
// Network
U32 packUpdate( NetConnection *, U32 mask, BitStream *stream );
void unpackUpdate( NetConnection *, BitStream *stream );
// SceneObject.
virtual void buildSilhouette( const SceneCameraState& cameraState, Vector< Point3F >& outPoints );
virtual void setTransform( const MatrixF& mat );
};
#endif // !_AccumulationVolume_H_

View file

@ -28,6 +28,7 @@
#include "T3D/player.h"
#include "T3D/gameBase/moveManager.h"
#include "console/consoleInternal.h"
#include "console/engineAPI.h"
IMPLEMENT_CONOBJECT( AIClient );
@ -52,6 +53,8 @@ ConsoleDocClass( AIClient,
"@ingroup Networking\n"
);
IMPLEMENT_CALLBACK(AIClient, onConnect, void, (const char* idString), (idString),"");
/**
* Constructor
*/
@ -415,15 +418,17 @@ void AIClient::onAdd( const char *nameSpace ) {
/**
* Sets the move speed for an AI object
*/
ConsoleMethod( AIClient, setMoveSpeed, void, 3, 3, "ai.setMoveSpeed( float );" ) {
DefineConsoleMethod( AIClient, setMoveSpeed, void, (F32 speed), , "ai.setMoveSpeed( float );" )
{
AIClient *ai = static_cast<AIClient *>( object );
ai->setMoveSpeed( dAtof( argv[2] ) );
ai->setMoveSpeed( speed );
}
/**
* Stops all AI movement, halt!
*/
ConsoleMethod( AIClient, stop, void, 2, 2, "ai.stop();" ) {
DefineConsoleMethod( AIClient, stop, void, (),, "ai.stop();" )
{
AIClient *ai = static_cast<AIClient *>( object );
ai->setMoveMode( AIClient::ModeStop );
}
@ -431,10 +436,9 @@ ConsoleMethod( AIClient, stop, void, 2, 2, "ai.stop();" ) {
/**
* Tells the AI to aim at the location provided
*/
ConsoleMethod( AIClient, setAimLocation, void, 3, 3, "ai.setAimLocation( x y z );" ) {
DefineConsoleMethod( AIClient, setAimLocation, void, (Point3F v), , "ai.setAimLocation( x y z );" )
{
AIClient *ai = static_cast<AIClient *>( object );
Point3F v( 0.0f,0.0f,0.0f );
dSscanf( argv[2], "%f %f %f", &v.x, &v.y, &v.z );
ai->setAimLocation( v );
}
@ -442,10 +446,9 @@ ConsoleMethod( AIClient, setAimLocation, void, 3, 3, "ai.setAimLocation( x y z )
/**
* Tells the AI to move to the location provided
*/
ConsoleMethod( AIClient, setMoveDestination, void, 3, 3, "ai.setMoveDestination( x y z );" ) {
DefineConsoleMethod( AIClient, setMoveDestination, void, (Point3F v), , "ai.setMoveDestination( x y z );" )
{
AIClient *ai = static_cast<AIClient *>( object );
Point3F v( 0.0f, 0.0f, 0.0f );
dSscanf( argv[2], "%f %f", &v.x, &v.y );
ai->setMoveDestination( v );
}
@ -453,40 +456,31 @@ ConsoleMethod( AIClient, setMoveDestination, void, 3, 3, "ai.setMoveDestination(
/**
* Returns the point the AI is aiming at
*/
ConsoleMethod( AIClient, getAimLocation, const char *, 2, 2, "ai.getAimLocation();" ) {
DefineConsoleMethod( AIClient, getAimLocation, Point3F, (),, "ai.getAimLocation();" )
{
AIClient *ai = static_cast<AIClient *>( object );
Point3F aimPoint = ai->getAimLocation();
static const U32 bufSize = 256;
char *returnBuffer = Con::getReturnBuffer( bufSize );
dSprintf( returnBuffer, bufSize, "%f %f %f", aimPoint.x, aimPoint.y, aimPoint.z );
return returnBuffer;
return ai->getAimLocation();
}
/**
* Returns the point the AI is set to move to
*/
ConsoleMethod( AIClient, getMoveDestination, const char *, 2, 2, "ai.getMoveDestination();" ) {
DefineConsoleMethod( AIClient, getMoveDestination, Point3F, (),, "ai.getMoveDestination();" )
{
AIClient *ai = static_cast<AIClient *>( object );
Point3F movePoint = ai->getMoveDestination();
static const U32 bufSize = 256;
char *returnBuffer = Con::getReturnBuffer( bufSize );
dSprintf( returnBuffer, bufSize, "%f %f %f", movePoint.x, movePoint.y, movePoint.z );
return returnBuffer;
return ai->getMoveDestination();
}
/**
* Sets the bots target object
*/
ConsoleMethod( AIClient, setTargetObject, void, 3, 3, "ai.setTargetObject( obj );" ) {
DefineConsoleMethod( AIClient, setTargetObject, void, (const char * objName), , "ai.setTargetObject( obj );" )
{
AIClient *ai = static_cast<AIClient *>( object );
// Find the target
ShapeBase *targetObject;
if( Sim::findObject( argv[2], targetObject ) )
if( Sim::findObject( objName, targetObject ) )
ai->setTargetObject( targetObject );
else
ai->setTargetObject( NULL );
@ -495,7 +489,8 @@ ConsoleMethod( AIClient, setTargetObject, void, 3, 3, "ai.setTargetObject( obj )
/**
* Gets the object the AI is targeting
*/
ConsoleMethod( AIClient, getTargetObject, S32, 2, 2, "ai.getTargetObject();" ) {
DefineConsoleMethod( AIClient, getTargetObject, S32, (),, "ai.getTargetObject();" )
{
AIClient *ai = static_cast<AIClient *>( object );
return ai->getTargetObject();
@ -504,7 +499,8 @@ ConsoleMethod( AIClient, getTargetObject, S32, 2, 2, "ai.getTargetObject();" ) {
/**
* Tells the bot the mission is cycling
*/
ConsoleMethod( AIClient, missionCycleCleanup, void, 2, 2, "ai.missionCycleCleanup();" ) {
DefineConsoleMethod( AIClient, missionCycleCleanup, void, (),, "ai.missionCycleCleanup();" )
{
AIClient *ai = static_cast<AIClient*>( object );
ai->missionCycleCleanup();
}
@ -512,7 +508,8 @@ ConsoleMethod( AIClient, missionCycleCleanup, void, 2, 2, "ai.missionCycleCleanu
/**
* Sets the AI to run mode
*/
ConsoleMethod( AIClient, move, void, 2, 2, "ai.move();" ) {
DefineConsoleMethod( AIClient, move, void, (),, "ai.move();" )
{
AIClient *ai = static_cast<AIClient *>( object );
ai->setMoveMode( AIClient::ModeMove );
}
@ -520,21 +517,17 @@ ConsoleMethod( AIClient, move, void, 2, 2, "ai.move();" ) {
/**
* Gets the AI's location in the world
*/
ConsoleMethod( AIClient, getLocation, const char *, 2, 2, "ai.getLocation();" ) {
DefineConsoleMethod( AIClient, getLocation, Point3F, (),, "ai.getLocation();" )
{
AIClient *ai = static_cast<AIClient *>( object );
Point3F locPoint = ai->getLocation();
static const U32 bufSize = 256;
char *returnBuffer = Con::getReturnBuffer( bufSize );
dSprintf( returnBuffer, bufSize, "%f %f %f", locPoint.x, locPoint.y, locPoint.z );
return returnBuffer;
return ai->getLocation();
}
/**
* Adds an AI Player to the game
*/
ConsoleFunction( aiAddPlayer, S32 , 2, 3, "aiAddPlayer( 'playerName'[, 'AIClassType'] );" ) {
DefineConsoleFunction( aiAddPlayer, S32, (const char * name, const char * ns), (""), "'playerName'[, 'AIClassType'] );")
{
// Create the player
AIClient *aiPlayer = new AIClient();
aiPlayer->registerObject();
@ -548,18 +541,13 @@ ConsoleFunction( aiAddPlayer, S32 , 2, 3, "aiAddPlayer( 'playerName'[, 'AIClassT
SimGroup *g = Sim::getClientGroup();
g->addObject( aiPlayer );
char *name = new char[ dStrlen( argv[1] ) + 1];
char *ns = new char[ dStrlen( argv[2] ) + 1];
dStrcpy( name, argv[1] );
dStrcpy( ns, argv[2] );
// Execute the connect console function, this is the same
// onConnect function invoked for normal client connections
Con::executef( aiPlayer, "onConnect", name );
aiPlayer->onConnect_callback( name );
// Now execute the onAdd command and feed it the namespace
if( argc > 2 )
if(dStrcmp( ns,"" ) != 0 )
aiPlayer->onAdd( ns );
else
aiPlayer->onAdd( "AIClient" );
@ -571,7 +559,8 @@ ConsoleFunction( aiAddPlayer, S32 , 2, 3, "aiAddPlayer( 'playerName'[, 'AIClassT
/**
* Tells the AI to move forward 100 units...TEST FXN
*/
ConsoleMethod( AIClient, moveForward, void, 2, 2, "ai.moveForward();" ) {
DefineConsoleMethod( AIClient, moveForward, void, (),, "ai.moveForward();" )
{
AIClient *ai = static_cast<AIClient *>( object );
ShapeBase *player = dynamic_cast<ShapeBase*>(ai->getControlObject());

View file

@ -70,6 +70,8 @@ class AIClient : public AIConnection {
DECLARE_CONOBJECT( AIClient );
DECLARE_CALLBACK( void, onConnect, (const char* idString) );
enum {
ModeStop = 0,
ModeMove,

View file

@ -21,6 +21,7 @@
//-----------------------------------------------------------------------------
#include "T3D/aiConnection.h"
#include "console/engineAPI.h"
IMPLEMENT_CONOBJECT( AIConnection );
@ -159,7 +160,7 @@ ConsoleFunction(aiConnect, S32 , 2, 20, "(...)"
//-----------------------------------------------------------------------------
ConsoleMethod(AIConnection,setMove,void,4, 4,"(string field, float value)"
DefineConsoleMethod(AIConnection, setMove, void, (const char * field, F32 value), ,"(string field, float value)"
"Set a field on the current move.\n\n"
"@param field One of {'x','y','z','yaw','pitch','roll'}\n"
"@param value Value to set field to.")
@ -167,59 +168,59 @@ ConsoleMethod(AIConnection,setMove,void,4, 4,"(string field, float value)"
Move move = object->getMove();
// Ok, a little slow for now, but this is just an example..
if (!dStricmp(argv[2],"x"))
move.x = mClampF(dAtof(argv[3]),-1,1);
if (!dStricmp(field,"x"))
move.x = mClampF(value,-1,1);
else
if (!dStricmp(argv[2],"y"))
move.y = mClampF(dAtof(argv[3]),-1,1);
if (!dStricmp(field,"y"))
move.y = mClampF(value,-1,1);
else
if (!dStricmp(argv[2],"z"))
move.z = mClampF(dAtof(argv[3]),-1,1);
if (!dStricmp(field,"z"))
move.z = mClampF(value,-1,1);
else
if (!dStricmp(argv[2],"yaw"))
move.yaw = moveClamp(dAtof(argv[3]));
if (!dStricmp(field,"yaw"))
move.yaw = moveClamp(value);
else
if (!dStricmp(argv[2],"pitch"))
move.pitch = moveClamp(dAtof(argv[3]));
if (!dStricmp(field,"pitch"))
move.pitch = moveClamp(value);
else
if (!dStricmp(argv[2],"roll"))
move.roll = moveClamp(dAtof(argv[3]));
if (!dStricmp(field,"roll"))
move.roll = moveClamp(value);
//
object->setMove(&move);
}
ConsoleMethod(AIConnection,getMove,F32,3, 3,"(string field)"
DefineConsoleMethod(AIConnection,getMove,F32, (const char * field), ,"(string field)"
"Get the given field of a move.\n\n"
"@param field One of {'x','y','z','yaw','pitch','roll'}\n"
"@returns The requested field on the current move.")
{
const Move& move = object->getMove();
if (!dStricmp(argv[2],"x"))
if (!dStricmp(field,"x"))
return move.x;
if (!dStricmp(argv[2],"y"))
if (!dStricmp(field,"y"))
return move.y;
if (!dStricmp(argv[2],"z"))
if (!dStricmp(field,"z"))
return move.z;
if (!dStricmp(argv[2],"yaw"))
if (!dStricmp(field,"yaw"))
return move.yaw;
if (!dStricmp(argv[2],"pitch"))
if (!dStricmp(field,"pitch"))
return move.pitch;
if (!dStricmp(argv[2],"roll"))
if (!dStricmp(field,"roll"))
return move.roll;
return 0;
}
ConsoleMethod(AIConnection,setFreeLook,void,3, 3,"(bool isFreeLook)"
DefineConsoleMethod(AIConnection,setFreeLook,void,(bool isFreeLook), ,"(bool isFreeLook)"
"Enable/disable freelook on the current move.")
{
Move move = object->getMove();
move.freeLook = dAtob(argv[2]);
move.freeLook = isFreeLook;
object->setMove(&move);
}
ConsoleMethod(AIConnection,getFreeLook,bool,2, 2,"getFreeLook()"
DefineConsoleMethod(AIConnection, getFreeLook, bool, (), ,"getFreeLook()"
"Is freelook on for the current move?")
{
return object->getMove().freeLook;
@ -228,21 +229,20 @@ ConsoleMethod(AIConnection,getFreeLook,bool,2, 2,"getFreeLook()"
//-----------------------------------------------------------------------------
ConsoleMethod(AIConnection,setTrigger,void,4, 4,"(int trigger, bool set)"
DefineConsoleMethod(AIConnection,setTrigger,void, (S32 idx, bool set), ,"(int trigger, bool set)"
"Set a trigger.")
{
S32 idx = dAtoi(argv[2]);
if (idx >= 0 && idx < MaxTriggerKeys) {
if (idx >= 0 && idx < MaxTriggerKeys)
{
Move move = object->getMove();
move.trigger[idx] = dAtob(argv[3]);
move.trigger[idx] = set;
object->setMove(&move);
}
}
ConsoleMethod(AIConnection,getTrigger,bool,4, 4,"(int trigger)"
DefineConsoleMethod(AIConnection,getTrigger,bool, (S32 idx), ,"(int trigger)"
"Is the given trigger set?")
{
S32 idx = dAtoi(argv[2]);
if (idx >= 0 && idx < MaxTriggerKeys)
return object->getMove().trigger[idx];
return false;
@ -251,7 +251,7 @@ ConsoleMethod(AIConnection,getTrigger,bool,4, 4,"(int trigger)"
//-----------------------------------------------------------------------------
ConsoleMethod(AIConnection,getAddress,const char*,2, 2,"")
DefineConsoleMethod(AIConnection,getAddress,const char*,(), ,"")
{
// Override the netConnection method to return to indicate
// this is an ai connection.

View file

@ -1119,23 +1119,21 @@ ConsoleDocFragment _setAimObject(
"AIPlayer",
"void setAimObject(GameBase targetObject, Point3F offset);"
);
ConsoleMethod( AIPlayer, setAimObject, void, 3, 4, "( GameBase obj, [Point3F offset] )"
DefineConsoleMethod( AIPlayer, setAimObject, void, ( const char * objName, Point3F offset ), (Point3F::Zero), "( GameBase obj, [Point3F offset] )"
"Sets the bot's target object. Optionally set an offset from target location."
"@hide")
{
Point3F off( 0.0f, 0.0f, 0.0f );
// Find the target
GameBase *targetObject;
if( Sim::findObject( argv[2], targetObject ) )
if( Sim::findObject( objName, targetObject ) )
{
if (argc == 4)
dSscanf( argv[3], "%g %g %g", &off.x, &off.y, &off.z );
object->setAimObject( targetObject, off );
object->setAimObject( targetObject, offset );
}
else
object->setAimObject( 0, off );
object->setAimObject( 0, offset );
}
DefineEngineMethod( AIPlayer, getAimObject, S32, (),,

View file

@ -1860,7 +1860,7 @@ DefineEngineMethod( Camera, setOffset, void, (Point3F offset), ,
//-----------------------------------------------------------------------------
DefineEngineMethod( Camera, setOrbitMode, void, (GameBase* orbitObject, TransformF orbitPoint, F32 minDistance, F32 maxDistance,
F32 initDistance, bool ownClientObj, Point3F offset, bool locked), (false, Point3F(0.0f, 0.0f, 0.0f), false),
F32 initDistance, bool ownClientObj, Point3F offset, bool locked), (false, Point3F::Zero, false),
"Set the camera to orbit around the given object, or if none is given, around the given point.\n\n"
"@param orbitObject The object to orbit around. If no object is given (0 or blank string is passed in) use the orbitPoint instead\n"
"@param orbitPoint The point to orbit around when no object is given. In the form of \"x y z ax ay az aa\" such as returned by SceneObject::getTransform().\n"
@ -1883,7 +1883,7 @@ DefineEngineMethod( Camera, setOrbitMode, void, (GameBase* orbitObject, Transfor
DefineEngineMethod( Camera, setOrbitObject, bool, (GameBase* orbitObject, VectorF rotation, F32 minDistance,
F32 maxDistance, F32 initDistance, bool ownClientObject, Point3F offset, bool locked),
(false, Point3F(0.0f, 0.0f, 0.0f), false),
(false, Point3F::Zero, false),
"Set the camera to orbit around a given object.\n\n"
"@param orbitObject The object to orbit around.\n"
"@param rotation The initial camera rotation about the object in radians in the form of \"x y z\".\n"
@ -1911,7 +1911,7 @@ DefineEngineMethod( Camera, setOrbitObject, bool, (GameBase* orbitObject, Vector
DefineEngineMethod( Camera, setOrbitPoint, void, (TransformF orbitPoint, F32 minDistance, F32 maxDistance, F32 initDistance,
Point3F offset, bool locked),
(Point3F(0.0f, 0.0f, 0.0f), false),
(Point3F::Zero, false),
"Set the camera to orbit around a given point.\n\n"
"@param orbitPoint The point to orbit around. In the form of \"x y z ax ay az aa\" such as returned by SceneObject::getTransform().\n"
"@param minDistance The minimum distance allowed to the orbit object or point.\n"
@ -1929,7 +1929,7 @@ DefineEngineMethod( Camera, setOrbitPoint, void, (TransformF orbitPoint, F32 min
//-----------------------------------------------------------------------------
DefineEngineMethod( Camera, setTrackObject, bool, (GameBase* trackObject, Point3F offset), (Point3F(0.0f, 0.0f, 0.0f)),
DefineEngineMethod( Camera, setTrackObject, bool, (GameBase* trackObject, Point3F offset), (Point3F::Zero),
"Set the camera to track a given object.\n\n"
"@param trackObject The object to track.\n"
"@param offset [optional] An offset added to the camera's position. Default is no offset.\n"

View file

@ -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();

View file

@ -138,8 +138,17 @@ ConsoleDocClass( Explosion,
MRandomLCG sgRandom(0xdeadbeef);
//WLE - Vince - The defaults are bad, the whole point of calling this function\
//is to determine the explosion coverage on a object. Why would you want them
//To call this with a null for the ID? In fact, it just returns a 1f if
//it can't find the object. Seems useless to me. Cause how can I apply
//damage to a object that doesn't exist?
DefineEngineFunction(calcExplosionCoverage, F32, (Point3F pos, S32 id, U32 covMask),(Point3F(0.0f,0.0f,0.0f), NULL, NULL),
//I could possible see a use with passing in a null covMask, but even that
//sounds flaky because it will be 100 percent if your saying not to take
//any thing in consideration for coverage. So I'm removing these defaults they are just bad.
DefineEngineFunction(calcExplosionCoverage, F32, (Point3F pos, S32 id, U32 covMask),,
"@brief Calculates how much an explosion effects a specific object.\n\n"
"Use this to determine how much damage to apply to objects based on their "
"distance from the explosion's center point, and whether the explosion is "

View file

@ -929,13 +929,10 @@ DefineEngineMethod(Lightning, strikeRandomPoint, void, (),,
object->strikeRandomPoint();
}
DefineEngineMethod(Lightning, strikeObject, void, (S32 id), (NULL),
DefineEngineMethod(Lightning, strikeObject, void, (ShapeBase* pSB),,
"Creates a LightningStrikeEvent which strikes a specific object.\n"
"@note This method is currently unimplemented.\n" )
{
ShapeBase* pSB;
if (object->isServerObject() && Sim::findObject(id, pSB))
object->strikeObject(pSB);
}

View file

@ -145,6 +145,7 @@ ParticleEmitterData::ParticleEmitterData()
blendStyle = ParticleRenderInst::BlendUndefined;
sortParticles = false;
renderReflection = true;
glow = false;
reverseOrder = false;
textureName = 0;
textureHandle = 0;
@ -289,6 +290,9 @@ void ParticleEmitterData::initPersistFields()
addField( "renderReflection", TYPEID< bool >(), Offset(renderReflection, ParticleEmitterData),
"Controls whether particles are rendered onto reflective surfaces like water." );
addField("glow", TYPEID< bool >(), Offset(glow, ParticleEmitterData),
"If true, the particles are rendered to the glow buffer as well.");
//@}
endGroup( "ParticleEmitterData" );
@ -356,6 +360,7 @@ void ParticleEmitterData::packData(BitStream* stream)
}
stream->writeFlag(highResOnly);
stream->writeFlag(renderReflection);
stream->writeFlag(glow);
stream->writeInt( blendStyle, 4 );
}
@ -418,6 +423,7 @@ void ParticleEmitterData::unpackData(BitStream* stream)
}
highResOnly = stream->readFlag();
renderReflection = stream->readFlag();
glow = stream->readFlag();
blendStyle = stream->readInt( 4 );
}
@ -909,6 +915,8 @@ void ParticleEmitter::prepRenderImage(SceneRenderState* state)
ri->blendStyle = mDataBlock->blendStyle;
ri->glow = mDataBlock->glow;
// use first particle's texture unless there is an emitter texture to override it
if (mDataBlock->textureHandle)
ri->diffuseTex = &*(mDataBlock->textureHandle);

View file

@ -114,6 +114,7 @@ class ParticleEmitterData : public GameBaseData
GFXTexHandle textureHandle; ///< Emitter texture handle from txrName
bool highResOnly; ///< This particle system should not use the mixed-resolution particle rendering
bool renderReflection; ///< Enables this emitter to render into reflection passes.
bool glow; ///< Renders this emitter into the glow buffer.
bool reload();
};

View file

@ -393,8 +393,9 @@ void ParticleEmitterNode::setEmitterDataBlock(ParticleEmitterData* data)
mEmitterDatablock = data;
}
DefineEngineMethod(ParticleEmitterNode, setEmitterDataBlock, void, (ParticleEmitterData* emitterDatablock), (0),
DefineEngineMethod(ParticleEmitterNode, setEmitterDataBlock, void, (ParticleEmitterData* emitterDatablock), (NULL),
"Assigns the datablock for this emitter node.\n"
"@param emitterDatablock ParticleEmitterData datablock to assign\n"
"@tsexample\n"

View file

@ -506,7 +506,7 @@ DefineEngineMethod(Precipitation, modifyStorm, void, (F32 percentage, F32 second
object->modifyStorm(percentage, S32(seconds * 1000.0f));
}
DefineEngineMethod(Precipitation, setTurbulence, void, (F32 max, F32 speed, F32 seconds), (1.0f, 5.0f, 5.0),
DefineEngineMethod(Precipitation, setTurbulence, void, (F32 max, F32 speed, F32 seconds), (1.0f, 5.0f, 5.0f),
"Smoothly change the turbulence parameters over a period of time.\n"
"@param max New #maxTurbulence value. Set to 0 to disable turbulence.\n"
"@param speed New #turbulenceSpeed value.\n"
@ -1666,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);
@ -1799,7 +1799,7 @@ void Precipitation::renderObject(ObjectRenderInst *ri, SceneRenderState *state,
GFX->setShaderConstBuffer(mSplashShaderConsts);
}
else
GFX->disableShaders();
GFX->setupGenericShaders(GFXDevice::GSTexture);
while (curr)
{

View file

@ -672,9 +672,9 @@ void Ribbon::createBuffers(SceneRenderState *state, GFXVertexBufferHandle<GFXVer
Point3F pointA = verts[count-1].point;
Point3F pointB = verts[0].point;
verts.unlock();
pb.unlock();
verts.unlock();
Point3F diffSize = pointA - pointB;
Box3F objBox;
@ -704,4 +704,4 @@ void Ribbon::createBuffers(SceneRenderState *state, GFXVertexBufferHandle<GFXVer
}
mUpdateBuffers = false;
}
}

View file

@ -388,7 +388,9 @@ F32 GameBase::getUpdatePriority(CameraScopeQuery *camInfo, U32 updateMask, S32 u
// Weight by field of view, objects directly in front
// will be weighted 1, objects behind will be 0
F32 dot = mDot(pos,camInfo->orientation);
bool inFov = dot > camInfo->cosFov;
bool inFov = dot > camInfo->cosFov * 1.5f;
F32 wFov = inFov? 1.0f: 0;
// Weight by linear velocity parallel to the viewing plane
@ -406,7 +408,7 @@ F32 GameBase::getUpdatePriority(CameraScopeQuery *camInfo, U32 updateMask, S32 u
// Weight by interest.
F32 wInterest;
if (getTypeMask() & PlayerObjectType)
if (getTypeMask() & (PlayerObjectType || VehicleObjectType ))
wInterest = 0.75f;
else if (getTypeMask() & ProjectileObjectType)
{

View file

@ -35,6 +35,10 @@
#ifndef _DYNAMIC_CONSOLETYPES_H_
#include "console/dynamicTypes.h"
#endif
#ifndef __SCENEMANAGER_H__
#include "scene/sceneManager.h"
#define __SCENEMANAGER_H__
#endif
class NetConnection;
class ProcessList;

View file

@ -226,6 +226,8 @@ GameConnection::GameConnection()
mAddYawToAbsRot = false;
mAddPitchToAbsRot = false;
mVisibleGhostDistance = 0.0f;
clearDisplayDevice();
}
@ -240,6 +242,16 @@ GameConnection::~GameConnection()
//----------------------------------------------------------------------------
void GameConnection::setVisibleGhostDistance(F32 dist)
{
mVisibleGhostDistance = dist;
}
F32 GameConnection::getVisibleGhostDistance()
{
return mVisibleGhostDistance;
}
bool GameConnection::canRemoteCreate()
{
return true;
@ -2199,3 +2211,21 @@ DefineEngineMethod( GameConnection, getControlSchemeAbsoluteRotation, bool, (),,
{
return object->getControlSchemeAbsoluteRotation();
}
DefineEngineMethod( GameConnection, setVisibleGhostDistance, void, (F32 dist),,
"@brief Sets the distance that objects around it will be ghosted. If set to 0, "
"it may be defined by the LevelInfo.\n\n"
"@dist - is the max distance\n\n"
)
{
object->setVisibleGhostDistance(dist);
}
DefineEngineMethod( GameConnection, getVisibleGhostDistance, F32, (),,
"@brief Gets the distance that objects around the connection will be ghosted.\n\n"
"@return S32 of distance.\n\n"
)
{
return object->getVisibleGhostDistance();
}

View file

@ -72,6 +72,8 @@ private:
U32 mMissionCRC; // crc of the current mission file from the server
F32 mVisibleGhostDistance;
private:
U32 mLastControlRequestTime;
S32 mDataBlockModifiedKey;
@ -155,6 +157,9 @@ public:
bool canRemoteCreate();
void setVisibleGhostDistance(F32 dist);
F32 getVisibleGhostDistance();
private:
/// @name Connection State
/// This data is set with setConnectArgs() and setJoinPassword(), and

View file

@ -20,6 +20,7 @@
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "console/engineAPI.h"
#include "platform/platform.h"
#include "T3D/gameBase/gameProcess.h"
@ -33,7 +34,7 @@ ClientProcessList* ClientProcessList::smClientProcessList = NULL;
ServerProcessList* ServerProcessList::smServerProcessList = NULL;
static U32 gNetOrderNextId = 0;
ConsoleFunction( dumpProcessList, void, 1, 1,
DefineConsoleFunction( dumpProcessList, void, ( ), ,
"Dumps all ProcessObjects in ServerProcessList and ClientProcessList to the console." )
{
Con::printf( "client process list:" );

View file

@ -88,7 +88,7 @@ extern void ShowInit();
//------------------------------------------------------------------------------
/// Camera and FOV info
namespace {
namespace CameraAndFOV{
const U32 MaxZoomSpeed = 2000; ///< max number of ms to reach target FOV
@ -112,7 +112,7 @@ static U32 sgServerQueryIndex = 0;
//SERVER FUNCTIONS ONLY
ConsoleFunctionGroupBegin( Containers, "Spatial query functions. <b>Server side only!</b>");
ConsoleFunction(containerFindFirst, const char*, 6, 6, "(int mask, Point3F point, float x, float y, float z)"
DefineConsoleFunction( containerFindFirst, const char*, (U32 typeMask, Point3F origin, Point3F size), , "(int mask, Point3F point, float x, float y, float z)"
"@brief Find objects matching the bitmask type within a box centered at point, with extents x, y, z.\n\n"
"@returns The first object found, or an empty string if nothing was found. Thereafter, you can get more "
"results using containerFindNext()."
@ -120,17 +120,6 @@ ConsoleFunction(containerFindFirst, const char*, 6, 6, "(int mask, Point3F point
"@ingroup Game")
{
//find out what we're looking for
U32 typeMask = U32(dAtoi(argv[1]));
//find the center of the container volume
Point3F origin(0.0f, 0.0f, 0.0f);
dSscanf(argv[2], "%g %g %g", &origin.x, &origin.y, &origin.z);
//find the box dimensions
Point3F size(0.0f, 0.0f, 0.0f);
size.x = mFabs(dAtof(argv[3]));
size.y = mFabs(dAtof(argv[4]));
size.z = mFabs(dAtof(argv[5]));
//build the container volume
Box3F queryBox;
@ -155,7 +144,7 @@ ConsoleFunction(containerFindFirst, const char*, 6, 6, "(int mask, Point3F point
return buff;
}
ConsoleFunction( containerFindNext, const char*, 1, 1, "()"
DefineConsoleFunction( containerFindNext, const char*, (), , "()"
"@brief Get more results from a previous call to containerFindFirst().\n\n"
"@note You must call containerFindFirst() to begin the search.\n"
"@returns The next object found, or an empty string if nothing else was found.\n"
@ -191,9 +180,9 @@ DefineEngineFunction( setDefaultFov, void, ( F32 defaultFOV ),,
"@param defaultFOV The default field of view in degrees\n"
"@ingroup CameraSystem")
{
sDefaultFov = mClampF(defaultFOV, MinCameraFov, MaxCameraFov);
if(sCameraFov == sTargetFov)
sTargetFov = sDefaultFov;
CameraAndFOV::sDefaultFov = mClampF(defaultFOV, MinCameraFov, MaxCameraFov);
if(CameraAndFOV::sCameraFov == CameraAndFOV::sTargetFov)
CameraAndFOV::sTargetFov = CameraAndFOV::sDefaultFov;
}
DefineEngineFunction( setZoomSpeed, void, ( S32 speed ),,
@ -203,7 +192,7 @@ DefineEngineFunction( setZoomSpeed, void, ( S32 speed ),,
"@param speed The camera's zoom speed in ms per 90deg FOV change\n"
"@ingroup CameraSystem")
{
sZoomSpeed = mClamp(speed, 0, MaxZoomSpeed);
CameraAndFOV::sZoomSpeed = mClamp(speed, 0, CameraAndFOV::MaxZoomSpeed);
}
DefineEngineFunction( setFov, void, ( F32 FOV ),,
@ -211,22 +200,22 @@ DefineEngineFunction( setFov, void, ( F32 FOV ),,
"@param FOV The camera's new FOV in degrees\n"
"@ingroup CameraSystem")
{
sTargetFov = mClampF(FOV, MinCameraFov, MaxCameraFov);
CameraAndFOV::sTargetFov = mClampF(FOV, MinCameraFov, MaxCameraFov);
}
F32 GameGetCameraFov()
{
return(sCameraFov);
return(CameraAndFOV::sCameraFov);
}
void GameSetCameraFov(F32 fov)
{
sTargetFov = sCameraFov = fov;
CameraAndFOV::sTargetFov = CameraAndFOV::sCameraFov = fov;
}
void GameSetCameraTargetFov(F32 fov)
{
sTargetFov = fov;
CameraAndFOV::sTargetFov = fov;
}
void GameUpdateCameraFov()
@ -234,29 +223,29 @@ void GameUpdateCameraFov()
F32 time = F32(Platform::getVirtualMilliseconds());
// need to update fov?
if(sTargetFov != sCameraFov)
if(CameraAndFOV::sTargetFov != CameraAndFOV::sCameraFov)
{
F32 delta = time - sLastCameraUpdateTime;
F32 delta = time - CameraAndFOV::sLastCameraUpdateTime;
// snap zoom?
if((sZoomSpeed == 0) || (delta <= 0.f))
sCameraFov = sTargetFov;
if((CameraAndFOV::sZoomSpeed == 0) || (delta <= 0.f))
CameraAndFOV::sCameraFov = CameraAndFOV::sTargetFov;
else
{
// gZoomSpeed is time in ms to zoom 90deg
F32 step = 90.f * (delta / F32(sZoomSpeed));
F32 step = 90.f * (delta / F32(CameraAndFOV::sZoomSpeed));
if(sCameraFov > sTargetFov)
if(CameraAndFOV::sCameraFov > CameraAndFOV::sTargetFov)
{
sCameraFov -= step;
if(sCameraFov < sTargetFov)
sCameraFov = sTargetFov;
CameraAndFOV::sCameraFov -= step;
if(CameraAndFOV::sCameraFov < CameraAndFOV::sTargetFov)
CameraAndFOV::sCameraFov = CameraAndFOV::sTargetFov;
}
else
{
sCameraFov += step;
if(sCameraFov > sTargetFov)
sCameraFov = sTargetFov;
CameraAndFOV::sCameraFov += step;
if(CameraAndFOV::sCameraFov > CameraAndFOV::sTargetFov)
CameraAndFOV::sCameraFov = CameraAndFOV::sTargetFov;
}
}
}
@ -266,23 +255,23 @@ void GameUpdateCameraFov()
if(connection)
{
// check if fov is valid on control object
if(connection->isValidControlCameraFov(sCameraFov))
connection->setControlCameraFov(sCameraFov);
if(connection->isValidControlCameraFov(CameraAndFOV::sCameraFov))
connection->setControlCameraFov(CameraAndFOV::sCameraFov);
else
{
// will set to the closest fov (fails only on invalid control object)
if(connection->setControlCameraFov(sCameraFov))
if(connection->setControlCameraFov(CameraAndFOV::sCameraFov))
{
F32 setFov = sCameraFov;
F32 setFov = CameraAndFOV::sCameraFov;
connection->getControlCameraFov(&setFov);
sTargetFov = sCameraFov = setFov;
CameraAndFOV::sTargetFov =CameraAndFOV::sCameraFov = setFov;
}
}
}
// update the console variable
sConsoleCameraFov = sCameraFov;
sLastCameraUpdateTime = time;
CameraAndFOV::sConsoleCameraFov = CameraAndFOV::sCameraFov;
CameraAndFOV::sLastCameraUpdateTime = time;
}
//--------------------------------------------------------------------------
@ -355,8 +344,8 @@ bool GameProcessCameraQuery(CameraQuery *query)
// Scale the normal visible distance by the performance
// tuning scale which we never let over 1.
sVisDistanceScale = mClampF( sVisDistanceScale, 0.01f, 1.0f );
query->farPlane = gClientSceneGraph->getVisibleDistance() * sVisDistanceScale;
CameraAndFOV::sVisDistanceScale = mClampF( CameraAndFOV::sVisDistanceScale, 0.01f, 1.0f );
query->farPlane = gClientSceneGraph->getVisibleDistance() * CameraAndFOV::sVisDistanceScale;
// Provide some default values
query->projectionOffset = Point2F::Zero;
@ -432,10 +421,10 @@ static void Process3D()
static void RegisterGameFunctions()
{
Con::addVariable( "$pref::Camera::distanceScale", TypeF32, &sVisDistanceScale,
Con::addVariable( "$pref::Camera::distanceScale", TypeF32, &CameraAndFOV::sVisDistanceScale,
"A scale to apply to the normal visible distance, typically used for tuning performance.\n"
"@ingroup Game");
Con::addVariable( "$cameraFov", TypeF32, &sConsoleCameraFov,
Con::addVariable( "$cameraFov", TypeF32, &CameraAndFOV::sConsoleCameraFov,
"The camera's Field of View.\n\n"
"@ingroup Game" );

View file

@ -35,6 +35,8 @@
#include "console/engineAPI.h"
#include "math/mathIO.h"
#include "torqueConfig.h"
IMPLEMENT_CO_NETOBJECT_V1(LevelInfo);
@ -77,6 +79,7 @@ static SFXAmbience sDefaultAmbience;
LevelInfo::LevelInfo()
: mNearClip( 0.1f ),
mVisibleDistance( 1000.0f ),
mVisibleGhostDistance ( 0 ),
mDecalBias( 0.0015f ),
mCanvasClearColor( 255, 0, 255, 255 ),
mSoundAmbience( NULL ),
@ -113,7 +116,8 @@ void LevelInfo::initPersistFields()
addGroup( "Visibility" );
addField( "nearClip", TypeF32, Offset( mNearClip, LevelInfo ), "Closest distance from the camera's position to render the world." );
addField( "visibleDistance", TypeF32, Offset( mVisibleDistance, LevelInfo ), "Furthest distance fromt he camera's position to render the world." );
addField( "visibleDistance", TypeF32, Offset( mVisibleDistance, LevelInfo ), "Furthest distance from the camera's position to render the world." );
addField( "visibleGhostDistance", TypeF32, Offset( mVisibleGhostDistance, LevelInfo ), "Furthest distance from the camera's position to render players. Defaults to visibleDistance." );
addField( "decalBias", TypeF32, Offset( mDecalBias, LevelInfo ),
"NearPlane bias used when rendering Decal and DecalRoad. This should be tuned to the visibleDistance in your level." );
@ -300,6 +304,7 @@ void LevelInfo::_updateSceneGraph()
scene->setNearClip( mNearClip );
scene->setVisibleDistance( mVisibleDistance );
scene->setVisibleGhostDistance( mVisibleGhostDistance );
gDecalBias = mDecalBias;

View file

@ -36,7 +36,6 @@
#include "sfx/sfxCommon.h"
#endif
class SFXAmbience;
class SFXSoundscape;
@ -55,6 +54,8 @@ class LevelInfo : public NetObject
F32 mVisibleDistance;
F32 mVisibleGhostDistance;
F32 mDecalBias;
ColorI mCanvasClearColor;

View file

@ -425,21 +425,22 @@ static ConsoleDocFragment _lbplayAnimation2(
"LightBase",
"void playAnimation(LightAnimData anim);"
);
ConsoleMethod( LightBase, playAnimation, void, 2, 3, "( [LightAnimData anim] )\t"
DefineConsoleMethod( LightBase, playAnimation, void, (const char * anim), (""), "( [LightAnimData anim] )\t"
"Plays a light animation on the light. If no LightAnimData is passed the "
"existing one is played."
"@hide")
{
if ( argc == 2 )
if ( dStrIsEmpty(anim) )
{
object->playAnimation();
return;
}
LightAnimData *animData;
if ( !Sim::findObject( argv[2], animData ) )
if ( !Sim::findObject( anim, animData ) )
{
Con::errorf( "LightBase::playAnimation() - Invalid LightAnimData '%s'.", (const char*)argv[2] );
Con::errorf( "LightBase::playAnimation() - Invalid LightAnimData '%s'.", anim );
return;
}
@ -469,7 +470,7 @@ void LightBase::playAnimation( LightAnimData *animData )
}
}
ConsoleMethod( LightBase, pauseAnimation, void, 2, 2, "Stops the light animation." )
DefineConsoleMethod( LightBase, pauseAnimation, void, (), , "Stops the light animation." )
{
object->pauseAnimation();
}

View file

@ -279,8 +279,6 @@ void WayPoint::unpackUpdate(NetConnection * con, BitStream * stream)
setHidden(stream->readFlag());
}
void WayPoint::initPersistFields()
{
addGroup("Misc");
@ -506,16 +504,16 @@ ConsoleDocFragment _SpawnSpherespawnObject1(
"bool spawnObject(string additionalProps);"
);
ConsoleMethod(SpawnSphere, spawnObject, S32, 2, 3,
DefineConsoleMethod(SpawnSphere, spawnObject, S32, (String additionalProps), ,
"([string additionalProps]) Spawns the object based on the SpawnSphere's "
"class, datablock, properties, and script settings. Allows you to pass in "
"extra properties."
"@hide" )
{
String additionalProps;
//String additionalProps;
if (argc == 3)
additionalProps = (const char*)argv[2];
//if (argc == 3)
// additionalProps = String(argv[2]);
SimObject* obj = object->spawnObject(additionalProps);

View file

@ -581,7 +581,7 @@ static CameraSpline::Knot::Path resolveKnotPath(const char *arg)
}
DefineEngineMethod(PathCamera, pushBack, void, (TransformF transform, F32 speed, const char* type, const char* path),
(1.0, "Normal", "Linear"),
(1.0f, "Normal", "Linear"),
"@brief Adds a new knot to the back of a path camera's path.\n"
"@param transform Transform for the new knot. In the form of \"x y z ax ay az aa\" such as returned by SceneObject::getTransform()\n"
"@param speed Speed setting for this knot.\n"
@ -606,7 +606,7 @@ DefineEngineMethod(PathCamera, pushBack, void, (TransformF transform, F32 speed,
}
DefineEngineMethod(PathCamera, pushFront, void, (TransformF transform, F32 speed, const char* type, const char* path),
(1.0, "Normal", "Linear"),
(1.0f, "Normal", "Linear"),
"@brief Adds a new knot to the front of a path camera's path.\n"
"@param transform Transform for the new knot. In the form of \"x y z ax ay az aa\" such as returned by SceneObject::getTransform()\n"
"@param speed Speed setting for this knot.\n"

View file

@ -27,6 +27,7 @@
#include "math/mathUtils.h"
#include "console/consoleTypes.h"
#include "console/consoleObject.h"
#include "console/engineAPI.h"
#include "sim/netConnection.h"
#include "scene/sceneRenderState.h"
#include "scene/sceneManager.h"
@ -237,7 +238,7 @@ void PhysicsDebrisData::unpackData(BitStream* stream)
shapeName = stream->readSTString();
}
ConsoleMethod( PhysicsDebrisData, preload, void, 2, 2,
DefineConsoleMethod( PhysicsDebrisData, preload, void, (), ,
"@brief Loads some information to have readily available at simulation time.\n\n"
"Forces generation of shaders, materials, and other data used by the %PhysicsDebris object. "
"This function should be used while a level is loading in order to shorten "

View file

@ -24,6 +24,7 @@
#include "T3D/physics/physicsPlugin.h"
#include "console/console.h"
#include "console/engineAPI.h"
#include "console/consoleTypes.h"
#include "console/simSet.h"
#include "core/strings/stringFunctions.h"
@ -123,55 +124,52 @@ void PhysicsPlugin::_debugDraw( SceneManager *graph, const SceneRenderState *sta
world->onDebugDraw( state );
}
ConsoleFunction( physicsPluginPresent, bool, 1, 1, "physicsPluginPresent()\n"
DefineConsoleFunction( physicsPluginPresent, bool, (), , "physicsPluginPresent()"
"@brief Returns true if a physics plugin exists and is initialized.\n\n"
"@ingroup Physics" )
{
return PHYSICSMGR != NULL;
}
ConsoleFunction( physicsInit, bool, 1, 2, "physicsInit( [string library] )" )
DefineConsoleFunction( physicsInit, bool, (const char * library), ("default"), "physicsInit( [string library] )")
{
const char *library = "default";
if ( argc > 1 )
library = argv[1];
return PhysicsPlugin::activate( library );
}
ConsoleFunction( physicsDestroy, void, 1, 1, "physicsDestroy()" )
DefineConsoleFunction( physicsDestroy, void, (), , "physicsDestroy()")
{
if ( PHYSICSMGR )
PHYSICSMGR->destroyPlugin();
}
ConsoleFunction( physicsInitWorld, bool, 2, 2, "physicsInitWorld( String worldName )" )
DefineConsoleFunction( physicsInitWorld, bool, (const char * worldName), , "physicsInitWorld( String worldName )")
{
return PHYSICSMGR && PHYSICSMGR->createWorld( (const char*)argv[1] );
bool res = PHYSICSMGR && PHYSICSMGR->createWorld( String( worldName ) );
return res;
}
ConsoleFunction( physicsDestroyWorld, void, 2, 2, "physicsDestroyWorld( String worldName )" )
DefineConsoleFunction( physicsDestroyWorld, void, (const char * worldName), , "physicsDestroyWorld( String worldName )")
{
if ( PHYSICSMGR )
PHYSICSMGR->destroyWorld( (const char*)argv[1] );
PHYSICSMGR->destroyWorld( worldName );
}
// Control/query of the stop/started state
// of the currently running simulation.
ConsoleFunction( physicsStartSimulation, void, 2, 2, "physicsStartSimulation( String worldName )" )
DefineConsoleFunction( physicsStartSimulation, void, (const char * worldName), , "physicsStartSimulation( String worldName )")
{
if ( PHYSICSMGR )
PHYSICSMGR->enableSimulation( (const char*)argv[1], true );
PHYSICSMGR->enableSimulation( String( worldName ), true );
}
ConsoleFunction( physicsStopSimulation, void, 2, 2, "physicsStopSimulation( String worldName )" )
DefineConsoleFunction( physicsStopSimulation, void, (const char * worldName), , "physicsStopSimulation( String worldName )")
{
if ( PHYSICSMGR )
PHYSICSMGR->enableSimulation( (const char*)argv[1], false );
PHYSICSMGR->enableSimulation( String( worldName ), false );
}
ConsoleFunction( physicsSimulationEnabled, bool, 1, 1, "physicsSimulationEnabled()" )
DefineConsoleFunction( physicsSimulationEnabled, bool, (), , "physicsStopSimulation( String worldName )")
{
return PHYSICSMGR && PHYSICSMGR->isSimulationEnabled();
}
@ -179,14 +177,14 @@ ConsoleFunction( physicsSimulationEnabled, bool, 1, 1, "physicsSimulationEnabled
// Used for slowing down time on the
// physics simulation, and for pausing/restarting
// the simulation.
ConsoleFunction( physicsSetTimeScale, void, 2, 2, "physicsSetTimeScale( F32 scale )" )
DefineConsoleFunction( physicsSetTimeScale, void, (F32 scale), , "physicsSetTimeScale( F32 scale )")
{
if ( PHYSICSMGR )
PHYSICSMGR->setTimeScale( argv[1] );
PHYSICSMGR->setTimeScale( scale );
}
// Get the currently set time scale.
ConsoleFunction( physicsGetTimeScale, F32, 1, 1, "physicsGetTimeScale()" )
DefineConsoleFunction( physicsGetTimeScale, F32, (), , "physicsGetTimeScale()")
{
return PHYSICSMGR && PHYSICSMGR->getTimeScale();
}
@ -195,7 +193,7 @@ ConsoleFunction( physicsGetTimeScale, F32, 1, 1, "physicsGetTimeScale()" )
// physics simulation that they should store
// their current state for later restoration,
// such as when the editor is closed.
ConsoleFunction( physicsStoreState, void, 1, 1, "physicsStoreState()" )
DefineConsoleFunction( physicsStoreState, void, (), , "physicsStoreState()")
{
PhysicsPlugin::getPhysicsResetSignal().trigger( PhysicsResetEvent_Store );
}
@ -203,14 +201,14 @@ ConsoleFunction( physicsStoreState, void, 1, 1, "physicsStoreState()" )
// Used to send a signal to objects in the
// physics simulation that they should restore
// their saved state, such as when the editor is opened.
ConsoleFunction( physicsRestoreState, void, 1, 1, "physicsRestoreState()" )
DefineConsoleFunction( physicsRestoreState, void, (), , "physicsRestoreState()")
{
if ( PHYSICSMGR )
PHYSICSMGR->reset();
}
ConsoleFunction( physicsDebugDraw, void, 2, 2, "physicsDebugDraw( bool enable )" )
DefineConsoleFunction( physicsDebugDraw, void, (bool enable), , "physicsDebugDraw( bool enable )")
{
if ( PHYSICSMGR )
PHYSICSMGR->enableDebugDraw( (S32)argv[1] );
PHYSICSMGR->enableDebugDraw( enable );
}

View 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_

View 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);
}

View 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_

View 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_

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

View 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_

View 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 );
}

View 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_

View 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();
}

View 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_

View 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 );
}

View 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_

View 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];
}

View 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_

View file

@ -0,0 +1,568 @@
//-----------------------------------------------------------------------------
// 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)
{
//Create shared cpu dispatcher
if(!smCpuDispatcher)
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);
}

View 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_

View file

@ -28,6 +28,7 @@
#include "console/simBase.h"
#include "console/console.h"
#include "console/consoleTypes.h"
#include "console/engineAPI.h"
#include "T3D/gameBase/moveManager.h"
#include "ts/tsShapeInstance.h"
#include "T3D/staticShape.h"
@ -317,15 +318,15 @@ void StaticShape::unpackUpdate(NetConnection *connection, BitStream *bstream)
// This appears to be legacy T2 stuff
// Marked internal, as this is flagged to be deleted
// [8/1/2010 mperry]
ConsoleMethod( StaticShape, setPoweredState, void, 3, 3, "(bool isPowered)"
DefineConsoleMethod( StaticShape, setPoweredState, void, (bool isPowered), , "(bool isPowered)"
"@internal")
{
if(!object->isServerObject())
return;
object->setPowered(dAtob(argv[2]));
object->setPowered(isPowered);
}
ConsoleMethod( StaticShape, getPoweredState, bool, 2, 2, "@internal")
DefineConsoleMethod( StaticShape, getPoweredState, bool, (), , "@internal")
{
if(!object->isServerObject())
return(false);

View file

@ -48,6 +48,7 @@
#include "materials/materialFeatureData.h"
#include "materials/materialFeatureTypes.h"
#include "console/engineAPI.h"
#include "T3D/accumulationVolume.h"
using namespace Torque;
@ -111,6 +112,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 +198,13 @@ void TSStatic::initPersistFields()
endGroup("Collision");
addGroup( "AlphaFade" );
addField( "alphaFadeEnable", TypeBool, Offset(mUseAlphaFade, TSStatic), "Turn on/off Alpha Fade" );
addField( "alphaFadeStart", TypeF32, Offset(mAlphaFadeStart, TSStatic), "Distance of start Alpha Fade" );
addField( "alphaFadeEnd", TypeF32, Offset(mAlphaFadeEnd, TSStatic), "Distance of end Alpha Fade" );
addField( "alphaFadeInverse", TypeBool, Offset(mInvertAlphaFade, TSStatic), "Invert Alpha Fade's Start & End Distance" );
endGroup( "AlphaFade" );
addGroup("Debug");
addField( "renderNormals", TypeF32, Offset( mRenderNormalScalar, TSStatic ),
@ -281,6 +294,13 @@ bool TSStatic::onAdd()
_updateShouldTick();
// Accumulation
if ( isClientObject() && mShapeInstance )
{
if ( mShapeInstance->hasAccumulation() )
AccumulationVolume::addObject(this);
}
return true;
}
@ -391,6 +411,13 @@ void TSStatic::onRemove()
{
SAFE_DELETE( mPhysicsRep );
// Accumulation
if ( isClientObject() && mShapeInstance )
{
if ( mShapeInstance->hasAccumulation() )
AccumulationVolume::removeObject(this);
}
mConvexList->nukeList();
removeFromScene();
@ -502,6 +529,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 )
@ -520,6 +577,9 @@ void TSStatic::prepRenderImage( SceneRenderState* state )
rdata.setFadeOverride( 1.0f );
rdata.setOriginSort( mUseOriginSort );
// Acculumation
rdata.setAccuTex(mAccuTex);
// If we have submesh culling enabled then prepare
// the object space frustum to pass to the shape.
Frustum culler;
@ -545,6 +605,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 )
@ -594,6 +667,13 @@ void TSStatic::setTransform(const MatrixF & mat)
if ( mPhysicsRep )
mPhysicsRep->setTransform( mat );
// Accumulation
if ( isClientObject() && mShapeInstance )
{
if ( mShapeInstance->hasAccumulation() )
AccumulationVolume::updateObject(this);
}
// Since this is a static it's render transform changes 1
// to 1 with it's collision transform... no interpolation.
setRenderTransform(mat);
@ -625,6 +705,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 +769,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);

View file

@ -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();

View file

@ -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)