*
This commit is contained in:
@@ -0,0 +1,531 @@
|
||||
#include "GUINodeContainer.h"
|
||||
#include <gui/GUIManager.h>
|
||||
#include <math/Spline.h>
|
||||
#include <Property.h>
|
||||
#include <gui/PropertyItemFile.h>
|
||||
#include "GUIShaderNodeTexture.h"
|
||||
#include "EditorShared.h"
|
||||
|
||||
GUINodeContainer::GUINodeContainer(IShaderGraph* graph)
|
||||
:cache_length(0)
|
||||
{
|
||||
graphics_graph = graph;
|
||||
//skip_mouse = true;
|
||||
menu = new GUIMenu(true);
|
||||
}
|
||||
|
||||
GUIShaderNode* GUINodeContainer::FindNodeByGraphicsID(int id)
|
||||
{
|
||||
int node_count = GetNodeCount();
|
||||
for(int i = 0; i < node_count; i++){
|
||||
GUIShaderNode* node = nodes[i];
|
||||
if(node->GetGraphicsNode()->id == id)
|
||||
return node;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
bool GUINodeContainer::Serialize(Core::IMemoryStream* stm)
|
||||
{
|
||||
int node_count = GetNodeCount();
|
||||
stm->Write(node_count);
|
||||
|
||||
for(int i = 0; i < node_count; i++){
|
||||
GUIShaderNode* node = nodes[i];
|
||||
stm->Write(node->GetGraphicsNode()->id);
|
||||
stm->Write(node->GetPosition().X);
|
||||
stm->Write(node->GetPosition().Y);
|
||||
stm->Write(node->GetWidth());
|
||||
stm->Write(node->GetHeight());
|
||||
StringSerialize(node->GetCaption(), stm);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool GUINodeContainer::Deserialize(Core::IMemoryStream* stm)
|
||||
{
|
||||
int node_count;
|
||||
stm->ReadInt32(node_count);
|
||||
|
||||
for(int i = 0; i < node_count; i++){
|
||||
int graphics_id;
|
||||
int pos_x, pos_y;
|
||||
int node_width, node_height;
|
||||
String caption;
|
||||
GUIShaderNode* node;
|
||||
|
||||
stm->ReadInt32(graphics_id);
|
||||
stm->ReadInt32(pos_x);
|
||||
stm->ReadInt32(pos_y);
|
||||
stm->ReadInt32(node_width);
|
||||
stm->ReadInt32(node_height);
|
||||
caption = StringDeserialize(stm);
|
||||
|
||||
node = FindNodeByGraphicsID(graphics_id);
|
||||
|
||||
if(node != nullptr){
|
||||
node->SetPosition(Vec2i(pos_x, pos_y));
|
||||
node->SetWidth(node_width);
|
||||
node->SetHeight(node_height);
|
||||
node->SetCaption(caption);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void GUINodeContainer::MakeLink(GUIShaderNodeIO* left, GUIShaderNodeIO* right)
|
||||
{
|
||||
LinkInfo info;
|
||||
info.left = left;
|
||||
info.right = right;
|
||||
links.push_back(info);
|
||||
Invalidate();
|
||||
}
|
||||
void GUINodeContainer::BreakLink(GUIShaderNodeIO* left, GUIShaderNodeIO* right)
|
||||
{
|
||||
for(LinksCollectionItr it = links.begin(); it != links.end(); ++it)
|
||||
{
|
||||
LinkInfo info = *it;
|
||||
if((info.left == left && info.right == right) ||
|
||||
(info.left == right && info.right == left))
|
||||
{
|
||||
links.erase(it);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GUINodeContainer::OnNodeSelect(GUIShaderNode* node)
|
||||
{
|
||||
EditorShared::me()->propGrid->SetTarget(node);
|
||||
}
|
||||
NodeCollection* GUINodeContainer::GetTextureUnits()
|
||||
{
|
||||
return &texNodes;
|
||||
}
|
||||
void GUINodeContainer::SetSelection(GUIShaderNode* node)
|
||||
{
|
||||
selection = node;
|
||||
}
|
||||
void GUINodeContainer::OnNodeHeaderMouseClick(GUIWindow* wnd, int param)
|
||||
{
|
||||
if(param == KEY_MOUSE_RIGHT)
|
||||
{
|
||||
this->SetSelection((GUIShaderNode*)wnd);
|
||||
menu->RemoveItems();
|
||||
menu->AddItem(STR("Delete node"), false)->Event_Select += NewDelegate(this, &GUINodeContainer::OnDeleteNode);
|
||||
menu->SetPosition(FindOverlay()->cursorPos);
|
||||
|
||||
|
||||
FindOverlay()->AddChild(menu);
|
||||
FindOverlay()->SetFocusWindow(menu);
|
||||
}
|
||||
}
|
||||
|
||||
void GUINodeContainer::OnDeleteNode(GUIMenuItem* itm)
|
||||
{
|
||||
DeleteNode(selection);
|
||||
}
|
||||
void GUINodeContainer::DeleteNode(GUIShaderNode* node)
|
||||
{
|
||||
Event_DeleteNode.Invoke(this, node);
|
||||
this->RemoveChild(node->hwnd);
|
||||
graphics_graph->DeleteNode(node->GetGraphicsNode()->id);
|
||||
|
||||
|
||||
restart_delete_links:
|
||||
for(LinksCollectionItr it = links.begin(); it != links.end(); ++it)
|
||||
{
|
||||
if((*it).left->Owner == node || (*it).right->Owner == node)
|
||||
{
|
||||
links.erase(it);
|
||||
goto restart_delete_links;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
for(NodeCollectionItr it = nodes.begin(); it != nodes.end(); it++)
|
||||
{
|
||||
if((*it)->ID == node->ID)
|
||||
{
|
||||
nodes.erase(it);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
done:
|
||||
delete node;
|
||||
Invalidate();
|
||||
}
|
||||
void GUINodeContainer::RegisterNewNode(GUIShaderNode* node)
|
||||
{
|
||||
nodes.push_back(node);
|
||||
node->Event_HeaderClick += NewDelegate(this, &GUINodeContainer::OnNodeHeaderMouseClick);
|
||||
}
|
||||
void GUINodeContainer::RebuildGraph()
|
||||
{
|
||||
//remove all nodes firstly
|
||||
for(NodeCollectionItr it = nodes.begin(); it != nodes.end(); it++)
|
||||
{
|
||||
//Event_DeleteNode.Invoke(this, node);
|
||||
this->RemoveChild((*it)->hwnd);
|
||||
delete (*it);
|
||||
}
|
||||
nodes.clear();
|
||||
|
||||
links.clear();
|
||||
|
||||
|
||||
int cnt = graphics_graph->GetNodeCount();
|
||||
|
||||
//build nodes
|
||||
for(int k = 0; k < cnt; k++)
|
||||
{
|
||||
IShaderGraphNode* gn = graphics_graph->GetNodeByArrayID(k);
|
||||
GUIShaderNode* node;
|
||||
|
||||
if(gn->Name == STR("SrcTex2D")){
|
||||
node = new GUIShaderNodeTexture(gn);
|
||||
texNodes.push_back(node);
|
||||
}
|
||||
else
|
||||
node = new GUIShaderNode(gn);
|
||||
|
||||
//copy all properties =)
|
||||
PropertyCollection* props = gn->GetProperties();
|
||||
for(int i = 0; i < props->size(); i++)
|
||||
{
|
||||
IProperty* prop = (*props)[i];
|
||||
prop->Event_ValueChanged.Invoke();
|
||||
node->RegisterProperty(prop);
|
||||
}
|
||||
|
||||
node->Event_Select += NewDelegate(this, &GUINodeContainer::OnNodeSelect);
|
||||
|
||||
node->SetCaption(gn->Name);
|
||||
int in_count = gn->Inputs.size();
|
||||
int out_count = gn->Outputs.size();
|
||||
|
||||
//create input ports
|
||||
for(int i = 0; i < in_count; i++)
|
||||
{
|
||||
IShaderGraphNodePort* port = gn->Inputs[i];
|
||||
GUIShaderNodeIO* io = new GUIShaderNodeIO(node);
|
||||
io->SetCaption(port->Name);
|
||||
node->AddInput(io);
|
||||
io->GraphicsPort = port;
|
||||
io->Event_PortClick += NewDelegate(this, &GUINodeContainer::OnNodePortMouseClick);
|
||||
}
|
||||
|
||||
//create output ports
|
||||
for(int i = 0; i < out_count; i++)
|
||||
{
|
||||
IShaderGraphNodePort* port = gn->Outputs[i];
|
||||
GUIShaderNodeIO* io = new GUIShaderNodeIO(node);
|
||||
io->SetCaption(port->Name);
|
||||
io->GraphicsPort = port;
|
||||
io->Event_PortClick += NewDelegate(this, &GUINodeContainer::OnNodePortMouseClick);
|
||||
node->AddOutput(io);
|
||||
}
|
||||
|
||||
if(name == STR("Material"))
|
||||
{
|
||||
materialNode = node;
|
||||
}
|
||||
AddChild(node);
|
||||
RegisterNewNode(node);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//build links
|
||||
cnt = nodes.size();
|
||||
for(int k = 0; k < cnt; k++)
|
||||
{
|
||||
GUIShaderNode* node = nodes[k];
|
||||
IShaderGraphNode* n = node->GetGraphicsNode();
|
||||
int inc = n->Inputs.size();
|
||||
|
||||
for(int c = 0; c < inc; c++)
|
||||
{
|
||||
//make link
|
||||
if(n->Inputs[c]->GetLinkCount())
|
||||
{
|
||||
IShaderGraphNodePort* right_port = n->Inputs[c]->GetLink(0);
|
||||
//get right node
|
||||
GUIShaderNode* rn = this->FindNode(right_port->Parent->id);
|
||||
|
||||
int roc = rn->GetOutputCount();
|
||||
|
||||
int rightId = -1;
|
||||
for(int m = 0; m < roc; m++)
|
||||
{
|
||||
if(rn->GetGraphicsNode()->GetOutputPortByID(m) == right_port)
|
||||
{
|
||||
rightId = m;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//found right side link - make it!
|
||||
if(rightId >=0)
|
||||
{
|
||||
MakeLink(node->GetInput(c), rn->GetOutput(rightId));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
String GUINodeContainer::GetTexNameByID(int id)
|
||||
{
|
||||
int cnt = nodes.size();
|
||||
for(int i = 0; i < cnt; i++)
|
||||
{
|
||||
if(nodes[i]->GetGraphicsNode()->id == id)
|
||||
{
|
||||
GUIShaderNodeTexture* tn = (GUIShaderNodeTexture*)nodes[i];
|
||||
return tn->GetFilename();
|
||||
}
|
||||
}
|
||||
return "TexNotFound";
|
||||
}
|
||||
GUIShaderNode* GUINodeContainer::FindNode(int id)
|
||||
{
|
||||
int cnt = nodes.size();
|
||||
for(int k = 0; k < cnt; k++)
|
||||
{
|
||||
GUIShaderNode* node = nodes[k];
|
||||
if(node->GetGraphicsNode()->id == id)
|
||||
return node;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
GUIShaderNode* GUINodeContainer::AddNode(const String& name)
|
||||
{
|
||||
IShaderGraphNode* gn = graphics_graph->AddNode(name);
|
||||
GUIShaderNode* node;
|
||||
|
||||
if(name == STR("SrcTex2D"))
|
||||
{
|
||||
node = new GUIShaderNodeTexture(gn);
|
||||
texNodes.push_back(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
node = new GUIShaderNode(gn);
|
||||
}
|
||||
|
||||
//copy all properties =)
|
||||
PropertyCollection* props = gn->GetProperties();
|
||||
for(int i = 0; i < props->size(); i++)
|
||||
{
|
||||
IProperty* prop = (*props)[i];
|
||||
node->RegisterProperty(prop);
|
||||
}
|
||||
|
||||
node->Event_Select += NewDelegate(this, &GUINodeContainer::OnNodeSelect);
|
||||
|
||||
int in_count = gn->Inputs.size();
|
||||
int out_count = gn->Outputs.size();
|
||||
|
||||
//create input ports
|
||||
for(int i = 0; i < in_count; i++)
|
||||
{
|
||||
IShaderGraphNodePort* port = gn->Inputs[i];
|
||||
GUIShaderNodeIO* io = new GUIShaderNodeIO(node);
|
||||
io->SetCaption(port->Name);
|
||||
node->AddInput(io);
|
||||
io->GraphicsPort = port;
|
||||
io->Event_PortClick += NewDelegate(this, &GUINodeContainer::OnNodePortMouseClick);
|
||||
}
|
||||
|
||||
//create output ports
|
||||
for(int i = 0; i < out_count; i++)
|
||||
{
|
||||
IShaderGraphNodePort* port = gn->Outputs[i];
|
||||
GUIShaderNodeIO* io = new GUIShaderNodeIO(node);
|
||||
io->SetCaption(port->Name);
|
||||
node->AddOutput(io);
|
||||
io->GraphicsPort = port;
|
||||
io->Event_PortClick += NewDelegate(this, &GUINodeContainer::OnNodePortMouseClick);
|
||||
}
|
||||
|
||||
if(name == STR("Material"))
|
||||
{
|
||||
materialNode = node;
|
||||
}
|
||||
AddChild(node);
|
||||
RegisterNewNode(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
void GUINodeContainer::OnDeleteLink(GUIMenuItem* itm)
|
||||
{
|
||||
selected_port->GraphicsPort->BreakLink();
|
||||
|
||||
restart_delete_links:
|
||||
for(LinksCollectionItr it = links.begin(); it != links.end(); ++it)
|
||||
{
|
||||
if((*it).left == selected_port || (*it).right == selected_port)
|
||||
{
|
||||
links.erase(it);
|
||||
goto restart_delete_links;
|
||||
}
|
||||
}
|
||||
Invalidate();
|
||||
}
|
||||
void GUINodeContainer::OnNodePortMouseClick(GUIWindow* wnd, int param)
|
||||
{
|
||||
//right click on node IO port
|
||||
if(param == KEY_MOUSE_RIGHT)
|
||||
{
|
||||
menu->RemoveItems();
|
||||
selected_port = (GUIShaderNodeIO*)wnd;
|
||||
menu->AddItem("Delete links", false)->Event_Select += NewDelegate(this, &GUINodeContainer::OnDeleteLink);
|
||||
menu->SetPosition(FindOverlay()->cursorPos);
|
||||
FindOverlay()->AddChild(menu);
|
||||
FindOverlay()->SetFocusWindow(menu);
|
||||
}
|
||||
}
|
||||
void GUINodeContainer::OnNodeLayoutUpdate()
|
||||
{
|
||||
Invalidate();
|
||||
}
|
||||
GUINodeContainer::~GUINodeContainer()
|
||||
{
|
||||
}
|
||||
void GUINodeContainer::SetBackColor(const Vec4f& color)
|
||||
{
|
||||
}
|
||||
void GUINodeContainer::GenGeom()
|
||||
{
|
||||
cache_length = 0;
|
||||
|
||||
int lc = links.size();
|
||||
|
||||
for(int i = 0; i < lc; i++)
|
||||
{
|
||||
LinkInfo info = links[i];
|
||||
Vec2i p1 = info.left->GetAttachPoint();
|
||||
Vec2i p2;
|
||||
Vec2i p3;
|
||||
Vec2i p4 = info.right->GetAttachPoint();
|
||||
|
||||
//if input - shift to right
|
||||
if(info.left->IsInput())
|
||||
{
|
||||
p2 = p1 + Vec2i(50, 0);
|
||||
p3 = p4 + Vec2i(-50, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
p2 = p1 + Vec2i(-50, 0);
|
||||
p3 = p4 + Vec2i(50, 0);
|
||||
}
|
||||
|
||||
GUIVertex points[4];
|
||||
points[0].Color = Vec4f(1,1,1,1);
|
||||
points[1].Color = Vec4f(1,1,1,1);
|
||||
points[2].Color = Vec4f(1,1,1,1);
|
||||
points[3].Color = Vec4f(1,1,1,1);
|
||||
|
||||
points[0].Position = Vec3f((float)p1.X, (float)p1.Y, 0);
|
||||
points[1].Position = Vec3f((float)p2.X, (float)p2.Y, 0);
|
||||
points[2].Position = Vec3f((float)p3.X, (float)p3.Y, 0);
|
||||
points[3].Position = Vec3f((float)p4.X, (float)p4.Y, 0);
|
||||
|
||||
//we have 4 points! now we have to convert them to cubic spline
|
||||
int offset = 0;
|
||||
GUIVertex prev;
|
||||
prev = points[0];
|
||||
for(int i = 1; i <= SPLINE_FREQ; i++)
|
||||
{
|
||||
GUIVertex newP = Core::CubicBezier<GUIVertex>((1.0f / (float)SPLINE_FREQ) * (float)i, points[0], points[1], points[2], points[3]);
|
||||
cache[offset++] = prev;
|
||||
cache[offset++] = newP;
|
||||
|
||||
prev = newP;
|
||||
}
|
||||
|
||||
offset = 0;
|
||||
|
||||
Rect2i sc = GetScissor();
|
||||
|
||||
GUIVertex tmp;
|
||||
//all spline points generated! Now it's time to cut them by owner's client rectangle
|
||||
for(int i = 0; i < SPLINE_FREQ; i++)
|
||||
{
|
||||
GUIVertex v1 = cache[i * 2];
|
||||
GUIVertex v2 = cache[i * 2 + 1];
|
||||
|
||||
//test is vertices are visible
|
||||
if(v1.Position.X < sc.x && v2.Position.X < sc.x) continue;
|
||||
if(v1.Position.X > sc.GetMaxX() && v2.Position.X > sc.GetMaxX()) continue;
|
||||
if(v1.Position.Y < sc.y && v2.Position.Y < sc.y) continue;
|
||||
if(v1.Position.Y > sc.GetMaxY() && v2.Position.Y > sc.GetMaxY()) continue;
|
||||
|
||||
//sort vertices
|
||||
if(v1.Position.X > v2.Position.X)
|
||||
{
|
||||
tmp = v1;
|
||||
v1 = v2;
|
||||
v2 = tmp;
|
||||
}
|
||||
//crop right side
|
||||
if(v2.Position.X > sc.GetMaxX())
|
||||
{
|
||||
float slope = (v2.Position.Y - v1.Position.Y) / (v2.Position.X - v1.Position.X);
|
||||
float xd = v2.Position.X - float(sc.GetMaxX());
|
||||
v2.Position.X -= xd;
|
||||
v2.Position.Y -= xd * slope;
|
||||
}
|
||||
//crop left side
|
||||
if(v1.Position.X < sc.x)
|
||||
{
|
||||
float slope = (v2.Position.Y - v1.Position.Y) / (v2.Position.X - v1.Position.X);
|
||||
float xd = sc.x - v1.Position.X;
|
||||
v1.Position.X += xd;
|
||||
v1.Position.Y += xd * slope;
|
||||
}
|
||||
|
||||
//sort vertices
|
||||
if(v1.Position.Y > v2.Position.Y)
|
||||
{
|
||||
tmp = v1;
|
||||
v1 = v2;
|
||||
v2 = tmp;
|
||||
}
|
||||
//crop bottom side
|
||||
if(v2.Position.Y > sc.GetMaxY())
|
||||
{
|
||||
float slope = (v2.Position.X - v1.Position.X) / (v2.Position.Y - v1.Position.Y);
|
||||
float yd = v2.Position.Y - float(sc.GetMaxY());
|
||||
v2.Position.X -= yd * slope;
|
||||
v2.Position.Y -= yd;
|
||||
}
|
||||
//crop top side
|
||||
if(v1.Position.Y < sc.y)
|
||||
{
|
||||
float slope = (v2.Position.X - v1.Position.X) / (v2.Position.Y - v1.Position.Y);
|
||||
float yd = sc.y - v1.Position.Y;
|
||||
v1.Position.X += yd * slope;
|
||||
v1.Position.Y += yd;
|
||||
}
|
||||
|
||||
cache2[cache_length++] = v1;
|
||||
cache2[cache_length++] = v2;
|
||||
}
|
||||
}
|
||||
invalid = false;
|
||||
}
|
||||
void GUINodeContainer::RenderSelf()
|
||||
{
|
||||
if(invalid)
|
||||
GenGeom();
|
||||
|
||||
if(cache_length)
|
||||
{
|
||||
Video::IGUIRenderer* renderer = GUIManager::me()->GetRenderer();
|
||||
renderer->SetTexture(GUIManager::me()->DIFF, 0, true);
|
||||
renderer->Write(&cache2[0], cache_length);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user