TerraForge3D  2.3.1
3D Terrain And Landscape Generator
CustomShaderNode.cpp
1#include "Shading/ShaderNodes/CustomShaderNode.h"
2
3#include <iostream>
4#include <sstream>
5#include <regex>
6
7static std::string ReplaceString(std::string subject, const std::string &search,
8 const std::string &replace)
9{
10 size_t pos = 0;
11
12 while((pos = subject.find(search, pos)) != std::string::npos)
13 {
14 subject.replace(pos, search.length(), replace);
15 pos += replace.length();
16 }
17
18 return subject;
19}
20
21void CustomShaderNode::OnEvaluate(GLSLFunction *function, GLSLLine *line)
22{
23 GLSLFunction ft = *func;
24 std::string cline = code;
25 // Add code symbols
26 cline = ReplaceString(cline, "{ID}", STR(id));
27 cline = ReplaceString(cline, "{OFFSET}", STR(dataBlobOffset));
28 int did = 0;
29 for(auto it : sharedDataTemplate)
30 {
31 cline = ReplaceString(cline, it.alias, SDATA(did));
32 did++;
33 }
34 ft.AddLine(GLSLLine(cline));
35 handler->AddFunction(ft);
36 int i = 0;
37
38 if(!useArrayParams)
39 {
40 i = 0;
41 for(auto &param : params)
42 {
43 function->AddLine(GLSLLine(param.first + " " + VAR(param.second + STR(i)) + " = " + param.first + "(0.0f);"));
44
45 if(inputPins[i]->IsLinked())
46 {
47 GLSLLine tmp("");
48 inputPins[i]->other->Evaluate(GetParams(function, &tmp));
49 function->AddLine(GLSLLine(VAR(param.second + STR(i)) + " = " + tmp.line + ";"));
50 }
51
52 i++;
53 }
54 }
55 else
56 {
57 i = 0;
58 for(auto &param: params)
59 {
60 function->AddLine(GLSLLine(param.first + " " + VAR(param.second + STR(i)) + "[" + STR(paramCount) + "];"));
61 for(int k = 0 ; k < paramCount ; k++)
62 {
63 if (inputPins[k * params.size() + i]->IsLinked())
64 {
65 GLSLLine tmp("");
66 inputPins[k * params.size() + i]->other->Evaluate(GetParams(function, &tmp));
67 function->AddLine(GLSLLine(VAR(param.second + STR(i)) + "[" + STR(k) + "]" + " = " + tmp.line + ";"));
68 }
69 else
70 {
71 function->AddLine(GLSLLine(VAR(param.second + STR(i)) + "[" + STR(k) + "]" + " = " + param.first + "(0.0f);"));
72 }
73 }
74 }
75 i++;
76 }
77
78 line->line = func->name + "(";
79 i = 0;
80 int n = params.size();
81
82 for(auto &param : params)
83 {
84 line->line += VAR(param.second + STR(i));
85
86 if(i < n - 1)
87 {
88 line->line += ", ";
89 }
90
91 i++;
92 }
93 int callerPin = 0;
94 for(int i = 0;i<outputPins.size();i++)
95 {
96 if(outputPins[i]->id == callerPinId)
97 {
98 callerPin = i;
99 break;
100 }
101 }
102 line->line += (params.size() == 0 ? "" : ", ") + STR(callerPin) + ")";
103}
104
105void CustomShaderNode::Load(nlohmann::json data)
106{
107 int i = 0;
108
109 for(auto &it : sharedDataTemplate)
110 {
111 if(it.type == "float")
112 {
113 fData[i] = data[it.alias].get<float>();
114 }
115
116 else if(it.type == "bool")
117 {
118 bData[i] = data[it.alias].get<bool>();
119 }
120
121 i++;
122 }
123}
124
125nlohmann::json CustomShaderNode::Save()
126{
127 nlohmann::json data;
128 data["type"] = "CustomShader";
129 int i = 0;
130
131 for(auto &it : sharedDataTemplate)
132 {
133 if(it.type == "float")
134 {
135 data[it.alias] = fData[i];
136 }
137
138 else if(it.type == "bool")
139 {
140 data[it.alias] = bData[i];
141 }
142
143 i++;
144 }
145
146 data["shader"] = shader;
147 return data;
148}
149
150void CustomShaderNode::UpdateShaders()
151{
152 int i = 0;
153
154 for(auto &it : sharedDataTemplate)
155 {
156 if(i > 31)
157 {
158 break;
159 }
160
161 if(it.type == "float")
162 {
163 SetSharedMemoryItem(sharedData, i, fData[i]);
164 }
165
166 else if(it.type == "bool")
167 {
168 SetSharedMemoryItem(sharedData, i, bData[i] ? 1.0f : 0.0f);
169 }
170
171 i++;
172 }
173}
174
175void CustomShaderNode::OnRender()
176{
177 DrawHeader(name);
178
179 if(!useMultipleOpins)
180 {
181 ImGui::Text("Output");
182 outputPins[0]->Render();
183 ImGui::NewLine();
184 }
185 else
186 {
187 for(int i = 0 ; i < oPinStrs.size() ; i++)
188 {
189 ImGui::Text(oPinStrs[i].data());
190 outputPins[i]->Render();
191 ImGui::NewLine();
192 }
193 }
194
195 int j = 0;
196
197 if(!useArrayParams)
198 {
199 for(auto &params: params)
200 {
201 inputPins[j]->Render();
202 ImGui::Text(params.second.c_str());
203 j++;
204 }
205 }
206 else
207 {
208 for(int k = 0 ; k < paramCount ; k++)
209 {
210 j = 0;
211 for(auto &param: params)
212 {
213 inputPins[k + j]->Render();
214 ImGui::Text((param.second + " #" + STR(k)).c_str());
215 j++;
216 }
217 }
218 }
219
220 ImGui::PushItemWidth(100);
221 int i = 0;
222
223 for(auto &it : sharedDataTemplate)
224 {
225 if(i > 31)
226 {
227 break;
228 }
229
230 ImGui::PushID(i);
231
232 if(it.type == "float")
233 {
234 if(ImGui::DragFloat(it.text.data(), &fData[i], 0.01f))
235 {
236 SetSharedMemoryItem(sharedData, i, fData[i]);
237 }
238 }
239
240 else if(it.type == "bool")
241 {
242 if(ImGui::Checkbox(it.text.data(), &bData[i]))
243 {
244 SetSharedMemoryItem(sharedData, i, bData[i] ? 1.0f : 0.0f);
245 }
246 }
247
248 ImGui::PopID();
249 i++;
250 }
251
252 ImGui::PopItemWidth();
253}
254
255CustomShaderNode::CustomShaderNode(GLSLHandler *handler, std::string s)
256 :SNENode(handler)
257{
258 name = "Custom Shader";
259 headerColor = ImColor(SHADER_VALUE_NODE_COLOR);
260 shader = s;
261 // Parse the shader
262 std::stringstream ss(shader);
263 std::string line;
264 std::string codeStr = "";
265 std::string metaStr = "";
266 bool isCodeActive = false;
267 bool isMetaActive = false;
268
269 while(std::getline(ss, line))
270 {
271 if(line[0] == '#')
272 {
273 continue;
274 }
275
276 else if(line == "[META]")
277 {
278 isMetaActive = true;
279 }
280
281 else if(line == "[CODE]")
282 {
283 isCodeActive = true;
284 }
285
286 else if(line == "[/META]")
287 {
288 isMetaActive = false;
289 }
290
291 else if(line == "[/CODE]")
292 {
293 isCodeActive = false;
294 }
295
296 else if(isMetaActive)
297 {
298 metaStr += line + "\n";
299 }
300
301 else if(isCodeActive)
302 {
303 codeStr += line + "\n";
304 }
305 }
306
307 // Load the meta data
308 if(metaStr.size() > 0)
309 {
310 meta = nlohmann::json::parse(metaStr);
311 }
312
313 else
314 {
315 throw std::runtime_error("No meta data found in shader");
316 }
317
318 // Load the code
319 if(codeStr.size() > 0)
320 {
321 code = codeStr;
322 }
323
324 else
325 {
326 throw std::runtime_error("No code found in shader");
327 }
328
329 // Load the data
330 name = meta["name"];
331 std::cout << "Loading Node : " << name << "\n";
332 std::string paramsStr = "";
333 int j = 0;
334
335 if(meta.find("param_count") != meta.end())
336 {
337 paramCount = meta["param_count"];
338 useArrayParams = true;
339 }
340 else
341 {
342 paramCount = 1;
343 useArrayParams = false;
344 }
345 int pss = meta["params"].size();
346
347 for(std::string param : meta["params"])
348 {
349 std::string pType = param.substr(0, param.find(":"));
350 std::string pName = param.substr(param.find(":") + 1);
351 params.push_back(std::make_pair(pType, pName));
352 if(useArrayParams)
353 paramsStr += pType + " " + pName + "[" + STR(paramCount) + "]" + (j < pss - 1 ? ", " : "");
354 else
355 paramsStr += pType + " " + pName + (j < pss - 1 ? ", " : "");
356 j++;
357 }
358
359 paramsStr += (params.size() == 0 ? "" : ", ") + std::string("int callerPin");
360
361 func = new GLSLFunction(meta["fname"], paramsStr, meta["returns"]);
362 func->name += STR(id);
363 sharedDataTemplate.clear();
364 int i = 0;
365
366 for(auto it = meta["sharedData"].begin() ; it != meta["sharedData"].end() ; it++)
367 {
368 std::string alias = ReplaceString(it.key(), " ", "");
369 if(it.value().find("alias") != it.value().end())
370 alias = it.value()["alias"];
371 sharedDataTemplate.push_back(SharedDataRep(it.key(), it.value()["type"], alias));
372
373 if(it.value()["type"] == "float")
374 {
375 fData[i] = it.value()["default"].get<float>();
376 }
377
378 else if(it.value()["type"] == "bool")
379 {
380 bData[i] = it.value()["default"].get<bool>();
381 }
382
383 i++;
384 }
385
386 if(meta.find("output_pins") != meta.end())
387 {
388 std::string returns = meta["returns"];
389 useMultipleOpins = true;
390 for(std::string oPin : meta["output_pins"])
391 {
392 oPinStrs.push_back(oPin);
393 if(meta["returns"] == "float")
394 {
395 outputPins.push_back(new SNEPin(NodeEditorPinType::Output, SNEPinType::SNEPinType_Float));
396 }
397 else if(meta["returns"] == "vec3")
398 {
399 outputPins.push_back(new SNEPin(NodeEditorPinType::Output, SNEPinType::SNEPinType_Float3));
400 }
401 }
402 }
403 else
404 {
405 if(meta["returns"] == "float")
406 {
407 outputPins.push_back(new SNEPin(NodeEditorPinType::Output, SNEPinType::SNEPinType_Float));
408 }
409 else if(meta["returns"] == "vec3")
410 {
411 outputPins.push_back(new SNEPin(NodeEditorPinType::Output, SNEPinType::SNEPinType_Float3));
412 }
413 else
414 {
415 std::string t = meta["returns"];
416 throw std::runtime_error("Custom shader node does not support return type " + t);
417 }
418 }
419
420
421 for(int k = 0 ; k < paramCount ; k++)
422 {
423 for(auto &it : params)
424 {
425 if(it.first == "float")
426 {
427 inputPins.push_back(new SNEPin(NodeEditorPinType::Input, SNEPinType::SNEPinType_Float));
428 }
429
430 else if(it.first == "vec3")
431 {
432 inputPins.push_back(new SNEPin(NodeEditorPinType::Input, SNEPinType::SNEPinType_Float3));
433 }
434
435 else
436 {
437 throw std::runtime_error("Custom shader node does not support parameter type " + it.first);
438 }
439 }
440 }
441 headerColor = ImColor(meta["color"]["r"].get<int>(), meta["color"]["r"].get<int>(), meta["color"]["b"].get<int>());
442}
443
444
445CustomShaderNode::~CustomShaderNode()
446{
447 delete func;
448}
static JSON_HEDLEY_WARN_UNUSED_RESULT basic_json parse(InputType &&i, const parser_callback_t cb=nullptr, const bool allow_exceptions=true, const bool ignore_comments=false)
deserialize from a compatible input
Definition: json.hpp:24605
auto get() const noexcept(noexcept(std::declval< const basic_json_t & >().template get_impl< ValueType >(detail::priority_tag< 4 > {}))) -> decltype(std::declval< const basic_json_t & >().template get_impl< ValueType >(detail::priority_tag< 4 > {}))
get a (pointer) value (explicit)
Definition: json.hpp:20907
a class to store JSON values
Definition: json.hpp:17860