void PxSerialization::complete(PxCollection& collection, PxSerializationRegistry& sr, const PxCollection* exceptFor, bool followJoints) { PxCollection* curCollection = PxCreateCollection(); PX_ASSERT(curCollection); curCollection->add(collection); PxCollection* requiresCollection = PxCreateCollection(); PX_ASSERT(requiresCollection); do { getRequiresCollection(*requiresCollection, *curCollection, collection, exceptFor, sr, followJoints); collection.add(*requiresCollection); PxCollection* swap = curCollection; curCollection = requiresCollection; requiresCollection = swap; (static_cast<Cm::Collection*>(requiresCollection))->mObjects.clear(); }while(curCollection->getNbObjects() > 0); requiresCollection->release(); curCollection->release(); }
void PxCollectionExt::remove(PxCollection& collection, PxType concreteType, PxCollection* to) { shdfnd::Array<PxBase*> removeObjects; for (PxU32 i = 0; i < collection.getNbObjects(); i++) { PxBase& object = collection.getObject(i); if(concreteType == object.getConcreteType()) { if(to) to->add(object); removeObjects.pushBack(&object); } } for (PxU32 i = 0; i < removeObjects.size(); ++i) collection.remove(*removeObjects[i]); }
void PxSerialization::createSerialObjectIds(PxCollection& collection, const PxSerialObjectId base) { PxSerialObjectId localBase = base; PxU32 nbObjects = collection.getNbObjects(); for (PxU32 i = 0; i < nbObjects; ++i) { while(collection.find(localBase)) { localBase++; } PxBase& s = collection.getObject(i); if(PX_SERIAL_OBJECT_ID_INVALID == collection.getId(s)) { collection.addId(s, localBase); localBase++; } } }
void CEntity::deserializeFromRepXFile(const std::string &file, int group, const std::vector<int>& groupList, const Logic::IPhysics* component) { // Obtenemos el puntero al servidor de fisicas Physics::CServer* physicsServer = Physics::CServer::getSingletonPtr(); PxScene* scene = physicsServer->getActiveScene(); PxPhysics* physics = physicsServer->getPhysxSDK(); PxCooking* cooking = physicsServer->getCooking(); assert(scene); // Preparar parámetros para deserializar PxDefaultFileInputData data(file.c_str()); PxCollection* bufferCollection = physics->createCollection(); PxCollection* sceneCollection = physics->createCollection(); PxStringTable* stringTable = &PxStringTableExt::createStringTable( CServer::getSingletonPtr()->getFoundation()->getAllocatorCallback() ); PxUserReferences* externalRefs = NULL; PxUserReferences* userRefs = NULL; // Deserializar a partir del fichero RepX repx::deserializeFromRepX(data, *physics, *cooking, stringTable, externalRefs, *bufferCollection, *sceneCollection, userRefs); // Añadir entidades físicas a la escena physics->addCollection(*sceneCollection, *scene); // Buscar una entidad de tipo PxRigidActor. Asumimos que hay exactamente 1 en el fichero. _actor = NULL; for (unsigned int i = 0; i < sceneCollection->getNbObjects() && !_actor; ++i) { PxSerializable* p = sceneCollection->getObject(i); _actor = p->is<PxRigidActor>(); } assert(_actor); // Anotar el componente lógico asociado a la entidad física _actor->userData = (void*)component; // Establecer el grupo de colisión PxSetGroup(*_actor, group); // Establecer los filtros de colisión Physics::CServer::getSingletonPtr()->setupFiltering(_actor, group, groupList); // Liberar recursos bufferCollection->release(); sceneCollection->release(); }
PxCollection* PxCollectionExt::createCollection(PxPhysics& physics) { PxCollection* collection = PxCreateCollection(); if (!collection) return NULL; // Collect convexes { shdfnd::Array<PxConvexMesh*> objects(physics.getNbConvexMeshes()); const PxU32 nb = physics.getConvexMeshes(objects.begin(), objects.size()); PX_ASSERT(nb == objects.size()); PX_UNUSED(nb); for(PxU32 i=0;i<objects.size();i++) collection->add(*objects[i]); } // Collect triangle meshes { shdfnd::Array<PxTriangleMesh*> objects(physics.getNbTriangleMeshes()); const PxU32 nb = physics.getTriangleMeshes(objects.begin(), objects.size()); PX_ASSERT(nb == objects.size()); PX_UNUSED(nb); for(PxU32 i=0;i<objects.size();i++) collection->add(*objects[i]); } // Collect heightfields { shdfnd::Array<PxHeightField*> objects(physics.getNbHeightFields()); const PxU32 nb = physics.getHeightFields(objects.begin(), objects.size()); PX_ASSERT(nb == objects.size()); PX_UNUSED(nb); for(PxU32 i=0;i<objects.size();i++) collection->add(*objects[i]); } // Collect materials { shdfnd::Array<PxMaterial*> objects(physics.getNbMaterials()); const PxU32 nb = physics.getMaterials(objects.begin(), objects.size()); PX_ASSERT(nb == objects.size()); PX_UNUSED(nb); for(PxU32 i=0;i<objects.size();i++) collection->add(*objects[i]); } #if PX_USE_CLOTH_API // Collect cloth fabrics { shdfnd::Array<PxClothFabric*> objects(physics.getNbClothFabrics()); const PxU32 nb = physics.getClothFabrics(objects.begin(), objects.size()); PX_ASSERT(nb == objects.size()); PX_UNUSED(nb); for(PxU32 i=0;i<objects.size();i++) collection->add(*objects[i]); } #endif // Collect shapes { shdfnd::Array<PxShape*> objects(physics.getNbShapes()); const PxU32 nb = physics.getShapes(objects.begin(), objects.size()); PX_ASSERT(nb == objects.size()); PX_UNUSED(nb); for(PxU32 i=0;i<objects.size();i++) collection->add(*objects[i]); } return collection; }
PxCollection* PxCollectionExt::createCollection(PxScene& scene) { PxCollection* collection = PxCreateCollection(); if (!collection) return NULL; // Collect actors { PxActorTypeFlags selectionFlags = PxActorTypeFlag::eRIGID_STATIC | PxActorTypeFlag::eRIGID_DYNAMIC; #if PX_USE_PARTICLE_SYSTEM_API selectionFlags |= PxActorTypeFlag::ePARTICLE_SYSTEM | PxActorTypeFlag::ePARTICLE_FLUID; #endif #if PX_USE_CLOTH_API selectionFlags |= PxActorTypeFlag::eCLOTH; #endif shdfnd::Array<PxActor*> objects(scene.getNbActors(selectionFlags)); const PxU32 nb = scene.getActors(selectionFlags, objects.begin(), objects.size()); PX_ASSERT(nb==objects.size()); PX_UNUSED(nb); for(PxU32 i=0;i<objects.size();i++) collection->add(*objects[i]); } // Collect constraints { shdfnd::Array<PxConstraint*> objects(scene.getNbConstraints()); const PxU32 nb = scene.getConstraints(objects.begin(), objects.size()); PX_ASSERT(nb==objects.size()); PX_UNUSED(nb); for(PxU32 i=0;i<objects.size();i++) { PxU32 typeId; PxJoint* joint = reinterpret_cast<PxJoint*>(objects[i]->getExternalReference(typeId)); if(typeId == PxConstraintExtIDs::eJOINT) collection->add(*joint); } } // Collect articulations { shdfnd::Array<PxArticulation*> objects(scene.getNbArticulations()); const PxU32 nb = scene.getArticulations(objects.begin(), objects.size()); PX_ASSERT(nb==objects.size()); PX_UNUSED(nb); for(PxU32 i=0;i<objects.size();i++) collection->add(*objects[i]); } // Collect aggregates { shdfnd::Array<PxAggregate*> objects(scene.getNbAggregates()); const PxU32 nb = scene.getAggregates(objects.begin(), objects.size()); PX_ASSERT(nb==objects.size()); PX_UNUSED(nb); for(PxU32 i=0;i<objects.size();i++) collection->add(*objects[i]); } return collection; }
void FPhysxSharedData::DumpSharedMemoryUsage(FOutputDevice* Ar) { struct FSharedResourceEntry { uint64 MemorySize; uint64 Count; }; struct FSortBySize { FORCEINLINE bool operator()( const FSharedResourceEntry& A, const FSharedResourceEntry& B ) const { // Sort descending return B.MemorySize < A.MemorySize; } }; TMap<FString, FSharedResourceEntry> AllocationsByType; uint64 OverallSize = 0; int32 OverallCount = 0; TMap<FString, TArray<PxBase*> > ObjectsByType; for (int32 i=0; i < (int32)SharedObjects->getNbObjects(); ++i) { PxBase& Obj = SharedObjects->getObject(i); FString TypeName = ANSI_TO_TCHAR(Obj.getConcreteTypeName()); TArray<PxBase*>* ObjectsArray = ObjectsByType.Find(TypeName); if (ObjectsArray == NULL) { ObjectsByType.Add(TypeName, TArray<PxBase*>()); ObjectsArray = ObjectsByType.Find(TypeName); } check(ObjectsArray); ObjectsArray->Add(&Obj); } TArray<FString> TypeNames; ObjectsByType.GetKeys(TypeNames); for (int32 TypeIdx=0; TypeIdx < TypeNames.Num(); ++TypeIdx) { const FString& TypeName = TypeNames[TypeIdx]; TArray<PxBase*>* ObjectsArray = ObjectsByType.Find(TypeName); check(ObjectsArray); PxSerializationRegistry* Sr = PxSerialization::createSerializationRegistry(*GPhysXSDK); PxCollection* Collection = PxCreateCollection(); for (int32 i=0; i < ObjectsArray->Num(); ++i) { Collection->add(*((*ObjectsArray)[i]));; } PxSerialization::complete(*Collection, *Sr); // chase all other stuff (shared shaps, materials, etc) needed to serialize this collection FPhysXCountMemoryStream Out; PxSerialization::serializeCollectionToBinary(Out, *Collection, *Sr); Collection->release(); Sr->release(); OverallSize += Out.UsedMemory; OverallCount += ObjectsArray->Num(); FSharedResourceEntry NewEntry; NewEntry.Count = ObjectsArray->Num(); NewEntry.MemorySize = Out.UsedMemory; AllocationsByType.Add(TypeName, NewEntry); } Ar->Logf(TEXT("")); Ar->Logf(TEXT("Shared Resources:")); Ar->Logf(TEXT("")); AllocationsByType.ValueSort(FSortBySize()); Ar->Logf(TEXT("%-10d %s (%d)"), OverallSize, TEXT("Overall"), OverallCount ); for( auto It=AllocationsByType.CreateConstIterator(); It; ++It ) { Ar->Logf(TEXT("%-10d %s (%d)"), It.Value().MemorySize, *It.Key(), It.Value().Count ); } }
bool PhysXWorld::ExportWholeScene(const char *filename) const { using namespace physx::repx; if (!PhysXSDK || !PhysXScene) return false; PxCollection *cl = PhysXSDK->createCollection(); if (!cl) return false; PhysxUserFileWriteStream fs(filename); RepXCollection* theCollection = createCollection(PhysXSDK->getTolerancesScale(), PhysXFoundation->getAllocatorCallback()); RepXIdToRepXObjectMap* theIdMap = RepXIdToRepXObjectMap::create(PxGetFoundation().getAllocatorCallback()); addSDKItemsToRepX ( *PhysXSDK, *theIdMap, *theCollection); //add physcis object addSceneItemsToRepX ( *PhysXScene, *theIdMap, *theCollection); //add physcis object // physx::repx::addObjectsToScene(theCollection, physics, cooking, scene, mStringTable ); theCollection->save(fs); theCollection->destroy(); theIdMap->destroy(); return true; // PxCollectForExportSDK(*PhysXSDK, *cl); // PxCollectForExportScene(*PhysXScene, *cl); ObjectIterator iter = GameWorld().GetFirstOfAllObjects(); while( iter.current ) { GameObject* o = iter.current; if (o->PhysicsObject) { PxActor *a = o->PhysicsObject->getPhysicsActor(); PxSerialFlags f = a->getSerialFlags(); a->collectForExport(*cl); break; } iter = GameWorld().GetNextOfAllObjects( iter ); } PxU32 numObjs = cl->getNbObjects(); numObjs; cl->serialize(fs); PhysXSDK->releaseCollection(*cl); fclose(fs.fpw); FILE* fp=NULL; if( (fp = fopen(filename, "rb")) ) { fseek(fp, 0, SEEK_END); PxU32 fileSize = ftell(fp); fseek(fp, 0, SEEK_SET); PX_ASSERT(fileSize!=0); void* mem = malloc(fileSize+PX_SERIAL_FILE_ALIGN); void* mem16 = (void*)((size_t(mem) + PX_SERIAL_FILE_ALIGN)&~(PX_SERIAL_FILE_ALIGN-1)); fread(mem16, 1, fileSize, fp); fclose(fp); PxUserReferences* convexRefs = PhysXSDK->createUserReferences(); PxCollection* collection = PhysXSDK->createCollection(); collection->deserialize(mem16, convexRefs, NULL); PxU32 numObjs = collection->getNbObjects(); for (PxU32 i = 0; i < numObjs; ++i) { PxSerializable *o = collection->getObject(i); const char * name = o->getConcreteTypeName(); PX_ASSERT(name); } } return true; }
void UPhysicsSerializer::CreatePhysicsData(const TArray<UBodySetup*>& BodySetups, const TArray<UPhysicalMaterial*>& PhysicalMaterials) { if (!FParse::Param(FCommandLine::Get(), TEXT("PhysxSerialization"))) { return; } #if PLATFORM_MAC return; //This is not supported right now #endif #if !WITH_EDITOR QUICK_SCOPE_CYCLE_COUNTER(STAT_PhysicsSerializer_CreatePhysicsData); const FName Format(FPlatformProperties::GetPhysicsFormat()); if(BinaryFormatData.Contains(Format)) { FByteBulkData& BinaryData = BinaryFormatData.GetFormat(Format); #if WITH_PHYSX // Read serialized physics data uint8* SerializedData = (uint8*)BinaryData.Lock(LOCK_READ_ONLY); FBufferReader Ar(SerializedData, BinaryData.GetBulkDataSize(), false ); uint8 bIsLittleEndian; uint64 BaseId; //the starting index of the shared resources we didn't serialize out Ar << bIsLittleEndian; Ar.SetByteSwapping( PLATFORM_LITTLE_ENDIAN ? !bIsLittleEndian : !!bIsLittleEndian ); Ar << BaseId; //Note that PhysX expects the binary data to be 128-byte aligned. Because of this we've padded so find the next spot in memory int32 BytesToPad = PHYSX_SERIALIZATION_ALIGNMENT - (Ar.Tell() % PHYSX_SERIALIZATION_ALIGNMENT); physx::PxSerializationRegistry* PRegistry = PxSerialization::createSerializationRegistry(*GPhysXSDK); physx::PxCollection* PCollection = nullptr; PxCollection* PExternalData = MakePhysXCollection(PhysicalMaterials, BodySetups, BaseId); { QUICK_SCOPE_CYCLE_COUNTER(STAT_DeserializePhysics); PCollection = PxSerialization::createCollectionFromBinary(SerializedData + Ar.Tell() + BytesToPad, *PRegistry, PExternalData); } { QUICK_SCOPE_CYCLE_COUNTER(STAT_AddBodiesToMap); const uint32 NumObjects = PCollection->getNbObjects(); for (uint32 ObjectIdx = 0; ObjectIdx < NumObjects; ++ObjectIdx) { PxBase& PObject = PCollection->getObject(ObjectIdx); if (PxRigidActor* PRigidActor = PObject.is<PxRigidActor>()) { const PxSerialObjectId ObjectId = PCollection->getId(PObject); ActorsMap.Add(ObjectId, PRigidActor); } else if (PxShape* PShape = PObject.is<PxShape>()) { PShape->release(); //we do not need to hold on to this reference because our actors always have the reference directly } } } PExternalData->release(); PCollection->release(); PRegistry->release(); #endif }else { #if !WITH_EDITOR UE_LOG(LogPhysics, Warning, TEXT("PhysicsSerializer has no binary data. Body instances will fall back to slow creation path.")); #endif } #endif }
bool PxSerialization::isSerializable(PxCollection& collection, PxSerializationRegistry& sr, const PxCollection* externalReferences) { PxCollection* subordinateCollection = PxCreateCollection(); PX_ASSERT(subordinateCollection); for(PxU32 i = 0; i < collection.getNbObjects(); ++i) { PxBase& s = collection.getObject(i); const PxSerializer* serializer = sr.getSerializer(s.getConcreteType()); PX_ASSERT(serializer); if(serializer->isSubordinate()) subordinateCollection->add(s); if(externalReferences) { PxSerialObjectId id = collection.getId(s); if(id != PX_SERIAL_OBJECT_ID_INVALID) { PxBase* object = externalReferences->find(id); if(object && (object != &s)) { subordinateCollection->release(); Ps::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "PxSerialization::isSerializable: Reference id %llu used both in current collection and in externalReferences. " "Please use unique identifiers.", id); return false; } } } } PxCollection* requiresCollection = PxCreateCollection(); PX_ASSERT(requiresCollection); RequiresCallback requiresCallback0(*requiresCollection); for (PxU32 i = 0; i < collection.getNbObjects(); ++i) { PxBase& s = collection.getObject(i); const PxSerializer* serializer = sr.getSerializer(s.getConcreteType()); PX_ASSERT(serializer); serializer->requires(s, requiresCallback0); Cm::Collection* cmRequiresCollection = static_cast<Cm::Collection*>(requiresCollection); for(PxU32 j = 0; j < cmRequiresCollection->getNbObjects(); ++j) { PxBase& s0 = cmRequiresCollection->getObject(j); if(subordinateCollection->contains(s0)) { subordinateCollection->remove(s0); continue; } bool requiredIsInCollection = collection.contains(s0); if(!requiredIsInCollection) { if(externalReferences) { if(!externalReferences->contains(s0)) { Ps::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "PxSerialization::isSerializable: Object of type %s references a missing object of type %s. " "The missing object needs to be added to either the current collection or the externalReferences collection.", s.getConcreteTypeName(), s0.getConcreteTypeName()); } else if(externalReferences->getId(s0) == PX_SERIAL_OBJECT_ID_INVALID) { Ps::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "PxSerialization::isSerializable: Object of type %s in externalReferences collection requires an id.", s0.getConcreteTypeName()); } else continue; } else { Ps::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "PxSerialization::isSerializable: Object of type %s references a missing serial object of type %s. " "Please completed the collection or specify an externalReferences collection containing the object.", s.getConcreteTypeName(), s0.getConcreteTypeName()); } subordinateCollection->release(); requiresCollection->release(); return false; } } cmRequiresCollection->mObjects.clear(); } requiresCollection->release(); PxU32 numOrphans = subordinateCollection->getNbObjects(); for(PxU32 j = 0; j < numOrphans; ++j) { PxBase& subordinate = subordinateCollection->getObject(j); Ps::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "PxSerialization::isSerializable: An object of type %s is subordinate but not required " "by other objects in the collection (orphan). Please remove the object from the collection or add its owner.", subordinate.getConcreteTypeName()); } subordinateCollection->release(); if(numOrphans>0) return false; if(externalReferences) { PxCollection* oppositeRequiresCollection = PxCreateCollection(); PX_ASSERT(oppositeRequiresCollection); RequiresCallback requiresCallback(*oppositeRequiresCollection); for (PxU32 i = 0; i < externalReferences->getNbObjects(); ++i) { PxBase& s = externalReferences->getObject(i); const PxSerializer* serializer = sr.getSerializer(s.getConcreteType()); PX_ASSERT(serializer); serializer->requires(s, requiresCallback); Cm::Collection* cmCollection = static_cast<Cm::Collection*>(oppositeRequiresCollection); for(PxU32 j = 0; j < cmCollection->getNbObjects(); ++j) { PxBase& s0 = cmCollection->getObject(j); if(collection.contains(s0)) { oppositeRequiresCollection->release(); Ps::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "PxSerialization::isSerializable: Object of type %s in externalReferences references an object " "of type %s in collection (circular dependency).", s.getConcreteTypeName(), s0.getConcreteTypeName()); return false; } } cmCollection->mObjects.clear(); } oppositeRequiresCollection->release(); } return true; }
bool PxSerialization::isSerializable(PxCollection& collection, PxSerializationRegistry& sr, const PxCollection* externalReferences) { bool bRet = true; PxCollection* subordinateCollection = PxCreateCollection(); PX_ASSERT(subordinateCollection); for(PxU32 i = 0; i < collection.getNbObjects(); ++i) { PxBase& s = collection.getObject(i); const PxSerializer* serializer = sr.getSerializer(s.getConcreteType()); PX_ASSERT(serializer); if(serializer->isSubordinate()) subordinateCollection->add(s); if(externalReferences) { PxSerialObjectId id = collection.getId(s); if(id != PX_SERIAL_OBJECT_ID_INVALID) { PxBase* object = externalReferences->find(id); if(object && (object != &s)) { subordinateCollection->release(); Ps::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "NpCollection::isSerializable: object shares reference name with other object in externalReferences (reference clash)."); return false; } } } } PxCollection* requiresCollection = PxCreateCollection(); PX_ASSERT(requiresCollection); RequiresCallback requiresCallback0(*requiresCollection); for (PxU32 i = 0; i < collection.getNbObjects(); ++i) { PxBase& s = collection.getObject(i); const PxSerializer* serializer = sr.getSerializer(s.getConcreteType()); PX_ASSERT(serializer); serializer->requires(s, requiresCallback0); } for(PxU32 j = 0; j < subordinateCollection->getNbObjects(); ++j) { PxBase& subordinate = subordinateCollection->getObject(j); bRet = requiresCollection->contains(subordinate); if(!bRet) { requiresCollection->release(); subordinateCollection->release(); Ps::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "NpCollection::isSerializable: object is a subordinate and not required by other objects in the collection (orphan)."); return false; } } subordinateCollection->release(); for(PxU32 j = 0; j < requiresCollection->getNbObjects(); ++j) { PxBase& s0 = requiresCollection->getObject(j); bRet = collection.contains(s0); if(!bRet && externalReferences) { bRet = externalReferences->contains(s0) && externalReferences->getId(s0) != PX_SERIAL_OBJECT_ID_INVALID; } if(!bRet) { requiresCollection->release(); Ps::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "NpCollection::isSerializable: cannot find a required serial object (collection is not complete)."); return false; } } requiresCollection->release(); if(externalReferences) { PxCollection* oppsiteRequiresCollection = PxCreateCollection(); PX_ASSERT(oppsiteRequiresCollection); RequiresCallback requiresCallback(*oppsiteRequiresCollection); for (PxU32 i = 0; i < externalReferences->getNbObjects(); ++i) { PxBase& s = externalReferences->getObject(i); const PxSerializer* serializer = sr.getSerializer(s.getConcreteType()); PX_ASSERT(serializer); serializer->requires(s, requiresCallback); } for(PxU32 j = 0; j < oppsiteRequiresCollection->getNbObjects(); ++j) { PxBase& s0 = oppsiteRequiresCollection->getObject(j); if(collection.contains(s0)) { oppsiteRequiresCollection->release(); Ps::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "NpCollection::isSerializable: object in externalReferences requires an object in collection (circular dependency)."); return false; } } oppsiteRequiresCollection->release(); } return true; }
virtual bool SerializeActors(FName Format, const TArray<FBodyInstance*>& Bodies, const TArray<UBodySetup*>& BodySetups, const TArray<UPhysicalMaterial*>& PhysicalMaterials, TArray<uint8>& OutBuffer) const override { #if WITH_PHYSX PxSerializationRegistry* PRegistry = PxSerialization::createSerializationRegistry(*GPhysXSDK); PxCollection* PCollection = PxCreateCollection(); PxBase* PLastObject = nullptr; for(FBodyInstance* BodyInstance : Bodies) { if(BodyInstance->RigidActorSync) { PCollection->add(*BodyInstance->RigidActorSync, BodyInstance->RigidActorSyncId); PLastObject = BodyInstance->RigidActorSync; } if(BodyInstance->RigidActorAsync) { PCollection->add(*BodyInstance->RigidActorAsync, BodyInstance->RigidActorAsyncId); PLastObject = BodyInstance->RigidActorAsync; } } PxSerialization::createSerialObjectIds(*PCollection, PxSerialObjectId(1)); //we get physx to assign an id for each actor //Note that rigid bodies may have assigned ids. It's important to let them go first because we rely on that id for deserialization. //One this is done we must find out the next available ID, and use that for naming the shared resources. We have to save this for deserialization uint64 BaseId = PLastObject ? (PCollection->getId(*PLastObject) + 1) : 1; PxCollection* PExceptFor = MakePhysXCollection(PhysicalMaterials, BodySetups, BaseId); for (FBodyInstance* BodyInstance : Bodies) //and then we mark that id back into the bodyinstance so we can pair the two later { if (BodyInstance->RigidActorSync) { BodyInstance->RigidActorSyncId = PCollection->getId(*BodyInstance->RigidActorSync); } if (BodyInstance->RigidActorAsync) { BodyInstance->RigidActorAsyncId = PCollection->getId(*BodyInstance->RigidActorAsync); } } //We must store the BaseId for shared resources. FMemoryWriter Ar(OutBuffer); uint8 bIsLittleEndian = PLATFORM_LITTLE_ENDIAN; //TODO: We should pass the target platform into this function and write it. Then swap the endian on the writer so the reader doesn't have to do it at runtime Ar << bIsLittleEndian; Ar << BaseId; //Note that PhysX expects the binary data to be 128-byte aligned. Because of this we must pad int32 BytesToPad = PHYSX_SERIALIZATION_ALIGNMENT - (Ar.Tell() % PHYSX_SERIALIZATION_ALIGNMENT); OutBuffer.AddZeroed(BytesToPad); FPhysXOutputStream Buffer(&OutBuffer); PxSerialization::complete(*PCollection, *PRegistry, PExceptFor); PxSerialization::serializeCollectionToBinary(Buffer, *PCollection, *PRegistry, PExceptFor); #if PHYSX_MEMORY_VALIDATION GPhysXAllocator->ValidateHeaders(); #endif PCollection->release(); PExceptFor->release(); PRegistry->release(); #if PHYSX_MEMORY_VALIDATION GPhysXAllocator->ValidateHeaders(); #endif return true; #endif return false; }