work on material parameters

This commit is contained in:
2026-04-05 03:20:51 -04:00
parent c949a4db05
commit 9c1f474170
13 changed files with 257 additions and 307 deletions

Binary file not shown.

View File

@@ -24,56 +24,27 @@ public:
UPROPERTY(EditAnywhere, meta=(Description="Target material instance"))
FString MaterialInstance;
UPROPERTY(EditAnywhere, meta=(Description="Parameter name to clear"))
UPROPERTY(EditAnywhere, meta=(Description="Parameter ID: 'Name', 'Layer:N:Name', or 'Blend:N:Name'"))
FString Parameter;
UPROPERTY(EditAnywhere, meta=(Description="Parameter association: 'Global', 'Layer', or 'Blend'. Default: 'Global'", Optional))
FString ParameterAssociation = TEXT("Global");
UPROPERTY(EditAnywhere, meta=(Description="Layer/blend index (0-based). Only used when ParameterAssociation is 'Layer' or 'Blend'", Optional))
int32 ParameterLayer = INDEX_NONE;
virtual void Register() override
{
UWingServer::AddHandler(this,
TEXT("Remove a parameter override from a Material Instance, reverting it to the parent material's value."));
}
virtual void Handle() override
{
WingFetcher F(WingOut::Stdout);
UMaterialInstanceConstant* MI = F.Asset(MaterialInstance).Cast<UMaterialInstanceConstant>();
if (!MI) return;
// Parse the association string.
EMaterialParameterAssociation Association;
if (!WingMaterialParameter::ParseMaterialParameterAssociation(ParameterAssociation, Association, WingOut::Stdout))
// Parse the parameter ID.
FMaterialParameterInfo ID;
if (!WingMaterialParameter::ParseID(Parameter, ID, WingOut::Stdout))
return;
FMaterialParameterInfo ParamID(*Parameter, Association, ParameterLayer);
// Remove the override from all parameter arrays.
auto RemoveFrom = [&](auto& Arr) {
return Arr.RemoveAll([&](auto& Entry) { return Entry.ParameterInfo == ParamID; });
};
int32 Removed = 0;
Removed += RemoveFrom(MI->ScalarParameterValues);
Removed += RemoveFrom(MI->VectorParameterValues);
Removed += RemoveFrom(MI->DoubleVectorParameterValues);
Removed += RemoveFrom(MI->TextureParameterValues);
Removed += RemoveFrom(MI->TextureCollectionParameterValues);
Removed += RemoveFrom(MI->RuntimeVirtualTextureParameterValues);
Removed += RemoveFrom(MI->SparseVolumeTextureParameterValues);
Removed += RemoveFrom(MI->FontParameterValues);
if (Removed == 0)
{
WingOut::Stdout.Printf(TEXT("No override found for parameter '%s' (association=%s layer=%d) on %s"),
*Parameter, *ParameterAssociation, ParameterLayer, *WingUtils::FormatName(MI));
return;
}
WingOut::Stdout.Printf(TEXT("Cleared override for '%s' on %s\n"),
*Parameter, *WingUtils::FormatName(MI));
if (!WingMaterialParameter::RemoveOverride(ID, MI, WingOut::Stdout)) return
WingOut::Stdout.Printf(TEXT("Removed override\n"));
}
};

View File

@@ -36,23 +36,7 @@ public:
if (!MI) return;
auto AllParams = WingMaterialParameter::GetMaterialParameters(MI);
// Overridden parameters first.
bool bHasOverrides = false;
for (auto& [Info, Meta] : AllParams)
{
if (!Meta.bOverride) continue;
if (!bHasOverrides) { WingOut::Stdout.Print(TEXT("\nOverridden Parameters:\n")); bHasOverrides = true; }
WingMaterialParameter::FormatMaterialParameter(Info, Meta);
}
// Inherited (non-overridden) parameters.
bool bHasInherited = false;
for (auto& [Info, Meta] : AllParams)
{
if (Meta.bOverride) continue;
if (!bHasInherited) { WingOut::Stdout.Print(TEXT("\nInherited Parameters (not overridden):\n")); bHasInherited = true; }
WingMaterialParameter::FormatMaterialParameter(Info, Meta);
}
WingMaterialParameter::PrintAll(AllParams, true);
if (AllParams.IsEmpty()) WingOut::Stdout.Printf(TEXT("No material parameters.\n"));
}
};

View File

@@ -25,15 +25,9 @@ public:
UPROPERTY(EditAnywhere, meta=(Description="Target material instance"))
FString MaterialInstance;
UPROPERTY(EditAnywhere, meta=(Description="Parameter name to set"))
UPROPERTY(EditAnywhere, meta=(Description="Parameter ID: 'Name', 'Layer:N:Name', or 'Blend:N:Name'"))
FString Parameter;
UPROPERTY(EditAnywhere, meta=(Description="Parameter association: 'Global', 'Layer', or 'Blend'. Default: 'Global'", Optional))
FString ParameterAssociation = TEXT("Global");
UPROPERTY(EditAnywhere, meta=(Description="Layer/blend index (0-based). Only used when ParameterAssociation is 'Layer' or 'Blend'", Optional))
int32 ParameterLayer = INDEX_NONE;
UPROPERTY(EditAnywhere, meta=(Description="Value to set (uses Unreal text format, e.g. '0.5' for scalar, '(R=1,G=0,B=0,A=1)' for vector)"))
FString Value;
@@ -48,30 +42,19 @@ public:
UMaterialInstanceConstant* MI = F.Asset(MaterialInstance).Cast<UMaterialInstanceConstant>();
if (!MI) return;
// Parse the association string.
EMaterialParameterAssociation Association;
if (!WingMaterialParameter::ParseMaterialParameterAssociation(ParameterAssociation, Association, WingOut::Stdout))
// Parse the parameter ID.
FMaterialParameterInfo ID;
if (!WingMaterialParameter::ParseID(Parameter, ID, WingOut::Stdout))
return;
// Build the parameter ID to look up.
FMaterialParameterInfo ParamID(*Parameter, Association, ParameterLayer);
// Find it in the material's parameter map.
auto AllParams = WingMaterialParameter::GetMaterialParameters(MI);
FMaterialParameterMetadata* Found = AllParams.Find(ParamID);
if (!Found)
{
WingOut::Stdout.Printf(TEXT("No parameter named '%s' with association=%s layer=%d"),
*Parameter, *ParameterAssociation, ParameterLayer);
return;
}
if (Found->PrimitiveDataIndex != INDEX_NONE)
{
WingOut::Stdout.Printf(TEXT("Parameter '%s' uses custom primitive data and cannot be set on a material instance"), *Parameter);
return;
}
FMaterialParameterMetadata* Meta =
WingMaterialParameter::FindParameter(AllParams, ID, WingOut::Stdout);
if (!Meta) return;
if (!WingMaterialParameter::CheckNoCustomPrimitiveData(ID, *Meta, WingOut::Stdout)) return;
EMaterialParameterType Type = Found->Value.Type;
EMaterialParameterType Type = Meta->Value.Type;
switch (Type)
{
@@ -83,7 +66,7 @@ public:
WingOut::Stdout.Printf(TEXT("Failed to parse '%s' as a float"), *Value);
return;
}
MI->SetScalarParameterValueEditorOnly(ParamID, ScalarValue);
MI->SetScalarParameterValueEditorOnly(ID, ScalarValue);
break;
}
case EMaterialParameterType::Vector:
@@ -94,14 +77,13 @@ public:
WingOut::Stdout.Printf(TEXT("Failed to parse '%s' as a color/vector (expected format: '(R=1,G=0,B=0,A=1)')"), *Value);
return;
}
MI->SetVectorParameterValueEditorOnly(ParamID, Color);
MI->SetVectorParameterValueEditorOnly(ID, Color);
break;
}
default:
WingOut::Stdout.Printf(TEXT("Parameters of type %d (see EMaterialParameterType) are not implemented"), (int)Type);
return;
}
WingOut::Stdout.Printf(TEXT("Set '%s' = %s on %s\n"),
*Parameter, *Value, *WingUtils::FormatName(MI));
WingOut::Stdout.Printf(TEXT("Assigned.\n"));
}
};

View File

@@ -35,11 +35,7 @@ public:
if (!Mat) return;
auto AllParams = WingMaterialParameter::GetMaterialParameters(Mat);
for (auto& [Info, Meta] : AllParams)
{
WingMaterialParameter::FormatMaterialParameter(Info, Meta);
}
WingMaterialParameter::PrintAll(AllParams, false);
if (AllParams.IsEmpty()) WingOut::Stdout.Printf(TEXT("No material parameters.\n"));
}
};

View File

@@ -1,32 +0,0 @@
#pragma once
#include "CoreMinimal.h"
#include "WingServer.h"
#include "WingHandler.h"
#include "WingTokenizer.h"
#include "Test_Sanitizer.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS()
class UWing_Test_Sanitizer : public UWingHandler
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, meta=(Description="The string to sanitize"))
FString Input;
virtual void Register() override
{
UWingServer::AddHandler(this,
TEXT("Test the sanitizer by sanitizing a string and printing the result."));
}
virtual void Handle() override
{
WingOut::Stdout.Printf(TEXT("%s\n"), *WingTokenizer::ExternalizeID(FName(Input)));
}
};

View File

@@ -1,33 +0,0 @@
#pragma once
#include "CoreMinimal.h"
#include "WingServer.h"
#include "WingHandler.h"
#include "WingTokenizer.h"
#include "Test_Tokenizer.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS()
class UWing_Test_Tokenizer : public UWingHandler
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, meta=(Description="The string to tokenize"))
FString Input;
virtual void Register() override
{
UWingServer::AddHandler(this,
TEXT("Test the tokenizer by tokenizing a string and printing the result."));
}
virtual void Handle() override
{
WingTokenizer T(Input);
T.PrintEverything(WingOut::StdoutBuffer);
}
};

View File

@@ -1,63 +0,0 @@
#pragma once
#include "CoreMinimal.h"
#include "WingServer.h"
#include "WingHandler.h"
#include "WingTypes.h"
#include "Test_TypeToText.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS()
class UWing_Test_TypeToText : public UWingHandler
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, meta=(Description="The type name to parse, e.g. 'Array<Vector>'"))
FString Input;
virtual void Register() override
{
UWingServer::AddHandler(this,
TEXT("Test the type parser by parsing a type name and dumping the resulting FEdGraphPinType."));
}
virtual void Handle() override
{
FEdGraphPinType PinType;
UWingTypes::Requirements Require;
Require.BlueprintType = false;
Require.Blueprintable = false;
Require.AllowContainer = true;
bool OK = UWingTypes::TextToType(Input, PinType, Require, WingOut::Stdout);
auto& Out = WingOut::Stdout;
Out.Printf(TEXT("ParseResult: %s\n"), OK ? TEXT("OK") : TEXT("FAILED"));
Out.Printf(TEXT("PinCategory: %s\n"), *PinType.PinCategory.ToString());
Out.Printf(TEXT("PinSubCategory: %s\n"), *PinType.PinSubCategory.ToString());
Out.Printf(TEXT("PinSubCategoryObject: %s\n"),
PinType.PinSubCategoryObject.IsValid()
? *PinType.PinSubCategoryObject->GetPathName()
: TEXT("(none)"));
Out.Printf(TEXT("ContainerType: %d\n"), (int32)PinType.ContainerType);
if (PinType.IsMap())
{
Out.Printf(TEXT("ValueTerminalCategory: %s\n"), *PinType.PinValueType.TerminalCategory.ToString());
Out.Printf(TEXT("ValueTerminalSubCategory: %s\n"), *PinType.PinValueType.TerminalSubCategory.ToString());
Out.Printf(TEXT("ValueTerminalSubCategoryObject: %s\n"),
PinType.PinValueType.TerminalSubCategoryObject.IsValid()
? *PinType.PinValueType.TerminalSubCategoryObject->GetPathName()
: TEXT("(none)"));
}
if (OK)
{
FString RoundTrip = UWingTypes::TypeToText(PinType);
Out.Printf(TEXT("TypeToText: %s\n"), RoundTrip.IsEmpty() ? TEXT("(empty)") : *RoundTrip);
}
}
};

View File

@@ -1,41 +0,0 @@
#pragma once
#include "CoreMinimal.h"
#include "WingServer.h"
#include "WingHandler.h"
#include "WingTokenizer.h"
#include "Test_Unsanitize.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS()
class UWing_Test_Unsanitize : public UWingHandler
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, meta=(Description="The sanitized identifier to unsanitize"))
FString Input;
virtual void Register() override
{
UWingServer::AddHandler(this,
TEXT("Test the unsanitizer by unsanitizing a string and printing the result."));
}
virtual void Handle() override
{
FString Error;
FName Result = WingTokenizer::TryInternalizeID(Input, Error);
if (!Error.IsEmpty())
{
WingOut::Stdout.Printf(TEXT("Error: %s\n"), *Error);
}
if (!Result.IsNone())
{
WingOut::Stdout.Printf(TEXT("Result: %s\n"), *Result.ToString());
}
}
};

View File

@@ -1,12 +1,13 @@
#include "WingMaterialParameter.h"
#include "WingUtils.h"
#include "WingTokenizer.h"
#include "WingServer.h"
TMap<FMaterialParameterInfo, FMaterialParameterMetadata> WingMaterialParameter::GetMaterialParameters(UMaterialInterface* Material)
WingMaterialParameter::InfoMetaMap WingMaterialParameter::GetMaterialParameters(UMaterialInterface* Material)
{
TMap<FMaterialParameterInfo, FMaterialParameterMetadata> Result;
InfoMetaMap Result;
if (!Material) return Result;
TMap<FMaterialParameterInfo, FMaterialParameterMetadata> Temp;
InfoMetaMap Temp;
for (int32 i = 0; i < (int32)EMaterialParameterType::NumRuntime; i++)
{
Material->GetAllParametersOfType((EMaterialParameterType)i, Temp);
@@ -31,48 +32,183 @@ bool WingMaterialParameter::ParseMaterialParameterAssociation(const FString& Str
return true;
}
void WingMaterialParameter::FormatMaterialParameter(const FMaterialParameterInfo& Info, const FMaterialParameterMetadata& Meta)
void WingMaterialParameter::ReportBadToken(WingTokenizer &Tok, const TCHAR *Expected, WingOut Errors)
{
// Association prefix for layer/blend parameters.
FString Prefix;
if (Info.Association == LayerParameter)
Prefix = FString::Printf(TEXT("[Layer %d] "), Info.Index);
else if (Info.Association == BlendParameter)
Prefix = FString::Printf(TEXT("[Blend %d] "), Info.Index);
FString Whole = Tok.GetRange(FName(), 1000);
Tok.SaveCursor(FName());
FString Next = Tok.GetRange(FName(), 1);
Errors.Printf(TEXT("Parsing %s, near %s: expected %s"), *Whole, *Next, Expected);
}
switch (Meta.Value.Type)
FString WingMaterialParameter::StringID(const FMaterialParameterInfo &ID)
{
case EMaterialParameterType::Scalar:
WingOut::Stdout.Printf(TEXT(" %sScalar \"%s\" = %g\n"), *Prefix, *Info.Name.ToString(), Meta.Value.AsScalar());
break;
case EMaterialParameterType::Vector:
FString Ext = WingUtils::ExternalizeID(ID.Name);
if (ID.Association != EMaterialParameterAssociation::GlobalParameter)
{
FLinearColor C = Meta.Value.AsLinearColor();
WingOut::Stdout.Printf(TEXT(" %sVector \"%s\" = (R=%.3f, G=%.3f, B=%.3f, A=%.3f)\n"),
*Prefix, *Info.Name.ToString(), C.R, C.G, C.B, C.A);
break;
const TCHAR *Prefix = TEXT("Layer");
if (ID.Association == EMaterialParameterAssociation::BlendParameter)
Prefix = TEXT("Blend");
return FString::Printf(TEXT("%s:%d:%s"), Prefix, ID.Index, *Ext);
}
case EMaterialParameterType::DoubleVector:
else
{
FVector4d V = Meta.Value.AsVector4d();
WingOut::Stdout.Printf(TEXT(" %sDoubleVector \"%s\" = (%.3f, %.3f, %.3f, %.3f)\n"),
*Prefix, *Info.Name.ToString(), V.X, V.Y, V.Z, V.W);
break;
}
case EMaterialParameterType::Texture:
{
UTexture* Tex = Cast<UTexture>(Meta.Value.AsTextureObject());
WingOut::Stdout.Printf(TEXT(" %sTexture \"%s\" = %s\n"),
*Prefix, *Info.Name.ToString(), Tex ? *WingUtils::FormatName(Tex) : TEXT("None"));
break;
}
case EMaterialParameterType::StaticSwitch:
WingOut::Stdout.Printf(TEXT(" %sStaticSwitch \"%s\" = %s\n"),
*Prefix, *Info.Name.ToString(), Meta.Value.AsStaticSwitch() ? TEXT("true") : TEXT("false"));
break;
default:
WingOut::Stdout.Printf(TEXT(" %sType%d \"%s\"\n"), *Prefix, (int)Meta.Value.Type, *Info.Name.ToString());
break;
return Ext;
}
}
bool WingMaterialParameter::ParseID(const FString& IDString, FMaterialParameterInfo& ID, WingOut Errors)
{
WingTokenizer Tok(IDString);
ID.Association = EMaterialParameterAssociation::GlobalParameter;
ID.Index = 0;
ID.Name = FName();
// Parse the Layer or blend prefix.
if (Tok.TokenIs(TEXT("Layer")) || Tok.TokenIs(TEXT("Blend")))
{
if (Tok.NextName() == TEXT("Layer"))
ID.Association = EMaterialParameterAssociation::LayerParameter;
else
ID.Association = EMaterialParameterAssociation::BlendParameter;
Tok.Advance();
if (!Tok.TokenIs(':'))
{ ReportBadToken(Tok, TEXT("colon"), Errors); return false; }
Tok.Advance();
if ((!Tok.TokenIs(Tok.Identifier)) ||
(!LexTryParseString(ID.Index, *Tok.NextName().ToString())))
{ ReportBadToken(Tok, TEXT("integer"), Errors); return false; }
Tok.Advance();
if ((ID.Index < 0)||(ID.Index > 50))
{
Errors.Printf(TEXT("Layer/Blend index outside of reasonable range\n"));
return false;
}
if (!Tok.TokenIs(':'))
{ ReportBadToken(Tok, TEXT("colon"), Errors); return false; }
Tok.Advance();
}
// Parse the parameter name
if (!Tok.TokenIs(Tok.Identifier))
{ ReportBadToken(Tok, TEXT("parameter name"), Errors); return false; }
ID.Name = Tok.NextName();
Tok.Advance();
if (!Tok.TokenIs(0))
{ ReportBadToken(Tok, TEXT("end of input"), Errors); return false; }
return true;
}
FMaterialParameterMetadata *WingMaterialParameter::FindParameter(
InfoMetaMap &Map, const FMaterialParameterInfo &ID, WingOut Errors)
{
FMaterialParameterMetadata* Found = Map.Find(ID);
if (!Found)
{
Errors.Printf(TEXT("No parameter named '%s' in this material"), *StringID(ID));
return nullptr;
}
return Found;
}
bool WingMaterialParameter::CheckNoCustomPrimitiveData(
const FMaterialParameterInfo &ID, const FMaterialParameterMetadata &Data, WingOut Errors)
{
if (Data.PrimitiveDataIndex != INDEX_NONE)
{
Errors.Printf(
TEXT("Parameter '%s' uses custom primitive data, which cannot be set on a material instance"),
*StringID(ID));
return false;
}
return true;
}
FString WingMaterialParameter::FormatValue(const FMaterialParameterValue& Value)
{
switch (Value.Type)
{
case EMaterialParameterType::Scalar: {
return FString::Printf(TEXT("scalar(%g)"), Value.AsScalar());
}
case EMaterialParameterType::Vector: {
return FString::Printf(TEXT("vector(%s)"), *Value.AsLinearColor().ToString());
}
case EMaterialParameterType::DoubleVector: {
return FString::Printf(TEXT("doublevector(%s)"), *Value.AsLinearColor().ToString());
}
case EMaterialParameterType::Texture: {
UTexture* Tex = Cast<UTexture>(Value.AsTextureObject());
return FString::Printf(TEXT("texture(%s)"), *Tex->GetPathName());
}
case EMaterialParameterType::StaticSwitch: {
const TCHAR *Str = Value.AsStaticSwitch() ? TEXT("true") : TEXT("false");
return FString::Printf(TEXT("staticswitch(%s)"), Str);
}
default: {
return FString::Printf(TEXT("unknown(%d)"), (int)Value.Type);
}
}
}
bool WingMaterialParameter::RemoveOverride(
const FMaterialParameterInfo &ID, UMaterialInstanceConstant *MI, WingOut Errors)
{
// Remove the override from all parameter arrays.
auto RemoveFrom = [&](auto& Arr) {
return Arr.RemoveAll([&](auto& Entry) { return Entry.ParameterInfo == ID; });
};
int32 Removed = 0;
Removed += RemoveFrom(MI->ScalarParameterValues);
Removed += RemoveFrom(MI->VectorParameterValues);
Removed += RemoveFrom(MI->DoubleVectorParameterValues);
Removed += RemoveFrom(MI->TextureParameterValues);
Removed += RemoveFrom(MI->TextureCollectionParameterValues);
Removed += RemoveFrom(MI->RuntimeVirtualTextureParameterValues);
Removed += RemoveFrom(MI->SparseVolumeTextureParameterValues);
Removed += RemoveFrom(MI->FontParameterValues);
if (Removed == 0)
{
Errors.Printf(TEXT("No override found for parameter '%s'"), *StringID(ID));
return false;
}
return true;
}
void WingMaterialParameter::Print(
const FMaterialParameterInfo &Info, const FMaterialParameterMetadata &Meta)
{
WingOut::Stdout.Printf(TEXT(" %s %s\n"),
*WingMaterialParameter::StringID(Info), *WingMaterialParameter::FormatValue(Meta.Value));
}
void WingMaterialParameter::PrintAll(const InfoMetaMap &Params, bool Headings)
{
// Overridden parameters first.
bool bHasOverrides = false;
for (auto& [Info, Meta] : Params)
{
if (!Meta.bOverride) continue;
if (Headings && !bHasOverrides)
{ WingOut::Stdout.Print(TEXT("\nOverridden Parameters:\n")); bHasOverrides = true; }
WingMaterialParameter::Print(Info, Meta);
}
// Inherited (non-overridden) parameters.
bool bHasInherited = false;
for (auto& [Info, Meta] : Params)
{
if (Meta.bOverride) continue;
if (Headings && !bHasInherited)
{ WingOut::Stdout.Print(TEXT("\nInherited Parameters (not overridden):\n")); bHasInherited = true; }
WingMaterialParameter::Print(Info, Meta);
}
}

View File

@@ -249,16 +249,16 @@ void WingTokenizer::SaveCursor(FName Name)
SavedCursor.Emplace(Name, Cursor);
}
FStringView WingTokenizer::GetRange(FName SavePos, int Extra) const
FString WingTokenizer::GetRange(FName SavePos, int Extra) const
{
int Lo = 0;
for (auto &Pair : SavedCursor) if (Pair.Key == SavePos) Lo = Pair.Value;
int Hi = (Next - Tokens.GetData()) + Extra;
Hi = FMath::Clamp(Hi, Lo, Tokens.Num());
if (Lo >= Hi) return FStringView();
if (Lo >= Hi) return FString();
const TCHAR* Start = Tokens[Lo].Source.GetData();
const TCHAR* End = Tokens[Hi - 1].Source.GetData() + Tokens[Hi - 1].Source.Len();
return FStringView(Start, End - Start);
return FString(End - Start, Start);
}
void WingTokenizer::PrintEverything(FStringBuilderBase &Out) const

View File

@@ -2,13 +2,63 @@
#include "CoreMinimal.h"
#include "Materials/Material.h"
#include "WingTokenizer.h"
#include "Materials/MaterialInstanceConstant.h"
#include "WingHandler.h"
class WingMaterialParameter
{
public:
static TMap<FMaterialParameterInfo, FMaterialParameterMetadata> GetMaterialParameters(UMaterialInterface* Material);
using InfoMetaMap = TMap<FMaterialParameterInfo, FMaterialParameterMetadata>;
// Get all the material parameters of the specified material including
// both parameters that have been overridden and those that haven't.
//
static InfoMetaMap GetMaterialParameters(UMaterialInterface* Material);
// Find a material parameter in the InfoMap.
// If it doesn't exist, or report an error and return nullptr.
//
static FMaterialParameterMetadata *FindParameter(
InfoMetaMap &Map, const FMaterialParameterInfo &ID, WingOut Errors);
// If the material uses custom primitive data, print an error
// and return false.
//
static bool CheckNoCustomPrimitiveData(
const FMaterialParameterInfo &ID, const FMaterialParameterMetadata &Data, WingOut Errors);
// Convert a parameter ID into an ID string.
//
static bool ParseID(const FString& Str, FMaterialParameterInfo& ID, WingOut Errors);
// Parse a parameter ID String into a parameter ID.
//
static FString StringID(const FMaterialParameterInfo& ID);
// Remove a material parameter override from a material instance.
// If there is no override, print an error and return false.
//
static bool RemoveOverride(
const FMaterialParameterInfo &ID, UMaterialInstanceConstant *MI, WingOut Errors);
// Format a material parameter value.
//
static FString FormatValue(const FMaterialParameterValue& Value);
// Print out a material parameter with ID.
//
static void Print(const FMaterialParameterInfo &Info, const FMaterialParameterMetadata &Meta);
// Print out a map full of material parameters. If Headings is
// true, the parameters are grouped by inherited/overridden.
//
static void PrintAll(const InfoMetaMap &Params, bool Headings);
static bool ParseMaterialParameterAssociation(const FString& Str, EMaterialParameterAssociation& OutAssociation, WingOut Errors);
static void FormatMaterialParameter(const FMaterialParameterInfo& Info, const FMaterialParameterMetadata& Meta);
private:
static void ReportBadToken(WingTokenizer &Tok, const TCHAR *Expected, WingOut Errors);
};

View File

@@ -1,6 +1,6 @@
#pragma once
#include "CoreMinimal.h"
#include "WingHandler.h"
// -----------------------------------------------------------------
//
@@ -130,7 +130,7 @@ struct WingTokenizer
// Get the input text from a saved cursor position to the current
// cursor, optionally including additional tokens.
FStringView GetRange(FName SavePos, int32 Extra = 0) const;
FString GetRange(FName SavePos, int32 Extra = 0) const;
// Tokenize a line of input. The tokens are stored in
// the token array, and the cursor is positioned on the first