// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
#pragma once
#if COMPILE_WITH_MATERIAL_GRAPH
#include "Engine/Graphics/Materials/MaterialInfo.h"
#include "Engine/Graphics/Materials/MaterialParams.h"
#include "MaterialLayer.h"
#include "Types.h"
///
/// Material node input boxes (each enum item value maps to box ID).
///
enum class MaterialGraphBoxes
{
///
/// The layer input.
///
Layer = 0,
///
/// The color input.
///
Color = 1,
///
/// The mask input.
///
Mask = 2,
///
/// The emissive input.
///
Emissive = 3,
///
/// The metalness input.
///
Metalness = 4,
///
/// The specular input.
///
Specular = 5,
///
/// The roughness input.
///
Roughness = 6,
///
/// The ambient occlusion input.
///
AmbientOcclusion = 7,
///
/// The normal input.
///
Normal = 8,
///
/// The opacity input.
///
Opacity = 9,
///
/// The refraction input.
///
Refraction = 10,
///
/// The position offset input.
///
PositionOffset = 11,
///
/// The tessellation multiplier input.
///
TessellationMultiplier = 12,
///
/// The world displacement input.
///
WorldDisplacement = 13,
///
/// The subsurface color input.
///
SubsurfaceColor = 14,
///
/// The amount of input boxes.
///
MAX
};
///
/// Material shaders generator from graphs.
///
class MaterialGenerator : public ShaderGenerator
{
public:
struct MaterialGraphBoxesMapping
{
byte ID;
const Char* SubName;
MaterialTreeType TreeType;
MaterialValue DefaultValue;
};
private:
Array _layers;
Array> _vsToPsInterpolants;
MaterialTreeType _treeType;
MaterialLayer* _treeLayer = nullptr;
String _treeLayerVarName;
MaterialValue _ddx, _ddy, _cameraVector;
public:
MaterialGenerator();
~MaterialGenerator();
public:
///
/// Gets material root layer
///
/// Base layer
MaterialLayer* GetRootLayer() const;
///
/// Add new layer to the generator data (will be deleted after usage)
///
/// Layer to add
void AddLayer(MaterialLayer* layer);
///
/// Gets layer that has given ID, if not loaded tries to load it
///
/// Layer ID
/// Calling node
/// Material layer or null if cannot do that
MaterialLayer* GetLayer(const Guid& id, Node* caller);
///
/// Generate material source code (first layer should be the base one)
///
/// Output source code
/// Material info structure (will contain output data)
/// Output material parameters data
/// True if cannot generate code, otherwise false
bool Generate(WriteStream& source, MaterialInfo& materialInfo, BytesContainer& parametersData);
private:
void clearCache();
void createGradients(Node* caller);
Value getCameraVector(Node* caller);
void eatMaterialGraphBox(String& layerVarName, MaterialGraphBox* nodeBox, MaterialGraphBoxes box);
void eatMaterialGraphBox(MaterialLayer* layer, MaterialGraphBoxes box);
void eatMaterialGraphBoxWithDefault(MaterialLayer* layer, MaterialGraphBoxes box);
void ProcessGroupLayers(Box* box, Node* node, Value& value);
void ProcessGroupMaterial(Box* box, Node* node, Value& value);
void ProcessGroupMath(Box* box, Node* node, Value& value);
void ProcessGroupParameters(Box* box, Node* node, Value& value);
void ProcessGroupTextures(Box* box, Node* node, Value& value);
void ProcessGroupTools(Box* box, Node* node, Value& value);
void ProcessGroupParticles(Box* box, Node* node, Value& value);
void ProcessGroupFunction(Box* box, Node* node, Value& value);
void writeBlending(MaterialGraphBoxes box, Value& result, const Value& bottom, const Value& top, const Value& alpha);
using ShaderGenerator::findParam;
SerializedMaterialParam* findParam(const Guid& id, MaterialLayer* layer);
MaterialGraphParameter* findGraphParam(const Guid& id);
MaterialValue* sampleTextureRaw(Node* caller, Value& value, Box* box, SerializedMaterialParam* texture);
void sampleTexture(Node* caller, Value& value, Box* box, SerializedMaterialParam* texture);
void sampleSceneDepth(Node* caller, Value& value, Box* box);
void linearizeSceneDepth(Node* caller, const Value& depth, Value& value);
// This must match ParticleAttribute::ValueTypes enum in Particles Module
enum class ParticleAttributeValueTypes
{
Float,
Float2,
Float3,
Float4,
Int,
Uint,
};
enum class ParticleAttributeSpace
{
AsIs,
LocalPosition,
LocalDirection,
};
MaterialValue AccessParticleAttribute(Node* caller, const StringView& name, ParticleAttributeValueTypes valueType, const Char* index = nullptr, ParticleAttributeSpace space = ParticleAttributeSpace::AsIs);
void prepareLayer(MaterialLayer* layer, bool allowVisibleParams);
void WriteCustomGlobalCode(const Array>& nodes, int32 templateInputsMapping);
Value VsToPs(Node* node, Box* input);
public:
static MaterialValue getUVs;
static MaterialValue getTime;
static MaterialValue getNormal;
static MaterialValue getNormalZero;
static MaterialValue getVertexColor;
static MaterialGraphBoxesMapping MaterialGraphBoxesMappings[];
static const MaterialGraphBoxesMapping& GetMaterialRootNodeBox(MaterialGraphBoxes box);
};
#endif