// Copyright Epic Games, Inc. All Rights Reserved. #include "DatasmithFacadeScene.h" // Datasmith facade. #include "DatasmithFacadeActor.h" #include "DatasmithFacadeElement.h" #include "DatasmithFacadeMaterial.h" #include "DatasmithFacadeMesh.h" #include "DatasmithFacadeMetaData.h" #include "DatasmithFacadeTexture.h" #include "DatasmithFacadeVariant.h" #include "DatasmithFacadeAnimation.h" // Datasmith SDK. #include "DatasmithAnimationSerializer.h" #include "DatasmithExporterManager.h" #include "DatasmithExportOptions.h" #include "DatasmithSceneExporter.h" #include "Misc/Paths.h" #include "HAL/FileManager.h" FDatasmithFacadeScene::FDatasmithFacadeScene( const TCHAR* InApplicationHostName, const TCHAR* InApplicationVendorName, const TCHAR* InApplicationProductName, const TCHAR* InApplicationProductVersion ) : SceneRef(FDatasmithSceneFactory::CreateScene(TEXT(""))), SceneExporterRef(MakeShared()) { // Set the name of the host application used to build the scene. SceneRef->SetHost(InApplicationHostName); // Set the vendor name of the application used to build the scene. SceneRef->SetVendor(InApplicationVendorName); // Set the product name of the application used to build the scene. SceneRef->SetProductName(InApplicationProductName); // Set the product version of the application used to build the scene. SceneRef->SetProductVersion(InApplicationProductVersion); } void FDatasmithFacadeScene::AddActor( FDatasmithFacadeActor* InActorPtr ) { if (InActorPtr) { SceneRef->AddActor(InActorPtr->GetDatasmithActorElement()); } } int32 FDatasmithFacadeScene::GetActorsCount() const { return SceneRef->GetActorsCount(); } FDatasmithFacadeActor* FDatasmithFacadeScene::GetNewActor( int32 ActorIndex ) { if (TSharedPtr ActorElement = SceneRef->GetActor(ActorIndex)) { return FDatasmithFacadeActor::GetNewFacadeActorFromSharedPtr(ActorElement); } return nullptr; } void FDatasmithFacadeScene::RemoveActor( FDatasmithFacadeActor* InActorPtr, EActorRemovalRule RemovalRule ) { SceneRef->RemoveActor(InActorPtr->GetDatasmithActorElement(), static_cast( RemovalRule )); } void FDatasmithFacadeScene::AddMaterial( FDatasmithFacadeBaseMaterial* InMaterialPtr ) { if (InMaterialPtr) { SceneRef->AddMaterial(InMaterialPtr->GetDatasmithBaseMaterial()); } } int32 FDatasmithFacadeScene::GetMaterialsCount() const { return SceneRef->GetMaterialsCount(); } FDatasmithFacadeBaseMaterial* FDatasmithFacadeScene::GetNewMaterial( int32 MaterialIndex ) { if (TSharedPtr ActorElement = SceneRef->GetMaterial( MaterialIndex )) { return FDatasmithFacadeBaseMaterial::GetNewFacadeBaseMaterialFromSharedPtr( ActorElement ); } return nullptr; } void FDatasmithFacadeScene::RemoveMaterial( FDatasmithFacadeBaseMaterial* InMaterialPtr ) { if (InMaterialPtr) { SceneRef->RemoveMaterial( InMaterialPtr->GetDatasmithBaseMaterial() ); } } FDatasmithFacadeMeshElement* FDatasmithFacadeScene::ExportDatasmithMesh( FDatasmithFacadeMesh* Mesh, FDatasmithFacadeMesh* CollisionMesh /*= nullptr*/ ) { TSharedPtr ExportedMeshElement; FString AssetOutputPath = SceneExporterRef->GetAssetsOutputPath(); if (Mesh && !AssetOutputPath.IsEmpty()) { FDatasmithMesh& MeshRef = Mesh->GetDatasmithMesh(); FDatasmithMesh* CollitionMeshPtr = CollisionMesh ? &CollisionMesh->GetDatasmithMesh() : nullptr; ExportedMeshElement = FDatasmithMeshExporter().ExportToUObject( *AssetOutputPath, Mesh->GetName(), MeshRef, CollitionMeshPtr, FDatasmithExportOptions::LightmapUV ); } return ExportedMeshElement.IsValid() ? new FDatasmithFacadeMeshElement(ExportedMeshElement.ToSharedRef()) : nullptr; } bool FDatasmithFacadeScene::ExportDatasmithMesh( FDatasmithFacadeMeshElement* MeshElement, FDatasmithFacadeMesh* Mesh, FDatasmithFacadeMesh* CollisionMesh /*= nullptr*/ ) { TSharedPtr ExportedMeshElement; FString AssetOutputPath = SceneExporterRef->GetAssetsOutputPath(); if (MeshElement && Mesh && !AssetOutputPath.IsEmpty()) { TSharedPtr MeshElementSharedPtr = MeshElement->GetDatasmithMeshElement(); FDatasmithMesh& MeshRef = Mesh->GetDatasmithMesh(); FDatasmithMesh* CollitionMeshPtr = CollisionMesh ? &CollisionMesh->GetDatasmithMesh() : nullptr; return FDatasmithMeshExporter().ExportToUObject(MeshElementSharedPtr, *AssetOutputPath, MeshRef, CollitionMeshPtr, FDatasmithExportOptions::LightmapUV); } return false; } void FDatasmithFacadeScene::AddMesh( FDatasmithFacadeMeshElement* InMeshPtr ) { if (InMeshPtr) { SceneRef->AddMesh(InMeshPtr->GetDatasmithMeshElement()); } } FDatasmithFacadeMeshElement* FDatasmithFacadeScene::GetNewMesh( int32 MeshIndex ) { if (const TSharedPtr DSMesh = SceneRef->GetMesh(MeshIndex)) { return new FDatasmithFacadeMeshElement(DSMesh.ToSharedRef()); } return nullptr; } void FDatasmithFacadeScene::RemoveMesh( FDatasmithFacadeMeshElement* InMeshElementPtr ) { if (InMeshElementPtr) { SceneRef->RemoveMesh(InMeshElementPtr->GetDatasmithMeshElement()); } } void FDatasmithFacadeScene::AddTexture( FDatasmithFacadeTexture* InTexturePtr ) { if (InTexturePtr) { // Make sure ElementHash is valid TSharedRef TextureElement = InTexturePtr->GetDatasmithTextureElement(); FMD5Hash FileHash = FMD5Hash::HashFile(TextureElement->GetFile()); TextureElement->SetFileHash(FileHash); TextureElement->CalculateElementHash(true); SceneRef->AddTexture(TextureElement); } } int32 FDatasmithFacadeScene::GetTexturesCount() const { return SceneRef->GetTexturesCount(); } FDatasmithFacadeTexture* FDatasmithFacadeScene::GetNewTexture( int32 TextureIndex ) { if (TSharedPtr TextureElement = SceneRef->GetTexture(TextureIndex)) { return new FDatasmithFacadeTexture(TextureElement.ToSharedRef()); } return nullptr; } void FDatasmithFacadeScene::RemoveTexture( FDatasmithFacadeTexture* InTexturePtr ) { SceneRef->RemoveTexture(InTexturePtr->GetDatasmithTextureElement()); } void FDatasmithFacadeScene::AddLevelSequence( FDatasmithFacadeLevelSequence* InLevelSequence ) { if (InLevelSequence) { SceneRef->AddLevelSequence(InLevelSequence->GetDatasmithLevelSequence()); } } int32 FDatasmithFacadeScene::GetLevelSequencesCount() const { return SceneRef->GetLevelSequencesCount(); } FDatasmithFacadeLevelSequence* FDatasmithFacadeScene::GetNewLevelSequence( int32 LevelSequenceIndex ) { if (TSharedPtr LevelSequenceElement = SceneRef->GetLevelSequence(LevelSequenceIndex)) { return new FDatasmithFacadeLevelSequence(LevelSequenceElement.ToSharedRef()); } return nullptr; } void FDatasmithFacadeScene::RemoveLevelSequence( FDatasmithFacadeLevelSequence* InLevelSequence ) { SceneRef->RemoveLevelSequence(InLevelSequence->GetDatasmithLevelSequence()); } void FDatasmithFacadeScene::AddLevelVariantSets( FDatasmithFacadeLevelVariantSets* InLevelVariantSetsPtr ) { if (InLevelVariantSetsPtr) { SceneRef->AddLevelVariantSets(InLevelVariantSetsPtr->GetDatasmithLevelVariantSets()); } } int32 FDatasmithFacadeScene::GetLevelVariantSetsCount() const { return SceneRef->GetLevelVariantSetsCount(); } FDatasmithFacadeLevelVariantSets* FDatasmithFacadeScene::GetNewLevelVariantSets( int32 LevelVariantSetsIndex ) { if (TSharedPtr LevelVariantSetsElement = SceneRef->GetLevelVariantSets(LevelVariantSetsIndex)) { return new FDatasmithFacadeLevelVariantSets(LevelVariantSetsElement.ToSharedRef()); } return nullptr; } void FDatasmithFacadeScene::RemoveLevelVariantSets( FDatasmithFacadeLevelVariantSets* InLevelVariantSetsPtr ) { SceneRef->RemoveLevelVariantSets(InLevelVariantSetsPtr->GetDatasmithLevelVariantSets()); } void FDatasmithFacadeScene::AddMetaData( FDatasmithFacadeMetaData* InMetaData ) { if (InMetaData) { SceneRef->AddMetaData(InMetaData->GetDatasmithMetaDataElement()); } } int32 FDatasmithFacadeScene::GetMetaDataCount() const { return SceneRef->GetMetaDataCount(); } FDatasmithFacadeMetaData* FDatasmithFacadeScene::GetNewMetaData( int32 MetaDataIndex ) { if (TSharedPtr MetaDataElement = SceneRef->GetMetaData(MetaDataIndex)) { return new FDatasmithFacadeMetaData(MetaDataElement.ToSharedRef()); } return nullptr; } FDatasmithFacadeMetaData* FDatasmithFacadeScene::GetNewMetaData( FDatasmithFacadeElement* Element ) { if (Element) { if (TSharedPtr MetaDataElement = SceneRef->GetMetaData(Element->GetDatasmithElement())) { return new FDatasmithFacadeMetaData(MetaDataElement.ToSharedRef()); } } return nullptr; } void FDatasmithFacadeScene::RemoveMetaData( FDatasmithFacadeMetaData* InMetaDataPtr ) { SceneRef->RemoveMetaData(InMetaDataPtr->GetDatasmithMetaDataElement()); } //This function is a temporary workaround to make sure Materials and texture are not deleted from the scene. //There won't be a need to reset the scene once all the Facade elements will stop generating DatasmithElement on the fly (and duplicating the data) during BuildElement() void ResetBuiltFacadeElement(TSharedRef& SceneRef) { TArray> MeshesArray; TArray> MaterialArray; TArray> TextureArray; TArray> MetaDataArray; TArray> ActorArray; TArray> LevelSequences; TArray> LevelVariantSets; const int32 MeshCount = SceneRef->GetMeshesCount(); const int32 MaterialCount = SceneRef->GetMaterialsCount(); const int32 TextureCount = SceneRef->GetTexturesCount(); const int32 MetaDataCount = SceneRef->GetMetaDataCount(); const int32 ActorCount = SceneRef->GetActorsCount(); const int32 LevelSequencesCount = SceneRef->GetLevelSequencesCount(); const int32 LevelVariantSetsCount = SceneRef->GetLevelVariantSetsCount(); MeshesArray.Reserve( MeshCount ); MaterialArray.Reserve( MaterialCount ); TextureArray.Reserve( TextureCount ); MetaDataArray.Reserve( MetaDataCount ); ActorArray.Reserve( ActorCount ); LevelSequences.Reserve( LevelSequencesCount ); LevelVariantSets.Reserve( LevelVariantSetsCount ); //Backup Meshes, Materials and Textures before reseting the scene in order to restore them. for ( int32 MeshIndex = 0; MeshIndex < MeshCount; ++MeshIndex ) { MeshesArray.Add( SceneRef->GetMesh( MeshIndex ) ); } for ( int32 MaterialIndex = 0; MaterialIndex < MaterialCount; ++MaterialIndex ) { MaterialArray.Add( SceneRef->GetMaterial( MaterialIndex ) ); } for ( int32 TextureIndex = 0; TextureIndex < TextureCount; ++TextureIndex ) { TextureArray.Add( SceneRef->GetTexture( TextureIndex ) ); } for ( int32 MetaDataIndex = 0; MetaDataIndex < MetaDataCount; ++MetaDataIndex ) { MetaDataArray.Add( SceneRef->GetMetaData( MetaDataIndex ) ); } for ( int32 ActorIndex = 0; ActorIndex < ActorCount; ++ActorIndex ) { ActorArray.Add( SceneRef->GetActor( ActorIndex ) ); } for ( int32 LevelSequenceIndex = 0; LevelSequenceIndex < LevelSequencesCount; ++LevelSequenceIndex ) { LevelSequences.Add( SceneRef->GetLevelSequence( LevelSequenceIndex ) ); } for ( int32 LevelVariantSetIndex = 0; LevelVariantSetIndex < LevelVariantSetsCount; ++LevelVariantSetIndex ) { LevelVariantSets.Add( SceneRef->GetLevelVariantSets( LevelVariantSetIndex ) ); } SceneRef->Reset(); for ( TSharedPtr& CurrentMesh : MeshesArray ) { SceneRef->AddMesh( CurrentMesh ); } for ( TSharedPtr& CurrentMaterial : MaterialArray ) { SceneRef->AddMaterial( CurrentMaterial ); } for ( TSharedPtr& CurrentTexture: TextureArray ) { SceneRef->AddTexture( CurrentTexture ); } for ( TSharedPtr& CurrentMetaData : MetaDataArray ) { SceneRef->AddMetaData( CurrentMetaData ); } for ( TSharedPtr& CurrentLevelSequence : LevelSequences ) { SceneRef->AddLevelSequence( CurrentLevelSequence.ToSharedRef() ); } for ( TSharedPtr& CurrentLevelVariantSet : LevelVariantSets ) { SceneRef->AddLevelVariantSets( CurrentLevelVariantSet ); } for ( TSharedPtr& CurrentActor : ActorArray ) { SceneRef->AddActor( CurrentActor ); } } void FDatasmithFacadeScene::CleanUp() { FDatasmithSceneUtils::CleanUpScene(SceneRef, true); } void FDatasmithFacadeScene::PreExport() { // Initialize the Datasmith exporter module. FDatasmithExporterManager::Initialize(); // Start measuring the time taken to export the scene. SceneExporterRef->PreExport(); } void FDatasmithFacadeScene::SetName(const TCHAR* InName) { SceneExporterRef->SetName(InName); SceneRef->SetName(SceneExporterRef->GetName()); } const TCHAR* FDatasmithFacadeScene::GetName() const { return SceneExporterRef->GetName(); } void FDatasmithFacadeScene::SetOutputPath(const TCHAR* InOutputPath) { SceneExporterRef->SetOutputPath(InOutputPath); SceneRef->SetResourcePath(SceneExporterRef->GetOutputPath()); } const TCHAR* FDatasmithFacadeScene::GetOutputPath() const { return SceneExporterRef->GetOutputPath(); } const TCHAR* FDatasmithFacadeScene::GetAssetsOutputPath() const { return SceneExporterRef->GetAssetsOutputPath(); } void FDatasmithFacadeScene::SetGeolocationLatitude(double Latitude) { SceneRef->SetGeolocationLatitude(Latitude); } void FDatasmithFacadeScene::SetGeolocationLongitude(double Longitude) { SceneRef->SetGeolocationLongitude(Longitude); } void FDatasmithFacadeScene::SetGeolocationElevation(double Elevation) { SceneRef->SetGeolocationElevation(Elevation); } void FDatasmithFacadeScene::GetGeolocation(double& OutLatitude, double& OutLongitude, double& OutElevation) const { FVector Geolocation = SceneRef->GetGeolocation(); OutLatitude = Geolocation.X; OutLongitude = Geolocation.Y; OutElevation = Geolocation.Z; } void FDatasmithFacadeScene::Shutdown() { FDatasmithExporterManager::Shutdown(); } bool FDatasmithFacadeScene::ExportScene( const TCHAR* InOutputPath, bool bCleanupUnusedElements ) { FString OutputPath = InOutputPath; // Set the name of the scene to export and let Datasmith sanitize it when required. FString SceneName = FPaths::GetBaseFilename(OutputPath); SetName(*SceneName); // Set the output folder where this scene will be exported. FString SceneFolder = FPaths::GetPath(OutputPath); SetOutputPath(*SceneFolder); return ExportScene(bCleanupUnusedElements); } bool FDatasmithFacadeScene::ExportScene(bool bCleanupUnusedElements) { if ( FCString::Strlen(SceneExporterRef->GetName()) == 0 || FCString::Strlen(SceneExporterRef->GetOutputPath()) == 0) { return false; } // Export the Datasmith scene instance into its file. SceneExporterRef->Export(SceneRef, bCleanupUnusedElements); return true; } void FDatasmithFacadeScene::SerializeLevelSequences() { FDatasmithAnimationSerializer AnimSerializer; int32 NumSequences = SceneRef->GetLevelSequencesCount(); for (int32 SequenceIndex = 0; SequenceIndex < NumSequences; ++SequenceIndex) { const TSharedPtr& LevelSequence = SceneRef->GetLevelSequence(SequenceIndex); if (LevelSequence.IsValid()) { FString AnimFilePath = FPaths::Combine(SceneExporterRef->GetAssetsOutputPath(), LevelSequence->GetName()) + DATASMITH_ANIMATION_EXTENSION; if (AnimSerializer.Serialize(LevelSequence.ToSharedRef(), *AnimFilePath)) { TUniquePtr AnimArchive(IFileManager::Get().CreateFileReader(*AnimFilePath)); if (AnimArchive) { LevelSequence->SetFileHash(FMD5Hash::HashFileFromArchive(AnimArchive.Get())); } LevelSequence->SetFile(*AnimFilePath); } } } } TSharedRef FDatasmithFacadeScene::GetScene() const { return SceneRef; } void FDatasmithFacadeScene::SetLabel(const TCHAR* InSceneLabel) { SceneRef->SetLabel(InSceneLabel); } const TCHAR* FDatasmithFacadeScene::GetLabel() const { return SceneRef->GetLabel(); }