void Update() override final { if (lastActivated >= 0) { InputPort<AnyType>* port = static_cast<InputPort<AnyType>*>(GetInput(lastActivated)); GetOutput<0>().Set(*port->Get()); lastActivated = -1; } }
void Update() override final { if (lastActivated >= 0 && activationMap == 0b11'1111) { InputPort<AnyType>* port = static_cast<InputPort<AnyType>*>(GetInput(lastActivated+1)); GetOutput<0>().Set(*port->Get()); } }
void MaterialShaderGraph::AssembleShaderCode() { std::vector<ShaderNode> shaderNodes(m_nodes.size()); std::vector<std::vector<MaterialShaderParameter>> shaderNodeParams(m_nodes.size()); std::vector<eMaterialShaderParamType> shaderNodeReturns(m_nodes.size()); std::vector<std::string> functions(m_nodes.size()); // collect individual shader codes and set number of input params for each node for (size_t i = 0; i < m_nodes.size(); ++i) { MaterialShader* shader = m_nodes[i].get(); functions[i] = shader->GetShaderCode(); ExtractShaderParameters(functions[i], "main", shaderNodeReturns[i], shaderNodeParams[i]); for (auto p : shaderNodeParams[i]) { if (p.type == eMaterialShaderParamType::UNKNOWN) { throw InvalidArgumentException("Parameter of unknown type."); } } shaderNodes[i].SetNumInputs(shaderNodeParams[i].size()); } // link nodes together for (const auto& link : m_links) { ShaderNode& source = shaderNodes[link.sourceNode]; ShaderNode& sink = shaderNodes[link.sinkNode]; if (sink.GetNumInputs() <= link.sinkPort) { throw InvalidArgumentException("Invalid link: port does not have that many inputs."); } bool isLinked = source.GetOutput(0)->Link(sink.GetInput(link.sinkPort)); if (!isLinked) { throw InvalidArgumentException("Invalid link: duplicate input to a single port."); } } // create output port LUT std::unordered_map<OutputPortBase*, size_t> outputLut; for (size_t i = 0; i < shaderNodes.size(); ++i) { outputLut.insert({ shaderNodes[i].GetOutput(0), i }); } // get the sink node size_t sinkNodeIdx = -1; for (size_t i = 0; i < shaderNodes.size(); ++i) { if (shaderNodes[i].GetOutput(0)->begin() == shaderNodes[i].GetOutput(0)->end()) { if (sinkNodeIdx != -1) { throw InvalidArgumentException("Invalid graph: multiple sink nodes."); } sinkNodeIdx = i; } } if (sinkNodeIdx == -1) { throw InvalidArgumentException("Invalid graph: no sink nodes, contains circle."); } // run backwards DFS from sink node // - get topological order // - get list of free params struct FreeParam { size_t node, input; std::string name; }; std::vector<size_t> topologicalOrder; std::vector<bool> visited(shaderNodes.size(), false); std::vector<FreeParam> freeParams; auto VisitNode = [&](size_t node, auto& self) { if (visited[node]) { return; } visited[node] = true; for (int i = 0; i < shaderNodes[node].GetNumInputs(); ++i) { auto* input = shaderNodes[node].GetInput(i); if (input->GetLink() != nullptr) { auto* linkOutput = input->GetLink(); size_t linkNode = outputLut[linkOutput]; self(linkNode, self); } else { std::stringstream ss; ss << m_nodes[node]->GetName() << "__" << shaderNodeParams[node][i].name; static_cast<InputPort<std::string>*>(input)->Set(ss.str()); freeParams.push_back({ node, (size_t)i, ss.str() }); } } std::stringstream ss; ss << "main_" << topologicalOrder.size(); shaderNodes[node].SetFunctionName(ss.str()); functions[node] = std::regex_replace(functions[node], std::regex("main"), ss.str()); topologicalOrder.push_back(node); shaderNodes[node].SetFunctionReturn(GetParameterString(shaderNodeReturns[node])); }; // attach final input port to sink node, and update according to topological order InputPort<std::string> finalCodePort; shaderNodes[sinkNodeIdx].GetOutput(0)->Link(&finalCodePort); VisitNode(sinkNodeIdx, VisitNode); for (auto idx : topologicalOrder) { shaderNodes[idx].Update(); } // assemble resulting code std::stringstream finalCode; // sub-functions for (auto node : topologicalOrder) { finalCode << functions[node] << "\n"; } finalCode << "\n\n"; // signature std::string returnType = GetParameterString(shaderNodeReturns[*--topologicalOrder.end()]); finalCode << returnType << " main("; bool firstParam = true; for (auto& p : freeParams) { if (!firstParam) finalCode << ", "; finalCode << GetParameterString(shaderNodeParams[p.node][p.input].type) << " "; finalCode << p.name; firstParam = false; } finalCode << ") {\n"; finalCode << "\n"; // preambles for (auto idx : topologicalOrder) { finalCode << " " << shaderNodes[idx].GetPreamble() << "\n"; } finalCode << "\n"; // return statement finalCode << "return " << finalCodePort.Get() << ";\n"; finalCode << "}\n"; m_source = finalCode.str(); }