// Copyright (c) Wojciech Figat. All rights reserved. #pragma once #if USE_EDITOR #include "Graph.h" #include "ShaderGraphValue.h" #include "Engine/Core/Collections/Dictionary.h" #include "Engine/Core/Collections/HashSet.h" #include "Engine/Core/Math/Vector4.h" #include "Engine/Utilities/TextWriter.h" #include "Engine/Graphics/Materials/MaterialParams.h" #include "Engine/Content/AssetsContainer.h" #include "Engine/Animations/Curve.h" #define SHADER_GRAPH_MAX_CALL_STACK 50 enum class MaterialSceneTextures; template class ShaderGraphNode; class ShaderGraphBox : public GraphBox { public: /// /// The cached value. /// ShaderGraphValue Cache; public: ShaderGraphBox() : GraphBox() { } ShaderGraphBox(void* parent, byte id, const VariantType::Types type) : GraphBox(parent, id, type) { } ShaderGraphBox(void* parent, byte id, const VariantType& type) : GraphBox(parent, id, type) { } public: FORCE_INLINE ShaderGraphBox* FirstConnection() const { return (ShaderGraphBox*)Connections[0]; } }; template class ShaderGraphNode : public GraphNode { public: struct CurveData { /// /// The curve index. /// int32 CurveIndex; }; /// /// Custom cached data per node type. Compact to use as small amount of memory as possible. /// struct AdditionalData { union { CurveData Curve; }; }; public: ShaderGraphNode() : GraphNode() { } public: /// /// The custom data (depends on node type). Used to cache data for faster usage at runtime. /// AdditionalData Data; }; class ShaderGraphParameter : public GraphParameter { public: ShaderGraphParameter() : GraphParameter(SpawnParams(Guid::New(), TypeInitializer)) { } }; template, class BoxType = ShaderGraphBox, class ParameterType = ShaderGraphParameter> class ShaderGraph : public Graph { public: typedef ShaderGraphValue Value; typedef Graph Base; public: /// /// The float curves used by the graph. /// Array> FloatCurves; /// /// The Float2 curves used by the graph. /// Array> Float2Curves; /// /// The Float3 curves used by the graph. /// Array> Float3Curves; /// /// The Float4 curves used by the graph. /// Array> Float4Curves; public: // [Graph] bool onNodeLoaded(NodeType* n) override { // Check if this node needs a state or data cache switch (n->GroupID) { // Tools case 7: switch (n->TypeID) { // Curves #define SETUP_CURVE(id, curves, access) \ case id: \ { \ n->Data.Curve.CurveIndex = curves.Count(); \ auto& curve = curves.AddOne(); \ const int32 keyframesCount = n->Values[0].AsInt; \ auto& keyframes = curve.GetKeyframes(); \ keyframes.Resize(keyframesCount); \ for (int32 i = 0; i < keyframesCount; i++) \ { \ const int32 idx = i * 4; \ auto& keyframe = keyframes[i]; \ keyframe.Time = n->Values[idx + 1].AsFloat; \ keyframe.Value = n->Values[idx + 2].access; \ keyframe.TangentIn = n->Values[idx + 3].access; \ keyframe.TangentOut = n->Values[idx + 4].access; \ } \ break; \ } SETUP_CURVE(12, FloatCurves, AsFloat) SETUP_CURVE(13, Float2Curves, AsFloat2()) SETUP_CURVE(14, Float3Curves, AsFloat3()) SETUP_CURVE(15, Float4Curves, AsFloat4()) #undef SETUP_CURVE } break; } // Base return Base::onNodeLoaded(n); } }; /// /// Shaders generator from graphs. /// class ShaderGenerator { public: typedef ShaderGraph<> Graph; typedef ShaderGraph<>::Node Node; typedef ShaderGraph<>::Box Box; typedef ShaderGraph<>::Parameter Parameter; typedef ShaderGraphValue Value; typedef VariantType::Types ValueType; typedef Delegate ErrorHandler; typedef Function ProcessBoxHandler; protected: int32 _localIndex; Dictionary _functions; Array _parameters; TextWriterUnicode _writer; HashSet _includes; Array> _perGroupProcessCall; Array> _callStack; Array> _graphStack; public: /// /// Initializes a new instance of the class. /// ShaderGenerator(); /// /// Finalizes an instance of the class. /// ~ShaderGenerator(); public: ErrorHandler Error; /// /// The assets container for graph generation. Holds references to used assets. Can be used to gather assets referenced by graph (eg. nested graph functions). /// AssetsContainer Assets; public: void OnError(Node* node, Box* box, const StringView& message); void ProcessGroupConstants(Box* box, Node* node, Value& value); void ProcessGroupMath(Box* box, Node* node, Value& value); void ProcessGroupPacking(Box* box, Node* node, Value& value); void ProcessGroupTools(Box* box, Node* node, Value& value); void ProcessGroupBoolean(Box* box, Node* node, Value& value); void ProcessGroupBitwise(Box* box, Node* node, Value& value); void ProcessGroupComparisons(Box* box, Node* node, Value& value); protected: static const Char* _mathFunctions[]; static const Char* _subs[]; protected: Value eatBox(Node* caller, Box* box); Value tryGetValue(Box* box, int32 defaultValueBoxIndex, const Value& defaultValue); Value tryGetValue(Box* box, const Value& defaultValue); Value tryGetValue(Box* box, const Variant& defaultValue); Value writeLocal(ValueType type, Node* caller); Value writeLocal(ValueType type, Node* caller, const String& name); Value writeLocal(ValueType type, const Value& value, Node* caller); Value writeLocal(const Value& value, Node* caller); Value writeLocal(ValueType type, const String& value, Node* caller); Value writeLocal(ValueType type, const String& value, Node* caller, const String& name); Value writeOperation2(Node* caller, const Value& valueA, const Value& valueB, Char op1); Value writeFunction1(Node* caller, const Value& valueA, const String& function); Value writeFunction2(Node* caller, const Value& valueA, const Value& valueB, const String& function); Value writeFunction2(Node* caller, const Value& valueA, const Value& valueB, const String& function, ValueType resultType); Value writeFunction3(Node* caller, const Value& valueA, const Value& valueB, const Value& valueC, const String& function, ValueType resultType); SerializedMaterialParam* findParam(const String& shaderName); SerializedMaterialParam* findParam(const Guid& id); SerializedMaterialParam findOrAddTexture(const Guid& id); SerializedMaterialParam findOrAddNormalMap(const Guid& id); SerializedMaterialParam findOrAddCubeTexture(const Guid& id); SerializedMaterialParam findOrAddSceneTexture(MaterialSceneTextures type); SerializedMaterialParam& findOrAddTextureGroupSampler(int32 index); SerializedMaterialParam& findOrAddGlobalSDF(); static String getLocalName(int32 index); static String getParamName(int32 index); }; #endif