| @@ -82,33 +82,40 @@ void Shader::Destroy(Shader *shader) | |||
| Shader::Shader(char const *vert, char const *frag) | |||
| : data(new ShaderData()) | |||
| { | |||
| char buf[4096]; | |||
| char buf[4096], errbuf[4096]; | |||
| char const *shader = buf; | |||
| GLsizei len; | |||
| #if !defined __CELLOS_LV2__ | |||
| /* Compile vertex shader and fragment shader */ | |||
| /* Compile vertex shader */ | |||
| ShaderData::Patch(buf, vert); | |||
| data->vert_crc = Hash::Crc32(buf); | |||
| data->vert_id = glCreateShader(GL_VERTEX_SHADER); | |||
| glShaderSource(data->vert_id, 1, &shader, NULL); | |||
| glCompileShader(data->vert_id); | |||
| glGetShaderInfoLog(data->vert_id, sizeof(buf), &len, buf); | |||
| glGetShaderInfoLog(data->vert_id, sizeof(errbuf), &len, errbuf); | |||
| 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); | |||
| data->frag_crc = Hash::Crc32(buf); | |||
| data->frag_id = glCreateShader(GL_FRAGMENT_SHADER); | |||
| glShaderSource(data->frag_id, 1, &shader, NULL); | |||
| glCompileShader(data->frag_id); | |||
| glGetShaderInfoLog(data->frag_id, sizeof(buf), &len, buf); | |||
| glGetShaderInfoLog(data->frag_id, sizeof(errbuf), &len, errbuf); | |||
| 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(); | |||
| glAttachShader(data->prog_id, data->vert_id); | |||
| glAttachShader(data->prog_id, data->frag_id); | |||
| @@ -213,42 +220,99 @@ void ShaderData::Patch(char *dst, char const *src) | |||
| { | |||
| int version = GetVersion(); | |||
| strcpy(dst, src); | |||
| if (version >= 130) | |||
| { | |||
| strcpy(dst, src); | |||
| 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 | |||
| }; | |||
| 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]); | |||
| 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'; | |||
| } | |||
| } | |||