// // 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-2018 NVIDIA Corporation. All rights reserved. // Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. // Copyright (c) 2001-2004 NovodeX AG. All rights reserved. #include "SnXmlImpl.h" #include "PsHash.h" #include "PsHashMap.h" #include "SnSimpleXmlWriter.h" #include "PsSort.h" #include "PsFastXml.h" #include "PsString.h" #include "SnXmlMemoryPool.h" #include "PxExtensionMetaDataObjects.h" #include "SnXmlVisitorWriter.h" #include "SnXmlVisitorReader.h" #include "SnXmlMemoryAllocator.h" #include "SnXmlStringToType.h" #include "PsString.h" #include "SnRepXCollection.h" #include "SnRepXUpgrader.h" #include "../SnSerializationRegistry.h" #include "PsFoundation.h" #include "CmCollection.h" using namespace physx; using namespace Sn; using namespace physx::profile; //for the foundation wrapper system. namespace physx { namespace Sn { class XmlNodeWriter : public SimpleXmlWriter { XmlMemoryAllocatorImpl& mParseAllocator; XmlNode* mCurrentNode; XmlNode* mTopNode; PxU32 mTabCount; public: XmlNodeWriter( XmlMemoryAllocatorImpl& inAllocator, PxU32 inTabCount = 0 ) : mParseAllocator( inAllocator ) , mCurrentNode( NULL ) , mTopNode( NULL ) , mTabCount( inTabCount ) {} XmlNodeWriter& operator=(const XmlNodeWriter&); virtual ~XmlNodeWriter(){} void onNewNode( XmlNode* newNode ) { if ( mCurrentNode != NULL ) mCurrentNode->addChild( newNode ); if ( mTopNode == NULL ) mTopNode = newNode; mCurrentNode = newNode; ++mTabCount; } XmlNode* getTopNode() const { return mTopNode; } virtual void beginTag( const char* inTagname ) { onNewNode( allocateRepXNode( &mParseAllocator.mManager, inTagname, NULL ) ); } virtual void endTag() { if ( mCurrentNode ) mCurrentNode = mCurrentNode->mParent; if ( mTabCount ) --mTabCount; } virtual void addAttribute( const char*, const char* ) { PX_ASSERT( false ); } virtual void writeContentTag( const char* inTag, const char* inContent ) { onNewNode( allocateRepXNode( &mParseAllocator.mManager, inTag, inContent ) ); endTag(); } virtual void addContent( const char* inContent ) { if ( mCurrentNode->mData ) releaseStr( &mParseAllocator.mManager, mCurrentNode->mData ); mCurrentNode->mData = copyStr( &mParseAllocator.mManager, inContent ); } virtual PxU32 tabCount() { return mTabCount; } }; struct XmlWriterImpl : public XmlWriter { PxU32 mTagDepth; SimpleXmlWriter* mWriter; MemoryBuffer* mMemBuffer; XmlWriterImpl( SimpleXmlWriter* inWriter, MemoryBuffer* inMemBuffer ) : mTagDepth( 0 ) , mWriter( inWriter ) , mMemBuffer( inMemBuffer ) { } ~XmlWriterImpl() { while( mTagDepth ) { --mTagDepth; mWriter->endTag(); } } virtual void write( const char* inName, const char* inData ) { mWriter->writeContentTag( inName, inData ); } virtual void write( const char* inName, const PxRepXObject& inLiveObject ) { (*mMemBuffer) << inLiveObject.id; writeProperty( *mWriter, *mMemBuffer, inName ); } virtual void addAndGotoChild( const char* inName ) { mWriter->beginTag( inName ); mTagDepth++; } virtual void leaveChild() { if ( mTagDepth ) { mWriter->endTag(); --mTagDepth; } } }; struct XmlParseArgs { XmlMemoryAllocatorImpl* mAllocator; PxProfileArray* mCollection; XmlParseArgs( XmlMemoryAllocatorImpl* inAllocator , PxProfileArray* inCollection) : mAllocator( inAllocator ) , mCollection( inCollection ) { } }; struct XmlNodeReader : public XmlReaderWriter { PxProfileAllocatorWrapper mWrapper; CMemoryPoolManager& mManager; XmlNode* mCurrentNode; XmlNode* mTopNode; PxProfileArray mContext; XmlNodeReader( XmlNode* inCurrentNode, PxAllocatorCallback& inAllocator, CMemoryPoolManager& nodePoolManager ) : mWrapper( inAllocator ) , mManager( nodePoolManager ) , mCurrentNode( inCurrentNode ) , mTopNode( inCurrentNode ) , mContext( mWrapper ) { } //Does this node exist as data in the format. virtual bool read( const char* inName, const char*& outData ) { XmlNode* theChild( mCurrentNode->findChildByName( inName ) ); if ( theChild ) { outData = theChild->mData; return outData && *outData; } return false; } virtual bool read( const char* inName, PxSerialObjectId& outId ) { XmlNode* theChild( mCurrentNode->findChildByName( inName ) ); if ( theChild ) { const char* theValue( theChild->mData ); strto( outId, theValue ); return true; } return false; } virtual bool gotoChild( const char* inName ) { XmlNode* theChild( mCurrentNode->findChildByName( inName ) ); if ( theChild ) { mCurrentNode =theChild; return true; } return false; } virtual bool gotoFirstChild() { if ( mCurrentNode->mFirstChild ) { mCurrentNode = mCurrentNode->mFirstChild; return true; } return false; } virtual bool gotoNextSibling() { if ( mCurrentNode->mNextSibling ) { mCurrentNode = mCurrentNode->mNextSibling; return true; } return false; } virtual PxU32 countChildren() { PxU32 retval= 0; for ( XmlNode* theChild = mCurrentNode->mFirstChild; theChild != NULL; theChild = theChild->mNextSibling ) ++retval; return retval; } virtual const char* getCurrentItemName() { return mCurrentNode->mName; } virtual const char* getCurrentItemValue() { return mCurrentNode->mData; } virtual bool leaveChild() { if ( mCurrentNode != mTopNode && mCurrentNode->mParent ) { mCurrentNode = mCurrentNode->mParent; return true; } return false; } virtual void pushCurrentContext() { mContext.pushBack( mCurrentNode ); } virtual void popCurrentContext() { if ( mContext.size() ) { mCurrentNode = mContext.back(); mContext.popBack(); } } virtual void setNode( XmlNode& inNode ) { mContext.clear(); mCurrentNode = &inNode; mTopNode = mCurrentNode; } virtual XmlReader* getParentReader() { XmlReader* retval = PX_PLACEMENT_NEW((mWrapper.getAllocator().allocate(sizeof(XmlNodeReader), "createNodeEditor", __FILE__, __LINE__ )), XmlNodeReader) ( mTopNode, mWrapper.getAllocator(), mManager ); return retval; } virtual void addOrGotoChild( const char* inName ) { if ( gotoChild( inName )== false ) { XmlNode* newNode = allocateRepXNode( &mManager, inName, NULL ); mCurrentNode->addChild( newNode ); mCurrentNode = newNode; } } virtual void setCurrentItemValue( const char* inValue ) { mCurrentNode->mData = copyStr( &mManager, inValue ); } virtual bool removeChild( const char* name ) { XmlNode* theChild( mCurrentNode->findChildByName( name ) ); if ( theChild ) { releaseNodeAndChildren( &mManager, theChild ); return true; } return false; } virtual void release() { this->~XmlNodeReader(); mWrapper.getAllocator().deallocate(this); } private: XmlNodeReader& operator=(const XmlNodeReader&); }; PX_INLINE void freeNodeAndChildren( XmlNode* tempNode, TMemoryPoolManager& inManager ) { for( XmlNode* theNode = tempNode->mFirstChild; theNode != NULL; theNode = theNode->mNextSibling ) freeNodeAndChildren( theNode, inManager ); tempNode->orphan(); release( &inManager, tempNode ); } class XmlParser : public Ps::FastXml::Callback { XmlParseArgs mParseArgs; //For parse time only allocations XmlMemoryAllocatorImpl& mParseAllocator; XmlNode* mCurrentNode; XmlNode* mTopNode; public: XmlParser( XmlParseArgs inArgs, XmlMemoryAllocatorImpl& inParseAllocator ) : mParseArgs( inArgs ) , mParseAllocator( inParseAllocator ) , mCurrentNode( NULL ) , mTopNode( NULL ) { } virtual ~XmlParser(){} virtual bool processComment(const char* /*comment*/) { return true; } // 'element' is the name of the element that is being closed. // depth is the recursion depth of this element. // Return true to continue processing the XML file. // Return false to stop processing the XML file; leaves the read pointer of the stream right after this close tag. // The bool 'isError' indicates whether processing was stopped due to an error, or intentionally canceled early. virtual bool processClose(const char* /*element*/,physx::PxU32 /*depth*/,bool& /*isError*/) { mCurrentNode = mCurrentNode->mParent; return true; } // return true to continue processing the XML document, false to skip. virtual bool processElement( const char *elementName, // name of the element const char *elementData, // element data, null if none const Ps::FastXml::AttributePairs& attr, // attributes PxI32 /*lineno*/) { XmlNode* newNode = allocateRepXNode( &mParseAllocator.mManager, elementName, elementData ); if ( mCurrentNode ) mCurrentNode->addChild( newNode ); mCurrentNode = newNode; //Add the elements as children. for( PxI32 item = 0; item < attr.getNbAttr(); item ++ ) { XmlNode* node = allocateRepXNode( &mParseAllocator.mManager, attr.getKey(PxU32(item)), attr.getValue(PxU32(item)) ); mCurrentNode->addChild( node ); } if ( mTopNode == NULL ) mTopNode = newNode; return true; } XmlNode* getTopNode() { return mTopNode; } virtual void * allocate(PxU32 size) { if ( size ) return mParseAllocator.allocate(size); return NULL; } virtual void deallocate(void *mem) { if ( mem ) mParseAllocator.deallocate(reinterpret_cast(mem)); } private: XmlParser& operator=(const XmlParser&); }; struct RepXCollectionSharedData { PxProfileAllocatorWrapper mWrapper; XmlMemoryAllocatorImpl mAllocator; PxU32 mRefCount; RepXCollectionSharedData( PxAllocatorCallback& inAllocator ) : mWrapper( inAllocator ) , mAllocator( inAllocator ) , mRefCount( 0 ) { } ~RepXCollectionSharedData() {} void addRef() { ++mRefCount;} void release() { if ( mRefCount ) --mRefCount; if ( !mRefCount ) { this->~RepXCollectionSharedData(); mWrapper.getAllocator().deallocate(this);} } }; struct SharedDataPtr { RepXCollectionSharedData* mData; SharedDataPtr( RepXCollectionSharedData* inData ) : mData( inData ) { mData->addRef(); } SharedDataPtr( const SharedDataPtr& inOther ) : mData( inOther.mData ) { mData->addRef(); } SharedDataPtr& operator=( const SharedDataPtr& inOther ); ~SharedDataPtr() { mData->release(); mData = NULL; } RepXCollectionSharedData* operator->() { return mData; } const RepXCollectionSharedData* operator->() const { return mData; } }; class RepXCollectionImpl : public RepXCollection, public Ps::UserAllocated { SharedDataPtr mSharedData; XmlMemoryAllocatorImpl& mAllocator; PxSerializationRegistry& mSerializationRegistry; PxProfileArray mCollection; TMemoryPoolManager mSerializationManager; MemoryBuffer mPropertyBuffer; PxTolerancesScale mScale; PxVec3 mUpVector; const char* mVersionStr; PxCollection* mPxCollection; public: RepXCollectionImpl( PxSerializationRegistry& inRegistry, PxAllocatorCallback& inAllocator, PxCollection& inPxCollection ) : mSharedData( &PX_NEW_REPX_SERIALIZER( RepXCollectionSharedData )) , mAllocator( mSharedData->mAllocator ) , mSerializationRegistry( inRegistry ) , mCollection( mSharedData->mWrapper ) , mSerializationManager( inAllocator ) , mPropertyBuffer( &mSerializationManager ) , mUpVector( 0,0,0 ) , mVersionStr( getLatestVersion() ) , mPxCollection( &inPxCollection ) { memset( &mScale, 0, sizeof( PxTolerancesScale ) ); PX_ASSERT( mScale.isValid() == false ); } RepXCollectionImpl( PxSerializationRegistry& inRegistry, const RepXCollectionImpl& inSrc, const char* inNewVersion ) : mSharedData( inSrc.mSharedData ) , mAllocator( mSharedData->mAllocator ) , mSerializationRegistry( inRegistry ) , mCollection( mSharedData->mWrapper ) , mSerializationManager( mSharedData->mWrapper.getAllocator() ) , mPropertyBuffer( &mSerializationManager ) , mScale( inSrc.mScale ) , mUpVector( inSrc.mUpVector ) , mVersionStr( inNewVersion ) , mPxCollection( NULL ) { } virtual ~RepXCollectionImpl() { PxU32 numItems = mCollection.size(); for ( PxU32 idx = 0; idx < numItems; ++idx ) { XmlNode* theNode = mCollection[idx].descriptor; releaseNodeAndChildren( &mAllocator.mManager, theNode ); } } RepXCollectionImpl& operator=(const RepXCollectionImpl&); virtual void destroy() { PxProfileAllocatorWrapper tempWrapper( mSharedData->mWrapper.getAllocator() ); this->~RepXCollectionImpl(); tempWrapper.getAllocator().deallocate(this); } virtual void setTolerancesScale(const PxTolerancesScale& inScale) { mScale = inScale; } virtual PxTolerancesScale getTolerancesScale() const { return mScale; } virtual void setUpVector( const PxVec3& inUpVector ) { mUpVector = inUpVector; } virtual PxVec3 getUpVector() const { return mUpVector; } PX_INLINE RepXCollectionItem findItemBySceneItem( const PxRepXObject& inObject ) const { //See if the object is in the collection for ( PxU32 idx =0; idx < mCollection.size(); ++idx ) if ( mCollection[idx].liveObject.serializable == inObject.serializable ) return mCollection[idx]; return RepXCollectionItem(); } virtual RepXAddToCollectionResult addRepXObjectToCollection( const PxRepXObject& inObject, PxCollection* inCollection, PxRepXInstantiationArgs& inArgs ) { PX_ASSERT( inObject.serializable ); PX_ASSERT( inObject.id ); if ( inObject.serializable == NULL || inObject.id == 0 ) return RepXAddToCollectionResult( RepXAddToCollectionResult::InvalidParameters ); PxRepXSerializer* theSerializer = mSerializationRegistry.getRepXSerializer( inObject.typeName ); if ( theSerializer == NULL ) return RepXAddToCollectionResult( RepXAddToCollectionResult::SerializerNotFound ); RepXCollectionItem existing = findItemBySceneItem( inObject ); if ( existing.liveObject.serializable ) return RepXAddToCollectionResult( RepXAddToCollectionResult::AlreadyInCollection, existing.liveObject.id ); XmlNodeWriter theXmlWriter( mAllocator, 1 ); XmlWriterImpl theRepXWriter( &theXmlWriter, &mPropertyBuffer ); { SimpleXmlWriter::STagWatcher theWatcher( theXmlWriter, inObject.typeName ); writeProperty( theXmlWriter, mPropertyBuffer, "Id", inObject.id ); theSerializer->objectToFile( inObject, inCollection, theRepXWriter, mPropertyBuffer,inArgs ); } mCollection.pushBack( RepXCollectionItem( inObject, theXmlWriter.getTopNode() ) ); return RepXAddToCollectionResult( RepXAddToCollectionResult::Success, inObject.id ); } virtual bool instantiateCollection( PxRepXInstantiationArgs& inArgs, PxCollection& inCollection ) { for ( PxU32 idx =0; idx < mCollection.size(); ++idx ) { RepXCollectionItem theItem( mCollection[idx] ); PxRepXSerializer* theSerializer = mSerializationRegistry.getRepXSerializer( theItem.liveObject.typeName ); if (theSerializer ) { XmlNodeReader theReader( theItem.descriptor, mAllocator.getAllocator(), mAllocator.mManager ); XmlMemoryAllocatorImpl instantiationAllocator( mAllocator.getAllocator() ); PxRepXObject theLiveObject = theSerializer->fileToObject( theReader, instantiationAllocator, inArgs, &inCollection ); if (theLiveObject.isValid()) { const PxBase* s = reinterpret_cast( theLiveObject.serializable ) ; inCollection.add( *const_cast(s), PxSerialObjectId( theItem.liveObject.id )); } else return false; } else { Ps::getFoundation().error(PxErrorCode::eINTERNAL_ERROR, __FILE__, __LINE__, "PxSerialization::createCollectionFromXml: " "PxRepXSerializer missing for type %s", theItem.liveObject.typeName); return false; } } return true; } void saveXmlNode( XmlNode* inNode, SimpleXmlWriter& inWriter ) { XmlNode* theNode( inNode ); if ( theNode->mData && *theNode->mData && theNode->mFirstChild == NULL ) inWriter.writeContentTag( theNode->mName, theNode->mData ); else { inWriter.beginTag( theNode->mName ); if ( theNode->mData && *theNode->mData ) inWriter.addContent( theNode->mData ); for ( XmlNode* theChild = theNode->mFirstChild; theChild != NULL; theChild = theChild->mNextSibling ) saveXmlNode( theChild, inWriter ); inWriter.endTag(); } } virtual void save( PxOutputStream& inStream ) { SimpleXmlWriterImpl theWriter( inStream, mAllocator.getAllocator() ); theWriter.beginTag( "PhysX30Collection" ); theWriter.addAttribute( "version", mVersionStr ); { XmlWriterImpl theRepXWriter( &theWriter, &mPropertyBuffer ); writeProperty( theWriter, mPropertyBuffer, "UpVector", mUpVector ); theRepXWriter.addAndGotoChild( "Scale" ); writeAllProperties( &mScale, theRepXWriter, mPropertyBuffer, *mPxCollection); theRepXWriter.leaveChild(); } for ( PxU32 idx =0; idx < mCollection.size(); ++idx ) { RepXCollectionItem theItem( mCollection[idx] ); XmlNode* theNode( theItem.descriptor ); saveXmlNode( theNode, theWriter ); } } void load( PxInputData& inFileBuf, SerializationRegistry& s ) { inFileBuf.seek(0); XmlParser theParser( XmlParseArgs( &mAllocator, &mCollection ), mAllocator ); Ps::FastXml* theFastXml = Ps::createFastXml( &theParser ); theFastXml->processXml( inFileBuf ); XmlNode* theTopNode = theParser.getTopNode(); if ( theTopNode != NULL ) { { XmlMemoryAllocatorImpl instantiationAllocator( mAllocator.getAllocator() ); XmlNodeReader theReader( theTopNode, mAllocator.getAllocator(), mAllocator.mManager ); readProperty( theReader, "UpVector", mUpVector ); if ( theReader.gotoChild( "Scale" ) ) { readAllProperties( PxRepXInstantiationArgs( s.getPhysics() ), theReader, &mScale, instantiationAllocator, *mPxCollection); theReader.leaveChild(); } const char* verStr = NULL; if ( theReader.read( "version", verStr ) ) mVersionStr = verStr; } for ( XmlNode* theChild = theTopNode->mFirstChild; theChild != NULL; theChild = theChild->mNextSibling ) { if ( physx::shdfnd::stricmp( theChild->mName, "scale" ) == 0 || physx::shdfnd::stricmp( theChild->mName, "version" ) == 0 || physx::shdfnd::stricmp( theChild->mName, "upvector" ) == 0 ) continue; XmlNodeReader theReader( theChild, mAllocator.getAllocator(), mAllocator.mManager ); PxRepXObject theObject; theObject.typeName = theChild->mName; theObject.serializable = NULL; PxSerialObjectId theId = 0; theReader.read( "Id", theId ); theObject.id = theId; mCollection.pushBack( RepXCollectionItem( theObject, theChild ) ); } } else { Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "Cannot parse any object from the input buffer, please check the input repx data."); } theFastXml->release(); } virtual const char* getVersion() { return mVersionStr; } virtual const RepXCollectionItem* begin() const { return mCollection.begin(); } virtual const RepXCollectionItem* end() const { return mCollection.end(); } virtual RepXCollection& createCollection( const char* inVersionStr ) { PxAllocatorCallback& allocator = mSharedData->mWrapper.getAllocator(); RepXCollectionImpl* retval = PX_PLACEMENT_NEW((allocator.allocate(sizeof(RepXCollectionImpl), "createCollection", __FILE__, __LINE__ )), RepXCollectionImpl) ( mSerializationRegistry, *this, inVersionStr ); return *retval; } //Performs a deep copy of the repx node. virtual XmlNode* copyRepXNode( const XmlNode* srcNode ) { return physx::Sn::copyRepXNode( &mAllocator.mManager, srcNode ); } virtual void addCollectionItem( RepXCollectionItem inItem ) { mCollection.pushBack( inItem ); } virtual PxAllocatorCallback& getAllocator() { return mSharedData->mAllocator.getAllocator(); } //Create a new repx node with this name. Its value is unset. virtual XmlNode& createRepXNode( const char* name ) { XmlNode* newNode = allocateRepXNode( &mSharedData->mAllocator.mManager, name, NULL ); return *newNode; } //Release this when finished. virtual XmlReaderWriter& createNodeEditor() { PxAllocatorCallback& allocator = mSharedData->mWrapper.getAllocator(); XmlReaderWriter* retval = PX_PLACEMENT_NEW((allocator.allocate(sizeof(XmlNodeReader), "createNodeEditor", __FILE__, __LINE__ )), XmlNodeReader) ( NULL, allocator, mAllocator.mManager ); return *retval; } }; const char* RepXCollection::getLatestVersion() { #define TOSTR_(x) #x #define CONCAT_(a, b, c) TOSTR_(a.##b.##c) #define MAKE_VERSION_STR(a,b,c) CONCAT_(a, b, c) return MAKE_VERSION_STR(PX_PHYSICS_VERSION_MAJOR,PX_PHYSICS_VERSION_MINOR,PX_PHYSICS_VERSION_BUGFIX); } static RepXCollection* create(SerializationRegistry& s, PxAllocatorCallback& inAllocator, PxCollection& inCollection ) { return PX_PLACEMENT_NEW((inAllocator.allocate(sizeof(RepXCollectionImpl), "RepXCollection::create", __FILE__, __LINE__ )), RepXCollectionImpl) ( s, inAllocator, inCollection ); } static RepXCollection* create(SerializationRegistry& s, PxInputData &data, PxAllocatorCallback& inAllocator, PxCollection& inCollection ) { RepXCollectionImpl* theCollection = static_cast( create(s, inAllocator, inCollection ) ); theCollection->load( data, s ); return theCollection; } } bool PxSerialization::serializeCollectionToXml( PxOutputStream& outputStream, PxCollection& collection, PxSerializationRegistry& sr, PxCooking* cooking, const PxCollection* externalRefs, PxXmlMiscParameter* inArgs ) { if( !PxSerialization::isSerializable(collection, sr, const_cast(externalRefs)) ) return false; bool bRet = true; SerializationRegistry& sn = static_cast(sr); PxRepXInstantiationArgs args( sn.getPhysics(), cooking ); PxCollection* tmpCollection = PxCreateCollection(); PX_ASSERT(tmpCollection); tmpCollection->add( collection ); if(externalRefs) { tmpCollection->add(*const_cast(externalRefs)); } PxAllocatorCallback& allocator = PxGetFoundation().getAllocatorCallback(); Sn::RepXCollection* theRepXCollection = Sn::create(sn, allocator, *tmpCollection ); if(inArgs != NULL) { theRepXCollection->setTolerancesScale(inArgs->scale); theRepXCollection->setUpVector(inArgs->upVector); } PxU32 nbObjects = collection.getNbObjects(); if( nbObjects ) { sortCollection( static_cast(collection), sn, true); for( PxU32 i = 0; i < nbObjects; i++ ) { PxBase& s = collection.getObject(i); if( PxConcreteType::eSHAPE == s.getConcreteType() ) { PxShape& shape = static_cast(s); if( shape.isExclusive() ) continue; } PxSerialObjectId id = collection.getId(s); if(id == PX_SERIAL_OBJECT_ID_INVALID) id = static_cast( reinterpret_cast( &s )); PxRepXObject ro = PxCreateRepXObject( &s, id ); if ( ro.serializable == NULL || ro.id == 0 ) { bRet = false; break; } theRepXCollection->addRepXObjectToCollection( ro, tmpCollection, args ); } } tmpCollection->release(); theRepXCollection->save(outputStream); theRepXCollection->destroy(); return bRet; } PxCollection* PxSerialization::createCollectionFromXml(PxInputData& inputData, PxCooking& cooking, PxSerializationRegistry& sr, const PxCollection* externalRefs, PxStringTable* stringTable, PxXmlMiscParameter* outArgs) { SerializationRegistry& sn = static_cast(sr); PxCollection* collection = PxCreateCollection(); PX_ASSERT(collection); if( externalRefs ) collection->add(*const_cast(externalRefs)); PxAllocatorCallback& allocator = PxGetFoundation().getAllocatorCallback(); Sn::RepXCollection* theRepXCollection = Sn::create(sn, inputData, allocator, *collection); theRepXCollection = &Sn::RepXUpgrader::upgradeCollection( *theRepXCollection ); PxRepXInstantiationArgs args( sn.getPhysics(), &cooking, stringTable ); if( !theRepXCollection->instantiateCollection(args, *collection) ) { collection->release(); theRepXCollection->destroy(); return NULL; } if( externalRefs ) collection->remove(*const_cast(externalRefs)); if(outArgs != NULL) { outArgs->upVector = theRepXCollection->getUpVector(); outArgs->scale = theRepXCollection->getTolerancesScale(); } theRepXCollection->destroy(); return collection; } }