1#include "Shading/ShadingManager.h"
2#include "Utils/Utils.h"
3#include "Data/ApplicationState.h"
6#include "imgui/imgui.h"
9#include "Shading/ShaderNodes/ShaderOutputNode.h"
10#include "Shading/ShaderNodes/ShaderTextureNode.h"
11#include "Shading/ShaderNodes/Float3Node.h"
12#include "Shading/ShaderNodes/FloatNode.h"
13#include "Shading/ShaderNodes/PBRMaterialNode.h"
14#include "Shading/ShaderNodes/CustomShaderNode.h"
15#include "Shading/ShaderNodes/BakeToSlotNode.h"
19namespace fs = std::filesystem;
21static char *stristr4(
const char *str,
const char *pattern)
32 if (toupper((
unsigned char)*str) == toupper((
unsigned char)*pattern))
41 if (toupper((
unsigned char)str[i]) != toupper((
unsigned char)pattern[i]))
53#define NODE_MAKER_COND(x) length == 0 || stristr4(x, data)
54#define NODE_MAKER_SHOW(x, y, z) if (NODE_MAKER_COND(y)) {if (ImGui::Button((y + std::string("##SHADERNODEMAKER")).c_str())) { editor->AddNode(new x(handler)); z = z || true; ImGui::CloseCurrentPopup(); } }
59 static char data[1000];
60 static bool didMake =
false;
62 ImGui::InputTextWithHint(
"##SearchShaderNodes",
"Search ...", data,
sizeof(data));
63 int length = strlen(data);
64 ImGui::BeginChild(
"##ShaderNodesMaker", ImVec2(200, 250));
66 NODE_MAKER_SHOW(
Float3Node,
"Float3", didMake);
68 NODE_MAKER_SHOW(
FloatNode,
"Float Value", didMake);
73 if (NODE_MAKER_COND(
"Texture"))
75 if (ImGui::Button((
"Texture" + std::string(
"##SHADERNODEMAKER")).c_str()))
78 didMake = didMake ||
true;
79 ImGui::CloseCurrentPopup();
85 for (
auto &node : defaultCustomNodes)
87 if (NODE_MAKER_COND(node.name.data()))
89 if (ImGui::Button((node.name + std::string(
"##SHADERNODEMAKER")).c_str()))
92 didMake = didMake ||
true;
93 ImGui::CloseCurrentPopup();
98 if (NODE_MAKER_COND(
"Custom Shader"))
100 if (ImGui::Button((
"Custom Shader" + std::string(
"##SHADERNODEMAKER")).c_str()))
102 std::string path = ShowOpenFileDialog(
"*.json\0");
107 editor->AddNode(
new CustomShaderNode(handler, ReadShaderSourceFile(path, &tmp)));
108 didMake = didMake ||
true;
109 ImGui::CloseCurrentPopup();
128 config.makeNodeFunc = [&]()
130 ImGuiNodeEditor::Suspend();
131 ImGui::OpenPopup(
"NodeMakerDropped");
132 ImGuiNodeEditor::Resume();
138 if(data[
"type"] ==
"ShaderOutput")
143 else if(data[
"type"] ==
"Float3")
148 else if(data[
"type"] ==
"Float")
153 else if(data[
"type"] ==
"ShaderTexture")
158 else if(data[
"type"] ==
"PBRMaterial")
163 else if(data[
"type"] ==
"BakeToSlot")
168 else if(data[
"type"] ==
"CustomShader")
175 config.saveFile = GetExecutableDir() + PATH_SEPARATOR
"Data" PATH_SEPARATOR
"configs" PATH_SEPARATOR
"ShaderNodes.json";
177 shaderNodeEditor->name =
"Shader Nodes";
179 LoadDefaultCustomNodes();
183ShadingManager::~ShadingManager()
188 delete sharedMemoryManager;
194 data[
"nodeEditor"] = shaderNodeEditor->Save();
200 shaderNodeEditor->Load(data[
"nodeEditor"]);
204void ShadingManager::UpdateShaders()
213 sharedMemoryManager->UpdateShader(appState->shaders.terrain);
214 shaderTextureManager->Bind(7);
215 appState->shaders.terrain->SetUniformi(
"_Textures", 7);
218void ShadingManager::LoadDefaultCustomNodes()
220 std::string nodesDir = GetExecutableDir() + PATH_SEPARATOR
"Data" PATH_SEPARATOR
"shader_nodes";
221 defaultCustomNodes.clear();
224 for (
const auto &entry : fs::directory_iterator(nodesDir))
226 if(entry.path().extension().string() !=
".json")
229 n.name = entry.path().filename().string();
230 n.name = n.name.substr(0, n.name.find_last_of(
"."));
231 n.content = ReadShaderSourceFile(entry.path().string(), &tmp);
232 defaultCustomNodes.push_back(n);
235 extraSource = ReadShaderSourceFile(nodesDir + PATH_SEPARATOR
"extras.glsl", &tmp);
239void ShadingManager::ReCompileShaders()
243 sharedMemoryManager->Clear();
244 SNENode *outputNode =
static_cast<SNENode *
>(shaderNodeEditor->outputNode);
245 outputNode->dataBlobOffset = sharedMemoryManager->AddItem();
247 for(
auto &it : shaderNodeEditor->nodes)
250 node->dataBlobOffset = sharedMemoryManager->AddItem();
253 outputNode->sharedData = sharedMemoryManager->At(outputNode->dataBlobOffset);
254 outputNode->UpdateShaders();
256 for(
auto &it : shaderNodeEditor->nodes)
259 node->sharedData = sharedMemoryManager->At(node->dataBlobOffset);
260 node->UpdateShaders();
263 shaderTextureManager->UpdateShaders();
265 vertexSource = vsh->GenerateGLSL();
267 geometrySource = gsh->GenerateGLSL();
269 fragmentSource = fsh->GenerateGLSL();
287 appState->shaders.terrain =
new Shader(vertexSource, fragmentSource, geometrySource);
290 logs.push_back(
"Generated & Compiled Shaders in " + std::to_string(time) +
"ms");
293void ShadingManager::ShowSettings(
bool *pOpen)
295 ImGui::Begin(
"Shading##ShadingManager", pOpen);
297 if(ImGui::Button(
"Compile Shaders"))
304 if(ImGui::Button(
"Export GLSL"))
306 std::string path = ShowSaveFileDialog(
"*.glsl\0");
310 SaveToFile(path, fragmentSource);
314 if(ImGui::Button(
"Print GLSL"))
316 std::cout << fragmentSource << std::endl;
323 if(ImGui::Checkbox(
"Optimize GLSL", &optimizeGLSL))
331 if(ImGui::CollapsingHeader(
"Logs"))
335 ImGui::Text(
"Logs:");
337 for(std::string &s : logs)
339 ImGui::Text(s.data());
344 if(ImGui::CollapsingHeader(
"Shader Nodes"))
346 if (ImGui::Button(
"Add Node##ShaderNodeMaker"))
348 ImGui::OpenPopup(
"NodeMakerDropped");
353 if (ImGui::Button(
"Reset##ShaderNodeMaker"))
355 shaderNodeEditor->Reset();
361 if (ImGui::Button(
"Export##ShaderNodeMaker"))
363 std::string file = ShowSaveFileDialog(
"*.terr3d");
367 if (file.find(
".terr3d") == std::string::npos)
372 SaveToFile(file, shaderNodeEditor->Save().
dump(4));
378 if (ImGui::Button(
"Import##CPUNE"))
380 std::string file = ShowOpenFileDialog(
"*.terr3d");
385 shaderNodeEditor->Reset();
393 if(ImGui::Button(
"Reload Nodes"))
395 LoadDefaultCustomNodes();
398 int nC = shaderNodeEditor->nodes.size();
399 int lC = shaderNodeEditor->links.size();
400 int pC = shaderNodeEditor->pins.size();
401 shaderNodeEditor->Render();
403 if ((nC != shaderNodeEditor->nodes.size()) || (lC != shaderNodeEditor->links.size()) || (pC != shaderNodeEditor->pins.size()))
409 if (ImGui::IsWindowFocused() && (((IsKeyDown(TERR3D_KEY_RIGHT_SHIFT) || IsKeyDown(TERR3D_KEY_LEFT_SHIFT)) && IsKeyDown(TERR3D_KEY_A)) || IsMouseButtonDown(TERR3D_MOUSE_BUTTON_MIDDLE)))
411 ImGui::OpenPopup(
"NodeMakerDropped");
414 if(ImGui::BeginPopup(
"NodeMakerDropped"))
416 if(ShowNodeMaker(shaderNodeEditor, fsh, shaderTextureManager, defaultCustomNodes))
421 if (ImGui::Button(
"Close##ShaderNodeMaker"))
423 ImGui::CloseCurrentPopup();
432void ShadingManager::PrepVertShader()
435 vsh->AddTopLine(
GLSLLine(
"layout (location = 0) in vec4 aPos;",
"The world position of the vertex"));
436 vsh->AddTopLine(
GLSLLine(
"layout (location = 1) in vec4 aNorm;",
"The vertex normals"));
437 vsh->AddTopLine(
GLSLLine(
"layout (location = 2) in vec2 aTexCoord;",
"The texture coordinates of the vertex"));
438 vsh->AddTopLine(
GLSLLine(
"layout (location = 3) in vec4 aExtras1;",
"Extra data like generated height, erosion delta, etc."));
439 vsh->AddTopLine(
GLSLLine(
"",
"The Output passed to the Geometry Shader"));
453 vsh->AddUniform(
GLSLUniform(
"_TextureBake",
"float",
"0.0f"));
454 vsh->AddUniform(
GLSLUniform(
"_Scale",
"float",
"1.0f"));
455 vsh->AddUniform(
GLSLUniform(
"_Tiled",
"float",
"0.0f"));
456 vsh->AddUniform(
GLSLUniform(
"_NumTiles",
"float",
"0.0f"));
457 vsh->AddUniform(
GLSLUniform(
"_TileX",
"float",
"0.0f"));
458 vsh->AddUniform(
GLSLUniform(
"_TileY",
"float",
"0.0f"));
464if(_TextureBake == 0.0f)
465 gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0f);
470 gl_Position = vec4(aPos.x/_Scale, aPos.z/_Scale, 0.0f, 1.0f);
474 float factor = _NumTiles / _Scale;
475 gl_Position = vec4(aPos.x * factor + _TileX, aPos.z * factor + _TileY, 0.0f, 1.0f);
479 main.AddLine(GLSLLine("data_out.height = aExtras1.x;",
"The actual generated noise value"));
480 main.AddLine(
GLSLLine(
"data_out.FragPos = vec3(aPos.x, aPos.y, aPos.z);",
"The world position"));
481 main.AddLine(
GLSLLine(
"data_out.Normal = vec3(aNorm.x, aNorm.y, aNorm.z);",
"The vertex normals"));
482 main.AddLine(
GLSLLine(
"data_out.TexCoord = aTexCoord;",
"The texture coordinates"));
483 main.AddLine(
GLSLLine(
"data_out.Extras1 = aExtras1;",
"The texture coordinates"));
486 vsh->AddFunction(main);
489void ShadingManager::PrepGeomShader()
493 gsh->AddTopLine(
GLSLLine(
"layout(triangles) in;",
"Take 3 vertices of a triangles as input"));
494 gsh->AddTopLine(
GLSLLine(
"layout(triangle_strip, max_vertices = 3) out;"));
495 gsh->AddTopLine(
GLSLLine(
"",
"The data passed in from the vertex shader"));
507 gsh->AddTopLine(
GLSLLine(
"out float height;",
"Pass the height to the fragment shader"));
508 gsh->AddTopLine(
GLSLLine(
"out vec4 FragPos;",
"Pass the position to the fragment shader"));
509 gsh->AddTopLine(
GLSLLine(
"out vec4 Extras1;",
"Pass the extras to the fragment shader"));
510 gsh->AddTopLine(
GLSLLine(
"out vec3 Normal;",
"Pass the normal to the fragment shader"));
511 gsh->AddTopLine(
GLSLLine(
"out vec2 TexCoord;",
"Pass the texture coordinates to the fragment shader"));
512 gsh->AddTopLine(
GLSLLine(
"out mat3 TBN;",
"Pass the Tangent Bitangent Normal matrix to the fragment shader"));
515 gsh->AddUniform(
GLSLUniform(
"_FlatShade",
"float"));
518 main.AddLine(
GLSLLine(
"vec3 a = (_PV * gl_in[0].gl_Position).xyz;",
"Vertex a of triangle"));
519 main.AddLine(
GLSLLine(
"vec3 b = (_PV * gl_in[1].gl_Position).xyz;",
"Vertex b of triangle"));
520 main.AddLine(
GLSLLine(
"vec3 c = (_PV * gl_in[2].gl_Position).xyz;",
"Vertex c of triangle"));
522 main.AddLine(
GLSLLine(
"vec3 edge0 = b - c;"));
523 main.AddLine(
GLSLLine(
"vec3 edge1 = c - a;"));
525 main.AddLine(
GLSLLine(
"vec2 deltaUV0 = data_in[1].TexCoord - data_in[0].TexCoord;"));
526 main.AddLine(
GLSLLine(
"vec2 deltaUV1 = data_in[2].TexCoord - data_in[0].TexCoord;"));
528 main.AddLine(
GLSLLine(
"float invDet = 1.0f / (deltaUV0.x * deltaUV1.y - deltaUV1.x * deltaUV0.y);",
"One over the determinant"));
530 main.AddLine(
GLSLLine(
"vec3 tangent = vec3(invDet * (deltaUV1.y * edge0 - deltaUV0.y * edge1));"));
531 main.AddLine(
GLSLLine(
"vec3 bitangent = vec3(invDet * (-deltaUV1.x * edge0 + deltaUV0.x * edge1));"));
532 main.AddLine(
GLSLLine(
"mat4 model = mat4(1);",
"A default model matrix"));
534 main.AddLine(
GLSLLine(
"vec3 T = normalize(vec3(model * vec4(tangent, 0.0f)));"));
535 main.AddLine(
GLSLLine(
"vec3 B = normalize(vec3(model * vec4(bitangent, 0.0f)));"));
536 main.AddLine(
GLSLLine(
"vec3 N = normalize(vec3(model * vec4(cross(edge1, edge0), 0.0f)));"));
538 main.AddLine(
GLSLLine(
"TBN = mat3(T, B, N);"));
540 main.AddLine(
GLSLLine(
"vec3 n = normalize(cross(edge1, edge0));",
"Calculate face normal for flat shading"));
545 main.AddLine(
GLSLLine(
"gl_Position = _PV * gl_in[" + std::to_string(i) +
"].gl_Position;"));
546 main.AddLine(
GLSLLine(
"height = data_in[" + std::to_string(i) +
"].height;"));
547 main.AddLine(
GLSLLine(
"TexCoord = data_in[" + std::to_string(i) +
"].TexCoord;"));
548 main.AddLine(
GLSLLine(
"Extras1 = data_in[" + std::to_string(i) +
"].Extras1;"));
549 main.AddLine(
GLSLLine(
"FragPos = vec4(data_in[" + std::to_string(i) +
"].FragPos, 1.0f);"));
551 if(_FlatShade > 0.5f)
554 Normal = data_in[)" + std::to_string(i) + R"(].Normal;
556 main.AddLine(GLSLLine("EmitVertex();",
"Emit the vertex"));
559main.AddLine(
GLSLLine(
"EndPrimitive();",
"Emit the triangle"));
562gsh->AddFunction(main);
566void ShadingManager::PrepFragShader()
569 fsh->AddTopLine(
GLSLLine(
"out vec4 FragColor;",
"The result of the fragment shader"));
571 fsh->AddTopLine(
GLSLLine(
"in float height;",
"Take the height passed in from the Geometry Shader"));
572 fsh->AddTopLine(
GLSLLine(
"in vec4 FragPos;",
"Take the world position passed in from the Geometry Shader"));
573 fsh->AddTopLine(
GLSLLine(
"in vec4 Extras1;",
"Take the extras 1 passed in from the Geometry Shader"));
574 fsh->AddTopLine(
GLSLLine(
"in vec3 Normal;",
"Take the normal passed in from the Geometry Shader"));
575 fsh->AddTopLine(
GLSLLine(
"in vec2 TexCoord;",
"Take the texture coordinates passed in from the Geometry Shader"));
576 fsh->AddTopLine(
GLSLLine(
"in mat3 TBN;",
"Take the tangent bitangent normal matrix in from the Geometry Shader"));
578 fsh->AddTopLine(
GLSLLine(extraSource));
586 fsh->AddTopLine(GLSLLine("const float PI = 3.14159265359;"));
587 fsh->AddTopLine(
GLSLLine(
"const float gamma = 2.2f;"));
588 fsh->AddUniform(
GLSLUniform(
"_LightPosition",
"vec3"));
589 fsh->AddUniform(
GLSLUniform(
"_LightColor",
"vec3"));
590 fsh->AddUniform(
GLSLUniform(
"_LightStrength",
"float"));
591 fsh->AddUniform(
GLSLUniform(
"_CameraPos",
"vec3"));
592 fsh->AddUniform(
GLSLUniform(
"_HMapMinMax",
"vec3"));
593 fsh->AddUniform(
GLSLUniform(
"_TextureBake",
"float",
"0.0f"));
594 fsh->AddUniform(
GLSLUniform(
"_Slot",
"float",
"0.0f"));
595 fsh->AddUniform(
GLSLUniform(
"_Tiled",
"float",
"0.0f"));
596 fsh->AddUniform(
GLSLUniform(
"_NumTiles",
"float",
"0.0f"));
597 fsh->AddUniform(
GLSLUniform(
"_TileX",
"float",
"0.0f"));
598 fsh->AddUniform(
GLSLUniform(
"_TileY",
"float",
"0.0f"));
599 fsh->AddUniform(
GLSLUniform(
"_Textures",
"sampler2DArray"));
600 GLSLSSBO dataBlobs(
"dataBlobs", std::to_string(sharedMemoryManager->ssboBinding),
"These are small data blobs which may be used for nodes, etc.");
601 dataBlobs.AddLine(
GLSLLine(
"DataBlob data[];"));
602 fsh->AddSSBO(dataBlobs);
605 main.AddLine(
GLSLLine(
"vec3 textureBakeSlots[10];"));
608 param.userData1 = &main;
609 param.userData2 = &tmp;
610 shaderNodeEditor->outputNode->Evaluate(param,
nullptr);
613 if(_TextureBake == 1.0f)
615 textureBakeSlots[0] = vec3( (height - _HMapMinMax.x) / (_HMapMinMax.y - _HMapMinMax.x) ); // Slot 0 is reserved for height map
616 FragColor = vec4(textureBakeSlots[int(_Slot)], 1.0f);
621 main.AddLine(
GLSLLine(
"FragColor = vec4(" + tmp.line +
", 1.0f);"));
622 fsh->AddFunction(main);
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
string_t dump(const int indent=-1, const char indent_char=' ', const bool ensure_ascii=false, const error_handler_t error_handler=error_handler_t::strict) const
serialization
a class to store JSON values