| @@ -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 */ | |||