|
|
@@ -13,6 +13,8 @@ |
|
|
|
#endif |
|
|
|
|
|
|
|
#include <cmath> |
|
|
|
#include <cstring> |
|
|
|
#include <cstdio> |
|
|
|
|
|
|
|
#ifdef WIN32 |
|
|
|
# define WIN32_LEAN_AND_MEAN |
|
|
@@ -37,6 +39,10 @@ private: |
|
|
|
GLuint prog_id, vert_id, frag_id; |
|
|
|
uint32_t vert_crc, frag_crc; |
|
|
|
|
|
|
|
/* Shader patcher */ |
|
|
|
static int GetVersion(); |
|
|
|
static void Patch(char *dst, char const *src); |
|
|
|
|
|
|
|
/* Global shader cache */ |
|
|
|
static Shader *shaders[]; |
|
|
|
static int nshaders; |
|
|
@@ -77,21 +83,26 @@ Shader::Shader(char const *vert, char const *frag) |
|
|
|
: data(new ShaderData()) |
|
|
|
{ |
|
|
|
char buf[4096]; |
|
|
|
char const *shader = buf; |
|
|
|
GLsizei len; |
|
|
|
|
|
|
|
#if !defined __CELLOS_LV2__ |
|
|
|
data->vert_crc = Hash::Crc32(vert); |
|
|
|
|
|
|
|
/* Compile vertex shader and fragment shader */ |
|
|
|
ShaderData::Patch(buf, vert); |
|
|
|
data->vert_crc = Hash::Crc32(buf); |
|
|
|
data->vert_id = glCreateShader(GL_VERTEX_SHADER); |
|
|
|
glShaderSource(data->vert_id, 1, &vert, NULL); |
|
|
|
glShaderSource(data->vert_id, 1, &shader, NULL); |
|
|
|
glCompileShader(data->vert_id); |
|
|
|
|
|
|
|
glGetShaderInfoLog(data->vert_id, sizeof(buf), &len, buf); |
|
|
|
if (len > 0) |
|
|
|
Log::Error("failed to compile vertex shader: %s", buf); |
|
|
|
|
|
|
|
data->frag_crc = Hash::Crc32(frag); |
|
|
|
ShaderData::Patch(buf, frag); |
|
|
|
data->frag_crc = Hash::Crc32(buf); |
|
|
|
data->frag_id = glCreateShader(GL_FRAGMENT_SHADER); |
|
|
|
glShaderSource(data->frag_id, 1, &frag, NULL); |
|
|
|
glShaderSource(data->frag_id, 1, &shader, NULL); |
|
|
|
glCompileShader(data->frag_id); |
|
|
|
|
|
|
|
glGetShaderInfoLog(data->frag_id, sizeof(buf), &len, buf); |
|
|
@@ -148,5 +159,98 @@ Shader::~Shader() |
|
|
|
#endif |
|
|
|
} |
|
|
|
|
|
|
|
/* Try to detect shader compiler features */ |
|
|
|
int ShaderData::GetVersion() |
|
|
|
{ |
|
|
|
static int version = 0; |
|
|
|
|
|
|
|
if (!version) |
|
|
|
{ |
|
|
|
char buf[4096]; |
|
|
|
GLsizei len; |
|
|
|
|
|
|
|
int id = glCreateShader(GL_VERTEX_SHADER); |
|
|
|
|
|
|
|
/* Can we compile 1.30 shaders? */ |
|
|
|
char const *test130 = |
|
|
|
"#version 130\n" |
|
|
|
"void main() { gl_Position = vec4(0.0, 0.0, 0.0, 0.0); }"; |
|
|
|
glShaderSource(id, 1, &test130, NULL); |
|
|
|
glCompileShader(id); |
|
|
|
glGetShaderInfoLog(id, sizeof(buf), &len, buf); |
|
|
|
if (len <= 0) |
|
|
|
version = 130; |
|
|
|
|
|
|
|
/* If not, can we compile 1.20 shaders? */ |
|
|
|
if (!version) |
|
|
|
{ |
|
|
|
char const *test120 = |
|
|
|
"#version 120\n" |
|
|
|
"void main() { gl_Position = vec4(0.0, 0.0, 0.0, 0.0); }"; |
|
|
|
glShaderSource(id, 1, &test120, NULL); |
|
|
|
glCompileShader(id); |
|
|
|
glGetShaderInfoLog(id, sizeof(buf), &len, buf); |
|
|
|
if (len <= 0) |
|
|
|
version = 120; |
|
|
|
} |
|
|
|
|
|
|
|
/* Otherwise, assume we can compile 1.10 shaders. */ |
|
|
|
if (!version) |
|
|
|
version = 110; |
|
|
|
|
|
|
|
glDeleteShader(id); |
|
|
|
} |
|
|
|
|
|
|
|
return version; |
|
|
|
} |
|
|
|
|
|
|
|
/* Simple shader source patching for old GLSL versions. |
|
|
|
* If supported version is 1.30, do nothing. |
|
|
|
* If supported version is 1.20: |
|
|
|
* - replace "#version 130" with "#version 120" |
|
|
|
*/ |
|
|
|
void ShaderData::Patch(char *dst, char const *src) |
|
|
|
{ |
|
|
|
int version = GetVersion(); |
|
|
|
|
|
|
|
if (version >= 130) |
|
|
|
{ |
|
|
|
strcpy(dst, src); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (version == 120) |
|
|
|
{ |
|
|
|
static char const * const replaces[] = |
|
|
|
{ |
|
|
|
"#version 130", "#version 120", |
|
|
|
"\nin vec2", "\nvec2", |
|
|
|
"\nin vec3", "\nvec3", |
|
|
|
"\nin vec4", "\nvec4", |
|
|
|
"\nin mat4", "\nmat4", |
|
|
|
NULL |
|
|
|
}; |
|
|
|
|
|
|
|
while (*src) |
|
|
|
{ |
|
|
|
for (char const * const *rep = replaces; rep[0]; rep += 2) |
|
|
|
{ |
|
|
|
size_t l0 = strlen(rep[0]); |
|
|
|
if (!strncmp(src, rep[0], l0)) |
|
|
|
{ |
|
|
|
src += l0; |
|
|
|
dst += sprintf(dst, "%s", rep[1]); |
|
|
|
goto next; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
*dst++ = *src++; |
|
|
|
|
|
|
|
next: continue; |
|
|
|
} |
|
|
|
*dst = '\0'; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} /* namespace lol */ |
|
|
|
|