Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -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-<BuildConfiguration>.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/*
99 changes: 58 additions & 41 deletions Source/TransientObjectSaver/Private/TransientObjectSaverLibrary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -31,28 +36,28 @@ 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;
}

UPackage* Package = Object->GetPackage();

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;
}

Expand All @@ -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;
}

Expand All @@ -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<UMaterialInstanceDynamic>(Material);
if (MaterialInstanceDynamic)
{
Expand All @@ -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);
}
}
Expand All @@ -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);
}
}
Expand All @@ -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<UTexture2D>(Value);
if (Texture2D)
{
FTexturePlatformData* PlatformData = Texture2D->GetPlatformData();
if (PlatformData->Mips.IsValidIndex(0))
{
const void* Data = PlatformData->Mips[0].BulkData.LockReadOnly();

FImageView ImageView(const_cast<void*>(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<UTexture2D>(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<uint8> 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);
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}

Expand All @@ -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;
}

Expand Down Expand Up @@ -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++)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down