diff --git a/.codex b/.codex new file mode 100644 index 00000000..e69de29b diff --git a/Content/Testing/M_Test.uasset b/Content/Testing/M_Test.uasset new file mode 100644 index 00000000..c39e8da2 --- /dev/null +++ b/Content/Testing/M_Test.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f59c25d873af575f886903b2d856feda90caa4e601fdb335a8b88ed5988804a2 +size 13148 diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/MaterialInstance_ClearParameter.h b/Plugins/UEWingman/Source/UEWingman/Handlers/MaterialInstance_ClearParameter.h index 7a2cd78f..f7090b13 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/MaterialInstance_ClearParameter.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/MaterialInstance_ClearParameter.h @@ -40,7 +40,7 @@ public: if (!MI) return; // Parse the parameter ID. - FMaterialParameterInfo ID; + WingMaterialParameter::Info ID; if (!WingMaterialParameter::ParseID(Parameter, ID, WingOut::Stdout)) return; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/MaterialInstance_SetParameter.h b/Plugins/UEWingman/Source/UEWingman/Handlers/MaterialInstance_SetParameter.h index 152d72a5..deeb5bb4 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/MaterialInstance_SetParameter.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/MaterialInstance_SetParameter.h @@ -8,7 +8,6 @@ #include "WingMaterialParameter.h" #include "Materials/MaterialInstanceConstant.h" #include "MaterialTypes.h" -#include "Misc/DefaultValueHelper.h" #include "MaterialInstance_SetParameter.generated.h" @@ -43,47 +42,19 @@ public: if (!MI) return; // Parse the parameter ID. - FMaterialParameterInfo ID; + WingMaterialParameter::Info ID; if (!WingMaterialParameter::ParseID(Parameter, ID, WingOut::Stdout)) return; - // Find it in the material's parameter map. + // Make sure the parameter actually exists. auto AllParams = WingMaterialParameter::GetMaterialParameters(MI); FMaterialParameterMetadata* Meta = WingMaterialParameter::FindParameter(AllParams, ID, WingOut::Stdout); if (!Meta) return; if (!WingMaterialParameter::CheckNoCustomPrimitiveData(ID, *Meta, WingOut::Stdout)) return; - EMaterialParameterType Type = Meta->Value.Type; - - switch (Type) - { - case EMaterialParameterType::Scalar: - { - float ScalarValue; - if (!FDefaultValueHelper::ParseFloat(Value, ScalarValue)) - { - WingOut::Stdout.Printf(TEXT("Failed to parse '%s' as a float"), *Value); - return; - } - MI->SetScalarParameterValueEditorOnly(ID, ScalarValue); - break; - } - case EMaterialParameterType::Vector: - { - FLinearColor Color; - if (!Color.InitFromString(Value)) - { - 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(ID, Color); - break; - } - default: - WingOut::Stdout.Printf(TEXT("Parameters of type %d (see EMaterialParameterType) are not implemented"), (int)Type); - return; - } + // Set the parameter + if (!WingMaterialParameter::AddOverride(ID, MI, Value, WingOut::Stdout)) return; WingOut::Stdout.Printf(TEXT("Assigned.\n")); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingMaterialParameter.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingMaterialParameter.cpp index 6876c365..3e09afa6 100644 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingMaterialParameter.cpp +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingMaterialParameter.cpp @@ -2,36 +2,69 @@ #include "WingUtils.h" #include "WingTokenizer.h" #include "WingServer.h" +#include "Engine/Font.h" +#include "Engine/TextureCollection.h" +#include "Misc/DefaultValueHelper.h" +#include "SparseVolumeTexture/SparseVolumeTexture.h" +#include "VT/RuntimeVirtualTexture.h" + +const TCHAR *WingMaterialParameter::EMaterialParameterTypeToString(EMaterialParameterType Type) +{ + switch (Type) + { + case EMaterialParameterType::Scalar: return TEXT("Scalar"); + case EMaterialParameterType::Vector: return TEXT("Vector"); + case EMaterialParameterType::DoubleVector: return TEXT("DoubleVector"); + case EMaterialParameterType::Texture: return TEXT("Texture"); + case EMaterialParameterType::TextureCollection: return TEXT("TextureCollection"); + case EMaterialParameterType::Font: return TEXT("Font"); + case EMaterialParameterType::RuntimeVirtualTexture: return TEXT("RuntimeVirtualTexture"); + case EMaterialParameterType::SparseVolumeTexture: return TEXT("SparseVolumeTexture"); + case EMaterialParameterType::StaticSwitch: return TEXT("StaticSwitch"); + case EMaterialParameterType::StaticComponentMask: return TEXT("StaticComponentMask"); + case EMaterialParameterType::Num: return TEXT("Num"); + case EMaterialParameterType::None: return TEXT("None"); + } + return TEXT("None"); +} + +bool WingMaterialParameter::EMaterialParameterTypeFromName(FName Name, EMaterialParameterType &Result, WingOut Errors) +{ + if (Name == TEXT("Scalar")) { Result = EMaterialParameterType::Scalar; return true; } + if (Name == TEXT("Vector")) { Result = EMaterialParameterType::Vector; return true; } + if (Name == TEXT("DoubleVector")) { Result = EMaterialParameterType::DoubleVector; return true; } + if (Name == TEXT("Texture")) { Result = EMaterialParameterType::Texture; return true; } + if (Name == TEXT("TextureCollection")) { Result = EMaterialParameterType::TextureCollection; return true; } + if (Name == TEXT("Font")) { Result = EMaterialParameterType::Font; return true; } + if (Name == TEXT("RuntimeVirtualTexture")) { Result = EMaterialParameterType::RuntimeVirtualTexture; return true; } + if (Name == TEXT("SparseVolumeTexture")) { Result = EMaterialParameterType::SparseVolumeTexture; return true; } + if (Name == TEXT("StaticSwitch")) { Result = EMaterialParameterType::StaticSwitch; return true; } + if (Name == TEXT("StaticComponentMask")) { Result = EMaterialParameterType::StaticComponentMask; return true; } + if (Name == TEXT("Num")) { Result = EMaterialParameterType::Num; return true; } + if (Name == TEXT("None")) { Result = EMaterialParameterType::None; return true; } + Errors.Printf(TEXT("ERROR: '%s' is not a valid EMaterialParameterType\n"), *Name.ToString()); + Result = EMaterialParameterType::None; + return false; +} WingMaterialParameter::InfoMetaMap WingMaterialParameter::GetMaterialParameters(UMaterialInterface* Material) { InfoMetaMap Result; if (!Material) return Result; - InfoMetaMap Temp; - for (int32 i = 0; i < (int32)EMaterialParameterType::NumRuntime; i++) + TMap Temp; + for (int I = 0; I < int(EMaterialParameterType::NumRuntime); I++) { - Material->GetAllParametersOfType((EMaterialParameterType)i, Temp); - Result.Append(Temp); + EMaterialParameterType T = (EMaterialParameterType)I; + Material->GetAllParametersOfType(T, Temp); + for (const auto &KV : Temp) + { + check(KV.Value.Value.Type == T); + Result.Add(Info(KV.Key, T), KV.Value); + } } return Result; } -bool WingMaterialParameter::ParseMaterialParameterAssociation(const FString& Str, EMaterialParameterAssociation& OutAssociation, WingOut Errors) -{ - if (Str.Equals(TEXT("Global"), ESearchCase::IgnoreCase)) - OutAssociation = GlobalParameter; - else if (Str.Equals(TEXT("Layer"), ESearchCase::IgnoreCase)) - OutAssociation = LayerParameter; - else if (Str.Equals(TEXT("Blend"), ESearchCase::IgnoreCase)) - OutAssociation = BlendParameter; - else - { - Errors.Printf(TEXT("ERROR: Invalid ParameterAssociation '%s' (expected 'Global', 'Layer', or 'Blend')\n"), *Str); - return false; - } - return true; -} - void WingMaterialParameter::ReportBadToken(WingTokenizer &Tok, const TCHAR *Expected, WingOut Errors) { FString Whole = Tok.GetRange(FName(), 1000); @@ -40,41 +73,54 @@ void WingMaterialParameter::ReportBadToken(WingTokenizer &Tok, const TCHAR *Expe Errors.Printf(TEXT("Parsing %s, near %s: expected %s"), *Whole, *Next, Expected); } -FString WingMaterialParameter::StringID(const FMaterialParameterInfo &ID) +FString WingMaterialParameter::StringID(const Info &ID) { + const TCHAR *Type = EMaterialParameterTypeToString(ID.Type); FString Ext = WingUtils::ExternalizeID(ID.Name); if (ID.Association != EMaterialParameterAssociation::GlobalParameter) { const TCHAR *Prefix = TEXT("Layer"); if (ID.Association == EMaterialParameterAssociation::BlendParameter) Prefix = TEXT("Blend"); - return FString::Printf(TEXT("%s:%d:%s"), Prefix, ID.Index, *Ext); + return FString::Printf(TEXT("%s:%s:%d:%s"), Type, Prefix, ID.Index, *Ext); } else { - return Ext; + return FString::Printf(TEXT("%s:%s"), Type, *Ext); } } -bool WingMaterialParameter::ParseID(const FString& IDString, FMaterialParameterInfo& ID, WingOut Errors) +bool WingMaterialParameter::ParseID(const FString& IDString, Info& ID, WingOut Errors) { WingTokenizer Tok(IDString); + ID.Type = EMaterialParameterType::None; ID.Association = EMaterialParameterAssociation::GlobalParameter; ID.Index = 0; ID.Name = FName(); + // Parse the type. + const TCHAR *GoodTypes = TEXT("Vector, DoubleVector, Texture, TextureCollection, Font, RuntimeVirtualTexture, SparseVolumeTexture, or StaticSwitch"); + if (!Tok.TokenIs(Tok.Identifier)) + { ReportBadToken(Tok, GoodTypes, Errors); return false; } + EMaterialParameterType TypeValue; + if (!EMaterialParameterTypeFromName(Tok.NextName(), TypeValue, Errors)) return false; + if (TypeValue >= EMaterialParameterType::NumRuntime) + { ReportBadToken(Tok, GoodTypes, Errors); return false; } + ID.Type = TypeValue; + Tok.Advance(); + + // A colon after the type. + if (!Tok.TokenIs(':')) { ReportBadToken(Tok, TEXT("colon"), Errors); return false; } + // Parse the Layer or blend prefix. - if (Tok.TokenIs(TEXT("Layer")) || Tok.TokenIs(TEXT("Blend"))) + 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)) || @@ -104,20 +150,20 @@ bool WingMaterialParameter::ParseID(const FString& IDString, FMaterialParameterI return true; } -FMaterialParameterMetadata *WingMaterialParameter::FindParameter( - InfoMetaMap &Map, const FMaterialParameterInfo &ID, WingOut Errors) +WingMaterialParameter::Metadata *WingMaterialParameter::FindParameter( + InfoMetaMap &Map, const Info &ID, WingOut Errors) { - FMaterialParameterMetadata* Found = Map.Find(ID); + Metadata* Found = Map.Find(ID); if (!Found) { - Errors.Printf(TEXT("No parameter named '%s' in this material"), *StringID(ID)); + Errors.Printf(TEXT("No parameter '%s' in this material"), *StringID(ID)); return nullptr; } return Found; } bool WingMaterialParameter::CheckNoCustomPrimitiveData( - const FMaterialParameterInfo &ID, const FMaterialParameterMetadata &Data, WingOut Errors) + const Info &ID, const Metadata &Data, WingOut Errors) { if (Data.PrimitiveDataIndex != INDEX_NONE) { @@ -134,30 +180,98 @@ FString WingMaterialParameter::FormatValue(const FMaterialParameterValue& Value) switch (Value.Type) { case EMaterialParameterType::Scalar: { - return FString::Printf(TEXT("scalar(%g)"), Value.AsScalar()); + return FString::Printf(TEXT("%g"), Value.AsScalar()); } case EMaterialParameterType::Vector: { - return FString::Printf(TEXT("vector(%s)"), *Value.AsLinearColor().ToString()); + return Value.AsLinearColor().ToString(); } case EMaterialParameterType::DoubleVector: { - return FString::Printf(TEXT("doublevector(%s)"), *Value.AsLinearColor().ToString()); + return Value.AsVector4d().ToString(); } case EMaterialParameterType::Texture: { - UTexture* Tex = Cast(Value.AsTextureObject()); - return FString::Printf(TEXT("texture(%s)"), *Tex->GetPathName()); + return PathNameOrNone(Value.Texture); + } + case EMaterialParameterType::TextureCollection: { + return PathNameOrNone(Value.TextureCollection); + } + case EMaterialParameterType::Font: { + return FString::Printf(TEXT("%s:%d"), *PathNameOrNone(Value.Font.Value), Value.Font.Page); + } + case EMaterialParameterType::RuntimeVirtualTexture: { + return PathNameOrNone(Value.RuntimeVirtualTexture); + } + case EMaterialParameterType::SparseVolumeTexture: { + return PathNameOrNone(Value.SparseVolumeTexture); } case EMaterialParameterType::StaticSwitch: { - const TCHAR *Str = Value.AsStaticSwitch() ? TEXT("true") : TEXT("false"); - return FString::Printf(TEXT("staticswitch(%s)"), Str); + return Value.AsStaticSwitch() ? TEXT("true") : TEXT("false"); } - default: { - return FString::Printf(TEXT("unknown(%d)"), (int)Value.Type); + case EMaterialParameterType::StaticComponentMask: { + const FStaticComponentMaskValue Mask = Value.AsStaticComponentMask(); + return FString::Printf( + TEXT("(R=%s,G=%s,B=%s,A=%s)"), + Mask.R ? TEXT("true") : TEXT("false"), + Mask.G ? TEXT("true") : TEXT("false"), + Mask.B ? TEXT("true") : TEXT("false"), + Mask.A ? TEXT("true") : TEXT("false")); + } + case EMaterialParameterType::Num: { + return TEXT("invalid-parameter-type"); + } + case EMaterialParameterType::None: { + return TEXT("invalid-parameter-type"); } } + return TEXT("invalid-parameter-type"); +} + +bool WingMaterialParameter::AddOverride( + const Info &ID, UMaterialInstanceConstant *MI, const FString &Value, WingOut Errors) +{ + switch (ID.Type) + { + case EMaterialParameterType::Scalar: + { + float ScalarValue; + if (!FDefaultValueHelper::ParseFloat(Value, ScalarValue)) + { + Errors.Printf(TEXT("Failed to parse '%s' as a float"), *Value); + return false; + } + MI->SetScalarParameterValueEditorOnly(ID, ScalarValue); + return true; + } + case EMaterialParameterType::Vector: + { + FLinearColor Color; + if (!Color.InitFromString(Value)) + { + Errors.Printf(TEXT("Failed to parse '%s' as a color/vector (expected format: '(R=1,G=0,B=0,A=1)')"), *Value); + return false; + } + MI->SetVectorParameterValueEditorOnly(ID, Color); + return true; + } + case EMaterialParameterType::DoubleVector: + case EMaterialParameterType::Texture: + case EMaterialParameterType::TextureCollection: + case EMaterialParameterType::Font: + case EMaterialParameterType::RuntimeVirtualTexture: + case EMaterialParameterType::SparseVolumeTexture: + case EMaterialParameterType::StaticSwitch: + case EMaterialParameterType::StaticComponentMask: + Errors.Printf(TEXT("Parameters of type %s are not implemented"), EMaterialParameterTypeToString(ID.Type)); + return false; + case EMaterialParameterType::Num: + case EMaterialParameterType::None: + Errors.Printf(TEXT("Parameter Type is not valid")); + return false; + } + return false; } bool WingMaterialParameter::RemoveOverride( - const FMaterialParameterInfo &ID, UMaterialInstanceConstant *MI, WingOut Errors) + const Info &ID, UMaterialInstanceConstant *MI, WingOut Errors) { // Remove the override from all parameter arrays. auto RemoveFrom = [&](auto& Arr) { @@ -165,14 +279,21 @@ bool WingMaterialParameter::RemoveOverride( }; 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); + switch (ID.Type) + { + case EMaterialParameterType::Scalar: Removed += RemoveFrom(MI->ScalarParameterValues); break; + case EMaterialParameterType::Vector: Removed += RemoveFrom(MI->VectorParameterValues); break; + case EMaterialParameterType::DoubleVector: Removed += RemoveFrom(MI->DoubleVectorParameterValues); break; + case EMaterialParameterType::Texture: Removed += RemoveFrom(MI->TextureParameterValues); break; + case EMaterialParameterType::TextureCollection: Removed += RemoveFrom(MI->TextureCollectionParameterValues); break; + case EMaterialParameterType::Font: Removed += RemoveFrom(MI->FontParameterValues); break; + case EMaterialParameterType::RuntimeVirtualTexture: Removed += RemoveFrom(MI->RuntimeVirtualTextureParameterValues); break; + case EMaterialParameterType::SparseVolumeTexture: Removed += RemoveFrom(MI->SparseVolumeTextureParameterValues); break; + case EMaterialParameterType::StaticSwitch: Errors.Printf(TEXT("Removal of static switches not implemented")); return false; + case EMaterialParameterType::StaticComponentMask: Errors.Printf(TEXT("Removal of static component masks not implemented")); return false; + case EMaterialParameterType::Num: Errors.Printf(TEXT("Parameter Type is not valid")); return false; + case EMaterialParameterType::None: Errors.Printf(TEXT("Parameter Type is not valid")); return false; + } if (Removed == 0) { @@ -184,7 +305,7 @@ bool WingMaterialParameter::RemoveOverride( void WingMaterialParameter::Print( - const FMaterialParameterInfo &Info, const FMaterialParameterMetadata &Meta) + const Info &Info, const Metadata &Meta) { WingOut::Stdout.Printf(TEXT(" %s %s\n"), *WingMaterialParameter::StringID(Info), *WingMaterialParameter::FormatValue(Meta.Value)); diff --git a/Plugins/UEWingman/Source/UEWingman/Public/WingMaterialParameter.h b/Plugins/UEWingman/Source/UEWingman/Public/WingMaterialParameter.h index 7fb38fd3..901c6883 100644 --- a/Plugins/UEWingman/Source/UEWingman/Public/WingMaterialParameter.h +++ b/Plugins/UEWingman/Source/UEWingman/Public/WingMaterialParameter.h @@ -6,10 +6,37 @@ #include "Materials/MaterialInstanceConstant.h" #include "WingHandler.h" + + class WingMaterialParameter { public: - using InfoMetaMap = TMap; + // Info struct is a FMaterialParameterInfo plus a type field. + struct Info : public FMaterialParameterInfo + { + EMaterialParameterType Type; + + Info() : FMaterialParameterInfo(), Type(EMaterialParameterType::None) {} + Info(const FMaterialParameterInfo &I, EMaterialParameterType T) : FMaterialParameterInfo(I), Type(T) {} + friend FORCEINLINE bool operator==(const Info& Lhs, const Info& Rhs) + { + return Lhs.Name.IsEqual(Rhs.Name) && Lhs.Association == Rhs.Association && Lhs.Index == Rhs.Index && Lhs.Type == Rhs.Type; + } + friend FORCEINLINE bool operator!=(const Info& Lhs, const Info& Rhs) + { + return !operator==(Lhs, Rhs); + } + friend FORCEINLINE uint32 GetTypeHash(const Info& Value) + { + return HashCombine(HashCombine(HashCombine(GetTypeHash(NameToScriptName(Value.Name)), Value.Index), (uint32)Value.Association), (uint32)Value.Type); + } + }; + + + using Type = EMaterialParameterType; + using Metadata = FMaterialParameterMetadata; + using Value = FMaterialParameterValue; + using InfoMetaMap = TMap; // Get all the material parameters of the specified material including // both parameters that have been overridden and those that haven't. @@ -19,46 +46,48 @@ public: // 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); + static Metadata *FindParameter(InfoMetaMap &Map, const Info &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); + static bool CheckNoCustomPrimitiveData(const Info &ID, const Metadata &Data, WingOut Errors); - // Convert a parameter ID into an ID string. + // Convert an ID in string form into an ID in info form. // - static bool ParseID(const FString& Str, FMaterialParameterInfo& ID, WingOut Errors); + static bool ParseID(const FString& Str, Info& ID, WingOut Errors); - // Parse a parameter ID String into a parameter ID. + // Convert an ID in Info form into an ID in string form. // - static FString StringID(const FMaterialParameterInfo& ID); + static FString StringID(const Info& ID); + + // Add a material parameter override to a material instance. + // + static bool AddOverride( + const Info &ID, UMaterialInstanceConstant *MI, const FString &Value, WingOut Errors); // 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); + static bool RemoveOverride(const Info &ID, UMaterialInstanceConstant *MI, WingOut Errors); // Format a material parameter value. // - static FString FormatValue(const FMaterialParameterValue& Value); + static FString FormatValue(const Value& Value); // Print out a material parameter with ID. // - static void Print(const FMaterialParameterInfo &Info, const FMaterialParameterMetadata &Meta); + static void Print(const Info &Info, const Metadata &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); - private: static void ReportBadToken(WingTokenizer &Tok, const TCHAR *Expected, WingOut Errors); + static const TCHAR *EMaterialParameterTypeToString(EMaterialParameterType Type); + static bool EMaterialParameterTypeFromName(FName Name, EMaterialParameterType &Result, WingOut Errors); + static FString PathNameOrNone(UObject *Obj) { return Obj ? Obj->GetPathName() : FString(TEXT("None")); } }; -