// Lot STM1 (COMMUN-28 S6). Voir LPDumpMaterialCommandlet.h. #include "LPDumpMaterialCommandlet.h" #include "Materials/Material.h" #include "Materials/MaterialExpression.h" #include "Misc/FileHelper.h" #include "UObject/UnrealType.h" DEFINE_LOG_CATEGORY_STATIC(LogLPDumpMaterial, Log, All); ULPDumpMaterialCommandlet::ULPDumpMaterialCommandlet() { IsClient = false; IsServer = false; IsEditor = true; LogToConsole = true; } int32 ULPDumpMaterialCommandlet::Main(const FString& Params) { TArray Tokens, Switches; TMap ParamsMap; ParseCommandLine(*Params, Tokens, Switches, ParamsMap); const FString ReportPath = ParamsMap.FindRef(TEXT("Report")); TArray Paths; ParamsMap.FindRef(TEXT("Material")).ParseIntoArray(Paths, TEXT(";")); TArray Report; auto Line = [&Report](const FString& Text) { UE_LOG(LogLPDumpMaterial, 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 (Paths.IsEmpty()) { Line(TEXT("usage : -Material=[;...] [-Report=]")); return Finish(2); } for (const FString& Path : Paths) { UMaterial* Material = LoadObject(nullptr, *Path); Line(FString::Printf(TEXT("# %s"), *Path)); if (!Material) { Line(TEXT("ECHEC : UMaterial introuvable")); return Finish(1); } const TConstArrayView> Expressions = Material->GetExpressions(); auto IndexOf = [&Expressions](const UMaterialExpression* E) { for (int32 I = 0; I < Expressions.Num(); ++I) if (Expressions[I] == E) return I; return int32(INDEX_NONE); }; Line(FString::Printf(TEXT("domaine %s ; melange %s ; ombrage %s ; deux faces %d ; noeuds %d"), *StaticEnum()->GetNameStringByValue(int64(Material->MaterialDomain)), *StaticEnum()->GetNameStringByValue(int64(Material->BlendMode)), *StaticEnum()->GetNameStringByValue(int64(Material->GetShadingModels().GetFirstShadingModel())), Material->IsTwoSided() ? 1 : 0, Expressions.Num())); if (const UMaterialEditorOnlyData* Data = Material->GetEditorOnlyData()) { const TPair Inputs[] = { { TEXT("BaseColor"), &Data->BaseColor }, { TEXT("EmissiveColor"), &Data->EmissiveColor }, { TEXT("Normal"), &Data->Normal }, { TEXT("Metallic"), &Data->Metallic }, { TEXT("Roughness"), &Data->Roughness }, { TEXT("Specular"), &Data->Specular }, { TEXT("Opacity"), &Data->Opacity }, { TEXT("OpacityMask"), &Data->OpacityMask }, { TEXT("WorldPositionOffset"), &Data->WorldPositionOffset } }; for (const TPair& Input : Inputs) { if (Input.Value->Expression) { Line(FString::Printf(TEXT("entree %s <- noeud %d (%s), sortie %d"), Input.Key, IndexOf(Input.Value->Expression), *Input.Value->Expression->GetClass()->GetName(), Input.Value->OutputIndex)); } } } for (int32 I = 0; I < Expressions.Num(); ++I) { UMaterialExpression* E = Expressions[I]; if (!E) continue; TArray Props; for (TFieldIterator It(E->GetClass(), EFieldIteratorFlags::ExcludeSuper); It; ++It) { if (CastField(*It) && CastField(*It)->Struct->GetName().Contains(TEXT("ExpressionInput"))) continue; FString Value; It->ExportTextItem_InContainer(Value, E, nullptr, nullptr, PPF_None); if (Value.Len() > 120) Value = Value.Left(120) + TEXT("..."); Props.Add(FString::Printf(TEXT("%s=%s"), *It->GetName(), *Value)); } TArray Links; for (FExpressionInputIterator It{ E }; It; ++It) { if (It->Expression) { Links.Add(FString::Printf(TEXT("%s<-%d"), *E->GetInputName(It.Index).ToString(), IndexOf(It->Expression))); } } Line(FString::Printf(TEXT(" [%d] %s \"%s\" | %s | entrees : %s"), I, *E->GetClass()->GetName(), *E->GetDescription(), *FString::Join(Props, TEXT(" ; ")), Links.IsEmpty() ? TEXT("-") : *FString::Join(Links, TEXT(", ")))); } } return Finish(0); }