#include "GUINodeContainer.h" #include #include #include #include #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((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); } }