You're breathtaking!
This commit is contained in:
600
Source/Engine/Visject/Graph.h
Normal file
600
Source/Engine/Visject/Graph.h
Normal file
@@ -0,0 +1,600 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Core/Collections/Array.h"
|
||||
#include "VisjectMeta.h"
|
||||
#include "GraphNode.h"
|
||||
#include "GraphParameter.h"
|
||||
#include "Engine/Serialization/ReadStream.h"
|
||||
#include "Engine/Serialization/WriteStream.h"
|
||||
|
||||
// [Deprecated on 31.07.2020, expires on 31.07.2022]
|
||||
extern FLAXENGINE_API void ReadOldGraphParamValue_Deprecated(byte graphParamType, ReadStream* stream, GraphParameter* param);
|
||||
extern FLAXENGINE_API void ReadOldGraphNodeValue_Deprecated(ReadStream* stream, Variant& result);
|
||||
extern FLAXENGINE_API void ReadOldGraphBoxType_Deprecated(uint32 connectionType, VariantType& type);
|
||||
extern FLAXENGINE_API StringView GetGraphFunctionTypeName_Deprecated(const Variant& v);
|
||||
|
||||
/// <summary>
|
||||
/// Visject graph
|
||||
/// </summary>
|
||||
template<class NodeType, class BoxType, class ParameterType>
|
||||
class Graph
|
||||
{
|
||||
public:
|
||||
|
||||
typedef Graph<NodeType, BoxType, ParameterType> GraphType;
|
||||
typedef NodeType Node;
|
||||
typedef BoxType Box;
|
||||
typedef ParameterType Parameter;
|
||||
|
||||
private:
|
||||
|
||||
struct TmpConnectionHint
|
||||
{
|
||||
Node* Node;
|
||||
byte BoxID;
|
||||
};
|
||||
|
||||
public:
|
||||
NON_COPYABLE(Graph);
|
||||
|
||||
/// <summary>
|
||||
/// All graph nodes
|
||||
/// </summary>
|
||||
Array<Node> Nodes;
|
||||
|
||||
/// <summary>
|
||||
/// All graph parameters
|
||||
/// </summary>
|
||||
Array<Parameter> Parameters;
|
||||
|
||||
/// <summary>
|
||||
/// Metadata for whole graph
|
||||
/// </summary>
|
||||
VisjectMeta Meta;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Graph"/> class.
|
||||
/// </summary>
|
||||
Graph()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finalizes an instance of the <see cref="Graph"/> class.
|
||||
/// </summary>
|
||||
virtual ~Graph()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Save graph to the stream
|
||||
/// </summary>
|
||||
/// <param name="stream">Output stream</param>
|
||||
/// <param name="saveMeta">True if save all loaded metadata</param>
|
||||
/// <returns>True if cannot save data, otherwise false</returns>
|
||||
virtual bool Save(WriteStream* stream, bool saveMeta) const
|
||||
{
|
||||
// Magic Code
|
||||
stream->WriteInt32(1963542358);
|
||||
|
||||
// Version
|
||||
stream->WriteInt32(7000);
|
||||
|
||||
// Nodes count
|
||||
stream->WriteInt32(Nodes.Count());
|
||||
|
||||
// Parameters count
|
||||
stream->WriteInt32(Parameters.Count());
|
||||
|
||||
// For each node
|
||||
for (int32 i = 0; i < Nodes.Count(); i++)
|
||||
{
|
||||
auto node = &Nodes[i];
|
||||
stream->WriteUint32(node->ID);
|
||||
stream->WriteUint32(node->Type);
|
||||
}
|
||||
|
||||
// For each param
|
||||
for (int32 i = 0; i < Parameters.Count(); i++)
|
||||
{
|
||||
const Parameter* param = &Parameters[i];
|
||||
stream->WriteVariantType(param->Type);
|
||||
stream->Write(¶m->Identifier);
|
||||
stream->WriteString(param->Name, 97);
|
||||
stream->WriteBool(param->IsPublic);
|
||||
stream->WriteVariant(param->Value);
|
||||
if (param->Meta.Save(stream, saveMeta))
|
||||
return true;
|
||||
}
|
||||
|
||||
// For each node
|
||||
Array<const Box*, InlinedAllocation<32>> boxes;
|
||||
for (int32 i = 0; i < Nodes.Count(); i++)
|
||||
{
|
||||
const Node* node = &Nodes[i];
|
||||
|
||||
// Values
|
||||
stream->WriteInt32(node->Values.Count());
|
||||
for (int32 j = 0; j < node->Values.Count(); j++)
|
||||
stream->WriteVariant(node->Values[j]);
|
||||
|
||||
// Boxes
|
||||
node->GetBoxes(boxes);
|
||||
stream->WriteUint16(boxes.Count());
|
||||
for (int32 j = 0; j < boxes.Count(); j++)
|
||||
{
|
||||
const Box* box = boxes[j];
|
||||
stream->WriteByte(box->ID);
|
||||
stream->WriteVariantType(box->Type);
|
||||
stream->WriteUint16(box->Connections.Count());
|
||||
for (int32 k = 0; k < box->Connections.Count(); k++)
|
||||
{
|
||||
auto targetBox = box->Connections[k];
|
||||
if (targetBox == nullptr)
|
||||
return true;
|
||||
stream->WriteUint32(targetBox->template GetParent<Node>()->ID);
|
||||
stream->WriteByte(targetBox->ID);
|
||||
}
|
||||
}
|
||||
|
||||
// Meta
|
||||
if (node->Meta.Save(stream, saveMeta))
|
||||
return true;
|
||||
}
|
||||
|
||||
// Meta
|
||||
if (Meta.Save(stream, saveMeta))
|
||||
return true;
|
||||
|
||||
// Ending char
|
||||
stream->WriteByte('\t');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load graph from the stream
|
||||
/// </summary>
|
||||
/// <param name="stream">Input stream</param>
|
||||
/// <param name="loadMeta">True if load all saved metadata</param>
|
||||
/// <returns>True if cannot load data, otherwise false</returns>
|
||||
virtual bool Load(ReadStream* stream, bool loadMeta)
|
||||
{
|
||||
// Clear previous data
|
||||
Clear();
|
||||
|
||||
// Magic Code
|
||||
int32 tmp;
|
||||
stream->ReadInt32(&tmp);
|
||||
if (tmp != 1963542358)
|
||||
{
|
||||
LOG(Warning, "Invalid data.");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Version
|
||||
uint32 version;
|
||||
stream->ReadUint32(&version);
|
||||
|
||||
Array<TmpConnectionHint> tmpHints;
|
||||
if (version < 7000)
|
||||
{
|
||||
// [Deprecated on 31.07.2020, expires on 31.07.2022]
|
||||
|
||||
// Time saved
|
||||
int64 timeSaved;
|
||||
stream->ReadInt64(&timeSaved);
|
||||
|
||||
// Nodes count
|
||||
int32 nodesCount;
|
||||
stream->ReadInt32(&nodesCount);
|
||||
Nodes.Resize(nodesCount, false);
|
||||
|
||||
// Parameters count
|
||||
int32 parametersCount;
|
||||
stream->ReadInt32(¶metersCount);
|
||||
Parameters.Resize(parametersCount, false);
|
||||
|
||||
// For each node
|
||||
for (int32 i = 0; i < nodesCount; i++)
|
||||
{
|
||||
auto node = &Nodes[i];
|
||||
|
||||
// ID
|
||||
stream->ReadUint32(&node->ID);
|
||||
|
||||
// Type
|
||||
stream->ReadUint32(&node->Type);
|
||||
|
||||
if (onNodeCreated(node))
|
||||
return true;
|
||||
}
|
||||
|
||||
// For each param
|
||||
for (int32 i = 0; i < parametersCount; i++)
|
||||
{
|
||||
// Create param
|
||||
auto param = &Parameters[i];
|
||||
|
||||
// Properties
|
||||
auto type = stream->ReadByte();
|
||||
stream->Read(¶m->Identifier);
|
||||
stream->ReadString(¶m->Name, 97);
|
||||
param->IsPublic = stream->ReadBool();
|
||||
bool isStatic = stream->ReadBool();
|
||||
bool isUIVisible = stream->ReadBool();
|
||||
bool isUIEditable = stream->ReadBool();
|
||||
|
||||
// References [Deprecated]
|
||||
int32 refsCount;
|
||||
stream->ReadInt32(&refsCount);
|
||||
for (int32 j = 0; j < refsCount; j++)
|
||||
{
|
||||
uint32 refID;
|
||||
stream->ReadUint32(&refID);
|
||||
}
|
||||
|
||||
// Value
|
||||
ReadOldGraphParamValue_Deprecated(type, stream, param);
|
||||
|
||||
// Meta
|
||||
if (param->Meta.Load(stream, loadMeta))
|
||||
return true;
|
||||
|
||||
if (onParamCreated(param))
|
||||
return true;
|
||||
}
|
||||
|
||||
// For each node
|
||||
for (int32 i = 0; i < nodesCount; i++)
|
||||
{
|
||||
auto node = &Nodes[i];
|
||||
|
||||
// Values
|
||||
int32 valuesCnt;
|
||||
stream->ReadInt32(&valuesCnt);
|
||||
node->Values.Resize(valuesCnt);
|
||||
for (int32 j = 0; j < valuesCnt; j++)
|
||||
ReadOldGraphNodeValue_Deprecated(stream, node->Values[j]);
|
||||
|
||||
// Boxes
|
||||
uint16 boxesCount;
|
||||
stream->ReadUint16(&boxesCount);
|
||||
node->Boxes.Clear();
|
||||
for (int32 j = 0; j < boxesCount; j++)
|
||||
{
|
||||
byte boxID = stream->ReadByte();
|
||||
node->Boxes.Resize(node->Boxes.Count() > boxID + 1 ? node->Boxes.Count() : boxID + 1);
|
||||
Box* box = &node->Boxes[boxID];
|
||||
|
||||
box->Parent = node;
|
||||
box->ID = boxID;
|
||||
uint32 connectionType;
|
||||
stream->ReadUint32((uint32*)&connectionType);
|
||||
ReadOldGraphBoxType_Deprecated(connectionType, box->Type);
|
||||
|
||||
uint16 connectionsCount;
|
||||
stream->ReadUint16(&connectionsCount);
|
||||
box->Connections.Resize(connectionsCount);
|
||||
for (int32 k = 0; k < connectionsCount; k++)
|
||||
{
|
||||
uint32 targetNodeID;
|
||||
stream->ReadUint32(&targetNodeID);
|
||||
byte targetBoxID = stream->ReadByte();
|
||||
TmpConnectionHint hint;
|
||||
hint.Node = GetNode(targetNodeID);
|
||||
if (hint.Node == nullptr)
|
||||
return true;
|
||||
hint.BoxID = targetBoxID;
|
||||
box->Connections[k] = (Box*)(intptr)tmpHints.Count();
|
||||
tmpHints.Add(hint);
|
||||
}
|
||||
}
|
||||
|
||||
// Meta
|
||||
if (node->Meta.Load(stream, loadMeta))
|
||||
return true;
|
||||
|
||||
if (onNodeLoaded(node))
|
||||
return true;
|
||||
}
|
||||
|
||||
// Visject Meta
|
||||
if (Meta.Load(stream, loadMeta))
|
||||
return true;
|
||||
|
||||
// Setup connections
|
||||
for (int32 i = 0; i < Nodes.Count(); i++)
|
||||
{
|
||||
auto node = &Nodes[i];
|
||||
for (int32 j = 0; j < node->Boxes.Count(); j++)
|
||||
{
|
||||
Box* box = &node->Boxes[j];
|
||||
if (box->Parent == nullptr)
|
||||
continue;
|
||||
for (int32 k = 0; k < box->Connections.Count(); k++)
|
||||
{
|
||||
int32 hintIndex = (int32)(intptr)box->Connections[k];
|
||||
TmpConnectionHint hint = tmpHints[hintIndex];
|
||||
box->Connections[k] = hint.Node->GetBox(hint.BoxID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ending char
|
||||
byte end;
|
||||
stream->ReadByte(&end);
|
||||
if (end != '\t')
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (version == 7000)
|
||||
{
|
||||
// Nodes count
|
||||
int32 nodesCount;
|
||||
stream->ReadInt32(&nodesCount);
|
||||
Nodes.Resize(nodesCount, false);
|
||||
|
||||
// Parameters count
|
||||
int32 parametersCount;
|
||||
stream->ReadInt32(¶metersCount);
|
||||
Parameters.Resize(parametersCount, false);
|
||||
|
||||
// For each node
|
||||
for (int32 i = 0; i < nodesCount; i++)
|
||||
{
|
||||
auto node = &Nodes[i];
|
||||
stream->ReadUint32(&node->ID);
|
||||
stream->ReadUint32(&node->Type);
|
||||
if (onNodeCreated(node))
|
||||
return true;
|
||||
}
|
||||
|
||||
// For each param
|
||||
for (int32 i = 0; i < parametersCount; i++)
|
||||
{
|
||||
auto param = &Parameters[i];
|
||||
stream->ReadVariantType(¶m->Type);
|
||||
stream->Read(¶m->Identifier);
|
||||
stream->ReadString(¶m->Name, 97);
|
||||
param->IsPublic = stream->ReadBool();
|
||||
stream->ReadVariant(¶m->Value);
|
||||
if (param->Meta.Load(stream, loadMeta))
|
||||
return true;
|
||||
if (onParamCreated(param))
|
||||
return true;
|
||||
}
|
||||
|
||||
// For each node
|
||||
for (int32 i = 0; i < nodesCount; i++)
|
||||
{
|
||||
auto node = &Nodes[i];
|
||||
|
||||
// Values
|
||||
int32 valuesCnt;
|
||||
stream->ReadInt32(&valuesCnt);
|
||||
node->Values.Resize(valuesCnt);
|
||||
for (int32 j = 0; j < valuesCnt; j++)
|
||||
stream->ReadVariant(&node->Values[j]);
|
||||
|
||||
// Boxes
|
||||
uint16 boxesCount;
|
||||
stream->ReadUint16(&boxesCount);
|
||||
node->Boxes.Clear();
|
||||
for (int32 j = 0; j < boxesCount; j++)
|
||||
{
|
||||
byte boxID = stream->ReadByte();
|
||||
node->Boxes.Resize(node->Boxes.Count() > boxID + 1 ? node->Boxes.Count() : boxID + 1);
|
||||
Box* box = &node->Boxes[boxID];
|
||||
box->Parent = node;
|
||||
box->ID = boxID;
|
||||
stream->ReadVariantType(&box->Type);
|
||||
uint16 connectionsCount;
|
||||
stream->ReadUint16(&connectionsCount);
|
||||
box->Connections.Resize(connectionsCount);
|
||||
for (int32 k = 0; k < connectionsCount; k++)
|
||||
{
|
||||
uint32 targetNodeID;
|
||||
stream->ReadUint32(&targetNodeID);
|
||||
byte targetBoxID = stream->ReadByte();
|
||||
TmpConnectionHint hint;
|
||||
hint.Node = GetNode(targetNodeID);
|
||||
if (hint.Node == nullptr)
|
||||
return true;
|
||||
hint.BoxID = targetBoxID;
|
||||
box->Connections[k] = (Box*)(intptr)tmpHints.Count();
|
||||
tmpHints.Add(hint);
|
||||
}
|
||||
}
|
||||
|
||||
// Meta
|
||||
if (node->Meta.Load(stream, loadMeta))
|
||||
return true;
|
||||
|
||||
if (onNodeLoaded(node))
|
||||
return true;
|
||||
}
|
||||
|
||||
// Visject Meta
|
||||
if (Meta.Load(stream, loadMeta))
|
||||
return true;
|
||||
|
||||
// Setup connections
|
||||
for (int32 i = 0; i < Nodes.Count(); i++)
|
||||
{
|
||||
auto node = &Nodes[i];
|
||||
for (int32 j = 0; j < node->Boxes.Count(); j++)
|
||||
{
|
||||
Box* box = &node->Boxes[j];
|
||||
if (box->Parent == nullptr)
|
||||
continue;
|
||||
for (int32 k = 0; k < box->Connections.Count(); k++)
|
||||
{
|
||||
int32 hintIndex = (int32)(intptr)box->Connections[k];
|
||||
TmpConnectionHint hint = tmpHints[hintIndex];
|
||||
box->Connections[k] = hint.Node->GetBox(hint.BoxID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ending char
|
||||
byte end;
|
||||
stream->ReadByte(&end);
|
||||
if (end != '\t')
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Find node by ID
|
||||
/// </summary>
|
||||
/// <param name="id">Node ID</param>
|
||||
/// <returns>Node or null if cannot find it</returns>
|
||||
Node* GetNode(uint32 id)
|
||||
{
|
||||
Node* result = nullptr;
|
||||
for (int32 i = 0; i < Nodes.Count(); i++)
|
||||
{
|
||||
if (Nodes[i].ID == id)
|
||||
{
|
||||
result = &Nodes[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find parameter by ID
|
||||
/// </summary>
|
||||
/// <param name="id">Parameter ID</param>
|
||||
/// <returns>Parameter or null if cannot find it</returns>
|
||||
Parameter* GetParameter(const Guid& id)
|
||||
{
|
||||
Parameter* result = nullptr;
|
||||
for (int32 i = 0; i < Parameters.Count(); i++)
|
||||
{
|
||||
if (Parameters[i].Identifier == id)
|
||||
{
|
||||
result = &Parameters[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find parameter by ID
|
||||
/// </summary>
|
||||
/// <param name="id">Parameter ID</param>
|
||||
/// <param name="outIndex">Parameter index</param>
|
||||
/// <returns>Parameter or null if cannot find it</returns>
|
||||
Parameter* GetParameter(const Guid& id, int32& outIndex)
|
||||
{
|
||||
Parameter* result = nullptr;
|
||||
outIndex = INVALID_INDEX;
|
||||
for (int32 i = 0; i < Parameters.Count(); i++)
|
||||
{
|
||||
if (Parameters[i].Identifier == id)
|
||||
{
|
||||
result = &Parameters[i];
|
||||
outIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear whole graph data
|
||||
/// </summary>
|
||||
virtual void Clear()
|
||||
{
|
||||
Nodes.Resize(0);
|
||||
Parameters.Resize(0);
|
||||
Meta.Release();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
/// <summary>
|
||||
/// Gets the asset references.
|
||||
/// </summary>
|
||||
/// </remarks>
|
||||
/// <param name="output">The output collection of the asset ids referenced by this object.</param>
|
||||
virtual void GetReferences(Array<Guid>& output) const
|
||||
{
|
||||
for (int32 i = 0; i < Parameters.Count(); i++)
|
||||
{
|
||||
const auto& p = Parameters[i];
|
||||
const Guid id = (Guid)p.Value;
|
||||
if (id.IsValid())
|
||||
output.Add(id);
|
||||
}
|
||||
|
||||
for (int32 i = 0; i < Nodes.Count(); i++)
|
||||
{
|
||||
const auto& n = Nodes[i];
|
||||
for (int32 j = 0; j < n.Values.Count(); j++)
|
||||
{
|
||||
const Guid id = (Guid)n.Values[j];
|
||||
if (id.IsValid())
|
||||
output.Add(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
virtual bool onNodeCreated(Node* n)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool onNodeLoaded(Node* n)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool onParamCreated(Parameter* p)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 getFreeNodeID() const
|
||||
{
|
||||
uint32 result = 1;
|
||||
while (true)
|
||||
{
|
||||
bool valid = true;
|
||||
for (int32 i = 0; i < Nodes.Count(); i++)
|
||||
{
|
||||
if (Nodes[i].Identifier == result)
|
||||
{
|
||||
result++;
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (valid)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
225
Source/Engine/Visject/GraphNode.h
Normal file
225
Source/Engine/Visject/GraphNode.h
Normal file
@@ -0,0 +1,225 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Core/Types/Variant.h"
|
||||
#include "Engine/Core/Collections/Array.h"
|
||||
#include "Engine/Visject/VisjectMeta.h"
|
||||
|
||||
template<class BoxType>
|
||||
class GraphNode;
|
||||
|
||||
#define GRAPH_NODE_MAKE_TYPE(groupID, typeID) ((groupID) << 16 | (typeID))
|
||||
|
||||
#define GRAPH_NODE_MAX_VALUES 32
|
||||
|
||||
/// <summary>
|
||||
/// Represents single box of the graph node
|
||||
/// </summary>
|
||||
class GraphBox
|
||||
{
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// The parent node
|
||||
/// </summary>
|
||||
void* Parent;
|
||||
|
||||
/// <summary>
|
||||
/// Unique box ID within single node
|
||||
/// </summary>
|
||||
byte ID;
|
||||
|
||||
/// <summary>
|
||||
/// The box type.
|
||||
/// </summary>
|
||||
VariantType Type;
|
||||
|
||||
/// <summary>
|
||||
/// List with all connections to other boxes
|
||||
/// </summary>
|
||||
Array<GraphBox*, InlinedAllocation<4>> Connections;
|
||||
|
||||
public:
|
||||
|
||||
GraphBox()
|
||||
: Parent(nullptr)
|
||||
, ID(0)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Init
|
||||
/// </summary>
|
||||
/// <param name="parent">Parent node</param>
|
||||
/// <param name="id">Unique box id</param>
|
||||
/// <param name="type">Connections type</param>
|
||||
GraphBox(void* parent, byte id, const VariantType::Types type)
|
||||
: Parent(parent)
|
||||
, ID(id)
|
||||
, Type(type)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Init
|
||||
/// </summary>
|
||||
/// <param name="parent">Parent node</param>
|
||||
/// <param name="id">Unique box id</param>
|
||||
/// <param name="type">Connections type</param>
|
||||
GraphBox(void* parent, byte id, const VariantType& type)
|
||||
: Parent(parent)
|
||||
, ID(id)
|
||||
, Type(type)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parent node.
|
||||
/// </summary>
|
||||
template<class NodeType>
|
||||
FORCE_INLINE NodeType* GetParent() const
|
||||
{
|
||||
return static_cast<NodeType*>(Parent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if box has one or more connections.
|
||||
/// </summary>
|
||||
FORCE_INLINE bool HasConnection() const
|
||||
{
|
||||
return Connections.HasItems();
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Visject graph node base
|
||||
/// </summary>
|
||||
template<class BoxType>
|
||||
class GraphNode
|
||||
{
|
||||
public:
|
||||
|
||||
typedef BoxType Box;
|
||||
typedef GraphNode<BoxType> Node;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Unique node ID (within a graph).
|
||||
/// </summary>
|
||||
uint32 ID;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint16 TypeID;
|
||||
uint16 GroupID;
|
||||
};
|
||||
|
||||
uint32 Type;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// List of all node values. Array size and value types are constant over time. Only value data can change.
|
||||
/// </summary>
|
||||
Array<Variant, FixedAllocation<GRAPH_NODE_MAX_VALUES>> Values;
|
||||
|
||||
/// <summary>
|
||||
/// Node boxes cache. Array index matches the box ID (for fast O(1) lookups).
|
||||
/// </summary>
|
||||
Array<Box> Boxes;
|
||||
|
||||
/// <summary>
|
||||
/// Additional metadata.
|
||||
/// </summary>
|
||||
VisjectMeta Meta;
|
||||
|
||||
public:
|
||||
|
||||
GraphNode()
|
||||
: ID(0)
|
||||
, Type(0)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destructor
|
||||
/// </summary>
|
||||
~GraphNode()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Gets all the valid boxes.
|
||||
/// </summary>
|
||||
/// <param name="result">The result container.</param>
|
||||
template<typename AllocationType = HeapAllocation>
|
||||
void GetBoxes(Array<Box*, AllocationType>& result)
|
||||
{
|
||||
result.Clear();
|
||||
for (int32 i = 0; i < Boxes.Count(); i++)
|
||||
{
|
||||
if (Boxes[i].Parent == this)
|
||||
{
|
||||
result.Add(&Boxes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all the valid boxes.
|
||||
/// </summary>
|
||||
/// <param name="result">The result container.</param>
|
||||
template<typename AllocationType = HeapAllocation>
|
||||
void GetBoxes(Array<const Box*, AllocationType>& result) const
|
||||
{
|
||||
result.Clear();
|
||||
for (int32 i = 0; i < Boxes.Count(); i++)
|
||||
{
|
||||
if (Boxes[i].Parent == this)
|
||||
{
|
||||
result.Add(&Boxes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get box by ID
|
||||
/// </summary>
|
||||
/// <param name="id">Box ID</param>
|
||||
/// <returns>Box</returns>
|
||||
Box* GetBox(int32 id)
|
||||
{
|
||||
ASSERT(Boxes.HasItems() && Boxes.Count() > id && Boxes[id].ID == id && Boxes[id].Parent == this);
|
||||
return &Boxes[id];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get box by ID, returns null if missing.
|
||||
/// </summary>
|
||||
/// <param name="id">Box ID</param>
|
||||
/// <returns>Box</returns>
|
||||
Box* TryGetBox(int32 id)
|
||||
{
|
||||
if (id >= 0 && id < Boxes.Count() && Boxes[id].ID == id && Boxes[id].Parent == this)
|
||||
return &Boxes[id];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get box by ID
|
||||
/// </summary>
|
||||
/// <param name="id">Box ID</param>
|
||||
/// <returns>Box</returns>
|
||||
const Box* GetBox(int32 id) const
|
||||
{
|
||||
ASSERT(Boxes.HasItems() && Boxes.Count() > id && Boxes[id].ID == id && Boxes[id].Parent == this);
|
||||
return &Boxes[id];
|
||||
}
|
||||
};
|
||||
18
Source/Engine/Visject/GraphParameter.cpp
Normal file
18
Source/Engine/Visject/GraphParameter.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "GraphParameter.h"
|
||||
#include "Engine/Core/Types/DataContainer.h"
|
||||
|
||||
BytesContainer GraphParameter::GetMetaData(int32 typeID) const
|
||||
{
|
||||
BytesContainer result;
|
||||
for (const auto& e : Meta.Entries)
|
||||
{
|
||||
if (e.TypeID == typeID)
|
||||
{
|
||||
result.Link(e.Data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
94
Source/Engine/Visject/GraphParameter.h
Normal file
94
Source/Engine/Visject/GraphParameter.h
Normal file
@@ -0,0 +1,94 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Core/Types/Variant.h"
|
||||
#include "Engine/Scripting/ScriptingObject.h"
|
||||
#include "VisjectMeta.h"
|
||||
|
||||
template<typename T>
|
||||
class DataContainer;
|
||||
typedef DataContainer<byte> BytesContainer;
|
||||
|
||||
/// <summary>
|
||||
/// The channel mask modes.
|
||||
/// </summary>
|
||||
API_ENUM() enum class ChannelMask
|
||||
{
|
||||
/// <summary>
|
||||
/// The red channel.
|
||||
/// </summary>
|
||||
Red = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The green channel.
|
||||
/// </summary>
|
||||
Green = 1,
|
||||
|
||||
/// <summary>
|
||||
/// The blue channel.
|
||||
/// </summary>
|
||||
Blue = 2,
|
||||
|
||||
/// <summary>
|
||||
/// The alpha channel.
|
||||
/// </summary>
|
||||
Alpha = 3,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Represents a parameter in the Graph.
|
||||
/// </summary>
|
||||
API_CLASS() class FLAXENGINE_API GraphParameter : public PersistentScriptingObject
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_WITH_CONSTRUCTOR_IMPL(GraphParameter, PersistentScriptingObject);
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Parameter type
|
||||
/// </summary>
|
||||
API_FIELD(ReadOnly) VariantType Type;
|
||||
|
||||
/// <summary>
|
||||
/// Parameter unique ID
|
||||
/// </summary>
|
||||
API_FIELD(ReadOnly) Guid Identifier;
|
||||
|
||||
/// <summary>
|
||||
/// Parameter name
|
||||
/// </summary>
|
||||
API_FIELD(ReadOnly) String Name;
|
||||
|
||||
/// <summary>
|
||||
/// Parameter value
|
||||
/// </summary>
|
||||
API_FIELD() Variant Value;
|
||||
|
||||
/// <summary>
|
||||
/// True if is exposed outside
|
||||
/// </summary>
|
||||
API_FIELD() bool IsPublic = true;
|
||||
|
||||
/// <summary>
|
||||
/// Additional metadata
|
||||
/// </summary>
|
||||
VisjectMeta Meta;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Gets the typename of the parameter type (excluding in-build types).
|
||||
/// </summary>
|
||||
/// <returns>The typename of the parameter type.</returns>
|
||||
API_PROPERTY() StringAnsiView GetTypeTypeName() const
|
||||
{
|
||||
return StringAnsiView(Type.TypeName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data of the Visject Meta entry assigned to this parameter.
|
||||
/// </summary>
|
||||
/// <param name="typeID">Entry type ID</param>
|
||||
/// <returns>The entry data or empty if missing or not loaded.</returns>
|
||||
API_FUNCTION() BytesContainer GetMetaData(int32 typeID) const;
|
||||
};
|
||||
704
Source/Engine/Visject/GraphUtilities.cpp
Normal file
704
Source/Engine/Visject/GraphUtilities.cpp
Normal file
@@ -0,0 +1,704 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "GraphUtilities.h"
|
||||
|
||||
// [Deprecated on 31.07.2020, expires on 31.07.2022]
|
||||
enum class GraphParamType_Deprecated
|
||||
{
|
||||
Bool = 0,
|
||||
Integer = 1,
|
||||
Float = 2,
|
||||
Vector2 = 3,
|
||||
Vector3 = 4,
|
||||
Vector4 = 5,
|
||||
Color = 6,
|
||||
Texture = 7,
|
||||
NormalMap = 8,
|
||||
String = 9,
|
||||
Box = 10,
|
||||
Rotation = 11,
|
||||
Transform = 12,
|
||||
Asset = 13,
|
||||
Actor = 14,
|
||||
Rectangle = 15,
|
||||
CubeTexture = 16,
|
||||
SceneTexture = 17,
|
||||
GPUTexture = 18,
|
||||
Matrix = 19,
|
||||
GPUTextureArray = 20,
|
||||
GPUTextureVolume = 21,
|
||||
GPUTextureCube = 22,
|
||||
ChannelMask = 23,
|
||||
};
|
||||
|
||||
// [Deprecated on 31.07.2020, expires on 31.07.2022]
|
||||
enum class GraphConnectionType_Deprecated : uint32
|
||||
{
|
||||
Invalid = 0,
|
||||
Impulse = 1 << 0,
|
||||
Bool = 1 << 1,
|
||||
Integer = 1 << 2,
|
||||
Float = 1 << 3,
|
||||
Vector2 = 1 << 4,
|
||||
Vector3 = 1 << 5,
|
||||
Vector4 = 1 << 6,
|
||||
String = 1 << 7,
|
||||
Object = 1 << 8,
|
||||
Rotation = 1 << 9,
|
||||
Transform = 1 << 10,
|
||||
Box = 1 << 11,
|
||||
ImpulseSecondary = 1 << 12,
|
||||
UnsignedInteger = 1 << 13,
|
||||
Scalar = Bool | Integer | Float | UnsignedInteger,
|
||||
Vector = Vector2 | Vector3 | Vector4,
|
||||
Variable = Scalar | Vector | String | Object | Rotation | Transform | Box,
|
||||
All = Variable | Impulse,
|
||||
};
|
||||
|
||||
// Required by deprecated graph data upgrade code
|
||||
#include "Engine/Content/Assets/Texture.h"
|
||||
#include "Engine/Content/Assets/CubeTexture.h"
|
||||
#include "Engine/Scripting/ScriptingObjectReference.h"
|
||||
#include "Engine/Core/Types/CommonValue.h"
|
||||
#include "Engine/Level/Actor.h"
|
||||
|
||||
FLAXENGINE_API void ReadOldGraphParamValue_Deprecated(byte graphParamType, ReadStream* stream, GraphParameter* param)
|
||||
{
|
||||
// [Deprecated on 31.07.2020, expires on 31.07.2022]
|
||||
CommonValue value;
|
||||
stream->ReadCommonValue(&value);
|
||||
switch ((GraphParamType_Deprecated)graphParamType)
|
||||
{
|
||||
case GraphParamType_Deprecated::Bool:
|
||||
param->Type = VariantType(VariantType::Bool);
|
||||
param->Value = value.GetBool();
|
||||
break;
|
||||
case GraphParamType_Deprecated::Integer:
|
||||
param->Type = VariantType(VariantType::Int);
|
||||
param->Value = value.GetInteger();
|
||||
break;
|
||||
case GraphParamType_Deprecated::Float:
|
||||
param->Type = VariantType(VariantType::Float);
|
||||
param->Value = value.GetFloat();
|
||||
break;
|
||||
case GraphParamType_Deprecated::Vector2:
|
||||
param->Type = VariantType(VariantType::Vector2);
|
||||
param->Value = value.GetVector2();
|
||||
break;
|
||||
case GraphParamType_Deprecated::Vector3:
|
||||
param->Type = VariantType(VariantType::Vector3);
|
||||
param->Value = value.GetVector3();
|
||||
break;
|
||||
case GraphParamType_Deprecated::Vector4:
|
||||
param->Type = VariantType(VariantType::Vector4);
|
||||
param->Value = value.GetVector4();
|
||||
break;
|
||||
case GraphParamType_Deprecated::Color:
|
||||
param->Type = VariantType(VariantType::Color);
|
||||
param->Value = value.GetColor();
|
||||
break;
|
||||
case GraphParamType_Deprecated::Texture:
|
||||
case GraphParamType_Deprecated::NormalMap:
|
||||
ASSERT(value.Type == CommonType::Guid);
|
||||
param->Type = VariantType(VariantType::Asset, TEXT("FlaxEngine.Texture"));
|
||||
param->Value.SetAsset(LoadAsset(value.AsGuid, Texture::TypeInitializer));
|
||||
break;
|
||||
case GraphParamType_Deprecated::String:
|
||||
ASSERT(value.Type == CommonType::String);
|
||||
param->Type = VariantType(VariantType::String);
|
||||
param->Value.SetString(StringView(value.AsString));
|
||||
break;
|
||||
case GraphParamType_Deprecated::Box:
|
||||
ASSERT(value.Type == CommonType::Box);
|
||||
param->Type = VariantType(VariantType::BoundingBox);
|
||||
param->Value = Variant(value.AsBox);
|
||||
break;
|
||||
case GraphParamType_Deprecated::Rotation:
|
||||
ASSERT(value.Type == CommonType::Rotation);
|
||||
param->Type = VariantType(VariantType::Quaternion);
|
||||
param->Value = value.AsRotation;
|
||||
break;
|
||||
case GraphParamType_Deprecated::Transform:
|
||||
ASSERT(value.Type == CommonType::Transform);
|
||||
param->Type = VariantType(VariantType::Transform);
|
||||
param->Value = Variant(value.AsTransform);
|
||||
break;
|
||||
case GraphParamType_Deprecated::Asset:
|
||||
ASSERT(value.Type == CommonType::Guid);
|
||||
param->Type = VariantType(VariantType::Asset);
|
||||
param->Value.SetAsset(LoadAsset(value.AsGuid, Asset::TypeInitializer));
|
||||
break;
|
||||
case GraphParamType_Deprecated::Rectangle:
|
||||
ASSERT(value.Type == CommonType::Rectangle);
|
||||
param->Type = VariantType(VariantType::Rectangle);
|
||||
param->Value = value.AsRectangle;
|
||||
break;
|
||||
case GraphParamType_Deprecated::Matrix:
|
||||
ASSERT(value.Type == CommonType::Matrix);
|
||||
param->Type = VariantType(VariantType::Matrix);
|
||||
param->Value = Variant(value.AsMatrix);
|
||||
break;
|
||||
case GraphParamType_Deprecated::Actor:
|
||||
ASSERT(value.Type == CommonType::Guid);
|
||||
param->Type = VariantType(VariantType::Object, TEXT("FlaxEngine.Actor"));
|
||||
param->Value.SetObject(FindObject(value.AsGuid, Actor::GetStaticClass()));
|
||||
break;
|
||||
case GraphParamType_Deprecated::CubeTexture:
|
||||
ASSERT(value.Type == CommonType::Guid);
|
||||
param->Type = VariantType(VariantType::Asset, TEXT("FlaxEngine.CubeTexture"));
|
||||
param->Value.SetAsset(LoadAsset(value.AsGuid, CubeTexture::TypeInitializer));
|
||||
break;
|
||||
case GraphParamType_Deprecated::GPUTexture:
|
||||
case GraphParamType_Deprecated::GPUTextureArray:
|
||||
case GraphParamType_Deprecated::GPUTextureVolume:
|
||||
case GraphParamType_Deprecated::GPUTextureCube:
|
||||
param->Type = VariantType(VariantType::Object, TEXT("FlaxEngine.GPUTexture"));
|
||||
param->Value.SetObject(nullptr);
|
||||
break;
|
||||
case GraphParamType_Deprecated::SceneTexture:
|
||||
param->Type = VariantType(VariantType::Enum, TEXT("FlaxEngine.MaterialSceneTextures"));
|
||||
param->Value.AsUint64 = (uint64)value.AsInteger;
|
||||
break;
|
||||
case GraphParamType_Deprecated::ChannelMask:
|
||||
param->Type = VariantType(VariantType::Enum, TEXT("FlaxEngine.ChannelMask"));
|
||||
param->Value.AsUint64 = (uint64)value.AsInteger;
|
||||
break;
|
||||
default:
|
||||
CRASH;
|
||||
}
|
||||
}
|
||||
|
||||
FLAXENGINE_API void ReadOldGraphNodeValue_Deprecated(ReadStream* stream, Variant& result)
|
||||
{
|
||||
// [Deprecated on 31.07.2020, expires on 31.07.2022]
|
||||
CommonValue value;
|
||||
stream->ReadCommonValue(&value);
|
||||
result = Variant(value);
|
||||
}
|
||||
|
||||
FLAXENGINE_API void ReadOldGraphBoxType_Deprecated(uint32 connectionType, VariantType& type)
|
||||
{
|
||||
// [Deprecated on 31.07.2020, expires on 31.07.2022]
|
||||
switch ((GraphConnectionType_Deprecated)connectionType)
|
||||
{
|
||||
case GraphConnectionType_Deprecated::Invalid:
|
||||
type = VariantType(VariantType::Null);
|
||||
break;
|
||||
case GraphConnectionType_Deprecated::Impulse:
|
||||
type = VariantType(VariantType::Void);
|
||||
break;
|
||||
case GraphConnectionType_Deprecated::Bool:
|
||||
type = VariantType(VariantType::Bool);
|
||||
break;
|
||||
case GraphConnectionType_Deprecated::Integer:
|
||||
type = VariantType(VariantType::Int);
|
||||
break;
|
||||
case GraphConnectionType_Deprecated::Float:
|
||||
type = VariantType(VariantType::Float);
|
||||
break;
|
||||
case GraphConnectionType_Deprecated::Vector2:
|
||||
type = VariantType(VariantType::Vector2);
|
||||
break;
|
||||
case GraphConnectionType_Deprecated::Vector3:
|
||||
type = VariantType(VariantType::Vector3);
|
||||
break;
|
||||
case GraphConnectionType_Deprecated::Vector4:
|
||||
type = VariantType(VariantType::Vector4);
|
||||
break;
|
||||
case GraphConnectionType_Deprecated::String:
|
||||
type = VariantType(VariantType::String);
|
||||
break;
|
||||
case GraphConnectionType_Deprecated::Object:
|
||||
type = VariantType(VariantType::Object);
|
||||
break;
|
||||
case GraphConnectionType_Deprecated::Rotation:
|
||||
type = VariantType(VariantType::Quaternion);
|
||||
break;
|
||||
case GraphConnectionType_Deprecated::Transform:
|
||||
type = VariantType(VariantType::Transform);
|
||||
break;
|
||||
case GraphConnectionType_Deprecated::Box:
|
||||
type = VariantType(VariantType::BoundingBox);
|
||||
break;
|
||||
case GraphConnectionType_Deprecated::ImpulseSecondary:
|
||||
type = VariantType(VariantType::Void);
|
||||
break;
|
||||
case GraphConnectionType_Deprecated::UnsignedInteger:
|
||||
type = VariantType(VariantType::Uint);
|
||||
break;
|
||||
case GraphConnectionType_Deprecated::Scalar:
|
||||
type = VariantType(VariantType::Null);
|
||||
break;
|
||||
case GraphConnectionType_Deprecated::Vector:
|
||||
type = VariantType(VariantType::Null);
|
||||
break;
|
||||
case GraphConnectionType_Deprecated::Variable:
|
||||
type = VariantType(VariantType::Null);
|
||||
break;
|
||||
case GraphConnectionType_Deprecated::All:
|
||||
type = VariantType(VariantType::Null);
|
||||
break;
|
||||
default:
|
||||
type = VariantType(VariantType::Null);
|
||||
}
|
||||
}
|
||||
|
||||
FLAXENGINE_API StringView GetGraphFunctionTypeName_Deprecated(const Variant& v)
|
||||
{
|
||||
// [Deprecated on 31.07.2020, expires on 31.07.2022]
|
||||
if (v.Type.Type == VariantType::String)
|
||||
return (StringView)v;
|
||||
if (v.Type.Type == VariantType::Int)
|
||||
{
|
||||
switch ((GraphConnectionType_Deprecated)v.AsInt)
|
||||
{
|
||||
case GraphConnectionType_Deprecated::Impulse:
|
||||
case GraphConnectionType_Deprecated::ImpulseSecondary:
|
||||
return TEXT("System.Void");
|
||||
case GraphConnectionType_Deprecated::Invalid:
|
||||
case GraphConnectionType_Deprecated::Variable:
|
||||
case GraphConnectionType_Deprecated::All:
|
||||
return StringView::Empty;
|
||||
case GraphConnectionType_Deprecated::Bool:
|
||||
return TEXT("System.Boolean");
|
||||
case GraphConnectionType_Deprecated::Integer:
|
||||
return TEXT("System.Int32");
|
||||
case GraphConnectionType_Deprecated::Float:
|
||||
case GraphConnectionType_Deprecated::Scalar:
|
||||
return TEXT("System.Single");
|
||||
case GraphConnectionType_Deprecated::Vector2:
|
||||
return TEXT("FlaxEngine.Vector2");
|
||||
case GraphConnectionType_Deprecated::Vector3:
|
||||
return TEXT("FlaxEngine.Vector3");
|
||||
case GraphConnectionType_Deprecated::Vector4:
|
||||
case GraphConnectionType_Deprecated::Vector:
|
||||
return TEXT("FlaxEngine.Vector4");
|
||||
case GraphConnectionType_Deprecated::String:
|
||||
return TEXT("System.String");
|
||||
case GraphConnectionType_Deprecated::Object:
|
||||
return TEXT("FlaxEngine.Object");
|
||||
case GraphConnectionType_Deprecated::Rotation:
|
||||
return TEXT("System.Quaternion");
|
||||
case GraphConnectionType_Deprecated::Transform:
|
||||
return TEXT("System.Transform");
|
||||
case GraphConnectionType_Deprecated::Box:
|
||||
return TEXT("System.BoundingBox");
|
||||
case GraphConnectionType_Deprecated::UnsignedInteger:
|
||||
return TEXT("System.UInt32");
|
||||
default: ;
|
||||
}
|
||||
}
|
||||
return StringView::Empty;
|
||||
}
|
||||
|
||||
void GraphUtilities::ApplySomeMathHere(Variant& v, Variant& a, MathOp1 op)
|
||||
{
|
||||
v.SetType(a.Type);
|
||||
switch (a.Type.Type)
|
||||
{
|
||||
case VariantType::Bool:
|
||||
v.AsBool = op(a.AsBool ? 1.0f : 0.0f) > ZeroTolerance;
|
||||
break;
|
||||
case VariantType::Int:
|
||||
v.AsInt = (int32)op((float)a.AsInt);
|
||||
break;
|
||||
case VariantType::Uint:
|
||||
v.AsUint = (uint32)op((float)a.AsUint);
|
||||
break;
|
||||
case VariantType::Float:
|
||||
v.AsFloat = op(a.AsFloat);
|
||||
break;
|
||||
case VariantType::Vector2:
|
||||
(*(Vector2*)v.AsData).X = op((*(Vector2*)a.AsData).X);
|
||||
(*(Vector2*)v.AsData).Y = op((*(Vector2*)a.AsData).Y);
|
||||
break;
|
||||
case VariantType::Vector3:
|
||||
(*(Vector3*)v.AsData).X = op((*(Vector3*)a.AsData).X);
|
||||
(*(Vector3*)v.AsData).Y = op((*(Vector3*)a.AsData).Y);
|
||||
(*(Vector3*)v.AsData).Z = op((*(Vector3*)a.AsData).Z);
|
||||
break;
|
||||
case VariantType::Vector4:
|
||||
case VariantType::Color:
|
||||
(*(Vector4*)v.AsData).X = op((*(Vector4*)a.AsData).X);
|
||||
(*(Vector4*)v.AsData).Y = op((*(Vector4*)a.AsData).Y);
|
||||
(*(Vector4*)v.AsData).Z = op((*(Vector4*)a.AsData).Z);
|
||||
(*(Vector4*)v.AsData).W = op((*(Vector4*)a.AsData).W);
|
||||
break;
|
||||
case VariantType::Quaternion:
|
||||
(*(Quaternion*)v.AsData).X = op((*(Quaternion*)a.AsData).X);
|
||||
(*(Quaternion*)v.AsData).Y = op((*(Quaternion*)a.AsData).Y);
|
||||
(*(Quaternion*)v.AsData).Z = op((*(Quaternion*)a.AsData).Z);
|
||||
(*(Quaternion*)v.AsData).W = op((*(Quaternion*)a.AsData).W);
|
||||
break;
|
||||
case VariantType::Transform:
|
||||
{
|
||||
Transform& vTransform = *(Transform*)v.AsBlob.Data;
|
||||
const Transform& aTransform = *(const Transform*)a.AsBlob.Data;
|
||||
vTransform.Translation.X = op(aTransform.Translation.X);
|
||||
vTransform.Translation.Y = op(aTransform.Translation.Y);
|
||||
vTransform.Translation.Z = op(aTransform.Translation.Z);
|
||||
vTransform.Orientation.X = op(aTransform.Orientation.X);
|
||||
vTransform.Orientation.Y = op(aTransform.Orientation.Y);
|
||||
vTransform.Orientation.Z = op(aTransform.Orientation.Z);
|
||||
vTransform.Orientation.W = op(aTransform.Orientation.W);
|
||||
vTransform.Scale.X = op(aTransform.Scale.X);
|
||||
vTransform.Scale.Y = op(aTransform.Scale.Y);
|
||||
vTransform.Scale.Z = op(aTransform.Scale.Z);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
v = a;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GraphUtilities::ApplySomeMathHere(Variant& v, Variant& a, Variant& b, MathOp2 op)
|
||||
{
|
||||
v.SetType(a.Type);
|
||||
switch (a.Type.Type)
|
||||
{
|
||||
case VariantType::Bool:
|
||||
v.AsBool = op(a.AsBool ? 1.0f : 0.0f, b.AsBool ? 1.0f : 0.0f) > ZeroTolerance;
|
||||
break;
|
||||
case VariantType::Int:
|
||||
v.AsInt = (int32)op((float)a.AsInt, (float)b.AsInt);
|
||||
break;
|
||||
case VariantType::Uint:
|
||||
v.AsUint = (uint32)op((float)a.AsUint, (float)b.AsUint);
|
||||
break;
|
||||
case VariantType::Float:
|
||||
v.AsFloat = op(a.AsFloat, b.AsFloat);
|
||||
break;
|
||||
case VariantType::Vector2:
|
||||
(*(Vector2*)v.AsData).X = op((*(Vector2*)a.AsData).X, (*(Vector2*)b.AsData).X);
|
||||
(*(Vector2*)v.AsData).Y = op((*(Vector2*)a.AsData).Y, (*(Vector2*)b.AsData).Y);
|
||||
break;
|
||||
case VariantType::Vector3:
|
||||
(*(Vector3*)v.AsData).X = op((*(Vector3*)a.AsData).X, (*(Vector3*)b.AsData).X);
|
||||
(*(Vector3*)v.AsData).Y = op((*(Vector3*)a.AsData).Y, (*(Vector3*)b.AsData).Y);
|
||||
(*(Vector3*)v.AsData).Z = op((*(Vector3*)a.AsData).Z, (*(Vector3*)b.AsData).Z);
|
||||
break;
|
||||
case VariantType::Vector4:
|
||||
case VariantType::Color:
|
||||
(*(Vector4*)v.AsData).X = op((*(Vector4*)a.AsData).X, (*(Vector4*)b.AsData).X);
|
||||
(*(Vector4*)v.AsData).Y = op((*(Vector4*)a.AsData).Y, (*(Vector4*)b.AsData).Y);
|
||||
(*(Vector4*)v.AsData).Z = op((*(Vector4*)a.AsData).Z, (*(Vector4*)b.AsData).Z);
|
||||
(*(Vector4*)v.AsData).W = op((*(Vector4*)a.AsData).W, (*(Vector4*)b.AsData).W);
|
||||
case VariantType::Quaternion:
|
||||
(*(Quaternion*)v.AsData).X = op((*(Quaternion*)a.AsData).X, (*(Quaternion*)b.AsData).X);
|
||||
(*(Quaternion*)v.AsData).Y = op((*(Quaternion*)a.AsData).Y, (*(Quaternion*)b.AsData).Y);
|
||||
(*(Quaternion*)v.AsData).Z = op((*(Quaternion*)a.AsData).Z, (*(Quaternion*)b.AsData).Z);
|
||||
(*(Quaternion*)v.AsData).W = op((*(Quaternion*)a.AsData).W, (*(Quaternion*)b.AsData).W);
|
||||
break;
|
||||
case VariantType::Transform:
|
||||
{
|
||||
Transform& vTransform = *(Transform*)v.AsBlob.Data;
|
||||
const Transform& aTransform = *(const Transform*)a.AsBlob.Data;
|
||||
const Transform& bTransform = *(const Transform*)b.AsBlob.Data;
|
||||
vTransform.Translation.X = op(aTransform.Translation.X, bTransform.Translation.X);
|
||||
vTransform.Translation.Y = op(aTransform.Translation.Y, bTransform.Translation.Y);
|
||||
vTransform.Translation.Z = op(aTransform.Translation.Z, bTransform.Translation.Z);
|
||||
vTransform.Orientation.X = op(aTransform.Orientation.X, bTransform.Orientation.X);
|
||||
vTransform.Orientation.Y = op(aTransform.Orientation.Y, bTransform.Orientation.Y);
|
||||
vTransform.Orientation.Z = op(aTransform.Orientation.Z, bTransform.Orientation.Z);
|
||||
vTransform.Orientation.W = op(aTransform.Orientation.W, bTransform.Orientation.W);
|
||||
vTransform.Scale.X = op(aTransform.Scale.X, bTransform.Scale.X);
|
||||
vTransform.Scale.Y = op(aTransform.Scale.Y, bTransform.Scale.Y);
|
||||
vTransform.Scale.Z = op(aTransform.Scale.Z, bTransform.Scale.Z);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
v = a;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GraphUtilities::ApplySomeMathHere(Variant& v, Variant& a, Variant& b, Variant& c, MathOp3 op)
|
||||
{
|
||||
v.SetType(a.Type);
|
||||
switch (a.Type.Type)
|
||||
{
|
||||
case VariantType::Bool:
|
||||
v.AsBool = op(a.AsBool ? 1.0f : 0.0f, b.AsBool ? 1.0f : 0.0f, c.AsBool ? 1.0f : 0.0f) > ZeroTolerance;
|
||||
break;
|
||||
case VariantType::Int:
|
||||
v.AsInt = (int32)op((float)a.AsInt, (float)b.AsInt, (float)c.AsInt);
|
||||
break;
|
||||
case VariantType::Uint:
|
||||
v.AsUint = (int32)op((float)a.AsUint, (float)b.AsUint, (float)c.AsUint);
|
||||
break;
|
||||
case VariantType::Float:
|
||||
v.AsFloat = op(a.AsFloat, b.AsFloat, c.AsFloat);
|
||||
break;
|
||||
case VariantType::Vector2:
|
||||
(*(Vector2*)v.AsData).X = op((*(Vector2*)a.AsData).X, (*(Vector2*)b.AsData).X, (*(Vector2*)c.AsData).X);
|
||||
(*(Vector2*)v.AsData).Y = op((*(Vector2*)a.AsData).Y, (*(Vector2*)b.AsData).Y, (*(Vector2*)c.AsData).Y);
|
||||
break;
|
||||
case VariantType::Vector3:
|
||||
(*(Vector3*)v.AsData).X = op((*(Vector3*)a.AsData).X, (*(Vector3*)b.AsData).X, (*(Vector3*)c.AsData).X);
|
||||
(*(Vector3*)v.AsData).Y = op((*(Vector3*)a.AsData).Y, (*(Vector3*)b.AsData).Y, (*(Vector3*)c.AsData).Y);
|
||||
(*(Vector3*)v.AsData).Z = op((*(Vector3*)a.AsData).Z, (*(Vector3*)b.AsData).Z, (*(Vector3*)c.AsData).Z);
|
||||
break;
|
||||
case VariantType::Vector4:
|
||||
case VariantType::Color:
|
||||
(*(Vector4*)v.AsData).X = op((*(Vector4*)a.AsData).X, (*(Vector4*)b.AsData).X, (*(Vector4*)c.AsData).X);
|
||||
(*(Vector4*)v.AsData).Y = op((*(Vector4*)a.AsData).Y, (*(Vector4*)b.AsData).Y, (*(Vector4*)c.AsData).Y);
|
||||
(*(Vector4*)v.AsData).Z = op((*(Vector4*)a.AsData).Z, (*(Vector4*)b.AsData).Z, (*(Vector4*)c.AsData).Z);
|
||||
(*(Vector4*)v.AsData).W = op((*(Vector4*)a.AsData).W, (*(Vector4*)b.AsData).W, (*(Vector4*)c.AsData).W);
|
||||
break;
|
||||
case VariantType::Quaternion:
|
||||
(*(Quaternion*)v.AsData).X = op((*(Quaternion*)a.AsData).X, (*(Quaternion*)b.AsData).X, (*(Quaternion*)c.AsData).X);
|
||||
(*(Quaternion*)v.AsData).Y = op((*(Quaternion*)a.AsData).Y, (*(Quaternion*)b.AsData).Y, (*(Quaternion*)c.AsData).Y);
|
||||
(*(Quaternion*)v.AsData).Z = op((*(Quaternion*)a.AsData).Z, (*(Quaternion*)b.AsData).Z, (*(Quaternion*)c.AsData).Z);
|
||||
(*(Quaternion*)v.AsData).W = op((*(Quaternion*)a.AsData).W, (*(Quaternion*)b.AsData).W, (*(Quaternion*)c.AsData).W);
|
||||
break;
|
||||
case VariantType::Transform:
|
||||
{
|
||||
Transform& vTransform = *(Transform*)v.AsBlob.Data;
|
||||
const Transform& aTransform = *(const Transform*)a.AsBlob.Data;
|
||||
const Transform& bTransform = *(const Transform*)b.AsBlob.Data;
|
||||
const Transform& cTransform = *(const Transform*)c.AsBlob.Data;
|
||||
vTransform.Translation.X = op(aTransform.Translation.X, bTransform.Translation.X, cTransform.Translation.X);
|
||||
vTransform.Translation.Y = op(aTransform.Translation.Y, bTransform.Translation.Y, cTransform.Translation.Y);
|
||||
vTransform.Translation.Z = op(aTransform.Translation.Z, bTransform.Translation.Z, cTransform.Translation.Z);
|
||||
vTransform.Orientation.X = op(aTransform.Orientation.X, bTransform.Orientation.X, cTransform.Orientation.X);
|
||||
vTransform.Orientation.Y = op(aTransform.Orientation.Y, bTransform.Orientation.Y, cTransform.Orientation.Y);
|
||||
vTransform.Orientation.Z = op(aTransform.Orientation.Z, bTransform.Orientation.Z, cTransform.Orientation.Z);
|
||||
vTransform.Orientation.W = op(aTransform.Orientation.W, bTransform.Orientation.W, cTransform.Orientation.W);
|
||||
vTransform.Scale.X = op(aTransform.Scale.X, bTransform.Scale.X, cTransform.Scale.X);
|
||||
vTransform.Scale.Y = op(aTransform.Scale.Y, bTransform.Scale.Y, cTransform.Scale.Y);
|
||||
vTransform.Scale.Z = op(aTransform.Scale.Z, bTransform.Scale.Z, cTransform.Scale.Z);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
v = a;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GraphUtilities::ApplySomeMathHere(uint16 typeId, Variant& v, Variant& a)
|
||||
{
|
||||
// Select operation
|
||||
MathOp1 op;
|
||||
switch (typeId)
|
||||
{
|
||||
case 7:
|
||||
op = [](float a)
|
||||
{
|
||||
return Math::Abs(a);
|
||||
};
|
||||
break;
|
||||
case 8:
|
||||
op = [](float a)
|
||||
{
|
||||
return Math::Ceil(a);
|
||||
};
|
||||
break;
|
||||
case 9:
|
||||
op = [](float a)
|
||||
{
|
||||
return Math::Cos(a);
|
||||
};
|
||||
break;
|
||||
case 10:
|
||||
op = [](float a)
|
||||
{
|
||||
return Math::Floor(a);
|
||||
};
|
||||
break;
|
||||
case 13:
|
||||
op = [](float a)
|
||||
{
|
||||
return Math::Round(a);
|
||||
};
|
||||
break;
|
||||
case 14:
|
||||
op = [](float a)
|
||||
{
|
||||
return Math::Saturate(a);
|
||||
};
|
||||
break;
|
||||
case 15:
|
||||
op = [](float a)
|
||||
{
|
||||
return Math::Sin(a);
|
||||
};
|
||||
break;
|
||||
case 16:
|
||||
op = [](float a)
|
||||
{
|
||||
return Math::Sqrt(a);
|
||||
};
|
||||
break;
|
||||
case 17:
|
||||
op = [](float a)
|
||||
{
|
||||
return Math::Tan(a);
|
||||
};
|
||||
break;
|
||||
case 27:
|
||||
op = [](float a)
|
||||
{
|
||||
return -a;
|
||||
};
|
||||
break;
|
||||
case 28:
|
||||
op = [](float a)
|
||||
{
|
||||
return 1 - a;
|
||||
};
|
||||
break;
|
||||
case 33:
|
||||
op = [](float a)
|
||||
{
|
||||
return Math::Asin(a);
|
||||
};
|
||||
break;
|
||||
case 34:
|
||||
op = [](float a)
|
||||
{
|
||||
return Math::Acos(a);
|
||||
};
|
||||
break;
|
||||
case 35:
|
||||
op = [](float a)
|
||||
{
|
||||
return Math::Atan(a);
|
||||
};
|
||||
break;
|
||||
case 38:
|
||||
op = [](float a)
|
||||
{
|
||||
return Math::Trunc(a);
|
||||
};
|
||||
break;
|
||||
case 39:
|
||||
op = [](float a)
|
||||
{
|
||||
float tmp;
|
||||
return Math::ModF(a, &tmp);
|
||||
};
|
||||
break;
|
||||
case 43:
|
||||
{
|
||||
op = [](float a)
|
||||
{
|
||||
return a * RadiansToDegrees;
|
||||
};
|
||||
break;
|
||||
}
|
||||
case 44:
|
||||
{
|
||||
op = [](float a)
|
||||
{
|
||||
return a * DegreesToRadians;
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
// Perform operation
|
||||
ApplySomeMathHere(v, a, op);
|
||||
}
|
||||
|
||||
void GraphUtilities::ApplySomeMathHere(uint16 typeId, Variant& v, Variant& a, Variant& b)
|
||||
{
|
||||
// Select operation
|
||||
MathOp2 op;
|
||||
switch (typeId)
|
||||
{
|
||||
case 1:
|
||||
op = [](float a, float b)
|
||||
{
|
||||
return a + b;
|
||||
};
|
||||
break;
|
||||
case 2:
|
||||
op = [](float a, float b)
|
||||
{
|
||||
return a - b;
|
||||
};
|
||||
break;
|
||||
case 3:
|
||||
op = [](float a, float b)
|
||||
{
|
||||
return a * b;
|
||||
};
|
||||
break;
|
||||
case 4:
|
||||
op = [](float a, float b)
|
||||
{
|
||||
return (float)((int)a % (int)b);
|
||||
};
|
||||
break;
|
||||
case 5:
|
||||
op = [](float a, float b)
|
||||
{
|
||||
return a / b;
|
||||
};
|
||||
break;
|
||||
case 21:
|
||||
op = [](float a, float b)
|
||||
{
|
||||
return Math::Max(a, b);
|
||||
};
|
||||
break;
|
||||
case 22:
|
||||
op = [](float a, float b)
|
||||
{
|
||||
return Math::Min(a, b);
|
||||
};
|
||||
break;
|
||||
case 23:
|
||||
op = [](float a, float b)
|
||||
{
|
||||
return Math::Pow(a, b);
|
||||
};
|
||||
break;
|
||||
case 40:
|
||||
op = [](float a, float b)
|
||||
{
|
||||
return Math::Mod(a, b);
|
||||
};
|
||||
break;
|
||||
case 41:
|
||||
op = [](float a, float b)
|
||||
{
|
||||
return Math::Atan2(a, b);
|
||||
};
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
// Perform operation
|
||||
ApplySomeMathHere(v, a, b, op);
|
||||
}
|
||||
|
||||
int32 GraphUtilities::CountComponents(VariantType::Types type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case VariantType::Bool:
|
||||
case VariantType::Int:
|
||||
case VariantType::Int64:
|
||||
case VariantType::Uint:
|
||||
case VariantType::Uint64:
|
||||
case VariantType::Float:
|
||||
case VariantType::Double:
|
||||
case VariantType::Pointer:
|
||||
return 1;
|
||||
case VariantType::Vector2:
|
||||
return 2;
|
||||
case VariantType::Vector3:
|
||||
return 3;
|
||||
case VariantType::Vector4:
|
||||
case VariantType::Color:
|
||||
return 4;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
22
Source/Engine/Visject/GraphUtilities.h
Normal file
22
Source/Engine/Visject/GraphUtilities.h
Normal file
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Core/Types/Variant.h"
|
||||
#include "Engine/Visject/Graph.h"
|
||||
|
||||
namespace GraphUtilities
|
||||
{
|
||||
typedef float (*MathOp1)(float);
|
||||
typedef float (*MathOp2)(float, float);
|
||||
typedef float (*MathOp3)(float, float, float);
|
||||
|
||||
void ApplySomeMathHere(Variant& v, Variant& a, MathOp1 op);
|
||||
void ApplySomeMathHere(Variant& v, Variant& a, Variant& b, MathOp2 op);
|
||||
void ApplySomeMathHere(Variant& v, Variant& a, Variant& b, Variant& c, MathOp3 op);
|
||||
|
||||
void ApplySomeMathHere(uint16 typeId, Variant& v, Variant& a);
|
||||
void ApplySomeMathHere(uint16 typeId, Variant& v, Variant& a, Variant& b);
|
||||
|
||||
int32 CountComponents(VariantType::Types type);
|
||||
}
|
||||
1251
Source/Engine/Visject/ShaderGraph.cpp
Normal file
1251
Source/Engine/Visject/ShaderGraph.cpp
Normal file
File diff suppressed because it is too large
Load Diff
292
Source/Engine/Visject/ShaderGraph.h
Normal file
292
Source/Engine/Visject/ShaderGraph.h
Normal file
@@ -0,0 +1,292 @@
|
||||
// Copyright (c) 2012-2020 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/Utilities/TextWriter.h"
|
||||
#include "Engine/Graphics/Materials/MaterialParams.h"
|
||||
#include "Engine/Content/Utilities/AssetsContainer.h"
|
||||
#include "Engine/Animations/Curve.h"
|
||||
|
||||
#define SHADER_GRAPH_MAX_CALL_STACK 100
|
||||
|
||||
enum class MaterialSceneTextures;
|
||||
template<class BoxType>
|
||||
class ShaderGraphNode;
|
||||
|
||||
class ShaderGraphBox : public GraphBox
|
||||
{
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// The cached value.
|
||||
/// </summary>
|
||||
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:
|
||||
|
||||
ShaderGraphBox* FirstConnection() const
|
||||
{
|
||||
return (ShaderGraphBox*)Connections[0];
|
||||
}
|
||||
};
|
||||
|
||||
template<class BoxType = ShaderGraphBox>
|
||||
class ShaderGraphNode : public GraphNode<BoxType>
|
||||
{
|
||||
public:
|
||||
|
||||
struct CurveData
|
||||
{
|
||||
/// <summary>
|
||||
/// The curve index.
|
||||
/// </summary>
|
||||
int32 CurveIndex;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Custom cached data per node type. Compact to use as small amount of memory as possible.
|
||||
/// </summary>
|
||||
struct AdditionalData
|
||||
{
|
||||
union
|
||||
{
|
||||
CurveData Curve;
|
||||
};
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
ShaderGraphNode()
|
||||
: GraphNode<ShaderGraphBox>()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// The custom data (depends on node type). Used to cache data for faster usage at runtime.
|
||||
/// </summary>
|
||||
AdditionalData Data;
|
||||
};
|
||||
|
||||
class ShaderGraphParameter : public GraphParameter
|
||||
{
|
||||
public:
|
||||
|
||||
ShaderGraphParameter()
|
||||
: GraphParameter(SpawnParams(Guid::New(), TypeInitializer))
|
||||
{
|
||||
}
|
||||
|
||||
ShaderGraphParameter(const ShaderGraphParameter& other)
|
||||
: ShaderGraphParameter()
|
||||
{
|
||||
#if !BUILD_RELEASE
|
||||
CRASH; // Not used
|
||||
#endif
|
||||
}
|
||||
|
||||
ShaderGraphParameter& operator=(const ShaderGraphParameter& other)
|
||||
{
|
||||
#if !BUILD_RELEASE
|
||||
CRASH; // Not used
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template<class NodeType = ShaderGraphNode<>, class BoxType = ShaderGraphBox, class ParameterType = ShaderGraphParameter>
|
||||
class ShaderGraph : public Graph<NodeType, BoxType, ParameterType>
|
||||
{
|
||||
public:
|
||||
|
||||
typedef ShaderGraphValue Value;
|
||||
typedef Graph<NodeType, BoxType, ParameterType> Base;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// The float curves used by the graph.
|
||||
/// </summary>
|
||||
Array<BezierCurve<float>> FloatCurves;
|
||||
|
||||
/// <summary>
|
||||
/// The float curves used by the graph.
|
||||
/// </summary>
|
||||
Array<BezierCurve<Vector2>> Vector2Curves;
|
||||
|
||||
/// <summary>
|
||||
/// The float curves used by the graph.
|
||||
/// </summary>
|
||||
Array<BezierCurve<Vector3>> Vector3Curves;
|
||||
|
||||
/// <summary>
|
||||
/// The float curves used by the graph.
|
||||
/// </summary>
|
||||
Array<BezierCurve<Vector4>> Vector4Curves;
|
||||
|
||||
public:
|
||||
|
||||
// [Graph]
|
||||
bool onNodeLoaded(Node* 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, Vector2Curves, AsVector2())
|
||||
SETUP_CURVE(14, Vector3Curves, AsVector3())
|
||||
SETUP_CURVE(15, Vector4Curves, AsVector4())
|
||||
#undef SETUP_CURVE
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Base
|
||||
return Base::onNodeLoaded(n);
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Shaders generator from graphs.
|
||||
/// </summary>
|
||||
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<Node*, Box*, const StringView&> ErrorHandler;
|
||||
typedef Function<void(Box*, Node*, Value&)> ProcessBoxHandler;
|
||||
|
||||
protected:
|
||||
|
||||
int32 _localIndex;
|
||||
Dictionary<Node*, Graph*> _functions;
|
||||
Array<SerializedMaterialParam> _parameters;
|
||||
TextWriterUnicode _writer;
|
||||
HashSet<String> _includes;
|
||||
Array<ProcessBoxHandler, FixedAllocation<17>> _perGroupProcessCall;
|
||||
Array<Node*, FixedAllocation<SHADER_GRAPH_MAX_CALL_STACK>> _callStack;
|
||||
Array<Graph*, FixedAllocation<32>> _graphStack;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ShaderGenerator"/> class.
|
||||
/// </summary>
|
||||
ShaderGenerator();
|
||||
|
||||
/// <summary>
|
||||
/// Finalizes an instance of the <see cref="ShaderGenerator"/> class.
|
||||
/// </summary>
|
||||
~ShaderGenerator();
|
||||
|
||||
public:
|
||||
|
||||
ErrorHandler Error;
|
||||
|
||||
/// <summary>
|
||||
/// The assets container for graph generation. Holds references to used assets. Can be used to gather assets referenced by graph (eg. nested graph functions).
|
||||
/// </summary>
|
||||
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);
|
||||
|
||||
static String getLocalName(int32 index);
|
||||
static String getParamName(int32 index);
|
||||
};
|
||||
|
||||
#endif
|
||||
377
Source/Engine/Visject/ShaderGraphUtilities.cpp
Normal file
377
Source/Engine/Visject/ShaderGraphUtilities.cpp
Normal file
@@ -0,0 +1,377 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
#include "ShaderGraphUtilities.h"
|
||||
#include "ShaderGraphValue.h"
|
||||
#include "Engine/Core/Types/StringBuilder.h"
|
||||
#include "Engine/Content/Content.h"
|
||||
#include "Engine/Engine/GameplayGlobals.h"
|
||||
|
||||
void ShaderGraphUtilities::GenerateShaderConstantBuffer(TextWriterUnicode& writer, Array<SerializedMaterialParam>& parameters)
|
||||
{
|
||||
int32 constantsOffset = 0;
|
||||
int32 paddingIndex = 0;
|
||||
|
||||
for (int32 i = 0; i < parameters.Count(); i++)
|
||||
{
|
||||
auto& param = parameters[i];
|
||||
|
||||
const Char* format = nullptr;
|
||||
int32 size;
|
||||
int32 alignment;
|
||||
switch (param.Type)
|
||||
{
|
||||
case MaterialParameterType::Bool:
|
||||
size = 4;
|
||||
alignment = 4;
|
||||
format = TEXT("bool {0};");
|
||||
break;
|
||||
case MaterialParameterType::Integer:
|
||||
size = 4;
|
||||
alignment = 4;
|
||||
format = TEXT("int {0};");
|
||||
break;
|
||||
case MaterialParameterType::Float:
|
||||
size = 4;
|
||||
alignment = 4;
|
||||
format = TEXT("float {0};");
|
||||
break;
|
||||
case MaterialParameterType::Vector2:
|
||||
size = 8;
|
||||
alignment = 8;
|
||||
format = TEXT("float2 {0};");
|
||||
break;
|
||||
case MaterialParameterType::Vector3:
|
||||
size = 12;
|
||||
alignment = 16;
|
||||
format = TEXT("float3 {0};");
|
||||
break;
|
||||
case MaterialParameterType::Vector4:
|
||||
case MaterialParameterType::ChannelMask:
|
||||
case MaterialParameterType::Color:
|
||||
size = 16;
|
||||
alignment = 16;
|
||||
format = TEXT("float4 {0};");
|
||||
break;
|
||||
case MaterialParameterType::Matrix:
|
||||
size = 16 * 4;
|
||||
alignment = 16;
|
||||
format = TEXT("float4x4 {0};");
|
||||
break;
|
||||
case MaterialParameterType::GameplayGlobal:
|
||||
{
|
||||
auto asset = Content::LoadAsync<GameplayGlobals>(param.AsGuid);
|
||||
if (!asset || asset->WaitForLoaded())
|
||||
break;
|
||||
GameplayGlobals::Variable variable;
|
||||
if (!asset->Variables.TryGet(param.Name, variable))
|
||||
break;
|
||||
switch (variable.DefaultValue.Type.Type)
|
||||
{
|
||||
case VariantType::Bool:
|
||||
size = 4;
|
||||
alignment = 4;
|
||||
format = TEXT("bool {0};");
|
||||
break;
|
||||
case VariantType::Int:
|
||||
size = 4;
|
||||
alignment = 4;
|
||||
format = TEXT("int {0};");
|
||||
break;
|
||||
case VariantType::Uint:
|
||||
size = 4;
|
||||
alignment = 4;
|
||||
format = TEXT("uint {0};");
|
||||
break;
|
||||
case VariantType::Float:
|
||||
size = 4;
|
||||
alignment = 4;
|
||||
format = TEXT("float {0};");
|
||||
break;
|
||||
case VariantType::Vector2:
|
||||
size = 8;
|
||||
alignment = 8;
|
||||
format = TEXT("float2 {0};");
|
||||
break;
|
||||
case VariantType::Vector3:
|
||||
size = 12;
|
||||
alignment = 16;
|
||||
format = TEXT("float3 {0};");
|
||||
break;
|
||||
case VariantType::Vector4:
|
||||
case VariantType::Color:
|
||||
size = 16;
|
||||
alignment = 16;
|
||||
format = TEXT("float4 {0};");
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: ;
|
||||
}
|
||||
if (format)
|
||||
{
|
||||
int32 padding = Math::Abs((alignment - (constantsOffset % 16))) % alignment;
|
||||
if (padding != 0)
|
||||
{
|
||||
constantsOffset += padding;
|
||||
padding /= 4;
|
||||
while (padding-- > 0)
|
||||
{
|
||||
writer.WriteLine(TEXT("uint PADDING_{0};"), paddingIndex++);
|
||||
}
|
||||
}
|
||||
|
||||
param.RegisterIndex = 0;
|
||||
param.Offset = constantsOffset;
|
||||
writer.WriteLine(format, param.ShaderName);
|
||||
constantsOffset += size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Char* ShaderGraphUtilities::GenerateShaderResources(TextWriterUnicode& writer, Array<SerializedMaterialParam>& parameters, int32 startRegister)
|
||||
{
|
||||
int32 registerIndex = startRegister;
|
||||
for (int32 i = 0; i < parameters.Count(); i++)
|
||||
{
|
||||
auto& param = parameters[i];
|
||||
|
||||
const Char* format;
|
||||
switch (param.Type)
|
||||
{
|
||||
case MaterialParameterType::NormalMap:
|
||||
case MaterialParameterType::GPUTexture:
|
||||
case MaterialParameterType::SceneTexture:
|
||||
case MaterialParameterType::Texture:
|
||||
format = TEXT("Texture2D {0} : register(t{1});");
|
||||
break;
|
||||
case MaterialParameterType::GPUTextureCube:
|
||||
case MaterialParameterType::CubeTexture:
|
||||
format = TEXT("TextureCube {0} : register(t{1});");
|
||||
break;
|
||||
case MaterialParameterType::GPUTextureArray:
|
||||
format = TEXT("Texture2DArray {0} : register(t{1});");
|
||||
break;
|
||||
case MaterialParameterType::GPUTextureVolume:
|
||||
format = TEXT("Texture3D {0} : register(t{1});");
|
||||
break;
|
||||
default:
|
||||
format = nullptr;
|
||||
break;
|
||||
}
|
||||
|
||||
if (format)
|
||||
{
|
||||
param.Offset = 0;
|
||||
param.RegisterIndex = registerIndex;
|
||||
writer.WriteLine(format, param.ShaderName, static_cast<int32>(registerIndex));
|
||||
registerIndex++;
|
||||
|
||||
// Validate Shader Resource count limit
|
||||
if (param.RegisterIndex >= GPU_MAX_SR_BINDED)
|
||||
{
|
||||
return TEXT("Too many textures used. The maximum supported amount is " MACRO_TO_STR(GPU_MAX_SR_BINDED) " (including lightmaps and utility textures for lighting).");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (startRegister != registerIndex)
|
||||
writer.WriteLine();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const Char* GetTypename()
|
||||
{
|
||||
return TEXT("");
|
||||
}
|
||||
|
||||
template<>
|
||||
const Char* GetTypename<float>()
|
||||
{
|
||||
return TEXT("float");
|
||||
}
|
||||
|
||||
template<>
|
||||
const Char* GetTypename<Vector2>()
|
||||
{
|
||||
return TEXT("float2");
|
||||
}
|
||||
|
||||
template<>
|
||||
const Char* GetTypename<Vector3>()
|
||||
{
|
||||
return TEXT("float3");
|
||||
}
|
||||
|
||||
template<>
|
||||
const Char* GetTypename<Vector4>()
|
||||
{
|
||||
return TEXT("float4");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void ShaderGraphUtilities::SampleCurve(TextWriterUnicode& writer, const BezierCurve<T>& curve, const String& time, const String& value)
|
||||
{
|
||||
const auto& keyframes = curve.GetKeyframes();
|
||||
|
||||
if (keyframes.Count() == 0)
|
||||
{
|
||||
writer.Write(
|
||||
TEXT(
|
||||
" {{\n"
|
||||
" // Curve ({1})\n"
|
||||
" {0} = 0;\n"
|
||||
" }}\n"
|
||||
),
|
||||
value, // {0}
|
||||
GetTypename<T>() // {1}
|
||||
);
|
||||
}
|
||||
else if (keyframes.Count() == 1)
|
||||
{
|
||||
writer.Write(
|
||||
TEXT(
|
||||
" {{\n"
|
||||
" // Curve ({1})\n"
|
||||
" {0} = {2};\n"
|
||||
" }}\n"
|
||||
),
|
||||
value, // {0}
|
||||
GetTypename<T>(), // {1}
|
||||
ShaderGraphValue(keyframes[0].Value).Value // {2}
|
||||
);
|
||||
}
|
||||
else if (keyframes.Count() == 2)
|
||||
{
|
||||
writer.Write(
|
||||
TEXT(
|
||||
" {{\n"
|
||||
" // Curve ({4})\n"
|
||||
" const float leftTime = {3};\n"
|
||||
" const float rightTime = {5};\n"
|
||||
" const float lengthTime = rightTime - leftTime;\n"
|
||||
" float time = clamp({0}, leftTime, rightTime);\n"
|
||||
" float alpha = lengthTime < 0.0000001 ? 0.0f : (time - leftTime) / lengthTime;\n"
|
||||
|
||||
" const {4} leftValue = {6};\n"
|
||||
" const {4} rightValue = {7};\n"
|
||||
" const float oneThird = 1.0f / 3.0f;\n"
|
||||
" {4} leftTangent = leftValue + {8} * (lengthTime * oneThird);\n"
|
||||
" {4} rightTangent = rightValue + {1} * (lengthTime * oneThird);\n"
|
||||
|
||||
" {4} p01 = lerp(leftValue, leftTangent, alpha);\n"
|
||||
" {4} p12 = lerp(leftTangent, rightTangent, alpha);\n"
|
||||
" {4} p23 = lerp(rightTangent, rightValue, alpha);\n"
|
||||
" {4} p012 = lerp(p01, p12, alpha);\n"
|
||||
" {4} p123 = lerp(p12, p23, alpha);\n"
|
||||
" {2} = lerp(p012, p123, alpha);\n"
|
||||
" }}\n"
|
||||
),
|
||||
time, // {0}
|
||||
ShaderGraphValue(keyframes[1].TangentIn).Value, // {1}
|
||||
value, // {2}
|
||||
StringUtils::ToString(keyframes[0].Time), // {3}
|
||||
GetTypename<T>(), // {4}
|
||||
StringUtils::ToString(keyframes[1].Time), // {5}
|
||||
ShaderGraphValue(keyframes[0].Value).Value, // {6}
|
||||
ShaderGraphValue(keyframes[1].Value).Value, // {7}
|
||||
ShaderGraphValue(keyframes[0].TangentOut).Value // {8}
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
StringBuilder keyframesTime, keyframesValue, keyframesTangentIn, keyframesTangentOut;
|
||||
for (int32 i = 0; i < keyframes.Count(); i++)
|
||||
{
|
||||
const auto& keyframe = keyframes[i];
|
||||
if (i != 0)
|
||||
{
|
||||
keyframesTime.Append(',');
|
||||
keyframesValue.Append(',');
|
||||
keyframesTangentIn.Append(',');
|
||||
keyframesTangentOut.Append(',');
|
||||
}
|
||||
keyframesTime.Append(StringUtils::ToString(keyframe.Time));
|
||||
keyframesValue.Append(ShaderGraphValue(keyframe.Value).Value);
|
||||
keyframesTangentIn.Append(ShaderGraphValue(keyframe.TangentIn).Value);
|
||||
keyframesTangentOut.Append(ShaderGraphValue(keyframe.TangentOut).Value);
|
||||
}
|
||||
keyframesTime.Append('\0');
|
||||
keyframesValue.Append('\0');
|
||||
keyframesTangentIn.Append('\0');
|
||||
keyframesTangentOut.Append('\0');
|
||||
|
||||
writer.Write(
|
||||
TEXT(
|
||||
" {{\n"
|
||||
" // Curve ({4})\n"
|
||||
" int count = {0};\n"
|
||||
" float time = clamp({1}, 0.0, {2});\n"
|
||||
|
||||
" static float keyframesTime[] = {{ {5} }};\n"
|
||||
" static {4} keyframesValue[] = {{ {6} }};\n"
|
||||
" static {4} keyframesTangentIn[] = {{ {7} }};\n"
|
||||
" static {4} keyframesTangentOut[] = {{ {8} }};\n"
|
||||
|
||||
" int start = 0;\n"
|
||||
" int searchLength = count;\n"
|
||||
" while (searchLength > 0)\n"
|
||||
" {{\n"
|
||||
" int halfPos = searchLength >> 1;\n"
|
||||
" int midPos = start + halfPos;\n"
|
||||
" if (time < keyframesTime[midPos])\n"
|
||||
" {{\n"
|
||||
" searchLength = halfPos;\n"
|
||||
" }}\n"
|
||||
" else\n"
|
||||
" {{\n"
|
||||
" start = midPos + 1;\n"
|
||||
" searchLength -= halfPos + 1;\n"
|
||||
" }}\n"
|
||||
" }}\n"
|
||||
" int leftKey = max(0, start - 1);\n"
|
||||
" int rightKey = min(start, count - 1);\n"
|
||||
|
||||
" const float leftTime = keyframesTime[leftKey];\n"
|
||||
" const float rightTime = keyframesTime[rightKey];\n"
|
||||
" const float lengthTime = rightTime - leftTime;\n"
|
||||
" float alpha = lengthTime < 0.0000001 ? 0.0f : (time - leftTime) / lengthTime;\n"
|
||||
|
||||
" const {4} leftValue = keyframesValue[leftKey];\n"
|
||||
" const {4} rightValue = keyframesValue[rightKey];\n"
|
||||
" const float oneThird = 1.0f / 3.0f;\n"
|
||||
" {4} leftTangent = leftValue + keyframesTangentOut[leftKey] * (lengthTime * oneThird);\n"
|
||||
" {4} rightTangent = rightValue + keyframesTangentIn[rightKey] * (lengthTime * oneThird);\n"
|
||||
|
||||
" {4} p01 = lerp(leftValue, leftTangent, alpha);\n"
|
||||
" {4} p12 = lerp(leftTangent, rightTangent, alpha);\n"
|
||||
" {4} p23 = lerp(rightTangent, rightValue, alpha);\n"
|
||||
" {4} p012 = lerp(p01, p12, alpha);\n"
|
||||
" {4} p123 = lerp(p12, p23, alpha);\n"
|
||||
" {3} = lerp(p012, p123, alpha);\n"
|
||||
" }}\n"
|
||||
),
|
||||
keyframes.Count(), // {0}
|
||||
time, // {1}
|
||||
curve.GetLength(), // {2}
|
||||
value, // {3}
|
||||
GetTypename<T>(), // {4}
|
||||
*keyframesTime, // {5}
|
||||
*keyframesValue, // {6}
|
||||
*keyframesTangentIn, // {7}
|
||||
*keyframesTangentOut // {8}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
template void ShaderGraphUtilities::SampleCurve(TextWriterUnicode& writer, const BezierCurve<float>& curve, const String& time, const String& value);
|
||||
template void ShaderGraphUtilities::SampleCurve(TextWriterUnicode& writer, const BezierCurve<Vector2>& curve, const String& time, const String& value);
|
||||
template void ShaderGraphUtilities::SampleCurve(TextWriterUnicode& writer, const BezierCurve<Vector3>& curve, const String& time, const String& value);
|
||||
template void ShaderGraphUtilities::SampleCurve(TextWriterUnicode& writer, const BezierCurve<Vector4>& curve, const String& time, const String& value);
|
||||
|
||||
#endif
|
||||
19
Source/Engine/Visject/ShaderGraphUtilities.h
Normal file
19
Source/Engine/Visject/ShaderGraphUtilities.h
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
#include "Engine/Graphics/Materials/MaterialParams.h"
|
||||
#include "Engine/Utilities/TextWriter.h"
|
||||
#include "Engine/Animations/Curve.h"
|
||||
|
||||
namespace ShaderGraphUtilities
|
||||
{
|
||||
void GenerateShaderConstantBuffer(TextWriterUnicode& writer, Array<SerializedMaterialParam>& parameters);
|
||||
const Char* GenerateShaderResources(TextWriterUnicode& writer, Array<SerializedMaterialParam>& parameters, int32 startRegister);
|
||||
template<typename T>
|
||||
void SampleCurve(TextWriterUnicode& writer, const BezierCurve<T>& curve, const String& time, const String& value);
|
||||
}
|
||||
|
||||
#endif
|
||||
328
Source/Engine/Visject/ShaderGraphValue.cpp
Normal file
328
Source/Engine/Visject/ShaderGraphValue.cpp
Normal file
@@ -0,0 +1,328 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "ShaderGraphValue.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Core/Math/Vector2.h"
|
||||
#include "Engine/Core/Math/Vector3.h"
|
||||
#include "Engine/Core/Math/Vector4.h"
|
||||
#include "Engine/Core/Types/StringView.h"
|
||||
|
||||
const Char* ShaderGraphValue::_subs[] =
|
||||
{
|
||||
TEXT(".x"),
|
||||
TEXT(".y"),
|
||||
TEXT(".z"),
|
||||
TEXT(".w")
|
||||
};
|
||||
|
||||
const ShaderGraphValue ShaderGraphValue::Zero(VariantType::Types::Float, TEXT("0.0"));
|
||||
const ShaderGraphValue ShaderGraphValue::Half(VariantType::Types::Float, TEXT("0.5"));
|
||||
const ShaderGraphValue ShaderGraphValue::One(VariantType::Types::Float, TEXT("1.0"));
|
||||
const ShaderGraphValue ShaderGraphValue::True(VariantType::Types::Bool, TEXT("true"));
|
||||
const ShaderGraphValue ShaderGraphValue::False(VariantType::Types::Bool, TEXT("false"));
|
||||
|
||||
ShaderGraphValue::ShaderGraphValue(const Variant& v)
|
||||
{
|
||||
switch (v.Type.Type)
|
||||
{
|
||||
case VariantType::Bool:
|
||||
Type = VariantType::Types::Bool;
|
||||
Value = v.AsBool ? TEXT('1') : TEXT('0');
|
||||
break;
|
||||
case VariantType::Int:
|
||||
Type = VariantType::Types::Int;
|
||||
Value = StringUtils::ToString(v.AsInt);
|
||||
break;
|
||||
case VariantType::Uint:
|
||||
Type = VariantType::Types::Uint;
|
||||
Value = StringUtils::ToString(v.AsUint);
|
||||
break;
|
||||
case VariantType::Float:
|
||||
Type = VariantType::Types::Float;
|
||||
Value = String::Format(TEXT("{0}"), v.AsFloat);
|
||||
break;
|
||||
case VariantType::Vector2:
|
||||
Type = VariantType::Types::Vector2;
|
||||
Value = String::Format(TEXT("float2({0}, {1})"), (*(Vector2*)v.AsData).X, (*(Vector2*)v.AsData).Y);
|
||||
break;
|
||||
case VariantType::Vector3:
|
||||
Type = VariantType::Types::Vector3;
|
||||
Value = String::Format(TEXT("float3({0}, {1}, {2})"), (*(Vector3*)v.AsData).X, (*(Vector3*)v.AsData).Y, (*(Vector3*)v.AsData).Z);
|
||||
break;
|
||||
case VariantType::Vector4:
|
||||
case VariantType::Color:
|
||||
Type = VariantType::Types::Vector4;
|
||||
Value = String::Format(TEXT("float4({0}, {1}, {2}, {3})"), (*(Vector4*)v.AsData).X, (*(Vector4*)v.AsData).Y, (*(Vector4*)v.AsData).Z, (*(Vector4*)v.AsData).W);
|
||||
break;
|
||||
case VariantType::String:
|
||||
Type = VariantType::Types::String;
|
||||
Value = (StringView)v;
|
||||
break;
|
||||
default:
|
||||
Type = VariantType::Types::Null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool ShaderGraphValue::IsZero() const
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case VariantType::Types::Bool:
|
||||
case VariantType::Types::Int:
|
||||
case VariantType::Types::Uint:
|
||||
case VariantType::Types::Float:
|
||||
return Value == TEXT("0") || Value == TEXT("0.0");
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ShaderGraphValue::IsOne() const
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case VariantType::Types::Bool:
|
||||
case VariantType::Types::Int:
|
||||
case VariantType::Types::Uint:
|
||||
case VariantType::Types::Float:
|
||||
return Value == TEXT("1") || Value == TEXT("1.0");
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ShaderGraphValue ShaderGraphValue::InitForZero(VariantType::Types type)
|
||||
{
|
||||
const Char* v;
|
||||
switch (type)
|
||||
{
|
||||
case VariantType::Types::Float:
|
||||
v = TEXT("0.0");
|
||||
break;
|
||||
case VariantType::Types::Bool:
|
||||
case VariantType::Types::Int:
|
||||
case VariantType::Types::Uint:
|
||||
v = TEXT("0");
|
||||
break;
|
||||
case VariantType::Types::Vector2:
|
||||
v = TEXT("float2(0, 0)");
|
||||
break;
|
||||
case VariantType::Types::Vector3:
|
||||
v = TEXT("float3(0, 0, 0)");
|
||||
break;
|
||||
case VariantType::Types::Vector4:
|
||||
case VariantType::Types::Color:
|
||||
v = TEXT("float4(0, 0, 0, 0)");
|
||||
break;
|
||||
case VariantType::Types::Void:
|
||||
v = TEXT("((Material)0)");
|
||||
break;
|
||||
default:
|
||||
CRASH;
|
||||
v = nullptr;
|
||||
}
|
||||
return ShaderGraphValue(type, String(v));
|
||||
}
|
||||
|
||||
ShaderGraphValue ShaderGraphValue::InitForHalf(VariantType::Types type)
|
||||
{
|
||||
const Char* v;
|
||||
switch (type)
|
||||
{
|
||||
case VariantType::Types::Float:
|
||||
v = TEXT("0.5");
|
||||
break;
|
||||
case VariantType::Types::Bool:
|
||||
case VariantType::Types::Int:
|
||||
case VariantType::Types::Uint:
|
||||
v = TEXT("0");
|
||||
break;
|
||||
case VariantType::Types::Vector2:
|
||||
v = TEXT("float2(0.5, 0.5)");
|
||||
break;
|
||||
case VariantType::Types::Vector3:
|
||||
v = TEXT("float3(0.5, 0.5, 0.5)");
|
||||
break;
|
||||
case VariantType::Types::Vector4:
|
||||
case VariantType::Types::Color:
|
||||
v = TEXT("float4(0.5, 0.5, 0.5, 0.5)");
|
||||
break;
|
||||
default:
|
||||
CRASH;
|
||||
v = nullptr;
|
||||
}
|
||||
return ShaderGraphValue(type, String(v));
|
||||
}
|
||||
|
||||
ShaderGraphValue ShaderGraphValue::InitForOne(VariantType::Types type)
|
||||
{
|
||||
const Char* v;
|
||||
switch (type)
|
||||
{
|
||||
case VariantType::Types::Float:
|
||||
v = TEXT("1.0");
|
||||
break;
|
||||
case VariantType::Types::Bool:
|
||||
case VariantType::Types::Int:
|
||||
case VariantType::Types::Uint:
|
||||
v = TEXT("1");
|
||||
break;
|
||||
case VariantType::Types::Vector2:
|
||||
v = TEXT("float2(1, 1)");
|
||||
break;
|
||||
case VariantType::Types::Vector3:
|
||||
v = TEXT("float3(1, 1, 1)");
|
||||
break;
|
||||
case VariantType::Types::Vector4:
|
||||
case VariantType::Types::Color:
|
||||
v = TEXT("float4(1, 1, 1, 1)");
|
||||
break;
|
||||
default:
|
||||
CRASH;
|
||||
v = nullptr;
|
||||
}
|
||||
return ShaderGraphValue(type, String(v));
|
||||
}
|
||||
|
||||
ShaderGraphValue ShaderGraphValue::Cast(const ShaderGraphValue& v, VariantType::Types to)
|
||||
{
|
||||
// If they are the same types or input value is empty, then just return value
|
||||
if (v.Type == to || v.Value.IsEmpty())
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
// Select format string
|
||||
const Char* format = nullptr;
|
||||
switch (to)
|
||||
{
|
||||
case VariantType::Types::Bool:
|
||||
switch (v.Type)
|
||||
{
|
||||
case VariantType::Types::Int:
|
||||
case VariantType::Types::Uint:
|
||||
case VariantType::Types::Float:
|
||||
format = TEXT("((bool){0})");
|
||||
break;
|
||||
case VariantType::Types::Vector2:
|
||||
case VariantType::Types::Vector3:
|
||||
case VariantType::Types::Vector4:
|
||||
case VariantType::Types::Color:
|
||||
format = TEXT("((bool){0}.x)");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case VariantType::Types::Int:
|
||||
switch (v.Type)
|
||||
{
|
||||
case VariantType::Types::Bool:
|
||||
case VariantType::Types::Uint:
|
||||
case VariantType::Types::Float:
|
||||
format = TEXT("((int){0})");
|
||||
break;
|
||||
case VariantType::Types::Vector2:
|
||||
case VariantType::Types::Vector3:
|
||||
case VariantType::Types::Vector4:
|
||||
case VariantType::Types::Color:
|
||||
format = TEXT("((int){0}.x)");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case VariantType::Types::Uint:
|
||||
switch (v.Type)
|
||||
{
|
||||
case VariantType::Types::Bool:
|
||||
case VariantType::Types::Int:
|
||||
case VariantType::Types::Float:
|
||||
format = TEXT("((uint){0})");
|
||||
break;
|
||||
case VariantType::Types::Vector2:
|
||||
case VariantType::Types::Vector3:
|
||||
case VariantType::Types::Vector4:
|
||||
case VariantType::Types::Color:
|
||||
format = TEXT("((uint){0}.x)");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case VariantType::Types::Float:
|
||||
switch (v.Type)
|
||||
{
|
||||
case VariantType::Types::Bool:
|
||||
case VariantType::Types::Int:
|
||||
case VariantType::Types::Uint:
|
||||
format = TEXT("((float){0})");
|
||||
break;
|
||||
case VariantType::Types::Vector2:
|
||||
case VariantType::Types::Vector3:
|
||||
case VariantType::Types::Vector4:
|
||||
case VariantType::Types::Color:
|
||||
format = TEXT("((float){0}.x)");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case VariantType::Types::Vector2:
|
||||
switch (v.Type)
|
||||
{
|
||||
case VariantType::Types::Bool:
|
||||
case VariantType::Types::Int:
|
||||
case VariantType::Types::Uint:
|
||||
case VariantType::Types::Float:
|
||||
format = TEXT("float2({0}, {0})");
|
||||
break;
|
||||
case VariantType::Types::Vector3:
|
||||
case VariantType::Types::Vector4:
|
||||
case VariantType::Types::Color:
|
||||
format = TEXT("{0}.xy");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case VariantType::Types::Vector3:
|
||||
switch (v.Type)
|
||||
{
|
||||
case VariantType::Types::Bool:
|
||||
case VariantType::Types::Int:
|
||||
case VariantType::Types::Uint:
|
||||
case VariantType::Types::Float:
|
||||
format = TEXT("float3({0}, {0}, {0})");
|
||||
break;
|
||||
case VariantType::Types::Vector2:
|
||||
format = TEXT("float3({0}.xy, 0)");
|
||||
break;
|
||||
case VariantType::Types::Vector4:
|
||||
case VariantType::Types::Color:
|
||||
format = TEXT("{0}.xyz");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case VariantType::Types::Vector4:
|
||||
case VariantType::Types::Color:
|
||||
switch (v.Type)
|
||||
{
|
||||
case VariantType::Types::Bool:
|
||||
case VariantType::Types::Int:
|
||||
case VariantType::Types::Uint:
|
||||
case VariantType::Types::Float:
|
||||
format = TEXT("float4({0}, {0}, {0}, {0})");
|
||||
break;
|
||||
case VariantType::Types::Vector2:
|
||||
format = TEXT("float4({0}.xy, 0, 0)");
|
||||
break;
|
||||
case VariantType::Types::Vector3:
|
||||
format = TEXT("float4({0}.xyz, 0)");
|
||||
break;
|
||||
case VariantType::Types::Color:
|
||||
case VariantType::Types::Vector4:
|
||||
format = TEXT("{0}");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (format == nullptr)
|
||||
{
|
||||
LOG(Error, "Failed to cast shader graph value of type {0} to {1}", VariantType(v.Type), VariantType(to));
|
||||
return Zero;
|
||||
}
|
||||
|
||||
return ShaderGraphValue(to, String::Format(format, v.Value));
|
||||
}
|
||||
420
Source/Engine/Visject/ShaderGraphValue.h
Normal file
420
Source/Engine/Visject/ShaderGraphValue.h
Normal file
@@ -0,0 +1,420 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Core/Types/String.h"
|
||||
#include "Engine/Core/Object.h"
|
||||
#include "GraphNode.h"
|
||||
|
||||
/// <summary>
|
||||
/// Shader source generator value container. Caches the value type and the value variable name (shader local, global parameter or constant value). Supports value type casting and component swizzle.
|
||||
/// </summary>
|
||||
struct ShaderGraphValue : Object
|
||||
{
|
||||
private:
|
||||
|
||||
static const Char* _subs[];
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// The value type.
|
||||
/// </summary>
|
||||
VariantType::Types Type;
|
||||
|
||||
/// <summary>
|
||||
/// The shader value.
|
||||
/// </summary>
|
||||
String Value;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Zero value (as float).
|
||||
/// </summary>
|
||||
static const ShaderGraphValue Zero;
|
||||
|
||||
/// <summary>
|
||||
/// Half value (as float).
|
||||
/// </summary>
|
||||
static const ShaderGraphValue Half;
|
||||
|
||||
/// <summary>
|
||||
/// One value (as float).
|
||||
/// </summary>
|
||||
static const ShaderGraphValue One;
|
||||
|
||||
/// <summary>
|
||||
/// True value (as bool).
|
||||
/// </summary>
|
||||
static const ShaderGraphValue True;
|
||||
|
||||
/// <summary>
|
||||
/// False value (as bool).
|
||||
/// </summary>
|
||||
static const ShaderGraphValue False;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ShaderGraphValue"/> struct.
|
||||
/// </summary>
|
||||
ShaderGraphValue()
|
||||
: Type(VariantType::Types::Null)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ShaderGraphValue"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
ShaderGraphValue(VariantType::Types type, const Char* value)
|
||||
: Type(type)
|
||||
, Value(value)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ShaderGraphValue"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
ShaderGraphValue(VariantType::Types type, const String& value)
|
||||
: Type(type)
|
||||
, Value(value)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ShaderGraphValue"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
explicit ShaderGraphValue(const bool value)
|
||||
: Type(VariantType::Types::Bool)
|
||||
, Value(value ? TEXT("true") : TEXT("false"))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ShaderGraphValue"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
explicit ShaderGraphValue(const float value)
|
||||
: Type(VariantType::Types::Float)
|
||||
, Value(StringUtils::ToString(value))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ShaderGraphValue"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
explicit ShaderGraphValue(const int32 value)
|
||||
: Type(VariantType::Types::Int)
|
||||
, Value(StringUtils::ToString(value))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ShaderGraphValue"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="v">The value.</param>
|
||||
explicit ShaderGraphValue(const Variant& v);
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if value is valid.
|
||||
/// </summary>
|
||||
/// <returns>True if is valid, otherwise false.</returns>
|
||||
bool IsValid() const
|
||||
{
|
||||
return Type != VariantType::Types::Null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if value is invalid.
|
||||
/// </summary>
|
||||
/// <returns>True if is invalid, otherwise false.</returns>
|
||||
bool IsInvalid() const
|
||||
{
|
||||
return Type == VariantType::Types::Null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if value contains static part with zero.
|
||||
/// </summary>
|
||||
/// <returns>True if contains zero number.</returns>
|
||||
bool IsZero() const;
|
||||
|
||||
/// <summary>
|
||||
/// Checks if value contains static part with one.
|
||||
/// </summary>
|
||||
/// <returns>True if contains one number.</returns>
|
||||
bool IsOne() const;
|
||||
|
||||
/// <summary>
|
||||
/// Clears this instance.
|
||||
/// </summary>
|
||||
void Clear()
|
||||
{
|
||||
Type = VariantType::Types::Null;
|
||||
Value.Clear();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Formats thw value.
|
||||
/// </summary>
|
||||
/// <param name="format">The format text.</param>
|
||||
/// <param name="v1">The value.</param>
|
||||
/// <returns>The formatted value.</returns>
|
||||
static String Format(const Char* format, const ShaderGraphValue& v1)
|
||||
{
|
||||
return String::Format(format, v1.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats thw value.
|
||||
/// </summary>
|
||||
/// <param name="format">The format text.</param>
|
||||
/// <param name="v1">The first value.</param>
|
||||
/// <param name="v2">The second value.</param>
|
||||
/// <returns>The formatted value.</returns>
|
||||
static String Format(const Char* format, const ShaderGraphValue& v1, const ShaderGraphValue& v2)
|
||||
{
|
||||
return String::Format(format, v1.Value, v2.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats thw value.
|
||||
/// </summary>
|
||||
/// <param name="format">The format text.</param>
|
||||
/// <param name="v1">The first value.</param>
|
||||
/// <param name="v2">The second value.</param>
|
||||
/// <param name="v3">The third value.</param>
|
||||
/// <returns>The formatted value.</returns>
|
||||
static String Format(const Char* format, const ShaderGraphValue& v1, const ShaderGraphValue& v2, const ShaderGraphValue& v3)
|
||||
{
|
||||
return String::Format(format, v1.Value, v2.Value, v3.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats thw value.
|
||||
/// </summary>
|
||||
/// <param name="format">The format text.</param>
|
||||
/// <param name="v1">The first value.</param>
|
||||
/// <param name="v2">The second value.</param>
|
||||
/// <param name="v3">The third value.</param>
|
||||
/// <param name="v4">The fourth value.</param>
|
||||
/// <returns>The formatted value.</returns>
|
||||
static String Format(const Char* format, const ShaderGraphValue& v1, const ShaderGraphValue& v2, const ShaderGraphValue& v3, const ShaderGraphValue& v4)
|
||||
{
|
||||
return String::Format(format, v1.Value, v2.Value, v3.Value, v4.Value);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the shader variable for given connection type Zero.
|
||||
/// </summary>
|
||||
/// <param name="type">The graph connection type.</param>
|
||||
/// <returns>Initial value for given type.</returns>
|
||||
static ShaderGraphValue InitForZero(VariantType::Types type);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the shader variable for given connection type Half.
|
||||
/// </summary>
|
||||
/// <param name="type">The graph connection type.</param>
|
||||
/// <returns>Initial value for given type.</returns>
|
||||
static ShaderGraphValue InitForHalf(VariantType::Types type);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the shader variable for given connection type One.
|
||||
/// </summary>
|
||||
/// <param name="type">The graph connection type.</param>
|
||||
/// <returns>Initial value for given type.</returns>
|
||||
static ShaderGraphValue InitForOne(VariantType::Types type);
|
||||
|
||||
/// <summary>
|
||||
/// Create float2 from X and Y values.
|
||||
/// </summary>
|
||||
/// <param name="x">The x.</param>
|
||||
/// <param name="y">The y.</param>
|
||||
/// <returns>float2</returns>
|
||||
static ShaderGraphValue Float2(const ShaderGraphValue& x, const ShaderGraphValue& y)
|
||||
{
|
||||
return ShaderGraphValue(
|
||||
VariantType::Types::Vector2,
|
||||
String::Format(TEXT("float2({0}, {1})"),
|
||||
Cast(x, VariantType::Types::Float).Value,
|
||||
Cast(y, VariantType::Types::Float).Value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create float3 from X, Y and Z values.
|
||||
/// </summary>
|
||||
/// <param name="x">The x.</param>
|
||||
/// <param name="y">The y.</param>
|
||||
/// <param name="z">The z.</param>
|
||||
/// <returns>float3</returns>
|
||||
static ShaderGraphValue Float3(const ShaderGraphValue& x, const ShaderGraphValue& y, const ShaderGraphValue& z)
|
||||
{
|
||||
return ShaderGraphValue(
|
||||
VariantType::Types::Vector3,
|
||||
String::Format(TEXT("float3({0}, {1}, {2})"),
|
||||
Cast(x, VariantType::Types::Float).Value,
|
||||
Cast(y, VariantType::Types::Float).Value,
|
||||
Cast(z, VariantType::Types::Float).Value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create float4 from X, Y, Z and W values.
|
||||
/// </summary>
|
||||
/// <param name="x">The X.</param>
|
||||
/// <param name="y">The Y.</param>
|
||||
/// <param name="z">The Z.</param>
|
||||
/// <param name="w">The W.</param>
|
||||
/// <returns>float4</returns>
|
||||
static ShaderGraphValue Float4(const ShaderGraphValue& x, const ShaderGraphValue& y, const ShaderGraphValue& z, const ShaderGraphValue& w)
|
||||
{
|
||||
return ShaderGraphValue(
|
||||
VariantType::Types::Vector4,
|
||||
String::Format(TEXT("float4({0}, {1}, {2}, {3})"),
|
||||
Cast(x, VariantType::Types::Float).Value,
|
||||
Cast(y, VariantType::Types::Float).Value,
|
||||
Cast(z, VariantType::Types::Float).Value,
|
||||
Cast(w, VariantType::Types::Float).Value));
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Gets the X component of the value. Valid only for single or vector types.
|
||||
/// </summary>
|
||||
/// <returns>The X component.</returns>
|
||||
ShaderGraphValue GetX() const
|
||||
{
|
||||
return ShaderGraphValue(VariantType::Types::Float, Value + _subs[0]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Y component of the value. Valid only for vector types.
|
||||
/// </summary>
|
||||
/// <returns>The Y component.</returns>
|
||||
ShaderGraphValue GetY() const
|
||||
{
|
||||
return ShaderGraphValue(VariantType::Types::Float, Value + _subs[1]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Z component of the value. Valid only for vector types.
|
||||
/// </summary>
|
||||
/// <returns>The Z component.</returns>
|
||||
ShaderGraphValue GetZ() const
|
||||
{
|
||||
return ShaderGraphValue(VariantType::Types::Float, Value + _subs[2]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the W component of the value. Valid only for vector types.
|
||||
/// </summary>
|
||||
/// <returns>The W component.</returns>
|
||||
ShaderGraphValue GetW() const
|
||||
{
|
||||
return ShaderGraphValue(VariantType::Types::Float, Value + _subs[3]);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Casts the value to the bool type.
|
||||
/// </summary>
|
||||
/// <returns>Bool</returns>
|
||||
ShaderGraphValue AsBool() const
|
||||
{
|
||||
return Cast(*this, VariantType::Types::Bool);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Casts the value to the integer type.
|
||||
/// </summary>
|
||||
/// <returns>Integer</returns>
|
||||
ShaderGraphValue AsInt() const
|
||||
{
|
||||
return Cast(*this, VariantType::Types::Int);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Casts the value to the unsigned integer type.
|
||||
/// </summary>
|
||||
/// <returns>UnsignedInteger</returns>
|
||||
ShaderGraphValue AsUint() const
|
||||
{
|
||||
return Cast(*this, VariantType::Types::Uint);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Casts the value to the float type.
|
||||
/// </summary>
|
||||
/// <returns>Float</returns>
|
||||
ShaderGraphValue AsFloat() const
|
||||
{
|
||||
return Cast(*this, VariantType::Types::Float);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Casts the value to the Vector2 type.
|
||||
/// </summary>
|
||||
/// <returns>Vector2</returns>
|
||||
ShaderGraphValue AsVector2() const
|
||||
{
|
||||
return Cast(*this, VariantType::Types::Vector2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Casts the value to the Vector3 type.
|
||||
/// </summary>
|
||||
/// <returns>Vector3</returns>
|
||||
ShaderGraphValue AsVector3() const
|
||||
{
|
||||
return Cast(*this, VariantType::Types::Vector3);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Casts the value to the Vector4 type.
|
||||
/// </summary>
|
||||
/// <returns>Vector4</returns>
|
||||
ShaderGraphValue AsVector4() const
|
||||
{
|
||||
return Cast(*this, VariantType::Types::Vector4);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Casts the value from its type to the another type.
|
||||
/// </summary>
|
||||
/// <param name="to">The result type.</param>
|
||||
/// <returns>The result value.</returns>
|
||||
ShaderGraphValue Cast(const VariantType::Types to) const
|
||||
{
|
||||
return Cast(*this, to);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Casts the value from its type to the another type.
|
||||
/// </summary>
|
||||
/// <param name="v">The value to cast.</param>
|
||||
/// <param name="to">The result type.</param>
|
||||
/// <returns>The result value.</returns>
|
||||
static ShaderGraphValue Cast(const ShaderGraphValue& v, VariantType::Types to);
|
||||
|
||||
public:
|
||||
|
||||
// [Object]
|
||||
String ToString() const override
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
};
|
||||
10
Source/Engine/Visject/Visject.Build.cs
Normal file
10
Source/Engine/Visject/Visject.Build.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
using Flax.Build;
|
||||
|
||||
/// <summary>
|
||||
/// Visject Surface module.
|
||||
/// </summary>
|
||||
public class Visject : EngineModule
|
||||
{
|
||||
}
|
||||
957
Source/Engine/Visject/VisjectGraph.cpp
Normal file
957
Source/Engine/Visject/VisjectGraph.cpp
Normal file
@@ -0,0 +1,957 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "VisjectGraph.h"
|
||||
#include "GraphUtilities.h"
|
||||
#include "Engine/Core/Random.h"
|
||||
#include "Engine/Core/Math/Vector4.h"
|
||||
#include "Engine/Core/Math/Transform.h"
|
||||
#include "Engine/Engine/GameplayGlobals.h"
|
||||
#include "Engine/Scripting/Scripting.h"
|
||||
#include "Engine/Level/Actor.h"
|
||||
|
||||
#define RAND Random::Rand()
|
||||
|
||||
VisjectExecutor::VisjectExecutor()
|
||||
{
|
||||
// Register per group type processing events
|
||||
// Note: index must match group id
|
||||
#if BUILD_DEBUG
|
||||
Platform::MemoryClear(&_perGroupProcessCall, sizeof(_perGroupProcessCall));
|
||||
#endif
|
||||
_perGroupProcessCall[2] = &VisjectExecutor::ProcessGroupConstants;
|
||||
_perGroupProcessCall[3] = &VisjectExecutor::ProcessGroupMath;
|
||||
_perGroupProcessCall[4] = &VisjectExecutor::ProcessGroupPacking;
|
||||
_perGroupProcessCall[7] = &VisjectExecutor::ProcessGroupTools;
|
||||
_perGroupProcessCall[10] = &VisjectExecutor::ProcessGroupBoolean;
|
||||
_perGroupProcessCall[11] = &VisjectExecutor::ProcessGroupBitwise;
|
||||
_perGroupProcessCall[12] = &VisjectExecutor::ProcessGroupComparisons;
|
||||
_perGroupProcessCall[14] = &VisjectExecutor::ProcessGroupParticles;
|
||||
}
|
||||
|
||||
VisjectExecutor::~VisjectExecutor()
|
||||
{
|
||||
}
|
||||
|
||||
void VisjectExecutor::OnError(Node* node, Box* box, const StringView& message)
|
||||
{
|
||||
Error(node, box, message);
|
||||
}
|
||||
|
||||
void VisjectExecutor::ProcessGroupConstants(Box* box, Node* node, Value& value)
|
||||
{
|
||||
switch (node->TypeID)
|
||||
{
|
||||
// Constant value
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 12:
|
||||
value = node->Values[0];
|
||||
break;
|
||||
case 4:
|
||||
{
|
||||
const Value& cv = node->Values[0];
|
||||
if (box->ID == 0)
|
||||
value = cv;
|
||||
else if (box->ID == 1)
|
||||
value = cv.AsVector2().X;
|
||||
else if (box->ID == 2)
|
||||
value = cv.AsVector2().Y;
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
const Value& cv = node->Values[0];
|
||||
if (box->ID == 0)
|
||||
value = cv;
|
||||
else if (box->ID == 1)
|
||||
value = cv.AsVector3().X;
|
||||
else if (box->ID == 2)
|
||||
value = cv.AsVector3().Y;
|
||||
else if (box->ID == 3)
|
||||
value = cv.AsVector3().Z;
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
case 7:
|
||||
{
|
||||
const Value& cv = node->Values[0];
|
||||
if (box->ID == 0)
|
||||
value = cv;
|
||||
else if (box->ID == 1)
|
||||
value = cv.AsVector4().X;
|
||||
else if (box->ID == 2)
|
||||
value = cv.AsVector4().Y;
|
||||
else if (box->ID == 3)
|
||||
value = cv.AsVector4().Z;
|
||||
else if (box->ID == 4)
|
||||
value = cv.AsVector4().W;
|
||||
break;
|
||||
}
|
||||
case 8:
|
||||
{
|
||||
const float pitch = (float)node->Values[0];
|
||||
const float yaw = (float)node->Values[1];
|
||||
const float roll = (float)node->Values[2];
|
||||
value = Quaternion::Euler(pitch, yaw, roll);
|
||||
break;
|
||||
}
|
||||
case 9:
|
||||
{
|
||||
value = node->Values[0];
|
||||
break;
|
||||
}
|
||||
// PI
|
||||
case 10:
|
||||
value = PI;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void VisjectExecutor::ProcessGroupMath(Box* box, Node* node, Value& value)
|
||||
{
|
||||
switch (node->TypeID)
|
||||
{
|
||||
// Add, Subtract, Multiply, Divide, Modulo, Max, Min, Pow, Fmod, Atan2
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 21:
|
||||
case 22:
|
||||
case 23:
|
||||
case 40:
|
||||
case 41:
|
||||
{
|
||||
Value v1 = tryGetValue(node->GetBox(0), 0, Value::Zero);
|
||||
Value v2 = tryGetValue(node->GetBox(1), 1, Value::Zero).Cast(v1.Type);
|
||||
GraphUtilities::ApplySomeMathHere(node->TypeID, value, v1, v2);
|
||||
break;
|
||||
}
|
||||
// Absolute Value, Ceil, Cosine, Floor, Round, Saturate, Sine, Sqrt, Tangent, Negate, 1 - Value, Asine, Acosine, Atan, Trunc, Frac, Degrees, Radians
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
case 16:
|
||||
case 17:
|
||||
case 27:
|
||||
case 28:
|
||||
case 33:
|
||||
case 34:
|
||||
case 35:
|
||||
case 38:
|
||||
case 39:
|
||||
case 43:
|
||||
case 44:
|
||||
{
|
||||
Value v1 = tryGetValue(node->GetBox(0), Value::Zero);
|
||||
GraphUtilities::ApplySomeMathHere(node->TypeID, value, v1);
|
||||
break;
|
||||
}
|
||||
// Length, Normalize
|
||||
case 11:
|
||||
case 12:
|
||||
{
|
||||
Value v1 = tryGetValue(node->GetBox(0), Value::Zero);
|
||||
switch (node->TypeID)
|
||||
{
|
||||
case 11:
|
||||
{
|
||||
switch (v1.Type.Type)
|
||||
{
|
||||
case VariantType::Vector2:
|
||||
value = v1.AsVector2().Length();
|
||||
break;
|
||||
case VariantType::Vector3:
|
||||
value = v1.AsVector3().Length();
|
||||
break;
|
||||
case VariantType::Vector4:
|
||||
value = Vector3(v1.AsVector4()).Length();
|
||||
break;
|
||||
default: CRASH;
|
||||
break;
|
||||
}
|
||||
}
|
||||
case 12:
|
||||
switch (v1.Type.Type)
|
||||
{
|
||||
case VariantType::Int:
|
||||
value = Math::Saturate(v1.AsInt);
|
||||
break;
|
||||
case VariantType::Uint:
|
||||
value = Math::Saturate(v1.AsUint);
|
||||
break;
|
||||
case VariantType::Float:
|
||||
value = Math::Saturate(v1.AsFloat);
|
||||
break;
|
||||
case VariantType::Vector2:
|
||||
value = Vector2::Normalize(v1.AsVector2());
|
||||
break;
|
||||
case VariantType::Vector3:
|
||||
value = Vector3::Normalize(v1.AsVector3());
|
||||
break;
|
||||
case VariantType::Vector4:
|
||||
value = Vector4(Vector3::Normalize(Vector3(v1.AsVector4())), 0.0f);
|
||||
break;
|
||||
default: CRASH;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Cross, Distance, Dot
|
||||
case 18:
|
||||
case 19:
|
||||
case 20:
|
||||
{
|
||||
Value v1 = tryGetValue(node->GetBox(0), Value::Zero);
|
||||
Value v2 = tryGetValue(node->GetBox(1), Value::Zero).Cast(v1.Type);
|
||||
switch (node->TypeID)
|
||||
{
|
||||
case 18:
|
||||
switch (v1.Type.Type)
|
||||
{
|
||||
case VariantType::Vector3:
|
||||
value = Vector3::Cross(v1.AsVector3(), v2.AsVector3());
|
||||
break;
|
||||
default: CRASH;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 19:
|
||||
switch (v1.Type.Type)
|
||||
{
|
||||
case VariantType::Vector2:
|
||||
value = Vector2::Distance(v1.AsVector2(), v2.AsVector2());
|
||||
break;
|
||||
case VariantType::Vector3:
|
||||
value = Vector3::Distance(v1.AsVector3(), v2.AsVector3());
|
||||
break;
|
||||
case VariantType::Vector4:
|
||||
case VariantType::Color:
|
||||
value = Vector3::Distance((Vector3)v1, (Vector3)v2);
|
||||
break;
|
||||
default: CRASH;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 20:
|
||||
switch (v1.Type.Type)
|
||||
{
|
||||
case VariantType::Vector2:
|
||||
value = Vector2::Dot(v1.AsVector2(), v2.AsVector2());
|
||||
break;
|
||||
case VariantType::Vector3:
|
||||
value = Vector3::Dot(v1.AsVector3(), v2.AsVector3());
|
||||
break;
|
||||
case VariantType::Vector4:
|
||||
case VariantType::Color:
|
||||
value = Vector3::Dot((Vector3)v1, (Vector3)v2);
|
||||
break;
|
||||
default: CRASH;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Clamp
|
||||
case 24:
|
||||
{
|
||||
Value v1 = tryGetValue(node->GetBox(0), Value::Zero);
|
||||
Value v2 = tryGetValue(node->GetBox(1), 0, Value::Zero).Cast(v1.Type);
|
||||
Value v3 = tryGetValue(node->GetBox(2), 1, Value::One).Cast(v1.Type);
|
||||
GraphUtilities::ApplySomeMathHere(value, v1, v2, v3, [](float a, float b, float c)
|
||||
{
|
||||
return Math::Clamp(a, b, c);
|
||||
});
|
||||
break;
|
||||
}
|
||||
// Lerp
|
||||
case 25:
|
||||
{
|
||||
Value a = tryGetValue(node->GetBox(0), 0, Value::Zero);
|
||||
Value b = tryGetValue(node->GetBox(1), 1, Value::One).Cast(a.Type);
|
||||
Value alpha = tryGetValue(node->GetBox(2), 2, Value::Zero).Cast(ValueType(ValueType::Float));
|
||||
value = Value::Lerp(a, b, alpha.AsFloat);
|
||||
break;
|
||||
}
|
||||
// Reflect
|
||||
case 26:
|
||||
{
|
||||
Value v1 = tryGetValue(node->GetBox(0), Value::Zero);
|
||||
Value v2 = tryGetValue(node->GetBox(1), Value::Zero).Cast(v1.Type);
|
||||
switch (v1.Type.Type)
|
||||
{
|
||||
case VariantType::Vector2:
|
||||
value = v1.AsVector2() - 2 * v2.AsVector2() * Vector2::Dot(v1.AsVector2(), v2.AsVector2());
|
||||
break;
|
||||
case VariantType::Vector3:
|
||||
value = v1.AsVector3() - 2 * v2.AsVector3() * Vector3::Dot(v1.AsVector3(), v2.AsVector3());
|
||||
break;
|
||||
case VariantType::Vector4:
|
||||
value = Vector4(v1.AsVector4() - 2 * v2.AsVector4() * Vector3::Dot((Vector3)v1, (Vector3)v2));
|
||||
break;
|
||||
default: CRASH;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Mad
|
||||
case 31:
|
||||
{
|
||||
Value v1 = tryGetValue(node->GetBox(0), Value::Zero);
|
||||
Value v2 = tryGetValue(node->GetBox(1), 0, Value::One).Cast(v1.Type);
|
||||
Value v3 = tryGetValue(node->GetBox(2), 1, Value::Zero).Cast(v1.Type);
|
||||
GraphUtilities::ApplySomeMathHere(value, v1, v2, v3, [](float a, float b, float c)
|
||||
{
|
||||
return (a * b) + c;
|
||||
});
|
||||
break;
|
||||
}
|
||||
// Extract Largest Component
|
||||
case 32:
|
||||
{
|
||||
const auto v1 = (Vector3)tryGetValue(node->GetBox(0), Value::Zero);
|
||||
value = Math::ExtractLargestComponent(v1);
|
||||
break;
|
||||
}
|
||||
// Bias and Scale
|
||||
case 36:
|
||||
{
|
||||
ASSERT(node->Values.Count() == 2 && node->Values[0].Type == VariantType::Float && node->Values[1].Type == VariantType::Float);
|
||||
const auto bias = node->Values[0].AsFloat;
|
||||
const auto scale = node->Values[1].AsFloat;
|
||||
const auto input = (Vector3)tryGetValue(node->GetBox(0), Value::Zero);
|
||||
value = (input + bias) * scale;
|
||||
break;
|
||||
}
|
||||
// Rotate About Axis
|
||||
case 37:
|
||||
{
|
||||
const auto normalizedRotationAxis = (Vector3)tryGetValue(node->GetBox(0), Value::Zero);
|
||||
const auto rotationAngle = (float)tryGetValue(node->GetBox(1), Value::Zero);
|
||||
const auto pivotPoint = (Vector3)tryGetValue(node->GetBox(2), Value::Zero);
|
||||
const auto position = (Vector3)tryGetValue(node->GetBox(3), Value::Zero);
|
||||
value = Math::RotateAboutAxis(normalizedRotationAxis, rotationAngle, pivotPoint, position);
|
||||
break;
|
||||
}
|
||||
// Near Equal
|
||||
case 42:
|
||||
{
|
||||
const Value a = tryGetValue(node->GetBox(0), node->Values[0]);
|
||||
const Value b = tryGetValue(node->GetBox(1), node->Values[1]).Cast(a.Type);
|
||||
const float epsilon = (float)tryGetValue(node->GetBox(2), node->Values[2]);
|
||||
value = Value::NearEqual(a, b, epsilon);
|
||||
break;
|
||||
}
|
||||
// Enum Value
|
||||
case 45:
|
||||
value = (uint64)tryGetValue(node->GetBox(0), Value::Zero);
|
||||
break;
|
||||
// Enum AND
|
||||
case 46:
|
||||
value = tryGetValue(node->GetBox(0), Value::Zero);
|
||||
if (value.Type.Type == VariantType::Enum)
|
||||
value.AsUint64 = value.AsUint64 & (uint64)tryGetValue(node->GetBox(1), Value::Zero);
|
||||
break;
|
||||
// Enum OR
|
||||
case 47:
|
||||
value = tryGetValue(node->GetBox(0), Value::Zero);
|
||||
if (value.Type.Type == VariantType::Enum)
|
||||
value.AsUint64 = value.AsUint64 | (uint64)tryGetValue(node->GetBox(1), Value::Zero);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void VisjectExecutor::ProcessGroupPacking(Box* box, Node* node, Value& value)
|
||||
{
|
||||
switch (node->TypeID)
|
||||
{
|
||||
// Pack
|
||||
case 20:
|
||||
{
|
||||
float vX = (float)tryGetValue(node->GetBox(1), node->Values[0]);
|
||||
float vY = (float)tryGetValue(node->GetBox(2), node->Values[1]);
|
||||
value = Vector2(vX, vY);
|
||||
break;
|
||||
}
|
||||
case 21:
|
||||
{
|
||||
float vX = (float)tryGetValue(node->GetBox(1), node->Values[0]);
|
||||
float vY = (float)tryGetValue(node->GetBox(2), node->Values[1]);
|
||||
float vZ = (float)tryGetValue(node->GetBox(3), node->Values[2]);
|
||||
value = Vector3(vX, vY, vZ);
|
||||
break;
|
||||
}
|
||||
case 22:
|
||||
{
|
||||
float vX = (float)tryGetValue(node->GetBox(1), node->Values[0]);
|
||||
float vY = (float)tryGetValue(node->GetBox(2), node->Values[1]);
|
||||
float vZ = (float)tryGetValue(node->GetBox(3), node->Values[2]);
|
||||
float vW = (float)tryGetValue(node->GetBox(4), node->Values[3]);
|
||||
value = Vector4(vX, vY, vZ, vW);
|
||||
break;
|
||||
}
|
||||
case 23:
|
||||
{
|
||||
float vX = (float)tryGetValue(node->GetBox(1), node->Values[0]);
|
||||
float vY = (float)tryGetValue(node->GetBox(2), node->Values[1]);
|
||||
float vZ = (float)tryGetValue(node->GetBox(3), node->Values[2]);
|
||||
value = Quaternion::Euler(vX, vY, vZ);
|
||||
break;
|
||||
}
|
||||
case 24:
|
||||
{
|
||||
const Vector3 vX = (Vector3)tryGetValue(node->GetBox(1), Vector3::Zero);
|
||||
const Quaternion vY = (Quaternion)tryGetValue(node->GetBox(2), Quaternion::Identity);
|
||||
const Vector3 vZ = (Vector3)tryGetValue(node->GetBox(3), Vector3::One);
|
||||
value = Variant(Transform(vX, vY, vZ));
|
||||
break;
|
||||
}
|
||||
case 25:
|
||||
{
|
||||
const Vector3 vX = (Vector3)tryGetValue(node->GetBox(1), Vector3::Zero);
|
||||
const Vector3 vY = (Vector3)tryGetValue(node->GetBox(2), Vector3::Zero);
|
||||
value = Variant(BoundingBox(vX, vY));
|
||||
break;
|
||||
}
|
||||
// Unpack
|
||||
case 30:
|
||||
{
|
||||
Vector2 v = (Vector2)tryGetValue(node->GetBox(0), Vector2::Zero);
|
||||
int32 subIndex = box->ID - 1;
|
||||
ASSERT(subIndex >= 0 && subIndex < 2);
|
||||
value = v.Raw[subIndex];
|
||||
break;
|
||||
}
|
||||
case 31:
|
||||
{
|
||||
Vector3 v = (Vector3)tryGetValue(node->GetBox(0), Vector3::Zero);
|
||||
int32 subIndex = box->ID - 1;
|
||||
ASSERT(subIndex >= 0 && subIndex < 3);
|
||||
value = v.Raw[subIndex];
|
||||
break;
|
||||
}
|
||||
case 32:
|
||||
{
|
||||
Vector4 v = (Vector4)tryGetValue(node->GetBox(0), Vector4::Zero);
|
||||
int32 subIndex = box->ID - 1;
|
||||
ASSERT(subIndex >= 0 && subIndex < 4);
|
||||
value = v.Raw[subIndex];
|
||||
break;
|
||||
}
|
||||
case 33:
|
||||
{
|
||||
const Vector3 v = ((Quaternion)tryGetValue(node->GetBox(0), Quaternion::Identity)).GetEuler();
|
||||
const int32 subIndex = box->ID - 1;
|
||||
ASSERT(subIndex >= 0 && subIndex < 3);
|
||||
value = v.Raw[subIndex];
|
||||
break;
|
||||
}
|
||||
case 34:
|
||||
{
|
||||
const Transform v = (Transform)tryGetValue(node->GetBox(0), Variant::Zero);
|
||||
switch (box->ID)
|
||||
{
|
||||
case 1:
|
||||
value = v.Translation;
|
||||
break;
|
||||
case 2:
|
||||
value = v.Orientation;
|
||||
break;
|
||||
case 3:
|
||||
value = v.Scale;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 35:
|
||||
{
|
||||
const BoundingBox v = (BoundingBox)tryGetValue(node->GetBox(0), Variant::Zero);
|
||||
switch (box->ID)
|
||||
{
|
||||
case 1:
|
||||
value = v.Minimum;
|
||||
break;
|
||||
case 2:
|
||||
value = v.Maximum;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Mask X, Y, Z, W
|
||||
case 40:
|
||||
case 41:
|
||||
case 42:
|
||||
case 43:
|
||||
{
|
||||
const Vector4 v = (Vector4)tryGetValue(node->GetBox(0), Vector4::Zero);
|
||||
value = v.Raw[node->TypeID - 40];
|
||||
break;
|
||||
}
|
||||
// Mask XY, YZ, XZ,...
|
||||
case 44:
|
||||
{
|
||||
value = (Vector2)tryGetValue(node->GetBox(0), Vector2::Zero);
|
||||
break;
|
||||
}
|
||||
case 45:
|
||||
{
|
||||
const Vector4 v = (Vector4)tryGetValue(node->GetBox(0), Vector4::Zero);
|
||||
value = Vector2(v.X, v.Z);
|
||||
break;
|
||||
}
|
||||
case 46:
|
||||
{
|
||||
const Vector4 v = (Vector4)tryGetValue(node->GetBox(0), Vector4::Zero);
|
||||
value = Vector2(v.Y, v.Z);
|
||||
break;
|
||||
}
|
||||
// Mask XYZ
|
||||
case 70:
|
||||
{
|
||||
value = (Vector3)tryGetValue(node->GetBox(0), Vector3::Zero);
|
||||
break;
|
||||
}
|
||||
// Append
|
||||
case 100:
|
||||
{
|
||||
auto in0 = node->GetBox(0);
|
||||
auto in1 = node->GetBox(1);
|
||||
if (!in0->HasConnection() || !in1->HasConnection())
|
||||
{
|
||||
value = Value::Zero;
|
||||
break;
|
||||
}
|
||||
|
||||
auto value0 = eatBox(in0->GetParent<Node>(), in0->FirstConnection());
|
||||
auto value1 = eatBox(in1->GetParent<Node>(), in1->FirstConnection());
|
||||
|
||||
auto count0 = GraphUtilities::CountComponents(value0.Type.Type);
|
||||
auto count1 = GraphUtilities::CountComponents(value1.Type.Type);
|
||||
|
||||
auto count = count0 + count1;
|
||||
switch (count)
|
||||
{
|
||||
case 1:
|
||||
value = count0 ? value0 : value1;
|
||||
break;
|
||||
case 2:
|
||||
value = Vector2((float)value0, (float)value1);
|
||||
break;
|
||||
case 3:
|
||||
if (count0 == 1)
|
||||
value = Vector3((float)value0, value1.AsVector2().X, value1.AsVector2().Y);
|
||||
else
|
||||
value = Vector3((Vector2)value0, (float)value1);
|
||||
break;
|
||||
case 4:
|
||||
if (count0 == 1)
|
||||
value = Vector4((float)value0, value1.AsVector3().X, value1.AsVector3().Y, value1.AsVector3().Z);
|
||||
else if (count0 == 2)
|
||||
value = Vector4(value0.AsVector2().X, value0.AsVector2().Y, value1.AsVector2().X, value1.AsVector2().Y);
|
||||
else
|
||||
value = Vector4((Vector3)value0, (float)value1);
|
||||
break;
|
||||
default:
|
||||
value = Value::Zero;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void VisjectExecutor::ProcessGroupTools(Box* box, Node* node, Value& value)
|
||||
{
|
||||
switch (node->TypeID)
|
||||
{
|
||||
// Color Gradient
|
||||
case 10:
|
||||
{
|
||||
float time, prevTime, curTime;
|
||||
Color prevColor, curColor;
|
||||
const int32 count = (int32)node->Values[0];
|
||||
switch (count)
|
||||
{
|
||||
case 0:
|
||||
// No sample
|
||||
value = Value::Zero;
|
||||
break;
|
||||
case 1:
|
||||
// Single sample
|
||||
value = (Color)node->Values[2];
|
||||
break;
|
||||
case 2:
|
||||
// Linear blend between 2 samples
|
||||
time = (float)tryGetValue(node->GetBox(0), Value::Zero);
|
||||
prevTime = (float)node->Values[1];
|
||||
prevColor = (Color)node->Values[2];
|
||||
curTime = (float)node->Values[3];
|
||||
curColor = (Color)node->Values[4];
|
||||
value = Color::Lerp(prevColor, curColor, Math::Saturate((time - prevTime) / (curTime - prevTime)));
|
||||
break;
|
||||
default:
|
||||
time = (float)tryGetValue(node->GetBox(0), Value::Zero);
|
||||
if (time >= node->Values[1 + count * 2 - 2].AsFloat)
|
||||
{
|
||||
// Outside the range
|
||||
value = (Color)node->Values[1 + count * 2 - 2 + 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Find 2 samples to blend between them
|
||||
prevTime = (float)node->Values[1];
|
||||
prevColor = (Color)node->Values[2];
|
||||
for (int32 i = 1; i < count; i++)
|
||||
{
|
||||
curTime = (float)node->Values[i * 2 + 1];
|
||||
curColor = (Color)node->Values[i * 2 + 2];
|
||||
|
||||
if (time <= curTime)
|
||||
{
|
||||
value = Color::Lerp(prevColor, curColor, Math::Saturate((time - prevTime) / (curTime - prevTime)));
|
||||
break;
|
||||
}
|
||||
|
||||
prevTime = curTime;
|
||||
prevColor = curColor;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Curve
|
||||
#define SAMPLE_CURVE(id, curves, type, graphType) \
|
||||
case id: \
|
||||
{ \
|
||||
const auto& curve = GetCurrentGraph()->curves[node->Data.Curve.CurveIndex]; \
|
||||
const float time = (float)tryGetValue(node->GetBox(0), Value::Zero); \
|
||||
value.Type = VariantType(VariantType::graphType); \
|
||||
curve.Evaluate(*(type*)value.AsData, time, false); \
|
||||
break; \
|
||||
}
|
||||
SAMPLE_CURVE(12, FloatCurves, float, Float)
|
||||
SAMPLE_CURVE(13, Vector2Curves, Vector2, Vector2)
|
||||
SAMPLE_CURVE(14, Vector3Curves, Vector3, Vector3)
|
||||
SAMPLE_CURVE(15, Vector4Curves, Vector4, Vector4)
|
||||
#undef SETUP_CURVE
|
||||
// Get Gameplay Global
|
||||
case 16:
|
||||
{
|
||||
const auto asset = node->Assets[0].As<GameplayGlobals>();
|
||||
if (asset)
|
||||
{
|
||||
const StringView& name = (StringView)node->Values[1];
|
||||
const auto e = asset->Variables.Find(name);
|
||||
value = e != asset->Variables.End() ? e->Value.Value : Value::Zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = Value::Zero;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Platform Switch
|
||||
case 17:
|
||||
{
|
||||
int32 boxId = 1;
|
||||
switch (PLATFORM_TYPE)
|
||||
{
|
||||
case PlatformType::Windows:
|
||||
boxId = 2;
|
||||
break;
|
||||
case PlatformType::XboxOne:
|
||||
boxId = 3;
|
||||
break;
|
||||
case PlatformType::UWP:
|
||||
boxId = 4;
|
||||
break;
|
||||
case PlatformType::Linux:
|
||||
boxId = 5;
|
||||
break;
|
||||
case PlatformType::PS4:
|
||||
boxId = 6;
|
||||
break;
|
||||
case PlatformType::XboxScarlett:
|
||||
boxId = 7;
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
value = tryGetValue(node->GetBox(node->GetBox(boxId)->HasConnection() ? boxId : 1), Value::Zero);
|
||||
break;
|
||||
}
|
||||
// Asset Reference
|
||||
case 18:
|
||||
{
|
||||
value = Content::LoadAsync<Asset>((Guid)node->Values[0]);
|
||||
break;
|
||||
}
|
||||
// To String
|
||||
case 20:
|
||||
{
|
||||
value.SetString(tryGetValue(node->GetBox(1), Value(StringView::Empty)).ToString());
|
||||
break;
|
||||
}
|
||||
// Actor Reference
|
||||
case 21:
|
||||
{
|
||||
value = Scripting::FindObject<Actor>((Guid)node->Values[0]);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void VisjectExecutor::ProcessGroupBoolean(Box* box, Node* node, Value& value)
|
||||
{
|
||||
switch (node->TypeID)
|
||||
{
|
||||
// NOT
|
||||
case 1:
|
||||
{
|
||||
const bool a = (bool)tryGetValue(node->GetBox(0), Value::False);
|
||||
value = !a;
|
||||
break;
|
||||
}
|
||||
// AND, OR, XOR, NOR, NAND
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
{
|
||||
const bool a = (bool)tryGetValue(node->GetBox(0), 0, node->Values[0]);
|
||||
const bool b = (bool)tryGetValue(node->GetBox(1), 1, node->Values[1]);
|
||||
bool result = false;
|
||||
switch (node->TypeID)
|
||||
{
|
||||
// AND
|
||||
case 2:
|
||||
result = a && b;
|
||||
break;
|
||||
// OR
|
||||
case 3:
|
||||
result = a || b;
|
||||
break;
|
||||
// XOR
|
||||
case 4:
|
||||
result = !a != !b;
|
||||
break;
|
||||
// NOR
|
||||
case 5:
|
||||
result = !(a || b);
|
||||
break;
|
||||
// NAND
|
||||
case 6:
|
||||
result = !(a && b);
|
||||
break;
|
||||
}
|
||||
value = result;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void VisjectExecutor::ProcessGroupBitwise(Box* box, Node* node, Value& value)
|
||||
{
|
||||
switch (node->TypeID)
|
||||
{
|
||||
// NOT
|
||||
case 1:
|
||||
{
|
||||
const int32 a = (int32)tryGetValue(node->GetBox(0), Value(0));
|
||||
value = !a;
|
||||
break;
|
||||
}
|
||||
// AND, OR, XOR
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
{
|
||||
const int32 a = (int32)tryGetValue(node->GetBox(0), 0, node->Values[0]);
|
||||
const int32 b = (int32)tryGetValue(node->GetBox(1), 1, node->Values[1]);
|
||||
int32 result = 0;
|
||||
switch (node->TypeID)
|
||||
{
|
||||
// AND
|
||||
case 2:
|
||||
result = a & b;
|
||||
break;
|
||||
// OR
|
||||
case 3:
|
||||
result = a | b;
|
||||
break;
|
||||
// XOR
|
||||
case 4:
|
||||
result = a ^ b;
|
||||
break;
|
||||
}
|
||||
value = result;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void VisjectExecutor::ProcessGroupComparisons(Box* box, Node* node, Value& value)
|
||||
{
|
||||
switch (node->TypeID)
|
||||
{
|
||||
// ==, !=, >, <=, >=
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
{
|
||||
const Value a = tryGetValue(node->GetBox(0), 0, node->Values[0]);
|
||||
const Value b = tryGetValue(node->GetBox(1), 1, node->Values[1]).Cast(a.Type);
|
||||
bool result = false;
|
||||
switch (node->TypeID)
|
||||
{
|
||||
case 1:
|
||||
result = a == b;
|
||||
break;
|
||||
case 2:
|
||||
result = a != b;
|
||||
break;
|
||||
case 3:
|
||||
result = a > b;
|
||||
break;
|
||||
case 4:
|
||||
result = a < b;
|
||||
break;
|
||||
case 5:
|
||||
result = a <= b;
|
||||
break;
|
||||
case 6:
|
||||
result = a >= b;
|
||||
break;
|
||||
}
|
||||
value = result;
|
||||
break;
|
||||
}
|
||||
// Switch On Bool
|
||||
case 7:
|
||||
{
|
||||
const Value condition = tryGetValue(node->GetBox(0), Value::False);
|
||||
if (condition)
|
||||
value = tryGetValue(node->GetBox(2), 1, Value::Zero);
|
||||
else
|
||||
value = tryGetValue(node->GetBox(1), 0, Value::Zero);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VisjectExecutor::ProcessGroupParticles(Box* box, Node* node, Value& value)
|
||||
{
|
||||
switch (node->TypeID)
|
||||
{
|
||||
// Random Float
|
||||
case 208:
|
||||
{
|
||||
value = RAND;
|
||||
break;
|
||||
}
|
||||
// Random Vector2
|
||||
case 209:
|
||||
{
|
||||
value = Vector2(RAND, RAND);
|
||||
break;
|
||||
}
|
||||
// Random Vector3
|
||||
case 210:
|
||||
{
|
||||
value = Vector3(RAND, RAND, RAND);
|
||||
break;
|
||||
}
|
||||
// Random Vector4
|
||||
case 211:
|
||||
{
|
||||
value = Vector4(RAND, RAND, RAND, RAND);
|
||||
break;
|
||||
}
|
||||
// Random Float Range
|
||||
case 213:
|
||||
{
|
||||
auto& a = node->Values[0].AsFloat;
|
||||
auto& b = node->Values[1].AsFloat;
|
||||
value = Math::Lerp(a, b, RAND);
|
||||
break;
|
||||
}
|
||||
// Random Vector2 Range
|
||||
case 214:
|
||||
{
|
||||
auto a = (Vector2)node->Values[0];
|
||||
auto b = (Vector2)node->Values[1];
|
||||
value = Vector2(
|
||||
Math::Lerp(a.X, b.X, RAND),
|
||||
Math::Lerp(a.Y, b.Y, RAND)
|
||||
);
|
||||
break;
|
||||
}
|
||||
// Random Vector3 Range
|
||||
case 215:
|
||||
{
|
||||
auto a = (Vector3)node->Values[0];
|
||||
auto b = (Vector3)node->Values[1];
|
||||
value = Vector3(
|
||||
Math::Lerp(a.X, b.X, RAND),
|
||||
Math::Lerp(a.Y, b.Y, RAND),
|
||||
Math::Lerp(a.Z, b.Z, RAND)
|
||||
);
|
||||
break;
|
||||
}
|
||||
// Random Vector4 Range
|
||||
case 216:
|
||||
{
|
||||
auto a = (Vector4)node->Values[0];
|
||||
auto b = (Vector4)node->Values[1];
|
||||
value = Vector4(
|
||||
Math::Lerp(a.X, b.X, RAND),
|
||||
Math::Lerp(a.Y, b.Y, RAND),
|
||||
Math::Lerp(a.Z, b.Z, RAND),
|
||||
Math::Lerp(a.W, b.W, RAND)
|
||||
);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
VisjectExecutor::Value VisjectExecutor::tryGetValue(Box* box, int32 defaultValueBoxIndex, const Value& defaultValue)
|
||||
{
|
||||
const auto parentNode = box->GetParent<Node>();
|
||||
if (box->HasConnection())
|
||||
return eatBox(parentNode, box->FirstConnection());
|
||||
if (parentNode->Values.Count() > defaultValueBoxIndex)
|
||||
return Value(parentNode->Values[defaultValueBoxIndex]);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
VisjectExecutor::Value VisjectExecutor::tryGetValue(Box* box, const Value& defaultValue)
|
||||
{
|
||||
return box && box->HasConnection() ? eatBox(box->GetParent<Node>(), box->FirstConnection()) : defaultValue;
|
||||
}
|
||||
273
Source/Engine/Visject/VisjectGraph.h
Normal file
273
Source/Engine/Visject/VisjectGraph.h
Normal file
@@ -0,0 +1,273 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Graph.h"
|
||||
#include "Engine/Core/Math/Vector2.h"
|
||||
#include "Engine/Core/Math/Vector3.h"
|
||||
#include "Engine/Core/Math/Vector4.h"
|
||||
#include "Engine/Content/Asset.h"
|
||||
#include "Engine/Content/AssetReference.h"
|
||||
#include "Engine/Content/Utilities/AssetsContainer.h"
|
||||
#include "Engine/Animations/Curve.h"
|
||||
|
||||
#define VISJECT_GRAPH_NODE_MAX_ASSETS 14
|
||||
|
||||
template<class BoxType>
|
||||
class VisjectGraphNode;
|
||||
|
||||
class VisjectGraphBox : public GraphBox
|
||||
{
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// The cached value.
|
||||
/// </summary>
|
||||
Variant Cache;
|
||||
|
||||
public:
|
||||
|
||||
VisjectGraphBox()
|
||||
: GraphBox()
|
||||
{
|
||||
}
|
||||
|
||||
VisjectGraphBox(void* parent, byte id, const VariantType::Types type)
|
||||
: GraphBox(parent, id, type)
|
||||
{
|
||||
}
|
||||
|
||||
VisjectGraphBox(void* parent, byte id, const VariantType& type)
|
||||
: GraphBox(parent, id, type)
|
||||
{
|
||||
}
|
||||
|
||||
FORCE_INLINE VisjectGraphBox* FirstConnection() const
|
||||
{
|
||||
return (VisjectGraphBox*)Connections[0];
|
||||
}
|
||||
};
|
||||
|
||||
template<class BoxType = VisjectGraphBox>
|
||||
class VisjectGraphNode : public GraphNode<BoxType>
|
||||
{
|
||||
public:
|
||||
|
||||
struct CurveData
|
||||
{
|
||||
/// <summary>
|
||||
/// The curve index.
|
||||
/// </summary>
|
||||
int32 CurveIndex;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Custom cached data per node type. Compact to use as small amount of memory as possible.
|
||||
/// </summary>
|
||||
struct AdditionalData
|
||||
{
|
||||
union
|
||||
{
|
||||
CurveData Curve;
|
||||
|
||||
struct
|
||||
{
|
||||
void* Method;
|
||||
BinaryModule* Module;
|
||||
int32 ParamsCount;
|
||||
uint32 OutParamsMask;
|
||||
bool IsStatic;
|
||||
} InvokeMethod;
|
||||
|
||||
struct
|
||||
{
|
||||
void* Field;
|
||||
BinaryModule* Module;
|
||||
bool IsStatic;
|
||||
} GetSetField;
|
||||
};
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
VisjectGraphNode()
|
||||
: GraphNode<BoxType>()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// The custom data (depends on node type). Used to cache data for faster usage at runtime.
|
||||
/// </summary>
|
||||
AdditionalData Data;
|
||||
|
||||
/// <summary>
|
||||
/// The asset references. Linked resources such as Animation assets are referenced in graph data as ID. We need to keep valid refs to them at runtime to keep data in memory.
|
||||
/// </summary>
|
||||
AssetReference<Asset> Assets[VISJECT_GRAPH_NODE_MAX_ASSETS];
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Visject graph parameter.
|
||||
/// </summary>
|
||||
/// <seealso cref="GraphParameter" />
|
||||
API_CLASS() class VisjectGraphParameter : public GraphParameter
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_WITH_CONSTRUCTOR_IMPL(VisjectGraphParameter, GraphParameter);
|
||||
public:
|
||||
|
||||
VisjectGraphParameter(const VisjectGraphParameter& other)
|
||||
: VisjectGraphParameter()
|
||||
{
|
||||
#if !BUILD_RELEASE
|
||||
CRASH; // Not used
|
||||
#endif
|
||||
}
|
||||
|
||||
VisjectGraphParameter& operator=(const VisjectGraphParameter& other)
|
||||
{
|
||||
#if !BUILD_RELEASE
|
||||
CRASH; // Not used
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template<class NodeType = VisjectGraphNode<>, class BoxType = VisjectGraphBox, class ParameterType = VisjectGraphParameter>
|
||||
class VisjectGraph : public Graph<NodeType, BoxType, ParameterType>
|
||||
{
|
||||
public:
|
||||
|
||||
typedef Variant Value;
|
||||
typedef VariantType::Types ValueType;
|
||||
typedef Graph<NodeType, BoxType, ParameterType> Base;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// The float curves used by the graph.
|
||||
/// </summary>
|
||||
Array<BezierCurve<float>> FloatCurves;
|
||||
|
||||
/// <summary>
|
||||
/// The float curves used by the graph.
|
||||
/// </summary>
|
||||
Array<BezierCurve<Vector2>> Vector2Curves;
|
||||
|
||||
/// <summary>
|
||||
/// The float curves used by the graph.
|
||||
/// </summary>
|
||||
Array<BezierCurve<Vector3>> Vector3Curves;
|
||||
|
||||
/// <summary>
|
||||
/// The float curves used by the graph.
|
||||
/// </summary>
|
||||
Array<BezierCurve<Vector4>> Vector4Curves;
|
||||
|
||||
public:
|
||||
|
||||
// [Graph]
|
||||
bool onNodeLoaded(NodeType* n) override
|
||||
{
|
||||
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, Vector2Curves, AsVector2())
|
||||
SETUP_CURVE(14, Vector3Curves, AsVector3())
|
||||
SETUP_CURVE(15, Vector4Curves, AsVector4())
|
||||
#undef SETUP_CURVE
|
||||
// Get Gameplay Global
|
||||
case 16:
|
||||
{
|
||||
n->Assets[0] = Content::LoadAsync<Asset>((Guid)n->Values[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Base
|
||||
return Base::onNodeLoaded(n);
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Visject Surface graph executor at runtime.
|
||||
/// </summary>
|
||||
class VisjectExecutor
|
||||
{
|
||||
public:
|
||||
|
||||
typedef VisjectGraph<> Graph;
|
||||
typedef VisjectGraph<>::Node Node;
|
||||
typedef VisjectGraph<>::Box Box;
|
||||
typedef VisjectGraph<>::Parameter Parameter;
|
||||
typedef Variant Value;
|
||||
typedef VariantType ValueType;
|
||||
typedef Delegate<Node*, Box*, const StringView&> ErrorHandler;
|
||||
typedef void (VisjectExecutor::*ProcessBoxHandler)(Box*, Node*, Value&);
|
||||
|
||||
protected:
|
||||
|
||||
ProcessBoxHandler _perGroupProcessCall[18];
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="VisjectExecutor"/> class.
|
||||
/// </summary>
|
||||
VisjectExecutor();
|
||||
|
||||
/// <summary>
|
||||
/// Finalizes an instance of the <see cref="VisjectExecutor"/> class.
|
||||
/// </summary>
|
||||
~VisjectExecutor();
|
||||
|
||||
public:
|
||||
|
||||
ErrorHandler Error;
|
||||
|
||||
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);
|
||||
void ProcessGroupParticles(Box* box, Node* node, Value& value);
|
||||
|
||||
protected:
|
||||
|
||||
virtual Value eatBox(Node* caller, Box* box) = 0;
|
||||
virtual Graph* GetCurrentGraph() const = 0;
|
||||
Value tryGetValue(Box* box, int32 defaultValueBoxIndex, const Value& defaultValue);
|
||||
Value tryGetValue(Box* box, const Value& defaultValue);
|
||||
};
|
||||
110
Source/Engine/Visject/VisjectMeta.cpp
Normal file
110
Source/Engine/Visject/VisjectMeta.cpp
Normal file
@@ -0,0 +1,110 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "VisjectMeta.h"
|
||||
#include "Engine/Core/Types/DateTime.h"
|
||||
#include "Engine/Serialization/ReadStream.h"
|
||||
#include "Engine/Serialization/WriteStream.h"
|
||||
|
||||
VisjectMeta::VisjectMeta()
|
||||
{
|
||||
}
|
||||
|
||||
bool VisjectMeta::Load(ReadStream* stream, bool loadData)
|
||||
{
|
||||
Release();
|
||||
|
||||
int32 entries;
|
||||
stream->ReadInt32(&entries);
|
||||
Entries.Resize(entries);
|
||||
|
||||
for (int32 i = 0; i < entries; i++)
|
||||
{
|
||||
Entry& e = Entries[i];
|
||||
|
||||
stream->ReadInt32(&e.TypeID);
|
||||
DateTime creationTime;
|
||||
stream->Read(&creationTime);
|
||||
|
||||
uint32 dataSize;
|
||||
stream->ReadUint32(&dataSize);
|
||||
e.IsLoaded = loadData;
|
||||
if (loadData)
|
||||
{
|
||||
e.Data.Resize(dataSize, false);
|
||||
if (dataSize > 0)
|
||||
{
|
||||
stream->ReadBytes(e.Data.Get(), dataSize);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
e.Data.SetCapacity(0);
|
||||
stream->SetPosition(stream->GetPosition() + dataSize);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VisjectMeta::Save(WriteStream* stream, bool saveData) const
|
||||
{
|
||||
stream->WriteInt32(Entries.Count());
|
||||
|
||||
for (int32 i = 0; i < Entries.Count(); i++)
|
||||
{
|
||||
const Entry& e = Entries[i];
|
||||
|
||||
stream->WriteInt32(e.TypeID);
|
||||
stream->WriteInt64(0); // unused creation time
|
||||
|
||||
const uint32 dataSize = e.IsLoaded && saveData ? e.Data.Count() : 0;
|
||||
stream->WriteUint32(dataSize);
|
||||
if (dataSize > 0)
|
||||
{
|
||||
stream->WriteBytes(e.Data.Get(), dataSize);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void VisjectMeta::Release()
|
||||
{
|
||||
Entries.Clear();
|
||||
}
|
||||
|
||||
const VisjectMeta::Entry* VisjectMeta::GetEntry(int32 typeID) const
|
||||
{
|
||||
const Entry* result = nullptr;
|
||||
for (const Entry& e : Entries)
|
||||
{
|
||||
if (e.TypeID == typeID)
|
||||
{
|
||||
result = &e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
VisjectMeta::Entry* VisjectMeta::GetEntry(int32 typeID)
|
||||
{
|
||||
Entry* result = nullptr;
|
||||
for (Entry& e : Entries)
|
||||
{
|
||||
if (e.TypeID == typeID)
|
||||
{
|
||||
result = &e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void VisjectMeta::AddEntry(int32 typeID, byte* data, int32 size)
|
||||
{
|
||||
auto& e = Entries.AddOne();
|
||||
e.IsLoaded = true;
|
||||
e.TypeID = typeID;
|
||||
e.Data.Set(data, size);
|
||||
}
|
||||
90
Source/Engine/Visject/VisjectMeta.h
Normal file
90
Source/Engine/Visject/VisjectMeta.h
Normal file
@@ -0,0 +1,90 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Core/Collections/Array.h"
|
||||
#include "Engine/Serialization/Stream.h"
|
||||
|
||||
/// <summary>
|
||||
/// Visject metadata container
|
||||
/// </summary>
|
||||
class VisjectMeta
|
||||
{
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Metadata entry
|
||||
/// </summary>
|
||||
struct Entry
|
||||
{
|
||||
int32 TypeID;
|
||||
bool IsLoaded;
|
||||
Array<byte> Data;
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// All meta entries
|
||||
/// </summary>
|
||||
Array<Entry, FixedAllocation<8>> Entries;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="VisjectMeta"/> class.
|
||||
/// </summary>
|
||||
VisjectMeta();
|
||||
|
||||
/// <summary>
|
||||
/// Finalizes an instance of the <see cref="VisjectMeta"/> class.
|
||||
/// </summary>
|
||||
~VisjectMeta()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Load from the stream
|
||||
/// </summary>
|
||||
/// <param name="stream">Stream</param>
|
||||
/// <param name="loadData">True if load meta data</param>
|
||||
/// <returns>True if cannot load data</returns>
|
||||
bool Load(ReadStream* stream, bool loadData);
|
||||
|
||||
/// <summary>
|
||||
/// Save to the stream
|
||||
/// </summary>
|
||||
/// <param name="stream">Stream</param>
|
||||
/// <param name="saveData">True if load meta data</param>
|
||||
/// <returns>True if cannot save data</returns>
|
||||
bool Save(WriteStream* stream, bool saveData) const;
|
||||
|
||||
/// <summary>
|
||||
/// Release meta data
|
||||
/// </summary>
|
||||
void Release();
|
||||
|
||||
/// <summary>
|
||||
/// Get entry
|
||||
/// </summary>
|
||||
/// <param name="typeID">Entry type ID</param>
|
||||
/// <returns>Entry</returns>
|
||||
const Entry* GetEntry(int32 typeID) const;
|
||||
|
||||
/// <summary>
|
||||
/// Get entry
|
||||
/// </summary>
|
||||
/// <param name="typeID">Entry type ID</param>
|
||||
/// <returns>Entry</returns>
|
||||
Entry* GetEntry(int32 typeID);
|
||||
|
||||
/// <summary>
|
||||
/// Add new entry
|
||||
/// </summary>
|
||||
/// <param name="typeID">Type ID</param>
|
||||
/// <param name="data">Bytes to set</param>
|
||||
/// <param name="size">Amount of bytes to assign</param>
|
||||
void AddEntry(int32 typeID, byte* data, int32 size);
|
||||
};
|
||||
Reference in New Issue
Block a user