pxMultiActor.cpp
Engine/source/T3D/physics/physx/pxMultiActor.cpp
Classes:
class
Public Functions
ConsoleDocClass(PxMultiActor , "@brief Represents a destructible physical object simulated using <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">PhysX.\n\n</a>" "Usually it is prefered <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> use <a href="/coding/class/classphysicsshape/">PhysicsShape</a> and not <a href="/coding/class/classpxmultiactor/">PxMultiActor</a> because " "it is not PhysX specific and much easier <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">setup.\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">PxMultiActorData.\n</a>" "@ingroup Physics" )
ConsoleDocClass(PxMultiActorData , "@brief Defines the properties of a type of <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">PxMultiActor.\n\n</a>" "Usually it is prefered <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> use <a href="/coding/class/classphysicsshape/">PhysicsShape</a> rather than <a href="/coding/class/classpxmultiactor/">PxMultiActor</a> because " "a <a href="/coding/class/classphysicsshape/">PhysicsShape</a> is not PhysX specific and can be much easier <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">setup.\n\n</a>" "For more information, refer <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> Nvidia 's PhysX <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">docs.\n\n</a>" " @ingroup Physics" )
ConsoleMethod(PxMultiActor , listMeshes , void , 3 , 3 , "(enum Hidden/Shown/All)" "@brief Lists all meshes of the provided type in the console <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">window.\n\n</a>" "@param All Lists all of the %<a href="/coding/class/classpxmultiactor/">PxMultiActor</a>'s <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">meshes.\n</a>" "@param Hidden Lists all of the %<a href="/coding/class/classpxmultiactor/">PxMultiActor</a>'s hidden <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">meshes.\n</a>" "@param Shown Lists all of the %<a href="/coding/class/classpxmultiactor/">PxMultiActor</a>'s visible <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">meshes.\n</a>" )
ConsoleMethod(PxMultiActor , setAllHidden , void , 3 , 3 , "( bool )" "@brief Hides or unhides all meshes contained in the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">PxMultiActor.\n\n</a>" "Hidden meshes will not be rendered." )
ConsoleMethod(PxMultiActor , setBroken , void , 3 , 3 , "( bool )" "@brief Sets the <a href="/coding/class/classpxmultiactor/">PxMultiActor</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> a broken or unbroken <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">state.\n\n</a>" )
ConsoleMethod(PxMultiActor , setMeshHidden , void , 4 , 4 , "(string meshName, bool isHidden)" "@brief Prevents the provided mesh from being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">rendered.\n\n</a>" )
ConsoleMethod(PxMultiActorData , dumpModel , void , 2 , 2 , "@brief Dumps model hierarchy and details <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> a <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">file.\n\n</a>" "The <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> will be created as \'model.dump\' in the game folder. " "If model.dump already exists, it will be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">overwritten.\n\n</a>" )
ConsoleMethod(PxMultiActorData , reload , void , 2 , 2 , "" "@brief Reloads all data used <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">PxMultiActorData.\n\n</a>" "If the reload sucessfully completes, all <a href="/coding/class/classpxmultiactor/">PxMultiActor</a> 's will be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">notified.\n\n</a>" )
Detailed Description
Public Functions
ConsoleDocClass(PxMultiActor , "@brief Represents a destructible physical object simulated using <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">PhysX.\n\n</a>" "Usually it is prefered <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> use <a href="/coding/class/classphysicsshape/">PhysicsShape</a> and not <a href="/coding/class/classpxmultiactor/">PxMultiActor</a> because " "it is not PhysX specific and much easier <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">setup.\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">PxMultiActorData.\n</a>" "@ingroup Physics" )
ConsoleDocClass(PxMultiActorData , "@brief Defines the properties of a type of <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">PxMultiActor.\n\n</a>" "Usually it is prefered <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> use <a href="/coding/class/classphysicsshape/">PhysicsShape</a> rather than <a href="/coding/class/classpxmultiactor/">PxMultiActor</a> because " "a <a href="/coding/class/classphysicsshape/">PhysicsShape</a> is not PhysX specific and can be much easier <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">setup.\n\n</a>" "For more information, refer <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> Nvidia 's PhysX <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">docs.\n\n</a>" " @ingroup Physics" )
ConsoleMethod(PxMultiActor , listMeshes , void , 3 , 3 , "(enum Hidden/Shown/All)" "@brief Lists all meshes of the provided type in the console <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">window.\n\n</a>" "@param All Lists all of the %<a href="/coding/class/classpxmultiactor/">PxMultiActor</a>'s <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">meshes.\n</a>" "@param Hidden Lists all of the %<a href="/coding/class/classpxmultiactor/">PxMultiActor</a>'s hidden <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">meshes.\n</a>" "@param Shown Lists all of the %<a href="/coding/class/classpxmultiactor/">PxMultiActor</a>'s visible <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">meshes.\n</a>" )
ConsoleMethod(PxMultiActor , setAllHidden , void , 3 , 3 , "( bool )" "@brief Hides or unhides all meshes contained in the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">PxMultiActor.\n\n</a>" "Hidden meshes will not be rendered." )
ConsoleMethod(PxMultiActor , setBroken , void , 3 , 3 , "( bool )" "@brief Sets the <a href="/coding/class/classpxmultiactor/">PxMultiActor</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> a broken or unbroken <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">state.\n\n</a>" )
ConsoleMethod(PxMultiActor , setMeshHidden , void , 4 , 4 , "(string meshName, bool isHidden)" "@brief Prevents the provided mesh from being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">rendered.\n\n</a>" )
ConsoleMethod(PxMultiActorData , dumpModel , void , 2 , 2 , "@brief Dumps model hierarchy and details <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> a <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">file.\n\n</a>" "The <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> will be created as \'model.dump\' in the game folder. " "If model.dump already exists, it will be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">overwritten.\n\n</a>" )
ConsoleMethod(PxMultiActorData , reload , void , 2 , 2 , "" "@brief Reloads all data used <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">PxMultiActorData.\n\n</a>" "If the reload sucessfully completes, all <a href="/coding/class/classpxmultiactor/">PxMultiActor</a> 's will be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">notified.\n\n</a>" )
IMPLEMENT_CO_DATABLOCK_V1(PxMultiActorData )
IMPLEMENT_CO_NETOBJECT_V1(PxMultiActor )
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "platform/platform.h" 25#include "T3D/physics/physX/pxMultiActor.h" 26 27#include "console/consoleTypes.h" 28#include "core/stream/fileStream.h" 29#include "core/stream/bitStream.h" 30#include "core/resourceManager.h" 31#include "core/strings/stringUnit.h" 32#include "sim/netConnection.h" 33#include "math/mathIO.h" 34#include "math/mathUtils.h" 35#include "gfx/gfxTransformSaver.h" 36#include "gfx/gfxDrawUtil.h" 37#include "gfx/primBuilder.h" 38#include "collision/collision.h" 39#include "collision/abstractPolyList.h" 40#include "ts/tsShapeInstance.h" 41#include "ts/tsPartInstance.h" 42#include "lighting/lightManager.h" 43#include "scene/sceneManager.h" 44#include "scene/sceneRenderState.h" 45#include "scene/sceneObjectLightingPlugin.h" 46#include "T3D/objectTypes.h" 47#include "T3D/containerQuery.h" 48#include "T3D/fx/particleEmitter.h" 49#include "T3D/debris.h" 50#include "renderInstance/renderPassManager.h" 51#include "gui/worldEditor/editor.h" // For gEditingMission 52#include "T3D/physics/physX/px.h" 53#include "T3D/physics/physX/pxWorld.h" 54#include "T3D/physics/physX/pxMaterial.h" 55#include "T3D/physics/physX/pxCasts.h" 56#include "T3D/physics/physx/pxUtils.h" 57#include "sfx/sfxSystem.h" 58 59#include <NXU_helper.h> 60#include <nxu_schema.h> 61#include <NXU_customcopy.h> 62 63 64class PxMultiActor_Notify : public NXU_userNotify 65{ 66protected: 67 68 Vector<NxActor*> mActors; 69 70 Vector<NxShape*> mShapes; 71 72 Vector<NxJoint*> mJoints; 73 74 const NxMat34 mTransform; 75 76 const Point3F mScale; 77 78 F32 mMassScale; 79 80 NxCompartment *mCompartment; 81 82 PxMaterial *mMaterial; 83 84 Vector<String> *mActorUserProperties; 85 86 Vector<String> *mJointUserProperties; 87 88public: 89 90 void NXU_notifyJoint( NxJoint *joint, const char *userProperties ) 91 { 92 if ( mJointUserProperties ) 93 mJointUserProperties->push_back( userProperties ); 94 mJoints.push_back( joint ); 95 } 96 97 bool NXU_preNotifyJoint( NxJointDesc &joint, const char *userProperties ) 98 { 99 joint.localAnchor[0].x *= mScale.x; 100 joint.localAnchor[0].y *= mScale.y; 101 joint.localAnchor[0].z *= mScale.z; 102 103 joint.localAnchor[1].x *= mScale.x; 104 joint.localAnchor[1].y *= mScale.y; 105 joint.localAnchor[1].z *= mScale.z; 106 107 // The PhysX exporter from 3dsMax doesn't allow creation 108 // of fixed joints. It also doesn't seem to export the 109 // joint names! So look for joints which all all the 110 // motion axes are locked... make those fixed joints. 111 if ( joint.getType() == NX_JOINT_D6 ) 112 { 113 NxD6JointDesc *d6Joint = static_cast<NxD6JointDesc*>( &joint ); 114 115 if ( d6Joint->xMotion == NX_D6JOINT_MOTION_LOCKED && 116 d6Joint->yMotion == NX_D6JOINT_MOTION_LOCKED && 117 d6Joint->zMotion == NX_D6JOINT_MOTION_LOCKED && 118 d6Joint->swing1Motion == NX_D6JOINT_MOTION_LOCKED && 119 d6Joint->swing2Motion == NX_D6JOINT_MOTION_LOCKED && 120 d6Joint->twistMotion == NX_D6JOINT_MOTION_LOCKED ) 121 { 122 // Ok... build a new fixed joint. 123 NxFixedJointDesc fixed; 124 fixed.actor[0] = joint.actor[0]; 125 fixed.actor[1] = joint.actor[1]; 126 fixed.localNormal[0] = joint.localNormal[0]; 127 fixed.localNormal[1] = joint.localNormal[1]; 128 fixed.localAxis[0] = joint.localAxis[0]; 129 fixed.localAxis[1] = joint.localAxis[1]; 130 fixed.localAnchor[0] = joint.localAnchor[0]; 131 fixed.localAnchor[1] = joint.localAnchor[1]; 132 fixed.maxForce = joint.maxForce; 133 fixed.maxTorque = joint.maxTorque; 134 fixed.name = joint.name; 135 fixed.userData = joint.userData; 136 fixed.jointFlags = joint.jointFlags; 137 138 // What scene are we adding this to? 139 NxActor *actor = fixed.actor[0] ? fixed.actor[0] : fixed.actor[1]; 140 NxScene &scene = actor->getScene(); 141 142 NxJoint* theJoint = scene.createJoint( fixed ); 143 mJoints.push_back( theJoint ); 144 if ( mJointUserProperties ) 145 mJointUserProperties->push_back( userProperties ); 146 147 // Don't generate this joint. 148 return false; 149 } 150 } 151 152 return true; 153 } 154 155 void NXU_notifyActor( NxActor *actor, const char *userProperties ) 156 { 157 mActors.push_back( actor ); 158 159 // Save the shapes. 160 for ( U32 i=0; i < actor->getNbShapes(); i++ ) 161 mShapes.push_back( actor->getShapes()[i] ); 162 163 mActorUserProperties->push_back( userProperties ); 164 }; 165 166 bool NXU_preNotifyMaterial( NxMaterialDesc &t, const char *userProperties ) 167 { 168 // Don't generate materials if we have one defined! 169 return !mMaterial; 170 } 171 172 bool NXU_preNotifyActor( NxActorDesc &actor, const char *userProperties ) 173 { 174 // Set the right compartment. 175 actor.compartment = mCompartment; 176 177 if ( actor.shapes.size() == 0 ) 178 Con::warnf( "PxMultiActor_Notify::NXU_preNotifyActor, got an actor (%s) with no shapes, was this intentional?", actor.name ); 179 180 // For every shape, cast to its particular type 181 // and apply the scale to size, mass and localPosition. 182 for( S32 i = 0; i < actor.shapes.size(); i++ ) 183 { 184 // If we have material then set it. 185 if ( mMaterial ) 186 actor.shapes[i]->materialIndex = mMaterial->getMaterialId(); 187 188 switch( actor.shapes[i]->getType() ) 189 { 190 case NX_SHAPE_BOX: 191 { 192 NxBoxShapeDesc *boxDesc = (NxBoxShapeDesc*)actor.shapes[i]; 193 194 boxDesc->mass *= mMassScale; 195 196 boxDesc->dimensions.x *= mScale.x; 197 boxDesc->dimensions.y *= mScale.y; 198 boxDesc->dimensions.z *= mScale.z; 199 200 boxDesc->localPose.t.x *= mScale.x; 201 boxDesc->localPose.t.y *= mScale.y; 202 boxDesc->localPose.t.z *= mScale.z; 203 break; 204 } 205 206 case NX_SHAPE_SPHERE: 207 { 208 NxSphereShapeDesc *sphereDesc = (NxSphereShapeDesc*)actor.shapes[i]; 209 210 sphereDesc->mass *= mMassScale; 211 212 // TODO: Spheres do not work with non-uniform 213 // scales very well... how do we fix this? 214 sphereDesc->radius *= mScale.x; 215 216 sphereDesc->localPose.t.x *= mScale.x; 217 sphereDesc->localPose.t.y *= mScale.y; 218 sphereDesc->localPose.t.z *= mScale.z; 219 break; 220 } 221 222 case NX_SHAPE_CAPSULE: 223 { 224 NxCapsuleShapeDesc *capsuleDesc = (NxCapsuleShapeDesc*)actor.shapes[i]; 225 226 capsuleDesc->mass *= mMassScale; 227 228 // TODO: Capsules do not work with non-uniform 229 // scales very well... how do we fix this? 230 capsuleDesc->radius *= mScale.x; 231 capsuleDesc->height *= mScale.y; 232 233 capsuleDesc->localPose.t.x *= mScale.x; 234 capsuleDesc->localPose.t.y *= mScale.y; 235 capsuleDesc->localPose.t.z *= mScale.z; 236 break; 237 } 238 239 default: 240 { 241 static String lookup[] = 242 { 243 "PLANE", 244 "SPHERE", 245 "BOX", 246 "CAPSULE", 247 "WHEEL", 248 "CONVEX", 249 "MESH", 250 "HEIGHTFIELD" 251 }; 252 253 Con::warnf( "PxMultiActor_Notify::NXU_preNotifyActor, unsupported shape type (%s), on Actor (%s)", lookup[actor.shapes[i]->getType()].c_str(), actor.name ); 254 255 delete actor.shapes[i]; 256 actor.shapes.erase( actor.shapes.begin() + i ); 257 --i; 258 break; 259 } 260 } 261 } 262 263 NxBodyDesc *body = const_cast<NxBodyDesc*>( actor.body ); 264 if ( body ) 265 { 266 // Must scale all of these parameters, else there will be odd results! 267 body->mass *= mMassScale; 268 body->massLocalPose.t.multiply( mMassScale, body->massLocalPose.t ); 269 body->massSpaceInertia.multiply( mMassScale, body->massSpaceInertia ); 270 271 // Ragdoll damping! 272 //body->sleepDamping = 1.7f; 273 //body->linearDamping = 0.4f; 274 //body->angularDamping = 0.08f; 275 //body->wakeUpCounter = 0.3f; 276 } 277 278 return true; 279 }; 280 281public: 282 283 PxMultiActor_Notify( NxCompartment *compartment, 284 PxMaterial *material, 285 const NxMat34& mat, 286 const Point3F& scale, 287 Vector<String> *actorProps = NULL, 288 Vector<String> *jointProps = NULL ) 289 : mCompartment( compartment ), 290 mMaterial( material ), 291 mScale( scale ), 292 mTransform( mat ), 293 mActorUserProperties( actorProps ), 294 mJointUserProperties( jointProps ) 295 { 296 const F32 unit = VectorF( 1.0f, 1.0f, 1.0f ).len(); 297 mMassScale = mScale.len() / unit; 298 } 299 300 virtual ~PxMultiActor_Notify() 301 { 302 } 303 304 const Vector<NxActor*>& getActors() { return mActors; } 305 const Vector<NxShape*>& getShapes() { return mShapes; } 306 const Vector<NxJoint*>& getJoints() { return mJoints; } 307}; 308 309ConsoleDocClass( PxMultiActorData, 310 311 "@brief Defines the properties of a type of PxMultiActor.\n\n" 312 313 "Usually it is prefered to use PhysicsShape rather than PxMultiActor because " 314 "a PhysicsShape is not PhysX specific and can be much easier to setup.\n\n" 315 316 "For more information, refer to Nvidia's PhysX docs.\n\n" 317 318 "@ingroup Physics" 319); 320 321IMPLEMENT_CO_DATABLOCK_V1(PxMultiActorData); 322 323PxMultiActorData::PxMultiActorData() 324 : material( NULL ), 325 collection( NULL ), 326 waterDragScale( 1.0f ), 327 buoyancyDensity( 1.0f ), 328 angularDrag( 0.0f ), 329 linearDrag( 0.0f ), 330 clientOnly( false ), 331 singlePlayerOnly( false ), 332 shapeName( StringTable->insert( "" ) ), 333 physXStream( StringTable->insert( "" ) ), 334 breakForce( 0.0f ) 335{ 336 for ( S32 i = 0; i < MaxCorrectionNodes; i++ ) 337 correctionNodeNames[i] = StringTable->insert( "" ); 338 339 for ( S32 i = 0; i < MaxCorrectionNodes; i++ ) 340 correctionNodes[i] = -1; 341 342 for ( S32 i = 0; i < NumMountPoints; i++ ) 343 { 344 mountNodeNames[i] = StringTable->insert( "" ); 345 mountPointNode[i] = -1; 346 } 347} 348 349PxMultiActorData::~PxMultiActorData() 350{ 351 if ( collection ) 352 NXU::releaseCollection( collection ); 353} 354 355void PxMultiActorData::initPersistFields() 356{ 357 Parent::initPersistFields(); 358 359 addGroup("Media"); 360 addField( "shapeName", TypeFilename, Offset( shapeName, PxMultiActorData ), 361 "@brief Path to the .DAE or .DTS file to render.\n\n"); 362 endGroup("Media"); 363 364 // PhysX collision properties. 365 addGroup( "Physics" ); 366 367 addField( "physXStream", TypeFilename, Offset( physXStream, PxMultiActorData ), 368 "@brief .XML file containing data such as actors, shapes, and joints.\n\n" 369 "These files can be created using a free PhysX plugin for 3DS Max.\n\n"); 370 addField( "material", TYPEID< PxMaterial >(), Offset( material, PxMultiActorData ), 371 "@brief An optional PxMaterial to be used for the PxMultiActor.\n\n" 372 "Defines properties such as friction and restitution. " 373 "Unrelated to the material used for rendering. The physXStream will contain " 374 "defined materials that can be customized in 3DS Max. " 375 "To override the material for all physics shapes in the physXStream, specify a material here.\n\n"); 376 377 addField( "noCorrection", TypeBool, Offset( noCorrection, PxMultiActorData ), 378 "@hide" ); 379 380 UTF8 buff[256]; 381 for ( S32 i=0; i < MaxCorrectionNodes; i++ ) 382 { 383 //dSprintf( buff, sizeof(buff), "correctionNode%d", i ); 384 addField( buff, TypeString, Offset( correctionNodeNames[i], PxMultiActorData ), "@hide" ); 385 } 386 387 for ( S32 i=0; i < NumMountPoints; i++ ) 388 { 389 //dSprintf( buff, sizeof(buff), "mountNode%d", i ); 390 addField( buff, TypeString, Offset( mountNodeNames[i], PxMultiActorData ), "@hide" ); 391 } 392 393 addField( "angularDrag", TypeF32, Offset( angularDrag, PxMultiActorData ), 394 "@brief Value used to help calculate rotational drag force while submerged in water.\n\n"); 395 addField( "linearDrag", TypeF32, Offset( linearDrag, PxMultiActorData ), 396 "@brief Value used to help calculate linear drag force while submerged in water.\n\n"); 397 addField( "waterDragScale", TypeF32, Offset( waterDragScale, PxMultiActorData ), 398 "@brief Scale to apply to linear and angular dampening while submerged in water.\n\n "); 399 addField( "buoyancyDensity", TypeF32, Offset( buoyancyDensity, PxMultiActorData ), 400 "@brief The density used to calculate buoyant forces.\n\n" 401 "The result of the calculated buoyancy is relative to the density of the WaterObject the PxMultiActor is within.\n\n" 402 "@note This value is necessary because Torque 3D does its own buoyancy simulation. It is not handled by PhysX." 403 "@see WaterObject::density"); 404 405 endGroup( "Physics" ); 406 407 addField( "clientOnly", TypeBool, Offset( clientOnly, PxMultiActorData ), 408 "@hide"); 409 addField( "singlePlayerOnly", TypeBool, Offset( singlePlayerOnly, PxMultiActorData ), 410 "@hide"); 411 addField( "breakForce", TypeF32, Offset( breakForce, PxMultiActorData ), 412 "@brief Force required to break an actor.\n\n" 413 "This value does not apply to joints. " 414 "If an actor is associated with a joint it will break whenever the joint does. " 415 "This allows an actor \"not\" associated with a joint to also be breakable.\n\n"); 416} 417 418void PxMultiActorData::packData(BitStream* stream) 419{ 420 Parent::packData(stream); 421 422 stream->writeString( shapeName ); 423 stream->writeString( physXStream ); 424 425 if( stream->writeFlag( material ) ) 426 stream->writeRangedU32( packed ? SimObjectId( material ) : material->getId(), 427 DataBlockObjectIdFirst, DataBlockObjectIdLast ); 428 429 if ( !stream->writeFlag( noCorrection ) ) 430 { 431 // Write the correction node indices for the client. 432 for ( S32 i = 0; i < MaxCorrectionNodes; i++ ) 433 stream->write( correctionNodes[i] ); 434 } 435 436 for ( S32 i = 0; i < NumMountPoints; i++ ) 437 stream->write( mountPointNode[i] ); 438 439 stream->write( waterDragScale ); 440 stream->write( buoyancyDensity ); 441 stream->write( angularDrag ); 442 stream->write( linearDrag ); 443 444 stream->writeFlag( clientOnly ); 445 stream->writeFlag( singlePlayerOnly ); 446 stream->write( breakForce ); 447} 448 449void PxMultiActorData::unpackData(BitStream* stream) 450{ 451 Parent::unpackData(stream); 452 453 shapeName = stream->readSTString(); 454 physXStream = stream->readSTString(); 455 456 if( stream->readFlag() ) 457 material = (PxMaterial*)stream->readRangedU32( DataBlockObjectIdFirst, DataBlockObjectIdLast ); 458 459 noCorrection = stream->readFlag(); 460 if ( !noCorrection ) 461 { 462 for ( S32 i = 0; i < MaxCorrectionNodes; i++ ) 463 stream->read( &correctionNodes[i] ); 464 } 465 466 for ( S32 i = 0; i < NumMountPoints; i++ ) 467 stream->read( &mountPointNode[i] ); 468 469 stream->read( &waterDragScale ); 470 stream->read( &buoyancyDensity ); 471 stream->read( &angularDrag ); 472 stream->read( &linearDrag ); 473 474 clientOnly = stream->readFlag(); 475 singlePlayerOnly = stream->readFlag(); 476 stream->read( &breakForce ); 477} 478 479bool PxMultiActorData::preload( bool server, String &errorBuffer ) 480{ 481 if ( !Parent::preload( server, errorBuffer ) ) 482 return false; 483 484 // If the stream is null, exit. 485 if ( !physXStream || !physXStream[0] ) 486 { 487 errorBuffer = "PxMultiActorData::preload: physXStream is unset!"; 488 return false; 489 } 490 491 // Set up our buffer for the binary stream filename path. 492 UTF8 binPhysXStream[260] = { 0 }; 493 const UTF8* ext = dStrrchr( physXStream, '.' ); 494 495 // Copy the xml stream path except for the extension. 496 if ( ext ) 497 dStrncpy( binPhysXStream, physXStream, getMin( 260, ext - physXStream ) ); 498 else 499 dStrncpy( binPhysXStream, physXStream, 260 ); 500 501 // Concatenate the binary extension. 502 dStrcat( binPhysXStream, ".nxb" ); 503 504 // Get the modified times of the two files. 505 FileTime xmlTime = {0}, binTime = {0}; 506 Platform::getFileTimes( physXStream, NULL, &xmlTime ); 507 Platform::getFileTimes( binPhysXStream, NULL, &binTime ); 508 509 // If the binary is newer... load that. 510 if ( Platform::compareFileTimes( binTime, xmlTime ) >= 0 ) 511 _loadCollection( binPhysXStream, true ); 512 513 // If the binary failed... then load the xml. 514 if ( !collection ) 515 { 516 _loadCollection( physXStream, false ); 517 518 // If loaded... resave the xml in binary format 519 // for quicker subsequent loads. 520 if ( collection ) 521 NXU::saveCollection( collection, binPhysXStream, NXU::FT_BINARY ); 522 } 523 524 // If it still isn't loaded then we've failed! 525 if ( !collection ) 526 { 527 errorBuffer = String::ToString( "PxMultiActorDatas::preload: could not load '%s'!", physXStream ); 528 return false; 529 } 530 531 if (!shapeName || shapeName[0] == '\0') 532 { 533 errorBuffer = "PxMultiActorDatas::preload: no shape name!"; 534 return false; 535 } 536 537 shape = ResourceManager::get().load( shapeName ); 538 539 if (bool(shape) == false) 540 { 541 errorBuffer = String::ToString( "PxMultiActorData::preload: unable to load shape: %s", shapeName ); 542 return false; 543 } 544 545 // Find the client side material. 546 if ( !server && material ) 547 Sim::findObject( SimObjectId(material), material ); 548 549 // Get the ignore node indexes from the names. 550 for ( S32 i = 0; i < MaxCorrectionNodes; i++ ) 551 { 552 if( !correctionNodeNames[i] || !correctionNodeNames[i][0] ) 553 continue; 554 555 correctionNodes[i] = shape->findNode( correctionNodeNames[i] ); 556 } 557 558 // Resolve mount point node indexes 559 for ( S32 i = 0; i < NumMountPoints; i++) 560 { 561 char fullName[256]; 562 563 if ( !mountNodeNames[i] || !mountNodeNames[i][0] ) 564 { 565 dSprintf(fullName,sizeof(fullName),"mount%d",i); 566 mountPointNode[i] = shape->findNode(fullName); 567 } 568 else 569 mountPointNode[i] = shape->findNode(mountNodeNames[i]); 570 } 571 572 // Register for file change notification to reload the collection 573 if ( server ) 574 Torque::FS::AddChangeNotification( physXStream, this, &PxMultiActorData::_onFileChanged ); 575 576 return true; 577} 578 579void PxMultiActorData::_onFileChanged( const Torque::Path &path ) 580{ 581 reload(); 582} 583 584void PxMultiActorData::reload() 585{ 586 bool result = _loadCollection( physXStream, false ); 587 588 if ( !result ) 589 Con::errorf( "PxMultiActorData::reload(), _loadCollection failed..." ); 590 591 // Inform MultiActors who use this datablock to reload. 592 mReloadSignal.trigger(); 593} 594 595bool PxMultiActorData::_loadCollection( const UTF8 *path, bool isBinary ) 596{ 597 if ( collection ) 598 { 599 NXU::releaseCollection( collection ); 600 collection = NULL; 601 } 602 603 FileStream fs; 604 if ( !fs.open( path, Torque::FS::File::Read ) ) 605 return false; 606 607 // Load the data into memory. 608 U32 size = fs.getStreamSize(); 609 FrameTemp<U8> buff( size ); 610 fs.read( size, buff ); 611 612 // If the stream didn't read anything, there's a problem. 613 if ( size <= 0 ) 614 return false; 615 616 // Ok... try to load it. 617 collection = NXU::loadCollection( path, 618 isBinary ? NXU::FT_BINARY : NXU::FT_XML, 619 buff, 620 size ); 621 622 return collection != NULL; 623} 624 625 626bool PxMultiActorData::createActors( NxScene *scene, 627 NxCompartment *compartment, 628 const NxMat34 *nxMat, 629 const Point3F& scale, 630 Vector<NxActor*> *outActors, 631 Vector<NxShape*> *outShapes, 632 Vector<NxJoint*> *outJoints, 633 Vector<String> *outActorUserProperties, 634 Vector<String> *outJointUserProperties ) 635{ 636 if ( !scene ) 637 { 638 Con::errorf( "PxMultiActorData::createActor() - returned null NxScene" ); 639 return NULL; 640 } 641 642 PxMultiActor_Notify pxNotify( compartment, material, *nxMat, scale, outActorUserProperties, outJointUserProperties ); 643 644 NXU::instantiateCollection( collection, *gPhysicsSDK, scene, nxMat, &pxNotify ); 645 646 *outActors = pxNotify.getActors(); 647 *outJoints = pxNotify.getJoints(); 648 if ( outShapes ) 649 *outShapes = pxNotify.getShapes(); 650 651 if ( outActors->empty() ) 652 { 653 Con::errorf( "PxMultiActorData::createActors() - NXUStream notifier returned empty actors or joints!" ); 654 return false; 655 } 656 657 return true; 658} 659 660ConsoleDocClass( PxMultiActor, 661 662 "@brief Represents a destructible physical object simulated using PhysX.\n\n" 663 664 "Usually it is prefered to use PhysicsShape and not PxMultiActor because " 665 "it is not PhysX specific and much easier to setup.\n" 666 667 "@see PxMultiActorData.\n" 668 "@ingroup Physics" 669); 670 671IMPLEMENT_CO_NETOBJECT_V1(PxMultiActor); 672 673PxMultiActor::PxMultiActor() 674 : mShapeInstance( NULL ), 675 mRootActor( NULL ), 676 mWorld( NULL ), 677 mStartImpulse( 0, 0, 0 ), 678 mResetXfm( true ), 679 mActorScale( 0, 0, 0 ), 680 mDebugRender( false ), 681 mIsDummy( false ), 682 mBroken( false ), 683 mDataBlock( NULL ) 684{ 685 mNetFlags.set( Ghostable | ScopeAlways ); 686 687 mTypeMask |= StaticObjectType | StaticShapeObjectType; 688 689 //mUserData.setObject( this ); 690} 691 692void PxMultiActor::initPersistFields() 693{ 694 Parent::initPersistFields(); 695 696 /* 697 // We're overloading these fields from SceneObject 698 // in order to force it to go thru setTransform! 699 removeField( "position" ); 700 removeField( "rotation" ); 701 removeField( "scale" ); 702 703 addGroup( "Transform" ); 704 705 addProtectedField( "position", TypeMatrixPosition, 0, 706 &PxMultiActor::_setPositionField, 707 &PxMultiActor::_getPositionField, 708 "" ); 709 710 addProtectedField( "rotation", TypeMatrixRotation, 0, 711 &PxMultiActor::_setRotationField, 712 &PxMultiActor::_getRotationField, 713 "" ); 714 715 addField( "scale", TypePoint3F, Offset( mObjScale, PxMultiActor ) ); 716 717 endGroup( "Transform" ); 718 */ 719 720 //addGroup("Physics"); 721 // addField( "AngularDrag", TypeF32, ) 722 //endGroup("Physics"); 723 724 addGroup( "Debug" ); 725 addField( "debugRender", TypeBool, Offset( mDebugRender, PxMultiActor ), "@hide"); 726 addField( "broken", TypeBool, Offset( mBroken, PxMultiActor ), "@hide"); 727 endGroup( "Debug" ); 728 729 //addGroup("Collision"); 730 //endGroup("Collision"); 731} 732 733bool PxMultiActor::onAdd() 734{ 735 PROFILE_SCOPE( PxMultiActor_OnAdd ); 736 737 if (!Parent::onAdd() || !mDataBlock ) 738 return false; 739 740 mIsDummy = isClientObject() && PHYSICSMGR->isSinglePlayer(); //&& mDataBlock->singlePlayerOnly; 741 742 mShapeInstance = new TSShapeInstance( mDataBlock->shape, isClientObject() ); 743 744 mObjBox = mDataBlock->shape->bounds; 745 resetWorldBox(); 746 747 addToScene(); 748 749 String worldName = isServerObject() ? "server" : "client"; 750 751 // SinglePlayer objects only have server-side physics representations. 752 if ( mIsDummy ) 753 worldName = "server"; 754 755 mWorld = dynamic_cast<PxWorld*>( PHYSICSMGR->getWorld( worldName ) ); 756 if ( !mWorld || !mWorld->getScene() ) 757 { 758 Con::errorf( "PxMultiActor::onAdd() - PhysXWorld not initialized!" ); 759 return false; 760 } 761 762 applyWarp( getTransform(), true, false ); 763 mResetXfm = getTransform(); 764 765 if ( !_createActors( getTransform() ) ) 766 { 767 Con::errorf( "PxMultiActor::onAdd(), _createActors failed" ); 768 return false; 769 } 770 771 if ( !mIsDummy ) 772 mDataBlock->mReloadSignal.notify( this, &PxMultiActor::onFileNotify ); 773 774 // If the editor is on... let it know! 775 //if ( gEditingMission ) 776 //onEditorEnable(); // TODO: Fix this up. 777 778 PhysicsPlugin::getPhysicsResetSignal().notify( this, &PxMultiActor::onPhysicsReset, 1050.0f ); 779 780 setAllBroken( false ); 781 782 if ( isServerObject() ) 783 scriptOnAdd(); 784 785 return true; 786} 787 788 789void PxMultiActor::onRemove() 790{ 791 removeFromScene(); 792 793 _destroyActors(); 794 mWorld = NULL; 795 796 SAFE_DELETE( mShapeInstance ); 797 798 PhysicsPlugin::getPhysicsResetSignal().remove( this, &PxMultiActor::onPhysicsReset ); 799 800 if ( !mIsDummy && mDataBlock ) 801 mDataBlock->mReloadSignal.remove( this, &PxMultiActor::onFileNotify ); 802 803 Parent::onRemove(); 804} 805 806void PxMultiActor::_destroyActors() 807{ 808 // Dummies don't have physics objects. 809 if ( mIsDummy || !mWorld ) 810 return; 811 812 mWorld->releaseWriteLock(); 813 814 // Clear the root actor. 815 mRootActor = NULL; 816 817 // Clear the relative transforms. 818 //mRelXfms.clear(); 819 820 // The shapes are owned by the actors, so 821 // we just need to clear them. 822 mShapes.clear(); 823 824 // Release the joints first. 825 for( S32 i = 0; i < mJoints.size(); i++ ) 826 { 827 NxJoint *joint = mJoints[i]; 828 829 if ( !joint ) 830 continue; 831 832 // We allocate per joint userData and we must free it. 833 PxUserData *jointData = PxUserData::getData( *joint ); 834 if ( jointData ) 835 delete jointData; 836 837 mWorld->releaseJoint( *joint ); 838 } 839 mJoints.clear(); 840 841 // Now release the actors. 842 for( S32 i = 0; i < mActors.size(); i++ ) 843 { 844 NxActor *actor = mActors[i]; 845 846 PxUserData *actorData = PxUserData::getData( *actor ); 847 if ( actorData ) 848 delete actorData; 849 850 if ( actor ) 851 mWorld->releaseActor( *actor ); 852 } 853 mActors.clear(); 854} 855 856bool PxMultiActor::_createActors( const MatrixF &xfm ) 857{ 858 if ( mIsDummy ) 859 { 860 // Dummies don't have physics objects, but 861 // they do handle actor deltas. 862 863 PxMultiActor *serverObj = static_cast<PxMultiActor*>( mServerObject.getObject() ); 864 mActorDeltas.setSize( serverObj->mActors.size() ); 865 dMemset( mActorDeltas.address(), 0, mActorDeltas.memSize() ); 866 867 return true; 868 } 869 870 NxMat34 nxMat; 871 nxMat.setRowMajor44( xfm ); 872 873 // Store the scale for comparison in setScale(). 874 mActorScale = getScale(); 875 876 // Release the write lock so we can create actors. 877 mWorld->releaseWriteLock(); 878 879 Vector<String> actorUserProperties; 880 Vector<String> jointUserProperties; 881 bool created = mDataBlock->createActors( mWorld->getScene(), 882 NULL, 883 &nxMat, 884 mActorScale, 885 &mActors, 886 &mShapes, 887 &mJoints, 888 &actorUserProperties, 889 &jointUserProperties ); 890 891 // Debug output... 892 //for ( U32 i = 0; i < mJoints.size(); i++ ) 893 // Con::printf( "Joint0 name: '%s'", mJoints[i]->getName() ); 894 //for ( U32 i = 0; i < actorUserProperties.size(); i++ ) 895 //Con::printf( "actor%i UserProperties: '%s'", i, actorUserProperties[i].c_str() ); 896 //for ( U32 i = 0; i < jointUserProperties.size(); i++ ) 897 // Con::printf( "joint%i UserProperties: '%s'", i, jointUserProperties[i].c_str() ); 898 899 if ( !created ) 900 { 901 Con::errorf( "PxMultiActor::_createActors() - failed!" ); 902 return false; 903 } 904 905 // Make the first actor the root actor by default, but 906 // if we have a kinematic actor then use that. 907 mRootActor = mActors[0]; 908 for ( S32 i = 0; i < mActors.size(); i++ ) 909 { 910 if ( mActors[i]->readBodyFlag( NX_BF_KINEMATIC ) ) 911 { 912 mRootActor = mActors[i]; 913 break; 914 } 915 } 916 917 mDelta.pos = mDelta.lastPos = getPosition(); 918 mDelta.rot = mDelta.lastRot = getTransform(); 919 920 bool *usedActors = new bool[mActors.size()]; 921 dMemset( usedActors, 0, sizeof(bool) * mActors.size() ); 922 923 TSShape *shape = mShapeInstance->getShape(); 924 925 // Should already be done when actors are destroyed. 926 mMappedActors.clear(); 927 Vector<String> mappedActorProperties; 928 929 // Remap the actors to the shape instance's bone indices. 930 for( S32 i = 0; i < mShapeInstance->mNodeTransforms.size(); i++ ) 931 { 932 if ( !shape ) 933 break; 934 935 UTF8 comparisonName[260] = { 0 }; 936 NxActor *actor = NULL; 937 NxActor *pushActor = NULL; 938 String actorProperties; 939 940 S32 nodeNameIdx = shape->nodes[i].nameIndex; 941 const UTF8 *nodeName = shape->getName( nodeNameIdx ); 942 943 S32 dl = -1; 944 dStrcpy( comparisonName, String::GetTrailingNumber( nodeName, dl ) ); //, ext - nodeName ); 945 dSprintf( comparisonName, sizeof( comparisonName ), "%s_pxactor", comparisonName ); 946 947 //String test( nodeName ); 948 //AssertFatal( test.find("gableone",0,String::NoCase) == String::NPos, "found it" ); 949 950 // If we find an actor that corresponds to this node we will 951 // push it back into the remappedActors vector, otherwise 952 // we will push back NULL. 953 for ( S32 j = 0; j < mActors.size(); j++ ) 954 { 955 actor = mActors[j]; 956 const UTF8 *actorName = actor->getName(); 957 958 if ( dStricmp( comparisonName, actorName ) == 0 ) 959 { 960 pushActor = actor; 961 actorProperties = actorUserProperties[j]; 962 usedActors[j] = true; 963 break; 964 } 965 } 966 967 mMappedActors.push_back( pushActor ); 968 mappedActorProperties.push_back( actorProperties ); 969 if ( !pushActor ) 970 dl = -1; 971 mMappedActorDL.push_back( dl ); 972 973 // Increase the sleep tolerance. 974 if ( pushActor ) 975 { 976 //pushActor->raiseBodyFlag( NX_BF_ENERGY_SLEEP_TEST ); 977 //pushActor->setSleepEnergyThreshold( 2 ); 978 //pushActor->userData = NULL; 979 } 980 } 981 982 // Delete any unused/orphaned actors. 983 for ( S32 i = 0; i < mActors.size(); i++ ) 984 { 985 if ( usedActors[i] ) 986 continue; 987 988 NxActor *actor = mActors[i]; 989 990 Con::errorf( "PxMultiActor::_createActors() - Orphan NxActor - '%s'!", actor->getName() ); 991 992 if ( actor == mRootActor ) 993 { 994 Con::errorf( "PxMultiActor::_createActors() - root actor (%s) was orphan, cannot continue.", actor->getName() ); 995 return false; 996 } 997 998 // Remove references to shapes of the deleted actor. 999 for ( S32 i = 0; i < mShapes.size(); i++ ) 1000 { 1001 if ( &(mShapes[i]->getActor()) == actor ) 1002 { 1003 mShapes.erase_fast(i); 1004 i--; 1005 } 1006 } 1007 1008 mWorld->releaseActor( *actor ); 1009 } 1010 1011 // Done with this helper. 1012 delete [] usedActors; 1013 1014 // Repopulate mActors with one entry per real actor we own. 1015 mActors.clear(); 1016 mMappedToActorIndex.clear(); 1017 actorUserProperties.clear(); 1018 for ( S32 i = 0; i < mMappedActors.size(); i++ ) 1019 { 1020 S32 index = -1; 1021 if ( mMappedActors[i] ) 1022 { 1023 index = mActors.push_back_unique( mMappedActors[i] ); 1024 while ( index >= actorUserProperties.size() ) 1025 actorUserProperties.push_back( String::EmptyString ); 1026 actorUserProperties[index] = mappedActorProperties[i]; 1027 } 1028 mMappedToActorIndex.push_back( index ); 1029 } 1030 1031 if ( mActors.size() == 0 ) 1032 { 1033 Con::errorf( "PxMultiActor::_createActors, got zero actors! Were all actors orphans?" ); 1034 return false; 1035 } 1036 1037 // Initialize the actor deltas. 1038 mActorDeltas.setSize( mActors.size() ); 1039 dMemset( mActorDeltas.address(), 0, mActorDeltas.memSize() ); 1040 1041 // Assign user data for actors. 1042 for ( U32 i = 0; i < mActors.size(); i++ ) 1043 { 1044 NxActor *actor = mActors[i]; 1045 if ( !actor ) 1046 continue; 1047 1048 actor->userData = _createActorUserData( actor, actorUserProperties[i] ); 1049 } 1050 1051 //NxActor *actor1; 1052 //NxActor *actor2; 1053 //PxUserData *pUserData; 1054 1055 // Allocate user data for joints. 1056 for ( U32 i = 0; i < mJoints.size(); i++ ) 1057 { 1058 NxJoint *joint = mJoints[i]; 1059 if ( !joint ) 1060 continue; 1061 1062 joint->userData = _createJointUserData( joint, jointUserProperties[i] ); 1063 1064 /* 1065 // Set actors attached to joints as not-pushable (by the player). 1066 joint->getActors( &actor1, &actor2 ); 1067 if ( actor1 ) 1068 { 1069 pUserData = PxUserData::getData( *actor1 ); 1070 if ( pUserData ) 1071 pUserData->mCanPush = false; 1072 } 1073 if ( actor2 ) 1074 { 1075 pUserData = PxUserData::getData( *actor2 ); 1076 if ( pUserData ) 1077 pUserData->mCanPush = false; 1078 } 1079 */ 1080 } 1081 1082 // Set actors and meshes to the unbroken state. 1083 setAllBroken( false ); 1084 1085 return true; 1086} 1087 1088PxUserData* PxMultiActor::_createActorUserData( NxActor *actor, String &userProperties ) 1089{ 1090 PxUserData *actorData = new PxUserData(); 1091 actorData->setObject( this ); 1092 1093 // We use this for saving relative xfms for 'broken' actors. 1094 NxMat34 actorPose = actor->getGlobalPose(); 1095 NxMat34 actorSpaceXfm; 1096 actorPose.getInverse( actorSpaceXfm ); 1097 1098 const String actorName( actor->getName() ); 1099 1100 static const String showStr( "PxBrokenShow" ); 1101 static const String hideStr( "PxBrokenHide" ); 1102 1103 // 3DSMax saves out double newlines, replace them with one. 1104 userProperties.replace( "\r\n", "\n" ); 1105 1106 U32 propertyCount = StringUnit::getUnitCount( userProperties, "\n" ); 1107 for ( U32 i = 0; i < propertyCount; i++ ) 1108 { 1109 String propertyStr = StringUnit::getUnit( userProperties, i, "\n" ); 1110 U32 wordCount = StringUnit::getUnitCount( propertyStr, "=" ); 1111 1112 if ( wordCount == 0 ) 1113 { 1114 // We sometimes get empty lines between properties, 1115 // which doesn't break anything. 1116 continue; 1117 } 1118 1119 if ( wordCount != 2 ) 1120 { 1121 Con::warnf( "PxMultiActor::_createActorUserData, malformed UserProperty string (%s) for actor (%s)", propertyStr.c_str(), actorName.c_str() ); 1122 continue; 1123 } 1124 1125 String propertyName = StringUnit::getUnit( propertyStr, 0, "=" ); 1126 String propertyValue = StringUnit::getUnit( propertyStr, 1, "=" ); 1127 1128 Vector<NxActor*> *dstVector = NULL; 1129 if ( propertyName.equal( showStr, String::NoCase ) ) 1130 dstVector = &actorData->mBrokenActors; 1131 else if ( propertyName.equal( hideStr, String::NoCase ) ) 1132 dstVector = &actorData->mUnbrokenActors; 1133 1134 if ( !dstVector ) 1135 continue; 1136 1137 U32 valueCount = StringUnit::getUnitCount( propertyValue, "," ); 1138 for ( U32 j = 0; j < valueCount; j++ ) 1139 { 1140 String val = StringUnit::getUnit( propertyValue, j, "," ); 1141 1142 NxActor *pActor = _findActor( val ); 1143 if ( !pActor ) 1144 Con::warnf( "PxMultiActor::_createActorUserData, actor (%s) was not found when parsing UserProperties for actor (%s)", val.c_str(), actorName.c_str() ); 1145 else 1146 { 1147 dstVector->push_back( pActor ); 1148 1149 if ( dstVector == &actorData->mBrokenActors ) 1150 { 1151 NxMat34 relXfm = pActor->getGlobalPose(); 1152 relXfm.multiply( relXfm, actorSpaceXfm ); 1153 actorData->mRelXfm.push_back( relXfm ); 1154 } 1155 } 1156 } 1157 } 1158 1159 // Only add a contact signal to this actor if 1160 // we have objects we can break. 1161 if ( actorData->mBrokenActors.size() > 0 && 1162 mDataBlock->breakForce > 0.0f ) 1163 { 1164 actor->setContactReportFlags( NX_NOTIFY_ON_START_TOUCH_FORCE_THRESHOLD | NX_NOTIFY_FORCES ); 1165 actor->setContactReportThreshold( mDataBlock->breakForce ); 1166 actorData->getContactSignal().notify( this, &PxMultiActor::_onContact ); 1167 } 1168 1169 return actorData; 1170} 1171 1172PxUserData* PxMultiActor::_createJointUserData( NxJoint *joint, String &userProperties ) 1173{ 1174 PxUserData *jointData = new PxUserData(); 1175 jointData->setObject( this ); 1176 1177 // We use this for saving relative xfms for 'broken' actors. 1178 NxActor *actor0; 1179 NxActor *actor1; 1180 joint->getActors( &actor0, &actor1 ); 1181 NxMat34 actorPose = actor0->getGlobalPose(); 1182 NxMat34 actorSpaceXfm; 1183 actorPose.getInverse( actorSpaceXfm ); 1184 1185 // The PxMultiActor will live longer than the joint 1186 // so this notify shouldn't ever need to be removed. Although if someone 1187 // other than this multiactor were to register for this notify and their 1188 // lifetime could be shorter, then 'they' might have to. 1189 jointData->getOnJointBreakSignal().notify( this, &PxMultiActor::_onJointBreak ); 1190 1191 // JCFHACK: put this in userProperties too. 1192 Sim::findObject( "JointBreakEmitter", jointData->mParticleEmitterData ); 1193 1194 String showStr( "PxBrokenShow" ); 1195 String hideStr( "PxBrokenHide" ); 1196 1197 // Max saves out double newlines, replace them with one. 1198 userProperties.replace( "\r\n", "\n" ); 1199 1200 U32 propertyCount = StringUnit::getUnitCount( userProperties, "\n" ); 1201 for ( U32 i = 0; i < propertyCount; i++ ) 1202 { 1203 String propertyStr = StringUnit::getUnit( userProperties, i, "\n" ); 1204 U32 wordCount = StringUnit::getUnitCount( propertyStr, "=" ); 1205 1206 if ( wordCount == 0 ) 1207 { 1208 // We sometimes get empty lines between properties, 1209 // which doesn't break anything. 1210 continue; 1211 } 1212 1213 if ( wordCount != 2 ) 1214 { 1215 Con::warnf( "PxMultiActor::_createJointUserData, malformed UserProperty string (%s) for joint (%s)", propertyStr.c_str(), joint->getName() ); 1216 continue; 1217 } 1218 1219 String propertyName = StringUnit::getUnit( propertyStr, 0, "=" ); 1220 String propertyValue = StringUnit::getUnit( propertyStr, 1, "=" ); 1221 1222 Vector<NxActor*> *dstVector = NULL; 1223 if ( propertyName.equal( showStr, String::NoCase ) ) 1224 dstVector = &jointData->mBrokenActors; 1225 else if ( propertyName.equal( hideStr, String::NoCase ) ) 1226 dstVector = &jointData->mUnbrokenActors; 1227 1228 if ( !dstVector ) 1229 continue; 1230 1231 U32 valueCount = StringUnit::getUnitCount( propertyValue, "," ); 1232 for ( U32 j = 0; j < valueCount; j++ ) 1233 { 1234 String val = StringUnit::getUnit( propertyValue, j, "," ); 1235 1236 NxActor *pActor = _findActor( val ); 1237 if ( !pActor ) 1238 Con::warnf( "PxMultiActor::_createJointUserData, actor (%s) was not found when parsing UserProperties for joint (%s)", val.c_str(), joint->getName() ); 1239 else 1240 { 1241 dstVector->push_back( pActor ); 1242 1243 if ( dstVector == &jointData->mBrokenActors ) 1244 { 1245 NxMat34 relXfm = pActor->getGlobalPose(); 1246 relXfm.multiply( relXfm, actorSpaceXfm ); 1247 jointData->mRelXfm.push_back( relXfm ); 1248 } 1249 } 1250 } 1251 } 1252 1253 return jointData; 1254} 1255 1256NxActor* PxMultiActor::_findActor( const String &actorName ) const 1257{ 1258 for ( U32 i = 0; i < mActors.size(); i++ ) 1259 { 1260 NxActor *actor = mActors[i]; 1261 if ( !actor ) 1262 continue; 1263 1264 if ( dStricmp( actor->getName(), actorName ) == 0 ) 1265 return actor; 1266 } 1267 1268 return NULL; 1269} 1270 1271String PxMultiActor::_getMeshName( const NxActor *actor ) const 1272{ 1273 String meshName = actor->getName(); 1274 meshName.replace( "_pxactor", "" ); 1275 //meshName = StringUnit::getUnit( meshName, 0, "_" ); 1276 return meshName; 1277} 1278 1279bool PxMultiActor::onNewDataBlock( GameBaseData *dptr, bool reload ) 1280{ 1281 mDataBlock = dynamic_cast<PxMultiActorData*>(dptr); 1282 1283 if ( !mDataBlock || !Parent::onNewDataBlock( dptr, reload ) ) 1284 return false; 1285 1286 // JCF: if we supported it, we would recalculate the value of mIsDummy now, 1287 // but that would really hose everything since an object that was a dummy 1288 // wouldn't have any actors and would need to create them, etc... 1289 1290 scriptOnNewDataBlock(); 1291 1292 return true; 1293} 1294 1295void PxMultiActor::inspectPostApply() 1296{ 1297 // Make sure we call the parent... else 1298 // we won't get transform and scale updates! 1299 Parent::inspectPostApply(); 1300 1301 //setMaskBits( LightMask ); 1302 setMaskBits( UpdateMask ); 1303} 1304 1305void PxMultiActor::onStaticModified( const char *slotName, const char *newValue ) 1306{ 1307 if ( isProperlyAdded() && dStricmp( slotName, "broken" ) == 0 ) 1308 setAllBroken( dAtob(newValue) ); 1309} 1310 1311void PxMultiActor::onDeleteNotify( SimObject *obj ) 1312{ 1313 Parent::onDeleteNotify(obj); 1314 if ( obj == mMount.object ) 1315 unmount(); 1316} 1317 1318void PxMultiActor::onFileNotify() 1319{ 1320 // Destroy the existing actors and recreate them... 1321 1322 mWorld->getPhysicsResults(); 1323 _destroyActors(); 1324 _createActors( mResetXfm ); 1325} 1326 1327void PxMultiActor::onPhysicsReset( PhysicsResetEvent reset ) 1328{ 1329 // Dummies don't create or destroy actors, they just reuse the 1330 // server object's ones. 1331 if ( mIsDummy ) 1332 return; 1333 1334 // Store the reset transform for later use. 1335 if ( reset == PhysicsResetEvent_Store ) 1336 { 1337 mRootActor->getGlobalPose().getRowMajor44( mResetXfm ); 1338 } 1339 else if ( reset == PhysicsResetEvent_Restore ) 1340 { 1341 // Destroy the existing actors and recreate them to 1342 // ensure they are in the proper mission startup state. 1343 mWorld->getPhysicsResults(); 1344 1345 _destroyActors(); 1346 _createActors( mResetXfm ); 1347 } 1348 1349 for ( U32 i = 0; i < mActors.size(); i++ ) 1350 { 1351 if ( !mActors[i] ) 1352 continue; 1353 1354 mActors[i]->wakeUp(); 1355 } 1356} 1357 1358void PxMultiActor::prepRenderImage( SceneRenderState *state ) 1359{ 1360 PROFILE_SCOPE( PxMultiActor_PrepRenderImage ); 1361 1362 if ( !mShapeInstance ) 1363 return; 1364 1365 Point3F cameraOffset; 1366 getTransform().getColumn(3,&cameraOffset); 1367 cameraOffset -= state->getDiffuseCameraPosition(); 1368 F32 dist = cameraOffset.len(); 1369 if ( dist < 0.01f ) 1370 dist = 0.01f; 1371 1372 F32 invScale = (1.0f/getMax(getMax(mObjScale.x,mObjScale.y),mObjScale.z)); 1373 1374 S32 dl = mShapeInstance->setDetailFromDistance( state, dist * invScale ); 1375 if ( dl < 0 ) 1376 return; 1377 1378 GFXTransformSaver saver; 1379 1380 // Set up our TS render state here. 1381 TSRenderState rdata; 1382 rdata.setSceneState( state ); 1383 1384 // We might have some forward lit materials 1385 // so pass down a query to gather lights. 1386 LightQuery query; 1387 query.init( getWorldSphere() ); 1388 rdata.setLightQuery( &query ); 1389 1390 MatrixF mat = getRenderTransform(); 1391 mat.scale( getScale() ); 1392 GFX->setWorldMatrix( mat ); 1393 1394 if ( mDebugRender || Con::getBoolVariable( "$PxDebug::render", false ) ) 1395 { 1396 ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>(); 1397 ri->renderDelegate.bind( this, &PxMultiActor::_debugRender ); 1398 ri->type = RenderPassManager::RIT_Object; 1399 state->getRenderPass()->addInst( ri ); 1400 } 1401 else 1402 mShapeInstance->render( rdata ); 1403} 1404 1405void PxMultiActor::_debugRender( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat ) 1406{ 1407 if ( mShapeInstance ) 1408 { 1409 GFXTransformSaver saver; 1410 1411 MatrixF mat = getRenderTransform(); 1412 mat.scale( mObjScale ); 1413 GFX->multWorld( mat ); 1414 1415 //mShapeInstance->renderDebugNodes(); 1416 } 1417 1418 Vector<NxActor*> *actors = &mActors; 1419 if ( mIsDummy ) 1420 { 1421 PxMultiActor *serverObj = static_cast<PxMultiActor*>( mServerObject.getObject() ); 1422 if ( serverObj ) 1423 actors = &serverObj->mActors; 1424 } 1425 1426 if ( !actors ) 1427 return; 1428 1429 for ( U32 i = 0; i < actors->size(); i++ ) 1430 { 1431 NxActor *pActor = (*actors)[i]; 1432 if ( !pActor ) 1433 continue; 1434 1435 PxUtils::drawActor( pActor ); 1436 } 1437} 1438 1439void PxMultiActor::_onJointBreak( NxReal breakForce, NxJoint &brokenJoint ) 1440{ 1441 // Dummies do not have physics objects 1442 // and shouldn't receive this callback. 1443 if ( mIsDummy ) 1444 return; 1445 1446 NxActor *actor0 = NULL; 1447 NxActor *actor1 = NULL; 1448 brokenJoint.getActors( &actor0, &actor1 ); 1449 NxMat34 parentPose = actor0->getGlobalPose(); 1450 1451 Point3F jointPos = pxCast<Point3F>( brokenJoint.getGlobalAnchor() ); 1452 1453 PxUserData *jointData = PxUserData::getData( brokenJoint ); 1454 setBroken( parentPose, NxVec3( 0.0f ), jointData, true ); 1455 1456 // NOTE: We do not NULL the joint in the list, 1457 // or release it here, as we allow it to be released 1458 // by the _destroyActors function on a reset or destruction 1459 // of the PxMultiActor. 1460} 1461 1462void PxMultiActor::_onContact( PhysicsUserData *us, 1463 PhysicsUserData *them, 1464 const Point3F &hitPoint, 1465 const Point3F &hitForce ) 1466{ 1467 PxUserData *data = (PxUserData*)us; 1468 if ( data && 1469 !data->mIsBroken && 1470 hitForce.len() > mDataBlock->breakForce ) 1471 setAllBroken( true ); 1472} 1473 1474U32 PxMultiActor::packUpdate(NetConnection *con, U32 mask, BitStream *stream) 1475{ 1476 U32 retMask = Parent::packUpdate(con, mask, stream); 1477 1478 stream->writeFlag( mDebugRender ); 1479 1480 stream->writeFlag( mask & SleepMask ); 1481 1482 if ( stream->writeFlag( mask & WarpMask ) ) 1483 { 1484 stream->writeAffineTransform( getTransform() ); 1485 } 1486 else if ( stream->writeFlag( mask & MoveMask ) ) 1487 { 1488 /* 1489 stream->writeAffineTransform( getTransform() ); 1490 1491 NxActor *actor = mActors[ mDataBlock->correctionNodes[0] ]; 1492 1493 const NxVec3& linVel = actor->getLinearVelocity(); 1494 stream->write( linVel.x ); 1495 stream->write( linVel.y ); 1496 stream->write( linVel.z ); 1497 */ 1498 } 1499 1500 // This internally uses the mask passed to it. 1501 if ( mLightPlugin ) 1502 retMask |= mLightPlugin->packUpdate( this, LightMask, con, mask, stream ); 1503 1504 return retMask; 1505} 1506 1507 1508void PxMultiActor::unpackUpdate(NetConnection *con, BitStream *stream) 1509{ 1510 Parent::unpackUpdate(con, stream); 1511 1512 mDebugRender = stream->readFlag(); 1513 1514 if ( stream->readFlag() ) // SleepMask 1515 { 1516 for ( S32 i = 0; i < mActors.size(); i++ ) 1517 { 1518 NxActor *actor = mActors[i]; 1519 1520 if ( !actor ) 1521 continue; 1522 1523 if ( actor ) 1524 actor->putToSleep(); 1525 } 1526 } 1527 1528 if ( stream->readFlag() ) // WarpMask 1529 { 1530 // If we set a warp mask, 1531 // we need to instantly move 1532 // the actor to the new position 1533 // without applying any corrections. 1534 MatrixF mat; 1535 stream->readAffineTransform( &mat ); 1536 1537 applyWarp( mat, true, false ); 1538 } 1539 else if ( stream->readFlag() ) // MoveMask 1540 { 1541 /* 1542 MatrixF mat; 1543 stream->readAffineTransform( &mat ); 1544 1545 NxVec3 linVel, angVel; 1546 stream->read( &linVel.x ); 1547 stream->read( &linVel.y ); 1548 stream->read( &linVel.z ); 1549 1550 applyCorrection( mat, linVel, angVel ); 1551 */ 1552 } 1553/* 1554 if ( stream->readFlag() ) // ImpulseMask 1555 { 1556 // TODO : Set up correction nodes. 1557 1558 NxVec3 linVel; 1559 stream->read( &linVel.x ); 1560 stream->read( &linVel.y ); 1561 stream->read( &linVel.z ); 1562 1563 NxActor *actor = mActors[ mDataBlock->correctionNodes[0] ]; 1564 1565 if ( actor ) 1566 { 1567 mWorld->releaseWriteLock(); 1568 actor->setLinearVelocity( linVel ); 1569 mStartImpulse.zero(); 1570 } 1571 else 1572 mStartImpulse.set( linVel.x, linVel.y, linVel.z ); 1573 } 1574*/ 1575 if ( mLightPlugin ) 1576 mLightPlugin->unpackUpdate( this, con, stream ); 1577} 1578 1579void PxMultiActor::setScale( const VectorF& scale ) 1580{ 1581 if ( scale == getScale() ) 1582 return; 1583 1584 // This is so that the level 1585 // designer can change the scale 1586 // of a PhysXSingleActor in the editor 1587 // and have the PhysX representation updated properly. 1588 1589 // First we call the parent's setScale 1590 // so that the ScaleMask can be set. 1591 Parent::setScale( scale ); 1592 1593 // Check to see if the scale has really changed. 1594 if ( !isProperlyAdded() || mActorScale.equal( scale ) ) 1595 return; 1596 1597 // Recreate the physics actors. 1598 _destroyActors(); 1599 _createActors( getTransform() ); 1600} 1601 1602void PxMultiActor::applyWarp( const MatrixF& newMat, bool interpRender, bool sweep ) 1603{ 1604 // Do we have actors to move? 1605 if ( mRootActor ) 1606 { 1607 // Get ready to change the physics state. 1608 mWorld->releaseWriteLock(); 1609 1610 /// Convert the new transform to nx. 1611 NxMat34 destXfm; 1612 destXfm.setRowMajor44( newMat ); 1613 1614 // Get the inverse of the root actor transform 1615 // so we can move all the actors relative to it. 1616 NxMat34 rootInverseXfm; 1617 mRootActor->getGlobalPose().getInverse( rootInverseXfm ); 1618 1619 // Offset all the actors. 1620 MatrixF tMat; 1621 NxMat34 newXfm, relXfm; 1622 for ( S32 i = 0; i < mActors.size(); i++ ) 1623 { 1624 NxActor *actor = mActors[i]; 1625 if ( !actor ) 1626 continue; 1627 1628 const bool isKinematic = actor->readBodyFlag( NX_BF_KINEMATIC ); 1629 1630 // Stop any velocity on it. 1631 if ( !isKinematic ) 1632 { 1633 actor->setAngularVelocity( NxVec3( 0.0f ) ); 1634 actor->setLinearVelocity( NxVec3( 0.0f ) ); 1635 } 1636 1637 // Get the transform relative to the current root. 1638 relXfm.multiply( actor->getGlobalPose(), rootInverseXfm ); 1639 1640 /* 1641 if ( sweep ) 1642 { 1643 actor->getGl obalPose().getRowMajor44( mResetPos[i] ); 1644 sweepTest( &newMat ); 1645 } 1646 */ 1647 1648 // 1649 newXfm.multiply( relXfm, destXfm ); 1650 //if ( isKinematic ) 1651 //actor->moveGlobalPose( newXfm ); 1652 //else 1653 actor->setGlobalPose( newXfm ); 1654 1655 // Reset the delta. 1656 Delta &delta = mActorDeltas[i]; 1657 delta.pos = pxCast<Point3F>( newXfm.t ); 1658 newXfm.getRowMajor44( tMat ); 1659 delta.rot.set( tMat ); 1660 1661 if ( !interpRender ) 1662 { 1663 mActorDeltas[i].lastPos = mActorDeltas[i].pos; 1664 mActorDeltas[i].lastRot = mActorDeltas[i].rot; 1665 } 1666 } 1667 } 1668 1669 Parent::setTransform( newMat ); 1670 1671 mDelta.pos = newMat.getPosition(); 1672 mDelta.rot = newMat; 1673 1674 if ( !interpRender ) 1675 { 1676 mDelta.lastPos = mDelta.pos; 1677 mDelta.lastRot = mDelta.rot; 1678 } 1679} 1680 1681/* 1682bool PxMultiActor::_setPositionField( void *obj, const char *data ) 1683{ 1684 PxMultiActor *object = reinterpret_cast<PxMultiActor*>( obj ); 1685 1686 MatrixF transform( object->getTransform() ); 1687 Con::setData( TypeMatrixPosition, &transform, 0, 1, &data ); 1688 1689 object->setTransform( transform ); 1690 1691 return false; 1692} 1693 1694const char* PxMultiActor::_getPositionField( void *obj, const char *data ) 1695{ 1696 PxMultiActor *object = reinterpret_cast<PxMultiActor*>( obj ); 1697 return Con::getData( TypeMatrixPosition, 1698 &object->mObjToWorld, 1699 0 ); 1700} 1701 1702bool PxMultiActor::_setRotationField( void *obj, const char *data ) 1703{ 1704 PxMultiActor *object = reinterpret_cast<PxMultiActor*>( obj ); 1705 1706 MatrixF transform( object->getTransform() ); 1707 Con::setData( TypeMatrixRotation, &transform, 0, 1, &data ); 1708 1709 object->setTransform( transform ); 1710 1711 return false; 1712} 1713 1714const char* PxMultiActor::_getRotationField( void *obj, const char *data ) 1715{ 1716 PxMultiActor *object = reinterpret_cast<PxMultiActor*>( obj ); 1717 return Con::getData( TypeMatrixRotation, 1718 &object->mObjToWorld, 1719 0 ); 1720} 1721*/ 1722 1723void PxMultiActor::setTransform( const MatrixF& mat ) 1724{ 1725 applyWarp( mat, false, true ); 1726 setMaskBits( WarpMask ); 1727} 1728 1729void PxMultiActor::mountObject( SceneObject *obj, U32 node ) 1730{ 1731 if (obj->getObjectMount()) 1732 obj->unmount(); 1733 1734 obj->mountObject( this, (node >= 0 && node < PxMultiActorData::NumMountPoints) ? node: 0 ); 1735} 1736 1737 1738void PxMultiActor::unmountObject( SceneObject *obj ) 1739{ 1740 obj->unmountObject( this ); 1741} 1742 1743bool PxMultiActor::_getNodeTransform( U32 nodeIdx, MatrixF *outXfm ) 1744{ 1745 if ( !mShapeInstance ) 1746 return false; 1747 1748 PxMultiActor *actorOwner = this; 1749 if ( mIsDummy ) 1750 { 1751 actorOwner = static_cast<PxMultiActor*>( mServerObject.getObject() ); 1752 if ( !actorOwner ) 1753 return false; 1754 } 1755 1756 TSShape *shape = mShapeInstance->getShape(); 1757 String nodeName = shape->getNodeName( nodeIdx ); 1758 1759 NxActor *pActor = NULL; 1760 UTF8 comparisonName[260] = { 0 }; 1761 S32 dummy = -1; 1762 1763 // Convert the passed node name to a valid actor name. 1764 dStrcpy( comparisonName, String::GetTrailingNumber( nodeName, dummy ) ); 1765 dSprintf( comparisonName, sizeof( comparisonName ), "%s_pxactor", comparisonName ); 1766 1767 // If we have an actor with that name, we are done. 1768 pActor = actorOwner->_findActor( comparisonName ); 1769 if ( pActor ) 1770 { 1771 pActor->getGlobalPose().getRowMajor44( *outXfm ); 1772 return true; 1773 } 1774 1775 // Check if the parent node has an actor... 1776 1777 S32 parentIdx = shape->nodes[nodeIdx].parentIndex; 1778 if ( parentIdx == -1 ) 1779 return false; 1780 1781 const String &parentName = shape->getNodeName( parentIdx ); 1782 dStrcpy( comparisonName, String::GetTrailingNumber( parentName, dummy ) ); 1783 dSprintf( comparisonName, sizeof( comparisonName ), "%s_pxactor", comparisonName ); 1784 1785 pActor = actorOwner->_findActor( comparisonName ); 1786 if ( !pActor ) 1787 return false; 1788 1789 MatrixF actorMat; 1790 pActor->getGlobalPose().getRowMajor44( actorMat ); 1791 1792 MatrixF nmat; 1793 QuatF q; 1794 TSTransform::setMatrix( shape->defaultRotations[nodeIdx].getQuatF(&q),shape->defaultTranslations[nodeIdx],&nmat); 1795 *outXfm->mul( actorMat, nmat ); 1796 1797 return true; 1798} 1799 1800void PxMultiActor::getMountTransform(U32 mountPoint,MatrixF* mat) 1801{ 1802 // Returns mount point to world space transform 1803 if (mountPoint < PxMultiActorData::NumMountPoints) { 1804 S32 ni = mDataBlock->mountPointNode[mountPoint]; 1805 if (ni != -1) { 1806 if ( _getNodeTransform( ni, mat ) ) 1807 return; 1808 } 1809 } 1810 *mat = mObjToWorld; 1811} 1812 1813void PxMultiActor::getRenderMountTransform(U32 mountPoint,MatrixF* mat) 1814{ 1815 // Returns mount point to world space transform 1816 if (mountPoint < PxMultiActorData::NumMountPoints) { 1817 S32 ni = mDataBlock->mountPointNode[mountPoint]; 1818 if (ni != -1) { 1819 if ( _getNodeTransform( ni, mat ) ) 1820 return; 1821 } 1822 } 1823 *mat = getRenderTransform(); 1824} 1825 1826void PxMultiActor::processTick( const Move *move ) 1827{ 1828 PROFILE_SCOPE( PxMultiActor_ProcessTick ); 1829 1830 // Set the last pos/rot to the 1831 // values of the previous tick for interpolateTick. 1832 mDelta.lastPos = mDelta.pos; 1833 mDelta.lastRot = mDelta.rot; 1834 1835 /* 1836 NxActor *corrActor = mActors[ mDataBlock->correctionNodes[0] ]; 1837 1838 if ( corrActor->isSleeping() || corrActor->readBodyFlag( NX_BF_FROZEN ) ) 1839 { 1840 if ( !mSleepingLastTick ) 1841 setMaskBits( WarpMask | SleepMask ); 1842 1843 mSleepingLastTick = true; 1844 1845 // HACK! Refactor sleeping so that we don't 1846 // sleep when only one correction actor does. 1847 _updateBounds(); 1848 1849 return; 1850 } 1851 1852 mSleepingLastTick = false; 1853 */ 1854 1855 MatrixF mat; 1856 Vector<NxActor*> *actors; 1857 1858 if ( mIsDummy ) 1859 { 1860 PxMultiActor *serverObj = static_cast<PxMultiActor*>( mServerObject.getObject() ); 1861 if ( !serverObj ) 1862 return; 1863 1864 mat = serverObj->getTransform(); 1865 actors = &serverObj->mActors; 1866 } 1867 else 1868 { 1869 // Container buoyancy & drag 1870 _updateContainerForces(); 1871 1872 // Save the transform from the root actor. 1873 mRootActor->getGlobalPose().getRowMajor44( mat ); 1874 actors = &mActors; 1875 } 1876 1877 // Update the transform and the root delta. 1878 Parent::setTransform( mat ); 1879 mDelta.pos = mat.getPosition(); 1880 mDelta.rot.set( mat ); 1881 1882 // On the client we update the individual 1883 // actor deltas as well for interpolation. 1884 if ( isClientObject() ) 1885 { 1886 PROFILE_SCOPE( PxMultiActor_ProcessTick_UpdateDeltas ); 1887 1888 for ( U32 i = 0; i < mActorDeltas.size(); i++ ) 1889 { 1890 if ( !(*actors)[i] ) 1891 continue; 1892 1893 Delta &delta = mActorDeltas[i]; 1894 1895 // Store the last position. 1896 delta.lastPos = delta.pos; 1897 delta.lastRot = delta.rot; 1898 1899 // Get the new position. 1900 (*actors)[i]->getGlobalPose().getRowMajor44( (NxF32*)mat ); 1901 1902 // Calculate the delta between the current 1903 // global pose and the last global pose. 1904 delta.pos = mat.getPosition(); 1905 delta.rot.set( mat ); 1906 } 1907 } 1908 1909 // Update the bounding box to match the physics. 1910 _updateBounds(); 1911 1912 // Set the MoveMask so this will be updated to the client. 1913 //setMaskBits( MoveMask ); 1914} 1915 1916void PxMultiActor::interpolateTick( F32 delta ) 1917{ 1918 PROFILE_SCOPE( PxMultiActor_InterpolateTick ); 1919 1920 Point3F interpPos; 1921 QuatF interpRot; 1922 { 1923 // Interpolate the position based on the delta. 1924 interpPos.interpolate( mDelta.pos, mDelta.lastPos, delta ); 1925 1926 // Interpolate the rotation based on the delta. 1927 interpRot.interpolate( mDelta.rot, mDelta.lastRot, delta ); 1928 1929 // Set up the interpolated transform. 1930 MatrixF interpMat; 1931 interpRot.setMatrix( &interpMat ); 1932 interpMat.setPosition( interpPos ); 1933 1934 Parent::setRenderTransform( interpMat ); 1935 } 1936 1937 PxMultiActor *srcObj = NULL; 1938 if ( mIsDummy ) 1939 srcObj = static_cast<PxMultiActor*>( mServerObject.getObject() ); 1940 else 1941 srcObj = this; 1942 1943 // JCF: to disable applying NxActor positions to the renderable mesh 1944 // you can uncomment this line. 1945 //srcObj = NULL; 1946 if ( mShapeInstance && srcObj != NULL ) 1947 { 1948 mShapeInstance->animate(); 1949 getDynamicXfms( srcObj, delta ); 1950 } 1951} 1952 1953/* 1954void PxMultiActor::sweepTest( MatrixF *mat ) 1955{ 1956 NxVec3 nxCurrPos = getPosition(); 1957 1958 // If the position is zero, 1959 // the parent hasn't been updated yet 1960 // and we don't even need to do the sweep test. 1961 // This is a fix for a problem that was happening 1962 // where on the add of the PhysXSingleActor, it would 1963 // set the position to a very small value because it would be getting a hit 1964 // even though the current position was 0. 1965 if ( nxCurrPos.isZero() ) 1966 return; 1967 1968 // Set up the flags and the query structure. 1969 NxU32 flags = NX_SF_STATICS | NX_SF_DYNAMICS; 1970 1971 NxSweepQueryHit sweepResult; 1972 dMemset( &sweepResult, 0, sizeof( sweepResult ) ); 1973 1974 NxVec3 nxNewPos = mat->getPosition(); 1975 1976 // Get the velocity which will be our sweep direction and distance. 1977 NxVec3 nxDir = nxNewPos - nxCurrPos; 1978 if ( nxDir.isZero() ) 1979 return; 1980 1981 NxActor *corrActor = mActors[ mDataBlock->correctionNodes[0] ]; 1982 1983 // Get the scene and do the sweep. 1984 corrActor->wakeUp(); 1985 corrActor->linearSweep( nxDir, flags, NULL, 1, &sweepResult, NULL ); 1986 1987 if ( sweepResult.hitShape && sweepResult.t < nxDir.magnitude() ) 1988 { 1989 nxDir.normalize(); 1990 nxDir *= sweepResult.t; 1991 nxCurrPos += nxDir; 1992 1993 mat->setPosition( Point3F( nxCurrPos.x, nxCurrPos.y, nxCurrPos.z ) ); 1994 } 1995} 1996*/ 1997 1998/* 1999void PxMultiActor::applyCorrection( const MatrixF& mat, const NxVec3& linVel, const NxVec3& angVel ) 2000{ 2001 // Sometimes the actor hasn't been 2002 // created yet during the call from unpackUpdate. 2003 NxActor *corrActor = mActors[ mDataBlock->correctionNodes[0] ]; 2004 2005 if ( !corrActor || mForceSleep ) 2006 return; 2007 2008 NxVec3 newPos = mat.getPosition(); 2009 NxVec3 currPos = getPosition(); 2010 2011 NxVec3 offset = newPos - currPos; 2012 2013 // If the difference isn't large enough, 2014 // just set the new transform, no correction. 2015 if ( offset.magnitude() > 0.3f ) 2016 { 2017 // If we're going to set the linear or angular velocity, 2018 // we do it before we add a corrective force, since it would be overwritten otherwise. 2019 NxVec3 currLinVel, currAngVel; 2020 currLinVel = corrActor->getLinearVelocity(); 2021 currAngVel = corrActor->getAngularVelocity(); 2022 2023 // Scale the corrective force by half, 2024 // otherwise it will over correct and oscillate. 2025 NxVec3 massCent = corrActor->getCMassGlobalPosition(); 2026 corrActor->addForceAtPos( offset, massCent, NX_SMOOTH_VELOCITY_CHANGE ); 2027 2028 // If the linear velocity is divergent enough, change to server linear velocity. 2029 if ( (linVel - currLinVel).magnitude() > 0.3f ) 2030 corrActor->setLinearVelocity( linVel ); 2031 // Same for angular. 2032 if ( (angVel - currAngVel).magnitude() > 0.3f ) 2033 corrActor->setAngularVelocity( angVel ); 2034 } 2035 2036 Parent::setTransform( mat ); 2037} 2038*/ 2039 2040void PxMultiActor::_updateBounds() 2041{ 2042 PROFILE_SCOPE( PxMultiActor_UpdateBounds ); 2043 2044 if ( mIsDummy ) 2045 { 2046 PxMultiActor *serverObj = static_cast<PxMultiActor*>( mServerObject.getObject() ); 2047 if ( !serverObj ) 2048 return; 2049 2050 mWorldBox = serverObj->getWorldBox(); 2051 mWorldSphere = serverObj->getWorldSphere(); 2052 mObjBox = serverObj->getObjBox(); 2053 mRenderWorldBox = serverObj->getRenderWorldBox(); 2054 mRenderWorldSphere = mWorldSphere; 2055 2056 return; 2057 } 2058 2059 NxBounds3 bounds; 2060 bounds.setEmpty(); 2061 2062 NxBounds3 shapeBounds; 2063 2064 for ( U32 i = 0; i < mActors.size(); i++ ) 2065 { 2066 NxActor *pActor = mActors[i]; 2067 2068 if ( !pActor || pActor->readActorFlag( NX_AF_DISABLE_COLLISION ) ) 2069 continue; 2070 2071 NxShape *const* pShapeArray = pActor->getShapes(); 2072 U32 shapeCount = pActor->getNbShapes(); 2073 for ( U32 i = 0; i < shapeCount; i++ ) 2074 { 2075 // Get the shape's bounds. 2076 pShapeArray[i]->getWorldBounds( shapeBounds ); 2077 2078 // Combine them into the total bounds. 2079 bounds.combine( shapeBounds ); 2080 } 2081 } 2082 2083 mWorldBox = pxCast<Box3F>( bounds ); 2084 2085 mWorldBox.getCenter(&mWorldSphere.center); 2086 mWorldSphere.radius = (mWorldBox.maxExtents - mWorldSphere.center).len(); 2087 2088 mObjBox = mWorldBox; 2089 mWorldToObj.mul(mObjBox); 2090 2091 mRenderWorldBox = mWorldBox; 2092 mRenderWorldSphere = mWorldSphere; 2093} 2094 2095void PxMultiActor::getDynamicXfms( PxMultiActor *srcObj, F32 dt ) 2096{ 2097 PROFILE_SCOPE( PxMultiActor_getDynamicXfms ); 2098 2099 Vector<MatrixF> *torqueXfms = &mShapeInstance->mNodeTransforms; 2100 const MatrixF &objectXfm = getRenderWorldTransform(); 2101 2102 AssertFatal( torqueXfms->size() == srcObj->mMappedActors.size(), "The two skeletons are different!" ); 2103 2104 TSShape *shape = mShapeInstance->getShape(); 2105 2106 // TODO: We're currently preparing deltas and getting 2107 // dynamic xforms even if the object isn't visible. 2108 // we should probably try to delay all this until 2109 // we're about to render. 2110 // 2111 /* 2112 // TODO: Set up deltas! 2113 if ( mCurrPos.empty() || mCurrRot.empty() ) 2114 _prepareDeltas(); 2115 */ 2116 2117 MatrixF globalXfm; 2118 MatrixF mat, tmp; 2119 QuatF newRot; 2120 Point3F newPos; 2121 2122 S32 dl = mShapeInstance->getCurrentDetail(); 2123 if ( dl < 0 ) 2124 return; 2125 2126 const String &detailName = shape->getName( shape->details[dl].nameIndex ); 2127 S32 detailSize = -1; 2128 String::GetTrailingNumber( detailName, detailSize ); 2129 2130 for( S32 i = 0; i < srcObj->mMappedActors.size(); i++ ) 2131 { 2132 NxActor *actor = srcObj->mMappedActors[i]; 2133 2134 if ( !actor || actor->readBodyFlag( NX_BF_KINEMATIC ) ) 2135 continue; 2136 2137 // see if the node at this index is part of the 2138 // currently visible detail level. 2139 if ( srcObj->mMappedActorDL[i] != detailSize ) 2140 continue; 2141 2142 // Get the right actor delta structure. 2143 U32 index = srcObj->mMappedToActorIndex[i]; 2144 const Delta &delta = mActorDeltas[index]; 2145 2146 // Do the interpolation. 2147 newRot.interpolate( delta.rot, delta.lastRot, dt ); 2148 newRot.setMatrix( &globalXfm ); 2149 newPos.interpolate( delta.pos, delta.lastPos, dt ); 2150 globalXfm.setPosition( newPos ); 2151 2152 (*torqueXfms)[i].mul( objectXfm, globalXfm ); 2153 } 2154} 2155 2156void PxMultiActor::applyImpulse( const Point3F &pos, const VectorF &vec ) 2157{ 2158 // TODO : Implement this based on correction nodes. 2159 /* 2160 if ( !mWorld || !mActor ) 2161 return; 2162 2163 mWorld->releaseWriteLock(); 2164 2165 NxVec3 linVel = mActor->getLinearVelocity(); 2166 NxVec3 nxVel( vel.x, vel.y, vel.z ); 2167 2168 mActor->setLinearVelocity(linVel + nxVel); 2169 */ 2170 2171 // JCF: something more complex is required to apply forces / breakage 2172 // on only individual actors, and we don't have enough data to do that 2173 // within this method. 2174 2175 if ( vec.len() > mDataBlock->breakForce ) 2176 setAllBroken( true ); 2177 2178 NxVec3 nxvec = pxCast<NxVec3>( vec ); 2179 NxVec3 nxpos = pxCast<NxVec3>( pos ); 2180 2181 for ( U32 i = 0; i < mActors.size(); i++ ) 2182 { 2183 NxActor *actor = mActors[i]; 2184 if ( actor->isDynamic() && 2185 !actor->readBodyFlag( NX_BF_KINEMATIC ) && 2186 !actor->readActorFlag( NX_AF_DISABLE_COLLISION ) ) 2187 { 2188 actor->addForceAtPos( nxvec, nxpos, NX_IMPULSE ); 2189 } 2190 } 2191 2192 //setMaskBits( ImpulseMask ); 2193} 2194 2195void PxMultiActor::applyRadialImpulse( const Point3F &origin, F32 radius, F32 magnitude ) 2196{ 2197 mWorld->releaseWriteLock(); 2198 2199 // Find all currently enabled actors hit by the impulse radius... 2200 Vector<NxActor*> hitActors; 2201 NxVec3 nxorigin = pxCast<NxVec3>(origin); 2202 NxSphere impulseSphere( nxorigin, radius ); 2203 2204 for ( U32 i = 0; i < mActors.size(); i++ ) 2205 { 2206 NxActor *pActor = mActors[i]; 2207 2208 if ( pActor->readActorFlag( NX_AF_DISABLE_COLLISION ) || 2209 !pActor->isDynamic() || 2210 pActor->readBodyFlag( NX_BF_KINEMATIC ) ) 2211 continue; 2212 2213 U32 numShapes = pActor->getNbShapes(); 2214 NxShape *const* pShapeArray = pActor->getShapes(); 2215 2216 for ( U32 j = 0; j < numShapes; j++ ) 2217 { 2218 const NxShape *pShape = pShapeArray[j]; 2219 2220 if ( pShape->checkOverlapSphere( impulseSphere ) ) 2221 { 2222 hitActors.push_back( pActor ); 2223 break; 2224 } 2225 } 2226 } 2227 2228 // Apply forces to hit actors, but swap out for broken 2229 // actors first if appropriate... 2230 for ( U32 i = 0; i < hitActors.size(); i++ ) 2231 { 2232 NxActor *pActor = hitActors[i]; 2233 2234 PxUserData *pUserData = PxUserData::getData( *pActor ); 2235 2236 // TODO: We should calculate the real force accounting 2237 // for falloff before we break things with it. 2238 2239 // If we have enough force, and this is an actor that 2240 // can be 'broken' by impacts, break it now. 2241 if ( pUserData && 2242 //pUserData->mCanPush && 2243 pUserData->mBrokenActors.size() > 0 && 2244 magnitude > mDataBlock->breakForce ) 2245 { 2246 setBroken( pActor->getGlobalPose(), 2247 pActor->getLinearVelocity(), 2248 pUserData, 2249 true ); 2250 2251 // apply force that would have been applied to this actor 2252 // to the broken actors we just enabled. 2253 2254 for ( U32 j = 0; j < pUserData->mBrokenActors.size(); j++ ) 2255 { 2256 NxActor *pBrokenActor = pUserData->mBrokenActors[j]; 2257 _applyActorRadialForce( pBrokenActor, nxorigin, radius, magnitude ); 2258 } 2259 } 2260 else 2261 { 2262 // Apply force to the actor. 2263 _applyActorRadialForce( pActor, nxorigin, radius, magnitude ); 2264 } 2265 } 2266} 2267 2268void PxMultiActor::_applyActorRadialForce( NxActor *inActor, const NxVec3 &origin, F32 radius, F32 magnitude ) 2269{ 2270 // TODO: We're not getting a good torque force 2271 // out of explosions because we're not picking 2272 // the nearest point on the actor to the origin 2273 // of the radial force. 2274 2275 NxVec3 force = inActor->getCMassGlobalPosition() - origin; 2276 NxF32 dist = force.magnitude(); 2277 force.normalize(); 2278 2279 if ( dist == 0.0f ) 2280 force *= magnitude; 2281 else 2282 force *= mClampF( radius / dist, 0.0f, 1.0f ) * magnitude; 2283 2284 // HACK: Make the position we push the force thru between the 2285 // actor pos and its center of mass. This gives us some 2286 // rotational force as well as make the covered structure 2287 // explode better. 2288 NxVec3 forcePos = ( inActor->getGlobalPosition() + inActor->getCMassGlobalPosition() ) / 2.0f; 2289 inActor->addForceAtPos( force, forcePos, NX_VELOCITY_CHANGE ); 2290} 2291 2292void PxMultiActor::_updateContainerForces() 2293{ 2294 if ( !mWorld->getEnabled() ) 2295 return; 2296 2297 PROFILE_SCOPE( PxMultiActor_updateContainerForces ); 2298 2299 // Update container drag and buoyancy properties ( for each Actor ) 2300 2301 for ( U32 i = 0; i < mActors.size(); i++ ) 2302 { 2303 NxActor *pActor = mActors[i]; 2304 2305 if ( !pActor || 2306 pActor->readBodyFlag(NX_BF_KINEMATIC) || 2307 pActor->readActorFlag(NX_AF_DISABLE_COLLISION) ) 2308 continue; 2309 2310 // Get world bounds of this actor ( the combination of all shape bounds ) 2311 NxShape *const* shapes = pActor->getShapes(); 2312 NxBounds3 bounds; 2313 bounds.setEmpty(); 2314 NxBounds3 shapeBounds; 2315 2316 for ( U32 i = 0; i < pActor->getNbShapes(); i++ ) 2317 { 2318 NxShape *pShape = shapes[i]; 2319 pShape->getWorldBounds(shapeBounds); 2320 2321 bounds.combine( shapeBounds ); 2322 } 2323 2324 Box3F boundsBox = pxCast<Box3F>(bounds); 2325 2326 ContainerQueryInfo info; 2327 info.box = boundsBox; 2328 info.mass = pActor->getMass(); 2329 2330 // Find and retreive physics info from intersecting WaterObject(s) 2331 mContainer->findObjects( boundsBox, WaterObjectType</a>|<a href="/coding/file/objecttypes_8h/#objecttypes_8h_1ac18d4a11e9446825e48fd474d7529084a1af121084d5760a7eaef4bb8828ce1cf">PhysicalZoneObjectType, findRouter, &info ); 2332 2333 // Calculate buoyancy and drag 2334 F32 angDrag = mDataBlock->angularDrag; 2335 F32 linDrag = mDataBlock->linearDrag; 2336 F32 buoyancy = 0.0f; 2337 2338 if ( true ) //info.waterCoverage >= 0.1f) 2339 { 2340 F32 waterDragScale = info.waterViscosity * mDataBlock->waterDragScale; 2341 F32 powCoverage = mPow( info.waterCoverage, 0.25f ); 2342 2343 if ( info.waterCoverage > 0.0f ) 2344 { 2345 //angDrag = mBuildAngDrag * waterDragScale; 2346 //linDrag = mBuildLinDrag * waterDragScale; 2347 angDrag = mLerp( angDrag, angDrag * waterDragScale, powCoverage ); 2348 linDrag = mLerp( linDrag, linDrag * waterDragScale, powCoverage ); 2349 } 2350 2351 buoyancy = ( info.waterDensity / mDataBlock->buoyancyDensity ) * mPow( info.waterCoverage, 2.0f ); 2352 } 2353 2354 // Apply drag (dampening) 2355 pActor->setLinearDamping( linDrag ); 2356 pActor->setAngularDamping( angDrag ); 2357 2358 // Apply buoyancy force 2359 if ( buoyancy != 0 ) 2360 { 2361 // A little hackery to prevent oscillation 2362 // Based on this blog post: 2363 // (http://reinot.blogspot.com/2005/11/oh-yes-they-float-georgie-they-all.html) 2364 // JCF: disabled! 2365 NxVec3 gravity; 2366 mWorld->getScene()->getGravity(gravity); 2367 //NxVec3 velocity = pActor->getLinearVelocity(); 2368 2369 NxVec3 buoyancyForce = buoyancy * -gravity * TickSec * pActor->getMass(); 2370 //F32 currHeight = getPosition().z; 2371 //const F32 C = 2.0f; 2372 //const F32 M = 0.1f; 2373 2374 //if ( currHeight + velocity.z * TickSec * C > info.waterHeight ) 2375 // buoyancyForce *= M; 2376 2377 pActor->addForceAtPos( buoyancyForce, pActor->getCMassGlobalPosition(), NX_IMPULSE ); 2378 } 2379 2380 // Apply physical zone forces 2381 if ( info.appliedForce.len() > 0.001f ) 2382 pActor->addForceAtPos( pxCast<NxVec3>(info.appliedForce), pActor->getCMassGlobalPosition(), NX_IMPULSE ); 2383 } 2384} 2385 2386/* 2387ConsoleMethod( PxMultiActor, applyImpulse, void, 3, 3, "applyImpulse - takes a velocity vector to apply") 2388{ 2389 VectorF vec; 2390 dSscanf( argv[2],"%g %g %g", 2391 &vec.x,&vec.y,&vec.z ); 2392 2393 object->applyImpulse( vec ); 2394} 2395*/ 2396 2397void PxMultiActor::setAllBroken( bool isBroken ) 2398{ 2399 PROFILE_SCOPE( PxMultiActor_SetAllBroken ); 2400 2401 if ( mIsDummy ) 2402 { 2403 PxMultiActor *serverObj = static_cast<PxMultiActor*>( mServerObject.getObject() ); 2404 serverObj->setAllBroken( isBroken ); 2405 return; 2406 } 2407 2408 mWorld->releaseWriteLock(); 2409 2410 NxActor *actor0 = NULL; 2411 NxActor *actor1 = NULL; 2412 NxMat34 parentPose; 2413 2414 for ( U32 i = 0; i < mJoints.size(); i++ ) 2415 { 2416 NxJoint *joint = mJoints[i]; 2417 if ( !joint ) 2418 continue; 2419 2420 PxUserData *jointData = PxUserData::getData( *joint ); 2421 if ( !jointData ) 2422 continue; 2423 2424 joint->getActors( &actor0, &actor1 ); 2425 parentPose = actor0->getGlobalPose(); 2426 2427 setBroken( parentPose, NxVec3(0.0f), jointData, isBroken ); 2428 } 2429 2430 for ( U32 i = 0; i < mActors.size(); i++ ) 2431 { 2432 NxActor *actor = mActors[i]; 2433 if ( !actor ) 2434 continue; 2435 2436 PxUserData *actorData = PxUserData::getData( *actor ); 2437 if ( !actorData ) 2438 continue; 2439 2440 setBroken( actor->getGlobalPose(), 2441 actor->getLinearVelocity(), 2442 actorData, 2443 isBroken ); 2444 } 2445} 2446 2447void PxMultiActor::setBroken( const NxMat34 &parentPose, 2448 const NxVec3 &parentVel, 2449 PxUserData *userData, 2450 bool isBroken ) 2451{ 2452 PROFILE_SCOPE( PxMultiActor_SetBroken ); 2453 2454 // TODO: This function is highly inefficent and 2455 // way too complex to follow... the hacked single 2456 // player mode doesn't help. 2457 2458 // Be careful not to set something broken twice. 2459 if ( isBroken && 2460 userData->mIsBroken == isBroken ) 2461 return; 2462 2463 userData->mIsBroken = isBroken; 2464 2465 Vector<NxActor*> *hideActors = NULL; 2466 Vector<NxActor*> *showActors = NULL; 2467 2468 if ( isBroken ) 2469 { 2470 hideActors = &userData->mUnbrokenActors; 2471 showActors = &userData->mBrokenActors; 2472 } 2473 else 2474 { 2475 hideActors = &userData->mBrokenActors; 2476 showActors = &userData->mUnbrokenActors; 2477 } 2478 2479 NxActor *pActor = NULL; 2480 MatrixF tMat; 2481 for ( U32 i = 0; i < hideActors->size(); i++ ) 2482 { 2483 pActor = (*hideActors)[i]; 2484 2485 pActor->raiseActorFlag( NX_AF_DISABLE_COLLISION ); 2486 pActor->raiseBodyFlag( NX_BF_KINEMATIC ); 2487 pActor->putToSleep(); 2488 2489 NxShape *const* pShapeArray = pActor->getShapes(); 2490 U32 shapeCount = pActor->getNbShapes(); 2491 for ( U32 i = 0; i < shapeCount; i++ ) 2492 pShapeArray[i]->setFlag( NX_SF_DISABLE_RAYCASTING, true ); 2493 2494 setMeshHidden( _getMeshName( pActor ), true ); 2495 } 2496 2497 // Get the client side delta array. 2498 Vector<Delta> *actorDeltas = NULL; 2499 if ( isClientObject() ) 2500 actorDeltas = &mActorDeltas; 2501 else if ( isServerObject() && PHYSICSMGR->isSinglePlayer() ) 2502 { 2503 PxMultiActor *clientObj = static_cast<PxMultiActor*>( getClientObject() ); 2504 if ( clientObj ) 2505 actorDeltas = &clientObj->mActorDeltas; 2506 } 2507 U32 index; 2508 2509 for ( U32 i = 0; i < showActors->size(); i++ ) 2510 { 2511 pActor = (*showActors)[i]; 2512 2513 if ( showActors == &userData->mBrokenActors ) 2514 { 2515 NxMat34 pose; 2516 pose.multiply( parentPose, userData->mRelXfm[i] ); 2517 pActor->setGlobalPose( pose ); 2518 2519 if ( actorDeltas ) 2520 { 2521 for ( U32 j=0; j < mMappedActors.size(); j++ ) 2522 { 2523 if ( mMappedActors[j] == pActor ) 2524 { 2525 index = mMappedToActorIndex[j]; 2526 2527 // Reset the delta. 2528 Delta &delta = (*actorDeltas)[index]; 2529 delta.pos = pxCast<Point3F>( pose.t ); 2530 pose.getRowMajor44( tMat ); 2531 delta.rot.set( tMat ); 2532 delta.lastPos = delta.pos; 2533 delta.lastRot = delta.rot; 2534 2535 break; 2536 } 2537 } 2538 } 2539 } 2540 2541 pActor->clearActorFlag( NX_AF_DISABLE_COLLISION ); 2542 pActor->clearBodyFlag( NX_BF_KINEMATIC ); 2543 pActor->setLinearVelocity( parentVel ); 2544 pActor->wakeUp(); 2545 2546 NxShape *const* pShapeArray = pActor->getShapes(); 2547 U32 shapeCount = pActor->getNbShapes(); 2548 for ( U32 i = 0; i < shapeCount; i++ ) 2549 pShapeArray[i]->setFlag( NX_SF_DISABLE_RAYCASTING, false ); 2550 2551 setMeshHidden( _getMeshName(pActor), false ); 2552 } 2553} 2554 2555void PxMultiActor::setAllHidden( bool hide ) 2556{ 2557 for ( U32 i = 0; i < mShapeInstance->mMeshObjects.size(); i++ ) 2558 mShapeInstance->setMeshForceHidden( i, hide ); 2559} 2560 2561ConsoleMethod( PxMultiActor, setAllHidden, void, 3, 3, "( bool )" 2562 "@brief Hides or unhides all meshes contained in the PxMultiActor.\n\n" 2563 "Hidden meshes will not be rendered.") 2564{ 2565 object->setAllHidden( dAtob(argv[2]) ); 2566} 2567 2568void PxMultiActor::setMeshHidden( String namePrefix, bool hidden ) 2569{ 2570 if ( isServerObject() && PHYSICSMGR->isSinglePlayer() ) 2571 { 2572 PxMultiActor *clientObj = static_cast<PxMultiActor*>( getClientObject() ); 2573 if ( clientObj ) 2574 clientObj->setMeshHidden( namePrefix, hidden ); 2575 } 2576 2577 for ( U32 i = 0; i < mShapeInstance->mMeshObjects.size(); i++ ) 2578 { 2579 String meshName = mShapeInstance->getShape()->getMeshName( i ); 2580 2581 if ( meshName.find( namePrefix ) != String::NPos ) 2582 { 2583 mShapeInstance->setMeshForceHidden( i, hidden ); 2584 return; 2585 } 2586 } 2587 2588 Con::warnf( "PxMultiActor::setMeshHidden - could not find mesh containing substring (%s)", namePrefix.c_str() ); 2589} 2590 2591ConsoleMethod( PxMultiActor, setBroken, void, 3, 3, "( bool )" 2592 "@brief Sets the PxMultiActor to a broken or unbroken state.\n\n") 2593{ 2594 object->setAllBroken( dAtob( argv[2] ) ); 2595} 2596 2597void PxMultiActorData::dumpModel() 2598{ 2599 TSShapeInstance *inst = new TSShapeInstance( shape, true ); 2600 2601 String path = Platform::getMainDotCsDir(); 2602 path += "/model.dump"; 2603 2604 FileStream *st; 2605 if((st = FileStream::createAndOpen( path, Torque::FS::File::Write )) != NULL) 2606 { 2607 if ( inst ) 2608 inst->dump( *st ); 2609 else 2610 Con::errorf( "PxMultiActor::dumpModel, no ShapeInstance." ); 2611 2612 delete st; 2613 } 2614 else 2615 Con::errorf( "PxMultiActor::dumpModel, error opening dump file." ); 2616} 2617 2618ConsoleMethod( PxMultiActorData, dumpModel, void, 2, 2, 2619 "@brief Dumps model hierarchy and details to a file.\n\n" 2620 "The file will be created as \'model.dump\' in the game folder. " 2621 "If model.dump already exists, it will be overwritten.\n\n") 2622{ 2623 object->dumpModel(); 2624} 2625 2626ConsoleMethod( PxMultiActor, setMeshHidden, void, 4, 4, "(string meshName, bool isHidden)" 2627 "@brief Prevents the provided mesh from being rendered.\n\n") 2628{ 2629 object->setMeshHidden( argv[2], dAtob( argv[3] ) ); 2630} 2631 2632void PxMultiActor::listMeshes( const String &state ) const 2633{ 2634 if ( mShapeInstance ) 2635 mShapeInstance->listMeshes( state ); 2636} 2637 2638ConsoleMethod( PxMultiActor, listMeshes, void, 3, 3, "(enum Hidden/Shown/All)" 2639 "@brief Lists all meshes of the provided type in the console window.\n\n" 2640 "@param All Lists all of the %PxMultiActor's meshes.\n" 2641 "@param Hidden Lists all of the %PxMultiActor's hidden meshes.\n" 2642 "@param Shown Lists all of the %PxMultiActor's visible meshes.\n") 2643{ 2644 object->listMeshes( argv[2] ); 2645}; 2646 2647ConsoleMethod( PxMultiActorData, reload, void, 2, 2, "" 2648 "@brief Reloads all data used for the PxMultiActorData.\n\n" 2649 "If the reload sucessfully completes, all PxMultiActor's will be notified.\n\n") 2650{ 2651 object->reload(); 2652} 2653
