// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // * Neither the name of NVIDIA CORPORATION nor the names of its // contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Copyright (c) 2008-2019 NVIDIA Corporation. All rights reserved. // Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. // Copyright (c) 2001-2004 NovodeX AG. All rights reserved. // suppress LNK4221 #include "foundation/PxPreprocessor.h" PX_DUMMY_SYMBOL #if PX_SUPPORT_PVD #include "foundation/PxSimpleTypes.h" #include "foundation/Px.h" #include "PxMetaDataObjects.h" #include "PxPvdDataStream.h" #include "PxScene.h" #include "ScBodyCore.h" #include "PvdMetaDataExtensions.h" #include "PvdMetaDataPropertyVisitor.h" #include "PvdMetaDataDefineProperties.h" #include "PvdMetaDataBindingData.h" #include "PxRigidDynamic.h" #include "PxArticulation.h" #include "PxArticulationReducedCoordinate.h" #include "PxArticulationLink.h" #include "NpScene.h" #include "NpPhysics.h" #include "PvdTypeNames.h" #include "PvdMetaDataPvdBinding.h" using namespace physx; using namespace Sc; using namespace Vd; using namespace Sq; namespace physx { namespace Vd { struct NameValuePair { const char* mName; PxU32 mValue; }; static const NameValuePair g_physx_Sq_SceneQueryID__EnumConversion[] = { { "QUERY_RAYCAST_ANY_OBJECT", PxU32(QueryID::QUERY_RAYCAST_ANY_OBJECT) }, { "QUERY_RAYCAST_CLOSEST_OBJECT", PxU32(QueryID::QUERY_RAYCAST_CLOSEST_OBJECT) }, { "QUERY_RAYCAST_ALL_OBJECTS", PxU32(QueryID::QUERY_RAYCAST_ALL_OBJECTS) }, { "QUERY_OVERLAP_SPHERE_ALL_OBJECTS", PxU32(QueryID::QUERY_OVERLAP_SPHERE_ALL_OBJECTS) }, { "QUERY_OVERLAP_AABB_ALL_OBJECTS", PxU32(QueryID::QUERY_OVERLAP_AABB_ALL_OBJECTS) }, { "QUERY_OVERLAP_OBB_ALL_OBJECTS", PxU32(QueryID::QUERY_OVERLAP_OBB_ALL_OBJECTS) }, { "QUERY_OVERLAP_CAPSULE_ALL_OBJECTS", PxU32(QueryID::QUERY_OVERLAP_CAPSULE_ALL_OBJECTS) }, { "QUERY_OVERLAP_CONVEX_ALL_OBJECTS", PxU32(QueryID::QUERY_OVERLAP_CONVEX_ALL_OBJECTS) }, { "QUERY_LINEAR_OBB_SWEEP_CLOSEST_OBJECT", PxU32(QueryID::QUERY_LINEAR_OBB_SWEEP_CLOSEST_OBJECT) }, { "QUERY_LINEAR_CAPSULE_SWEEP_CLOSEST_OBJECT", PxU32(QueryID::QUERY_LINEAR_CAPSULE_SWEEP_CLOSEST_OBJECT) }, { "QUERY_LINEAR_CONVEX_SWEEP_CLOSEST_OBJECT", PxU32(QueryID::QUERY_LINEAR_CONVEX_SWEEP_CLOSEST_OBJECT) }, { NULL, 0 } }; struct SceneQueryIDConvertor { const NameValuePair* NameConversion; SceneQueryIDConvertor() : NameConversion(g_physx_Sq_SceneQueryID__EnumConversion) { } }; PvdMetaDataBinding::PvdMetaDataBinding() : mBindingData(PX_NEW(PvdMetaDataBindingData)()) { } PvdMetaDataBinding::~PvdMetaDataBinding() { for(OwnerActorsMap::Iterator iter = mBindingData->mOwnerActorsMap.getIterator(); !iter.done(); iter++) { iter->second->~OwnerActorsValueType(); PX_FREE(iter->second); } PX_DELETE(mBindingData); mBindingData = NULL; } template static inline void definePropertyStruct(PvdDataStream& inStream, const char* pushName = NULL) { PvdPropertyDefinitionHelper& helper(inStream.getPropertyDefinitionHelper()); PvdClassInfoValueStructDefine definitionObj(helper); bool doPush = pushName && *pushName; if(doPush) definitionObj.pushName(pushName); visitAllPvdProperties(definitionObj); if(doPush) definitionObj.popName(); helper.addPropertyMessage(getPvdNamespacedNameForType(), getPvdNamespacedNameForType(), sizeof(TValueType)); } template static inline void createClassAndDefineProperties(PvdDataStream& inStream) { inStream.createClass(); PvdPropertyDefinitionHelper& helper(inStream.getPropertyDefinitionHelper()); PvdClassInfoDefine definitionObj(helper, getPvdNamespacedNameForType()); visitAllPvdProperties(definitionObj); } template static inline void createClassDeriveAndDefineProperties(PvdDataStream& inStream) { inStream.createClass(); inStream.deriveClass(); PvdPropertyDefinitionHelper& helper(inStream.getPropertyDefinitionHelper()); PvdClassInfoDefine definitionObj(helper, getPvdNamespacedNameForType()); visitInstancePvdProperties(definitionObj); } template static inline void defineProperty(PvdDataStream& inStream, const char* inPropertyName, const char* semantic) { PvdPropertyDefinitionHelper& helper(inStream.getPropertyDefinitionHelper()); // PxEnumTraits< TValueType > filterFlagsEnum; TConvertSrc filterFlagsEnum; const TConvertData* convertor = filterFlagsEnum.NameConversion; for(; convertor->mName != NULL; ++convertor) helper.addNamedValue(convertor->mName, convertor->mValue); inStream.createProperty(inPropertyName, semantic, PropertyType::Scalar, helper.getNamedValues()); helper.clearNamedValues(); } template static inline void definePropertyFlags(PvdDataStream& inStream, const char* inPropertyName) { defineProperty(inStream, inPropertyName, "Bitflag"); } template static inline void definePropertyEnums(PvdDataStream& inStream, const char* inPropertyName) { defineProperty(inStream, inPropertyName, "Enumeration Value"); } static PX_FORCE_INLINE void registerPvdRaycast(PvdDataStream& inStream) { inStream.createClass(); definePropertyEnums(inStream, "type"); inStream.createProperty("filterData"); definePropertyFlags, PxU32ToName>(inStream, "filterFlags"); inStream.createProperty("origin"); inStream.createProperty("unitDir"); inStream.createProperty("distance"); inStream.createProperty("hits_arrayName"); inStream.createProperty("hits_baseIndex"); inStream.createProperty("hits_count"); } static PX_FORCE_INLINE void registerPvdSweep(PvdDataStream& inStream) { inStream.createClass(); definePropertyEnums(inStream, "type"); definePropertyFlags, PxU32ToName>(inStream, "filterFlags"); inStream.createProperty("unitDir"); inStream.createProperty("distance"); inStream.createProperty("geom_arrayName"); inStream.createProperty("geom_baseIndex"); inStream.createProperty("geom_count"); inStream.createProperty("pose_arrayName"); inStream.createProperty("pose_baseIndex"); inStream.createProperty("pose_count"); inStream.createProperty("filterData_arrayName"); inStream.createProperty("filterData_baseIndex"); inStream.createProperty("filterData_count"); inStream.createProperty("hits_arrayName"); inStream.createProperty("hits_baseIndex"); inStream.createProperty("hits_count"); } static PX_FORCE_INLINE void registerPvdOverlap(PvdDataStream& inStream) { inStream.createClass(); definePropertyEnums(inStream, "type"); inStream.createProperty("filterData"); definePropertyFlags, PxU32ToName>(inStream, "filterFlags"); inStream.createProperty("pose"); inStream.createProperty("geom_arrayName"); inStream.createProperty("geom_baseIndex"); inStream.createProperty("geom_count"); inStream.createProperty("hits_arrayName"); inStream.createProperty("hits_baseIndex"); inStream.createProperty("hits_count"); } static PX_FORCE_INLINE void registerPvdSqHit(PvdDataStream& inStream) { inStream.createClass(); inStream.createProperty("Shape"); inStream.createProperty("Actor"); inStream.createProperty("FaceIndex"); definePropertyFlags, PxU32ToName>(inStream, "Flags"); inStream.createProperty("Impact"); inStream.createProperty("Normal"); inStream.createProperty("Distance"); inStream.createProperty("U"); inStream.createProperty("V"); } void PvdMetaDataBinding::registerSDKProperties(PvdDataStream& inStream) { if (inStream.isClassExist()) return; // PxPhysics { inStream.createClass(); PvdPropertyDefinitionHelper& helper(inStream.getPropertyDefinitionHelper()); PvdClassInfoDefine definitionObj(helper, getPvdNamespacedNameForType()); helper.pushName("TolerancesScale"); visitAllPvdProperties(definitionObj); helper.popName(); inStream.createProperty("Scenes", "children", PropertyType::Array); inStream.createProperty("SharedShapes", "children", PropertyType::Array); inStream.createProperty("Materials", "children", PropertyType::Array); inStream.createProperty("HeightFields", "children", PropertyType::Array); inStream.createProperty("ConvexMeshes", "children", PropertyType::Array); inStream.createProperty("TriangleMeshes", "children", PropertyType::Array); inStream.createProperty("Version.Major"); inStream.createProperty("Version.Minor"); inStream.createProperty("Version.Bugfix"); inStream.createProperty("Version.Build"); definePropertyStruct(inStream, "TolerancesScale"); } { // PxGeometry inStream.createClass(); inStream.createProperty("Shape", "parents", PropertyType::Scalar); } { // PxBoxGeometry createClassDeriveAndDefineProperties(inStream); definePropertyStruct(inStream); } { // PxSphereGeometry createClassDeriveAndDefineProperties(inStream); definePropertyStruct(inStream); } { // PxCapsuleGeometry createClassDeriveAndDefineProperties(inStream); definePropertyStruct(inStream); } { // PxPlaneGeometry createClassDeriveAndDefineProperties(inStream); } { // PxConvexMeshGeometry createClassDeriveAndDefineProperties(inStream); definePropertyStruct(inStream); } { // PxTriangleMeshGeometry createClassDeriveAndDefineProperties(inStream); definePropertyStruct(inStream); } { // PxHeightFieldGeometry createClassDeriveAndDefineProperties(inStream); definePropertyStruct(inStream); } // PxScene { // PT: TODO: why inline this for PvdContact but do PvdRaycast/etc in separate functions? { // contact information inStream.createClass(); inStream.createProperty("Point"); inStream.createProperty("Axis"); inStream.createProperty("Shapes[0]"); inStream.createProperty("Shapes[1]"); inStream.createProperty("Separation"); inStream.createProperty("NormalForce"); inStream.createProperty("InternalFaceIndex[0]"); inStream.createProperty("InternalFaceIndex[1]"); inStream.createProperty("NormalForceValid"); } registerPvdSqHit(inStream); registerPvdRaycast(inStream); registerPvdSweep(inStream); registerPvdOverlap(inStream); inStream.createClass(); PvdPropertyDefinitionHelper& helper(inStream.getPropertyDefinitionHelper()); PvdClassInfoDefine definitionObj(helper, getPvdNamespacedNameForType()); visitAllPvdProperties(definitionObj); helper.pushName("SimulationStatistics"); visitAllPvdProperties(definitionObj); helper.popName(); inStream.createProperty("Physics", "parents", PropertyType::Scalar); inStream.createProperty("Timestamp"); inStream.createProperty("SimulateElapsedTime"); definePropertyStruct(inStream); definePropertyStruct(inStream, "SimulationStatistics"); inStream.createProperty("Contacts", "", PropertyType::Array); inStream.createProperty("SceneQueries.Overlaps", "", PropertyType::Array); inStream.createProperty("SceneQueries.Sweeps", "", PropertyType::Array); inStream.createProperty("SceneQueries.Hits", "", PropertyType::Array); inStream.createProperty("SceneQueries.Raycasts", "", PropertyType::Array); inStream.createProperty("SceneQueries.PoseList", "", PropertyType::Array); inStream.createProperty("SceneQueries.FilterDataList", "", PropertyType::Array); inStream.createProperty("SceneQueries.GeometryList", "", PropertyType::Array); inStream.createProperty("BatchedQueries.Overlaps", "", PropertyType::Array); inStream.createProperty("BatchedQueries.Sweeps", "", PropertyType::Array); inStream.createProperty("BatchedQueries.Hits", "", PropertyType::Array); inStream.createProperty("BatchedQueries.Raycasts", "", PropertyType::Array); inStream.createProperty("BatchedQueries.PoseList", "", PropertyType::Array); inStream.createProperty("BatchedQueries.FilterDataList", "", PropertyType::Array); inStream.createProperty("BatchedQueries.GeometryList", "", PropertyType::Array); inStream.createProperty("RigidStatics", "children", PropertyType::Array); inStream.createProperty("RigidDynamics", "children", PropertyType::Array); inStream.createProperty("Articulations", "children", PropertyType::Array); inStream.createProperty("Joints", "children", PropertyType::Array); inStream.createProperty("Aggregates", "children", PropertyType::Array); } // PxMaterial { createClassAndDefineProperties(inStream); definePropertyStruct(inStream); inStream.createProperty("Physics", "parents", PropertyType::Scalar); } // PxHeightField { { inStream.createClass(); inStream.createProperty("Height"); inStream.createProperty("MaterialIndex[0]"); inStream.createProperty("MaterialIndex[1]"); } inStream.createClass(); // It is important the PVD fields match the RepX fields, so this has // to be hand coded. PvdPropertyDefinitionHelper& helper(inStream.getPropertyDefinitionHelper()); PvdClassInfoDefine definitionObj(helper, getPvdNamespacedNameForType()); visitAllPvdProperties(definitionObj); inStream.createProperty("Samples", "", PropertyType::Array); inStream.createProperty("Physics", "parents", PropertyType::Scalar); definePropertyStruct(inStream); } // PxConvexMesh { { // hull polygon data. inStream.createClass(); inStream.createProperty("NumVertices"); inStream.createProperty("IndexBase"); } inStream.createClass(); inStream.createProperty("Mass"); inStream.createProperty("LocalInertia"); inStream.createProperty("LocalCenterOfMass"); inStream.createProperty("Points", "", PropertyType::Array); inStream.createProperty("HullPolygons", "", PropertyType::Array); inStream.createProperty("PolygonIndexes", "", PropertyType::Array); inStream.createProperty("Physics", "parents", PropertyType::Scalar); } // PxTriangleMesh { inStream.createClass(); inStream.createProperty("Points", "", PropertyType::Array); inStream.createProperty("NbTriangles", "", PropertyType::Scalar); inStream.createProperty("Triangles", "", PropertyType::Array); inStream.createProperty("MaterialIndices", "", PropertyType::Array); inStream.createProperty("Physics", "parents", PropertyType::Scalar); } { // PxShape createClassAndDefineProperties(inStream); definePropertyStruct(inStream); inStream.createProperty("Geometry", "children"); inStream.createProperty("Materials", "children", PropertyType::Array); inStream.createProperty("Actor", "parents"); } // PxActor { createClassAndDefineProperties(inStream); inStream.createProperty("Scene", "parents"); } // PxRigidActor { createClassDeriveAndDefineProperties(inStream); inStream.createProperty("Shapes", "children", PropertyType::Array); inStream.createProperty("Joints", "children", PropertyType::Array); } // PxRigidStatic { createClassDeriveAndDefineProperties(inStream); definePropertyStruct(inStream); } { // PxRigidBody createClassDeriveAndDefineProperties(inStream); } // PxRigidDynamic { createClassDeriveAndDefineProperties(inStream); // If anyone adds a 'getKinematicTarget' to PxRigidDynamic you can remove the line // below (after the code generator has run). inStream.createProperty("KinematicTarget"); definePropertyStruct(inStream); // Manually define the update struct. PvdPropertyDefinitionHelper& helper(inStream.getPropertyDefinitionHelper()); /*struct PxRigidDynamicUpdateBlock { Transform GlobalPose; Float3 LinearVelocity; Float3 AngularVelocity; PxU8 IsSleeping; PxU8 padding[3]; }; */ helper.pushName("GlobalPose"); helper.addPropertyMessageArg(PX_OFFSET_OF_RT(PxRigidDynamicUpdateBlock, GlobalPose)); helper.popName(); helper.pushName("LinearVelocity"); helper.addPropertyMessageArg(PX_OFFSET_OF_RT(PxRigidDynamicUpdateBlock, LinearVelocity)); helper.popName(); helper.pushName("AngularVelocity"); helper.addPropertyMessageArg(PX_OFFSET_OF_RT(PxRigidDynamicUpdateBlock, AngularVelocity)); helper.popName(); helper.pushName("IsSleeping"); helper.addPropertyMessageArg(PX_OFFSET_OF_RT(PxRigidDynamicUpdateBlock, IsSleeping)); helper.popName(); helper.addPropertyMessage(); } // PxArticulationBase { createClassAndDefineProperties(inStream); inStream.createProperty("Scene", "parents"); inStream.createProperty("Links", "children", PropertyType::Array); definePropertyStruct(inStream); } //no support yet for concrete articulation types { // PxArticulation //createClassDeriveAndDefineProperties(inStream); //definePropertyStruct(inStream); } //no support yet for concrete articulation types { // PxArticulationReducedCoordinate //createClassDeriveAndDefineProperties(inStream); //definePropertyStruct(inStream); } { // PxArticulationLink createClassDeriveAndDefineProperties(inStream); inStream.createProperty("Parent", "parents"); inStream.createProperty("Links", "children", PropertyType::Array); inStream.createProperty("InboundJoint", "children"); definePropertyStruct(inStream); PvdPropertyDefinitionHelper& helper(inStream.getPropertyDefinitionHelper()); /*struct PxArticulationLinkUpdateBlock { Transform GlobalPose; Float3 LinearVelocity; Float3 AngularVelocity; }; */ helper.pushName("GlobalPose"); helper.addPropertyMessageArg(PX_OFFSET_OF(PxArticulationLinkUpdateBlock, GlobalPose)); helper.popName(); helper.pushName("LinearVelocity"); helper.addPropertyMessageArg(PX_OFFSET_OF(PxArticulationLinkUpdateBlock, LinearVelocity)); helper.popName(); helper.pushName("AngularVelocity"); helper.addPropertyMessageArg(PX_OFFSET_OF(PxArticulationLinkUpdateBlock, AngularVelocity)); helper.popName(); helper.addPropertyMessage(); } { // PxArticulationJoint createClassAndDefineProperties(inStream); inStream.createProperty("Link", "parents"); definePropertyStruct(inStream); } { // PxConstraint createClassAndDefineProperties(inStream); definePropertyStruct(inStream); } { // PxAggregate createClassAndDefineProperties(inStream); inStream.createProperty("Scene", "parents"); definePropertyStruct(inStream); inStream.createProperty("Actors", "children", PropertyType::Array); inStream.createProperty("Articulations", "children", PropertyType::Array); } } template static void doSendAllProperties(PvdDataStream& inStream, const TDataType* inDatatype, const void* instanceId) { TValueType theValues(inDatatype); inStream.setPropertyMessage(instanceId, theValues); } void PvdMetaDataBinding::sendAllProperties(PvdDataStream& inStream, const PxPhysics& inPhysics) { PxTolerancesScale theScale(inPhysics.getTolerancesScale()); doSendAllProperties(inStream, &theScale, &inPhysics); inStream.setPropertyValue(&inPhysics, "Version.Major", PxU32(PX_PHYSICS_VERSION_MAJOR)); inStream.setPropertyValue(&inPhysics, "Version.Minor", PxU32(PX_PHYSICS_VERSION_MINOR)); inStream.setPropertyValue(&inPhysics, "Version.Bugfix", PxU32(PX_PHYSICS_VERSION_BUGFIX)); #if PX_CHECKED #if defined(NDEBUG) // This is a checked build String buildType = "Checked"; #elif defined(_DEBUG) // This is a debug build String buildType = "Debug"; #endif #elif PX_PROFILE String buildType = "Profile"; #elif defined(NDEBUG) // This is a release build String buildType = "Release"; #endif inStream.setPropertyValue(&inPhysics, "Version.Build", buildType); } void PvdMetaDataBinding::sendAllProperties(PvdDataStream& inStream, const PxScene& inScene) { PxPhysics& physics(const_cast(inScene).getPhysics()); PxTolerancesScale theScale; PxSceneDesc theDesc(theScale); { theDesc.gravity = inScene.getGravity(); theDesc.simulationEventCallback = inScene.getSimulationEventCallback(); theDesc.contactModifyCallback = inScene.getContactModifyCallback(); theDesc.ccdContactModifyCallback = inScene.getCCDContactModifyCallback(); theDesc.filterShaderData = inScene.getFilterShaderData(); theDesc.filterShaderDataSize = inScene.getFilterShaderDataSize(); theDesc.filterShader = inScene.getFilterShader(); theDesc.filterCallback = inScene.getFilterCallback(); theDesc.broadPhaseType = inScene.getBroadPhaseType(); theDesc.broadPhaseCallback = inScene.getBroadPhaseCallback(); theDesc.limits = inScene.getLimits(); theDesc.frictionType = inScene.getFrictionType(); theDesc.bounceThresholdVelocity = inScene.getBounceThresholdVelocity(); theDesc.frictionOffsetThreshold = inScene.getFrictionOffsetThreshold(); theDesc.flags = inScene.getFlags(); theDesc.cpuDispatcher = inScene.getCpuDispatcher(); theDesc.cudaContextManager = inScene.getCudaContextManager(); theDesc.staticStructure = inScene.getStaticStructure(); theDesc.dynamicStructure = inScene.getDynamicStructure(); theDesc.dynamicTreeRebuildRateHint = inScene.getDynamicTreeRebuildRateHint(); theDesc.userData = inScene.userData; theDesc.solverBatchSize = inScene.getSolverBatchSize(); // theDesc.nbContactDataBlocks = inScene.getNbContactDataBlocksUsed(); // theDesc.maxNbContactDataBlocks = inScene.getMaxNbContactDataBlocksUsed(); theDesc.contactReportStreamBufferSize = inScene.getContactReportStreamBufferSize(); theDesc.ccdMaxPasses = inScene.getCCDMaxPasses(); // theDesc.simulationOrder = inScene.getSimulationOrder(); theDesc.wakeCounterResetValue = inScene.getWakeCounterResetValue(); } PxSceneDescGeneratedValues theValues(&theDesc); inStream.setPropertyMessage(&inScene, theValues); // Create parent/child relationship. inStream.setPropertyValue(&inScene, "Physics", reinterpret_cast(&physics)); inStream.pushBackObjectRef(&physics, "Scenes", &inScene); } void PvdMetaDataBinding::sendBeginFrame(PvdDataStream& inStream, const PxScene* inScene, PxReal simulateElapsedTime) { inStream.beginSection(inScene, "frame"); inStream.setPropertyValue(inScene, "Timestamp", inScene->getTimestamp()); inStream.setPropertyValue(inScene, "SimulateElapsedTime", simulateElapsedTime); } template struct NullConverter { void operator()(TDataType& data, const TDataType& src) { data = src; } }; template > class ScopedPropertyValueSender { TTargetType mStack[T_NUM_ITEMS]; TTargetType* mCur; const TTargetType* mEnd; PvdDataStream& mStream; public: ScopedPropertyValueSender(PvdDataStream& inStream, const void* inObj, String name) : mCur(mStack), mEnd(&mStack[T_NUM_ITEMS]), mStream(inStream) { mStream.beginSetPropertyValue(inObj, name, getPvdNamespacedNameForType()); } ~ScopedPropertyValueSender() { if(mStack != mCur) { PxU32 size = sizeof(TTargetType) * PxU32(mCur - mStack); mStream.appendPropertyValueData(DataRef(reinterpret_cast(mStack), size)); } mStream.endSetPropertyValue(); } void append(const TSourceType& data) { Converter()(*mCur, data); if(mCur < mEnd - 1) ++mCur; else { mStream.appendPropertyValueData(DataRef(reinterpret_cast(mStack), sizeof mStack)); mCur = mStack; } } private: ScopedPropertyValueSender& operator=(const ScopedPropertyValueSender&); }; void PvdMetaDataBinding::sendContacts(PvdDataStream& inStream, const PxScene& inScene) { inStream.setPropertyValue(&inScene, "Contacts", DataRef(), getPvdNamespacedNameForType()); } void PvdMetaDataBinding::sendStats(PvdDataStream& inStream, const PxScene* inScene) { PxSimulationStatistics theStats; inScene->getSimulationStatistics(theStats); PxSimulationStatisticsGeneratedValues values(&theStats); inStream.setPropertyMessage(inScene, values); } struct PvdContactConverter { void operator()(PvdContact& data, const Sc::Contact& src) { data.point = src.point; data.axis = src.normal; data.shape0 = src.shape0; data.shape1 = src.shape1; data.separation = src.separation; data.normalForce = src.normalForce; data.internalFaceIndex0 = src.faceIndex0; data.internalFaceIndex1 = src.faceIndex1; data.normalForceAvailable = src.normalForceAvailable; } }; void PvdMetaDataBinding::sendContacts(PvdDataStream& inStream, const PxScene& inScene, Array& inContacts) { ScopedPropertyValueSender sender(inStream, &inScene, "Contacts"); for(PxU32 i = 0; i < inContacts.size(); i++) { sender.append(inContacts[i]); } } void PvdMetaDataBinding::sendEndFrame(PvdDataStream& inStream, const PxScene* inScene) { //flush other client inStream.endSection(inScene, "frame"); } template static void addPhysicsGroupProperty(PvdDataStream& inStream, const char* groupName, const TDataType& inData, const PxPhysics& ownerPhysics) { inStream.setPropertyValue(&inData, "Physics", reinterpret_cast(&ownerPhysics)); inStream.pushBackObjectRef(&ownerPhysics, groupName, &inData); // Buffer type objects *have* to be flushed directly out once created else scene creation doesn't work. } template static void removePhysicsGroupProperty(PvdDataStream& inStream, const char* groupName, const TDataType& inData, const PxPhysics& ownerPhysics) { inStream.removeObjectRef(&ownerPhysics, groupName, &inData); inStream.destroyInstance(&inData); } void PvdMetaDataBinding::createInstance(PvdDataStream& inStream, const PxMaterial& inMaterial, const PxPhysics& ownerPhysics) { inStream.createInstance(&inMaterial); sendAllProperties(inStream, inMaterial); addPhysicsGroupProperty(inStream, "Materials", inMaterial, ownerPhysics); } void PvdMetaDataBinding::sendAllProperties(PvdDataStream& inStream, const PxMaterial& inMaterial) { PxMaterialGeneratedValues values(&inMaterial); inStream.setPropertyMessage(&inMaterial, values); } void PvdMetaDataBinding::destroyInstance(PvdDataStream& inStream, const PxMaterial& inMaterial, const PxPhysics& ownerPhysics) { removePhysicsGroupProperty(inStream, "Materials", inMaterial, ownerPhysics); } void PvdMetaDataBinding::sendAllProperties(PvdDataStream& inStream, const PxHeightField& inData) { PxHeightFieldDesc theDesc; // Save the height field to desc. theDesc.nbRows = inData.getNbRows(); theDesc.nbColumns = inData.getNbColumns(); theDesc.format = inData.getFormat(); theDesc.samples.stride = inData.getSampleStride(); theDesc.samples.data = NULL; theDesc.convexEdgeThreshold = inData.getConvexEdgeThreshold(); theDesc.flags = inData.getFlags(); PxU32 theCellCount = inData.getNbRows() * inData.getNbColumns(); PxU32 theSampleStride = sizeof(PxHeightFieldSample); PxU32 theSampleBufSize = theCellCount * theSampleStride; mBindingData->mTempU8Array.resize(theSampleBufSize); PxHeightFieldSample* theSamples = reinterpret_cast(mBindingData->mTempU8Array.begin()); inData.saveCells(theSamples, theSampleBufSize); theDesc.samples.data = theSamples; PxHeightFieldDescGeneratedValues values(&theDesc); inStream.setPropertyMessage(&inData, values); PxHeightFieldSample* theSampleData = reinterpret_cast(mBindingData->mTempU8Array.begin()); inStream.setPropertyValue(&inData, "Samples", theSampleData, theCellCount); } void PvdMetaDataBinding::createInstance(PvdDataStream& inStream, const PxHeightField& inData, const PxPhysics& ownerPhysics) { inStream.createInstance(&inData); sendAllProperties(inStream, inData); addPhysicsGroupProperty(inStream, "HeightFields", inData, ownerPhysics); } void PvdMetaDataBinding::destroyInstance(PvdDataStream& inStream, const PxHeightField& inData, const PxPhysics& ownerPhysics) { removePhysicsGroupProperty(inStream, "HeightFields", inData, ownerPhysics); } void PvdMetaDataBinding::createInstance(PvdDataStream& inStream, const PxConvexMesh& inData, const PxPhysics& ownerPhysics) { inStream.createInstance(&inData); PxReal mass; PxMat33 localInertia; PxVec3 localCom; inData.getMassInformation(mass, reinterpret_cast(localInertia), localCom); inStream.setPropertyValue(&inData, "Mass", mass); inStream.setPropertyValue(&inData, "LocalInertia", localInertia); inStream.setPropertyValue(&inData, "LocalCenterOfMass", localCom); // update arrays: // vertex Array: { const PxVec3* vertexPtr = inData.getVertices(); const PxU32 numVertices = inData.getNbVertices(); inStream.setPropertyValue(&inData, "Points", vertexPtr, numVertices); } // HullPolyArray: PxU16 maxIndices = 0; { PxU32 numPolygons = inData.getNbPolygons(); PvdHullPolygonData* tempData = mBindingData->allocateTemp(numPolygons); // Get the polygon data stripping the plane equations for(PxU32 index = 0; index < numPolygons; index++) { PxHullPolygon curOut; inData.getPolygonData(index, curOut); maxIndices = PxMax(maxIndices, PxU16(curOut.mIndexBase + curOut.mNbVerts)); tempData[index].mIndexBase = curOut.mIndexBase; tempData[index].mNumVertices = curOut.mNbVerts; } inStream.setPropertyValue(&inData, "HullPolygons", tempData, numPolygons); } // poly index Array: { const PxU8* indices = inData.getIndexBuffer(); inStream.setPropertyValue(&inData, "PolygonIndexes", indices, maxIndices); } addPhysicsGroupProperty(inStream, "ConvexMeshes", inData, ownerPhysics); } void PvdMetaDataBinding::destroyInstance(PvdDataStream& inStream, const PxConvexMesh& inData, const PxPhysics& ownerPhysics) { removePhysicsGroupProperty(inStream, "ConvexMeshes", inData, ownerPhysics); } void PvdMetaDataBinding::createInstance(PvdDataStream& inStream, const PxTriangleMesh& inData, const PxPhysics& ownerPhysics) { inStream.createInstance(&inData); bool hasMatIndex = inData.getTriangleMaterialIndex(0) != 0xffff; // update arrays: // vertex Array: { const PxVec3* vertexPtr = inData.getVertices(); const PxU32 numVertices = inData.getNbVertices(); inStream.setPropertyValue(&inData, "Points", vertexPtr, numVertices); } // index Array: { const bool has16BitIndices = inData.getTriangleMeshFlags() & PxTriangleMeshFlag::e16_BIT_INDICES ? true : false; const PxU32 numTriangles = inData.getNbTriangles(); inStream.setPropertyValue(&inData, "NbTriangles", numTriangles); const PxU32 numIndexes = numTriangles * 3; const PxU8* trianglePtr = reinterpret_cast(inData.getTriangles()); // We declared this type as a 32 bit integer above. // PVD will automatically unsigned-extend data that is smaller than the target type. if(has16BitIndices) inStream.setPropertyValue(&inData, "Triangles", reinterpret_cast(trianglePtr), numIndexes); else inStream.setPropertyValue(&inData, "Triangles", reinterpret_cast(trianglePtr), numIndexes); } // material Array: if(hasMatIndex) { PxU32 numMaterials = inData.getNbTriangles(); PxU16* matIndexData = mBindingData->allocateTemp(numMaterials); for(PxU32 m = 0; m < numMaterials; m++) matIndexData[m] = inData.getTriangleMaterialIndex(m); inStream.setPropertyValue(&inData, "MaterialIndices", matIndexData, numMaterials); } addPhysicsGroupProperty(inStream, "TriangleMeshes", inData, ownerPhysics); } void PvdMetaDataBinding::destroyInstance(PvdDataStream& inStream, const PxTriangleMesh& inData, const PxPhysics& ownerPhysics) { removePhysicsGroupProperty(inStream, "TriangleMeshes", inData, ownerPhysics); } template void PvdMetaDataBinding::registrarPhysicsObject(PvdDataStream&, const TDataType&, PsPvd*) { } template <> void PvdMetaDataBinding::registrarPhysicsObject(PvdDataStream& inStream, const PxConvexMeshGeometry& geom, PsPvd* pvd) { if(pvd->registerObject(geom.convexMesh)) createInstance(inStream, *geom.convexMesh, PxGetPhysics()); } template <> void PvdMetaDataBinding::registrarPhysicsObject(PvdDataStream& inStream, const PxTriangleMeshGeometry& geom, PsPvd* pvd) { if(pvd->registerObject(geom.triangleMesh)) createInstance(inStream, *geom.triangleMesh, PxGetPhysics()); } template <> void PvdMetaDataBinding::registrarPhysicsObject(PvdDataStream& inStream, const PxHeightFieldGeometry& geom, PsPvd* pvd) { if(pvd->registerObject(geom.heightField)) createInstance(inStream, *geom.heightField, PxGetPhysics()); } template static void sendGeometry(PvdMetaDataBinding& metaBind, PvdDataStream& inStream, const PxShape& inShape, const TGeomType& geom, PsPvd* pvd) { const void* geomInst = (reinterpret_cast(&inShape)) + 4; inStream.createInstance(getPvdNamespacedNameForType(), geomInst); metaBind.registrarPhysicsObject(inStream, geom, pvd); TGeneratedValuesType values(&geom); inStream.setPropertyMessage(geomInst, values); inStream.setPropertyValue(&inShape, "Geometry", geomInst); inStream.setPropertyValue(geomInst, "Shape", reinterpret_cast(&inShape)); } static void setGeometry(PvdMetaDataBinding& metaBind, PvdDataStream& inStream, const PxShape& inObj, PsPvd* pvd) { switch(inObj.getGeometryType()) { #define SEND_PVD_GEOM_TYPE(enumType, geomType, valueType) \ case PxGeometryType::enumType: \ { \ Px##geomType geom; \ inObj.get##geomType(geom); \ sendGeometry(metaBind, inStream, inObj, geom, pvd); \ } \ break; SEND_PVD_GEOM_TYPE(eSPHERE, SphereGeometry, PxSphereGeometryGeneratedValues); // Plane geometries don't have any properties, so this avoids using a property // struct for them. case PxGeometryType::ePLANE: { PxPlaneGeometry geom; inObj.getPlaneGeometry(geom); const void* geomInst = (reinterpret_cast(&inObj)) + 4; inStream.createInstance(getPvdNamespacedNameForType(), geomInst); inStream.setPropertyValue(&inObj, "Geometry", geomInst); inStream.setPropertyValue(geomInst, "Shape", reinterpret_cast(&inObj)); } break; SEND_PVD_GEOM_TYPE(eCAPSULE, CapsuleGeometry, PxCapsuleGeometryGeneratedValues); SEND_PVD_GEOM_TYPE(eBOX, BoxGeometry, PxBoxGeometryGeneratedValues); SEND_PVD_GEOM_TYPE(eCONVEXMESH, ConvexMeshGeometry, PxConvexMeshGeometryGeneratedValues); SEND_PVD_GEOM_TYPE(eTRIANGLEMESH, TriangleMeshGeometry, PxTriangleMeshGeometryGeneratedValues); SEND_PVD_GEOM_TYPE(eHEIGHTFIELD, HeightFieldGeometry, PxHeightFieldGeometryGeneratedValues); #undef SEND_PVD_GEOM_TYPE case PxGeometryType::eGEOMETRY_COUNT: case PxGeometryType::eINVALID: PX_ASSERT(false); break; } } static void setMaterials(PvdMetaDataBinding& metaBing, PvdDataStream& inStream, const PxShape& inObj, PsPvd* pvd, PvdMetaDataBindingData* mBindingData) { PxU32 numMaterials = inObj.getNbMaterials(); PxMaterial** materialPtr = mBindingData->allocateTemp(numMaterials); inObj.getMaterials(materialPtr, numMaterials); for(PxU32 idx = 0; idx < numMaterials; ++idx) { if(pvd->registerObject(materialPtr[idx])) metaBing.createInstance(inStream, *materialPtr[idx], PxGetPhysics()); inStream.pushBackObjectRef(&inObj, "Materials", materialPtr[idx]); } } void PvdMetaDataBinding::createInstance(PvdDataStream& inStream, const PxShape& inObj, const PxRigidActor& owner, const PxPhysics& ownerPhysics, PsPvd* pvd) { if(!inStream.isInstanceValid(&owner)) return; const OwnerActorsMap::Entry* entry = mBindingData->mOwnerActorsMap.find(&inObj); if(entry != NULL) { if(!mBindingData->mOwnerActorsMap[&inObj]->contains(&owner)) mBindingData->mOwnerActorsMap[&inObj]->insert(&owner); } else { OwnerActorsValueType* data = reinterpret_cast( PX_ALLOC(sizeof(OwnerActorsValueType), "mOwnerActorsMapValue")); //( 1 ); OwnerActorsValueType* actors = PX_PLACEMENT_NEW(data, OwnerActorsValueType); actors->insert(&owner); mBindingData->mOwnerActorsMap.insert(&inObj, actors); } if(inStream.isInstanceValid(&inObj)) { inStream.pushBackObjectRef(&owner, "Shapes", &inObj); return; } inStream.createInstance(&inObj); inStream.pushBackObjectRef(&owner, "Shapes", &inObj); inStream.setPropertyValue(&inObj, "Actor", reinterpret_cast(&owner)); sendAllProperties(inStream, inObj); setGeometry(*this, inStream, inObj, pvd); setMaterials(*this, inStream, inObj, pvd, mBindingData); if(!inObj.isExclusive()) inStream.pushBackObjectRef(&ownerPhysics, "SharedShapes", &inObj); } void PvdMetaDataBinding::sendAllProperties(PvdDataStream& inStream, const PxShape& inObj) { PxShapeGeneratedValues values(&inObj); inStream.setPropertyMessage(&inObj, values); } void PvdMetaDataBinding::releaseAndRecreateGeometry(PvdDataStream& inStream, const PxShape& inObj, PxPhysics& /*ownerPhysics*/, PsPvd* pvd) { const void* geomInst = (reinterpret_cast(&inObj)) + 4; inStream.destroyInstance(geomInst); // Quick fix for HF modify, PxConvexMesh and PxTriangleMesh need recook, they should always be new if modified if(inObj.getGeometryType() == PxGeometryType::eHEIGHTFIELD) { PxHeightFieldGeometry hfGeom; inObj.getHeightFieldGeometry(hfGeom); if(inStream.isInstanceValid(hfGeom.heightField)) sendAllProperties(inStream, *hfGeom.heightField); } setGeometry(*this, inStream, inObj, pvd); // Need update actor cause PVD takes actor-shape as a pair. { PxRigidActor* actor = inObj.getActor(); if(actor != NULL) { if(const PxRigidStatic* rgS = actor->is()) sendAllProperties(inStream, *rgS); else if(const PxRigidDynamic* rgD = actor->is()) sendAllProperties(inStream, *rgD); } } } void PvdMetaDataBinding::updateMaterials(PvdDataStream& inStream, const PxShape& inObj, PsPvd* pvd) { // Clear the shape's materials array. inStream.setPropertyValue(&inObj, "Materials", DataRef(), getPvdNamespacedNameForType()); setMaterials(*this, inStream, inObj, pvd, mBindingData); } void PvdMetaDataBinding::destroyInstance(PvdDataStream& inStream, const PxShape& inObj, const PxRigidActor& owner) { if(inStream.isInstanceValid(&inObj)) { inStream.removeObjectRef(&owner, "Shapes", &inObj); bool bDestroy = true; const OwnerActorsMap::Entry* entry0 = mBindingData->mOwnerActorsMap.find(&inObj); if(entry0 != NULL) { entry0->second->erase(&owner); if(entry0->second->size() > 0) bDestroy = false; else { mBindingData->mOwnerActorsMap[&inObj]->~OwnerActorsValueType(); PX_FREE(mBindingData->mOwnerActorsMap[&inObj]); mBindingData->mOwnerActorsMap.erase(&inObj); } } if(bDestroy) { if(!inObj.isExclusive()) inStream.removeObjectRef(&PxGetPhysics(), "SharedShapes", &inObj); const void* geomInst = (reinterpret_cast(&inObj)) + 4; inStream.destroyInstance(geomInst); inStream.destroyInstance(&inObj); const OwnerActorsMap::Entry* entry = mBindingData->mOwnerActorsMap.find(&inObj); if(entry != NULL) { entry->second->~OwnerActorsValueType(); PX_FREE(entry->second); mBindingData->mOwnerActorsMap.erase(&inObj); } } } } template static void addSceneGroupProperty(PvdDataStream& inStream, const char* groupName, const TDataType& inObj, const PxScene& inScene) { inStream.createInstance(&inObj); inStream.pushBackObjectRef(&inScene, groupName, &inObj); inStream.setPropertyValue(&inObj, "Scene", reinterpret_cast(&inScene)); } template static void removeSceneGroupProperty(PvdDataStream& inStream, const char* groupName, const TDataType& inObj, const PxScene& inScene) { inStream.removeObjectRef(&inScene, groupName, &inObj); inStream.destroyInstance(&inObj); } static void sendShapes(PvdMetaDataBinding& binding, PvdDataStream& inStream, const PxRigidActor& inObj, const PxPhysics& ownerPhysics, PsPvd* pvd) { InlineArray shapeData; PxU32 nbShapes = inObj.getNbShapes(); shapeData.resize(nbShapes); inObj.getShapes(shapeData.begin(), nbShapes); for(PxU32 idx = 0; idx < nbShapes; ++idx) binding.createInstance(inStream, *shapeData[idx], inObj, ownerPhysics, pvd); } static void releaseShapes(PvdMetaDataBinding& binding, PvdDataStream& inStream, const PxRigidActor& inObj) { InlineArray shapeData; PxU32 nbShapes = inObj.getNbShapes(); shapeData.resize(nbShapes); inObj.getShapes(shapeData.begin(), nbShapes); for(PxU32 idx = 0; idx < nbShapes; ++idx) binding.destroyInstance(inStream, *shapeData[idx], inObj); } void PvdMetaDataBinding::createInstance(PvdDataStream& inStream, const PxRigidStatic& inObj, const PxScene& ownerScene, const PxPhysics& ownerPhysics, PsPvd* pvd) { addSceneGroupProperty(inStream, "RigidStatics", inObj, ownerScene); sendAllProperties(inStream, inObj); sendShapes(*this, inStream, inObj, ownerPhysics, pvd); } void PvdMetaDataBinding::sendAllProperties(PvdDataStream& inStream, const PxRigidStatic& inObj) { PxRigidStaticGeneratedValues values(&inObj); inStream.setPropertyMessage(&inObj, values); } void PvdMetaDataBinding::destroyInstance(PvdDataStream& inStream, const PxRigidStatic& inObj, const PxScene& ownerScene) { releaseShapes(*this, inStream, inObj); removeSceneGroupProperty(inStream, "RigidStatics", inObj, ownerScene); } void PvdMetaDataBinding::createInstance(PvdDataStream& inStream, const PxRigidDynamic& inObj, const PxScene& ownerScene, const PxPhysics& ownerPhysics, PsPvd* pvd) { addSceneGroupProperty(inStream, "RigidDynamics", inObj, ownerScene); sendAllProperties(inStream, inObj); sendShapes(*this, inStream, inObj, ownerPhysics, pvd); } void PvdMetaDataBinding::sendAllProperties(PvdDataStream& inStream, const PxRigidDynamic& inObj) { PxRigidDynamicGeneratedValues values(&inObj); inStream.setPropertyMessage(&inObj, values); } void PvdMetaDataBinding::destroyInstance(PvdDataStream& inStream, const PxRigidDynamic& inObj, const PxScene& ownerScene) { releaseShapes(*this, inStream, inObj); removeSceneGroupProperty(inStream, "RigidDynamics", inObj, ownerScene); } static void addChild(PvdDataStream& inStream, const void* inParent, const PxArticulationLink& inChild) { inStream.pushBackObjectRef(inParent, "Links", &inChild); inStream.setPropertyValue(&inChild, "Parent", inParent); } void PvdMetaDataBinding::createInstance(PvdDataStream& inStream, const PxArticulationBase& inObj, const PxScene& ownerScene, const PxPhysics& ownerPhysics, PsPvd* pvd) { addSceneGroupProperty(inStream, "Articulations", inObj, ownerScene); sendAllProperties(inStream, inObj); PxU32 numLinks = inObj.getNbLinks(); mBindingData->mArticulationLinks.resize(numLinks); inObj.getLinks(mBindingData->mArticulationLinks.begin(), numLinks); // From Dilip Sequiera: /* No, there can only be one root, and in all the code I wrote (which is not 100% of the HL code for articulations), the index of a child is always > the index of the parent. */ // Create all the links for(PxU32 idx = 0; idx < numLinks; ++idx) { if(!inStream.isInstanceValid(mBindingData->mArticulationLinks[idx])) createInstance(inStream, *mBindingData->mArticulationLinks[idx], ownerPhysics, pvd); } // Setup the link graph for(PxU32 idx = 0; idx < numLinks; ++idx) { PxArticulationLink* link = mBindingData->mArticulationLinks[idx]; if(idx == 0) addChild(inStream, &inObj, *link); PxU32 numChildren = link->getNbChildren(); PxArticulationLink** children = mBindingData->allocateTemp(numChildren); link->getChildren(children, numChildren); for(PxU32 i = 0; i < numChildren; ++i) addChild(inStream, link, *children[i]); } } void PvdMetaDataBinding::sendAllProperties(PvdDataStream& inStream, const PxArticulationBase& inObj) { PxArticulationBaseGeneratedValues values(&inObj); inStream.setPropertyMessage(&inObj, values); } void PvdMetaDataBinding::destroyInstance(PvdDataStream& inStream, const PxArticulationBase& inObj, const PxScene& ownerScene) { removeSceneGroupProperty(inStream, "Articulations", inObj, ownerScene); } void PvdMetaDataBinding::createInstance(PvdDataStream& inStream, const PxArticulationLink& inObj, const PxPhysics& ownerPhysics, PsPvd* pvd) { inStream.createInstance(&inObj); PxArticulationJointBase* joint(inObj.getInboundJoint()); if(joint) { inStream.createInstance(joint); inStream.setPropertyValue(&inObj, "InboundJoint", reinterpret_cast(joint)); inStream.setPropertyValue(joint, "Link", reinterpret_cast(&inObj)); sendAllProperties(inStream, *joint); } sendAllProperties(inStream, inObj); sendShapes(*this, inStream, inObj, ownerPhysics, pvd); } void PvdMetaDataBinding::sendAllProperties(PvdDataStream& inStream, const PxArticulationLink& inObj) { PxArticulationLinkGeneratedValues values(&inObj); inStream.setPropertyMessage(&inObj, values); } void PvdMetaDataBinding::destroyInstance(PvdDataStream& inStream, const PxArticulationLink& inObj) { PxArticulationJointBase* joint(inObj.getInboundJoint()); if(joint) inStream.destroyInstance(joint); releaseShapes(*this, inStream, inObj); inStream.destroyInstance(&inObj); } // These are created as part of the articulation link's creation process, so outside entities don't need to // create them. void PvdMetaDataBinding::sendAllProperties(PvdDataStream& inStream, const PxArticulationJointBase& inObj) { PxArticulationJointBaseGeneratedValues values(&inObj); inStream.setPropertyMessage(&inObj, values); } void PvdMetaDataBinding::originShift(PvdDataStream& inStream, const PxScene* inScene, PxVec3 shift) { inStream.originShift(inScene, shift); } template static void updateActor(PvdDataStream& inStream, TActorType** actorGroup, PxU32 numActors, TOperator sleepingOp, PvdMetaDataBindingData& bindingData) { TBlockType theBlock; if(numActors == 0) return; for(PxU32 idx = 0; idx < numActors; ++idx) { TActorType* theActor(actorGroup[idx]); bool sleeping = sleepingOp(theActor, theBlock); bool wasSleeping = bindingData.mSleepingActors.contains(theActor); if(sleeping == false || sleeping != wasSleeping) { theBlock.GlobalPose = theActor->getGlobalPose(); theBlock.AngularVelocity = theActor->getAngularVelocity(); theBlock.LinearVelocity = theActor->getLinearVelocity(); inStream.sendPropertyMessageFromGroup(theActor, theBlock); if(sleeping != wasSleeping) { if(sleeping) bindingData.mSleepingActors.insert(theActor); else bindingData.mSleepingActors.erase(theActor); } } } } struct RigidDynamicUpdateOp { bool operator()(PxRigidDynamic* actor, PxRigidDynamicUpdateBlock& block) { bool sleeping = actor->isSleeping(); block.IsSleeping = sleeping; return sleeping; } }; struct ArticulationLinkUpdateOp { bool sleeping; ArticulationLinkUpdateOp(bool s) : sleeping(s) { } bool operator()(PxArticulationLink*, PxArticulationLinkUpdateBlock&) { return sleeping; } }; void PvdMetaDataBinding::updateDynamicActorsAndArticulations(PvdDataStream& inStream, const PxScene* inScene, PvdVisualizer* linkJointViz) { PX_COMPILE_TIME_ASSERT(sizeof(PxRigidDynamicUpdateBlock) == 14 * 4); { PxU32 actorCount = inScene->getNbActors(PxActorTypeFlag::eRIGID_DYNAMIC); if(actorCount) { inStream.beginPropertyMessageGroup(); mBindingData->mActors.resize(actorCount); PxActor** theActors = mBindingData->mActors.begin(); inScene->getActors(PxActorTypeFlag::eRIGID_DYNAMIC, theActors, actorCount); updateActor(inStream, reinterpret_cast(theActors), actorCount, RigidDynamicUpdateOp(), *mBindingData); inStream.endPropertyMessageGroup(); } } { PxU32 articulationCount = inScene->getNbArticulations(); if(articulationCount) { mBindingData->mArticulations.resize(articulationCount); PxArticulationBase** firstArticulation = mBindingData->mArticulations.begin(); PxArticulationBase** lastArticulation = firstArticulation + articulationCount; inScene->getArticulations(firstArticulation, articulationCount); inStream.beginPropertyMessageGroup(); for(; firstArticulation < lastArticulation; ++firstArticulation) { PxU32 linkCount = (*firstArticulation)->getNbLinks(); bool sleeping = (*firstArticulation)->isSleeping(); if(linkCount) { mBindingData->mArticulationLinks.resize(linkCount); PxArticulationLink** theLink = mBindingData->mArticulationLinks.begin(); (*firstArticulation)->getLinks(theLink, linkCount); updateActor(inStream, theLink, linkCount, ArticulationLinkUpdateOp(sleeping), *mBindingData); if(linkJointViz) { for(PxU32 idx = 0; idx < linkCount; ++idx) linkJointViz->visualize(*theLink[idx]); } } } inStream.endPropertyMessageGroup(); firstArticulation = mBindingData->mArticulations.begin(); for(; firstArticulation < lastArticulation; ++firstArticulation) inStream.setPropertyValue(*firstArticulation, "IsSleeping", (*firstArticulation)->isSleeping()); } } } template struct CollectionOperator { Array& mTempArray; const TObjType& mObject; PvdDataStream& mStream; CollectionOperator(Array& ary, const TObjType& obj, PvdDataStream& stream) : mTempArray(ary), mObject(obj), mStream(stream) { } void pushName(const char*) { } void popName() { } template void simpleProperty(PxU32 /*key*/, const TAccessor&) { } template void flagsProperty(PxU32 /*key*/, const TAccessor&, const PxU32ToName*) { } template void handleCollection(const TCollectionProp& prop, NamespacedName dtype, PxU32 countMultiplier = 1) { PxU32 count = prop.size(&mObject); mTempArray.resize(count * sizeof(TDataType)); TColType* start = reinterpret_cast(mTempArray.begin()); prop.get(&mObject, start, count * countMultiplier); mStream.setPropertyValue(&mObject, prop.mName, DataRef(mTempArray.begin(), mTempArray.size()), dtype); } template void handleCollection(const PxReadOnlyCollectionPropertyInfo& prop) { handleCollection(prop, getPvdNamespacedNameForType()); } // Enumerations or bitflags. template void handleCollection(const PxReadOnlyCollectionPropertyInfo& prop, const PxU32ToName*) { PX_COMPILE_TIME_ASSERT(sizeof(TColType) == sizeof(PxU32)); handleCollection(prop, getPvdNamespacedNameForType()); } private: CollectionOperator& operator=(const CollectionOperator&); }; // per frame update #define ENABLE_AGGREGATE_PVD_SUPPORT 1 #ifdef ENABLE_AGGREGATE_PVD_SUPPORT void PvdMetaDataBinding::createInstance(PvdDataStream& inStream, const PxAggregate& inObj, const PxScene& ownerScene) { addSceneGroupProperty(inStream, "Aggregates", inObj, ownerScene); sendAllProperties(inStream, inObj); } void PvdMetaDataBinding::sendAllProperties(PvdDataStream& inStream, const PxAggregate& inObj) { PxAggregateGeneratedValues values(&inObj); inStream.setPropertyMessage(&inObj, values); } void PvdMetaDataBinding::destroyInstance(PvdDataStream& inStream, const PxAggregate& inObj, const PxScene& ownerScene) { removeSceneGroupProperty(inStream, "Aggregates", inObj, ownerScene); } class ChangeOjectRefCmd : public PvdDataStream::PvdCommand { ChangeOjectRefCmd& operator=(const ChangeOjectRefCmd&) { PX_ASSERT(0); return *this; } // PX_NOCOPY doesn't work for local classes public: const void* mInstance; String mPropName; const void* mPropObj; const bool mPushBack; ChangeOjectRefCmd(const void* inInst, String inName, const void* inObj, bool pushBack) : mInstance(inInst), mPropName(inName), mPropObj(inObj), mPushBack(pushBack) { } // Assigned is needed for copying ChangeOjectRefCmd(const ChangeOjectRefCmd& other) : PvdDataStream::PvdCommand(other), mInstance(other.mInstance), mPropName(other.mPropName), mPropObj(other.mPropObj), mPushBack(other.mPushBack) { } virtual bool canRun(PvdInstanceDataStream& inStream) { PX_ASSERT(inStream.isInstanceValid(mInstance)); return inStream.isInstanceValid(mPropObj); } virtual void run(PvdInstanceDataStream& inStream) { if(!inStream.isInstanceValid(mInstance)) return; if(mPushBack) { if(inStream.isInstanceValid(mPropObj)) inStream.pushBackObjectRef(mInstance, mPropName, mPropObj); } else { // the called function will assert if propobj is already removed inStream.removeObjectRef(mInstance, mPropName, mPropObj); } } }; static void changeAggregateSubActors(PvdDataStream& inStream, const PxAggregate& inObj, const PxActor& inActor, bool pushBack) { const PxArticulationLink* link = inActor.is(); String propName = NULL; const void* object = NULL; if(link == NULL) { propName = "Actors"; object = &inActor; } else if(link->getInboundJoint() == NULL) { propName = "Articulations"; object = &link->getArticulation(); } else return; ChangeOjectRefCmd* cmd = PX_PLACEMENT_NEW(inStream.allocateMemForCmd(sizeof(ChangeOjectRefCmd)), ChangeOjectRefCmd)(&inObj, propName, object, pushBack); if(cmd->canRun(inStream)) cmd->run(inStream); else inStream.pushPvdCommand(*cmd); } void PvdMetaDataBinding::detachAggregateActor(PvdDataStream& inStream, const PxAggregate& inObj, const PxActor& inActor) { changeAggregateSubActors(inStream, inObj, inActor, false); } void PvdMetaDataBinding::attachAggregateActor(PvdDataStream& inStream, const PxAggregate& inObj, const PxActor& inActor) { changeAggregateSubActors(inStream, inObj, inActor, true); } #else void PvdMetaDataBinding::createInstance(PvdDataStream&, const PxAggregate&, const PxScene&, ObjectRegistrar&) { } void PvdMetaDataBinding::sendAllProperties(PvdDataStream&, const PxAggregate&) { } void PvdMetaDataBinding::destroyInstance(PvdDataStream&, const PxAggregate&, const PxScene&) { } void PvdMetaDataBinding::detachAggregateActor(PvdDataStream&, const PxAggregate&, const PxActor&) { } void PvdMetaDataBinding::attachAggregateActor(PvdDataStream&, const PxAggregate&, const PxActor&) { } #endif template static void sendSceneArray(PvdDataStream& inStream, const PxScene& inScene, const Ps::Array& inArray, const char* propName) { if(0 == inArray.size()) inStream.setPropertyValue(&inScene, propName, DataRef(), getPvdNamespacedNameForType()); else { ScopedPropertyValueSender sender(inStream, &inScene, propName); for(PxU32 i = 0; i < inArray.size(); ++i) sender.append(inArray[i]); } } static void sendSceneArray(PvdDataStream& inStream, const PxScene& inScene, const Ps::Array& inArray, const char* propName) { if(0 == inArray.size()) inStream.setPropertyValue(&inScene, propName, DataRef(), getPvdNamespacedNameForType()); else { ScopedPropertyValueSender sender(inStream, &inScene, propName); for(PxU32 i = 0; i < inArray.size(); ++i) { if(!inStream.isInstanceValid(inArray[i].mShape) || !inStream.isInstanceValid(inArray[i].mActor)) { PvdSqHit hit = inArray[i]; hit.mShape = NULL; hit.mActor = NULL; sender.append(hit); } else sender.append(inArray[i]); } } } void PvdMetaDataBinding::sendSceneQueries(PvdDataStream& inStream, const PxScene& inScene, PsPvd* pvd) { if(!inStream.isConnected()) return; const physx::NpScene& scene = static_cast(inScene); for(PxU32 i = 0; i < 2; i++) { PvdSceneQueryCollector& collector = ((i == 0) ? scene.getSingleSqCollector() : scene.getBatchedSqCollector()); Ps::Mutex::ScopedLock lock(collector.getLock()); String propName = collector.getArrayName(collector.mPvdSqHits); sendSceneArray(inStream, inScene, collector.mPvdSqHits, propName); propName = collector.getArrayName(collector.mPoses); sendSceneArray(inStream, inScene, collector.mPoses, propName); propName = collector.getArrayName(collector.mFilterData); sendSceneArray(inStream, inScene, collector.mFilterData, propName); const NamedArray& geometriesToDestroy = collector.getPrevFrameGeometries(); propName = collector.getArrayName(geometriesToDestroy); for(PxU32 k = 0; k < geometriesToDestroy.size(); ++k) { const PxGeometryHolder& inObj = geometriesToDestroy[k]; inStream.removeObjectRef(&inScene, propName, &inObj); inStream.destroyInstance(&inObj); } const Ps::Array& geometriesToCreate = collector.getCurrentFrameGeometries(); for(PxU32 k = 0; k < geometriesToCreate.size(); ++k) { const PxGeometry& geometry = geometriesToCreate[k].any(); switch(geometry.getType()) { #define SEND_PVD_GEOM_TYPE(enumType, TGeomType, TValueType) \ case enumType: \ { \ const TGeomType& inObj = static_cast(geometry); \ inStream.createInstance(getPvdNamespacedNameForType(), &inObj); \ registrarPhysicsObject(inStream, inObj, pvd); \ TValueType values(&inObj); \ inStream.setPropertyMessage(&inObj, values); \ inStream.pushBackObjectRef(&inScene, propName, &inObj); \ } \ break; SEND_PVD_GEOM_TYPE(PxGeometryType::eBOX, PxBoxGeometry, PxBoxGeometryGeneratedValues) SEND_PVD_GEOM_TYPE(PxGeometryType::eSPHERE, PxSphereGeometry, PxSphereGeometryGeneratedValues) SEND_PVD_GEOM_TYPE(PxGeometryType::eCAPSULE, PxCapsuleGeometry, PxCapsuleGeometryGeneratedValues) SEND_PVD_GEOM_TYPE(PxGeometryType::eCONVEXMESH, PxConvexMeshGeometry, PxConvexMeshGeometryGeneratedValues) #undef SEND_PVD_GEOM_TYPE case PxGeometryType::ePLANE: case PxGeometryType::eTRIANGLEMESH: case PxGeometryType::eHEIGHTFIELD: case PxGeometryType::eGEOMETRY_COUNT: case PxGeometryType::eINVALID: PX_ALWAYS_ASSERT_MESSAGE("unsupported scene query geometry type"); break; } } collector.prepareNextFrameGeometries(); propName = collector.getArrayName(collector.mAccumulatedRaycastQueries); sendSceneArray(inStream, inScene, collector.mAccumulatedRaycastQueries, propName); propName = collector.getArrayName(collector.mAccumulatedOverlapQueries); sendSceneArray(inStream, inScene, collector.mAccumulatedOverlapQueries, propName); propName = collector.getArrayName(collector.mAccumulatedSweepQueries); sendSceneArray(inStream, inScene, collector.mAccumulatedSweepQueries, propName); } } } } #endif