@ -61,6 +61,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
# include "../pnKeyedObject/plKey.h"
# include "../pnMessage/plCorrectionMsg.h"
# include "../pnMessage/plNodeRefMsg.h"
# include "../pnMessage/plObjRefMsg.h"
# include "../pnMessage/plSDLModifierMsg.h"
# include "../plMessage/plSimStateMsg.h"
# include "../plMessage/plSimInfluenceMsg.h"
@ -72,6 +73,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
# include "../plStatusLog/plStatusLog.h"
# include "plPXConvert.h"
# include "plPXPhysicalControllerCore.h"
# include "plPXSubWorld.h"
# include "../plModifier/plDetectorLog.h"
@ -84,25 +86,6 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
# define LogActivate(func) if (fActor->isSleeping()) SimLog("%s activated by %s", GetKeyName(), func);
PhysRecipe : : PhysRecipe ( )
: mass ( 0.f )
, friction ( 0.f )
, restitution ( 0.f )
, bounds ( plSimDefs : : kBoundsMax )
, group ( plSimDefs : : kGroupMax )
, reportsOn ( 0 )
, objectKey ( nil )
, sceneNode ( nil )
, worldKey ( nil )
, convexMesh ( nil )
, triMesh ( nil )
, radius ( 0.f )
, offset ( 0.f , 0.f , 0.f )
, meshStream ( nil )
{
l2s . Reset ( ) ;
}
plProfile_Extern ( MaySendLocation ) ;
plProfile_Extern ( LocationsSent ) ;
plProfile_Extern ( PhysicsUpdates ) ;
@ -128,19 +111,15 @@ int plPXPhysical::fNumberAnimatedActivators = 0;
plPXPhysical : : plPXPhysical ( )
: fSDLMod ( nil )
, fActor ( nil )
, fBoundsType ( plSimDefs : : kBoundsMax )
, fLOSDBs ( plSimDefs : : kLOSDBNone )
, fGroup ( plSimDefs : : kGroupMax )
, fReportsOn ( 0 )
, fLastSyncTime ( 0.0f )
, fProxyGen ( nil )
, fSceneNode ( nil )
, fWorldKey ( nil )
, fSndGroup ( nil )
, fWorldHull ( nil )
, fSaveTriangles ( nil )
, fHullNumberPlanes ( 0 )
, fMass ( 0.f )
, fWeWereHit ( false )
, fHitForce ( 0 , 0 , 0 )
, fHitPos ( 0 , 0 , 0 )
@ -354,15 +333,14 @@ hsBool plPXPhysical::Should_I_Trigger(hsBool enter, hsPoint3& pos)
}
hsBool plPXPhysical : : Init ( PhysRecipe & recipe )
hsBool plPXPhysical : : Init ( )
{
hsBool startAsleep = false ;
fBoundsType = recipe . bounds ;
fGroup = recipe . group ;
fReportsOn = recipe . reportsOn ;
fObjectKey = recipe . objectKey ;
fSceneNode = recipe . sceneNode ;
fWorldKey = recipe . worldKey ;
fGroup = fRecipe . group ;
fReportsOn = fRecipe . reportsOn ;
fObjectKey = fRecipe . objectKey ;
fSceneNode = fRecipe . sceneNode ;
NxActorDesc actorDesc ;
NxSphereShapeDesc sphereDesc ;
@ -370,19 +348,19 @@ hsBool plPXPhysical::Init(PhysRecipe& recipe)
NxTriangleMeshShapeDesc trimeshShapeDesc ;
NxBoxShapeDesc boxDesc ;
plPXConvert : : Matrix ( r ecipe. l2s , actorDesc . globalPose ) ;
plPXConvert : : Matrix ( fR ecipe. l2s , actorDesc . globalPose ) ;
switch ( fBoundsType )
switch ( fRecipe . bounds )
{
case plSimDefs : : kSphereBounds :
{
hsMatrix44 sphereL2W ;
sphereL2W . Reset ( ) ;
sphereL2W . SetTranslate ( & r ecipe. offset ) ;
sphereL2W . SetTranslate ( & fR ecipe. offset ) ;
sphereDesc . radius = r ecipe. radius ;
sphereDesc . radius = fR ecipe. radius ;
plPXConvert : : Matrix ( sphereL2W , sphereDesc . localPose ) ;
sphereDesc . group = fG roup ;
sphereDesc . group = fRecipe . g roup ;
actorDesc . shapes . pushBack ( & sphereDesc ) ;
}
break ;
@ -391,54 +369,54 @@ hsBool plPXPhysical::Init(PhysRecipe& recipe)
// If this is read time (ie, meshStream is nil), turn the convex hull
// into a box. That way the data won't have to change when convex hulls
// actually work right.
if ( fG roup = = plSimDefs : : kGroupDetector & & r ecipe. meshStream = = nil )
if ( fRecipe . g roup = = plSimDefs : : kGroupDetector & & fR ecipe. meshStream = = nil )
{
# ifdef USE_BOXES_FOR_DETECTOR_HULLS
MakeBoxFromHull ( r ecipe. convexMesh , boxDesc ) ;
plSimulationMgr : : GetInstance ( ) - > GetSDK ( ) - > releaseConvexMesh ( * r ecipe. convexMesh ) ;
boxDesc . group = fG roup ;
MakeBoxFromHull ( fR ecipe. convexMesh , boxDesc ) ;
plSimulationMgr : : GetInstance ( ) - > GetSDK ( ) - > releaseConvexMesh ( * fR ecipe. convexMesh ) ;
boxDesc . group = fRecipe . g roup ;
actorDesc . shapes . push_back ( & boxDesc ) ;
# else
# ifdef USE_PHYSX_CONVEXHULL_WORKAROUND
// make a hull of planes for testing IsInside
IMakeHull ( r ecipe. convexMesh , r ecipe. l2s ) ;
IMakeHull ( fR ecipe. convexMesh , fR ecipe. l2s ) ;
# endif // USE_PHYSX_CONVEXHULL_WORKAROUND
convexShapeDesc . meshData = r ecipe. convexMesh ;
convexShapeDesc . userData = r ecipe. meshStream ;
convexShapeDesc . group = fG roup ;
convexShapeDesc . meshData = fR ecipe. convexMesh ;
convexShapeDesc . userData = fR ecipe. meshStream ;
convexShapeDesc . group = fRecipe . g roup ;
actorDesc . shapes . pushBack ( & convexShapeDesc ) ;
# endif // USE_BOXES_FOR_DETECTOR_HULLS
}
else
{
convexShapeDesc . meshData = r ecipe. convexMesh ;
convexShapeDesc . userData = r ecipe. meshStream ;
convexShapeDesc . group = fG roup ;
convexShapeDesc . meshData = fR ecipe. convexMesh ;
convexShapeDesc . userData = fR ecipe. meshStream ;
convexShapeDesc . group = fRecipe . g roup ;
actorDesc . shapes . pushBack ( & convexShapeDesc ) ;
}
break ;
case plSimDefs : : kBoxBounds :
{
boxDesc . dimensions = plPXConvert : : Point ( r ecipe. bDimensions ) ;
boxDesc . dimensions = plPXConvert : : Point ( fR ecipe. bDimensions ) ;
hsMatrix44 boxL2W ;
boxL2W . Reset ( ) ;
boxL2W . SetTranslate ( & r ecipe. bOffset ) ;
boxL2W . SetTranslate ( & fR ecipe. bOffset ) ;
plPXConvert : : Matrix ( boxL2W , boxDesc . localPose ) ;
boxDesc . group = fG roup ;
boxDesc . group = fRecipe . g roup ;
actorDesc . shapes . push_back ( & boxDesc ) ;
}
break ;
case plSimDefs : : kExplicitBounds :
case plSimDefs : : kProxyBounds :
if ( fG roup = = plSimDefs : : kGroupDetector )
if ( fRecipe . g roup = = plSimDefs : : kGroupDetector )
{
SimLog ( " Someone using an Exact on a detector region: %s " , GetKeyName ( ) ) ;
}
trimeshShapeDesc . meshData = r ecipe. triMesh ;
trimeshShapeDesc . userData = r ecipe. meshStream ;
trimeshShapeDesc . group = fG roup ;
trimeshShapeDesc . meshData = fR ecipe. triMesh ;
trimeshShapeDesc . userData = fR ecipe. meshStream ;
trimeshShapeDesc . group = fRecipe . g roup ;
actorDesc . shapes . pushBack ( & trimeshShapeDesc ) ;
break ;
default :
@ -449,10 +427,9 @@ hsBool plPXPhysical::Init(PhysRecipe& recipe)
// Now fill out the body, or dynamic part of the physical
NxBodyDesc bodyDesc ;
fMass = recipe . mass ;
if ( recipe . mass ! = 0 )
if ( fRecipe . mass ! = 0 )
{
bodyDesc . mass = r ecipe. mass ;
bodyDesc . mass = fR ecipe. mass ;
actorDesc . body = & bodyDesc ;
if ( GetProperty ( plSimulationInterface : : kPinned ) )
@ -461,13 +438,13 @@ hsBool plPXPhysical::Init(PhysRecipe& recipe)
startAsleep = true ; // put it to sleep if they are going to be frozen
}
if ( fG roup ! = plSimDefs : : kGroupDynamic | | GetProperty ( plSimulationInterface : : kPhysAnim ) )
if ( fRecipe . g roup ! = plSimDefs : : kGroupDynamic | | GetProperty ( plSimulationInterface : : kPhysAnim ) )
{
SetProperty ( plSimulationInterface : : kPassive , true ) ;
// Even though the code for animated physicals and animated activators are the same
// keep these code snippets separated for fine tuning. Thanks.
if ( fG roup = = plSimDefs : : kGroupDynamic )
if ( fRecipe . g roup = = plSimDefs : : kGroupDynamic )
{
// handle the animated physicals.... make kinematic for now.
fNumberAnimatedPhysicals + + ;
@ -495,7 +472,7 @@ hsBool plPXPhysical::Init(PhysRecipe& recipe)
// Put the dynamics into actor group 1. The actor groups are only used for
// deciding who we get contact reports for.
if ( fG roup = = plSimDefs : : kGroupDynamic )
if ( fRecipe . g roup = = plSimDefs : : kGroupDynamic )
actorDesc . group = 1 ;
NxScene * scene = plSimulationMgr : : GetInstance ( ) - > GetScene ( fWorldKey ) ;
@ -512,7 +489,7 @@ hsBool plPXPhysical::Init(PhysRecipe& recipe)
return false ;
NxShape * shape = fActor - > getShapes ( ) [ 0 ] ;
shape - > setMaterial ( plSimulationMgr : : GetInstance ( ) - > GetMaterialIdx ( scene , r ecipe. friction , r ecipe. restitution ) ) ;
shape - > setMaterial ( plSimulationMgr : : GetInstance ( ) - > GetMaterialIdx ( scene , fR ecipe. friction , fR ecipe. restitution ) ) ;
// Turn on the trigger flags for any detectors.
//
@ -523,7 +500,7 @@ hsBool plPXPhysical::Init(PhysRecipe& recipe)
// problems trying to calculate an intertial tensor. By letting it be
// created as a normal dynamic first, then setting the flags, we work around
// that problem.
if ( fG roup = = plSimDefs : : kGroupDetector )
if ( fRecipe . g roup = = plSimDefs : : kGroupDetector )
{
shape - > setFlag ( NX_TRIGGER_ON_ENTER , true ) ;
shape - > setFlag ( NX_TRIGGER_ON_LEAVE , true ) ;
@ -547,14 +524,8 @@ hsBool plPXPhysical::Init(PhysRecipe& recipe)
plNodeRefMsg * refMsg = TRACKED_NEW plNodeRefMsg ( fSceneNode , plRefMsg : : kOnCreate , - 1 , plNodeRefMsg : : kPhysical ) ;
hsgResMgr : : ResMgr ( ) - > AddViaNotify ( GetKey ( ) , refMsg , plRefFlags : : kActiveRef ) ;
if ( fWorldKey )
{
plGenRefMsg * ref = TRACKED_NEW plGenRefMsg ( GetKey ( ) , plRefMsg : : kOnCreate , 0 , kPhysRefWorld ) ;
hsgResMgr : : ResMgr ( ) - > AddViaNotify ( fWorldKey , ref , plRefFlags : : kActiveRef ) ;
}
// only dynamic physicals without noSync need SDLs
if ( fG roup = = plSimDefs : : kGroupDynamic & & ! fProps . IsBitSet ( plSimulationInterface : : kNoSynchronize ) )
if ( fRecipe . group = = plSimDefs : : kGroupDynamic & & ! fProps . IsBitSet ( plSimulationInterface : : kNoSynchronize ) )
{
// add SDL modifier
plSceneObject * sceneObj = plSceneObject : : ConvertNoRef ( fObjectKey - > ObjectIsLoaded ( ) ) ;
@ -611,28 +582,65 @@ hsBool plPXPhysical::MsgReceive( plMessage* msg )
hsBool plPXPhysical : : HandleRefMsg ( plGenRefMsg * refMsg )
{
UInt8 refCtxt = refMsg - > GetContext ( ) ;
plKey refKey = refMsg - > GetRef ( ) - > GetKey ( ) ;
plKey ourKey = GetKey ( ) ;
PhysRefType refType = PhysRefType ( refMsg - > fType ) ;
const char * refKeyName = refKey ? refKey - > GetName ( ) : " MISSING " ;
switch ( refMsg - > fType ) {
case kPhysRefWorld : {
switch ( refCtxt ) {
case plRefMsg : : kOnCreate :
case plRefMsg : : kOnRequest :
// PotS files specify a plHKSubWorld as the subworld key. For everything else,
// the subworlds are a plSceneObject key. For sanity purposes, we will allow
// references to the plPXSubWorld here. HOWEVER, we will need to grab the target
// and replace our reference...
if ( plPXSubWorld * subWorldIface = plPXSubWorld : : ConvertNoRef ( refMsg - > GetRef ( ) ) ) {
hsAssert ( subWorldIface - > GetOwnerKey ( ) , " subworld owner is NULL?! Uh oh... " ) ;
plGenRefMsg * replaceRefMsg = new plGenRefMsg ( GetKey ( ) , plRefMsg : : kOnReplace , 0 , kPhysRefWorld ) ;
hsgResMgr : : ResMgr ( ) - > AddViaNotify ( subWorldIface - > GetOwnerKey ( ) , replaceRefMsg , plRefFlags : : kActiveRef ) ;
}
// fall-thru is intentional :)
case plRefMsg : : kOnReplace :
// loading into a subworld
if ( plSceneObject * subSO = plSceneObject : : ConvertNoRef ( refMsg - > GetRef ( ) ) ) {
fWorldKey = subSO - > GetKey ( ) ;
// Cyan produced files will never have plPXSubWorld as this is a H'uru-ism.
// Let us make a default one such that we can play with default subworlds at runtime.
// HAAAAAAAAAX!!!
plPXSubWorld * subWorldIface = plPXSubWorld : : ConvertNoRef ( subSO - > GetGenericInterface ( plPXSubWorld : : Index ( ) ) ) ;
if ( ! subWorldIface ) {
subWorldIface = new plPXSubWorld ( ) ;
// This can be simplified if/when incorporating zrax' String Theory library
std : : string strKeyName = subSO - > GetKeyName ( ) ;
strKeyName + = " _DefSubWorld " ;
const char * cKeyName = strKeyName . c_str ( ) ;
hsgResMgr : : ResMgr ( ) - > NewKey ( cKeyName ,
subWorldIface , GetKey ( ) - > GetUoid ( ) . GetLocation ( ) ) ;
plObjRefMsg * subIfaceRef = new plObjRefMsg ( subSO - > GetKey ( ) , plRefMsg : : kOnCreate , 0 , plObjRefMsg : : kInterface ) ;
// this will send the reference immediately
hsgResMgr : : ResMgr ( ) - > SendRef ( subWorldIface , subIfaceRef , plRefFlags : : kActiveRef ) ;
}
if ( refType = = kPhysRefWorld )
{
if ( refCtxt = = plRefMsg : : kOnCreate | | refCtxt = = plRefMsg : : kOnRequest )
{
// Cache the initial transform, since we assume the sceneobject already knows
// that and doesn't need to be told again
IGetTransformGlobal ( fCachedLocal2World ) ;
// Now, we can initialize the physical...
Init ( ) ;
IGetTransformGlobal ( fCachedLocal2World ) ;
return true ;
}
}
if ( refCtxt = = plRefMsg : : kOnDestroy )
{
break ;
case plRefMsg : : kOnDestroy : {
// our world was deleted out from under us: move to the main world
// NOTE: this was not implemented even before the PXSubWorld rewrite.
// not going to bother!
// hsAssert(0, "Lost world");
}
break ;
}
else if ( refType = = kPhysRefSndGroup )
{
break ;
case kPhysRefSndGroup : {
switch ( refCtxt )
{
case plRefMsg : : kOnCreate :
@ -645,9 +653,11 @@ hsBool plPXPhysical::HandleRefMsg(plGenRefMsg* refMsg)
break ;
}
}
else
{
break ;
default :
hsAssert ( 0 , " Unknown ref type, who sent us this? " ) ;
break ;
}
return true ;
@ -878,7 +888,6 @@ void plPXPhysical::IGetTransformGlobal(hsMatrix44& l2w) const
{
plSceneObject * so = plSceneObject : : ConvertNoRef ( fWorldKey - > ObjectIsLoaded ( ) ) ;
hsAssert ( so , " Scene object not loaded while accessing subworld. " ) ;
// We'll hit this at export time, when the ci isn't ready yet, so do a check
if ( so - > GetCoordinateInterface ( ) )
{
const hsMatrix44 & s2w = so - > GetCoordinateInterface ( ) - > GetLocalToWorld ( ) ;
@ -1026,23 +1035,22 @@ void plPXPhysical::Read(hsStream* stream, hsResMgr* mgr)
plPhysical : : Read ( stream , mgr ) ;
ClearMatrix ( fCachedLocal2World ) ;
PhysRecipe recipe ;
recipe . mass = stream - > ReadSwapScalar ( ) ;
recipe . friction = stream - > ReadSwapScalar ( ) ;
recipe . restitution = stream - > ReadSwapScalar ( ) ;
recipe . bounds = ( plSimDefs : : Bounds ) stream - > ReadByte ( ) ;
recipe . group = ( plSimDefs : : Group ) stream - > ReadByte ( ) ;
recipe . reportsOn = stream - > ReadSwap32 ( ) ;
fRecipe . mass = stream - > ReadSwapScalar ( ) ;
fRecipe . friction = stream - > ReadSwapScalar ( ) ;
fRecipe . restitution = stream - > ReadSwapScalar ( ) ;
fRecipe . bounds = ( plSimDefs : : Bounds ) stream - > ReadByte ( ) ;
fRecipe . group = ( plSimDefs : : Group ) stream - > ReadByte ( ) ;
fRecipe . reportsOn = stream - > ReadSwap32 ( ) ;
fLOSDBs = stream - > ReadSwap16 ( ) ;
//hack for swim regions currently they are labeled as static av blockers
if ( fLOSDBs = = plSimDefs : : kLOSDBSwimRegion )
{
r ecipe. group = plSimDefs : : kGroupMax ;
fR ecipe. group = plSimDefs : : kGroupMax ;
}
//
r ecipe. objectKey = mgr - > ReadKey ( stream ) ;
r ecipe. sceneNode = mgr - > ReadKey ( stream ) ;
r ecipe. worldKey = mgr - > ReadKey ( stream ) ;
fR ecipe. objectKey = mgr - > ReadKey ( stream ) ;
fR ecipe. sceneNode = mgr - > ReadKey ( stream ) ;
fR ecipe. worldKey = mgr - > ReadKeyNotifyMe ( stream , new plGenRefMsg ( GetKey ( ) , plRefMsg : : kOnCreate , 0 , kPhysRefWorld ) , plRefFlags : : kActiveRef ) ;
mgr - > ReadKeyNotifyMe ( stream , TRACKED_NEW plGenRefMsg ( GetKey ( ) , plRefMsg : : kOnCreate , 0 , kPhysRefSndGroup ) , plRefFlags : : kActiveRef ) ;
@ -1050,30 +1058,33 @@ void plPXPhysical::Read(hsStream* stream, hsResMgr* mgr)
hsQuat rot ;
pos . Read ( stream ) ;
rot . Read ( stream ) ;
rot . MakeMatrix ( & r ecipe. l2s ) ;
r ecipe. l2s . SetTranslate ( & pos ) ;
rot . MakeMatrix ( & fR ecipe. l2s ) ;
fR ecipe. l2s . SetTranslate ( & pos ) ;
fProps . Read ( stream ) ;
if ( r ecipe. bounds = = plSimDefs : : kSphereBounds )
if ( fR ecipe. bounds = = plSimDefs : : kSphereBounds )
{
r ecipe. radius = stream - > ReadSwapScalar ( ) ;
r ecipe. offset . Read ( stream ) ;
fR ecipe. radius = stream - > ReadSwapScalar ( ) ;
fR ecipe. offset . Read ( stream ) ;
}
else if ( r ecipe. bounds = = plSimDefs : : kBoxBounds )
else if ( fR ecipe. bounds = = plSimDefs : : kBoxBounds )
{
r ecipe. bDimensions . Read ( stream ) ;
r ecipe. bOffset . Read ( stream ) ;
fR ecipe. bDimensions . Read ( stream ) ;
fR ecipe. bOffset . Read ( stream ) ;
}
else
{
if ( r ecipe. bounds = = plSimDefs : : kHullBounds )
r ecipe. convexMesh = IReadHull ( stream ) ;
if ( fR ecipe. bounds = = plSimDefs : : kHullBounds )
fR ecipe. convexMesh = IReadHull ( stream ) ;
else
r ecipe. triMesh = IReadTriMesh ( stream ) ;
fR ecipe. triMesh = IReadTriMesh ( stream ) ;
}
Init ( recipe ) ;
// If we do not have a world, specified, we go ahead and init into the main world...
// This will been done in MsgReceive otherwise
if ( ! fRecipe . worldKey )
Init ( ) ;
hsAssert ( ! fProxyGen , " Already have proxy gen, double read? " ) ;
@ -1115,7 +1126,7 @@ void plPXPhysical::Read(hsStream* stream, hsResMgr* mgr)
// Statics are yellow
physColor . Set ( 1.f , 0.8f , 0.2f , 1.f ) ;
// if in a subworld... slightly transparent
if ( fW orldKey )
if ( fRecipe . w orldKey )
opac = 0.6f ;
}
else
@ -1241,7 +1252,7 @@ void plPXPhysical::Write(hsStream* stream, hsResMgr* mgr)
stream - > WriteSwapScalar ( fActor - > getMass ( ) ) ;
stream - > WriteSwapScalar ( friction ) ;
stream - > WriteSwapScalar ( restitution ) ;
stream - > WriteByte ( fBoundsType ) ;
stream - > WriteByte ( fRecipe . bounds ) ;
stream - > WriteByte ( fGroup ) ;
stream - > WriteSwap32 ( fReportsOn ) ;
stream - > WriteSwap16 ( fLOSDBs ) ;
@ -1259,14 +1270,14 @@ void plPXPhysical::Write(hsStream* stream, hsResMgr* mgr)
fProps . Write ( stream ) ;
if ( fBoundsType = = plSimDefs : : kSphereBounds )
if ( fRecipe . bounds = = plSimDefs : : kSphereBounds )
{
const NxSphereShape * sphereShape = shape - > isSphere ( ) ;
stream - > WriteSwapScalar ( sphereShape - > getRadius ( ) ) ;
hsPoint3 localPos = plPXConvert : : Point ( sphereShape - > getLocalPosition ( ) ) ;
localPos . Write ( stream ) ;
}
else if ( fBoundsType = = plSimDefs : : kBoxBounds )
else if ( fRecipe . bounds = = plSimDefs : : kBoxBounds )
{
const NxBoxShape * boxShape = shape - > isBox ( ) ;
hsPoint3 dim = plPXConvert : : Point ( boxShape - > getDimensions ( ) ) ;
@ -1276,7 +1287,7 @@ void plPXPhysical::Write(hsStream* stream, hsResMgr* mgr)
}
else
{
if ( fBoundsType = = plSimDefs : : kHullBounds )
if ( fRecipe . bounds = = plSimDefs : : kHullBounds )
hsAssert ( shape - > isConvexMesh ( ) , " Hull shape isn't a convex mesh " ) ;
else
hsAssert ( shape - > isTriangleMesh ( ) , " Exact shape isn't a trimesh " ) ;