From 60cbbdec07ab7a5636eac5b3c024ae44e937f4d4 Mon Sep 17 00:00:00 2001 From: chai Date: Mon, 13 Dec 2021 00:07:19 +0800 Subject: +init --- Client/Source/Graphics/ShaderCompiler.cpp | 347 ++++++++++++++++++++++++++++++ 1 file changed, 347 insertions(+) create mode 100644 Client/Source/Graphics/ShaderCompiler.cpp (limited to 'Client/Source/Graphics/ShaderCompiler.cpp') diff --git a/Client/Source/Graphics/ShaderCompiler.cpp b/Client/Source/Graphics/ShaderCompiler.cpp new file mode 100644 index 0000000..362b28e --- /dev/null +++ b/Client/Source/Graphics/ShaderCompiler.cpp @@ -0,0 +1,347 @@ +#include "ShaderCompiler.h" +#include +#include + +using namespace std; + +static const char* VSH_BEGIN = "VSH_BEGIN"; +static const char* VSH_END = "VSH_END"; +static const char* FSH_BEGIN = "FSH_BEGIN"; +static const char* FSH_END = "FSH_END"; +static const char* CMD_BEGIN = "CMD_BEGIN"; +static const char* CMD_END = "CMD_END"; + +std::string s_CompileError = ""; + +// GLSL分为四部分 +// * CMD_BEGIN 和 CMD_END 之间的命令 +// * VERTEX_SHADER_BEGIN 和 VERTEX_SHADER_END之间的顶点着色器 +// * FRAGMENT_SHADER_BEGIN 和 FRAGMENT_SHADER_END之间的片段着色器 +// * 三者之外的公共部分 +void GLSLCompiler::Compile(std::string& src, std::string& vsh, std::string& fsh, RenderCommandGroup& group)/*throw GLSLCompileException*/ +{ +#define CheckLabel(label) {\ + int pos = src.find(label);\ + if(pos == string::npos || !IsLabelActive(src, label)) {\ + s_CompileError = std::string("Compile Shader Error: No ") + #label + " label";\ + throw GLSLCompileException(s_CompileError.c_str());\ + }} + + CheckLabel(VSH_BEGIN); + CheckLabel(VSH_END); + CheckLabel(FSH_BEGIN); + CheckLabel(FSH_END); + + vsh = GetContent(src, VSH_BEGIN, VSH_END); + fsh = GetContent(src, FSH_BEGIN, FSH_END); + + bool hasCmd = IsLabelActive(src, CMD_BEGIN) && IsLabelActive(src, CMD_END); + if (hasCmd) + { + string cmd = GetContent(src, CMD_BEGIN, CMD_END); + if (cmd.size() > 0) + { + ParseCmd(cmd, group); + } + else + { + hasCmd = false; + } + } + + string common; + common = TrimContent(src, VSH_BEGIN, VSH_END); + common = TrimContent(common, FSH_BEGIN, FSH_END); + if (hasCmd) + common = TrimContent(common, CMD_BEGIN, CMD_END); + + vsh = common + vsh; + fsh = common + fsh; +} + +std::string GLSLCompiler::GetContent(std::string& src, const char* from, const char* to) +{ + int begin = src.find(from); + int end = src.find(to); + if (begin == string::npos || end == string::npos) + { + return ""; + } + std::string content = src.substr(begin + strlen(from), end - begin - strlen(from)); + return content; +} + +std::string GLSLCompiler::TrimContent(std::string& src, const char* from, const char* to) +{ + int begin = src.find(from); + int end = src.find(to); + string result = src.erase(begin, end + strlen(to) - begin); + return result; +} + +bool GLSLCompiler::IsLabelActive(std::string& src, const char* label) +{ + int pos = src.find(label); + if (pos == string::npos) + return false; + for (int i = pos - 1; i >= 0; --i) + { + int second = i; + int first = i - 1; + if (first < 0) + break; + if (src[second] == '\n' || src[first] == '\r') + break; + if (src[first] == '/' && src[second] == '/') + return false; + } + return true; +} + +bool GLSLCompiler::IsCommandActive(std::string& src, const char* label) +{ + int pos = src.find(label); + if (pos == string::npos) + return false; + for (int i = pos - 1; i >= 0; --i) + { + int second = i; + int first = i - 1; + if (first < 0) + break; + if (src[second] == '\n' || src[first] == '\r') + break; + if (src[first] == '/' && src[second] == '/') + return false; + } + return true; +} + +void GLSLCompiler::ParseCmd(std::string& cmds, RenderCommandGroup& group) +{ + istringstream ss = istringstream(cmds); + string line; + while (getline(ss, line)) + { + if(line.find('\r') != string::npos) + line.erase(std::remove(line.begin(), line.end(), '\r'), line.end()); + if (IsLineCommentd(line)) + continue; + int cb, ce; // cmd begin, end + if (!FindCmdPos(line, &cb, &ce)) + continue; + string cmdName = line.substr(cb, ce - cb + 1); + string cmdValue = line.substr(ce + 1, line.size() - ce - 1); + if (cmdName == "Cull") CommandCull(cmdValue, group); + else if (cmdName == "Blend") CommandBlend(cmdValue, group); + else if (cmdName == "DepthTest") CommandDepthTest(cmdValue, group); + else if (cmdName == "DepthWrite") CommandDepthWrite(cmdValue, group); + else + { + s_CompileError = string("Unknown command " + cmdName); + throw GLSLCompileException(s_CompileError.c_str()); + } + } +} + +#define IsSeperator(c) (c == ' ' || c == '\r' || c == '\n' || c == /*tab*/9) + +// 找到行内的第一个单词,作为命令名 +bool GLSLCompiler::FindCmdPos(std::string& line, int* start, int* end) +{ + for (int i = 0; i < line.size(); ++i) + { + if (IsSeperator(line[i])) + continue; + *start = i; + for (int j = i + 1; j < line.size(); ++j) + { + if (IsSeperator(line[j])) + { + *end = j - 1; + return true; + } + } + } + return false; +} + +bool GLSLCompiler::IsLineCommentd(std::string& line) +{ + for (int i = 0; i < line.size(); ++i) + { + if (IsSeperator(line[i])) + continue; + int first = i; + int second = i + 1; + if (second == line.size()) + return false; + if (line[first] == '/' && line[second] == '/') + return true; + return false; + } + return false; +} + +#define MAX_PARAM 2 + +void GLSLCompiler::CommandCull(std::string& p, RenderCommandGroup& group) +{ + std::string params[1]; + GetParams("Cull", p, params, 1); + + Cmd_Cull* pCull = new Cmd_Cull(); + Cmd_Cull& cull = *pCull; + if (params[0] == "Off") cull.cull = Cmd_Cull::Cull_Disable; + else if (params[0] == "Front") cull.cull = Cmd_Cull::Cull_Front; + else if (params[0] == "Back") cull.cull = Cmd_Cull::Cull_Back; + else if (params[0] == "Both") cull.cull = Cmd_Cull::Cull_Both; + else + { + delete pCull; + s_CompileError = string("Compile Shader Error: Invalid parameter of Cull: " + params[0]); + throw GLSLCompileException(s_CompileError.c_str()); + } + group.push_back(pCull); +} + +void GLSLCompiler::CommandBlend(std::string& p, RenderCommandGroup& group) +{ + std::string params[2]; + GetParams("Blend", p, params, 2); + + Cmd_Blend* pblend = new Cmd_Blend(); + Cmd_Blend& blend = *pblend; + if (params[0] == "Off") + { + blend.enable = false; + group.push_back(pblend); + return; + } + + blend.enable = true; + + if (params[0] == "Zero") blend.srcFac = Cmd_Blend::Blend_Zero; + else if (params[0] == "One") blend.srcFac = Cmd_Blend::Blend_One; + else if (params[0] == "SrcColor") blend.srcFac = Cmd_Blend::Blend_Src_Color; + else if (params[0] == "OneMinusSrcColor") blend.srcFac = Cmd_Blend::Blend_One_Minus_Src_Color; + else if (params[0] == "DstColor") blend.srcFac = Cmd_Blend::Blend_Dst_Color; + else if (params[0] == "OneMinusDstColor") blend.srcFac = Cmd_Blend::Blend_One_Minus_Dst_Color; + else if (params[0] == "SrcAlpha") blend.srcFac = Cmd_Blend::Blend_Src_Alpha; + else if (params[0] == "OneMinusSrcAlpha") blend.srcFac = Cmd_Blend::Blend_One_Minus_Src_Alpha; + else if (params[0] == "DstAlpha") blend.srcFac = Cmd_Blend::Blend_Dst_Alpha; + else if (params[0] == "OneMinusDstAlpha") blend.srcFac = Cmd_Blend::Blend_One_Minus_Dst_Alpha; + else if (params[0] == "ConstantColor") blend.srcFac = Cmd_Blend::Blend_Constant_Color; + else if (params[0] == "OneMinusConstantColor") blend.srcFac = Cmd_Blend::Blend_One_Minus_Constant_Color; + else if (params[0] == "ConstantAlpha") blend.srcFac = Cmd_Blend::Blend_Constant_Alpha; + else if (params[0] == "OneMinusConstantAlpha") blend.srcFac = Cmd_Blend::Blend_One_Minus_Constant_Alpha; + else + { + delete pblend; + s_CompileError = string("Compile Shader Error: Invalid parameter of Blend: " + params[0]); + throw GLSLCompileException(s_CompileError.c_str()); + } + + if (params[1] == "Zero") blend.dstFac = Cmd_Blend::Blend_Zero; + else if (params[1] == "One") blend.dstFac = Cmd_Blend::Blend_One; + else if (params[1] == "SrcColor") blend.dstFac = Cmd_Blend::Blend_Src_Color; + else if (params[1] == "OneMinusSrcColor") blend.dstFac = Cmd_Blend::Blend_One_Minus_Src_Color; + else if (params[1] == "DstColor") blend.dstFac = Cmd_Blend::Blend_Dst_Color; + else if (params[1] == "OneMinusDstColor") blend.dstFac = Cmd_Blend::Blend_One_Minus_Dst_Color; + else if (params[1] == "SrcAlpha") blend.dstFac = Cmd_Blend::Blend_Src_Alpha; + else if (params[1] == "OneMinusSrcAlpha") blend.dstFac = Cmd_Blend::Blend_One_Minus_Src_Alpha; + else if (params[1] == "DstAlpha") blend.dstFac = Cmd_Blend::Blend_Dst_Alpha; + else if (params[1] == "OneMinusDstAlpha") blend.dstFac = Cmd_Blend::Blend_One_Minus_Dst_Alpha; + else if (params[1] == "ConstantColor") blend.dstFac = Cmd_Blend::Blend_Constant_Color; + else if (params[1] == "OneMinusConstantColor") blend.dstFac = Cmd_Blend::Blend_One_Minus_Constant_Color; + else if (params[1] == "ConstantAlpha") blend.dstFac = Cmd_Blend::Blend_Constant_Alpha; + else if (params[1] == "OneMinusConstantAlpha") blend.dstFac = Cmd_Blend::Blend_One_Minus_Constant_Alpha; + else + { + delete pblend; + s_CompileError = string("Compile Shader Error: Invalid parameter of Blend: " + params[1]); + throw GLSLCompileException(s_CompileError.c_str()); + } + + group.push_back(pblend); +} + +void GLSLCompiler::CommandDepthTest(std::string& p, RenderCommandGroup& group) +{ + std::string params[1]; + GetParams("DepthTest", p, params, 1); + + Cmd_DepthTest* pTest = new Cmd_DepthTest(); + Cmd_DepthTest& test = *pTest; + if (params[0] == "Off") test.test = Cmd_DepthTest::DepthTest_Off; + else if (params[0] == "Always") test.test = Cmd_DepthTest::DepthTest_Always; + else if (params[0] == "Never") test.test = Cmd_DepthTest::DepthTest_Never; + else if (params[0] == "Less") test.test = Cmd_DepthTest::DepthTest_Less; + else if (params[0] == "Equal") test.test = Cmd_DepthTest::DepthTest_Equal; + else if (params[0] == "LEqual") test.test = Cmd_DepthTest::DepthTest_Lequal; + else if (params[0] == "Greater") test.test = Cmd_DepthTest::DepthTest_Greater; + else if (params[0] == "NotEqual") test.test = Cmd_DepthTest::DepthTest_Notequal; + else if (params[0] == "GEqual") test.test = Cmd_DepthTest::DepthTest_Gequal; + else + { + delete pTest; + s_CompileError = string("Compile Shader Error: Invalid parameter of DepthTest: " + params[0]); + throw GLSLCompileException(s_CompileError.c_str()); + } + group.push_back(pTest); +} + +void GLSLCompiler::CommandDepthWrite(std::string& p, RenderCommandGroup& group) +{ + std::string params[1]; + GetParams("DepthWrite", p, params, 1); + + Cmd_DepthWrite* pwrite = new Cmd_DepthWrite(); + Cmd_DepthWrite& write = *pwrite; + if (params[0] == "Off") write.write = false; + else if (params[0] == "On") write.write = true; + else + { + delete pwrite; + s_CompileError = string("Compile Shader Error: Invalid parameter of DepthWrite: " + params[0]); + throw GLSLCompileException(s_CompileError.c_str()); + } + group.push_back(pwrite); +} + +void GLSLCompiler::GetParams(const char* cmdName, std::string& params, std::string* out, int n) +{ + int index = 0; + for (int i = 0; i < params.size(); ++i) + { + if (IsSeperator(params[i])) + continue; + int j = i + 1; + for (; j < params.size(); ++j) + { + if (j == params.size() - 1) + { + if (index >= n) + { + s_CompileError = string("Compile Shader Error: Invalid parameter count of ") + cmdName +" : " + params; + throw GLSLCompileException(s_CompileError.c_str()); + } + if(!IsSeperator(params[j])) + out[index++] = params.substr(i, j - i + 1); + else + out[index++] = params.substr(i, j - i); + return; + } + if (!IsSeperator(params[j])) + continue; + if (index >= n) + { + s_CompileError = string("Compile Shader Error: Invalid parameter count of ") + cmdName + " : " + params; + throw GLSLCompileException(s_CompileError.c_str()); + } + out[index++] = params.substr(i, j - i); + break; + } + i = j; + } +} -- cgit v1.1-26-g67d0