// // 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-2021 NVIDIA Corporation. All rights reserved. // Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. // Copyright (c) 2001-2004 NovodeX AG. All rights reserved. #ifndef PX_XML_VISITOR_READER_H #define PX_XML_VISITOR_READER_H #include "PsArray.h" #include "PsUtilities.h" #include "RepXMetaDataPropertyVisitor.h" #include "SnPxStreamOperators.h" #include "SnXmlMemoryPoolStreams.h" #include "SnXmlReader.h" #include "SnXmlImpl.h" #include "SnXmlMemoryAllocator.h" #include "SnXmlStringToType.h" namespace physx { namespace Sn { inline PxU32 findEnumByName( const char* inName, const PxU32ToName* inTable ) { for ( PxU32 idx = 0; inTable[idx].mName != NULL; ++idx ) { if ( physx::shdfnd::stricmp( inTable[idx].mName, inName ) == 0 ) return inTable[idx].mValue; } return 0; } PX_INLINE void stringToFlagsType( const char* strData, XmlMemoryAllocator& alloc, PxU32& ioType, const PxU32ToName* inTable ) { if ( inTable == NULL ) return; ioType = 0; if ( strData && *strData) { //Destructively parse the string to get out the different flags. char* theValue = const_cast( copyStr( &alloc, strData ) ); char* theMarker = theValue; char* theNext = theValue; while( theNext && *theNext ) { ++theNext; if( *theNext == '|' ) { *theNext = 0; ++theNext; ioType |= static_cast< PxU32 > ( findEnumByName( theMarker, inTable ) ); theMarker = theNext; } } if ( theMarker && *theMarker ) ioType |= static_cast< PxU32 > ( findEnumByName( theMarker, inTable ) ); alloc.deallocate( reinterpret_cast( theValue ) ); } } template PX_INLINE void stringToEnumType( const char* strData, TDataType& ioType, const PxU32ToName* inTable ) { ioType = static_cast( findEnumByName( strData, inTable ) ); } template PX_INLINE bool readProperty( XmlReader& inReader, const char* pname, TDataType& ioType ) { const char* value; if ( inReader.read( pname, value ) ) { stringToType( value, ioType ); return true; } return false; } template inline TObjType* findReferencedObject( PxCollection& collection, PxSerialObjectId id) { PX_ASSERT(id > 0); TObjType* outObject = static_cast(const_cast(collection.find(id))); if (outObject == NULL) { Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "PxSerialization::createCollectionFromXml: " "Reference to ID %d cannot be resolved. Make sure externalRefs collection is specified if required and " "check Xml file for completeness.", id); } return outObject; } template inline bool readReference( XmlReader& inReader, PxCollection& collection, TObjType*& outObject ) { PxSerialObjectId theId; const char* theValue = inReader.getCurrentItemValue(); strto( theId, theValue ); if( theId == 0) { // the NULL pointer is a valid pointer if the input id is 0 outObject = NULL; return true; } else { outObject = findReferencedObject(collection, theId); return outObject != NULL; } } template inline bool readReference( XmlReader& inReader, PxCollection& inCollection, const char* pname, TObjType*& outObject ) { outObject = NULL; PxSerialObjectId theId = 0; if (readProperty ( inReader, pname, theId ) && theId ) { outObject = findReferencedObject(inCollection, theId); } // the NULL pointer is a valid pointer if the input id is 0 return (outObject != NULL) || 0 == theId; } template inline bool readFlagsProperty( XmlReader& reader, XmlMemoryAllocator& allocator, const char* pname, const PxU32ToName* inConversions, PxFlags& outFlags ) { const char* value; if ( reader.read( pname, value ) ) { PxU32 tempValue = 0; stringToFlagsType( value, allocator, tempValue, inConversions ); outFlags = PxFlags(Ps::to16(tempValue) ); return true; } return false; } template inline void readComplexObj( TReaderType& oldVisitor, TObjType* inObj, TInfoType& info); template inline void readComplexObj( TReaderType& oldVisitor, TObjType* inObj); template inline PxGeometry* parseGeometry( TReaderType& reader, TGeomType& /*inGeom*/) { PxAllocatorCallback& inAllocator = reader.mAllocator.getAllocator(); TGeomType* shape = PX_PLACEMENT_NEW((inAllocator.allocate(sizeof(TGeomType), "parseGeometry", __FILE__, __LINE__ )), TGeomType); PxClassInfoTraits info; readComplexObj( reader, shape); return shape; } template inline void parseShape( TReaderType& visitor, PxGeometry*& outResult, Ps::Array& outMaterials) { XmlReader& theReader( visitor.mReader ); PxCollection& collection = visitor.mCollection; visitor.pushCurrentContext(); if ( visitor.gotoTopName() ) { visitor.pushCurrentContext(); if ( visitor.gotoChild( "Materials" ) ) { for( bool matSuccess = visitor.gotoFirstChild(); matSuccess; matSuccess = visitor.gotoNextSibling() ) { PxMaterial* material = NULL; if(!readReference( theReader, collection, material )) visitor.mHadError = true; if ( material ) outMaterials.pushBack( material ); } } visitor.popCurrentContext(); visitor.pushCurrentContext(); PxPlaneGeometry plane; PxHeightFieldGeometry heightField; PxSphereGeometry sphere; PxTriangleMeshGeometry mesh; PxConvexMeshGeometry convex; PxBoxGeometry box; PxCapsuleGeometry capsule; if ( visitor.gotoChild( "Geometry" ) ) { if ( visitor.gotoFirstChild() ) { const char* geomTypeName = visitor.getCurrentItemName(); if ( physx::shdfnd::stricmp( geomTypeName, "PxSphereGeometry" ) == 0 ) outResult = parseGeometry(visitor, sphere); else if ( physx::shdfnd::stricmp( geomTypeName, "PxPlaneGeometry" ) == 0 ) outResult = parseGeometry(visitor, plane); else if ( physx::shdfnd::stricmp( geomTypeName, "PxCapsuleGeometry" ) == 0 ) outResult = parseGeometry(visitor, capsule); else if ( physx::shdfnd::stricmp( geomTypeName, "PxBoxGeometry" ) == 0 ) outResult = parseGeometry(visitor, box); else if ( physx::shdfnd::stricmp( geomTypeName, "PxConvexMeshGeometry" ) == 0 ) outResult = parseGeometry(visitor, convex); else if ( physx::shdfnd::stricmp( geomTypeName, "PxTriangleMeshGeometry" ) == 0 ) outResult = parseGeometry(visitor, mesh); else if ( physx::shdfnd::stricmp( geomTypeName, "PxHeightFieldGeometry" ) == 0 ) outResult = parseGeometry(visitor, heightField); else PX_ASSERT( false ); } } visitor.popCurrentContext(); } visitor.popCurrentContext(); return; } template inline void readShapesProperty( TReaderType& visitor, TObjType* inObj, const PxRigidActorShapeCollection* inProp = NULL, bool isSharedShape = false ) { PX_UNUSED(isSharedShape); PX_UNUSED(inProp); XmlReader& theReader( visitor.mReader ); PxCollection& collection( visitor.mCollection ); visitor.pushCurrentContext(); if ( visitor.gotoTopName() ) { //uggh working around the shape collection api. //read out materials and geometry for ( bool success = visitor.gotoFirstChild(); success; success = visitor.gotoNextSibling() ) { if( 0 == physx::shdfnd::stricmp( visitor.getCurrentItemName(), "PxShapeRef" ) ) { PxShape* shape = NULL; if(!readReference( theReader, collection, shape )) visitor.mHadError = true; if(shape) inObj->attachShape( *shape ); } else { Ps::Array materials; PxGeometry* geometry = NULL; parseShape( visitor, geometry, materials); PxShape* theShape = NULL; if ( materials.size() ) { theShape = visitor.mArgs.physics.createShape( *geometry, materials.begin(), Ps::to16(materials.size()), true ); if ( theShape ) { readComplexObj( visitor, theShape ); if(theShape) { inObj->attachShape(*theShape); collection.add( *theShape ); } } } switch(geometry->getType()) { case PxGeometryType::eSPHERE : static_cast(geometry)->~PxSphereGeometry(); break; case PxGeometryType::ePLANE : static_cast(geometry)->~PxPlaneGeometry(); break; case PxGeometryType::eCAPSULE : static_cast(geometry)->~PxCapsuleGeometry(); break; case PxGeometryType::eBOX : static_cast(geometry)->~PxBoxGeometry(); break; case PxGeometryType::eCONVEXMESH : static_cast(geometry)->~PxConvexMeshGeometry(); break; case PxGeometryType::eTRIANGLEMESH : static_cast(geometry)->~PxTriangleMeshGeometry(); break; case PxGeometryType::eHEIGHTFIELD : static_cast(geometry)->~PxHeightFieldGeometry(); break; case PxGeometryType::eGEOMETRY_COUNT: case PxGeometryType::eINVALID: PX_ASSERT(0); } visitor.mAllocator.getAllocator().deallocate(geometry); } } } visitor.popCurrentContext(); } struct ReaderNameStackEntry : NameStackEntry { bool mValid; ReaderNameStackEntry( const char* nm, bool valid ) : NameStackEntry(nm), mValid(valid) {} }; typedef PxProfileArray TReaderNameStack; template struct RepXVisitorReaderBase { protected: RepXVisitorReaderBase& operator=(const RepXVisitorReaderBase&); public: TReaderNameStack& mNames; PxProfileArray& mContexts; PxRepXInstantiationArgs mArgs; XmlReader& mReader; TObjType* mObj; XmlMemoryAllocator& mAllocator; PxCollection& mCollection; bool mValid; bool& mHadError; RepXVisitorReaderBase( TReaderNameStack& names, PxProfileArray& contexts, const PxRepXInstantiationArgs& args, XmlReader& reader, TObjType* obj , XmlMemoryAllocator& alloc, PxCollection& collection, bool& hadError ) : mNames( names ) , mContexts( contexts ) , mArgs( args ) , mReader( reader ) , mObj( obj ) , mAllocator( alloc ) , mCollection( collection ) , mValid( true ) , mHadError(hadError) { } RepXVisitorReaderBase( const RepXVisitorReaderBase& other ) : mNames( other.mNames ) , mContexts( other.mContexts ) , mArgs( other.mArgs ) , mReader( other.mReader ) , mObj( other.mObj ) , mAllocator( other.mAllocator ) , mCollection( other.mCollection ) , mValid( other.mValid ) , mHadError( other.mHadError ) { } void pushName( const char* name ) { gotoTopName(); mNames.pushBack( ReaderNameStackEntry( name, mValid ) ); } void pushBracketedName( const char* name ) { pushName( name ); } void popName() { if ( mNames.size() ) { if ( mNames.back().mOpen && mNames.back().mValid ) mReader.leaveChild(); mNames.popBack(); } mValid =true; if ( mNames.size() && mNames.back().mValid == false ) mValid = false; } void pushCurrentContext() { mContexts.pushBack( static_cast( mNames.size() ) ); } void popCurrentContext() { if ( mContexts.size() ) { PxU32 depth = mContexts.back(); PX_ASSERT( mNames.size() >= depth ); while( mNames.size() > depth ) popName(); mContexts.popBack(); } } bool updateLastEntryAfterOpen() { mNames.back().mValid = mValid; mNames.back().mOpen = mValid; return mValid; } bool gotoTopName() { if ( mNames.size() && mNames.back().mOpen == false ) { if ( mValid ) mValid = mReader.gotoChild( mNames.back().mName ); updateLastEntryAfterOpen(); } return mValid; } bool isValid() const { return mValid; } bool gotoChild( const char* name ) { pushName( name ); return gotoTopName(); } bool gotoFirstChild() { pushName( "__child" ); if ( mValid ) mValid = mReader.gotoFirstChild(); return updateLastEntryAfterOpen(); } bool gotoNextSibling() { bool retval = mValid; if ( mValid ) retval = mReader.gotoNextSibling(); return retval; } const char* getCurrentItemName() { if (mValid ) return mReader.getCurrentItemName(); return ""; } const char* topName() const { if ( mNames.size() ) return mNames.back().mName; PX_ASSERT( false ); return "bad__repx__name"; } const char* getCurrentValue() { const char* value = NULL; if ( isValid() && mReader.read( topName(), value ) ) return value; return NULL; } template bool readProperty(TDataType& outType) { const char* value = getCurrentValue(); if ( value && *value ) { stringToType( value, outType ); return true; } return false; } template bool readExtendedIndexProperty(TDataType& outType) { const char* value = mReader.getCurrentItemValue(); if ( value && *value ) { stringToType( value, outType ); return true; } return false; } template bool readReference(TRefType*& outRef) { return physx::Sn::readReference( mReader, mCollection, topName(), outRef ); } inline bool readProperty(const char*& outProp ) { outProp = ""; const char* value = getCurrentValue(); if ( value && *value && mArgs.stringTable ) { outProp = mArgs.stringTable->allocateStr( value ); return true; } return false; } inline bool readProperty(PxConvexMesh*& outProp ) { return readReference( outProp ); } inline bool readProperty(PxTriangleMesh*& outProp ) { return readReference( outProp ); } inline bool readProperty(PxBVH33TriangleMesh*& outProp ) { return readReference( outProp ); } inline bool readProperty(PxBVH34TriangleMesh*& outProp ) { return readReference( outProp ); } inline bool readProperty(PxHeightField*& outProp ) { return readReference( outProp ); } inline bool readProperty( PxRigidActor *& outProp ) { return readReference( outProp ); } template void simpleProperty( PxU32 /*key*/, TAccessorType& inProp ) { typedef typename TAccessorType::prop_type TPropertyType; TPropertyType value; if ( readProperty( value ) ) inProp.set( mObj, value ); } template void enumProperty( PxU32 /*key*/, TAccessorType& inProp, const PxU32ToName* inConversions ) { typedef typename TAccessorType::prop_type TPropertyType; const char* strVal = getCurrentValue(); if ( strVal && *strVal ) { TPropertyType pval; stringToEnumType( strVal, pval, inConversions ); inProp.set( mObj, pval ); } } template void flagsProperty( PxU32 /*key*/, const TAccessorType& inProp, const PxU32ToName* inConversions ) { typedef typename TAccessorType::prop_type TPropertyType; typedef typename TPropertyType::InternalType TInternalType; const char* strVal = getCurrentValue(); if ( strVal && *strVal ) { PxU32 tempValue = 0; stringToFlagsType( strVal, mAllocator, tempValue, inConversions ); inProp.set( mObj, TPropertyType(TInternalType( tempValue ))); } } template void complexProperty( PxU32* /*key*/, const TAccessorType& inProp, TInfoType& inInfo ) { typedef typename TAccessorType::prop_type TPropertyType; if ( gotoTopName() ) { TPropertyType propVal = inProp.get( mObj ); readComplexObj( *this, &propVal, inInfo ); inProp.set( mObj, propVal ); } } template void bufferCollectionProperty( PxU32* /*key*/, const TAccessorType& inProp, TInfoType& inInfo ) { typedef typename TAccessorType::prop_type TPropertyType; Ps::InlineArray theData; this->pushCurrentContext(); if ( this->gotoTopName() ) { for ( bool success = this->gotoFirstChild(); success; success = this->gotoNextSibling() ) { TPropertyType propVal; readComplexObj( *this, &propVal, inInfo ); theData.pushBack(propVal); } } this->popCurrentContext(); inProp.set( mObj, theData.begin(), theData.size() ); } template void extendedIndexedProperty( PxU32* /*key*/, const TAccessorType& inProp, TInfoType& inInfo ) { typedef typename TAccessorType::prop_type TPropertyType; this->pushCurrentContext(); if ( this->gotoTopName() ) { PxU32 index = 0; for ( bool success = this->gotoFirstChild(); success; success = this->gotoNextSibling() ) { TPropertyType propVal; readComplexObj( *this, &propVal, inInfo ); inProp.set(mObj, index, propVal); ++index; } } this->popCurrentContext(); } template void PxFixedSizeLookupTableProperty( PxU32* /*key*/, const TAccessorType& inProp, TInfoType& inInfo ) { typedef typename TAccessorType::prop_type TPropertyType; const_cast(inProp).clear( mObj ); this->pushCurrentContext(); if ( this->gotoTopName() ) { for ( bool success = this->gotoFirstChild(); success; success = this->gotoNextSibling() ) { TPropertyType propXVal; readComplexObj( *this, &propXVal, inInfo ); if(this->gotoNextSibling()) { TPropertyType propYVal; readComplexObj( *this, &propYVal, inInfo ); const_cast(inProp).addPair(mObj, propXVal, propYVal); } } } this->popCurrentContext(); } void handleShapes( const PxRigidActorShapeCollection& inProp ) { physx::Sn::readShapesProperty( *this, mObj, &inProp ); } void handleRigidActorGlobalPose(const PxRigidActorGlobalPosePropertyInfo& inProp) { PxArticulationLink* link = mObj->template is(); bool isReducedCoordinateLink = (link != NULL) && link->getArticulation().getConcreteType() == PxConcreteType::eARTICULATION_REDUCED_COORDINATE; if (!isReducedCoordinateLink) { PxRepXPropertyAccessor theAccessor( inProp ); simpleProperty(PxPropertyInfoName::PxRigidActor_GlobalPose, theAccessor); } } }; template struct RepXVisitorReader : public RepXVisitorReaderBase { RepXVisitorReader( TReaderNameStack& names, PxProfileArray& contexts, const PxRepXInstantiationArgs& args, XmlReader& reader, TObjType* obj , XmlMemoryAllocator& alloc, PxCollection& collection, bool& ret) : RepXVisitorReaderBase( names, contexts, args, reader, obj, alloc, collection, ret) { } RepXVisitorReader( const RepXVisitorReader& other ) : RepXVisitorReaderBase( other ) { } }; // Specialized template to load dynamic rigid, to determine the kinematic state first template<> struct RepXVisitorReader : public RepXVisitorReaderBase { RepXVisitorReader( TReaderNameStack& names, PxProfileArray& contexts, const PxRepXInstantiationArgs& args, XmlReader& reader, PxRigidDynamic* obj , XmlMemoryAllocator& alloc, PxCollection& collection, bool& ret) : RepXVisitorReaderBase( names, contexts, args, reader, obj, alloc, collection, ret) { } RepXVisitorReader( const RepXVisitorReader& other ) : RepXVisitorReaderBase( other ) { } void handleShapes( const PxRigidActorShapeCollection& inProp ) { // Need to read the parental actor to check if actor is kinematic // in that case we need to apply the kinematic flag before a shape is set XmlReaderWriter* parentReader = static_cast(mReader.getParentReader()); if(mObj) { const char* value; if (parentReader->read( "RigidBodyFlags", value )) { if(strstr(value, "eKINEMATIC")) { mObj->setRigidBodyFlag(PxRigidBodyFlag::eKINEMATIC, true); } } } physx::Sn::readShapesProperty( *this, mObj, &inProp ); parentReader->release(); } template void simpleProperty( PxU32 /*key*/, TAccessorType& inProp ) { typedef typename TAccessorType::prop_type TPropertyType; TPropertyType value; if (readProperty(value)) { // If the rigid body is kinematic, we cannot set the LinearVelocity or AngularVelocity const bool kinematic = (mObj->getRigidBodyFlags() & PxRigidBodyFlag::eKINEMATIC); if(kinematic && (inProp.mProperty.mKey == PxPropertyInfoName::PxRigidBody_LinearVelocity || inProp.mProperty.mKey == PxPropertyInfoName::PxRigidBody_AngularVelocity)) return; inProp.set(mObj, value ); } } private: RepXVisitorReader& operator=(const RepXVisitorReader&); }; template<> struct RepXVisitorReader : public RepXVisitorReaderBase { RepXVisitorReader( TReaderNameStack& names, PxProfileArray& contexts, const PxRepXInstantiationArgs& args, XmlReader& reader, PxShape* obj , XmlMemoryAllocator& alloc, PxCollection& collection, bool& ret ) : RepXVisitorReaderBase( names, contexts, args, reader, obj, alloc, collection, ret ) { } RepXVisitorReader( const RepXVisitorReader& other ) : RepXVisitorReaderBase( other ) { } void handleShapeMaterials( const PxShapeMaterialsProperty& ) //these were handled during construction. { } void handleGeometryProperty( const PxShapeGeometryProperty& ) { } private: RepXVisitorReader& operator=(const RepXVisitorReader&); }; template<> struct RepXVisitorReader : public RepXVisitorReaderBase { RepXVisitorReader( TReaderNameStack& names, PxProfileArray& contexts, const PxRepXInstantiationArgs& args, XmlReader& reader, PxArticulationLink* obj , XmlMemoryAllocator& alloc, PxCollection& collection, bool& ret ) : RepXVisitorReaderBase( names, contexts, args, reader, obj, alloc, collection, ret ) { } RepXVisitorReader( const RepXVisitorReader& other ) : RepXVisitorReaderBase( other ) { } void handleIncomingJoint( const TIncomingJointPropType& prop ) { pushName( "Joint" ); if ( gotoTopName() ) { PxArticulationBase& articulationBase = mObj->getArticulation(); if (articulationBase.getConcreteType() == PxConcreteType::eARTICULATION) { PxArticulationJoint* theJoint = static_cast((prop.get(mObj))); readComplexObj(*this, theJoint); //Add joint to PxCollection, since PxArticulation requires PxArticulationLink and joint. mCollection.add(*theJoint); } else { PX_ASSERT(articulationBase.getConcreteType() == PxConcreteType::eARTICULATION_REDUCED_COORDINATE); PxArticulationJointReducedCoordinate* theJoint = static_cast((prop.get(mObj))); readComplexObj(*this, theJoint); //Add joint to PxCollection, since PxArticulation requires PxArticulationLink and joint. mCollection.add(*theJoint); } } popName(); } private: RepXVisitorReader& operator=(const RepXVisitorReader&); }; template inline void readProperty( RepXVisitorReaderBase& inSerializer, ArticulationType* inObj, const PxArticulationLinkCollectionProp&) { PxProfileAllocatorWrapper theWrapper( inSerializer.mAllocator.getAllocator() ); PxCollection& collection( inSerializer.mCollection ); TArticulationLinkLinkMap linkRemapMap( theWrapper ); inSerializer.pushCurrentContext(); if( inSerializer.gotoTopName() ) { for ( bool links = inSerializer.gotoFirstChild(); links != false; links = inSerializer.gotoNextSibling() ) { //Need enough information to create the link... PxSerialObjectId theParentPtr = 0; const PxArticulationLink* theParentLink = NULL; if ( inSerializer.mReader.read( "Parent", theParentPtr ) ) { const TArticulationLinkLinkMap::Entry* theRemappedParent( linkRemapMap.find( theParentPtr ) ); //If we have a valid at write time, we had better have a valid parent at read time. PX_ASSERT( theRemappedParent ); theParentLink = theRemappedParent->second; } PxArticulationLink* newLink = inObj->createLink( const_cast( theParentLink ), PxTransform(PxIdentity) ); PxSerialObjectId theIdPtr = 0; inSerializer.mReader.read( "Id", theIdPtr ); linkRemapMap.insert( theIdPtr, newLink ); readComplexObj( inSerializer, newLink ); //Add link to PxCollection, since PxArticulation requires PxArticulationLink and joint. collection.add( *newLink, theIdPtr ); } } inSerializer.popCurrentContext(); } template<> struct RepXVisitorReader : public RepXVisitorReaderBase { RepXVisitorReader( TReaderNameStack& names, PxProfileArray& contexts, const PxRepXInstantiationArgs& args, XmlReader& reader, PxArticulation* obj , XmlMemoryAllocator& alloc, PxCollection& collection, bool& ret) : RepXVisitorReaderBase( names, contexts, args, reader, obj, alloc, collection, ret) { } RepXVisitorReader( const RepXVisitorReader& other ) : RepXVisitorReaderBase( other ) { } void handleArticulationLinks( const PxArticulationLinkCollectionProp& inProp ) { physx::Sn::readProperty( *this, mObj, inProp ); } }; template<> struct RepXVisitorReader : public RepXVisitorReaderBase { RepXVisitorReader(TReaderNameStack& names, PxProfileArray& contexts, const PxRepXInstantiationArgs& args, XmlReader& reader, PxArticulationReducedCoordinate* obj , XmlMemoryAllocator& alloc, PxCollection& collection, bool& ret) : RepXVisitorReaderBase(names, contexts, args, reader, obj, alloc, collection, ret) {} RepXVisitorReader(const RepXVisitorReader& other) : RepXVisitorReaderBase(other) {} void handleArticulationLinks(const PxArticulationLinkCollectionProp& inProp) { physx::Sn::readProperty(*this, mObj, inProp); } }; template inline bool readAllProperties( PxRepXInstantiationArgs args, TReaderNameStack& names, PxProfileArray& contexts, XmlReader& reader, TObjType* obj, XmlMemoryAllocator& alloc, PxCollection& collection, TInfoType& info ) { bool hadError = false; RepXVisitorReader theReader( names, contexts, args, reader, obj, alloc, collection, hadError); RepXPropertyFilter > theOp( theReader ); info.visitBaseProperties( theOp ); info.visitInstanceProperties( theOp ); return !hadError; } template inline bool readAllProperties( PxRepXInstantiationArgs args, XmlReader& reader, TObjType* obj, XmlMemoryAllocator& alloc, PxCollection& collection ) { PxProfileAllocatorWrapper wrapper( alloc.getAllocator() ); TReaderNameStack names( wrapper ); PxProfileArray contexts( wrapper ); PxClassInfoTraits info; return readAllProperties( args, names, contexts, reader, obj, alloc, collection, info.Info ); } template inline void readComplexObj( TReaderType& oldVisitor, TObjType* inObj, TInfoType& info) { if(!readAllProperties( oldVisitor.mArgs, oldVisitor.mNames, oldVisitor.mContexts, oldVisitor.mReader, inObj, oldVisitor.mAllocator, oldVisitor.mCollection, info )) oldVisitor.mHadError = true; } template inline void readComplexObj( TReaderType& oldVisitor, TObjType* inObj, const TInfoType& info) { if(!readAllProperties( oldVisitor.mArgs, oldVisitor.mNames, oldVisitor.mContexts, oldVisitor.mReader, inObj, oldVisitor.mAllocator, oldVisitor.mCollection, info )) oldVisitor.mHadError = true; } template inline void readComplexObj( TReaderType& oldVisitor, TObjType* inObj, const PxUnknownClassInfo& /*info*/) { const char* value = oldVisitor.mReader.getCurrentItemValue(); if ( value && *value ) { stringToType( value, *inObj ); return; } oldVisitor.mHadError = true; } template inline void readComplexObj( TReaderType& oldVisitor, TObjType* inObj) { PxClassInfoTraits info; if(!readAllProperties( oldVisitor.mArgs, oldVisitor.mNames, oldVisitor.mContexts, oldVisitor.mReader, inObj, oldVisitor.mAllocator, oldVisitor.mCollection, info.Info )) oldVisitor.mHadError = true; } } } #endif