diff --git a/src/gpu/shader.cpp b/src/gpu/shader.cpp index c2b19525..b9614a70 100644 --- a/src/gpu/shader.cpp +++ b/src/gpu/shader.cpp @@ -39,7 +39,25 @@ using namespace std; namespace lol { -static const char* attribute_names[] = { +struct ShaderType +{ + enum Value + { + Vertex = 1, + Fragment, + Geometry, + TessControl, + TessEval, + } + m_value; + + inline ShaderType(Value v) : m_value(v) {} + inline ShaderType(int v) : m_value((Value)v) {} + inline operator Value() { return m_value; } +}; + +static const char* attribute_names[] = +{ "in_Position", "in_BlendWeight", "in_BlendIndices", @@ -87,7 +105,7 @@ private: /* Shader patcher */ static int GetVersion(); - static void Patch(char *dst, char const *vert, char const *frag); + static String Patch(String const &code, ShaderType type); /* Global shader cache */ static Shader *shaders[]; @@ -200,8 +218,9 @@ Shader::Shader(char const *vert, char const *frag) { nullptr, nullptr } }; #elif !defined __CELLOS_LV2__ - char buf[4096], errbuf[4096]; - char const *shader = buf; + char errbuf[4096]; + String shader_code; + GLchar const *gl_code; GLint status; GLsizei len; #else @@ -232,9 +251,10 @@ Shader::Shader(char const *vert, char const *frag) &data->vert_shader); shader_code->Release(); #elif !defined __CELLOS_LV2__ - ShaderData::Patch(buf, vert, nullptr); + shader_code = ShaderData::Patch(vert, ShaderType::Vertex); data->vert_id = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(data->vert_id, 1, &shader, nullptr); + gl_code = shader_code.C(); + glShaderSource(data->vert_id, 1, &gl_code, nullptr); glCompileShader(data->vert_id); glGetShaderInfoLog(data->vert_id, sizeof(errbuf), &len, errbuf); @@ -242,12 +262,12 @@ Shader::Shader(char const *vert, char const *frag) if (status != GL_TRUE) { Log::Error("failed to compile vertex shader: %s", errbuf); - Log::Error("shader source:\n%s\n", buf); + Log::Error("shader source:\n%s\n", shader_code.C()); } else if (len > 16) { Log::Debug("compile log for vertex shader: %s", errbuf); - Log::Debug("shader source:\n%s\n", buf); + Log::Debug("shader source:\n%s\n", shader_code.C()); } #else data->vert_id = cgCreateProgram(cgCreateContext(), CG_SOURCE, vert, @@ -276,9 +296,10 @@ Shader::Shader(char const *vert, char const *frag) &data->frag_shader); shader_code->Release(); #elif !defined __CELLOS_LV2__ - ShaderData::Patch(buf, nullptr, frag); + shader_code = ShaderData::Patch(frag, ShaderType::Fragment); data->frag_id = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(data->frag_id, 1, &shader, nullptr); + gl_code = shader_code.C(); + glShaderSource(data->frag_id, 1, &gl_code, nullptr); glCompileShader(data->frag_id); glGetShaderInfoLog(data->frag_id, sizeof(errbuf), &len, errbuf); @@ -286,12 +307,12 @@ Shader::Shader(char const *vert, char const *frag) if (status != GL_TRUE) { Log::Error("failed to compile fragment shader: %s", errbuf); - Log::Error("shader source:\n%s\n", buf); + Log::Error("shader source:\n%s\n", shader_code.C()); } else if (len > 16) { Log::Debug("compile log for fragment shader: %s", errbuf); - Log::Debug("shader source:\n%s\n", buf); + Log::Debug("shader source:\n%s\n", shader_code.C()); } #else data->frag_id = cgCreateProgram(cgCreateContext(), CG_SOURCE, frag, @@ -858,18 +879,19 @@ int ShaderData::GetVersion() return version; } -/* Simple shader source patching for old GLSL versions. +/* + * Simple shader source patching for old GLSL versions. */ -void ShaderData::Patch(char *dst, char const *vert, char const *frag) +String ShaderData::Patch(String const &code, ShaderType type) { int ver_driver = GetVersion(); - strcpy(dst, vert ? vert : frag); + String patched_code = code; if (ver_driver >= 130) - return; + return patched_code; int ver_shader = 110; - char *parser = strstr(dst, "#version"); + char *parser = strstr(patched_code.C(), "#version"); if (parser) ver_shader = atoi(parser + strlen("#version")); @@ -878,7 +900,7 @@ void ShaderData::Patch(char *dst, char const *vert, char const *frag) { /* FIXME: this isn't elegant but honestly, we don't care, this * whole file is going to die soon. */ - char *p = strstr(dst, "#version"); + char *p = strstr(patched_code.C(), "#version"); if (p) { p += 8; @@ -891,17 +913,17 @@ void ShaderData::Patch(char *dst, char const *vert, char const *frag) if (ver_shader > 120 && ver_driver <= 120) { - char const *end = dst + strlen(dst) + 1; + char const *end = patched_code.C() + patched_code.Count() + 1; /* Find main() */ - parser = strstr(dst, "main"); - if (!parser) return; + parser = strstr(patched_code.C(), "main"); + if (!parser) return patched_code; parser = strstr(parser, "("); - if (!parser) return; + if (!parser) return patched_code; parser = strstr(parser, ")"); - if (!parser) return; + if (!parser) return patched_code; parser = strstr(parser, "{"); - if (!parser) return; + if (!parser) return patched_code; char *main = parser + 1; /* Perform main() replaces */ @@ -939,7 +961,7 @@ void ShaderData::Patch(char *dst, char const *vert, char const *frag) for (char const * const *rep = main_replaces; rep[0]; rep += 2) { - char *match = strstr(dst, rep[0]); + char *match = strstr(patched_code.C(), rep[0]); if (match && match < main) { size_t l0 = strlen(rep[0]); @@ -956,10 +978,10 @@ void ShaderData::Patch(char *dst, char const *vert, char const *frag) char const * const fast_replaces[] = { "#version 130", "#version 120", - "in vec2", vert ? "attribute vec2" : "varying vec2", - "in vec3", vert ? "attribute vec3" : "varying vec3", - "in vec4", vert ? "attribute vec4" : "varying vec4", - "in mat4", vert ? "attribute mat4" : "varying mat4", + "in vec2", type == ShaderType::Vertex ? "attribute vec2" : "varying vec2", + "in vec3", type == ShaderType::Vertex ? "attribute vec3" : "varying vec3", + "in vec4", type == ShaderType::Vertex ? "attribute vec4" : "varying vec4", + "in mat4", type == ShaderType::Vertex ? "attribute mat4" : "varying mat4", "out vec2", "varying vec2", "out vec3", "varying vec3", "out vec4", "varying vec4", @@ -970,7 +992,7 @@ void ShaderData::Patch(char *dst, char const *vert, char const *frag) for (char const * const *rep = fast_replaces; rep[0]; rep += 2) { char *match; - while ((match = strstr(dst, rep[0]))) + while ((match = strstr(patched_code.C(), rep[0]))) { size_t l0 = strlen(rep[0]); size_t l1 = strlen(rep[1]); @@ -984,6 +1006,10 @@ void ShaderData::Patch(char *dst, char const *vert, char const *frag) } } } + + patched_code.Resize(strlen(patched_code.C())); + + return patched_code; } } /* namespace lol */