211 lines
7.9 KiB
C++
211 lines
7.9 KiB
C++
|
|
// Lot STM1 (STM1-SPEC-11, M3 ; 1.4.3, STM1-SPEC-19 A1). Voir LPBindLandmarkTexturesCommandlet.h.
|
||
|
|
|
||
|
|
#include "LPBindLandmarkTexturesCommandlet.h"
|
||
|
|
|
||
|
|
#include "AssetRegistry/AssetRegistryModule.h"
|
||
|
|
#include "Engine/Texture2D.h"
|
||
|
|
#include "Factories/TextureFactory.h"
|
||
|
|
#include "HAL/FileManager.h"
|
||
|
|
#include "MaterialEditingLibrary.h"
|
||
|
|
#include "Materials/Material.h"
|
||
|
|
#include "Materials/MaterialExpressionTextureBase.h"
|
||
|
|
#include "Materials/MaterialExpressionTextureSample.h"
|
||
|
|
#include "Misc/FileHelper.h"
|
||
|
|
#include "Misc/PackageName.h"
|
||
|
|
#include "Misc/Paths.h"
|
||
|
|
#include "UObject/Package.h"
|
||
|
|
#include "UObject/SavePackage.h"
|
||
|
|
|
||
|
|
DEFINE_LOG_CATEGORY_STATIC(LogLPBindLandmarkTextures, Log, All);
|
||
|
|
|
||
|
|
namespace LPBindLandmarkTextures
|
||
|
|
{
|
||
|
|
/** 1.4.3 : aussi /lpm_city_<v>/Houses/<Nom> (arbres poses en HISM avec les maisons). */
|
||
|
|
bool IsAllowedFolder(const FString& Folder)
|
||
|
|
{
|
||
|
|
if (Folder.StartsWith(TEXT("/Game/Heavy/StreetMap/Landmarks/")))
|
||
|
|
{
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
TArray<FString> Parts;
|
||
|
|
Folder.ParseIntoArray(Parts, TEXT("/"));
|
||
|
|
return Parts.Num() == 3 && Parts[0].StartsWith(TEXT("lpm_city_")) && (Parts[1] == TEXT("Landmarks") || Parts[1] == TEXT("Houses"));
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Save(UPackage* Package, UObject* Asset)
|
||
|
|
{
|
||
|
|
FSavePackageArgs Args;
|
||
|
|
Args.TopLevelFlags = RF_Public | RF_Standalone;
|
||
|
|
return UPackage::SavePackage(Package, Asset, *FPackageName::LongPackageNameToFilename(Package->GetName(), FPackageName::GetAssetPackageExtension()), Args);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
ULPBindLandmarkTexturesCommandlet::ULPBindLandmarkTexturesCommandlet()
|
||
|
|
{
|
||
|
|
IsClient = false;
|
||
|
|
IsServer = false;
|
||
|
|
IsEditor = true;
|
||
|
|
LogToConsole = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
int32 ULPBindLandmarkTexturesCommandlet::Main(const FString& Params)
|
||
|
|
{
|
||
|
|
using namespace LPBindLandmarkTextures;
|
||
|
|
|
||
|
|
TArray<FString> Tokens, Switches;
|
||
|
|
TMap<FString, FString> ParamsMap;
|
||
|
|
ParseCommandLine(*Params, Tokens, Switches, ParamsMap);
|
||
|
|
const FString Folder = ParamsMap.FindRef(TEXT("Folder"));
|
||
|
|
const FString TexDir = ParamsMap.FindRef(TEXT("TexDir"));
|
||
|
|
const FString ReportPath = ParamsMap.FindRef(TEXT("Report"));
|
||
|
|
const int32 MaxTexture = ParamsMap.Contains(TEXT("MaxTexture")) ? FCString::Atoi(*ParamsMap[TEXT("MaxTexture")]) : 2048;
|
||
|
|
// 1.4.3 : -Masked=<materiau>,... : feuillage ; opacite = alpha de la texture, materiau Masked et double face.
|
||
|
|
TArray<FString> MaskedNames;
|
||
|
|
ParamsMap.FindRef(TEXT("Masked")).ParseIntoArray(MaskedNames, TEXT(","));
|
||
|
|
TMap<FString, FString> Explicit;
|
||
|
|
{
|
||
|
|
TArray<FString> Pairs;
|
||
|
|
ParamsMap.FindRef(TEXT("Map")).ParseIntoArray(Pairs, TEXT(";"));
|
||
|
|
for (const FString& Pair : Pairs)
|
||
|
|
{
|
||
|
|
FString Key, Value;
|
||
|
|
if (Pair.Split(TEXT("="), &Key, &Value)) Explicit.Add(Key, Value);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
TArray<FString> Report;
|
||
|
|
auto Line = [&Report](const FString& Text)
|
||
|
|
{
|
||
|
|
UE_LOG(LogLPBindLandmarkTextures, Display, TEXT("%s"), *Text);
|
||
|
|
Report.Add(Text);
|
||
|
|
};
|
||
|
|
auto Finish = [&](int32 Code)
|
||
|
|
{
|
||
|
|
Line(FString::Printf(TEXT("CODE %d"), Code));
|
||
|
|
if (!ReportPath.IsEmpty())
|
||
|
|
{
|
||
|
|
FFileHelper::SaveStringArrayToFile(Report, *ReportPath, FFileHelper::EEncodingOptions::ForceUTF8WithoutBOM);
|
||
|
|
}
|
||
|
|
return Code;
|
||
|
|
};
|
||
|
|
|
||
|
|
if (Folder.IsEmpty() || TexDir.IsEmpty())
|
||
|
|
{
|
||
|
|
Line(TEXT("usage : -Folder=</lpm_city_<v>/(Landmarks|Houses)/<Nom>> -TexDir=<dossier> [-Map=<materiau>=<fichier>;...] [-Masked=<materiau>,...] [-MaxTexture=2048] [-Report=<f.md>]"));
|
||
|
|
return Finish(2);
|
||
|
|
}
|
||
|
|
Line(FString::Printf(TEXT("# LPBindLandmarkTextures %s <- %s"), *Folder, *TexDir));
|
||
|
|
if (!IsAllowedFolder(Folder))
|
||
|
|
{
|
||
|
|
Line(TEXT("ECHEC : dossier hors de /lpm_city_*/(Landmarks|Houses)/<Nom> et de /Game/Heavy/StreetMap/Landmarks/ ; rien modifie"));
|
||
|
|
return Finish(1);
|
||
|
|
}
|
||
|
|
|
||
|
|
TArray<FAssetData> Assets;
|
||
|
|
IAssetRegistry& Registry = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry")).Get();
|
||
|
|
Registry.ScanPathsSynchronous({ Folder }, /*bForceRescan=*/true);
|
||
|
|
Registry.GetAssetsByPath(FName(*Folder), Assets, false);
|
||
|
|
int32 Bound = 0, Skipped = 0, Missing = 0;
|
||
|
|
for (const FAssetData& Data : Assets)
|
||
|
|
{
|
||
|
|
if (Data.AssetClassPath != UMaterial::StaticClass()->GetClassPathName()) continue;
|
||
|
|
UMaterial* Material = Cast<UMaterial>(Data.GetAsset());
|
||
|
|
if (!Material) continue;
|
||
|
|
// Une couleur de base deja issue d'une texture est gardee ; une couleur constante (mise par l'importeur FBX faute de
|
||
|
|
// texture reliee) est remplacee par la texture diffuse.
|
||
|
|
const UMaterialExpression* Existing = Material->GetEditorOnlyData() ? Material->GetEditorOnlyData()->BaseColor.Expression : nullptr;
|
||
|
|
if (Existing && Existing->IsA<UMaterialExpressionTextureBase>())
|
||
|
|
{
|
||
|
|
++Skipped;
|
||
|
|
Line(FString::Printf(TEXT("%s : couleur de base deja issue d'une texture (%s), rien fait"), *Material->GetName(), *Existing->GetClass()->GetName()));
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
const FString Name = Material->GetName();
|
||
|
|
TArray<FString> Candidates;
|
||
|
|
if (const FString* File = Explicit.Find(Name)) Candidates.Add(*File);
|
||
|
|
Candidates.Add(FString::Printf(TEXT("T_%s_D.png"), *Name));
|
||
|
|
Candidates.Add(Name + TEXT(".png"));
|
||
|
|
FString Found;
|
||
|
|
for (const FString& C : Candidates)
|
||
|
|
{
|
||
|
|
const FString Path = FPaths::Combine(TexDir, C);
|
||
|
|
if (IFileManager::Get().FileExists(*Path)) { Found = Path; break; }
|
||
|
|
}
|
||
|
|
if (Found.IsEmpty())
|
||
|
|
{
|
||
|
|
++Missing;
|
||
|
|
Line(FString::Printf(TEXT("%s : aucune texture trouvee (%s)"), *Name, *FString::Join(Candidates, TEXT(", "))));
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
const FString TexName = FString::Printf(TEXT("T_%s_D"), *Name);
|
||
|
|
const FString TexPackageName = Folder / TexName;
|
||
|
|
UTexture2D* Texture = nullptr;
|
||
|
|
if (FPackageName::DoesPackageExist(TexPackageName))
|
||
|
|
{
|
||
|
|
Texture = LoadObject<UTexture2D>(nullptr, *FString::Printf(TEXT("%s.%s"), *TexPackageName, *TexName));
|
||
|
|
}
|
||
|
|
if (!Texture)
|
||
|
|
{
|
||
|
|
UTextureFactory* Factory = NewObject<UTextureFactory>(GetTransientPackage());
|
||
|
|
Factory->AddToRoot();
|
||
|
|
Factory->SuppressImportOverwriteDialog();
|
||
|
|
UPackage* TexPackage = CreatePackage(*TexPackageName);
|
||
|
|
bool bCanceled = false;
|
||
|
|
Texture = Cast<UTexture2D>(Factory->ImportObject(UTexture2D::StaticClass(), TexPackage, *TexName, RF_Public | RF_Standalone, Found, nullptr, bCanceled));
|
||
|
|
Factory->RemoveFromRoot();
|
||
|
|
if (!Texture)
|
||
|
|
{
|
||
|
|
Line(FString::Printf(TEXT("ECHEC : import de %s"), *Found));
|
||
|
|
return Finish(1);
|
||
|
|
}
|
||
|
|
Texture->MaxTextureSize = MaxTexture;
|
||
|
|
Texture->PostEditChange();
|
||
|
|
FAssetRegistryModule::AssetCreated(Texture);
|
||
|
|
if (!Save(TexPackage, Texture))
|
||
|
|
{
|
||
|
|
Line(FString::Printf(TEXT("ECHEC : sauvegarde de %s"), *TexPackageName));
|
||
|
|
return Finish(1);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
UMaterialExpressionTextureSample* Sample = Cast<UMaterialExpressionTextureSample>(
|
||
|
|
UMaterialEditingLibrary::CreateMaterialExpression(Material, UMaterialExpressionTextureSample::StaticClass(), -400, 0));
|
||
|
|
if (!Sample)
|
||
|
|
{
|
||
|
|
Line(FString::Printf(TEXT("ECHEC : expression de texture pour %s"), *Name));
|
||
|
|
return Finish(1);
|
||
|
|
}
|
||
|
|
Sample->Texture = Texture;
|
||
|
|
Sample->SamplerType = SAMPLERTYPE_Color;
|
||
|
|
if (!UMaterialEditingLibrary::ConnectMaterialProperty(Sample, TEXT("RGB"), MP_BaseColor))
|
||
|
|
{
|
||
|
|
Line(FString::Printf(TEXT("ECHEC : branchement de la couleur de base de %s"), *Name));
|
||
|
|
return Finish(1);
|
||
|
|
}
|
||
|
|
const bool bMasked = MaskedNames.Contains(Name);
|
||
|
|
if (bMasked)
|
||
|
|
{
|
||
|
|
Material->BlendMode = BLEND_Masked;
|
||
|
|
Material->TwoSided = true;
|
||
|
|
if (!UMaterialEditingLibrary::ConnectMaterialProperty(Sample, TEXT("A"), MP_OpacityMask))
|
||
|
|
{
|
||
|
|
Line(FString::Printf(TEXT("ECHEC : branchement de l'opacite de %s"), *Name));
|
||
|
|
return Finish(1);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
UMaterialEditingLibrary::RecompileMaterial(Material);
|
||
|
|
if (!Save(Material->GetPackage(), Material))
|
||
|
|
{
|
||
|
|
Line(FString::Printf(TEXT("ECHEC : sauvegarde de %s"), *Material->GetPathName()));
|
||
|
|
return Finish(1);
|
||
|
|
}
|
||
|
|
++Bound;
|
||
|
|
Line(FString::Printf(TEXT("%s : %s -> %s (source %d x %d, plafond %d) ; remplace %s%s"), *Name, *FPaths::GetCleanFilename(Found), *TexPackageName,
|
||
|
|
Texture->Source.GetSizeX(), Texture->Source.GetSizeY(), MaxTexture, Existing ? *Existing->GetClass()->GetName() : TEXT("rien"),
|
||
|
|
bMasked ? TEXT(" ; Masked, double face, opacite = alpha") : TEXT("")));
|
||
|
|
}
|
||
|
|
Line(FString::Printf(TEXT("materiaux branches %d ; deja branches %d ; sans texture %d"), Bound, Skipped, Missing));
|
||
|
|
return Finish(0);
|
||
|
|
}
|