diff options
Diffstat (limited to 'src/engine/shader.cpp')
| -rw-r--r-- | src/engine/shader.cpp | 2373 |
1 files changed, 1184 insertions, 1189 deletions
diff --git a/src/engine/shader.cpp b/src/engine/shader.cpp index da17d4f..f7a740e 100644 --- a/src/engine/shader.cpp +++ b/src/engine/shader.cpp @@ -17,1206 +17,1201 @@ VAR(reservevpparams, 1, 16, 0); VAR(maxvsuniforms, 1, 0, 0); VAR(maxfsuniforms, 1, 0, 0); VAR(maxvaryings, 1, 0, 0); -VAR(dbgshader, 0, 0, 2); void loadshaders() { - standardshaders = true; - execfile("data/glsl.cfg"); - standardshaders = false; + standardshaders = true; + execfile("data/glsl.cfg"); + standardshaders = false; - nullshader = lookupshaderbyname("null"); - hudshader = lookupshaderbyname("hud"); - hudnotextureshader = lookupshaderbyname("hudnotexture"); - stdworldshader = lookupshaderbyname("stdworld"); - if(!nullshader || !hudshader || !hudnotextureshader || !stdworldshader) fatal("cannot find shader definitions"); + nullshader = lookupshaderbyname("null"); + hudshader = lookupshaderbyname("hud"); + hudnotextureshader = lookupshaderbyname("hudnotexture"); + stdworldshader = lookupshaderbyname("stdworld"); + if(!nullshader || !hudshader || !hudnotextureshader || !stdworldshader) fatal("cannot find shader definitions"); - dummyslot.shader = stdworldshader; + dummyslot.shader = stdworldshader; - textureshader = lookupshaderbyname("texture"); - notextureshader = lookupshaderbyname("notexture"); - nocolorshader = lookupshaderbyname("nocolor"); - foggedshader = lookupshaderbyname("fogged"); - foggednotextureshader = lookupshaderbyname("foggednotexture"); - - nullshader->set(); + textureshader = lookupshaderbyname("texture"); + notextureshader = lookupshaderbyname("notexture"); + nocolorshader = lookupshaderbyname("nocolor"); + foggedshader = lookupshaderbyname("fogged"); + foggednotextureshader = lookupshaderbyname("foggednotexture"); - loadedshaders = true; + nullshader->set(); + + loadedshaders = true; } -Shader *lookupshaderbyname(const char *name) -{ - Shader *s = shaders.access(name); - return s && s->loaded() ? s : NULL; +Shader *lookupshaderbyname(const char *name) +{ + Shader *s = shaders.access(name); + return s && s->loaded() ? s : NULL; } Shader *generateshader(const char *name, const char *fmt, ...) { - if(!loadedshaders) return NULL; - Shader *s = name ? lookupshaderbyname(name) : NULL; - if(!s) - { - defvformatstring(cmd, fmt, fmt); - bool wasstandard = standardshaders; - standardshaders = true; - execute(cmd); - standardshaders = wasstandard; - s = name ? lookupshaderbyname(name) : NULL; - if(!s) s = nullshader; - } - return s; + if(!loadedshaders) return NULL; + Shader *s = name ? lookupshaderbyname(name) : NULL; + if(!s) + { + defvformatstring(cmd, fmt, fmt); + bool wasstandard = standardshaders; + standardshaders = true; + execute(cmd); + standardshaders = wasstandard; + s = name ? lookupshaderbyname(name) : NULL; + if(!s) s = nullshader; + } + return s; } static void showglslinfo(GLenum type, GLuint obj, const char *name, const char **parts = NULL, int numparts = 0) { - GLint length = 0; - if(type) glGetShaderiv_(obj, GL_INFO_LOG_LENGTH, &length); - else glGetProgramiv_(obj, GL_INFO_LOG_LENGTH, &length); - if(length > 1) - { - conoutf(CON_ERROR, "GLSL ERROR (%s:%s)", type == GL_VERTEX_SHADER ? "VS" : (type == GL_FRAGMENT_SHADER ? "FS" : "PROG"), name); - FILE *l = getlogfile(); - if(l) - { - GLchar *log = new GLchar[length]; - if(type) glGetShaderInfoLog_(obj, length, &length, log); - else glGetProgramInfoLog_(obj, length, &length, log); - fprintf(l, "%s\n", log); - bool partlines = log[0] != '0'; - int line = 0; - loopi(numparts) - { - const char *part = parts[i]; - int startline = line; - while(*part) - { - const char *next = strchr(part, '\n'); - if(++line > 1000) goto done; - if(partlines) fprintf(l, "%d(%d): ", i, line - startline); else fprintf(l, "%d: ", line); - fwrite(part, 1, next ? next - part + 1 : strlen(part), l); - if(!next) { fputc('\n', l); break; } - part = next + 1; - } - } - done: - delete[] log; - } - } + GLint length = 0; + if(type) glGetShaderiv_(obj, GL_INFO_LOG_LENGTH, &length); + else glGetProgramiv_(obj, GL_INFO_LOG_LENGTH, &length); + if(length > 1) + { + conoutf(CON_ERROR, "GLSL ERROR (%s:%s)", type == GL_VERTEX_SHADER ? "VS" : (type == GL_FRAGMENT_SHADER ? "FS" : "PROG"), name); + FILE *l = getlogfile(); + if(l) + { + GLchar *log = new GLchar[length]; + if(type) glGetShaderInfoLog_(obj, length, &length, log); + else glGetProgramInfoLog_(obj, length, &length, log); + fprintf(l, "%s\n", log); + bool partlines = log[0] != '0'; + int line = 0; + loopi(numparts) + { + const char *part = parts[i]; + int startline = line; + while(*part) + { + const char *next = strchr(part, '\n'); + if(++line > 1000) goto done; + if(partlines) fprintf(l, "%d(%d): ", i, line - startline); else fprintf(l, "%d: ", line); + fwrite(part, 1, next ? next - part + 1 : strlen(part), l); + if(!next) { fputc('\n', l); break; } + part = next + 1; + } + } + done: + delete[] log; + } + } } -static void compileglslshader(GLenum type, GLuint &obj, const char *def, const char *name, bool msg = true) -{ - const char *source = def + strspn(def, " \t\r\n"); - const char *parts[16]; - int numparts = 0; - static const struct { int version; const char * const header; } glslversions[] = - { - { 330, "#version 330\n" }, - { 150, "#version 150\n" }, - { 130, "#version 130\n" }, - { 120, "#version 120\n" } - }; - loopi(sizeof(glslversions)/sizeof(glslversions[0])) if(glslversion >= glslversions[i].version) - { - parts[numparts++] = glslversions[i].header; - break; - } - if(glslversion >= 130) - { - if(type == GL_VERTEX_SHADER) parts[numparts++] = - "#define attribute in\n" - "#define varying out\n"; - else if(type == GL_FRAGMENT_SHADER) - { - parts[numparts++] = "#define varying in\n"; - if(glslversion < 150) parts[numparts++] = "precision highp float;\n"; - if(glversion >= 300) parts[numparts++] = - "out vec4 cube2_FragColor;\n" - "#define gl_FragColor cube2_FragColor\n"; - } - parts[numparts++] = - "#define texture2D(sampler, coords) texture(sampler, coords)\n" - "#define texture2DProj(sampler, coords) textureProj(sampler, coords)\n" - "#define textureCube(sampler, coords) texture(sampler, coords)\n"; - } - parts[numparts++] = source; - - obj = glCreateShader_(type); - glShaderSource_(obj, numparts, (const GLchar **)parts, NULL); - glCompileShader_(obj); - GLint success; - glGetShaderiv_(obj, GL_COMPILE_STATUS, &success); - if(!success) - { - if(msg) showglslinfo(type, obj, name, parts, numparts); - glDeleteShader_(obj); - obj = 0; - } - else if(dbgshader > 1 && msg) showglslinfo(type, obj, name, parts, numparts); -} - -VAR(dbgubo, 0, 0, 1); +static void compileglslshader(GLenum type, GLuint &obj, const char *def, const char *name, bool msg = true) +{ + const char *source = def + strspn(def, " \t\r\n"); + const char *parts[16]; + int numparts = 0; + static const struct { int version; const char * const header; } glslversions[] = + { + { 330, "#version 330\n" }, + { 150, "#version 150\n" }, + { 130, "#version 130\n" }, + { 120, "#version 120\n" } + }; + loopi(sizeof(glslversions)/sizeof(glslversions[0])) if(glslversion >= glslversions[i].version) + { + parts[numparts++] = glslversions[i].header; + break; + } + if(glslversion >= 130) + { + if(type == GL_VERTEX_SHADER) parts[numparts++] = + "#define attribute in\n" + "#define varying out\n"; + else if(type == GL_FRAGMENT_SHADER) + { + parts[numparts++] = "#define varying in\n"; + if(glslversion < 150) parts[numparts++] = "precision highp float;\n"; + if(glversion >= 300) parts[numparts++] = + "out vec4 cube2_FragColor;\n" + "#define gl_FragColor cube2_FragColor\n"; + } + parts[numparts++] = + "#define texture2D(sampler, coords) texture(sampler, coords)\n" + "#define texture2DProj(sampler, coords) textureProj(sampler, coords)\n" + "#define textureCube(sampler, coords) texture(sampler, coords)\n"; + } + parts[numparts++] = source; + + obj = glCreateShader_(type); + glShaderSource_(obj, numparts, (const GLchar **)parts, NULL); + glCompileShader_(obj); + GLint success; + glGetShaderiv_(obj, GL_COMPILE_STATUS, &success); + if(!success) + { + if(msg) showglslinfo(type, obj, name, parts, numparts); + glDeleteShader_(obj); + obj = 0; + } +} static void bindglsluniform(Shader &s, UniformLoc &u) { - u.loc = glGetUniformLocation_(s.program, u.name); - if(!u.blockname || !hasUBO) return; - GLuint bidx = glGetUniformBlockIndex_(s.program, u.blockname); - GLuint uidx = GL_INVALID_INDEX; - glGetUniformIndices_(s.program, 1, &u.name, &uidx); - if(bidx != GL_INVALID_INDEX && uidx != GL_INVALID_INDEX) - { - GLint sizeval = 0, offsetval = 0, strideval = 0; - glGetActiveUniformBlockiv_(s.program, bidx, GL_UNIFORM_BLOCK_DATA_SIZE, &sizeval); - if(sizeval <= 0) return; - glGetActiveUniformsiv_(s.program, 1, &uidx, GL_UNIFORM_OFFSET, &offsetval); - if(u.stride > 0) - { - glGetActiveUniformsiv_(s.program, 1, &uidx, GL_UNIFORM_ARRAY_STRIDE, &strideval); - if(strideval > u.stride) return; - } - u.offset = offsetval; - u.size = sizeval; - glUniformBlockBinding_(s.program, bidx, u.binding); - if(dbgubo) conoutf(CON_DEBUG, "UBO: %s:%s:%d, offset: %d, size: %d, stride: %d", u.name, u.blockname, u.binding, offsetval, sizeval, strideval); - } + u.loc = glGetUniformLocation_(s.program, u.name); + if(!u.blockname || !hasUBO) return; + GLuint bidx = glGetUniformBlockIndex_(s.program, u.blockname); + GLuint uidx = GL_INVALID_INDEX; + glGetUniformIndices_(s.program, 1, &u.name, &uidx); + if(bidx != GL_INVALID_INDEX && uidx != GL_INVALID_INDEX) + { + GLint sizeval = 0, offsetval = 0, strideval = 0; + glGetActiveUniformBlockiv_(s.program, bidx, GL_UNIFORM_BLOCK_DATA_SIZE, &sizeval); + if(sizeval <= 0) return; + glGetActiveUniformsiv_(s.program, 1, &uidx, GL_UNIFORM_OFFSET, &offsetval); + if(u.stride > 0) + { + glGetActiveUniformsiv_(s.program, 1, &uidx, GL_UNIFORM_ARRAY_STRIDE, &strideval); + if(strideval > u.stride) return; + } + u.offset = offsetval; + u.size = sizeval; + glUniformBlockBinding_(s.program, bidx, u.binding); + } } static void linkglslprogram(Shader &s, bool msg = true) { - s.program = s.vsobj && s.psobj ? glCreateProgram_() : 0; - GLint success = 0; - if(s.program) - { - glAttachShader_(s.program, s.vsobj); - glAttachShader_(s.program, s.psobj); - uint attribs = 0; - loopv(s.attriblocs) - { - AttribLoc &a = s.attriblocs[i]; - glBindAttribLocation_(s.program, a.loc, a.name); - attribs |= 1<<a.loc; - } - loopi(gle::MAXATTRIBS) if(!(attribs&(1<<i))) glBindAttribLocation_(s.program, i, gle::attribnames[i]); - if(glversion >= 300) - { - glBindFragDataLocation_(s.program, 0, "cube2_FragColor"); - } - glLinkProgram_(s.program); - glGetProgramiv_(s.program, GL_LINK_STATUS, &success); - } - if(success) - { - glUseProgram_(s.program); - loopi(8) - { - static const char * const texnames[8] = { "tex0", "tex1", "tex2", "tex3", "tex4", "tex5", "tex6", "tex7" }; - GLint loc = glGetUniformLocation_(s.program, texnames[i]); - if(loc != -1) glUniform1i_(loc, i); - } - loopv(s.defaultparams) - { - SlotShaderParamState ¶m = s.defaultparams[i]; - param.loc = glGetUniformLocation_(s.program, param.name); - } - loopv(s.uniformlocs) bindglsluniform(s, s.uniformlocs[i]); - glUseProgram_(0); - } - else if(s.program) - { - if(msg) showglslinfo(GL_FALSE, s.program, s.name); - glDeleteProgram_(s.program); - s.program = 0; - } + s.program = s.vsobj && s.psobj ? glCreateProgram_() : 0; + GLint success = 0; + if(s.program) + { + glAttachShader_(s.program, s.vsobj); + glAttachShader_(s.program, s.psobj); + uint attribs = 0; + loopv(s.attriblocs) + { + AttribLoc &a = s.attriblocs[i]; + glBindAttribLocation_(s.program, a.loc, a.name); + attribs |= 1<<a.loc; + } + loopi(gle::MAXATTRIBS) if(!(attribs&(1<<i))) glBindAttribLocation_(s.program, i, gle::attribnames[i]); + if(glversion >= 300) + { + glBindFragDataLocation_(s.program, 0, "cube2_FragColor"); + } + glLinkProgram_(s.program); + glGetProgramiv_(s.program, GL_LINK_STATUS, &success); + } + if(success) + { + glUseProgram_(s.program); + loopi(8) + { + static const char * const texnames[8] = { "tex0", "tex1", "tex2", "tex3", "tex4", "tex5", "tex6", "tex7" }; + GLint loc = glGetUniformLocation_(s.program, texnames[i]); + if(loc != -1) glUniform1i_(loc, i); + } + loopv(s.defaultparams) + { + SlotShaderParamState ¶m = s.defaultparams[i]; + param.loc = glGetUniformLocation_(s.program, param.name); + } + loopv(s.uniformlocs) bindglsluniform(s, s.uniformlocs[i]); + glUseProgram_(0); + } + else if(s.program) + { + if(msg) showglslinfo(GL_FALSE, s.program, s.name); + glDeleteProgram_(s.program); + s.program = 0; + } } int getlocalparam(const char *name) { - return localparams.access(name, int(localparams.numelems)); + return localparams.access(name, int(localparams.numelems)); } static int addlocalparam(Shader &s, const char *name, int loc, int size, GLenum format) { - int idx = getlocalparam(name); - if(idx >= s.localparamremap.length()) - { - int n = idx + 1 - s.localparamremap.length(); - memset(s.localparamremap.pad(n), 0xFF, n); - } - s.localparamremap[idx] = s.localparams.length(); - - LocalShaderParamState &l = s.localparams.add(); - l.name = name; - l.loc = loc; - l.size = size; - l.format = format; - return idx; + int idx = getlocalparam(name); + if(idx >= s.localparamremap.length()) + { + int n = idx + 1 - s.localparamremap.length(); + memset(s.localparamremap.pad(n), 0xFF, n); + } + s.localparamremap[idx] = s.localparams.length(); + + LocalShaderParamState &l = s.localparams.add(); + l.name = name; + l.loc = loc; + l.size = size; + l.format = format; + return idx; } GlobalShaderParamState *getglobalparam(const char *name) { - GlobalShaderParamState *param = globalparams.access(name); - if(!param) - { - param = &globalparams[name]; - param->name = name; - memset(param->buf, -1, sizeof(param->buf)); - param->version = -1; - } - return param; + GlobalShaderParamState *param = globalparams.access(name); + if(!param) + { + param = &globalparams[name]; + param->name = name; + memset(param->buf, -1, sizeof(param->buf)); + param->version = -1; + } + return param; } static GlobalShaderParamUse *addglobalparam(Shader &s, GlobalShaderParamState *param, int loc, int size, GLenum format) { - GlobalShaderParamUse &g = s.globalparams.add(); - g.param = param; - g.version = -2; - g.loc = loc; - g.size = size; - g.format = format; - return &g; + GlobalShaderParamUse &g = s.globalparams.add(); + g.param = param; + g.version = -2; + g.loc = loc; + g.size = size; + g.format = format; + return &g; } static void setglsluniformformat(Shader &s, const char *name, GLenum format, int size) { - switch(format) - { - case GL_FLOAT: - case GL_FLOAT_VEC2: - case GL_FLOAT_VEC3: - case GL_FLOAT_VEC4: - case GL_INT: - case GL_INT_VEC2: - case GL_INT_VEC3: - case GL_INT_VEC4: - case GL_BOOL: - case GL_BOOL_VEC2: - case GL_BOOL_VEC3: - case GL_BOOL_VEC4: - case GL_FLOAT_MAT2: - case GL_FLOAT_MAT3: - case GL_FLOAT_MAT4: - break; - default: - return; - } - if(!strncmp(name, "gl_", 3)) return; - - int loc = glGetUniformLocation_(s.program, name); - if(loc < 0) return; - loopvj(s.defaultparams) if(s.defaultparams[j].loc == loc) - { - s.defaultparams[j].format = format; - return; - } - loopvj(s.uniformlocs) if(s.uniformlocs[j].loc == loc) return; - loopvj(s.globalparams) if(s.globalparams[j].loc == loc) return; - loopvj(s.localparams) if(s.localparams[j].loc == loc) return; - - name = getshaderparamname(name); - GlobalShaderParamState *param = globalparams.access(name); - if(param) addglobalparam(s, param, loc, size, format); - else addlocalparam(s, name, loc, size, format); + switch(format) + { + case GL_FLOAT: + case GL_FLOAT_VEC2: + case GL_FLOAT_VEC3: + case GL_FLOAT_VEC4: + case GL_INT: + case GL_INT_VEC2: + case GL_INT_VEC3: + case GL_INT_VEC4: + case GL_BOOL: + case GL_BOOL_VEC2: + case GL_BOOL_VEC3: + case GL_BOOL_VEC4: + case GL_FLOAT_MAT2: + case GL_FLOAT_MAT3: + case GL_FLOAT_MAT4: + break; + default: + return; + } + if(!strncmp(name, "gl_", 3)) return; + + int loc = glGetUniformLocation_(s.program, name); + if(loc < 0) return; + loopvj(s.defaultparams) if(s.defaultparams[j].loc == loc) + { + s.defaultparams[j].format = format; + return; + } + loopvj(s.uniformlocs) if(s.uniformlocs[j].loc == loc) return; + loopvj(s.globalparams) if(s.globalparams[j].loc == loc) return; + loopvj(s.localparams) if(s.localparams[j].loc == loc) return; + + name = getshaderparamname(name); + GlobalShaderParamState *param = globalparams.access(name); + if(param) addglobalparam(s, param, loc, size, format); + else addlocalparam(s, name, loc, size, format); } static void allocglslactiveuniforms(Shader &s) { - GLint numactive = 0; - glGetProgramiv_(s.program, GL_ACTIVE_UNIFORMS, &numactive); - string name; - loopi(numactive) - { - GLsizei namelen = 0; - GLint size = 0; - GLenum format = GL_FLOAT_VEC4; - name[0] = '\0'; - glGetActiveUniform_(s.program, i, sizeof(name)-1, &namelen, &size, &format, name); - if(namelen <= 0 || size <= 0) continue; - name[clamp(int(namelen), 0, (int)sizeof(name)-2)] = '\0'; - char *brak = strchr(name, '['); - if(brak) *brak = '\0'; - setglsluniformformat(s, name, format, size); - } + GLint numactive = 0; + glGetProgramiv_(s.program, GL_ACTIVE_UNIFORMS, &numactive); + string name; + loopi(numactive) + { + GLsizei namelen = 0; + GLint size = 0; + GLenum format = GL_FLOAT_VEC4; + name[0] = '\0'; + glGetActiveUniform_(s.program, i, sizeof(name)-1, &namelen, &size, &format, name); + if(namelen <= 0 || size <= 0) continue; + name[clamp(int(namelen), 0, (int)sizeof(name)-2)] = '\0'; + char *brak = strchr(name, '['); + if(brak) *brak = '\0'; + setglsluniformformat(s, name, format, size); + } } void Shader::allocparams(Slot *slot) { - if(slot) - { + if(slot) + { #define UNIFORMTEX(name, tmu) \ - { \ - loc = glGetUniformLocation_(program, name); \ - int val = tmu; \ - if(loc != -1) glUniform1i_(loc, val); \ - } - int loc, tmu = 2; - if(type & SHADER_NORMALSLMS) - { - UNIFORMTEX("lmcolor", 1); - UNIFORMTEX("lmdir", 2); - tmu++; - } - else UNIFORMTEX("lightmap", 1); - if(type & SHADER_ENVMAP) UNIFORMTEX("envmap", tmu++); - UNIFORMTEX("shadowmap", 7); - int stex = 0; - loopv(slot->sts) - { - Slot::Tex &t = slot->sts[i]; - switch(t.type) - { - case TEX_DIFFUSE: UNIFORMTEX("diffusemap", 0); break; - case TEX_NORMAL: UNIFORMTEX("normalmap", tmu++); break; - case TEX_GLOW: UNIFORMTEX("glowmap", tmu++); break; - case TEX_DECAL: UNIFORMTEX("decal", tmu++); break; - case TEX_SPEC: if(t.combined<0) UNIFORMTEX("specmap", tmu++); break; - case TEX_DEPTH: if(t.combined<0) UNIFORMTEX("depthmap", tmu++); break; - case TEX_ALPHA: if(t.combined<0) UNIFORMTEX("alphamap", tmu++); break; - case TEX_UNKNOWN: - { - defformatstring(sname, "stex%d", stex++); - UNIFORMTEX(sname, tmu++); - break; - } - } - } - } - allocglslactiveuniforms(*this); + { \ + loc = glGetUniformLocation_(program, name); \ + int val = tmu; \ + if(loc != -1) glUniform1i_(loc, val); \ + } + int loc, tmu = 2; + if(type & SHADER_NORMALSLMS) + { + UNIFORMTEX("lmcolor", 1); + UNIFORMTEX("lmdir", 2); + tmu++; + } + else UNIFORMTEX("lightmap", 1); + if(type & SHADER_ENVMAP) UNIFORMTEX("envmap", tmu++); + UNIFORMTEX("shadowmap", 7); + int stex = 0; + loopv(slot->sts) + { + Slot::Tex &t = slot->sts[i]; + switch(t.type) + { + case TEX_DIFFUSE: UNIFORMTEX("diffusemap", 0); break; + case TEX_NORMAL: UNIFORMTEX("normalmap", tmu++); break; + case TEX_GLOW: UNIFORMTEX("glowmap", tmu++); break; + case TEX_DECAL: UNIFORMTEX("decal", tmu++); break; + case TEX_SPEC: if(t.combined<0) UNIFORMTEX("specmap", tmu++); break; + case TEX_DEPTH: if(t.combined<0) UNIFORMTEX("depthmap", tmu++); break; + case TEX_ALPHA: if(t.combined<0) UNIFORMTEX("alphamap", tmu++); break; + case TEX_UNKNOWN: + { + defformatstring(sname, "stex%d", stex++); + UNIFORMTEX(sname, tmu++); + break; + } + } + } + } + allocglslactiveuniforms(*this); } int GlobalShaderParamState::nextversion = 0; void GlobalShaderParamState::resetversions() { - enumerate(shaders, Shader, s, - { - loopv(s.globalparams) - { - GlobalShaderParamUse &u = s.globalparams[i]; - if(u.version != u.param->version) u.version = -2; - } - }); - nextversion = 0; - enumerate(globalparams, GlobalShaderParamState, g, { g.version = ++nextversion; }); - enumerate(shaders, Shader, s, - { - loopv(s.globalparams) - { - GlobalShaderParamUse &u = s.globalparams[i]; - if(u.version >= 0) u.version = u.param->version; - } - }); + enumerate(shaders, Shader, s, + { + loopv(s.globalparams) + { + GlobalShaderParamUse &u = s.globalparams[i]; + if(u.version != u.param->version) u.version = -2; + } + }); + nextversion = 0; + enumerate(globalparams, GlobalShaderParamState, g, { g.version = ++nextversion; }); + enumerate(shaders, Shader, s, + { + loopv(s.globalparams) + { + GlobalShaderParamUse &u = s.globalparams[i]; + if(u.version >= 0) u.version = u.param->version; + } + }); } static float *findslotparam(Slot &s, const char *name, float *noval = NULL) { - loopv(s.params) - { - SlotShaderParam ¶m = s.params[i]; - if(name == param.name) return param.val; - } - loopv(s.shader->defaultparams) - { - SlotShaderParamState ¶m = s.shader->defaultparams[i]; - if(name == param.name) return param.val; - } - return noval; + loopv(s.params) + { + SlotShaderParam ¶m = s.params[i]; + if(name == param.name) return param.val; + } + loopv(s.shader->defaultparams) + { + SlotShaderParamState ¶m = s.shader->defaultparams[i]; + if(name == param.name) return param.val; + } + return noval; } static float *findslotparam(VSlot &s, const char *name, float *noval = NULL) { - loopv(s.params) - { - SlotShaderParam ¶m = s.params[i]; - if(name == param.name) return param.val; - } - return findslotparam(*s.slot, name, noval); + loopv(s.params) + { + SlotShaderParam ¶m = s.params[i]; + if(name == param.name) return param.val; + } + return findslotparam(*s.slot, name, noval); } static inline void setslotparam(SlotShaderParamState &l, const float *val) { - switch(l.format) - { - case GL_BOOL: - case GL_FLOAT: glUniform1fv_(l.loc, 1, val); break; - case GL_BOOL_VEC2: - case GL_FLOAT_VEC2: glUniform2fv_(l.loc, 1, val); break; - case GL_BOOL_VEC3: - case GL_FLOAT_VEC3: glUniform3fv_(l.loc, 1, val); break; - case GL_BOOL_VEC4: - case GL_FLOAT_VEC4: glUniform4fv_(l.loc, 1, val); break; - case GL_INT: glUniform1i_(l.loc, int(val[0])); break; - case GL_INT_VEC2: glUniform2i_(l.loc, int(val[0]), int(val[1])); break; - case GL_INT_VEC3: glUniform3i_(l.loc, int(val[0]), int(val[1]), int(val[2])); break; - case GL_INT_VEC4: glUniform4i_(l.loc, int(val[0]), int(val[1]), int(val[2]), int(val[3])); break; - } + switch(l.format) + { + case GL_BOOL: + case GL_FLOAT: glUniform1fv_(l.loc, 1, val); break; + case GL_BOOL_VEC2: + case GL_FLOAT_VEC2: glUniform2fv_(l.loc, 1, val); break; + case GL_BOOL_VEC3: + case GL_FLOAT_VEC3: glUniform3fv_(l.loc, 1, val); break; + case GL_BOOL_VEC4: + case GL_FLOAT_VEC4: glUniform4fv_(l.loc, 1, val); break; + case GL_INT: glUniform1i_(l.loc, int(val[0])); break; + case GL_INT_VEC2: glUniform2i_(l.loc, int(val[0]), int(val[1])); break; + case GL_INT_VEC3: glUniform3i_(l.loc, int(val[0]), int(val[1]), int(val[2])); break; + case GL_INT_VEC4: glUniform4i_(l.loc, int(val[0]), int(val[1]), int(val[2]), int(val[3])); break; + } } #define SETSLOTPARAM(l, mask, i, val) do { \ - if(!(mask&(1<<i))) { \ - mask |= 1<<i; \ - setslotparam(l, val); \ - } \ + if(!(mask&(1<<i))) { \ + mask |= 1<<i; \ + setslotparam(l, val); \ + } \ } while(0) #define SETSLOTPARAMS(slotparams) \ - loopv(slotparams) \ - { \ - SlotShaderParam &p = slotparams[i]; \ - if(!defaultparams.inrange(p.loc)) continue; \ - SlotShaderParamState &l = defaultparams[p.loc]; \ - SETSLOTPARAM(l, unimask, p.loc, p.val); \ - } + loopv(slotparams) \ + { \ + SlotShaderParam &p = slotparams[i]; \ + if(!defaultparams.inrange(p.loc)) continue; \ + SlotShaderParamState &l = defaultparams[p.loc]; \ + SETSLOTPARAM(l, unimask, p.loc, p.val); \ + } #define SETDEFAULTPARAMS \ - loopv(defaultparams) \ - { \ - SlotShaderParamState &l = defaultparams[i]; \ - SETSLOTPARAM(l, unimask, i, l.val); \ - } + loopv(defaultparams) \ + { \ + SlotShaderParamState &l = defaultparams[i]; \ + SETSLOTPARAM(l, unimask, i, l.val); \ + } void Shader::setslotparams(Slot &slot) { - uint unimask = 0; - SETSLOTPARAMS(slot.params) - SETDEFAULTPARAMS + uint unimask = 0; + SETSLOTPARAMS(slot.params) + SETDEFAULTPARAMS } void Shader::setslotparams(Slot &slot, VSlot &vslot) { - uint unimask = 0; - if(vslot.slot == &slot) - { - SETSLOTPARAMS(vslot.params) - SETSLOTPARAMS(slot.params) - SETDEFAULTPARAMS - } - else - { - SETSLOTPARAMS(slot.params) - SETDEFAULTPARAMS - } + uint unimask = 0; + if(vslot.slot == &slot) + { + SETSLOTPARAMS(vslot.params) + SETSLOTPARAMS(slot.params) + SETDEFAULTPARAMS + } + else + { + SETSLOTPARAMS(slot.params) + SETDEFAULTPARAMS + } } void Shader::bindprograms() { - if(this == lastshader || type&(SHADER_DEFERRED|SHADER_INVALID)) return; - glUseProgram_(program); - lastshader = this; + if(this == lastshader || type&(SHADER_DEFERRED|SHADER_INVALID)) return; + glUseProgram_(program); + lastshader = this; } bool Shader::compile() { - if(!vsstr) vsobj = !reusevs || reusevs->invalid() ? 0 : reusevs->vsobj; - else compileglslshader(GL_VERTEX_SHADER, vsobj, vsstr, name, dbgshader || !variantshader); - if(!psstr) psobj = !reuseps || reuseps->invalid() ? 0 : reuseps->psobj; - else compileglslshader(GL_FRAGMENT_SHADER, psobj, psstr, name, dbgshader || !variantshader); - linkglslprogram(*this, !variantshader); - return program!=0; + if(!vsstr) vsobj = !reusevs || reusevs->invalid() ? 0 : reusevs->vsobj; + else compileglslshader(GL_VERTEX_SHADER, vsobj, vsstr, name, !variantshader); + if(!psstr) psobj = !reuseps || reuseps->invalid() ? 0 : reuseps->psobj; + else compileglslshader(GL_FRAGMENT_SHADER, psobj, psstr, name, !variantshader); + linkglslprogram(*this, !variantshader); + return program!=0; } void Shader::cleanup(bool invalid) { - detailshader = NULL; - used = false; - if(vsobj) { if(!reusevs) glDeleteShader_(vsobj); vsobj = 0; } - if(psobj) { if(!reuseps) glDeleteShader_(psobj); psobj = 0; } - if(program) { glDeleteProgram_(program); program = 0; } - localparams.setsize(0); - localparamremap.setsize(0); - globalparams.setsize(0); - if(standard || invalid) - { - type = SHADER_INVALID; - DELETEA(vsstr); - DELETEA(psstr); - DELETEA(defer); - variants.setsize(0); - DELETEA(variantrows); - defaultparams.setsize(0); - attriblocs.setsize(0); - uniformlocs.setsize(0); - altshader = NULL; - loopi(MAXSHADERDETAIL) fastshader[i] = this; - reusevs = reuseps = NULL; - } - else loopv(defaultparams) defaultparams[i].loc = -1; - owner = NULL; + detailshader = NULL; + used = false; + if(vsobj) { if(!reusevs) glDeleteShader_(vsobj); vsobj = 0; } + if(psobj) { if(!reuseps) glDeleteShader_(psobj); psobj = 0; } + if(program) { glDeleteProgram_(program); program = 0; } + localparams.setsize(0); + localparamremap.setsize(0); + globalparams.setsize(0); + if(standard || invalid) + { + type = SHADER_INVALID; + DELETEA(vsstr); + DELETEA(psstr); + DELETEA(defer); + variants.setsize(0); + DELETEA(variantrows); + defaultparams.setsize(0); + attriblocs.setsize(0); + uniformlocs.setsize(0); + altshader = NULL; + loopi(MAXSHADERDETAIL) fastshader[i] = this; + reusevs = reuseps = NULL; + } + else loopv(defaultparams) defaultparams[i].loc = -1; + owner = NULL; } bool Shader::isnull(const Shader *s) { return !s; } static void genattriblocs(Shader &s, const char *vs, const char *ps, Shader *reusevs, Shader *reuseps) { - static int len = strlen("//:attrib"); - string name; - int loc; - if(reusevs) s.attriblocs = reusevs->attriblocs; - else while((vs = strstr(vs, "//:attrib"))) - { - if(sscanf(vs, "//:attrib %100s %d", name, &loc) == 2) - s.attriblocs.add(AttribLoc(getshaderparamname(name), loc)); - vs += len; - } + static int len = strlen("//:attrib"); + string name; + int loc; + if(reusevs) s.attriblocs = reusevs->attriblocs; + else while((vs = strstr(vs, "//:attrib"))) + { + if(sscanf(vs, "//:attrib %100s %d", name, &loc) == 2) + s.attriblocs.add(AttribLoc(getshaderparamname(name), loc)); + vs += len; + } } static void genuniformlocs(Shader &s, const char *vs, const char *ps, Shader *reusevs, Shader *reuseps) { - static int len = strlen("//:uniform"); - string name, blockname; - int binding, stride; - if(reusevs) s.uniformlocs = reusevs->uniformlocs; - else while((vs = strstr(vs, "//:uniform"))) - { - int numargs = sscanf(vs, "//:uniform %100s %100s %d %d", name, blockname, &binding, &stride); - if(numargs >= 3) s.uniformlocs.add(UniformLoc(getshaderparamname(name), getshaderparamname(blockname), binding, numargs >= 4 ? stride : 0)); - else if(numargs >= 1) s.uniformlocs.add(UniformLoc(getshaderparamname(name))); - vs += len; - } + static int len = strlen("//:uniform"); + string name, blockname; + int binding, stride; + if(reusevs) s.uniformlocs = reusevs->uniformlocs; + else while((vs = strstr(vs, "//:uniform"))) + { + int numargs = sscanf(vs, "//:uniform %100s %100s %d %d", name, blockname, &binding, &stride); + if(numargs >= 3) s.uniformlocs.add(UniformLoc(getshaderparamname(name), getshaderparamname(blockname), binding, numargs >= 4 ? stride : 0)); + else if(numargs >= 1) s.uniformlocs.add(UniformLoc(getshaderparamname(name))); + vs += len; + } } Shader *newshader(int type, const char *name, const char *vs, const char *ps, Shader *variant = NULL, int row = 0) { - if(Shader::lastshader) - { - glUseProgram_(0); - Shader::lastshader = NULL; - } - - Shader *exists = shaders.access(name); - char *rname = exists ? exists->name : newstring(name); - Shader &s = shaders[rname]; - s.name = rname; - s.vsstr = newstring(vs); - s.psstr = newstring(ps); - DELETEA(s.defer); - s.type = type; - s.variantshader = variant; - s.standard = standardshaders; - if(forceshaders) s.forced = true; - s.reusevs = s.reuseps = NULL; - if(variant) - { - int row = 0, col = 0; - if(!vs[0] || sscanf(vs, "%d , %d", &row, &col) >= 1) - { - DELETEA(s.vsstr); - s.reusevs = !vs[0] ? variant : variant->getvariant(col, row); - } - row = col = 0; - if(!ps[0] || sscanf(ps, "%d , %d", &row, &col) >= 1) - { - DELETEA(s.psstr); - s.reuseps = !ps[0] ? variant : variant->getvariant(col, row); - } - } - if(variant) loopv(variant->defaultparams) s.defaultparams.add(variant->defaultparams[i]); - else loopv(slotparams) s.defaultparams.add(slotparams[i]); - s.attriblocs.setsize(0); - s.uniformlocs.setsize(0); - genattriblocs(s, vs, ps, s.reusevs, s.reuseps); - genuniformlocs(s, vs, ps, s.reusevs, s.reuseps); - if(!s.compile()) - { - s.cleanup(true); - if(variant) shaders.remove(rname); - return NULL; - } - if(variant) variant->addvariant(row, &s); - s.fixdetailshader(); - return &s; + if(Shader::lastshader) + { + glUseProgram_(0); + Shader::lastshader = NULL; + } + + Shader *exists = shaders.access(name); + char *rname = exists ? exists->name : newstring(name); + Shader &s = shaders[rname]; + s.name = rname; + s.vsstr = newstring(vs); + s.psstr = newstring(ps); + DELETEA(s.defer); + s.type = type; + s.variantshader = variant; + s.standard = standardshaders; + if(forceshaders) s.forced = true; + s.reusevs = s.reuseps = NULL; + if(variant) + { + int row = 0, col = 0; + if(!vs[0] || sscanf(vs, "%d , %d", &row, &col) >= 1) + { + DELETEA(s.vsstr); + s.reusevs = !vs[0] ? variant : variant->getvariant(col, row); + } + row = col = 0; + if(!ps[0] || sscanf(ps, "%d , %d", &row, &col) >= 1) + { + DELETEA(s.psstr); + s.reuseps = !ps[0] ? variant : variant->getvariant(col, row); + } + } + if(variant) loopv(variant->defaultparams) s.defaultparams.add(variant->defaultparams[i]); + else loopv(slotparams) s.defaultparams.add(slotparams[i]); + s.attriblocs.setsize(0); + s.uniformlocs.setsize(0); + genattriblocs(s, vs, ps, s.reusevs, s.reuseps); + genuniformlocs(s, vs, ps, s.reusevs, s.reuseps); + if(!s.compile()) + { + s.cleanup(true); + if(variant) shaders.remove(rname); + return NULL; + } + if(variant) variant->addvariant(row, &s); + s.fixdetailshader(); + return &s; } void setupshaders() { - GLint val; - glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &val); - maxvsuniforms = val/4; - glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &val); - maxfsuniforms = val/4; - if(glversion < 300) - { - glGetIntegerv(GL_MAX_VARYING_COMPONENTS, &val); - maxvaryings = val; - } - - standardshaders = true; - nullshader = newshader(0, "<init>null", - "attribute vec4 vvertex;\n" - "void main(void) {\n" - " gl_Position = vvertex;\n" - "}\n", - "void main(void) {\n" - " gl_FragColor = vec4(1.0, 0.0, 1.0, 0.0);\n" - "}\n"); - hudshader = newshader(0, "<init>hud", - "attribute vec4 vvertex, vcolor;\n" - "attribute vec2 vtexcoord0;\n" - "uniform mat4 hudmatrix;\n" - "varying vec2 texcoord0;\n" - "varying vec4 color;\n" - "void main(void) {\n" - " gl_Position = hudmatrix * vvertex;\n" - " texcoord0 = vtexcoord0;\n" - " color = vcolor;\n" - "}\n", - "varying vec2 texcoord0;\n" - "varying vec4 color;\n" - "uniform sampler2D tex0;\n" - "void main(void) {\n" - " gl_FragColor = color * texture2D(tex0, texcoord0);\n" - "}\n"); - hudnotextureshader = newshader(0, "<init>hudnotexture", - "attribute vec4 vvertex, vcolor;\n" - "uniform mat4 hudmatrix;\n" - "varying vec4 color;\n" - "void main(void) {\n" - " gl_Position = hudmatrix * vvertex;\n" - " color = vcolor;\n" - "}\n", - "varying vec4 color;\n" - "void main(void) {\n" - " gl_FragColor = color;\n" - "}\n"); - standardshaders = false; - - if(!nullshader || !hudshader || !hudnotextureshader) fatal("failed to setup shaders"); - - dummyslot.shader = nullshader; + GLint val; + glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &val); + maxvsuniforms = val/4; + glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &val); + maxfsuniforms = val/4; + if(glversion < 300) + { + glGetIntegerv(GL_MAX_VARYING_COMPONENTS, &val); + maxvaryings = val; + } + + standardshaders = true; + nullshader = newshader(0, "<init>null", + "attribute vec4 vvertex;\n" + "void main(void) {\n" + " gl_Position = vvertex;\n" + "}\n", + "void main(void) {\n" + " gl_FragColor = vec4(1.0, 0.0, 1.0, 0.0);\n" + "}\n"); + hudshader = newshader(0, "<init>hud", + "attribute vec4 vvertex, vcolor;\n" + "attribute vec2 vtexcoord0;\n" + "uniform mat4 hudmatrix;\n" + "varying vec2 texcoord0;\n" + "varying vec4 color;\n" + "void main(void) {\n" + " gl_Position = hudmatrix * vvertex;\n" + " texcoord0 = vtexcoord0;\n" + " color = vcolor;\n" + "}\n", + "varying vec2 texcoord0;\n" + "varying vec4 color;\n" + "uniform sampler2D tex0;\n" + "void main(void) {\n" + " gl_FragColor = color * texture2D(tex0, texcoord0);\n" + "}\n"); + hudnotextureshader = newshader(0, "<init>hudnotexture", + "attribute vec4 vvertex, vcolor;\n" + "uniform mat4 hudmatrix;\n" + "varying vec4 color;\n" + "void main(void) {\n" + " gl_Position = hudmatrix * vvertex;\n" + " color = vcolor;\n" + "}\n", + "varying vec4 color;\n" + "void main(void) {\n" + " gl_FragColor = color;\n" + "}\n"); + standardshaders = false; + + if(!nullshader || !hudshader || !hudnotextureshader) fatal("failed to setup shaders"); + + dummyslot.shader = nullshader; } static const char *findglslmain(const char *s) { - const char *main = strstr(s, "main"); - if(!main) return NULL; - for(; main >= s; main--) switch(*main) { case '\r': case '\n': case ';': return main + 1; } - return s; + const char *main = strstr(s, "main"); + if(!main) return NULL; + for(; main >= s; main--) switch(*main) { case '\r': case '\n': case ';': return main + 1; } + return s; } static void gengenericvariant(Shader &s, const char *sname, const char *vs, const char *ps, int row = 0) { - int rowoffset = 0; - bool vschanged = false, pschanged = false; - vector<char> vsv, psv; - vsv.put(vs, strlen(vs)+1); - psv.put(ps, strlen(ps)+1); - - static const int len = strlen("//:variant"), olen = strlen("override"); - for(char *vspragma = vsv.getbuf();; vschanged = true) - { - vspragma = strstr(vspragma, "//:variant"); - if(!vspragma) break; - if(sscanf(vspragma + len, "row %d", &rowoffset) == 1) continue; - memset(vspragma, ' ', len); - vspragma += len; - if(!strncmp(vspragma, "override", olen)) - { - memset(vspragma, ' ', olen); - vspragma += olen; - char *end = vspragma + strcspn(vspragma, "\n\r"); - end += strspn(end, "\n\r"); - int endlen = strcspn(end, "\n\r"); - memset(end, ' ', endlen); - } - } - for(char *pspragma = psv.getbuf();; pschanged = true) - { - pspragma = strstr(pspragma, "//:variant"); - if(!pspragma) break; - if(sscanf(pspragma + len, "row %d", &rowoffset) == 1) continue; - memset(pspragma, ' ', len); - pspragma += len; - if(!strncmp(pspragma, "override", olen)) - { - memset(pspragma, ' ', olen); - pspragma += olen; - char *end = pspragma + strcspn(pspragma, "\n\r"); - end += strspn(end, "\n\r"); - int endlen = strcspn(end, "\n\r"); - memset(end, ' ', endlen); - } - } - row += rowoffset; - if(row < 0 || row >= MAXVARIANTROWS) return; - int col = s.numvariants(row); - defformatstring(varname, "<variant:%d,%d>%s", col, row, sname); - string reuse; - if(col) formatstring(reuse, "%d", row); - else copystring(reuse, ""); - newshader(s.type, varname, vschanged ? vsv.getbuf() : reuse, pschanged ? psv.getbuf() : reuse, &s, row); + int rowoffset = 0; + bool vschanged = false, pschanged = false; + vector<char> vsv, psv; + vsv.put(vs, strlen(vs)+1); + psv.put(ps, strlen(ps)+1); + + static const int len = strlen("//:variant"), olen = strlen("override"); + for(char *vspragma = vsv.getbuf();; vschanged = true) + { + vspragma = strstr(vspragma, "//:variant"); + if(!vspragma) break; + if(sscanf(vspragma + len, "row %d", &rowoffset) == 1) continue; + memset(vspragma, ' ', len); + vspragma += len; + if(!strncmp(vspragma, "override", olen)) + { + memset(vspragma, ' ', olen); + vspragma += olen; + char *end = vspragma + strcspn(vspragma, "\n\r"); + end += strspn(end, "\n\r"); + int endlen = strcspn(end, "\n\r"); + memset(end, ' ', endlen); + } + } + for(char *pspragma = psv.getbuf();; pschanged = true) + { + pspragma = strstr(pspragma, "//:variant"); + if(!pspragma) break; + if(sscanf(pspragma + len, "row %d", &rowoffset) == 1) continue; + memset(pspragma, ' ', len); + pspragma += len; + if(!strncmp(pspragma, "override", olen)) + { + memset(pspragma, ' ', olen); + pspragma += olen; + char *end = pspragma + strcspn(pspragma, "\n\r"); + end += strspn(end, "\n\r"); + int endlen = strcspn(end, "\n\r"); + memset(end, ' ', endlen); + } + } + row += rowoffset; + if(row < 0 || row >= MAXVARIANTROWS) return; + int col = s.numvariants(row); + defformatstring(varname, "<variant:%d,%d>%s", col, row, sname); + string reuse; + if(col) formatstring(reuse, "%d", row); + else copystring(reuse, ""); + newshader(s.type, varname, vschanged ? vsv.getbuf() : reuse, pschanged ? psv.getbuf() : reuse, &s, row); } static bool genwatervariant(Shader &s, const char *sname, const char *vs, const char *ps, int row = 2) { - if(!strstr(vs, "//:water") && !strstr(ps, "//:water")) return false; - - vector<char> vsw, psw; - - const char *vsmain = findglslmain(vs), *vsend = strrchr(vs, '}'); - if(!vsmain || !vsend) return false; - vsw.put(vs, vsmain - vs); - const char *fadeparams = "\nuniform vec4 waterfadeparams;\nvarying float fadedepth;\n"; - vsw.put(fadeparams, strlen(fadeparams)); - vsw.put(vsmain, vsend - vsmain); - const char *fadedef = "\nfadedepth = vvertex.z*waterfadeparams.x + waterfadeparams.y;\n"; - vsw.put(fadedef, strlen(fadedef)); - vsw.put(vsend, strlen(vsend)+1); - - const char *psmain = findglslmain(ps), *psend = strrchr(ps, '}'); - if(!psmain || !psend) return false; - psw.put(ps, psmain - ps); - const char *fadeinterp = "\nvarying float fadedepth;\n"; - psw.put(fadeinterp, strlen(fadeinterp)); - psw.put(psmain, psend - psmain); - const char *fade = "\ngl_FragColor.a = fadedepth;\n"; - psw.put(fade, strlen(fade)); - psw.put(psend, strlen(psend)+1); - - defformatstring(name, "<water>%s", sname); - Shader *variant = newshader(s.type, name, vsw.getbuf(), psw.getbuf(), &s, row); - return variant!=NULL; + if(!strstr(vs, "//:water") && !strstr(ps, "//:water")) return false; + + vector<char> vsw, psw; + + const char *vsmain = findglslmain(vs), *vsend = strrchr(vs, '}'); + if(!vsmain || !vsend) return false; + vsw.put(vs, vsmain - vs); + const char *fadeparams = "\nuniform vec4 waterfadeparams;\nvarying float fadedepth;\n"; + vsw.put(fadeparams, strlen(fadeparams)); + vsw.put(vsmain, vsend - vsmain); + const char *fadedef = "\nfadedepth = vvertex.z*waterfadeparams.x + waterfadeparams.y;\n"; + vsw.put(fadedef, strlen(fadedef)); + vsw.put(vsend, strlen(vsend)+1); + + const char *psmain = findglslmain(ps), *psend = strrchr(ps, '}'); + if(!psmain || !psend) return false; + psw.put(ps, psmain - ps); + const char *fadeinterp = "\nvarying float fadedepth;\n"; + psw.put(fadeinterp, strlen(fadeinterp)); + psw.put(psmain, psend - psmain); + const char *fade = "\ngl_FragColor.a = fadedepth;\n"; + psw.put(fade, strlen(fade)); + psw.put(psend, strlen(psend)+1); + + defformatstring(name, "<water>%s", sname); + Shader *variant = newshader(s.type, name, vsw.getbuf(), psw.getbuf(), &s, row); + return variant!=NULL; } bool minimizedynlighttcusage() { return glversion < 300 && maxvaryings < 48; } static void gendynlightvariant(Shader &s, const char *sname, const char *vs, const char *ps, int row = 0) { - int numlights = minimizedynlighttcusage() ? 1 : MAXDYNLIGHTS; - - const char *vspragma = strstr(vs, "//:dynlight"), *pspragma = strstr(ps, "//:dynlight"); - if(!vspragma || !pspragma) return; - - string pslight; - vspragma += strcspn(vspragma, "\n"); - if(*vspragma) vspragma++; - - if(sscanf(pspragma, "//:dynlight %100s", pslight)!=1) return; - - pspragma += strcspn(pspragma, "\n"); - if(*pspragma) pspragma++; - - const char *vsmain = findglslmain(vs), *psmain = findglslmain(ps); - if(vsmain > vspragma) vsmain = vs; - if(psmain > pspragma) psmain = ps; - - vector<char> vsdl, psdl; - loopi(MAXDYNLIGHTS) - { - vsdl.setsize(0); - psdl.setsize(0); - if(vsmain >= vs) vsdl.put(vs, vsmain - vs); - if(psmain >= ps) psdl.put(ps, psmain - ps); - - defformatstring(pos, "uniform vec4 dynlightpos[%d];\n", i+1); - vsdl.put(pos, strlen(pos)); - psdl.put(pos, strlen(pos)); - defformatstring(color, "uniform vec3 dynlightcolor[%d];\n", i+1); - psdl.put(color, strlen(color)); - - loopk(min(i+1, numlights)) - { - defformatstring(dir, "%sdynlight%ddir%s", !k ? "varying vec3 " : " ", k, k==i || k+1==numlights ? ";\n" : ","); - vsdl.put(dir, strlen(dir)); - psdl.put(dir, strlen(dir)); - } - - vsdl.put(vsmain, vspragma-vsmain); - psdl.put(psmain, pspragma-psmain); - - loopk(i+1) - { - defformatstring(tc, - k<numlights ? - "dynlight%ddir = vvertex.xyz*dynlightpos[%d].w + dynlightpos[%d].xyz;\n" : - "vec3 dynlight%ddir = dynlight0dir*dynlightpos[%d].w + dynlightpos[%d].xyz;\n", - k, k, k); - if(k < numlights) vsdl.put(tc, strlen(tc)); - else psdl.put(tc, strlen(tc)); - - defformatstring(dl, - "%s.rgb += dynlightcolor[%d] * (1.0 - clamp(dot(dynlight%ddir, dynlight%ddir), 0.0, 1.0));\n", - pslight, k, k, k); - psdl.put(dl, strlen(dl)); - } - - vsdl.put(vspragma, strlen(vspragma)+1); - psdl.put(pspragma, strlen(pspragma)+1); - - defformatstring(name, "<dynlight %d>%s", i+1, sname); - Shader *variant = newshader(s.type, name, vsdl.getbuf(), psdl.getbuf(), &s, row); - if(!variant) return; - if(row < 4) genwatervariant(s, name, vsdl.getbuf(), psdl.getbuf(), row+2); - } + int numlights = minimizedynlighttcusage() ? 1 : MAXDYNLIGHTS; + + const char *vspragma = strstr(vs, "//:dynlight"), *pspragma = strstr(ps, "//:dynlight"); + if(!vspragma || !pspragma) return; + + string pslight; + vspragma += strcspn(vspragma, "\n"); + if(*vspragma) vspragma++; + + if(sscanf(pspragma, "//:dynlight %100s", pslight)!=1) return; + + pspragma += strcspn(pspragma, "\n"); + if(*pspragma) pspragma++; + + const char *vsmain = findglslmain(vs), *psmain = findglslmain(ps); + if(vsmain > vspragma) vsmain = vs; + if(psmain > pspragma) psmain = ps; + + vector<char> vsdl, psdl; + loopi(MAXDYNLIGHTS) + { + vsdl.setsize(0); + psdl.setsize(0); + if(vsmain >= vs) vsdl.put(vs, vsmain - vs); + if(psmain >= ps) psdl.put(ps, psmain - ps); + + defformatstring(pos, "uniform vec4 dynlightpos[%d];\n", i+1); + vsdl.put(pos, strlen(pos)); + psdl.put(pos, strlen(pos)); + defformatstring(color, "uniform vec3 dynlightcolor[%d];\n", i+1); + psdl.put(color, strlen(color)); + + loopk(min(i+1, numlights)) + { + defformatstring(dir, "%sdynlight%ddir%s", !k ? "varying vec3 " : " ", k, k==i || k+1==numlights ? ";\n" : ","); + vsdl.put(dir, strlen(dir)); + psdl.put(dir, strlen(dir)); + } + + vsdl.put(vsmain, vspragma-vsmain); + psdl.put(psmain, pspragma-psmain); + + loopk(i+1) + { + defformatstring(tc, + k<numlights ? + "dynlight%ddir = vvertex.xyz*dynlightpos[%d].w + dynlightpos[%d].xyz;\n" : + "vec3 dynlight%ddir = dynlight0dir*dynlightpos[%d].w + dynlightpos[%d].xyz;\n", + k, k, k); + if(k < numlights) vsdl.put(tc, strlen(tc)); + else psdl.put(tc, strlen(tc)); + + defformatstring(dl, + "%s.rgb += dynlightcolor[%d] * (1.0 - clamp(dot(dynlight%ddir, dynlight%ddir), 0.0, 1.0));\n", + pslight, k, k, k); + psdl.put(dl, strlen(dl)); + } + + vsdl.put(vspragma, strlen(vspragma)+1); + psdl.put(pspragma, strlen(pspragma)+1); + + defformatstring(name, "<dynlight %d>%s", i+1, sname); + Shader *variant = newshader(s.type, name, vsdl.getbuf(), psdl.getbuf(), &s, row); + if(!variant) return; + if(row < 4) genwatervariant(s, name, vsdl.getbuf(), psdl.getbuf(), row+2); + } } static void genshadowmapvariant(Shader &s, const char *sname, const char *vs, const char *ps, int row = 1) { - const char *vspragma = strstr(vs, "//:shadowmap"), *pspragma = strstr(ps, "//:shadowmap"); - if(!vspragma || !pspragma) return; - - string pslight; - vspragma += strcspn(vspragma, "\n"); - if(*vspragma) vspragma++; - - if(sscanf(pspragma, "//:shadowmap %100s", pslight)!=1) return; - - pspragma += strcspn(pspragma, "\n"); - if(*pspragma) pspragma++; - - const char *vsmain = findglslmain(vs), *psmain = findglslmain(ps); - if(vsmain > vspragma) vsmain = vs; - if(psmain > pspragma) psmain = ps; - - vector<char> vssm, pssm; - if(vsmain >= vs) vssm.put(vs, vsmain - vs); - if(psmain >= ps) pssm.put(ps, psmain - ps); - - const char *vsdecl = - "uniform mat4 shadowmapproject;\n" - "varying vec3 shadowmaptc;\n"; - vssm.put(vsdecl, strlen(vsdecl)); - - const char *psdecl = - "uniform sampler2D shadowmap;\n" - "uniform vec4 shadowmapambient;\n" - "varying vec3 shadowmaptc;\n"; - pssm.put(psdecl, strlen(psdecl)); - - vssm.put(vsmain, vspragma-vsmain); - pssm.put(psmain, pspragma-psmain); - - extern int smoothshadowmappeel; - const char *tcgen = - "shadowmaptc = vec3(shadowmapproject * vvertex);\n"; - vssm.put(tcgen, strlen(tcgen)); - const char *sm = - smoothshadowmappeel ? - "vec4 smvals = texture2D(shadowmap, shadowmaptc.xy);\n" - "vec2 smdiff = clamp(smvals.xz - shadowmaptc.zz*smvals.y, 0.0, 1.0);\n" - "float shadowed = clamp((smdiff.x > 0.0 ? smvals.w : 0.0) - 8.0*smdiff.y, 0.0, 1.0);\n" : - - "vec4 smvals = texture2D(shadowmap, shadowmaptc.xy);\n" - "float smtest = shadowmaptc.z*smvals.y;\n" - "float shadowed = smtest < smvals.x && smtest > smvals.z ? smvals.w : 0.0;\n"; - pssm.put(sm, strlen(sm)); - defformatstring(smlight, - "%s.rgb -= shadowed*clamp(%s.rgb - shadowmapambient.rgb, 0.0, 1.0);\n", - pslight, pslight); - pssm.put(smlight, strlen(smlight)); - - vssm.put(vspragma, strlen(vspragma)+1); - pssm.put(pspragma, strlen(pspragma)+1); - - defformatstring(name, "<shadowmap>%s", sname); - Shader *variant = newshader(s.type, name, vssm.getbuf(), pssm.getbuf(), &s, row); - if(!variant) return; - genwatervariant(s, name, vssm.getbuf(), pssm.getbuf(), row+2); - - if(strstr(vs, "//:dynlight")) gendynlightvariant(s, name, vssm.getbuf(), pssm.getbuf(), row); + const char *vspragma = strstr(vs, "//:shadowmap"), *pspragma = strstr(ps, "//:shadowmap"); + if(!vspragma || !pspragma) return; + + string pslight; + vspragma += strcspn(vspragma, "\n"); + if(*vspragma) vspragma++; + + if(sscanf(pspragma, "//:shadowmap %100s", pslight)!=1) return; + + pspragma += strcspn(pspragma, "\n"); + if(*pspragma) pspragma++; + + const char *vsmain = findglslmain(vs), *psmain = findglslmain(ps); + if(vsmain > vspragma) vsmain = vs; + if(psmain > pspragma) psmain = ps; + + vector<char> vssm, pssm; + if(vsmain >= vs) vssm.put(vs, vsmain - vs); + if(psmain >= ps) pssm.put(ps, psmain - ps); + + const char *vsdecl = + "uniform mat4 shadowmapproject;\n" + "varying vec3 shadowmaptc;\n"; + vssm.put(vsdecl, strlen(vsdecl)); + + const char *psdecl = + "uniform sampler2D shadowmap;\n" + "uniform vec4 shadowmapambient;\n" + "varying vec3 shadowmaptc;\n"; + pssm.put(psdecl, strlen(psdecl)); + + vssm.put(vsmain, vspragma-vsmain); + pssm.put(psmain, pspragma-psmain); + + extern int smoothshadowmappeel; + const char *tcgen = + "shadowmaptc = vec3(shadowmapproject * vvertex);\n"; + vssm.put(tcgen, strlen(tcgen)); + const char *sm = + smoothshadowmappeel ? + "vec4 smvals = texture2D(shadowmap, shadowmaptc.xy);\n" + "vec2 smdiff = clamp(smvals.xz - shadowmaptc.zz*smvals.y, 0.0, 1.0);\n" + "float shadowed = clamp((smdiff.x > 0.0 ? smvals.w : 0.0) - 8.0*smdiff.y, 0.0, 1.0);\n" : + + "vec4 smvals = texture2D(shadowmap, shadowmaptc.xy);\n" + "float smtest = shadowmaptc.z*smvals.y;\n" + "float shadowed = smtest < smvals.x && smtest > smvals.z ? smvals.w : 0.0;\n"; + pssm.put(sm, strlen(sm)); + defformatstring(smlight, + "%s.rgb -= shadowed*clamp(%s.rgb - shadowmapambient.rgb, 0.0, 1.0);\n", + pslight, pslight); + pssm.put(smlight, strlen(smlight)); + + vssm.put(vspragma, strlen(vspragma)+1); + pssm.put(pspragma, strlen(pspragma)+1); + + defformatstring(name, "<shadowmap>%s", sname); + Shader *variant = newshader(s.type, name, vssm.getbuf(), pssm.getbuf(), &s, row); + if(!variant) return; + genwatervariant(s, name, vssm.getbuf(), pssm.getbuf(), row+2); + + if(strstr(vs, "//:dynlight")) gendynlightvariant(s, name, vssm.getbuf(), pssm.getbuf(), row); } static void genfogshader(vector<char> &vsbuf, vector<char> &psbuf, const char *vs, const char *ps) { - const char *vspragma = strstr(vs, "//:fog"), *pspragma = strstr(ps, "//:fog"); - if(!vspragma && !pspragma) return; - static const int pragmalen = strlen("//:fog"); - const char *vsmain = findglslmain(vs), *vsend = strrchr(vs, '}'); - if(vsmain && vsend) - { - vsbuf.put(vs, vsmain - vs); - const char *fogparams = "\nuniform vec4 fogplane;\nvarying float fogcoord;\n"; - vsbuf.put(fogparams, strlen(fogparams)); - vsbuf.put(vsmain, vsend - vsmain); - const char *vsfog = "\nfogcoord = dot(fogplane, gl_Position);\n"; - vsbuf.put(vsfog, strlen(vsfog)); - vsbuf.put(vsend, strlen(vsend)+1); - } - const char *psmain = findglslmain(ps), *psend = strrchr(ps, '}'); - if(psmain && psend) - { - psbuf.put(ps, psmain - ps); - const char *fogparams = - "\nuniform vec3 fogcolor;\n" - "uniform vec2 fogparams;\n" - "varying float fogcoord;\n"; - psbuf.put(fogparams, strlen(fogparams)); - psbuf.put(psmain, psend - psmain); - const char *psdef = "\n#define FOG_COLOR "; - const char *psfog = - pspragma && !strncmp(pspragma+pragmalen, "rgba", 4) ? - "\ngl_FragColor = mix((FOG_COLOR), gl_FragColor, clamp(fogcoord*fogparams.x + fogparams.y, 0.0, 1.0));\n" : - "\ngl_FragColor.rgb = mix((FOG_COLOR).rgb, gl_FragColor.rgb, clamp(fogcoord*fogparams.x + fogparams.y, 0.0, 1.0));\n"; - int clen = 0; - if(pspragma) - { - pspragma += pragmalen; - while(iscubealpha(*pspragma)) pspragma++; - while(*pspragma && !iscubespace(*pspragma)) pspragma++; - pspragma += strspn(pspragma, " \t\v\f"); - clen = strcspn(pspragma, "\r\n"); - } - if(clen <= 0) { pspragma = "fogcolor"; clen = strlen(pspragma); } - psbuf.put(psdef, strlen(psdef)); - psbuf.put(pspragma, clen); - psbuf.put(psfog, strlen(psfog)); - psbuf.put(psend, strlen(psend)+1); - } + const char *vspragma = strstr(vs, "//:fog"), *pspragma = strstr(ps, "//:fog"); + if(!vspragma && !pspragma) return; + static const int pragmalen = strlen("//:fog"); + const char *vsmain = findglslmain(vs), *vsend = strrchr(vs, '}'); + if(vsmain && vsend) + { + vsbuf.put(vs, vsmain - vs); + const char *fogparams = "\nuniform vec4 fogplane;\nvarying float fogcoord;\n"; + vsbuf.put(fogparams, strlen(fogparams)); + vsbuf.put(vsmain, vsend - vsmain); + const char *vsfog = "\nfogcoord = dot(fogplane, gl_Position);\n"; + vsbuf.put(vsfog, strlen(vsfog)); + vsbuf.put(vsend, strlen(vsend)+1); + } + const char *psmain = findglslmain(ps), *psend = strrchr(ps, '}'); + if(psmain && psend) + { + psbuf.put(ps, psmain - ps); + const char *fogparams = + "\nuniform vec3 fogcolor;\n" + "uniform vec2 fogparams;\n" + "varying float fogcoord;\n"; + psbuf.put(fogparams, strlen(fogparams)); + psbuf.put(psmain, psend - psmain); + const char *psdef = "\n#define FOG_COLOR "; + const char *psfog = + pspragma && !strncmp(pspragma+pragmalen, "rgba", 4) ? + "\ngl_FragColor = mix((FOG_COLOR), gl_FragColor, clamp(fogcoord*fogparams.x + fogparams.y, 0.0, 1.0));\n" : + "\ngl_FragColor.rgb = mix((FOG_COLOR).rgb, gl_FragColor.rgb, clamp(fogcoord*fogparams.x + fogparams.y, 0.0, 1.0));\n"; + int clen = 0; + if(pspragma) + { + pspragma += pragmalen; + while(iscubealpha(*pspragma)) pspragma++; + while(*pspragma && !iscubespace(*pspragma)) pspragma++; + pspragma += strspn(pspragma, " \t\v\f"); + clen = strcspn(pspragma, "\r\n"); + } + if(clen <= 0) { pspragma = "fogcolor"; clen = strlen(pspragma); } + psbuf.put(psdef, strlen(psdef)); + psbuf.put(pspragma, clen); + psbuf.put(psfog, strlen(psfog)); + psbuf.put(psend, strlen(psend)+1); + } } static void genuniformdefs(vector<char> &vsbuf, vector<char> &psbuf, const char *vs, const char *ps, Shader *variant = NULL) { - if(variant ? variant->defaultparams.empty() : slotparams.empty()) return; - const char *vsmain = findglslmain(vs), *psmain = findglslmain(ps); - if(!vsmain || !psmain) return; - vsbuf.put(vs, vsmain - vs); - psbuf.put(ps, psmain - ps); - if(variant) loopv(variant->defaultparams) - { - defformatstring(uni, "\nuniform vec4 %s;\n", variant->defaultparams[i].name); - vsbuf.put(uni, strlen(uni)); - psbuf.put(uni, strlen(uni)); - } - else loopv(slotparams) - { - defformatstring(uni, "\nuniform vec4 %s;\n", slotparams[i].name); - vsbuf.put(uni, strlen(uni)); - psbuf.put(uni, strlen(uni)); - } - vsbuf.put(vsmain, strlen(vsmain)+1); - psbuf.put(psmain, strlen(psmain)+1); + if(variant ? variant->defaultparams.empty() : slotparams.empty()) return; + const char *vsmain = findglslmain(vs), *psmain = findglslmain(ps); + if(!vsmain || !psmain) return; + vsbuf.put(vs, vsmain - vs); + psbuf.put(ps, psmain - ps); + if(variant) loopv(variant->defaultparams) + { + defformatstring(uni, "\nuniform vec4 %s;\n", variant->defaultparams[i].name); + vsbuf.put(uni, strlen(uni)); + psbuf.put(uni, strlen(uni)); + } + else loopv(slotparams) + { + defformatstring(uni, "\nuniform vec4 %s;\n", slotparams[i].name); + vsbuf.put(uni, strlen(uni)); + psbuf.put(uni, strlen(uni)); + } + vsbuf.put(vsmain, strlen(vsmain)+1); + psbuf.put(psmain, strlen(psmain)+1); } VAR(defershaders, 0, 1, 1); void defershader(int *type, const char *name, const char *contents) { - Shader *exists = shaders.access(name); - if(exists && !exists->invalid()) return; - if(!defershaders) { execute(contents); return; } - char *rname = exists ? exists->name : newstring(name); - Shader &s = shaders[rname]; - s.name = rname; - DELETEA(s.defer); - s.defer = newstring(contents); - s.type = SHADER_DEFERRED | *type; - s.standard = standardshaders; + Shader *exists = shaders.access(name); + if(exists && !exists->invalid()) return; + if(!defershaders) { execute(contents); return; } + char *rname = exists ? exists->name : newstring(name); + Shader &s = shaders[rname]; + s.name = rname; + DELETEA(s.defer); + s.defer = newstring(contents); + s.type = SHADER_DEFERRED | *type; + s.standard = standardshaders; } void Shader::force() { - if(!deferred() || !defer) return; - - char *cmd = defer; - defer = NULL; - bool wasstandard = standardshaders, wasforcing = forceshaders; - int oldflags = identflags; - standardshaders = standard; - forceshaders = false; - identflags &= ~IDF_PERSIST; - slotparams.shrink(0); - execute(cmd); - identflags = oldflags; - forceshaders = wasforcing; - standardshaders = wasstandard; - delete[] cmd; - - if(deferred()) - { - DELETEA(defer); - type = SHADER_INVALID; - } + if(!deferred() || !defer) return; + + char *cmd = defer; + defer = NULL; + bool wasstandard = standardshaders, wasforcing = forceshaders; + int oldflags = identflags; + standardshaders = standard; + forceshaders = false; + identflags &= ~IDF_PERSIST; + slotparams.shrink(0); + execute(cmd); + identflags = oldflags; + forceshaders = wasforcing; + standardshaders = wasstandard; + delete[] cmd; + + if(deferred()) + { + DELETEA(defer); + type = SHADER_INVALID; + } } void fixshaderdetail() { - // must null out separately because fixdetailshader can recursively set it - enumerate(shaders, Shader, s, { if(!s.forced) s.detailshader = NULL; }); - enumerate(shaders, Shader, s, { if(s.forced) s.fixdetailshader(); }); - linkslotshaders(); + // must null out separately because fixdetailshader can recursively set it + enumerate(shaders, Shader, s, { if(!s.forced) s.detailshader = NULL; }); + enumerate(shaders, Shader, s, { if(s.forced) s.fixdetailshader(); }); + linkslotshaders(); } int Shader::uniformlocversion() { - static int version = 0; - if(++version >= 0) return version; - version = 0; - enumerate(shaders, Shader, s, { loopvj(s.uniformlocs) s.uniformlocs[j].version = -1; }); - return version; + static int version = 0; + if(++version >= 0) return version; + version = 0; + enumerate(shaders, Shader, s, { loopvj(s.uniformlocs) s.uniformlocs[j].version = -1; }); + return version; } VARFP(shaderdetail, 0, MAXSHADERDETAIL, MAXSHADERDETAIL, fixshaderdetail()); void Shader::fixdetailshader(bool shouldforce, bool recurse) { - Shader *alt = this; - detailshader = NULL; - do - { - Shader *cur = shaderdetail < MAXSHADERDETAIL ? alt->fastshader[shaderdetail] : alt; - if(cur->deferred() && shouldforce) cur->force(); - if(!cur->invalid()) - { - if(cur->deferred()) break; - detailshader = cur; - break; - } - alt = alt->altshader; - } while(alt && alt!=this); - - if(recurse && detailshader) loopv(detailshader->variants) detailshader->variants[i]->fixdetailshader(shouldforce, false); + Shader *alt = this; + detailshader = NULL; + do + { + Shader *cur = shaderdetail < MAXSHADERDETAIL ? alt->fastshader[shaderdetail] : alt; + if(cur->deferred() && shouldforce) cur->force(); + if(!cur->invalid()) + { + if(cur->deferred()) break; + detailshader = cur; + break; + } + alt = alt->altshader; + } while(alt && alt!=this); + + if(recurse && detailshader) loopv(detailshader->variants) detailshader->variants[i]->fixdetailshader(shouldforce, false); } Shader *useshaderbyname(const char *name) { - Shader *s = shaders.access(name); - if(!s) return NULL; - if(!s->detailshader) s->fixdetailshader(); - s->forced = true; - return s; + Shader *s = shaders.access(name); + if(!s) return NULL; + if(!s->detailshader) s->fixdetailshader(); + s->forced = true; + return s; } void shader(int *type, char *name, char *vs, char *ps) { - if(lookupshaderbyname(name)) return; - - defformatstring(info, "shader %s", name); - renderprogress(loadprogress, info); + if(lookupshaderbyname(name)) return; + + defformatstring(info, "shader %s", name); + renderprogress(loadprogress, info); - vector<char> vsbuf, psbuf, vsbak, psbak; + vector<char> vsbuf, psbuf, vsbak, psbak; #define GENSHADER(cond, body) \ - if(cond) \ - { \ - if(vsbuf.length()) { vsbak.setsize(0); vsbak.put(vs, strlen(vs)+1); vs = vsbak.getbuf(); vsbuf.setsize(0); } \ - if(psbuf.length()) { psbak.setsize(0); psbak.put(ps, strlen(ps)+1); ps = psbak.getbuf(); psbuf.setsize(0); } \ - body; \ - if(vsbuf.length()) vs = vsbuf.getbuf(); \ - if(psbuf.length()) ps = psbuf.getbuf(); \ - } - GENSHADER(slotparams.length(), genuniformdefs(vsbuf, psbuf, vs, ps)); - GENSHADER(strstr(vs, "//:fog") || strstr(ps, "//:fog"), genfogshader(vsbuf, psbuf, vs, ps)); - Shader *s = newshader(*type, name, vs, ps); - if(s) - { - if(strstr(vs, "//:water")) genwatervariant(*s, s->name, vs, ps); - if(strstr(vs, "//:shadowmap")) genshadowmapvariant(*s, s->name, vs, ps); - if(strstr(vs, "//:dynlight")) gendynlightvariant(*s, s->name, vs, ps); - } - slotparams.shrink(0); + if(cond) \ + { \ + if(vsbuf.length()) { vsbak.setsize(0); vsbak.put(vs, strlen(vs)+1); vs = vsbak.getbuf(); vsbuf.setsize(0); } \ + if(psbuf.length()) { psbak.setsize(0); psbak.put(ps, strlen(ps)+1); ps = psbak.getbuf(); psbuf.setsize(0); } \ + body; \ + if(vsbuf.length()) vs = vsbuf.getbuf(); \ + if(psbuf.length()) ps = psbuf.getbuf(); \ + } + GENSHADER(slotparams.length(), genuniformdefs(vsbuf, psbuf, vs, ps)); + GENSHADER(strstr(vs, "//:fog") || strstr(ps, "//:fog"), genfogshader(vsbuf, psbuf, vs, ps)); + Shader *s = newshader(*type, name, vs, ps); + if(s) + { + if(strstr(vs, "//:water")) genwatervariant(*s, s->name, vs, ps); + if(strstr(vs, "//:shadowmap")) genshadowmapvariant(*s, s->name, vs, ps); + if(strstr(vs, "//:dynlight")) gendynlightvariant(*s, s->name, vs, ps); + } + slotparams.shrink(0); } void variantshader(int *type, char *name, int *row, char *vs, char *ps) { - if(*row < 0) - { - shader(type, name, vs, ps); - return; - } - else if(*row >= MAXVARIANTROWS) return; - - Shader *s = lookupshaderbyname(name); - if(!s) return; - - defformatstring(varname, "<variant:%d,%d>%s", s->numvariants(*row), *row, name); - //defformatstring(info, "shader %s", varname); - //renderprogress(loadprogress, info); - vector<char> vsbuf, psbuf, vsbak, psbak; - GENSHADER(s->defaultparams.length(), genuniformdefs(vsbuf, psbuf, vs, ps, s)); - GENSHADER(strstr(vs, "//:fog") || strstr(ps, "//:fog"), genfogshader(vsbuf, psbuf, vs, ps)); - Shader *v = newshader(*type, varname, vs, ps, s, *row); - if(v) - { - if(strstr(vs, "//:dynlight")) gendynlightvariant(*s, varname, vs, ps, *row); - if(strstr(ps, "//:variant") || strstr(vs, "//:variant")) gengenericvariant(*s, varname, vs, ps, *row); - } + if(*row < 0) + { + shader(type, name, vs, ps); + return; + } + else if(*row >= MAXVARIANTROWS) return; + + Shader *s = lookupshaderbyname(name); + if(!s) return; + + defformatstring(varname, "<variant:%d,%d>%s", s->numvariants(*row), *row, name); + //defformatstring(info, "shader %s", varname); + //renderprogress(loadprogress, info); + vector<char> vsbuf, psbuf, vsbak, psbak; + GENSHADER(s->defaultparams.length(), genuniformdefs(vsbuf, psbuf, vs, ps, s)); + GENSHADER(strstr(vs, "//:fog") || strstr(ps, "//:fog"), genfogshader(vsbuf, psbuf, vs, ps)); + Shader *v = newshader(*type, varname, vs, ps, s, *row); + if(v) + { + if(strstr(vs, "//:dynlight")) gendynlightvariant(*s, varname, vs, ps, *row); + if(strstr(ps, "//:variant") || strstr(vs, "//:variant")) gengenericvariant(*s, varname, vs, ps, *row); + } } void setshader(char *name) { - slotparams.shrink(0); - Shader *s = shaders.access(name); - if(!s) - { - conoutf(CON_ERROR, "no such shader: %s", name); - } - else slotshader = s; + slotparams.shrink(0); + Shader *s = shaders.access(name); + if(!s) + { + conoutf(CON_ERROR, "no such shader: %s", name); + } + else slotshader = s; } void resetslotshader() { - slotshader = NULL; - slotparams.shrink(0); + slotshader = NULL; + slotparams.shrink(0); } void setslotshader(Slot &s) { - s.shader = slotshader; - if(!s.shader) - { - s.shader = stdworldshader; - return; - } - loopv(slotparams) s.params.add(slotparams[i]); + s.shader = slotshader; + if(!s.shader) + { + s.shader = stdworldshader; + return; + } + loopv(slotparams) s.params.add(slotparams[i]); } static void linkslotshaderparams(vector<SlotShaderParam> ¶ms, Shader *sh, bool load) { - if(sh) loopv(params) - { - int loc = -1; - SlotShaderParam ¶m = params[i]; - loopv(sh->defaultparams) - { - SlotShaderParamState &dparam = sh->defaultparams[i]; - if(dparam.name==param.name) - { - if(memcmp(param.val, dparam.val, sizeof(param.val))) loc = i; - break; - } - } - param.loc = loc; - } - else if(load) loopv(params) params[i].loc = -1; + if(sh) loopv(params) + { + int loc = -1; + SlotShaderParam ¶m = params[i]; + loopv(sh->defaultparams) + { + SlotShaderParamState &dparam = sh->defaultparams[i]; + if(dparam.name==param.name) + { + if(memcmp(param.val, dparam.val, sizeof(param.val))) loc = i; + break; + } + } + param.loc = loc; + } + else if(load) loopv(params) params[i].loc = -1; } void linkslotshader(Slot &s, bool load) { - if(!s.shader) return; + if(!s.shader) return; - if(load && !s.shader->detailshader) s.shader->fixdetailshader(); + if(load && !s.shader->detailshader) s.shader->fixdetailshader(); - linkslotshaderparams(s.params, s.shader->detailshader, load); + linkslotshaderparams(s.params, s.shader->detailshader, load); } void linkvslotshader(VSlot &s, bool load) { - if(!s.slot->shader) return; + if(!s.slot->shader) return; - Shader *sh = s.slot->shader->detailshader; - linkslotshaderparams(s.params, sh, load); + Shader *sh = s.slot->shader->detailshader; + linkslotshaderparams(s.params, sh, load); - if(!sh) return; + if(!sh) return; - if(s.slot->texmask&(1<<TEX_GLOW)) - { - static const char *paramname = getshaderparamname("glowcolor"); - const float *param = findslotparam(s, paramname); - if(param) s.glowcolor = vec(param).clamp(0, 1); - } + if(s.slot->texmask&(1<<TEX_GLOW)) + { + static const char *paramname = getshaderparamname("glowcolor"); + const float *param = findslotparam(s, paramname); + if(param) s.glowcolor = vec(param).clamp(0, 1); + } } void altshader(char *origname, char *altname) { - Shader *orig = shaders.access(origname), *alt = shaders.access(altname); - if(!orig || !alt) return; - orig->altshader = alt; - orig->fixdetailshader(false); + Shader *orig = shaders.access(origname), *alt = shaders.access(altname); + if(!orig || !alt) return; + orig->altshader = alt; + orig->fixdetailshader(false); } void fastshader(char *nice, char *fast, int *detail) { - Shader *ns = shaders.access(nice), *fs = shaders.access(fast); - if(!ns || !fs) return; - loopi(min(*detail+1, MAXSHADERDETAIL)) ns->fastshader[i] = fs; - ns->fixdetailshader(false); + Shader *ns = shaders.access(nice), *fs = shaders.access(fast); + if(!ns || !fs) return; + loopi(min(*detail+1, MAXSHADERDETAIL)) ns->fastshader[i] = fs; + ns->fixdetailshader(false); } COMMAND(shader, "isss"); @@ -1233,28 +1228,28 @@ static hashset<const char *> shaderparamnames(256); const char *getshaderparamname(const char *name, bool insert) { - const char *exists = shaderparamnames.find(name, NULL); - if(exists || !insert) return exists; - return shaderparamnames.add(newstring(name)); + const char *exists = shaderparamnames.find(name, NULL); + if(exists || !insert) return exists; + return shaderparamnames.add(newstring(name)); } void addslotparam(const char *name, float x, float y, float z, float w) { - if(name) name = getshaderparamname(name); - loopv(slotparams) - { - SlotShaderParam ¶m = slotparams[i]; - if(param.name==name) - { - param.val[0] = x; - param.val[1] = y; - param.val[2] = z; - param.val[3] = w; - return; - } - } - SlotShaderParam param = {name, -1, {x, y, z, w}}; - slotparams.add(param); + if(name) name = getshaderparamname(name); + loopv(slotparams) + { + SlotShaderParam ¶m = slotparams[i]; + if(param.name==name) + { + param.val[0] = x; + param.val[1] = y; + param.val[2] = z; + param.val[3] = w; + return; + } + } + SlotShaderParam param = {name, -1, {x, y, z, w}}; + slotparams.add(param); } ICOMMAND(setuniformparam, "sffff", (char *name, float *x, float *y, float *z, float *w), addslotparam(name, *x, *y, *z, *w)); @@ -1265,10 +1260,10 @@ ICOMMAND(defuniformparam, "sffff", (char *name, float *x, float *y, float *z, fl struct postfxtex { - GLuint id; - int scale, used; + GLuint id; + int scale, used; - postfxtex() : id(0), scale(0), used(-1) {} + postfxtex() : id(0), scale(0), used(-1) {} }; vector<postfxtex> postfxtexs; int postfxbinds[NUMPOSTFXBINDS]; @@ -1277,246 +1272,246 @@ int postfxw = 0, postfxh = 0; struct postfxpass { - Shader *shader; - vec4 params; - uint inputs, freeinputs; - int outputbind, outputscale; + Shader *shader; + vec4 params; + uint inputs, freeinputs; + int outputbind, outputscale; - postfxpass() : shader(NULL), inputs(1), freeinputs(1), outputbind(0), outputscale(0) {} + postfxpass() : shader(NULL), inputs(1), freeinputs(1), outputbind(0), outputscale(0) {} }; vector<postfxpass> postfxpasses; static int allocatepostfxtex(int scale) { - loopv(postfxtexs) - { - postfxtex &t = postfxtexs[i]; - if(t.scale==scale && t.used < 0) return i; - } - postfxtex &t = postfxtexs.add(); - t.scale = scale; - glGenTextures(1, &t.id); - createtexture(t.id, max(screenw>>scale, 1), max(screenh>>scale, 1), NULL, 3, 1, GL_RGB); - return postfxtexs.length()-1; + loopv(postfxtexs) + { + postfxtex &t = postfxtexs[i]; + if(t.scale==scale && t.used < 0) return i; + } + postfxtex &t = postfxtexs.add(); + t.scale = scale; + glGenTextures(1, &t.id); + createtexture(t.id, max(screenw>>scale, 1), max(screenh>>scale, 1), NULL, 3, 1, GL_RGB); + return postfxtexs.length()-1; } void cleanuppostfx(bool fullclean) { - if(fullclean && postfxfb) - { - glDeleteFramebuffers_(1, &postfxfb); - postfxfb = 0; - } + if(fullclean && postfxfb) + { + glDeleteFramebuffers_(1, &postfxfb); + postfxfb = 0; + } - loopv(postfxtexs) glDeleteTextures(1, &postfxtexs[i].id); - postfxtexs.shrink(0); + loopv(postfxtexs) glDeleteTextures(1, &postfxtexs[i].id); + postfxtexs.shrink(0); - postfxw = 0; - postfxh = 0; + postfxw = 0; + postfxh = 0; } void renderpostfx() { - if(postfxpasses.empty()) return; - - if(postfxw != screenw || postfxh != screenh) - { - cleanuppostfx(false); - postfxw = screenw; - postfxh = screenh; - } - - int binds[NUMPOSTFXBINDS]; - loopi(NUMPOSTFXBINDS) binds[i] = -1; - loopv(postfxtexs) postfxtexs[i].used = -1; - - binds[0] = allocatepostfxtex(0); - postfxtexs[binds[0]].used = 0; - glBindTexture(GL_TEXTURE_2D, postfxtexs[binds[0]].id); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, screenw, screenh); - - if(postfxpasses.length() > 1) - { - if(!postfxfb) glGenFramebuffers_(1, &postfxfb); - glBindFramebuffer_(GL_FRAMEBUFFER, postfxfb); - } - - GLOBALPARAMF(millis, lastmillis/1000.0f); - - loopv(postfxpasses) - { - postfxpass &p = postfxpasses[i]; - - int tex = -1; - if(!postfxpasses.inrange(i+1)) - { - if(postfxpasses.length() > 1) glBindFramebuffer_(GL_FRAMEBUFFER, 0); - } - else - { - tex = allocatepostfxtex(p.outputscale); - glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, postfxtexs[tex].id, 0); - } - - int w = tex >= 0 ? max(screenw>>postfxtexs[tex].scale, 1) : screenw, - h = tex >= 0 ? max(screenh>>postfxtexs[tex].scale, 1) : screenh; - glViewport(0, 0, w, h); - p.shader->set(); - LOCALPARAM(params, p.params); - int tw = w, th = h, tmu = 0; - loopj(NUMPOSTFXBINDS) if(p.inputs&(1<<j) && binds[j] >= 0) - { - if(!tmu) - { - tw = max(screenw>>postfxtexs[binds[j]].scale, 1); - th = max(screenh>>postfxtexs[binds[j]].scale, 1); - } - else glActiveTexture_(GL_TEXTURE0 + tmu); - glBindTexture(GL_TEXTURE_2D, postfxtexs[binds[j]].id); - ++tmu; - } - if(tmu) glActiveTexture_(GL_TEXTURE0); - LOCALPARAMF(postfxscale, 1.0f/tw, 1.0f/th); - screenquad(1, 1); - - loopj(NUMPOSTFXBINDS) if(p.freeinputs&(1<<j) && binds[j] >= 0) - { - postfxtexs[binds[j]].used = -1; - binds[j] = -1; - } - if(tex >= 0) - { - if(binds[p.outputbind] >= 0) postfxtexs[binds[p.outputbind]].used = -1; - binds[p.outputbind] = tex; - postfxtexs[tex].used = p.outputbind; - } - } + if(postfxpasses.empty()) return; + + if(postfxw != screenw || postfxh != screenh) + { + cleanuppostfx(false); + postfxw = screenw; + postfxh = screenh; + } + + int binds[NUMPOSTFXBINDS]; + loopi(NUMPOSTFXBINDS) binds[i] = -1; + loopv(postfxtexs) postfxtexs[i].used = -1; + + binds[0] = allocatepostfxtex(0); + postfxtexs[binds[0]].used = 0; + glBindTexture(GL_TEXTURE_2D, postfxtexs[binds[0]].id); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, screenw, screenh); + + if(postfxpasses.length() > 1) + { + if(!postfxfb) glGenFramebuffers_(1, &postfxfb); + glBindFramebuffer_(GL_FRAMEBUFFER, postfxfb); + } + + GLOBALPARAMF(millis, lastmillis/1000.0f); + + loopv(postfxpasses) + { + postfxpass &p = postfxpasses[i]; + + int tex = -1; + if(!postfxpasses.inrange(i+1)) + { + if(postfxpasses.length() > 1) glBindFramebuffer_(GL_FRAMEBUFFER, 0); + } + else + { + tex = allocatepostfxtex(p.outputscale); + glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, postfxtexs[tex].id, 0); + } + + int w = tex >= 0 ? max(screenw>>postfxtexs[tex].scale, 1) : screenw, + h = tex >= 0 ? max(screenh>>postfxtexs[tex].scale, 1) : screenh; + glViewport(0, 0, w, h); + p.shader->set(); + LOCALPARAM(params, p.params); + int tw = w, th = h, tmu = 0; + loopj(NUMPOSTFXBINDS) if(p.inputs&(1<<j) && binds[j] >= 0) + { + if(!tmu) + { + tw = max(screenw>>postfxtexs[binds[j]].scale, 1); + th = max(screenh>>postfxtexs[binds[j]].scale, 1); + } + else glActiveTexture_(GL_TEXTURE0 + tmu); + glBindTexture(GL_TEXTURE_2D, postfxtexs[binds[j]].id); + ++tmu; + } + if(tmu) glActiveTexture_(GL_TEXTURE0); + LOCALPARAMF(postfxscale, 1.0f/tw, 1.0f/th); + screenquad(1, 1); + + loopj(NUMPOSTFXBINDS) if(p.freeinputs&(1<<j) && binds[j] >= 0) + { + postfxtexs[binds[j]].used = -1; + binds[j] = -1; + } + if(tex >= 0) + { + if(binds[p.outputbind] >= 0) postfxtexs[binds[p.outputbind]].used = -1; + binds[p.outputbind] = tex; + postfxtexs[tex].used = p.outputbind; + } + } } static bool addpostfx(const char *name, int outputbind, int outputscale, uint inputs, uint freeinputs, const vec4 ¶ms) { - if(!*name) return false; - Shader *s = useshaderbyname(name); - if(!s) - { - conoutf(CON_ERROR, "no such postfx shader: %s", name); - return false; - } - postfxpass &p = postfxpasses.add(); - p.shader = s; - p.outputbind = outputbind; - p.outputscale = outputscale; - p.inputs = inputs; - p.freeinputs = freeinputs; - p.params = params; - return true; + if(!*name) return false; + Shader *s = useshaderbyname(name); + if(!s) + { + conoutf(CON_ERROR, "no such postfx shader: %s", name); + return false; + } + postfxpass &p = postfxpasses.add(); + p.shader = s; + p.outputbind = outputbind; + p.outputscale = outputscale; + p.inputs = inputs; + p.freeinputs = freeinputs; + p.params = params; + return true; } void clearpostfx() { - postfxpasses.shrink(0); - cleanuppostfx(false); + postfxpasses.shrink(0); + cleanuppostfx(false); } COMMAND(clearpostfx, ""); ICOMMAND(addpostfx, "siisffff", (char *name, int *bind, int *scale, char *inputs, float *x, float *y, float *z, float *w), { - int inputmask = inputs[0] ? 0 : 1; - int freemask = inputs[0] ? 0 : 1; - bool freeinputs = true; - for(; *inputs; inputs++) if(isdigit(*inputs)) - { - inputmask |= 1<<(*inputs-'0'); - if(freeinputs) freemask |= 1<<(*inputs-'0'); - } - else if(*inputs=='+') freeinputs = false; - else if(*inputs=='-') freeinputs = true; - inputmask &= (1<<NUMPOSTFXBINDS)-1; - freemask &= (1<<NUMPOSTFXBINDS)-1; - addpostfx(name, clamp(*bind, 0, NUMPOSTFXBINDS-1), max(*scale, 0), inputmask, freemask, vec4(*x, *y, *z, *w)); + int inputmask = inputs[0] ? 0 : 1; + int freemask = inputs[0] ? 0 : 1; + bool freeinputs = true; + for(; *inputs; inputs++) if(isdigit(*inputs)) + { + inputmask |= 1<<(*inputs-'0'); + if(freeinputs) freemask |= 1<<(*inputs-'0'); + } + else if(*inputs=='+') freeinputs = false; + else if(*inputs=='-') freeinputs = true; + inputmask &= (1<<NUMPOSTFXBINDS)-1; + freemask &= (1<<NUMPOSTFXBINDS)-1; + addpostfx(name, clamp(*bind, 0, NUMPOSTFXBINDS-1), max(*scale, 0), inputmask, freemask, vec4(*x, *y, *z, *w)); }); ICOMMAND(setpostfx, "sffff", (char *name, float *x, float *y, float *z, float *w), { - clearpostfx(); - if(name[0]) addpostfx(name, 0, 0, 1, 1, vec4(*x, *y, *z, *w)); + clearpostfx(); + if(name[0]) addpostfx(name, 0, 0, 1, 1, vec4(*x, *y, *z, *w)); }); void cleanupshaders() { - cleanuppostfx(true); + cleanuppostfx(true); - loadedshaders = false; - nullshader = hudshader = hudnotextureshader = textureshader = notextureshader = nocolorshader = foggedshader = foggednotextureshader = stdworldshader = NULL; - enumerate(shaders, Shader, s, s.cleanup()); - Shader::lastshader = NULL; - glUseProgram_(0); + loadedshaders = false; + nullshader = hudshader = hudnotextureshader = textureshader = notextureshader = nocolorshader = foggedshader = foggednotextureshader = stdworldshader = NULL; + enumerate(shaders, Shader, s, s.cleanup()); + Shader::lastshader = NULL; + glUseProgram_(0); } void reloadshaders() { - identflags &= ~IDF_PERSIST; - loadshaders(); - identflags |= IDF_PERSIST; - linkslotshaders(); - enumerate(shaders, Shader, s, - { - if(!s.standard && !(s.type&(SHADER_DEFERRED|SHADER_INVALID)) && !s.variantshader) - { - defformatstring(info, "shader %s", s.name); - renderprogress(0.0, info); - if(!s.compile()) s.cleanup(true); - loopv(s.variants) - { - Shader *v = s.variants[i]; - if((v->reusevs && v->reusevs->invalid()) || - (v->reuseps && v->reuseps->invalid()) || - !v->compile()) - v->cleanup(true); - } - } - if(s.forced && !s.detailshader) s.fixdetailshader(); - }); + identflags &= ~IDF_PERSIST; + loadshaders(); + identflags |= IDF_PERSIST; + linkslotshaders(); + enumerate(shaders, Shader, s, + { + if(!s.standard && !(s.type&(SHADER_DEFERRED|SHADER_INVALID)) && !s.variantshader) + { + defformatstring(info, "shader %s", s.name); + renderprogress(0.0, info); + if(!s.compile()) s.cleanup(true); + loopv(s.variants) + { + Shader *v = s.variants[i]; + if((v->reusevs && v->reusevs->invalid()) || + (v->reuseps && v->reuseps->invalid()) || + !v->compile()) + v->cleanup(true); + } + } + if(s.forced && !s.detailshader) s.fixdetailshader(); + }); } void setupblurkernel(int radius, float sigma, float *weights, float *offsets) { - if(radius<1 || radius>MAXBLURRADIUS) return; - sigma *= 2*radius; - float total = 1.0f/sigma; - weights[0] = total; - offsets[0] = 0; - // rely on bilinear filtering to sample 2 pixels at once - // transforms a*X + b*Y into (u+v)*[X*u/(u+v) + Y*(1 - u/(u+v))] - loopi(radius) - { - float weight1 = exp(-((2*i)*(2*i)) / (2*sigma*sigma)) / sigma, - weight2 = exp(-((2*i+1)*(2*i+1)) / (2*sigma*sigma)) / sigma, - scale = weight1 + weight2, - offset = 2*i+1 + weight2 / scale; - weights[i+1] = scale; - offsets[i+1] = offset; - total += 2*scale; - } - loopi(radius+1) weights[i] /= total; - for(int i = radius+1; i <= MAXBLURRADIUS; i++) weights[i] = offsets[i] = 0; + if(radius<1 || radius>MAXBLURRADIUS) return; + sigma *= 2*radius; + float total = 1.0f/sigma; + weights[0] = total; + offsets[0] = 0; + // rely on bilinear filtering to sample 2 pixels at once + // transforms a*X + b*Y into (u+v)*[X*u/(u+v) + Y*(1 - u/(u+v))] + loopi(radius) + { + float weight1 = exp(-((2*i)*(2*i)) / (2*sigma*sigma)) / sigma, + weight2 = exp(-((2*i+1)*(2*i+1)) / (2*sigma*sigma)) / sigma, + scale = weight1 + weight2, + offset = 2*i+1 + weight2 / scale; + weights[i+1] = scale; + offsets[i+1] = offset; + total += 2*scale; + } + loopi(radius+1) weights[i] /= total; + for(int i = radius+1; i <= MAXBLURRADIUS; i++) weights[i] = offsets[i] = 0; } void setblurshader(int pass, int size, int radius, float *weights, float *offsets) { - if(radius<1 || radius>MAXBLURRADIUS) return; - static Shader *blurshader[7][2] = { { NULL, NULL }, { NULL, NULL }, { NULL, NULL }, { NULL, NULL }, { NULL, NULL }, { NULL, NULL }, { NULL, NULL } }; - Shader *&s = blurshader[radius-1][pass]; - if(!s) - { - defformatstring(name, "blur%c%d", 'x'+pass, radius); - s = lookupshaderbyname(name); - } - s->set(); - LOCALPARAMV(weights, weights, 8); - float scaledoffsets[8]; - loopk(8) scaledoffsets[k] = offsets[k]/size; - LOCALPARAMV(offsets, scaledoffsets, 8); + if(radius<1 || radius>MAXBLURRADIUS) return; + static Shader *blurshader[7][2] = { { NULL, NULL }, { NULL, NULL }, { NULL, NULL }, { NULL, NULL }, { NULL, NULL }, { NULL, NULL }, { NULL, NULL } }; + Shader *&s = blurshader[radius-1][pass]; + if(!s) + { + defformatstring(name, "blur%c%d", 'x'+pass, radius); + s = lookupshaderbyname(name); + } + s->set(); + LOCALPARAMV(weights, weights, 8); + float scaledoffsets[8]; + loopk(8) scaledoffsets[k] = offsets[k]/size; + LOCALPARAMV(offsets, scaledoffsets, 8); } |
