void PxCollectionExt::releaseObjects(PxCollection& collection, bool releaseExclusiveShapes) { shdfnd::Array<PxBase*> releasableObjects; for (PxU32 i = 0; i < collection.getNbObjects(); ++i) { PxBase* s = &collection.getObject(i); // pruning structure must be released before its actors if(s->is<PxPruningStructure>()) { if(!releasableObjects.empty()) { PxBase* first = releasableObjects[0]; releasableObjects.pushBack(first); releasableObjects[0] = s; } } else { if (s->isReleasable() && (releaseExclusiveShapes || !s->is<PxShape>() || !s->is<PxShape>()->isExclusive())) releasableObjects.pushBack(s); } } for (PxU32 i = 0; i < releasableObjects.size(); ++i) releasableObjects[i]->release(); while (collection.getNbObjects() > 0) collection.remove(collection.getObject(0)); }
void PxCollectionExt::releaseObjects(PxCollection& collection) { shdfnd::Array<PxBase*> releasableObjects; for (PxU32 i = 0; i < collection.getNbObjects(); ++i) { PxBase* s = &collection.getObject(i); if(s->isReleasable()) releasableObjects.pushBack(s); } for (PxU32 i = 0; i < releasableObjects.size(); ++i) releasableObjects[i]->release(); while (collection.getNbObjects() > 0) collection.remove(collection.getObject(0)); }
void SerializationContext::registerReference(PxBase& serializable, PxU32 kind, size_t reference) { #if PX_CHECKED if ((kind & PX_SERIAL_REF_KIND_PTR_TYPE_BIT) == 0 && reference > 0xffffffff) { Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "PxSerializationContext::registerReference: only 32 bit indices supported."); return; } #endif bool isExternal = mExternalRefs && mExternalRefs->contains(serializable); PxU32 index; if (isExternal) { PxSerialObjectId id = mExternalRefs->getId(serializable); PX_ASSERT(id != PX_SERIAL_OBJECT_ID_INVALID); if (const Ps::HashMap<PxSerialObjectId, PxU32>::Entry* entry = mImportReferencesMap.find(id)) { index = entry->second; } else { index = mImportReferences.size(); mImportReferencesMap.insert(id, index); mImportReferences.pushBack(ImportReference(id, serializable.getConcreteType())); } } else { PX_ASSERT(mCollection.contains(serializable)); index = mObjToCollectionIndexMap[&serializable]; } InternalRefMap& targetMap = (kind & PX_SERIAL_REF_KIND_PTR_TYPE_BIT) ? mInternalReferencesPtrMap : mInternalReferencesIdxMap; targetMap[InternalRefKey(reference, kind)] = SerialObjectIndex(index, isExternal); }
bool PxSerialization::serializeCollectionToBinary(PxOutputStream& outputStream, PxCollection& pxCollection, PxSerializationRegistry& sr, const PxCollection* pxExternalRefs, bool exportNames) { if(!PxSerialization::isSerializable(pxCollection, sr, pxExternalRefs)) return false; Cm::Collection& collection = static_cast<Cm::Collection&>(pxCollection); const Cm::Collection* externalRefs = static_cast<const Cm::Collection*>(pxExternalRefs); //temporary memory stream which allows fixing up data up stream SerializationRegistry& sn = static_cast<SerializationRegistry&>(sr); // sort collection by "order" value (this will be the order in which they get serialized) sortCollection(collection, sn, false); //initialized the context with the sorted collection. SerializationContext context(collection, externalRefs); // gather reference information bool hasDeserializedAssets = false; { const PxU32 nb = collection.internalGetNbObjects(); for(PxU32 i=0;i<nb;i++) { PxBase* s = collection.internalGetObject(i); PX_ASSERT(s && s->getConcreteType()); #ifdef PX_CHECKED //can't guarantee marked padding for deserialized instances if(!(s->getBaseFlags() & PxBaseFlag::eOWNS_MEMORY)) hasDeserializedAssets = true; #endif const PxSerializer* serializer = sn.getSerializer(s->getConcreteType()); PX_ASSERT(serializer); serializer->registerReferences(*s, context); } } // now start the actual serialization into the output stream OutputStreamWriter writer(outputStream); LegacySerialStream stream(writer, collection, exportNames); writeHeader(stream, hasDeserializedAssets); // write size of collection stream.alignData(PX_SERIAL_ALIGN); PxU32 nbObjectsInCollection = collection.internalGetNbObjects(); stream.writeData(&nbObjectsInCollection, sizeof(PxU32)); // write the manifest table (PxU32 offset, PxConcreteType type) { Ps::Array<ManifestEntry> manifestTable(collection.internalGetNbObjects()); PxU32 headerOffset = 0; for(PxU32 i=0;i<collection.internalGetNbObjects();i++) { PxBase* s = collection.internalGetObject(i); PX_ASSERT(s && s->getConcreteType()); PxType concreteType = s->getConcreteType(); const PxSerializer* serializer = sn.getSerializer(concreteType); PX_ASSERT(serializer); manifestTable[i] = ManifestEntry(headerOffset, concreteType); PxU32 classSize = PxU32(serializer->getClassSize()); headerOffset += Cm::getPadding(classSize, PX_SERIAL_ALIGN) + classSize; } stream.alignData(PX_SERIAL_ALIGN); const PxU32 nb = manifestTable.size(); stream.writeData(&nb, sizeof(PxU32)); stream.writeData(manifestTable.begin(), manifestTable.size()*sizeof(ManifestEntry)); //store offset for end of object buffer (PxU32 offset) stream.writeData(&headerOffset, sizeof(PxU32)); } // write import references { const Ps::Array<ImportReference>& importReferences = context.getImportReferences(); stream.alignData(PX_SERIAL_ALIGN); const PxU32 nb = importReferences.size(); stream.writeData(&nb, sizeof(PxU32)); stream.writeData(importReferences.begin(), importReferences.size()*sizeof(ImportReference)); } // write export references { PxU32 nbIds = collection.getNbIds(); Ps::Array<ExportReference> exportReferences(nbIds); //we can't get quickly from id to object index in collection. //if we only need this here, its not worth to build a hash nbIds = 0; for (PxU32 i=0;i<collection.getNbObjects();i++) { PxBase& obj = collection.getObject(i); PxSerialObjectId id = collection.getId(obj); if (id != PX_SERIAL_OBJECT_ID_INVALID) { SerialObjectIndex objIndex(i, false); //i corresponds to manifest entry exportReferences[nbIds++] = ExportReference(id, objIndex); } } stream.alignData(PX_SERIAL_ALIGN); stream.writeData(&nbIds, sizeof(PxU32)); stream.writeData(exportReferences.begin(), exportReferences.size()*sizeof(ExportReference)); } // write internal references { InternalRefMap& internalReferencesPtrMap = context.getInternalReferencesPtrMap(); Ps::Array<InternalReferencePtr> internalReferencesPtr(internalReferencesPtrMap.size()); PxU32 nbInternalPtrReferences = 0; for(InternalRefMap::Iterator iter = internalReferencesPtrMap.getIterator(); !iter.done(); ++iter) internalReferencesPtr[nbInternalPtrReferences++] = InternalReferencePtr(iter->first.first, iter->first.second, iter->second); InternalRefMap& internalReferencesIdxMap = context.getInternalReferencesIdxMap(); Ps::Array<InternalReferenceIdx> internalReferencesIdx(internalReferencesIdxMap.size()); PxU32 nbInternalIdxReferences = 0; for(InternalRefMap::Iterator iter = internalReferencesIdxMap.getIterator(); !iter.done(); ++iter) internalReferencesIdx[nbInternalIdxReferences++] = InternalReferenceIdx(Ps::to32(iter->first.first), iter->first.second, iter->second); stream.alignData(PX_SERIAL_ALIGN); stream.writeData(&nbInternalPtrReferences, sizeof(PxU32)); stream.writeData(internalReferencesPtr.begin(), internalReferencesPtr.size()*sizeof(InternalReferencePtr)); stream.writeData(&nbInternalIdxReferences, sizeof(PxU32)); stream.writeData(internalReferencesIdx.begin(), internalReferencesIdx.size()*sizeof(InternalReferenceIdx)); } // write object data { stream.alignData(PX_SERIAL_ALIGN); const PxU32 nb = collection.internalGetNbObjects(); for(PxU32 i=0;i<nb;i++) { PxBase* s = collection.internalGetObject(i); PX_ASSERT(s && s->getConcreteType()); const PxSerializer* serializer = sn.getSerializer(s->getConcreteType()); PX_ASSERT(serializer); stream.alignData(PX_SERIAL_ALIGN); serializer->exportData(*s, stream); } } // write extra data { const PxU32 nb = collection.internalGetNbObjects(); for(PxU32 i=0;i<nb;i++) { PxBase* s = collection.internalGetObject(i); PX_ASSERT(s && s->getConcreteType()); const PxSerializer* serializer = sn.getSerializer(s->getConcreteType()); PX_ASSERT(serializer); stream.alignData(PX_SERIAL_ALIGN); serializer->exportExtraData(*s, stream); } } return true; }
PxCollection* PxSerialization::createCollectionFromBinary(void* memBlock, PxSerializationRegistry& sr, const PxCollection* pxExternalRefs) { #ifdef PX_CHECKED if(size_t(memBlock) & (PX_SERIAL_FILE_ALIGN-1)) { Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "Buffer must be 128-bytes aligned."); return NULL; } #endif PxU8* address = reinterpret_cast<PxU8*>(memBlock); const Cm::Collection* externalRefs = static_cast<const Cm::Collection*>(pxExternalRefs); PxU32 version; if (!readHeader(address, version)) { return NULL; } ManifestEntry* manifestTable; PxU32 nbObjectsInCollection; PxU32 objectDataEndOffset; // read number of objects in collection address = Cm::alignPtr(address); nbObjectsInCollection = read32(address); // read manifest (PxU32 offset, PxConcreteType type) { address = Cm::alignPtr(address); PxU32 nbManifestEntries = read32(address); PX_ASSERT(*reinterpret_cast<PxU32*>(address) == 0); //first offset is always 0 manifestTable = (nbManifestEntries > 0) ? reinterpret_cast<ManifestEntry*>(address) : NULL; address += nbManifestEntries*sizeof(ManifestEntry); objectDataEndOffset = read32(address); } ImportReference* importReferences; PxU32 nbImportReferences; // read import references { address = Cm::alignPtr(address); nbImportReferences = read32(address); importReferences = (nbImportReferences > 0) ? reinterpret_cast<ImportReference*>(address) : NULL; address += nbImportReferences*sizeof(ImportReference); } if (!checkImportReferences(importReferences, nbImportReferences, externalRefs)) { return NULL; } ExportReference* exportReferences; PxU32 nbExportReferences; // read export references { address = Cm::alignPtr(address); nbExportReferences = read32(address); exportReferences = (nbExportReferences > 0) ? reinterpret_cast<ExportReference*>(address) : NULL; address += nbExportReferences*sizeof(ExportReference); } // read internal references arrays PxU32 nbInternalPtrReferences = 0; PxU32 nbInternalIdxReferences = 0; InternalReferencePtr* internalPtrReferences = NULL; InternalReferenceIdx* internalIdxReferences = NULL; { address = Cm::alignPtr(address); nbInternalPtrReferences = read32(address); internalPtrReferences = (nbInternalPtrReferences > 0) ? reinterpret_cast<InternalReferencePtr*>(address) : NULL; address += nbInternalPtrReferences*sizeof(InternalReferencePtr); nbInternalIdxReferences = read32(address); internalIdxReferences = (nbInternalIdxReferences > 0) ? reinterpret_cast<InternalReferenceIdx*>(address) : NULL; address += nbInternalIdxReferences*sizeof(InternalReferenceIdx); } // create internal references map PxF32 loadFactor = 0.75f; PxF32 _loadFactor = 1.0f / loadFactor; PxU32 hashSize = PxU32((nbInternalPtrReferences + nbInternalIdxReferences + 1)*_loadFactor); InternalRefMap internalReferencesMap(hashSize, loadFactor); { //create hash (we should load the hashes directly from memory) for (PxU32 i=0;i<nbInternalPtrReferences;i++) { const InternalReferencePtr& ref = internalPtrReferences[i]; internalReferencesMap.insertUnique( InternalRefKey(ref.reference, ref.kind), SerialObjectIndex(ref.objIndex)); } for (PxU32 i=0;i<nbInternalIdxReferences;i++) { const InternalReferenceIdx& ref = internalIdxReferences[i]; internalReferencesMap.insertUnique(InternalRefKey(ref.reference, ref.kind), SerialObjectIndex(ref.objIndex)); } } SerializationRegistry& sn = static_cast<SerializationRegistry&>(sr); Cm::Collection* collection = static_cast<Cm::Collection*>(PxCreateCollection()); PX_ASSERT(collection); collection->mObjects.reserve((PxU32)(nbObjectsInCollection*_loadFactor) + 1); if(nbExportReferences > 0) collection->mIds.reserve((PxU32)(nbExportReferences*_loadFactor) + 1); PxU8* addressObjectData = Cm::alignPtr(address); PxU8* addressExtraData = Cm::alignPtr(addressObjectData + objectDataEndOffset); DeserializationContext context(manifestTable, importReferences, addressObjectData, internalReferencesMap, externalRefs, addressExtraData, version); // iterate over memory containing PxBase objects, create the instances, resolve the addresses, import the external data, add to collection. { PxU32 nbObjects = nbObjectsInCollection; while(nbObjects--) { address = Cm::alignPtr(address); context.alignExtraData(); // read PxBase header with type and get corresponding serializer. PxBase* header = reinterpret_cast<PxBase*>(address); const PxType classType = header->getConcreteType(); const PxSerializer* serializer = sn.getSerializer(classType); PX_ASSERT(serializer); PxBase* instance = serializer->createObject(address, context); if (!instance) { Ps::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "Cannot create class instance for concrete type %d.", classType); collection->release(); return NULL; } collection->internalAdd(instance); } } PX_ASSERT(nbObjectsInCollection == collection->internalGetNbObjects()); // update new collection with export references { PX_ASSERT(addressObjectData != NULL); for (PxU32 i=0;i<nbExportReferences;i++) { bool isExternal; PxU32 manifestIndex = exportReferences[i].objIndex.getIndex(isExternal); PX_ASSERT(!isExternal); PxBase* obj = reinterpret_cast<PxBase*>(addressObjectData + manifestTable[manifestIndex].offset); collection->mIds.insertUnique(exportReferences[i].id, obj); collection->mObjects[obj] = exportReferences[i].id; } } PxAddCollectionToPhysics(*collection); return collection; }