| @@ -82,33 +82,40 @@ void Shader::Destroy(Shader *shader) | |||||
| Shader::Shader(char const *vert, char const *frag) | Shader::Shader(char const *vert, char const *frag) | ||||
| : data(new ShaderData()) | : data(new ShaderData()) | ||||
| { | { | ||||
| char buf[4096]; | |||||
| char buf[4096], errbuf[4096]; | |||||
| char const *shader = buf; | char const *shader = buf; | ||||
| GLsizei len; | GLsizei len; | ||||
| #if !defined __CELLOS_LV2__ | #if !defined __CELLOS_LV2__ | ||||
| /* Compile vertex shader and fragment shader */ | |||||
| /* Compile vertex shader */ | |||||
| ShaderData::Patch(buf, vert); | ShaderData::Patch(buf, vert); | ||||
| data->vert_crc = Hash::Crc32(buf); | data->vert_crc = Hash::Crc32(buf); | ||||
| data->vert_id = glCreateShader(GL_VERTEX_SHADER); | data->vert_id = glCreateShader(GL_VERTEX_SHADER); | ||||
| glShaderSource(data->vert_id, 1, &shader, NULL); | glShaderSource(data->vert_id, 1, &shader, NULL); | ||||
| glCompileShader(data->vert_id); | glCompileShader(data->vert_id); | ||||
| glGetShaderInfoLog(data->vert_id, sizeof(buf), &len, buf); | |||||
| glGetShaderInfoLog(data->vert_id, sizeof(errbuf), &len, errbuf); | |||||
| if (len > 0) | if (len > 0) | ||||
| Log::Error("failed to compile vertex shader: %s", buf); | |||||
| { | |||||
| Log::Error("failed to compile vertex shader: %s", errbuf); | |||||
| Log::Error("shader source:\n%s\n", buf); | |||||
| } | |||||
| /* Compile fragment shader */ | |||||
| ShaderData::Patch(buf, frag); | ShaderData::Patch(buf, frag); | ||||
| data->frag_crc = Hash::Crc32(buf); | data->frag_crc = Hash::Crc32(buf); | ||||
| data->frag_id = glCreateShader(GL_FRAGMENT_SHADER); | data->frag_id = glCreateShader(GL_FRAGMENT_SHADER); | ||||
| glShaderSource(data->frag_id, 1, &shader, NULL); | glShaderSource(data->frag_id, 1, &shader, NULL); | ||||
| glCompileShader(data->frag_id); | glCompileShader(data->frag_id); | ||||
| glGetShaderInfoLog(data->frag_id, sizeof(buf), &len, buf); | |||||
| glGetShaderInfoLog(data->frag_id, sizeof(errbuf), &len, errbuf); | |||||
| if (len > 0) | if (len > 0) | ||||
| Log::Error("failed to compile fragment shader: %s", buf); | |||||
| { | |||||
| Log::Error("failed to compile fragment shader: %s", errbuf); | |||||
| Log::Error("shader source:\n%s\n", buf); | |||||
| } | |||||
| /* Create program */ | |||||
| data->prog_id = glCreateProgram(); | data->prog_id = glCreateProgram(); | ||||
| glAttachShader(data->prog_id, data->vert_id); | glAttachShader(data->prog_id, data->vert_id); | ||||
| glAttachShader(data->prog_id, data->frag_id); | glAttachShader(data->prog_id, data->frag_id); | ||||
| @@ -213,42 +220,99 @@ void ShaderData::Patch(char *dst, char const *src) | |||||
| { | { | ||||
| int version = GetVersion(); | int version = GetVersion(); | ||||
| strcpy(dst, src); | |||||
| if (version >= 130) | if (version >= 130) | ||||
| { | |||||
| strcpy(dst, src); | |||||
| return; | return; | ||||
| } | |||||
| if (version == 120) | |||||
| if (version >= 110) | |||||
| { | { | ||||
| static char const * const replaces[] = | |||||
| char *parser, *main; | |||||
| char const *end = dst + strlen(dst) + 1; | |||||
| /* Find main() */ | |||||
| parser = strstr(dst, "main"); | |||||
| if (!parser) return; | |||||
| parser = strstr(parser, "("); | |||||
| if (!parser) return; | |||||
| parser = strstr(parser, ")"); | |||||
| if (!parser) return; | |||||
| parser = strstr(parser, "{"); | |||||
| if (!parser) return; | |||||
| main = parser + 1; | |||||
| /* Perform main() replaces */ | |||||
| static char const * const main_replaces[] = | |||||
| { | { | ||||
| "#version 130", "#version 120", | |||||
| "\nin vec2", "\nvec2", | |||||
| "\nin vec3", "\nvec3", | |||||
| "\nin vec4", "\nvec4", | |||||
| "\nin mat4", "\nmat4", | |||||
| "in vec2 in_Vertex;", "vec2 in_Vertex = gl_Vertex.xy;", | |||||
| "in vec3 in_Vertex;", "vec3 in_Vertex = gl_Vertex.xyz;", | |||||
| "in vec4 in_Vertex;", "vec4 in_Vertex = gl_Vertex.xyzw;", | |||||
| "in vec2 in_Color;", "vec2 in_Color = gl_Color.xy;", | |||||
| "in vec3 in_Color;", "vec3 in_Color = gl_Color.xyz;", | |||||
| "in vec4 in_Color;", "vec4 in_Color = gl_Color.xyzw;", | |||||
| "in vec2 in_MultiTexCoord0;", | |||||
| "vec2 in_MultiTexCoord0 = gl_MultiTexCoord0.xy;", | |||||
| "in vec2 in_MultiTexCoord1;", | |||||
| "vec2 in_MultiTexCoord1 = gl_MultiTexCoord1.xy;", | |||||
| "in vec2 in_MultiTexCoord2;", | |||||
| "vec2 in_MultiTexCoord2 = gl_MultiTexCoord2.xy;", | |||||
| "in vec2 in_MultiTexCoord3;", | |||||
| "vec2 in_MultiTexCoord3 = gl_MultiTexCoord3.xy;", | |||||
| "in vec2 in_MultiTexCoord4;", | |||||
| "vec2 in_MultiTexCoord4 = gl_MultiTexCoord4.xy;", | |||||
| "in vec2 in_MultiTexCoord5;", | |||||
| "vec2 in_MultiTexCoord5 = gl_MultiTexCoord5.xy;", | |||||
| "in vec2 in_MultiTexCoord6;", | |||||
| "vec2 in_MultiTexCoord6 = gl_MultiTexCoord6.xy;", | |||||
| "in vec2 in_MultiTexCoord7;", | |||||
| "vec2 in_MultiTexCoord7 = gl_MultiTexCoord7.xy;", | |||||
| NULL | NULL | ||||
| }; | }; | ||||
| while (*src) | |||||
| for (char const * const *rep = main_replaces; rep[0]; rep += 2) | |||||
| { | { | ||||
| for (char const * const *rep = replaces; rep[0]; rep += 2) | |||||
| char *match = strstr(dst, rep[0]); | |||||
| if (match && match < main) | |||||
| { | { | ||||
| size_t l0 = strlen(rep[0]); | size_t l0 = strlen(rep[0]); | ||||
| if (!strncmp(src, rep[0], l0)) | |||||
| { | |||||
| src += l0; | |||||
| dst += sprintf(dst, "%s", rep[1]); | |||||
| goto next; | |||||
| } | |||||
| size_t l1 = strlen(rep[1]); | |||||
| memmove(main + l1, main, end - main); | |||||
| memcpy(main, rep[1], l1); | |||||
| memset(match, ' ', l0); | |||||
| main += l1; | |||||
| end += l1; | |||||
| } | } | ||||
| } | |||||
| *dst++ = *src++; | |||||
| /* Perform small replaces */ | |||||
| static char const * const fast_replaces[] = | |||||
| { | |||||
| "#version 130", "#version 120", | |||||
| "\nin vec2", "\n vec2", | |||||
| "\nin vec3", "\n vec3", | |||||
| "\nin vec4", "\n vec4", | |||||
| "\nin mat4", "\n mat4", | |||||
| NULL | |||||
| }; | |||||
| next: continue; | |||||
| for (char const * const *rep = fast_replaces; rep[0]; rep += 2) | |||||
| { | |||||
| char *match; | |||||
| while ((match = strstr(dst, rep[0]))) | |||||
| { | |||||
| size_t l0 = strlen(rep[0]); | |||||
| size_t l1 = strlen(rep[1]); | |||||
| if (l1 > l0) | |||||
| memmove(match + l1, match + l0, (end - match) - l0); | |||||
| memcpy(match, rep[1], l1); | |||||
| if (l1 < l0) | |||||
| memset(match + l0, ' ', l1 - l0); | |||||
| end += l1 - l0; | |||||
| } | |||||
| } | } | ||||
| *dst = '\0'; | |||||
| } | } | ||||
| } | } | ||||