This commit is contained in:
2025-05-13 02:46:21 +03:00
parent 143e16692e
commit 86914b7fcc
610 changed files with 92343 additions and 2 deletions
@@ -0,0 +1,307 @@
#include "shaders/IShaderFactorySource.h"
#include "shaders/IShaderGraphNodeFactory.h"
#include <Property.h>
#include <math/LifeMath.h>
namespace LifeGraphics
{
#define NEW_NODE(_NodeName, _NodeType) \
IShaderGraphNode* ##_NodeName## = new IShaderGraphNode(); \
_NodeName##->Name = STR(#_NodeName); \
_NodeName##->NodeType = ##_NodeType;
#define NEW_NODE_IN(_NodeName, _DataType, _InName) \
IShaderGraphNodePort* in_a##_InName##_DataType## = new IShaderGraphNodePort(##_NodeName##); \
in_a##_InName##_DataType##->DataType = _DataType; \
in_a##_InName##_DataType##->Name = STR(#_InName); \
_NodeName##->Inputs.push_back(in_a##_InName##_DataType##);
#define NEW_NODE_OUT(_NodeName, _DataType, _OutName) \
IShaderGraphNodePort* out_a##_OutName##_DataType## = new IShaderGraphNodePort(##_NodeName##); \
out_a##_OutName##_DataType##->DataType = _DataType; \
out_a##_OutName##_DataType##->Name = STR(#_OutName); \
_NodeName##->Outputs.push_back(out_a##_OutName##_DataType##);
void IShaderFactorySource::Register(IShaderGraphNodeFactory* factory)
{
factory->RegisterNode(STR("Material"), &IShaderFactorySource::node_mat_std);
factory->RegisterNode(STR("OpAdd"), &IShaderFactorySource::node_op_add);
factory->RegisterNode(STR("OpLerp"), &IShaderFactorySource::node_op_lerp);
factory->RegisterNode(STR("OpSub"), &IShaderFactorySource::node_op_sub);
factory->RegisterNode(STR("OpMul"), &IShaderFactorySource::node_op_mul);
factory->RegisterNode(STR("OpDiv"), &IShaderFactorySource::node_op_div);
factory->RegisterNode(STR("OpDot"), &IShaderFactorySource::node_op_dot);
factory->RegisterNode(STR("ConstFloat1"), &IShaderFactorySource::node_const_f1);
factory->RegisterNode(STR("ConstFloat2"), &IShaderFactorySource::node_const_f2);
factory->RegisterNode(STR("ConstFloat3"), &IShaderFactorySource::node_const_f3);
factory->RegisterNode(STR("ConstFloat4"), &IShaderFactorySource::node_const_f4);
factory->RegisterNode(STR("OpNormalize"), &IShaderFactorySource::node_op_normalize);
factory->RegisterNode(STR("SrcTex2D"), &IShaderFactorySource::node_src_sam_2d);
factory->RegisterNode(STR("SrcUV"), &IShaderFactorySource::node_src_uv);
factory->RegisterNode(STR("DecodeNormal"), &IShaderFactorySource::node_op_decode_normal);
factory->RegisterNode(STR("Time"), &IShaderFactorySource::node_val_time);
}
IShaderGraphNode* IShaderFactorySource::node_mat_std()
{
NEW_NODE(Material, NT_MATERIAL);
NEW_NODE_IN(Material, DT_FLOAT3, Diffuse);
NEW_NODE_IN(Material, DT_FLOAT3, Specular);
NEW_NODE_IN(Material, DT_FLOAT, SpecularPower);
NEW_NODE_IN(Material, DT_FLOAT3, Normal);
return Material;
}
IShaderGraphNode* IShaderFactorySource::node_op_add()
{
NEW_NODE(Add, NT_OP);
NEW_NODE_IN(Add, DT_ANY, A);
NEW_NODE_IN(Add, DT_ANY, B);
NEW_NODE_OUT(Add, DT_ANY, C);
return Add;
}
IShaderGraphNode* IShaderFactorySource::node_op_lerp()
{
NEW_NODE(Lerp, NT_OP);
NEW_NODE_IN(Lerp, DT_ANY, A);
NEW_NODE_IN(Lerp, DT_ANY, B);
NEW_NODE_IN(Lerp, DT_FLOAT, Factor);
NEW_NODE_OUT(Lerp, DT_ANY, C);
return Lerp;
}
IShaderGraphNode* IShaderFactorySource::node_val_time()
{
NEW_NODE(Time, NT_CONST);
NEW_NODE_OUT(Time, DT_FLOAT4, RGBA);
NEW_NODE_OUT(Time, DT_FLOAT, R);
return Time;
}
IShaderGraphNode* IShaderFactorySource::node_const_f1()
{
IShaderGraphNode* node = new IShaderGraphNode();
node->Name = STR("ConstFloat1");
node->NodeType = NT_CONST;
IShaderGraphNodePort* out_a = new IShaderGraphNodePort(node);
out_a->DataType = DT_FLOAT;
out_a->Name = STR("A");
node->Outputs.push_back(out_a);
LifeCore::Property<float>* valueProperty = new LifeCore::Property<float>();
(*valueProperty) = 0.5f;
valueProperty->AddAttribute(STR("Name"), STR("Value"));
valueProperty->AddAttribute(STR("DisplayName"), STR("Value"));
node->RegisterProperty(valueProperty);
return node;
}
IShaderGraphNode* IShaderFactorySource::node_const_f2()
{
IShaderGraphNode* node = new IShaderGraphNode();
node->Name = STR("ConstFloat2");
node->NodeType = NT_CONST;
IShaderGraphNodePort* out_a = new IShaderGraphNodePort(node);
out_a->DataType = DT_FLOAT2;
out_a->Name = STR("A");
LifeCore::Property<LifeMath::float2>* valueProperty = new LifeCore::Property<LifeMath::float2>();
(*valueProperty) = LifeMath::float2(0.0f, 0.0f);
valueProperty->AddAttribute(STR("Name"), STR("Value"));
valueProperty->AddAttribute(STR("DisplayName"), STR("Value"));
node->RegisterProperty(valueProperty);
node->Outputs.push_back(out_a);
return node;
}
IShaderGraphNode* IShaderFactorySource::node_const_f3()
{
IShaderGraphNode* node = new IShaderGraphNode();
node->Name = STR("ConstFloat3");
node->NodeType = NT_CONST;
IShaderGraphNodePort* out_a = new IShaderGraphNodePort(node);
out_a->DataType = DT_FLOAT3;
out_a->Name = STR("A");
LifeCore::Property<LifeMath::float3>* valueProperty = new LifeCore::Property<LifeMath::float3>();
(*valueProperty) = LifeMath::float3(0.0f, 0.0f, 0.0f);
valueProperty->AddAttribute(STR("Name"), STR("Value"));
valueProperty->AddAttribute(STR("DisplayName"), STR("Value"));
node->RegisterProperty(valueProperty);
node->Outputs.push_back(out_a);
return node;
}
IShaderGraphNode* IShaderFactorySource::node_const_f4()
{
IShaderGraphNode* node = new IShaderGraphNode();
node->Name = STR("ConstFloat4");
node->NodeType = NT_CONST;
IShaderGraphNodePort* out_a = new IShaderGraphNodePort(node);
out_a->DataType = DT_FLOAT4;
out_a->Name = STR("A");
LifeCore::Property<LifeMath::float4>* valueProperty = new LifeCore::Property<LifeMath::float4>();
(*valueProperty) = LifeMath::float4(0.0f, 0.0f, 0.0f, 0.0f);
valueProperty->AddAttribute(STR("Name"), STR("Value"));
valueProperty->AddAttribute(STR("DisplayName"), STR("Value"));
node->RegisterProperty(valueProperty);
node->Outputs.push_back(out_a);
return node;
}
IShaderGraphNode* IShaderFactorySource::node_op_sub()
{
return 0;
}
IShaderGraphNode* IShaderFactorySource::node_op_mul()
{
return 0;
}
IShaderGraphNode* IShaderFactorySource::node_op_div()
{
return 0;
}
IShaderGraphNode* IShaderFactorySource::node_op_dot()
{
return 0;
}
IShaderGraphNode* IShaderFactorySource::node_op_cross()
{
return 0;
}
IShaderGraphNode* IShaderFactorySource::node_op_normalize()
{
IShaderGraphNode* node = new IShaderGraphNode();
node->Name = STR("Normalize");
node->NodeType = NT_OP;
IShaderGraphNodePort* in_a = new IShaderGraphNodePort(node);
in_a->DataType = DT_ANY;
in_a->Name = STR("A");
IShaderGraphNodePort* out_a = new IShaderGraphNodePort(node);
out_a->DataType = DT_ANY;
out_a->Name = STR("B");
node->Inputs.push_back(in_a);
node->Outputs.push_back(out_a);
return node;
}
IShaderGraphNode* IShaderFactorySource::node_op_saturate()
{
return 0;
}
IShaderGraphNode* IShaderFactorySource::node_op_cmp_le()
{
return 0;
}
IShaderGraphNode* IShaderFactorySource::node_op_cmp_l()
{
return 0;
}
IShaderGraphNode* IShaderFactorySource::node_op_cmp_ge()
{
return 0;
}
IShaderGraphNode* IShaderFactorySource::node_op_cmp_g()
{
return 0;
}
IShaderGraphNode* IShaderFactorySource::node_op_cmp_e()
{
return 0;
}
IShaderGraphNode* IShaderFactorySource::node_op_decode_g()
{
return 0;
}
IShaderGraphNode* IShaderFactorySource::node_op_decode_normal()
{
NEW_NODE(DecodeNormal, NT_OP);
NEW_NODE_IN(DecodeNormal, DT_ANY, TexNormal);
NEW_NODE_OUT(DecodeNormal, DT_FLOAT3, Normal);
return DecodeNormal;
}
IShaderGraphNode* IShaderFactorySource::node_src_uv()
{
NEW_NODE(UV, NT_RES);
NEW_NODE_OUT(UV, DT_FLOAT2, UV);
LifeCore::Property<uint32>* channelProperty = new LifeCore::Property<uint32>();
(*channelProperty) = 0;
channelProperty->AddAttribute(STR("Name"), STR("Channel"));
channelProperty->AddAttribute(STR("DisplayName"), STR("UV Channel ID"));
UV->RegisterProperty(channelProperty);
return UV;
}
IShaderGraphNode* IShaderFactorySource::node_src_sam_2d()
{
IShaderGraphNode* node = new IShaderGraphNode();
node->Name = STR("Sam2D");
node->NodeType = NT_RES;
IShaderGraphNodePort* in_a = new IShaderGraphNodePort(node);
in_a->DataType = DT_FLOAT2;
in_a->Name = STR("UV");
IShaderGraphNodePort* out_a = new IShaderGraphNodePort(node);
out_a->DataType = DT_FLOAT4;
out_a->Name = STR("RGBA");
IShaderGraphNodePort* out_b = new IShaderGraphNodePort(node);
out_b->DataType = DT_FLOAT;
out_b->Name = STR("R");
IShaderGraphNodePort* out_c = new IShaderGraphNodePort(node);
out_c->DataType = DT_FLOAT;
out_c->Name = STR("G");
IShaderGraphNodePort* out_d = new IShaderGraphNodePort(node);
out_d->DataType = DT_FLOAT;
out_d->Name = STR("B");
IShaderGraphNodePort* out_e = new IShaderGraphNodePort(node);
out_e->DataType = DT_FLOAT;
out_e->Name = STR("A");
node->Inputs.push_back(in_a);
node->Outputs.push_back(out_a);
node->Outputs.push_back(out_b);
node->Outputs.push_back(out_c);
node->Outputs.push_back(out_d);
node->Outputs.push_back(out_e);
LifeCore::Property<String>* filename = new LifeCore::Property<String>();
(*filename) = STR("");
filename->AddAttribute(STR("Name"), STR("FilePath"));
filename->AddAttribute(STR("DisplayName"), STR("FilePath"));
filename->AddAttribute(STR("ValueEditor"), STR("FilePath"));
node->RegisterProperty(filename);
return node;
}
IShaderGraphNode* IShaderFactorySource::node_src_sam_3d()
{
return 0;
}
IShaderGraphNode* IShaderFactorySource::node_src_sam_cube()
{
return 0;
}
}
@@ -0,0 +1,45 @@
#ifndef IShaderFactorySource_h__
#define IShaderFactorySource_h__
#include "shaders/IShaderGraphNode.h"
namespace LifeGraphics
{
class IShaderGraphNodeFactory;
class IShaderFactorySource
{
public:
static void Register(IShaderGraphNodeFactory* factory);
static IShaderGraphNode* node_mat_std();
static IShaderGraphNode* node_op_add();
static IShaderGraphNode* node_op_lerp();
static IShaderGraphNode* node_op_sub();
static IShaderGraphNode* node_op_mul();
static IShaderGraphNode* node_op_div();
static IShaderGraphNode* node_op_dot();
static IShaderGraphNode* node_op_cross();
static IShaderGraphNode* node_op_normalize();
static IShaderGraphNode* node_op_saturate();
static IShaderGraphNode* node_op_cmp_le();
static IShaderGraphNode* node_op_cmp_l();
static IShaderGraphNode* node_op_cmp_ge();
static IShaderGraphNode* node_op_cmp_g();
static IShaderGraphNode* node_op_cmp_e();
static IShaderGraphNode* node_op_decode_g();
static IShaderGraphNode* node_op_decode_normal();
static IShaderGraphNode* node_src_uv();
static IShaderGraphNode* node_src_sam_2d();
static IShaderGraphNode* node_src_sam_3d();
static IShaderGraphNode* node_src_sam_cube();
static IShaderGraphNode* node_const_f1();
static IShaderGraphNode* node_const_f2();
static IShaderGraphNode* node_const_f3();
static IShaderGraphNode* node_const_f4();
static IShaderGraphNode* node_val_time();
};
}
#endif // IShaderFactorySource_h__
+207
View File
@@ -0,0 +1,207 @@
#include "shaders/IShaderGraph.h"
#include <Types.h>
#include "XML.h"
#define NAME_LENGTH 64
namespace LifeGraphics
{
IShaderGraph::IShaderGraph(IShaderGraphNodeFactory* factory)
:last_id(0)
{
pFactory = factory;
for(int i = 0; i < 16; i++)
{
texture_slots[i] = -1;
}
}
IShaderGraph::~IShaderGraph()
{
}
int IShaderGraph::GrabTextureSlot()
{
for(int i = 0; i < 16; i++)
{
if(texture_slots[i] == -1)
{
texture_slots[i] = 1;
return i;
}
}
return -1;
}
IShaderGraphNode* IShaderGraph::AddNode(const String& name)
{
IShaderGraphNode* node = pFactory->Build(name);
node->id = GetID();
Nodes.push_back(node);
if(name == STR("SrcTex2D"))
{
node->resource_id = GrabTextureSlot();
}
return node;
}
bool IShaderGraph::DeleteNode(int id)
{
for(NodeCollectionIt it = Nodes.begin(); it != Nodes.end(); ++it)
{
IShaderGraphNode* n = (*it);
if(n->id == id) {
//deactivate output links
for(int j = 0; j < n->Outputs.size(); j++){
IShaderGraphNodePort* port = n->Outputs[j];
port->BreakLink();
delete port;
}
//deactivate input links
for(int j = 0; j < n->Inputs.size(); j++){
IShaderGraphNodePort* port = n->Inputs[j];
port->BreakLink();
delete port;
}
delete (*it);
Nodes.erase(it);
return true;
}
}
return false;
}
IShaderGraphNode* IShaderGraph::GetNodeByID(int id)
{
int nc = Nodes.size();
for(int i = 0; i < nc; i++)
{
if(Nodes[i]->id == id)
return Nodes[i];
}
return 0;
}
void IShaderGraph::Clear()
{
int nc = Nodes.size();
for(int i = 0; i < nc; i++)
{
delete Nodes[i];
}
Nodes.clear();
}
IShaderGraphNode* IShaderGraph::GetNodeByArrayID(int id)
{
int nc = Nodes.size();
if(id < nc)
{
return Nodes[id];
}
return nullptr;
}
size_t IShaderGraph::GetNodeCount()
{
return Nodes.size();
}
void IShaderGraph::SerializeXML(LifeCore::IMemoryStream* stm)
{
/*int node_count = Nodes.size();
pugi::xml_document doc;
pugi::xml_node rootNode = doc.append_child("ShaderGraph");
rootNode.append_attribute("NodeCount") = node_count;
rootNode.append_attribute("LastID") = last_id;
//write node info
for(int i = 0; i < node_count; i++)
{
IShaderGraphNode* n = Nodes[i];
pugi::xml_node node = rootNode.append_child("Node");
node.append_attribute("Name") = n->Name;
node.append_attribute("ID") = n->id;
}*/
}
bool IShaderGraph::DeserializeXML(LifeCore::IMemoryStream* stm)
{
return true;
}
void IShaderGraph::Serialize(LifeCore::IMemoryStream* stm)
{
int node_count = Nodes.size();
//write total nodes count
stm->Write(node_count);
//write last id value
stm->Write(last_id);
//write basic node info
for(int i = 0; i < node_count; i++){
IShaderGraphNode* n = Nodes[i];
StringSerialize(n->Name, stm);
stm->Write(n->id);
}
//write advanced node info
for(int i = 0; i < node_count; i++){
IShaderGraphNode* n = Nodes[i];
n->Serialize(stm); //serialize properties
for(int j = 0; j < n->Inputs.size(); j++){
IShaderGraphNodePort* port = n->Inputs[j];
int val = -1;
int parent = -1;
if(port->GetLinkCount()){
val = port->GetLink(0)->Parent->GetOutputID(port->GetLink(0));
parent = port->GetLink(0)->Parent->id;
}
//write attached node ID
stm->Write(parent);
//write attached node port ID
stm->Write(val);
}
}
}
bool IShaderGraph::Deserialize(LifeCore::IMemoryStream* stm)
{
int node_count;
stm->ReadInt32(node_count);
stm->ReadInt32(last_id);
//read basic info and create nodes
for(int i = 0; i < node_count; i++){
//get node name
String name = StringDeserialize(stm);
IShaderGraphNode* n = pFactory->Build(name);
//get node ID
stm->ReadInt32(n->id);
Nodes.push_back(n);
}
//read extended info
for(int i = 0; i < node_count; i++){
IShaderGraphNode* n = Nodes[i];
n->Deserialize(stm); //deserialize properties
int pc = n->Inputs.size();
//read ports info
for(int j = 0; j < pc; j++){
int nid, pid;
//read attached node id
stm->ReadInt32(nid);
//read attached port id
stm->ReadInt32(pid);
//if attached - make link
if(pid != -1){
//current node
IShaderGraphNode* cn = Nodes[i];
//attachment node
IShaderGraphNode* an = GetNodeByID(nid);
cn->Inputs[j]->MakeLink(cn->Inputs[j], an->Outputs[pid]);
}
}
}
return true;
}
}
+40
View File
@@ -0,0 +1,40 @@
#ifndef IShaderGraph_h__
#define IShaderGraph_h__
#include "shaders/IShaderGraphNodeFactory.h"
#include "delegate/Delegate.h"
#include <vector>
#include <IMemoryStream.h>
namespace LifeGraphics
{
class IShaderGraph
{
public:
EVENT1(GraphEvent, IShaderGraphNode*);
GraphEvent Event_AddNode;
IShaderGraph(IShaderGraphNodeFactory* factory);
~IShaderGraph();
IShaderGraphNode* AddNode(const String& name);
bool DeleteNode(int id);
void Serialize(LifeCore::IMemoryStream* stm);
bool Deserialize(LifeCore::IMemoryStream* stm);
void SerializeXML(LifeCore::IMemoryStream* stm);
bool DeserializeXML(LifeCore::IMemoryStream* stm);
IShaderGraphNode* GetNodeByID(int id);
IShaderGraphNode* GetNodeByArrayID(int id);
size_t GetNodeCount();
void Clear();
private:
int texture_slots[16];
int last_id;
int GrabTextureSlot();
int GetID(){return last_id++;}
IShaderGraphNodeFactory* pFactory;
typedef std::vector<IShaderGraphNode*> NodeCollection;
typedef std::vector<IShaderGraphNode*>::iterator NodeCollectionIt;
NodeCollection Nodes;
};
}
#endif // IShaderGraph_h__
@@ -0,0 +1,70 @@
#ifndef IShaderGraphCompiler_h__
#define IShaderGraphCompiler_h__
#include "shaders/IShaderGraphNode.h"
namespace LifeGraphics
{
enum IShaderCompilerFlags
{
SCF_NONE = 0,
SCF_SKINNING = 1,
};
static int ShaderTypeToChannelCount(IShaderDataType t)
{
switch(t)
{
case DT_ANY:
return 0;
case DT_FLOAT:
return 1;
case DT_FLOAT2:
return 2;
case DT_FLOAT3:
return 3;
case DT_FLOAT4:
return 4;
}
return 0;
}
static IShaderDataType MaxType(IShaderDataType t1, IShaderDataType t2)
{
return ShaderTypeToChannelCount(t1) > ShaderTypeToChannelCount(t2) ? t1 : t2;
}
struct ShaderTextureMapping
{
int reg;
int nodeId;
String name;
};
struct ShaderConstantMapping
{
String name;
IShaderDataType DataType;
int size;
int offset;
};
struct ShaderConstantTable
{
};
struct ShaderInputInfo
{
std::vector<ShaderTextureMapping> Textures;
void Clear()
{
Textures.clear();
}
};
class IShaderGraphCompiler
{
public:
virtual void CompileNode(IShaderGraphNode* rootNode, int flags, String& ps, String& vs, ShaderInputInfo* info) = 0;
};
}
#endif // IShaderGraphCompiler_h__
+59
View File
@@ -0,0 +1,59 @@
#include <shaders/IShaderGraphNode.h>
namespace LifeGraphics
{
IShaderGraphNode::IShaderGraphNode()
:checked(false), resource_id(0)
{
}
bool IShaderGraphNode::Serialize(LifeCore::IMemoryStream* stm)
{
return IPropertyHolder::Serialize(stm);
}
bool IShaderGraphNode::Deserialize(LifeCore::IMemoryStream* stm)
{
return IPropertyHolder::Deserialize(stm);
}
IShaderGraphNodePort* IShaderGraphNode::GetInputPort(size_t id)
{
return Inputs[id];
}
IShaderGraphNodePort* IShaderGraphNode::GetInputPortByName(const String& name)
{
size_t cnt = Inputs.size();
for(size_t i = 0; i < cnt; i++){
if(Inputs[i]->Name == name)
return Inputs[i];
}
return nullptr;
}
IShaderGraphNodePort* IShaderGraphNode::GetOutputPortByName(const String& name)
{
size_t cnt = Outputs.size();
for(size_t i = 0; i < cnt; i++){
if(Outputs[i]->Name == name)
return Outputs[i];
}
return nullptr;
}
IShaderGraphNodePort* IShaderGraphNode::GetOutputPortByID(size_t id){
size_t cnt = Outputs.size();
if(id < cnt){
return Outputs[id];
}
return nullptr;
}
size_t IShaderGraphNode::GetOutputID(IShaderGraphNodePort* port)
{
for(size_t i = 0; i < Outputs.size(); i++){
if(Outputs[i] == port)
return i;
}
return 100500;
}
}
+36
View File
@@ -0,0 +1,36 @@
#ifndef IShaderGraphNode_h__
#define IShaderGraphNode_h__
#include <LString.h>
#include "IShaderTypes.h"
#include <vector>
#include "IPropertyHolder.h"
#include <delegate/Delegate.h>
#include "shaders/IShaderGraphNodePort.h"
namespace LifeGraphics
{
class IShaderGraphNode : public LifeCore::IPropertyHolder
{
public:
int resource_id;
ShaderNodeType NodeType;
String Name;
bool checked;
int id;
typedef std::vector<IShaderGraphNodePort*> PortCollection;
typedef std::vector<IShaderGraphNodePort*>::iterator PortCollectionItr;
PortCollection Inputs;
PortCollection Outputs;
IShaderGraphNode();
IShaderGraphNodePort* GetInputPortByName(const String& name);
IShaderGraphNodePort* GetInputPort(size_t id);
IShaderGraphNodePort* GetOutputPortByName(const String& name);
IShaderGraphNodePort* GetOutputPortByID(size_t id);
bool Serialize(LifeCore::IMemoryStream* stm);
bool Deserialize(LifeCore::IMemoryStream* stm);
size_t GetOutputID(IShaderGraphNodePort* port);
};
}
#endif // IShaderGraphNode_h__
@@ -0,0 +1,19 @@
#include "shaders/IShaderGraphNodeFactory.h"
namespace LifeGraphics
{
void IShaderGraphNodeFactory::RegisterNode(const String& name, NodeFactoryFunc func)
{
if(FactoryFuncs.find(name) != FactoryFuncs.end())
return;
FactoryFuncs[name] = func;
}
IShaderGraphNode* IShaderGraphNodeFactory::Build(const String& name)
{
if(FactoryFuncs.find(name) == FactoryFuncs.end())
return 0;
IShaderGraphNode* n = FactoryFuncs[name]();
n->Name = name;
return n;
}
}
@@ -0,0 +1,25 @@
#ifndef IShaderGraphNodeFactory_h__
#define IShaderGraphNodeFactory_h__
#include "shaders/IShaderGraphNode.h"
#include <hash_map>
#include <Singleton.h>
namespace LifeGraphics
{
class IShaderGraphNodeFactory;
class IShaderGraphNodeFactory : public Singleton<IShaderGraphNodeFactory>
{
public:
friend class Singleton<IShaderGraphNodeFactory>;
typedef IShaderGraphNode* (*NodeFactoryFunc)();
void RegisterNode(const String& name, NodeFactoryFunc func);
IShaderGraphNode* Build(const String& name);
private:
IShaderGraphNodeFactory(){}
typedef std::hash_map<String, NodeFactoryFunc> FactoryArray;
FactoryArray FactoryFuncs;
};
}
#endif // IShaderGraphNodeFactory_h__
@@ -0,0 +1,58 @@
#include "shaders/IShaderGraphNodePort.h"
#include <assert.h>
namespace LifeGraphics
{
IShaderGraphNodePort::IShaderGraphNodePort(IShaderGraphNode* parent)
:Parent(parent)
{
assert(parent != nullptr && "Shader graph node port parent is nullptr!");
}
IShaderGraphNodePort* IShaderGraphNodePort::GetLink(size_t id)
{
return links[id];
}
size_t IShaderGraphNodePort::GetLinkCount()
{
return links.size();
}
void IShaderGraphNodePort::MakeLink(IShaderGraphNodePort* input, IShaderGraphNodePort* output)
{
// assert(target != nullptr && "Failed on add link on IShaderGraphNodePort");
if(!input->IsLinkExists(output))
input->links.push_back(output);
if(!output->IsLinkExists(input))
output->links.push_back(input);
}
bool IShaderGraphNodePort::IsLinkExists(IShaderGraphNodePort* target)
{
for(LinkCollectonItr it = links.begin(); it != links.end(); ++it)
{
if(*it == target)
return true;
}
return false;
}
void IShaderGraphNodePort::BreakLink()
{
//remove self from remote ports
for(LinkCollectonItr it = links.begin(); it != links.end(); ++it) {
(*it)->RemoveLink(this);
}
//clear list of remote ports
links.clear();
}
void IShaderGraphNodePort::RemoveLink(IShaderGraphNodePort* target)
{
for(LinkCollectonItr it = links.begin(); it != links.end(); ++it)
{
IShaderGraphNodePort* lnk = *it;
if(lnk == target){
links.erase(it);
return;
}
}
}
}
@@ -0,0 +1,30 @@
#ifndef IShaderGraphNodePort_h__
#define IShaderGraphNodePort_h__
#include "IShaderTypes.h"
#include <vector>
namespace LifeGraphics
{
class IShaderGraphNode;
class IShaderGraphNodePort
{
public:
void MakeLink(IShaderGraphNodePort* input, IShaderGraphNodePort* output);
IShaderGraphNodePort* GetLink(size_t id);
size_t GetLinkCount();
bool IsLinkExists(IShaderGraphNodePort* target);
void BreakLink();
IShaderGraphNodePort(IShaderGraphNode* parent);
IShaderGraphNode* Parent;
String Name;
String Value;
IShaderDataType DataType;
private:
void RemoveLink(IShaderGraphNodePort* target);
typedef std::vector<IShaderGraphNodePort*> LinkCollecton;
typedef std::vector<IShaderGraphNodePort*>::iterator LinkCollectonItr;
LinkCollecton links;
};
}
#endif // IShaderGraphNodePort_h__
+22
View File
@@ -0,0 +1,22 @@
#ifndef IShaderTypes_h__
#define IShaderTypes_h__
#include <Types.h>
enum IShaderDataType
{
DT_ANY,
DT_FLOAT,
DT_FLOAT2,
DT_FLOAT3,
DT_FLOAT4,
};
enum ShaderNodeType
{
NT_CONST,
NT_OP,
NT_RES,
NT_MATERIAL
};
#endif // IShaderTypes_h__
@@ -0,0 +1,520 @@
#include "shaders/ShaderGraphCompilerHLSL.h"
#include <IProperty.h>
#include <Property.h>
#include <math/LifeMath.h>
#include <Utils.h>
namespace LifeGraphics
{
ShaderGraphCompilerHLSL::ShaderGraphCompilerHLSL()
:var_id(0)
{
}
String ShaderGraphCompilerHLSL::NewVarName(const String& baseName)
{
char tmp[32];
itoa(var_id, &tmp[0], 10);
var_id++;
return baseName + String(tmp);
}
String ShaderGraphCompilerHLSL::TypeToStr(IShaderDataType t)
{
switch(t)
{
case DT_FLOAT:
return STR("float");
case DT_FLOAT2:
return STR("float2");
case DT_FLOAT3:
return STR("float3");
case DT_FLOAT4:
return STR("float4");
default:
return STR("ERROR_TYPE");
}
}
void ShaderGraphCompilerHLSL::ExposeNode(String& shader, String& resources, IShaderGraphNode* node)
{
if(node->checked)
return;
node->checked = true;
//TCHAR* tmp = new TCHAR[128];
TCHAR tmp[1024];
//constant values
if(node->NodeType == NT_CONST)
{
if(node->Name == STR("ConstFloat1"))
{
String constName = NewVarName(node->Name);
node->Outputs[0]->Value = constName;
LifeCore::IProperty* valueProp;
if(!node->GetPropertyByAttribute(STR("Name"), STR("Value"), &valueProp))
{
printf("Failed to get \"Value\" Property from Float1 node!\n");
getchar();
exit(0);
}
String s = valueProp->ToString();
sprintf(&tmp[0], "float %s = %sf;\n", constName.c_str(), s.c_str());
shader = String(tmp) + shader;
}
else if(node->Name == STR("ConstFloat2"))
{
String constName = NewVarName(node->Name);
node->Outputs[0]->Value = constName;
LifeCore::IProperty* valueProp;
if(!node->GetPropertyByAttribute(STR("Name"), STR("Value"), &valueProp))
{
printf("Failed to get \"Value\" Property from Float1 node!\n");
getchar();
exit(0);
}
LifeCore::Property<LifeMath::float2>* prop_src = (LifeCore::Property<LifeMath::float2>*)valueProp;
sprintf(&tmp[0], "float2 %s = float2(%ff, %ff);\n", constName.c_str(), (*prop_src)().X, (*prop_src)().Y);
shader = String(tmp) + shader;
}
else if(node->Name == STR("ConstFloat3"))
{
String constName = NewVarName(node->Name);
node->Outputs[0]->Value = constName;
LifeCore::IProperty* valueProp;
if(!node->GetPropertyByAttribute(STR("Name"), STR("Value"), &valueProp))
{
printf("Failed to get \"Value\" Property from Float1 node!\n");
getchar();
exit(0);
}
LifeCore::Property<LifeMath::Vec3f>* prop_src = (LifeCore::Property<LifeMath::Vec3f>*)valueProp;
sprintf(&tmp[0], "float3 %s = float3(%ff, %ff, %ff);\n", constName.c_str(), (*prop_src)().X, (*prop_src)().Y, (*prop_src)().Z);
shader = String(tmp) + shader;
}
else if(node->Name == STR("ConstFloat4"))
{
String constName = NewVarName(node->Name);
node->Outputs[0]->Value = constName;
LifeCore::IProperty* valueProp;
if(!node->GetPropertyByAttribute(STR("Name"), STR("Value"), &valueProp))
{
printf("Failed to get \"Value\" Property from Float1 node!\n");
getchar();
exit(0);
}
LifeCore::Property<LifeMath::Vec4f>* prop_src = (LifeCore::Property<LifeMath::Vec4f>*)valueProp;
sprintf(&tmp[0], "float4 %s = float4(%ff, %ff, %ff, %ff);\n", constName.c_str(), (*prop_src)().X, (*prop_src)().Y, (*prop_src)().Z, (*prop_src)().W);
shader = String(tmp) + shader;
}
else if(node->Name == STR("Time"))
{
String constName = NewVarName(node->Name);
node->Outputs[0]->Value = STR("sceneTime.xxxx");
node->Outputs[1]->Value = STR("sceneTime.x");
}
}
else
{
if(node->Name == STR("OpAdd"))
{
if(!node->Inputs[0]->GetLinkCount() || !node->Inputs[1]->GetLinkCount()){
shader = String("ERROR_EXPRESSION") + shader; return;}
String top1;
String top2;
//Exposing connected nodes
ExposeNode(top1, resources, node->Inputs[0]->GetLink(0)->Parent);
ExposeNode(top2, resources, node->Inputs[1]->GetLink(0)->Parent);
String tn = TypeToStr(MaxType(node->Inputs[0]->GetLink(0)->DataType, node->Inputs[1]->GetLink(0)->DataType));
String cn = NewVarName(node->Name);
sprintf(&tmp[0], "%s %s = ((%s) + (%s));", tn.c_str(), cn.c_str(), node->Inputs[0]->GetLink(0)->Value.c_str(),
node->Inputs[1]->GetLink(0)->Value.c_str());
node->Outputs[0]->DataType = MaxType(node->Inputs[0]->GetLink(0)->DataType, node->Inputs[1]->GetLink(0)->DataType);
shader = top1 + top2 + String(tmp) + shader;
node->Outputs[0]->Value = cn;
}
else if(node->Name == STR("OpLerp"))
{
if(!node->Inputs[0]->GetLinkCount() || !node->Inputs[1]->GetLinkCount() || !node->Inputs[2]->GetLinkCount()){
shader = String("ERROR_EXPRESSION") + shader; return;}
String top1;
String top2;
String top3;
//Exposing connected nodes
ExposeNode(top1, resources, node->Inputs[0]->GetLink(0)->Parent);
ExposeNode(top2, resources, node->Inputs[1]->GetLink(0)->Parent);
ExposeNode(top3, resources, node->Inputs[2]->GetLink(0)->Parent);
String tn = TypeToStr(MaxType(node->Inputs[0]->GetLink(0)->DataType, node->Inputs[1]->GetLink(0)->DataType));
String cn = NewVarName(node->Name);
sprintf(&tmp[0], "%s %s = lerp((%s),(%s),(%s));", tn.c_str(), cn.c_str(), node->Inputs[0]->GetLink(0)->Value.c_str(),
node->Inputs[1]->GetLink(0)->Value.c_str(), node->Inputs[2]->GetLink(0)->Value.c_str());
node->Outputs[0]->DataType = MaxType(node->Inputs[0]->GetLink(0)->DataType, node->Inputs[1]->GetLink(0)->DataType);
shader = top1 + top2 + top3 + String(tmp) + shader;
node->Outputs[0]->Value = cn;
}
else if(node->Name == STR("SrcTex2D"))
{
//check UV input slot
if(!node->Inputs[0]->GetLinkCount()){
shader = String("ERROR_EXPRESSION") + shader; return;}
String top1;
ExposeNode(top1, resources, node->Inputs[0]->GetLink(0)->Parent);
//String tn = TypeToStr(node->Inputs[0]->Link->DataType);
String cn = NewVarName(node->Name);
node->resource_id = lastTexSlot;
//generate header's texture definition
sprintf(&tmp[0], "Texture2D SrcTexture2D%i : register(t%i);\n", lastTexSlot, lastTexSlot);
//write texture definition to the shader's header
ShaderTextureMapping mapping;
mapping.reg = node->resource_id;
mapping.name = String("SrcTexture2D") + Int32ToString(node->resource_id);
mapping.nodeId = node->id;
inputInfo.Textures.push_back(mapping);
resources += String(tmp);
sprintf(&tmp[0], "float4 %s = SrcTexture2D%i.Sample(linearSampler, %s);\n", cn.c_str(), node->resource_id, node->Inputs[0]->GetLink(0)->Value.c_str());
shader = top1 + String(tmp) + shader;
node->Outputs[0]->Value = cn + STR(".xyzw");
node->Outputs[1]->Value = cn + STR(".xxxx");
node->Outputs[2]->Value = cn + STR(".yyyy");
node->Outputs[3]->Value = cn + STR(".zzzz");
node->Outputs[4]->Value = cn + STR(".wwww");
lastTexSlot++;
}
else if(node->Name == STR("SrcUV"))
{
LifeCore::IProperty* channelProp;
if(!node->GetPropertyByAttribute(STR("Name"), STR("Channel"), &channelProp))
{
printf("Failed to get \"Channel\" Property from UV node!\n");
getchar();
exit(0);
}
node->Outputs[0]->Value = STR("Input.Texcoord") + channelProp->ToString() + STR(".xy");
}
else if(node->Name == STR("DecodeNormal"))
{
String top1;
ExposeNode(top1, resources, node->Inputs[0]->GetLink(0)->Parent);
String cn = NewVarName(node->Name);
sprintf(&tmp[0], "float3 %s = normalize(((%s).xyz * 2.0f) - 1.0f);", cn.c_str(), node->Inputs[0]->GetLink(0)->Value.c_str());
String src1(tmp);
sprintf(&tmp[0], "%s = normalize((%s).x * normalize(Input.Tangent) + (%s).y * normalize(Input.Binormal) + (%s).z * normalize(Input.Normal.xyz));", cn.c_str(), cn.c_str(),cn.c_str(),cn.c_str());
String src2(tmp);
sprintf(&tmp[0], "%s = (%s).xyz * 0.5f + 0.5f;", cn.c_str(), cn.c_str());
String src3(tmp);
shader = top1 + src1 + src2 + src3 + shader;
node->Outputs[0]->Value = cn;
/*
float3 n = normalize(nn.x * normalize(Input.Tangent) + nn.y * normalize(Input.Binormal) + nn.z * normalize(Input.Normal.xyz));
*/
}
else
{
shader = String("ERROR_EXPRESSION") + shader;
return;
}
}
// delete[] tmp;
}
void ShaderGraphCompilerHLSL::RemoveChecked(IShaderGraphNode* node)
{
node->checked = false;
for(IShaderGraphNode::PortCollectionItr it = node->Inputs.begin(); it != node->Inputs.end(); ++it)
{
IShaderGraphNodePort* port = *it; //my input port
if(port->GetLinkCount())
{
RemoveChecked(port->GetLink(0)->Parent);
}
}
}
void ShaderGraphCompilerHLSL::CompileNode(IShaderGraphNode* rootNode, int flags, String& ps, String& vs, ShaderInputInfo* info)
{
//remove "checked" flag from all nodes
lastTexSlot = 0;
inputInfo.Clear();
RemoveChecked(rootNode);
String per_object_cb = "cbuffer perObjectData : register(b0){row_major matrix mWorld;};\n";
String per_camera_cb =
"cbuffer perCameraData : register(b1)\n" \
"{\n" \
" row_major matrix matView;\n" \
" row_major matrix matProjection;\n" \
" row_major matrix matVP;\n" \
" float4 camPos;\n" \
" float4 camDir;\n" \
" float4 camNearFarVPWH;\n" \
" float4 corners[4];\n" \
"};\n";
/*per_camera_cb +=
"cbuffer materialData : register(b2){\n" \
"float shininess : packoffset(c0.x);\n" \
"float specularPower : packoffset(c0.y);\n" \
"float2 materialDummy : packoffset(c0.z);};\n";*/
per_camera_cb +=
"cbuffer sceneData : register(b3){\n" \
"float sceneTime : packoffset(c0.x);\n" \
"float3 sceneAmbient : packoffset(c0.y);};\n";
String shader;
String resources;
resources +=
"SamplerState linearSampler : register(s0);\n" \
"SamplerState pointSampler : register(s1);\n";
if(rootNode->Name != STR("Material"))
return;
int inSlotCount = rootNode->Inputs.size();
String diffuse_code;
String normal_code;
String specular_code;
String specular_power_code;
for(int i = 0; i < inSlotCount; i++)
{
String shader_tmp;
IShaderGraphNodePort* port = rootNode->Inputs[i];
if(port->Name == STR("Diffuse"))
{
if(port->GetLinkCount())
{
ExposeNode(shader_tmp, resources, port->GetLink(0)->Parent);
diffuse_code = port->GetLink(0)->Value;
}
}
else if(port->Name == STR("Normal"))
{
if(port->GetLinkCount())
{
ExposeNode(shader_tmp, resources, port->GetLink(0)->Parent);
normal_code = port->GetLink(0)->Value;
}
else
{
normal_code = "(Input.Normal * 0.5f + 0.5f)";
}
}
else if(port->Name == STR("Specular"))
{
if(port->GetLinkCount())
{
ExposeNode(shader_tmp, resources, port->GetLink(0)->Parent);
specular_code = port->GetLink(0)->Value;
}
else
{
specular_code = STR("0.0f");
}
}
else if(port->Name == STR("SpecularPower"))
{
if(port->GetLinkCount())
{
ExposeNode(shader_tmp, resources, port->GetLink(0)->Parent);
specular_power_code = port->GetLink(0)->Value;
}
else
{
specular_power_code = STR("0.0f");
}
}
shader = shader + shader_tmp + STR("\n");
}
String ps_input_struct =
"struct PS_INPUT \n" \
"{\n"\
" float4 Position : SV_Position;\n"\
" float2 Texcoord0 : TEXCOORD0;\n"\
" float4 Normal : TEXCOORD1;\n"\
" float3 wPos : TEXCOORD2;\n"\
" float3 Tangent : TEXCOORD3;\n"\
" float3 Binormal : TEXCOORD4;\n"\
" float4 ePos : TEXCOORD5;\n"\
"};\n";
String ps_output_struct =
"struct PS_OUT\n" \
"{\n" \
" float4 color0 : SV_Target0;\n" \
" float4 color1 : SV_Target1;\n" \
" float2 color2 : SV_Target2;\n" \
"};\n";
String final;
String func =
"PS_OUT main_PS( PS_INPUT Input )\n{\n"\
"PS_OUT output;\nfloat dist = length(Input.wPos - camPos);\nfloat ez = Input.Normal.w / camNearFarVPWH.y;\n";
func +=
"Input.Tangent.x*=-1; Input.Binormal.x*=-1;\n";
String out_albedo_refl =
"//albedo and reflection\noutput.color0 = float4((";
out_albedo_refl = out_albedo_refl + diffuse_code + STR(").xyz,") + specular_code + STR(");\n");
String out_normal_gloss =
"//normal and glossiness\noutput.color1 = float4((";
out_normal_gloss = out_normal_gloss + normal_code + STR(").xyz,") + specular_power_code + STR(");\n");
String out_depth =
"//depth info\noutput.color2 = float2(dist, ez);\n";
final = resources + per_object_cb + per_camera_cb + ps_input_struct + ps_output_struct + func + shader + out_albedo_refl + out_normal_gloss + out_depth + String("return output;\n}\n");
ps = final;
//generate vertex shader
String shader_vs;
//per object constant buffer
shader_vs += per_object_cb;
//per camera constant buffer
shader_vs += per_camera_cb;
//bones constant buffer (only for skinned meshes)
if((flags & SCF_SKINNING) != 0)
{
shader_vs +=
"cbuffer skinData : register(b5)\n" \
"{row_major matrix boneMatrix[MAX_BONES_COUNT];};\n";
}
//vertex shader input data structure
shader_vs +=
"struct VS_INPUT {\n" \
"float4 Position : POSITION;\n" \
"float2 Texcoord : TEXCOORD;\n" \
"float3 Normal : NORMAL;\n" \
"float3 Tangent : TANGENT;\n" \
"float3 Binormal : BINORMAL;\n";
//add skinning info
if((flags & SCF_SKINNING) != 0)
{
shader_vs +=
"float4 BlendIndices : BLENDINDICES;\n" \
"float4 BlendWeights : BLENDWEIGHT;\n";
}
//close structure
shader_vs += "};\n";
//shader output data structure
shader_vs +=
"struct VS_OUTPUT \n" \
"{\n" \
" float4 Position : SV_Position;\n" \
" float2 Texcoord : TEXCOORD0;\n" \
" float4 Normal : TEXCOORD1;\n" \
" float3 wPos : TEXCOORD2;\n" \
" float3 Tangent : TEXCOORD3;\n" \
" float3 Binormal : TEXCOORD4;\n" \
" float4 ePos : TEXCOORD5;\n" \
"};\n";
//add skinning function for skinned meshes
if((flags & SCF_SKINNING) != 0)
{
shader_vs +=
"float4 SkinVertex(float4 position, float4 index, float4 weight)\n" \
"{\n" \
" float4 pos = float4(0,0,0,0);\n" \
" int IndexArray[4] = (int[4])(index);\n" \
" float WeightArray[4] = (float[4])(weight);\n" \
" float LastWeight = 0.0f;\n" \
" int nb = 0;\n" \
" for(int i = 0; i < 4;i++)\n" \
" {\n" \
" if(WeightArray[i]==0)\n" \
" {\n" \
" nb = i;\n" \
" }\n" \
" LastWeight = LastWeight + WeightArray[i];\n" \
" pos = pos + mul(position, boneMatrix[IndexArray[i]] * WeightArray[i]);\n" \
" }\n" \
" pos = pos + mul(position, boneMatrix[IndexArray[nb]]* (1.0f - LastWeight));\n" \
" return pos;\n" \
"}\n";
}
//main vertex shader function
//function header
shader_vs +=
"VS_OUTPUT main_VS( VS_INPUT Input ){\n" \
"VS_OUTPUT Output = (VS_OUTPUT)0;\n";
//vertex transformation (skinned/not skinned)
if((flags & SCF_SKINNING) != 0) //skinned
{
shader_vs +=
"Output.Position = SkinVertex(Input.Position, Input.BlendIndices, Input.BlendWeights);\n" \
"Output.wPos = mul(float4(Output.Position.xyz, 1.0f), mWorld);\n" \
"Output.Position = mul(float4(Output.wPos.xyz, 1.0f), matVP);\n";
}
else
{
shader_vs +=
"Output.wPos = mul(float4(Input.Position.xyz, 1.0f), mWorld); \n" \
"Output.Position = mul(float4(Output.wPos.xyz, 1.0f), matVP); \n";
}
//tail
shader_vs +=
"Output.Texcoord = Input.Texcoord;\n" \
"float3x3 mWorldNT = (float3x3)mWorld;\n" \
"Output.ePos = Output.Position;\n" \
"Output.Normal = float4(mul(Input.Normal, mWorldNT), mul(float4(Output.wPos, 1.0f), matView).z);\n" \
"Output.Tangent = mul(Input.Tangent, mWorldNT);\n" \
"Output.Binormal = mul(Input.Binormal, mWorldNT);\n" \
"return Output;\n" \
"}\n";
vs = shader_vs;
*info = inputInfo;
}
}
@@ -0,0 +1,24 @@
#ifndef ShaderGraphCompilerHLSL_h__
#define ShaderGraphCompilerHLSL_h__
#include "shaders/IShaderGraphCompiler.h"
namespace LifeGraphics
{
class ShaderGraphCompilerHLSL : public IShaderGraphCompiler
{
public:
ShaderGraphCompilerHLSL();
void CompileNode(IShaderGraphNode* rootNode, int flags, String& ps, String& vs, ShaderInputInfo* info);
private:
ShaderInputInfo inputInfo;
int lastTexSlot;
void RemoveChecked(IShaderGraphNode* node);
String NewVarName(const String& baseName);
int var_id;
void ExposeNode(String& shader, String& resources, IShaderGraphNode* node);
String TypeToStr(IShaderDataType t);
};
}
#endif // ShaderGraphCompilerHLSL_h__