diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6582eaf --- /dev/null +++ b/.gitignore @@ -0,0 +1,74 @@ +# Visual Studio 2015 user specific files +.vs/ + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app +*.ipa + +# These project files can be generated by the engine +*.xcodeproj +*.xcworkspace +*.sln +*.suo +*.opensdf +*.sdf +*.VC.db +*.VC.opendb + +# Precompiled Assets +SourceArt/**/*.png +SourceArt/**/*.tga + +# Binary Files +Binaries/* +Plugins/*/Binaries/* + +# Builds +Build/* + +# Whitelist PakBlacklist-.txt files +!Build/*/ +Build/*/** +!Build/*/PakBlacklist*.txt + +# Don't ignore icon files in Build +!Build/**/*.ico + +# Built data for maps +*_BuiltData.uasset + +# Configuration files generated by the Editor +Saved/* + +# Compiled source files for the engine to use +Intermediate/* +Plugins/*/Intermediate/* + +# Cache files for the editor to use +DerivedDataCache/* diff --git a/Source/TransientObjectSaver/Private/TransientObjectSaverLibrary.cpp b/Source/TransientObjectSaver/Private/TransientObjectSaverLibrary.cpp index 09d562e..66d700a 100644 --- a/Source/TransientObjectSaver/Private/TransientObjectSaverLibrary.cpp +++ b/Source/TransientObjectSaver/Private/TransientObjectSaverLibrary.cpp @@ -8,8 +8,13 @@ #include "Rendering/SkeletalMeshRenderData.h" #include "Materials/MaterialInstanceConstant.h" #include "LODUtilities.h" +#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 1 +#include "Engine/SkinnedAssetCommon.h" +#endif +DEFINE_LOG_CATEGORY(LogTransientObjectSaver); + namespace TransientObjectSaver { bool IsTransient(UObject* Object) @@ -31,20 +36,20 @@ namespace TransientObjectSaver { if (!FPackageName::IsValidObjectPath(Path)) { - UE_LOG(LogTemp, Error, TEXT("Invalid UPackage path %s"), *Path); + UE_LOG(LogTransientObjectSaver, Error, TEXT("Invalid UPackage path %s"), *Path); return false; } if (FindPackage(nullptr, *Path) || LoadPackage(nullptr, *Path, EObjectFlags::RF_Public | EObjectFlags::RF_Standalone)) { - UE_LOG(LogTemp, Error, TEXT("UPackage %s already exists"), *Path); + UE_LOG(LogTransientObjectSaver, Error, TEXT("UPackage %s already exists"), *Path); return false; } UPackage* NewPackage = CreatePackage(*Path); if (!NewPackage) { - UE_LOG(LogTemp, Error, TEXT("Unable to create UPackage %s"), *Path); + UE_LOG(LogTransientObjectSaver, Error, TEXT("Unable to create UPackage %s"), *Path); return false; } @@ -52,7 +57,7 @@ namespace TransientObjectSaver if (!Object->Rename(nullptr, NewPackage, REN_DontCreateRedirectors)) { - UE_LOG(LogTemp, Error, TEXT("Unable to move UObject %s into UPackage %s"), *Object->GetFullName(), *Path); + UE_LOG(LogTransientObjectSaver, Error, TEXT("Unable to move UObject %s into UPackage %s"), *Object->GetFullName(), *Path); return false; } @@ -67,13 +72,13 @@ namespace TransientObjectSaver if (!Object->Rename(*NewName, nullptr, REN_DontCreateRedirectors)) { - UE_LOG(LogTemp, Error, TEXT("Unable to rename UObject %s to %s"), *Object->GetFullName(), *NewName); + UE_LOG(LogTransientObjectSaver, Error, TEXT("Unable to rename UObject %s to %s"), *Object->GetFullName(), *NewName); return false; } if (!UPackage::SavePackage(NewPackage, Object, EObjectFlags::RF_Standalone | EObjectFlags::RF_Public, *FPackageName::LongPackageNameToFilename(Path, FPackageName::GetAssetPackageExtension()))) { - UE_LOG(LogTemp, Error, TEXT("Unable to save UPackage %s"), *NewPackage->GetPathName()); + UE_LOG(LogTransientObjectSaver, Error, TEXT("Unable to save UPackage %s"), *NewPackage->GetPathName()); return false; } @@ -98,7 +103,7 @@ bool UTransientObjectSaverLibrary::SaveTransientMaterial(UMaterialInterface* Mat return false; } - UE_LOG(LogTemp, Error, TEXT("Material %s %s %d"), *(Material->GetFullName()), *(Material->GetOutermost()->GetFullName()), Material->GetOutermost()->HasAnyFlags(EObjectFlags::RF_Transient)); + UE_LOG(LogTransientObjectSaver, Log, TEXT("Material %s %s %d"), *(Material->GetFullName()), *(Material->GetOutermost()->GetFullName()), Material->GetOutermost()->HasAnyFlags(EObjectFlags::RF_Transient)); UMaterialInstanceDynamic* MaterialInstanceDynamic = Cast(Material); if (MaterialInstanceDynamic) { @@ -113,7 +118,7 @@ bool UTransientObjectSaverLibrary::SaveTransientMaterial(UMaterialInterface* Mat float Value = 0; if (MaterialInstanceDynamic->GetScalarParameterValue(MaterialsParameterInfos[ParameterIndex].Name, Value, true)) { - UE_LOG(LogTemp, Warning, TEXT("Param: %s [%s] = %f"), *MaterialsParameterInfos[ParameterIndex].Name.ToString(), *ParameterGuids[ParameterIndex].ToString(), Value); + UE_LOG(LogTransientObjectSaver, Warning, TEXT("Param: %s [%s] = %f"), *MaterialsParameterInfos[ParameterIndex].Name.ToString(), *ParameterGuids[ParameterIndex].ToString(), Value); MaterialInstance->SetScalarParameterValueEditorOnly(MaterialsParameterInfos[ParameterIndex], Value); } } @@ -124,7 +129,7 @@ bool UTransientObjectSaverLibrary::SaveTransientMaterial(UMaterialInterface* Mat FLinearColor Value = FLinearColor::Black; if (MaterialInstanceDynamic->GetVectorParameterValue(MaterialsParameterInfos[ParameterIndex].Name, Value, true)) { - UE_LOG(LogTemp, Warning, TEXT("Param: %s [%s] = %s"), *MaterialsParameterInfos[ParameterIndex].Name.ToString(), *ParameterGuids[ParameterIndex].ToString(), *Value.ToString()); + UE_LOG(LogTransientObjectSaver, Warning, TEXT("Param: %s [%s] = %s"), *MaterialsParameterInfos[ParameterIndex].Name.ToString(), *ParameterGuids[ParameterIndex].ToString(), *Value.ToString()); MaterialInstance->SetVectorParameterValueEditorOnly(MaterialsParameterInfos[ParameterIndex], Value); } } @@ -135,33 +140,44 @@ bool UTransientObjectSaverLibrary::SaveTransientMaterial(UMaterialInterface* Mat UTexture* Value = nullptr; if (MaterialInstanceDynamic->GetTextureParameterValue(MaterialsParameterInfos[ParameterIndex].Name, Value, true)) { - if (TransientObjectSaver::IsTransient(Value)) - { - if (!Value->Source.IsValid()) - { - UTexture2D* Texture2D = Cast(Value); - if (Texture2D) - { - FTexturePlatformData* PlatformData = Texture2D->GetPlatformData(); - if (PlatformData->Mips.IsValidIndex(0)) - { - const void* Data = PlatformData->Mips[0].BulkData.LockReadOnly(); - - FImageView ImageView(const_cast(Data), PlatformData->Mips[0].SizeX, PlatformData->Mips[0].SizeY, ERawImageFormat::BGRA8); - PlatformData->Mips[0].BulkData.Unlock(); - Value->Source.Init(ImageView); - } - } - } - const FString TextureName = TextureNameGenerator.Execute(Value, Material, MaterialPath, MaterialsParameterInfos[ParameterIndex].Name.ToString()); - if (!TextureName.IsEmpty()) - { - TransientObjectSaver::SaveUObject(Value, TextureName); - } - } - UE_LOG(LogTemp, Warning, TEXT("Param: %s [%s] = %s"), *MaterialsParameterInfos[ParameterIndex].Name.ToString(), *ParameterGuids[ParameterIndex].ToString(), *Value->GetFullName()); - MaterialInstance->SetTextureParameterValueEditorOnly(MaterialsParameterInfos[ParameterIndex], Value); + if (TransientObjectSaver::IsTransient(Value)) + { + if (!Value->Source.IsValid()) + { + UTexture2D* Texture2D = Cast(Value); + if (Texture2D) + { + FTexturePlatformData* PlatformData = Texture2D->GetPlatformData(); + if (PlatformData && PlatformData->Mips.IsValidIndex(0)) + { + const void* Data = PlatformData->Mips[0].BulkData.LockReadOnly(); + const int32 Width = PlatformData->Mips[0].SizeX; + const int32 Height = PlatformData->Mips[0].SizeY; + int32 ImageBytes = Width * Height * 4; // Assuming 4 bytes per pixel for BGRA8 + + TArray ImageData; + ImageData.AddUninitialized(ImageBytes); + + FMemory::Memcpy(ImageData.GetData(), Data, ImageBytes); + + PlatformData->Mips[0].BulkData.Unlock(); + + Value->Source.Init(Width, Height, 1, 1, TSF_BGRA8, ImageData.GetData()); + } + } + } + + const FString TextureName = TextureNameGenerator.Execute(Value, Material, MaterialPath, MaterialsParameterInfos[ParameterIndex].Name.ToString()); + if (!TextureName.IsEmpty()) + { + TransientObjectSaver::SaveUObject(Value, TextureName); + } + } + + UE_LOG(LogTransientObjectSaver, Warning, TEXT("Param: %s [%s] = %s"), *MaterialsParameterInfos[ParameterIndex].Name.ToString(), *ParameterGuids[ParameterIndex].ToString(), *Value->GetFullName()); + MaterialInstance->SetTextureParameterValueEditorOnly(MaterialsParameterInfos[ParameterIndex], Value); } + } OutMaterial = MaterialInstance; return TransientObjectSaver::SaveUObject(MaterialInstance, MaterialPath); @@ -189,7 +205,7 @@ bool UTransientObjectSaverLibrary::SaveTransientStaticMesh(UStaticMesh* StaticMe if (!StaticMesh->GetMeshDescription(0)) { - UE_LOG(LogTemp, Error, TEXT("The StaticMesh has no MeshDescription")); + UE_LOG(LogTransientObjectSaver, Error, TEXT("The StaticMesh has no MeshDescription")); return false; } @@ -218,8 +234,9 @@ bool UTransientObjectSaverLibrary::SaveTransientStaticMesh(UStaticMesh* StaticMe bool UTransientObjectSaverLibrary::SaveTransientSkeletalMesh(USkeletalMesh* SkeletalMesh, const FString& SkeletalMeshPath, const FString& SkeletonPath, const FString& PhysicsAssetPath, const FTransientObjectSaverMaterialNameGenerator& MaterialNameGenerator, const FTransientObjectSaverTextureNameGenerator& TextureNameGenerator) { - if (!SkeletalMesh) + if (!IsValid(SkeletalMesh)) { + UE_LOG(LogTransientObjectSaver, Error, TEXT("Invalid or destroyed SkeletalMesh.")); return false; } @@ -234,16 +251,16 @@ bool UTransientObjectSaverLibrary::SaveTransientSkeletalMesh(USkeletalMesh* Skel FSkeletalMeshModel* ImportedResource = SkeletalMesh->GetImportedModel(); if (!ImportedResource) { - UE_LOG(LogTemp, Error, TEXT("Unable to GetImportedModel()")); + UE_LOG(LogTransientObjectSaver, Error, TEXT("Unable to GetImportedModel()")); return false; } - UE_LOG(LogTemp, Error, TEXT("ImportedResource: %d"), ImportedResource->LODModels.Num()); + UE_LOG(LogTransientObjectSaver, Log, TEXT("ImportedResource: %d"), ImportedResource->LODModels.Num()); FSkeletalMeshRenderData* RenderData = SkeletalMesh->GetResourceForRendering(); if (!RenderData) { - UE_LOG(LogTemp, Error, TEXT("Unable to access RenderData")); + UE_LOG(LogTransientObjectSaver, Error, TEXT("Unable to access RenderData")); return false; } @@ -273,7 +290,7 @@ bool UTransientObjectSaverLibrary::SaveTransientSkeletalMesh(USkeletalMesh* Skel //ImportData.PointToRawMap.Add(VertexIndex); //} - UE_LOG(LogTemp, Error, TEXT("LOD %d has %d vertices and %d sections"), LODIndex, ImportedResource->LODModels[LODIndex].NumVertices, ImportedResource->LODModels[LODIndex].Sections.Num()); + UE_LOG(LogTransientObjectSaver, Log, TEXT("LOD %d has %d vertices and %d sections"), LODIndex, ImportedResource->LODModels[LODIndex].NumVertices, ImportedResource->LODModels[LODIndex].Sections.Num()); const int32 NumSections = RenderData->LODRenderData[LODIndex].RenderSections.Num(); for (int32 SectionIndex = 0; SectionIndex < NumSections; SectionIndex++) { diff --git a/Source/TransientObjectSaver/Public/TransientObjectSaverLibrary.h b/Source/TransientObjectSaver/Public/TransientObjectSaverLibrary.h index db45985..66a5c9e 100644 --- a/Source/TransientObjectSaver/Public/TransientObjectSaverLibrary.h +++ b/Source/TransientObjectSaver/Public/TransientObjectSaverLibrary.h @@ -6,6 +6,8 @@ #include "Kismet/BlueprintFunctionLibrary.h" #include "TransientObjectSaverLibrary.generated.h" +TRANSIENTOBJECTSAVER_API DECLARE_LOG_CATEGORY_EXTERN(LogTransientObjectSaver, Log, All); + DECLARE_DYNAMIC_DELEGATE_RetVal_ThreeParams(FString, FTransientObjectSaverMaterialNameGenerator, UMaterialInterface*, Material, const int32, MaterialIndex, const FString&, SlotName); DECLARE_DYNAMIC_DELEGATE_RetVal_FourParams(FString, FTransientObjectSaverTextureNameGenerator, UTexture*, Texture, UMaterialInterface*, Material, const FString&, MaterialPath, const FString&, ParamName);