Line data Source code
1 : // shader.cpp: OpenGL GLSL shader management
2 :
3 : #include "../libprimis-headers/cube.h"
4 : #include "../../shared/geomexts.h"
5 : #include "../../shared/glemu.h"
6 : #include "../../shared/glexts.h"
7 : #include "../../shared/stream.h"
8 :
9 : #include "octarender.h"
10 : #include "postfx.h"
11 : #include "rendergl.h"
12 : #include "renderlights.h"
13 : #include "rendermodel.h"
14 : #include "rendertimers.h"
15 : #include "renderwindow.h"
16 : #include "shaderparam.h"
17 : #include "shader.h"
18 : #include "texture.h"
19 :
20 : #include "interface/console.h"
21 : #include "interface/control.h"
22 : #include "interface/menus.h"
23 :
24 : Shader *Shader::lastshader = nullptr;
25 :
26 : Shader *nullshader = nullptr,
27 : *hudshader = nullptr,
28 : *hudtextshader = nullptr,
29 : *hudnotextureshader = nullptr,
30 : *nocolorshader = nullptr,
31 : *foggedshader = nullptr,
32 : *foggednotextureshader = nullptr,
33 : *ldrshader = nullptr,
34 : *ldrnotextureshader = nullptr,
35 : *stdworldshader = nullptr;
36 :
37 : static std::unordered_map<std::string, int> localparams;
38 : static std::unordered_map<std::string, Shader> shaders;
39 : static Shader *slotshader = nullptr;
40 : static std::vector<SlotShaderParam> slotparams;
41 : static bool standardshaders = false,
42 : forceshaders = true,
43 : loadedshaders = false;
44 : constexpr int maxvariantrows = 32;
45 :
46 : VAR(maxvsuniforms, 1, 0, 0);
47 : VAR(maxfsuniforms, 1, 0, 0);
48 : VAR(mintexoffset, 1, 0, 0);
49 : VAR(maxtexoffset, 1, 0, 0);
50 : VAR(debugshader, 0, 1, 2);
51 :
52 0 : void loadshaders()
53 : {
54 0 : standardshaders = true;
55 0 : execfile("config/glsl.cfg");
56 0 : standardshaders = false;
57 :
58 0 : nullshader = lookupshaderbyname("null");
59 0 : hudshader = lookupshaderbyname("hud");
60 0 : hudtextshader = lookupshaderbyname("hudtext");
61 0 : hudnotextureshader = lookupshaderbyname("hudnotexture");
62 0 : stdworldshader = lookupshaderbyname("stdworld");
63 0 : if(!nullshader || !hudshader || !hudtextshader || !hudnotextureshader || !stdworldshader)
64 : {
65 0 : fatal("cannot find shader definitions");
66 : }
67 0 : dummyslot.shader = stdworldshader;
68 0 : dummydecalslot.shader = nullshader;
69 :
70 0 : nocolorshader = lookupshaderbyname("nocolor");
71 0 : foggedshader = lookupshaderbyname("fogged");
72 0 : foggednotextureshader = lookupshaderbyname("foggednotexture");
73 0 : ldrshader = lookupshaderbyname("ldr");
74 0 : ldrnotextureshader = lookupshaderbyname("ldrnotexture");
75 :
76 0 : nullshader->set();
77 :
78 0 : loadedshaders = true;
79 0 : }
80 :
81 5 : Shader *lookupshaderbyname(const char *name)
82 : {
83 5 : auto itr = shaders.find(name);
84 5 : if(itr != shaders.end())
85 : {
86 5 : return (*itr).second.loaded() ? &(*itr).second : nullptr;
87 : }
88 0 : return nullptr;
89 : }
90 :
91 0 : Shader *generateshader(const char *name, const char *fmt, ...)
92 : {
93 0 : if(!loadedshaders)
94 : {
95 0 : return nullptr;
96 : }
97 0 : Shader *s = name ? lookupshaderbyname(name) : nullptr;
98 0 : if(!s)
99 : {
100 0 : DEFV_FORMAT_STRING(cmd, fmt, fmt);
101 0 : bool wasstandard = standardshaders;
102 0 : standardshaders = true;
103 0 : execute(cmd);
104 0 : standardshaders = wasstandard;
105 0 : s = name ? lookupshaderbyname(name) : nullptr;
106 0 : if(!s)
107 : {
108 0 : s = nullshader;
109 : }
110 : }
111 0 : return s;
112 : }
113 :
114 0 : static void showglslinfo(GLenum type, GLuint obj, const char *name, const char **parts = nullptr, int numparts = 0)
115 : {
116 0 : GLint length = 0;
117 0 : if(type)
118 : {
119 0 : glGetShaderiv(obj, GL_INFO_LOG_LENGTH, &length);
120 : }
121 : else
122 : {
123 0 : glGetProgramiv(obj, GL_INFO_LOG_LENGTH, &length);
124 : }
125 0 : if(length > 1)
126 : {
127 0 : conoutf(Console_Error, "GLSL ERROR (%s:%s)", type == GL_VERTEX_SHADER ? "Vertex shader" : (type == GL_FRAGMENT_SHADER ? "Fragment shader" : "Program"), name);
128 0 : FILE *l = getlogfile();
129 0 : if(l)
130 : {
131 0 : GLchar *log = new GLchar[length];
132 0 : if(type)
133 : {
134 0 : glGetShaderInfoLog(obj, length, &length, log);
135 : }
136 : else
137 : {
138 0 : glGetProgramInfoLog(obj, length, &length, log);
139 : }
140 0 : std::fprintf(l, "%s\n", log);
141 0 : bool partlines = log[0] != '0';
142 0 : int line = 0;
143 0 : for(int i = 0; i < numparts; ++i)
144 : {
145 0 : const char *part = parts[i];
146 0 : int startline = line;
147 0 : while(*part)
148 : {
149 0 : const char *next = std::strchr(part, '\n');
150 0 : if(++line > 1000)
151 : {
152 0 : goto done;
153 : }
154 0 : if(partlines)
155 : {
156 0 : std::fprintf(l, "%d(%d): ", i, line - startline);
157 : }
158 : else
159 : {
160 0 : std::fprintf(l, "%d: ", line);
161 : }
162 0 : std::fwrite(part, 1, next ? next - part + 1 : std::strlen(part), l);
163 0 : if(!next)
164 : {
165 0 : std::fputc('\n', l);
166 0 : break;
167 : }
168 0 : part = next + 1;
169 : }
170 : }
171 0 : done:
172 0 : delete[] log;
173 : }
174 : }
175 0 : }
176 :
177 4 : static void compileglslshader(const Shader &s, GLenum type, GLuint &obj, const char *def, const char *name, bool msg = true)
178 : {
179 4 : if(!glslversion)
180 : {
181 4 : conoutf(Console_Error, "Cannot compile GLSL shader without GLSL initialized");
182 4 : return;
183 : }
184 0 : const char *source = def + std::strspn(def, " \t\r\n");
185 0 : char *modsource = nullptr;
186 : const char *parts[16];
187 0 : int numparts = 0;
188 : static const struct { int version; const char * const header; } glslversions[] =
189 : {
190 : { 400, "#version 400\n" }, //OpenGL 4.0
191 : { 330, "#version 330\n" }, //OpenGL 3.3 (not supported)
192 : { 150, "#version 150\n" }, //OpenGL 3.2 (not supported)
193 : { 140, "#version 140\n" }, //OpenGL 3.1 (not supported)
194 : { 130, "#version 130\n" }, //OpenGL 3.0 (not supported)
195 : { 120, "#version 120\n" } //OpenGL 2.1 (not supported)
196 : };
197 0 : for(int i = 0; i < static_cast<int>(sizeof(glslversions)/sizeof(glslversions[0])); ++i)
198 : {
199 0 : if(glslversion >= glslversions[i].version)
200 : {
201 0 : parts[numparts++] = glslversions[i].header;
202 0 : break;
203 : }
204 : }
205 :
206 0 : parts[numparts++] = "#extension GL_ARB_explicit_attrib_location : enable\n";
207 : //glsl 1.5
208 0 : if(type == GL_VERTEX_SHADER) parts[numparts++] =
209 : "#define attribute in\n"
210 : "#define varying out\n";
211 0 : else if(type == GL_FRAGMENT_SHADER)
212 : {
213 0 : parts[numparts++] = "#define varying in\n";
214 0 : parts[numparts++] =
215 : "#define fragdata(loc) layout(location = loc) out\n"
216 : "#define fragblend(loc) layout(location = loc, index = 1) out\n";
217 : }
218 0 : parts[numparts++] =
219 : "#define texture1D(sampler, coords) texture(sampler, coords)\n"
220 : "#define texture2D(sampler, coords) texture(sampler, coords)\n"
221 : "#define texture2DOffset(sampler, coords, offset) textureOffset(sampler, coords, offset)\n"
222 : "#define texture2DProj(sampler, coords) textureProj(sampler, coords)\n"
223 : "#define shadow2D(sampler, coords) texture(sampler, coords)\n"
224 : "#define shadow2DOffset(sampler, coords, offset) textureOffset(sampler, coords, offset)\n"
225 : "#define texture3D(sampler, coords) texture(sampler, coords)\n"
226 : "#define textureCube(sampler, coords) texture(sampler, coords)\n";
227 : //glsl 1.4
228 0 : parts[numparts++] =
229 : "#define texture2DRect(sampler, coords) texture(sampler, coords)\n"
230 : "#define texture2DRectProj(sampler, coords) textureProj(sampler, coords)\n"
231 : "#define shadow2DRect(sampler, coords) texture(sampler, coords)\n";
232 0 : parts[numparts++] =
233 : "#define texture2DRectOffset(sampler, coords, offset) textureOffset(sampler, coords, offset)\n"
234 : "#define shadow2DRectOffset(sampler, coords, offset) textureOffset(sampler, coords, offset)\n";
235 0 : parts[numparts++] = modsource ? modsource : source;
236 : //end glsl 1.4
237 0 : obj = glCreateShader(type);
238 0 : glShaderSource(obj, numparts, (const GLchar **)parts, nullptr);
239 0 : glCompileShader(obj);
240 : GLint success;
241 0 : glGetShaderiv(obj, GL_COMPILE_STATUS, &success);
242 0 : if(!success)
243 : {
244 0 : if(msg)
245 : {
246 0 : showglslinfo(type, obj, name, parts, numparts);
247 : }
248 0 : glDeleteShader(obj);
249 0 : obj = 0;
250 : }
251 0 : else if(debugshader > 1 && msg)
252 : {
253 0 : showglslinfo(type, obj, name, parts, numparts);
254 : }
255 0 : if(modsource)
256 : {
257 0 : delete[] modsource;
258 : }
259 : }
260 :
261 0 : static void bindglsluniform(const Shader &s, UniformLoc &u)
262 : {
263 0 : static VAR(debugubo, 0, 0, 1); //print out to console information about ubos when bindglsluniform is called
264 :
265 0 : u.loc = glGetUniformLocation(s.program, u.name);
266 0 : if(!u.blockname)
267 : {
268 0 : return;
269 : }
270 0 : GLuint bidx = glGetUniformBlockIndex(s.program, u.blockname),
271 0 : uidx = GL_INVALID_INDEX;
272 0 : glGetUniformIndices(s.program, 1, &u.name, &uidx);
273 0 : if(bidx != GL_INVALID_INDEX && uidx != GL_INVALID_INDEX)
274 : {
275 0 : GLint sizeval = 0,
276 0 : offsetval = 0,
277 0 : strideval = 0;
278 0 : glGetActiveUniformBlockiv(s.program, bidx, GL_UNIFORM_BLOCK_DATA_SIZE, &sizeval);
279 0 : if(sizeval <= 0)
280 : {
281 0 : return;
282 : }
283 0 : glGetActiveUniformsiv(s.program, 1, &uidx, GL_UNIFORM_OFFSET, &offsetval);
284 0 : if(u.stride > 0)
285 : {
286 0 : glGetActiveUniformsiv(s.program, 1, &uidx, GL_UNIFORM_ARRAY_STRIDE, &strideval);
287 0 : if(strideval > u.stride)
288 : {
289 0 : return;
290 : }
291 : }
292 0 : u.offset = offsetval;
293 0 : u.size = sizeval;
294 0 : glUniformBlockBinding(s.program, bidx, u.binding);
295 0 : if(debugubo)
296 : {
297 0 : conoutf(Console_Debug, "UBO: %s:%s:%d, offset: %d, size: %d, stride: %d", u.name, u.blockname, u.binding, offsetval, sizeval, strideval);
298 : }
299 : }
300 : }
301 :
302 0 : void Shader::uniformtex(std::string_view name, int tmu) const
303 : {
304 0 : int loc = glGetUniformLocation(program, name.data());
305 0 : if(loc != -1)
306 : {
307 0 : glUniform1i(loc, tmu);
308 : }
309 0 : }
310 :
311 2 : void Shader::linkglslprogram(bool msg)
312 : {
313 2 : program = vsobj && psobj ? glCreateProgram() : 0;
314 2 : GLint success = 0;
315 2 : if(program)
316 : {
317 0 : glAttachShader(program, vsobj);
318 0 : glAttachShader(program, psobj);
319 0 : uint attribs = 0;
320 0 : for(const Shader::AttribLoc &a : attriblocs)
321 : {
322 0 : glBindAttribLocation(program, a.loc, a.name);
323 0 : attribs |= 1<<a.loc;
324 : }
325 0 : for(int i = 0; i < gle::Attribute_NumAttributes; ++i)
326 : {
327 0 : if(!(attribs&(1<<i)))
328 : {
329 0 : glBindAttribLocation(program, i, gle::attribnames[i]);
330 : }
331 : }
332 0 : glLinkProgram(program);
333 0 : glGetProgramiv(program, GL_LINK_STATUS, &success);
334 : }
335 2 : if(success)
336 : {
337 0 : glUseProgram(program);
338 0 : static std::array<std::string, 16> texnames = { "tex0", "tex1", "tex2", "tex3", "tex4", "tex5", "tex6", "tex7", "tex8", "tex9", "tex10", "tex11", "tex12", "tex13", "tex14", "tex15" };
339 0 : for(int i = 0; i < 16; ++i)
340 : {
341 0 : GLint loc = glGetUniformLocation(program, texnames[i].c_str());
342 0 : if(loc != -1)
343 : {
344 0 : glUniform1i(loc, i);
345 : }
346 : }
347 0 : if(type & Shader_World)
348 : {
349 0 : uniformtex("diffusemap", Tex_Diffuse);
350 0 : uniformtex("normalmap", Tex_Normal);
351 0 : uniformtex("glowmap", Tex_Glow);
352 0 : uniformtex("blendmap", 7);
353 0 : uniformtex("refractmask", 7);
354 0 : uniformtex("refractlight", 8);
355 : }
356 0 : for(SlotShaderParamState ¶m : defaultparams)
357 : {
358 0 : param.loc = glGetUniformLocation(program, param.name.c_str());
359 : }
360 0 : for(UniformLoc &loc : uniformlocs)
361 : {
362 0 : bindglsluniform(*this, loc);
363 : }
364 0 : glUseProgram(0);
365 : }
366 2 : else if(program)
367 : {
368 0 : if(msg)
369 : {
370 0 : showglslinfo(GL_FALSE, program, name);
371 : }
372 0 : glDeleteProgram(program);
373 0 : program = 0;
374 : }
375 2 : }
376 :
377 0 : size_t getlocalparam(const std::string &name)
378 : {
379 0 : auto itr = localparams.find(name);
380 0 : if(itr != localparams.end())
381 : {
382 0 : return (*itr).second;
383 : }
384 0 : size_t size = localparams.size();
385 0 : localparams.insert( { name, size } );
386 0 : return size;
387 : }
388 :
389 0 : static int addlocalparam(Shader &s, const char *name, GLint loc, GLsizei size, GLenum format)
390 : {
391 0 : size_t idx = getlocalparam(name);
392 0 : if(idx >= s.localparamremap.size())
393 : {
394 0 : int n = idx + 1 - s.localparamremap.size();
395 0 : for(int i = 0; i < n; ++i)
396 : {
397 0 : s.localparamremap.push_back(0xFF);
398 : }
399 : }
400 0 : s.localparamremap[idx] = s.localparams.size();
401 0 : LocalShaderParamState l;
402 0 : l.name = name;
403 0 : l.loc = loc;
404 0 : l.size = size;
405 0 : l.format = format;
406 0 : s.localparams.push_back(l);
407 0 : return idx;
408 0 : }
409 :
410 0 : static void addglobalparam(Shader &s, const GlobalShaderParamState *param, GLint loc, GLsizei size, GLenum format)
411 : {
412 0 : s.globalparams.emplace_back(loc, size, format, param, -2);
413 0 : }
414 :
415 0 : void Shader::setglsluniformformat(const char *name, GLenum format, GLsizei size)
416 : {
417 0 : switch(format)
418 : {
419 0 : case GL_FLOAT:
420 : case GL_FLOAT_VEC2:
421 : case GL_FLOAT_VEC3:
422 : case GL_FLOAT_VEC4:
423 : case GL_INT:
424 : case GL_INT_VEC2:
425 : case GL_INT_VEC3:
426 : case GL_INT_VEC4:
427 : case GL_UNSIGNED_INT:
428 : case GL_UNSIGNED_INT_VEC2:
429 : case GL_UNSIGNED_INT_VEC3:
430 : case GL_UNSIGNED_INT_VEC4:
431 : case GL_BOOL:
432 : case GL_BOOL_VEC2:
433 : case GL_BOOL_VEC3:
434 : case GL_BOOL_VEC4:
435 : case GL_FLOAT_MAT2:
436 : case GL_FLOAT_MAT3:
437 : case GL_FLOAT_MAT4:
438 : {
439 0 : break;
440 : }
441 0 : default:
442 : {
443 0 : return;
444 : }
445 : }
446 0 : if(!std::strncmp(name, "gl_", 3))
447 : {
448 0 : return;
449 : }
450 0 : GLint loc = glGetUniformLocation(program, name);
451 0 : if(loc < 0)
452 : {
453 0 : return;
454 : }
455 0 : for(uint j = 0; j < defaultparams.size(); j++)
456 : {
457 0 : if(defaultparams[j].loc == loc)
458 : {
459 0 : defaultparams[j].format = format;
460 0 : return;
461 : }
462 : }
463 0 : for(uint j = 0; j < uniformlocs.size(); j++)
464 : {
465 0 : if(uniformlocs[j].loc == loc)
466 : {
467 0 : return;
468 : }
469 : }
470 0 : for(uint j = 0; j < globalparams.size(); j++)
471 : {
472 0 : if(globalparams[j].loc == loc)
473 : {
474 0 : return;
475 : }
476 : }
477 0 : for(uint j = 0; j < localparams.size(); j++)
478 : {
479 0 : if(localparams[j].loc == loc)
480 : {
481 0 : return;
482 : }
483 : }
484 :
485 0 : name = getshaderparamname(name);
486 : //must explicitly enumerate scope because globalparams is a field & gvar :(
487 0 : auto itr = ::globalparams.find(name);
488 0 : if(itr != ::globalparams.end())
489 : {
490 0 : addglobalparam(*this, &((*itr).second), loc, size, format);
491 : }
492 : else
493 : {
494 0 : addlocalparam(*this, name, loc, size, format);
495 : }
496 : }
497 :
498 0 : void Shader::allocglslactiveuniforms()
499 : {
500 0 : GLint numactive = 0;
501 0 : glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &numactive);
502 : string name;
503 0 : for(int i = 0; i < numactive; ++i)
504 : {
505 0 : GLsizei namelen = 0;
506 0 : GLint size = 0;
507 0 : GLenum format = GL_FLOAT_VEC4;
508 0 : name[0] = '\0';
509 0 : glGetActiveUniform(program, i, sizeof(name)-1, &namelen, &size, &format, name);
510 0 : if(namelen <= 0 || size <= 0)
511 : {
512 0 : continue;
513 : }
514 0 : name[std::clamp(static_cast<int>(namelen), 0, static_cast<int>(sizeof(name))-2)] = '\0';
515 0 : char *brak = std::strchr(name, '[');
516 0 : if(brak)
517 : {
518 0 : *brak = '\0';
519 : }
520 0 : setglsluniformformat(name, format, size);
521 : }
522 0 : }
523 :
524 : int GlobalShaderParamState::nextversion = 0;
525 :
526 0 : void GlobalShaderParamState::resetversions()
527 : {
528 0 : for(auto &[k, s] : shaders)
529 : {
530 0 : for(GlobalShaderParamUse &u : s.globalparams)
531 : {
532 0 : if(u.version != u.param->version)
533 : {
534 0 : u.version = -2;
535 : }
536 : }
537 : }
538 0 : nextversion = 0;
539 0 : for(auto& [k, g] : globalparams)
540 : {
541 0 : g.version = ++nextversion;
542 : }
543 0 : for(auto &[k, s] : shaders)
544 : {
545 0 : for(GlobalShaderParamUse &u : s.globalparams)
546 : {
547 0 : if(u.version >= 0)
548 : {
549 0 : u.version = u.param->version;
550 : }
551 : }
552 : }
553 0 : }
554 :
555 0 : static const float *findslotparam(const Slot &s, const char *name, const float *noval = nullptr)
556 : {
557 0 : for(const SlotShaderParam ¶m : s.params)
558 : {
559 0 : if(name == param.name)
560 : {
561 0 : return ¶m.val[0];
562 : }
563 : }
564 0 : for(const SlotShaderParamState ¶m : s.shader->defaultparams)
565 : {
566 0 : if(name == param.name)
567 : {
568 0 : return ¶m.val[0];
569 : }
570 : }
571 0 : return noval;
572 : }
573 :
574 0 : static const float *findslotparam(const VSlot &s, const char *name, const float *noval = nullptr)
575 : {
576 0 : for(const SlotShaderParam ¶m : s.params)
577 : {
578 0 : if(name == param.name)
579 : {
580 0 : return ¶m.val[0];
581 : }
582 : }
583 0 : return findslotparam(*s.slot, name, noval);
584 : }
585 :
586 0 : static void setslotparam(const SlotShaderParamState &l, const float *val)
587 : {
588 0 : switch(l.format)
589 : {
590 0 : case GL_BOOL:
591 : case GL_FLOAT:
592 : {
593 0 : glUniform1fv(l.loc, 1, val);
594 0 : break;
595 : }
596 0 : case GL_BOOL_VEC2:
597 : case GL_FLOAT_VEC2:
598 : {
599 0 : glUniform2fv(l.loc, 1, val);
600 0 : break;
601 : }
602 0 : case GL_BOOL_VEC3:
603 : case GL_FLOAT_VEC3:
604 : {
605 0 : glUniform3fv(l.loc, 1, val);
606 0 : break;
607 : }
608 0 : case GL_BOOL_VEC4:
609 : case GL_FLOAT_VEC4:
610 : {
611 0 : glUniform4fv(l.loc, 1, val);
612 0 : break;
613 : }
614 0 : case GL_INT:
615 : {
616 0 : glUniform1i(l.loc, static_cast<int>(val[0]));
617 0 : break;
618 : }
619 0 : case GL_INT_VEC2:
620 : {
621 0 : glUniform2i(l.loc, static_cast<int>(val[0]), static_cast<int>(val[1]));
622 0 : break;
623 : }
624 0 : case GL_INT_VEC3:
625 : {
626 0 : glUniform3i(l.loc, static_cast<int>(val[0]), static_cast<int>(val[1]), static_cast<int>(val[2]));
627 0 : break;
628 : }
629 0 : case GL_INT_VEC4:
630 : {
631 0 : glUniform4i(l.loc, static_cast<int>(val[0]), static_cast<int>(val[1]), static_cast<int>(val[2]), static_cast<int>(val[3]));
632 0 : break;
633 : }
634 0 : case GL_UNSIGNED_INT:
635 : {
636 0 : glUniform1ui(l.loc, static_cast<uint>(val[0]));
637 0 : break;
638 : }
639 0 : case GL_UNSIGNED_INT_VEC2:
640 : {
641 0 : glUniform2ui(l.loc, static_cast<uint>(val[0]), static_cast<uint>(val[1]));
642 0 : break;
643 : }
644 0 : case GL_UNSIGNED_INT_VEC3:
645 : {
646 0 : glUniform3ui(l.loc, static_cast<uint>(val[0]), static_cast<uint>(val[1]), static_cast<uint>(val[2]));
647 0 : break;
648 : }
649 0 : case GL_UNSIGNED_INT_VEC4:
650 : {
651 0 : glUniform4ui(l.loc, static_cast<uint>(val[0]), static_cast<uint>(val[1]), static_cast<uint>(val[2]), static_cast<uint>(val[3]));
652 0 : break;
653 : }
654 : }
655 0 : }
656 :
657 0 : static void setslotparam(const SlotShaderParamState& l, uint& mask, uint i, const float* val)
658 : {
659 0 : if(!(mask&(1<<i)))
660 : {
661 0 : mask |= 1<<i;
662 0 : setslotparam(l, val);
663 : }
664 0 : }
665 :
666 0 : static void setslotparams(const std::vector<SlotShaderParam>& p, uint& unimask, const std::vector<SlotShaderParamState>& defaultparams)
667 : {
668 0 : for(const SlotShaderParam &p : slotparams)
669 : {
670 0 : if(!(defaultparams.size() > p.loc))
671 : {
672 0 : continue;
673 : }
674 0 : const SlotShaderParamState &l = defaultparams.at(p.loc);
675 0 : setslotparam(l, unimask, p.loc, p.val);
676 : }
677 0 : }
678 :
679 0 : static void setdefaultparams(const std::vector<SlotShaderParamState>& defaultparams, uint& unimask)
680 : {
681 0 : for(uint i = 0; i < defaultparams.size(); i++)
682 : {
683 0 : const SlotShaderParamState &l = defaultparams.at(i);
684 0 : setslotparam(l, unimask, i, &l.val[0]);
685 : }
686 0 : }
687 :
688 : //shader
689 :
690 1 : Shader::Shader() : name(nullptr), defer(nullptr), type(Shader_Default), program(0), variantshader(nullptr), standard(false), forced(false), owner(nullptr), vsstr(nullptr), psstr(nullptr), vsobj(0), psobj(0), reusevs(nullptr), reuseps(nullptr), variantrows(nullptr), used(false)
691 : {
692 1 : }
693 :
694 3 : Shader::~Shader()
695 : {
696 3 : delete[] name;
697 3 : delete[] vsstr;
698 3 : delete[] psstr;
699 3 : delete[] defer;
700 3 : delete[] variantrows;
701 3 : }
702 :
703 0 : void Shader::flushparams()
704 : {
705 0 : if(!used)
706 : {
707 0 : allocglslactiveuniforms();
708 0 : used = true;
709 : }
710 0 : for(GlobalShaderParamUse &i : globalparams)
711 : {
712 0 : i.flush();
713 : }
714 0 : }
715 :
716 0 : bool Shader::invalid() const
717 : {
718 0 : return (type & Shader_Invalid) != 0;
719 : }
720 0 : bool Shader::deferred() const
721 : {
722 0 : return (type & Shader_Deferred) != 0;
723 : }
724 5 : bool Shader::loaded() const
725 : {
726 5 : return !(type&(Shader_Deferred | Shader_Invalid));
727 : }
728 :
729 0 : bool Shader::isdynamic() const
730 : {
731 0 : return (type & Shader_Dynamic) != 0;
732 : }
733 :
734 0 : int Shader::numvariants(int row) const
735 : {
736 0 : if(row < 0 || row >= maxvariantrows || !variantrows)
737 : {
738 0 : return 0;
739 : }
740 0 : return variantrows[row+1] - variantrows[row];
741 : }
742 :
743 0 : const Shader *Shader::getvariant(int col, int row) const
744 : {
745 0 : if(row < 0 || row >= maxvariantrows || col < 0 || !variantrows)
746 : {
747 0 : return nullptr;
748 : }
749 0 : int start = variantrows[row],
750 0 : end = variantrows[row+1];
751 0 : return col < end - start ? variants[start + col] : nullptr;
752 : }
753 :
754 0 : void Shader::addvariant(int row, Shader *s)
755 : {
756 0 : if(row < 0 || row >= maxvariantrows || variants.size() >= USHRT_MAX)
757 : {
758 0 : return;
759 : }
760 0 : if(!variantrows)
761 : {
762 0 : variantrows = new ushort[maxvariantrows+1];
763 0 : std::memset(variantrows, 0, (maxvariantrows+1)*sizeof(ushort));
764 : }
765 0 : variants.insert(variants.begin() + variantrows[row+1], s);
766 0 : for(int i = row+1; i <= maxvariantrows; ++i)
767 : {
768 0 : ++variantrows[i];
769 : }
770 : }
771 :
772 0 : void Shader::setvariant_(int col, int row)
773 : {
774 0 : Shader *s = this;
775 0 : if(variantrows)
776 : {
777 0 : int start = variantrows[row],
778 0 : end = variantrows[row+1];
779 0 : for(col = std::min(start + col, end-1); col >= start; --col)
780 : {
781 0 : if(!variants[col]->invalid())
782 : {
783 0 : s = variants[col];
784 0 : break;
785 : }
786 : }
787 : }
788 0 : if(lastshader!=s)
789 : {
790 0 : s->bindprograms();
791 : }
792 0 : }
793 :
794 0 : void Shader::setvariant(int col, int row)
795 : {
796 0 : if(!loaded())
797 : {
798 0 : return;
799 : }
800 0 : setvariant_(col, row);
801 0 : lastshader->flushparams();
802 : }
803 :
804 0 : void Shader::setvariant(int col, int row, const Slot &slot)
805 : {
806 0 : if(!loaded())
807 : {
808 0 : return;
809 : }
810 0 : setvariant_(col, row);
811 0 : lastshader->flushparams();
812 0 : lastshader->setslotparams(slot);
813 : }
814 :
815 0 : void Shader::setvariant(int col, int row, const Slot &slot, const VSlot &vslot)
816 : {
817 0 : if(!loaded())
818 : {
819 0 : return;
820 : }
821 0 : setvariant_(col, row);
822 0 : lastshader->flushparams();
823 0 : lastshader->setslotparams(slot, vslot);
824 : }
825 :
826 0 : void Shader::set_()
827 : {
828 0 : if(lastshader!=this)
829 : {
830 0 : bindprograms();
831 : }
832 0 : }
833 :
834 0 : void Shader::set()
835 : {
836 0 : if(!loaded())
837 : {
838 0 : return;
839 : }
840 0 : set_();
841 0 : lastshader->flushparams();
842 : }
843 :
844 0 : void Shader::set(const Slot &slot)
845 : {
846 0 : if(!loaded())
847 : {
848 0 : return;
849 : }
850 0 : set_();
851 0 : lastshader->flushparams();
852 0 : lastshader->setslotparams(slot);
853 : }
854 :
855 0 : void Shader::set(const Slot &slot, const VSlot &vslot)
856 : {
857 0 : if(!loaded())
858 : {
859 0 : return;
860 : }
861 0 : set_();
862 0 : lastshader->flushparams();
863 0 : lastshader->setslotparams(slot, vslot);
864 : }
865 :
866 0 : void Shader::setslotparams(const Slot &slot)
867 : {
868 0 : uint unimask = 0;
869 0 : ::setslotparams(slot.params, unimask, defaultparams);
870 0 : setdefaultparams(defaultparams, unimask);
871 0 : }
872 :
873 0 : void Shader::setslotparams(const Slot &slot, const VSlot &vslot)
874 : {
875 : static bool thrown = false; //only throw error message once (will spam per frame otherwise)
876 0 : uint unimask = 0;
877 0 : if(vslot.slot == &slot)
878 : {
879 0 : ::setslotparams(vslot.params, unimask, defaultparams);
880 0 : for(size_t i = 0; i < slot.params.size(); i++)
881 : {
882 0 : const SlotShaderParam &p = slot.params.at(i);
883 0 : if(!(defaultparams.size() > p.loc))
884 : {
885 0 : continue;
886 : }
887 0 : if(p.loc == SIZE_MAX)
888 : {
889 0 : if(!thrown)
890 : {
891 0 : std::printf("Invalid slot shader param index: some slot shaders may not be in use\n");
892 0 : thrown = true;
893 : }
894 : }
895 0 : else if(!(unimask&(1<<p.loc)))
896 : {
897 0 : const SlotShaderParamState &l = defaultparams.at(p.loc);
898 0 : unimask |= 1<<p.loc;
899 0 : setslotparam(l, p.val);
900 : }
901 : }
902 0 : setdefaultparams(defaultparams, unimask);
903 : }
904 : else
905 : {
906 0 : ::setslotparams(slot.params, unimask, defaultparams);
907 0 : for(uint i = 0; i < defaultparams.size(); i++)
908 : {
909 0 : const SlotShaderParamState &l = defaultparams.at(i);
910 0 : setslotparam(l, unimask, i, l.flags&SlotShaderParam::REUSE ? findslotparam(vslot, l.name.c_str(), &l.val[0]) : &l.val[0]);
911 : }
912 : }
913 0 : }
914 :
915 0 : void Shader::bindprograms()
916 : {
917 0 : if(this == lastshader || !loaded())
918 : {
919 0 : return;
920 : }
921 0 : glUseProgram(program);
922 0 : lastshader = this;
923 : }
924 :
925 2 : bool Shader::compile()
926 : {
927 2 : if(!vsstr)
928 : {
929 0 : vsobj = !reusevs || reusevs->invalid() ? 0 : reusevs->vsobj;
930 : }
931 : else
932 : {
933 2 : compileglslshader(*this, GL_VERTEX_SHADER, vsobj, vsstr, name, debugshader || !variantshader);
934 : }
935 2 : if(!psstr)
936 : {
937 0 : psobj = !reuseps || reuseps->invalid() ? 0 : reuseps->psobj;
938 : }
939 : else
940 : {
941 2 : compileglslshader(*this, GL_FRAGMENT_SHADER, psobj, psstr, name, debugshader || !variantshader);
942 : }
943 2 : linkglslprogram(!variantshader);
944 2 : return program!=0;
945 : }
946 :
947 2 : void Shader::cleanup(bool full)
948 : {
949 2 : used = false;
950 2 : if(vsobj)
951 : {
952 0 : if(!reusevs)
953 : {
954 0 : glDeleteShader(vsobj); vsobj = 0;
955 : }
956 : }
957 2 : if(psobj)
958 : {
959 0 : if(!reuseps)
960 : {
961 0 : glDeleteShader(psobj);
962 0 : psobj = 0;
963 : }
964 : }
965 2 : if(program)
966 : {
967 0 : glDeleteProgram(program);
968 0 : program = 0;
969 : }
970 2 : localparams.clear();
971 2 : localparamremap.clear();
972 2 : globalparams.clear();
973 2 : if(standard || full)
974 : {
975 2 : type = Shader_Invalid;
976 :
977 2 : delete[] vsstr;
978 2 : delete[] psstr;
979 2 : delete[] defer;
980 :
981 2 : vsstr = nullptr;
982 2 : psstr = nullptr;
983 2 : defer = nullptr;
984 :
985 2 : variants.clear();
986 :
987 2 : delete[] variantrows;
988 2 : variantrows = nullptr;
989 :
990 2 : defaultparams.clear();
991 2 : attriblocs.clear();
992 2 : uniformlocs.clear();
993 2 : reusevs = reuseps = nullptr;
994 : }
995 : else
996 : {
997 0 : for(uint i = 0; i < defaultparams.size(); i++)
998 : {
999 0 : defaultparams[i].loc = -1;
1000 : }
1001 : }
1002 2 : }
1003 : //ShaderParamBinding
1004 :
1005 1 : ShaderParamBinding::ShaderParamBinding(GLint loc, GLsizei size, GLenum format) :
1006 1 : loc(loc), size(size), format(format)
1007 : {
1008 1 : }
1009 :
1010 : // globalshaderparamuse
1011 :
1012 0 : GlobalShaderParamUse::GlobalShaderParamUse(GLint loc, GLsizei size, GLenum format, const GlobalShaderParamState *param, int version) :
1013 0 : ShaderParamBinding(loc, size, format), param(param), version(version)
1014 : {
1015 0 : }
1016 :
1017 0 : void GlobalShaderParamUse::flush()
1018 : {
1019 0 : if(version == param->version)
1020 : {
1021 0 : return;
1022 : }
1023 0 : switch(format)
1024 : {
1025 0 : case GL_BOOL:
1026 : case GL_FLOAT:
1027 : {
1028 0 : glUniform1fv(loc, size, param->fval);
1029 0 : break;
1030 : }
1031 0 : case GL_BOOL_VEC2:
1032 : case GL_FLOAT_VEC2:
1033 : {
1034 0 : glUniform2fv(loc, size, param->fval);
1035 0 : break;
1036 : }
1037 0 : case GL_BOOL_VEC3:
1038 : case GL_FLOAT_VEC3:
1039 : {
1040 0 : glUniform3fv(loc, size, param->fval);
1041 0 : break;
1042 : }
1043 0 : case GL_BOOL_VEC4:
1044 : case GL_FLOAT_VEC4:
1045 : {
1046 0 : glUniform4fv(loc, size, param->fval);
1047 0 : break;
1048 : }
1049 0 : case GL_INT:
1050 : {
1051 0 : glUniform1iv(loc, size, param->ival);
1052 0 : break;
1053 : }
1054 0 : case GL_INT_VEC2:
1055 : {
1056 0 : glUniform2iv(loc, size, param->ival);
1057 0 : break;
1058 : }
1059 0 : case GL_INT_VEC3:
1060 : {
1061 0 : glUniform3iv(loc, size, param->ival);
1062 0 : break;
1063 : }
1064 0 : case GL_INT_VEC4:
1065 : {
1066 0 : glUniform4iv(loc, size, param->ival);
1067 0 : break;
1068 : }
1069 0 : case GL_UNSIGNED_INT:
1070 : {
1071 0 : glUniform1uiv(loc, size, param->uval);
1072 0 : break;
1073 : }
1074 0 : case GL_UNSIGNED_INT_VEC2:
1075 : {
1076 0 : glUniform2uiv(loc, size, param->uval);
1077 0 : break;
1078 : }
1079 0 : case GL_UNSIGNED_INT_VEC3:
1080 : {
1081 0 : glUniform3uiv(loc, size, param->uval);
1082 0 : break;
1083 : }
1084 0 : case GL_UNSIGNED_INT_VEC4:
1085 : {
1086 0 : glUniform4uiv(loc, size, param->uval);
1087 0 : break;
1088 : }
1089 0 : case GL_FLOAT_MAT2:
1090 : {
1091 0 : glUniformMatrix2fv(loc, 1, GL_FALSE, param->fval);
1092 0 : break;
1093 : }
1094 0 : case GL_FLOAT_MAT3:
1095 : {
1096 0 : glUniformMatrix3fv(loc, 1, GL_FALSE, param->fval);
1097 0 : break;
1098 : }
1099 0 : case GL_FLOAT_MAT4:
1100 : {
1101 0 : glUniformMatrix4fv(loc, 1, GL_FALSE, param->fval);
1102 0 : break;
1103 : }
1104 : }
1105 0 : version = param->version;
1106 : }
1107 :
1108 : //localshaderparamstate
1109 :
1110 1 : LocalShaderParamState::LocalShaderParamState(GLint loc, GLsizei size, GLenum format) :
1111 1 : ShaderParamBinding(loc, size, format)
1112 : {
1113 1 : }
1114 :
1115 :
1116 2 : void Shader::genattriblocs(const char *vs, const Shader *reusevs)
1117 : {
1118 : static int len = std::strlen("//:attrib");
1119 : string name;
1120 : int loc;
1121 2 : if(reusevs)
1122 : {
1123 0 : attriblocs = reusevs->attriblocs;
1124 : }
1125 : else
1126 : {
1127 2 : while((vs = std::strstr(vs, "//:attrib")))
1128 : {
1129 0 : if(std::sscanf(vs, "//:attrib %100s %d", name, &loc) == 2)
1130 : {
1131 0 : attriblocs.emplace_back(Shader::AttribLoc(getshaderparamname(name), loc));
1132 : }
1133 0 : vs += len;
1134 : }
1135 : }
1136 2 : }
1137 :
1138 : // adds to uniformlocs vector defined uniformlocs
1139 2 : void Shader::genuniformlocs(const char *vs, const Shader *reusevs, const Shader *reuseps)
1140 : {
1141 : static int len = std::strlen("//:uniform");
1142 : string name, blockname;
1143 : int binding, stride;
1144 2 : if(reusevs)
1145 : {
1146 0 : uniformlocs = reusevs->uniformlocs;
1147 : }
1148 : else
1149 : {
1150 2 : while((vs = std::strstr(vs, "//:uniform")))
1151 : {
1152 0 : int numargs = std::sscanf(vs, "//:uniform %100s %100s %d %d", name, blockname, &binding, &stride);
1153 0 : if(numargs >= 3)
1154 : {
1155 0 : uniformlocs.emplace_back(UniformLoc(getshaderparamname(name), getshaderparamname(blockname), binding, numargs >= 4 ? stride : 0));
1156 : }
1157 0 : else if(numargs >= 1)
1158 : {
1159 0 : uniformlocs.emplace_back(UniformLoc(getshaderparamname(name)));
1160 : }
1161 0 : vs += len;
1162 : }
1163 : }
1164 2 : }
1165 :
1166 2 : static Shader *newshader(int type, const char *name, const char *vs, const char *ps, Shader *variant = nullptr, int row = 0)
1167 : {
1168 2 : if(Shader::lastshader)
1169 : {
1170 0 : glUseProgram(0);
1171 0 : Shader::lastshader = nullptr;
1172 : }
1173 2 : auto itr = shaders.find(name);
1174 2 : Shader *exists = (itr != shaders.end()) ? &(*itr).second : nullptr;
1175 2 : char *rname = exists ? exists->name : newstring(name);
1176 2 : if(!exists)
1177 : {
1178 0 : itr = shaders.insert( { rname, Shader() } ).first;
1179 : }
1180 2 : Shader *retval = (*itr).second.setupshader(rname, ps, vs, variant, row);
1181 2 : return retval; //can be nullptr or s
1182 : }
1183 :
1184 2 : Shader *Shader::setupshader(char *rname, const char *ps, const char *vs, Shader *variant, int row)
1185 : {
1186 2 : name = rname;
1187 2 : vsstr = newstring(vs);
1188 2 : psstr = newstring(ps);
1189 :
1190 2 : delete[] defer;
1191 2 : defer = nullptr;
1192 :
1193 2 : type = type & ~(Shader_Invalid | Shader_Deferred);
1194 2 : variantshader = variant;
1195 2 : standard = standardshaders;
1196 2 : if(forceshaders)
1197 : {
1198 2 : forced = true;
1199 : }
1200 2 : reusevs = reuseps = nullptr;
1201 2 : if(variant)
1202 : {
1203 0 : int row = 0,
1204 0 : col = 0;
1205 0 : if(!vs[0] || std::sscanf(vs, "%d , %d", &row, &col) >= 1)
1206 : {
1207 0 : delete[] vsstr;
1208 0 : vsstr = nullptr;
1209 0 : reusevs = !vs[0] ? variant : variant->getvariant(col, row);
1210 : }
1211 0 : row = col = 0;
1212 0 : if(!ps[0] || std::sscanf(ps, "%d , %d", &row, &col) >= 1)
1213 : {
1214 0 : delete[] psstr;
1215 0 : psstr = nullptr;
1216 0 : reuseps = !ps[0] ? variant : variant->getvariant(col, row);
1217 : }
1218 : }
1219 2 : if(variant)
1220 : {
1221 0 : for(uint i = 0; i < variant->defaultparams.size(); i++)
1222 : {
1223 0 : defaultparams.emplace_back(variant->defaultparams[i]);
1224 : }
1225 : }
1226 : else
1227 : {
1228 3 : for(uint i = 0; i < slotparams.size(); i++)
1229 : {
1230 1 : defaultparams.emplace_back(slotparams[i]);
1231 : }
1232 : }
1233 2 : attriblocs.clear();
1234 2 : uniformlocs.clear();
1235 2 : genattriblocs(vs, reusevs);
1236 2 : genuniformlocs(vs, reusevs, reuseps);
1237 2 : if(!compile())
1238 : {
1239 2 : cleanup(true);
1240 2 : if(variant)
1241 : {
1242 0 : shaders.erase(rname);
1243 : }
1244 2 : return nullptr;
1245 : }
1246 0 : if(variant)
1247 : {
1248 0 : variant->addvariant(row, this);
1249 : }
1250 0 : return this;
1251 : }
1252 :
1253 2 : static size_t findglslmain(std::string s)
1254 : {
1255 2 : size_t main = s.find("main");
1256 2 : if(main == std::string::npos)
1257 : {
1258 2 : return std::string::npos;
1259 : }
1260 0 : for(; main >= 0; main--) //note reverse iteration
1261 : {
1262 0 : switch(s[main])
1263 : {
1264 0 : case '\r':
1265 : case '\n':
1266 : case ';':
1267 : {
1268 0 : return main + 1;
1269 : }
1270 : }
1271 : }
1272 : return 0;
1273 : }
1274 :
1275 0 : static void gengenericvariant(Shader &s, const char *sname, const char *vs, const char *ps, int row = 0)
1276 : {
1277 0 : int rowoffset = 0;
1278 0 : bool vschanged = false,
1279 0 : pschanged = false;
1280 0 : std::vector<char> vsv, psv;
1281 0 : for(uint i = 0; i < std::strlen(vs)+1; ++i)
1282 : {
1283 0 : vsv.push_back(vs[i]);
1284 : }
1285 0 : for(uint i = 0; i < std::strlen(ps)+1; ++i)
1286 : {
1287 0 : psv.push_back(ps[i]);
1288 : }
1289 :
1290 : //cannot be constexpr-- strlen is not compile time
1291 : static const int len = std::strlen("//:variant"),
1292 : olen = std::strlen("override");
1293 0 : for(char *vspragma = vsv.data();; vschanged = true)
1294 : {
1295 0 : vspragma = std::strstr(vspragma, "//:variant");
1296 0 : if(!vspragma)
1297 : {
1298 0 : break;
1299 : }
1300 0 : if(std::sscanf(vspragma + len, "row %d", &rowoffset) == 1)
1301 : {
1302 0 : continue;
1303 : }
1304 0 : std::memset(vspragma, ' ', len);
1305 0 : vspragma += len;
1306 0 : if(!std::strncmp(vspragma, "override", olen))
1307 : {
1308 0 : std::memset(vspragma, ' ', olen);
1309 0 : vspragma += olen;
1310 0 : char *end = vspragma + std::strcspn(vspragma, "\n\r");
1311 0 : end += std::strspn(end, "\n\r");
1312 0 : int endlen = std::strcspn(end, "\n\r");
1313 0 : std::memset(end, ' ', endlen);
1314 : }
1315 0 : }
1316 0 : for(char *pspragma = psv.data();; pschanged = true)
1317 : {
1318 0 : pspragma = std::strstr(pspragma, "//:variant");
1319 0 : if(!pspragma)
1320 : {
1321 0 : break;
1322 : }
1323 0 : if(std::sscanf(pspragma + len, "row %d", &rowoffset) == 1)
1324 : {
1325 0 : continue;
1326 : }
1327 0 : std::memset(pspragma, ' ', len);
1328 0 : pspragma += len;
1329 0 : if(!std::strncmp(pspragma, "override", olen))
1330 : {
1331 0 : std::memset(pspragma, ' ', olen);
1332 0 : pspragma += olen;
1333 0 : char *end = pspragma + std::strcspn(pspragma, "\n\r");
1334 0 : end += std::strspn(end, "\n\r");
1335 0 : int endlen = std::strcspn(end, "\n\r");
1336 0 : std::memset(end, ' ', endlen);
1337 : }
1338 0 : }
1339 0 : row += rowoffset;
1340 0 : if(row < 0 || row >= maxvariantrows)
1341 : {
1342 0 : return;
1343 : }
1344 0 : int col = s.numvariants(row);
1345 0 : DEF_FORMAT_STRING(varname, "<variant:%d,%d>%s", col, row, sname);
1346 : string reuse;
1347 0 : if(col)
1348 : {
1349 0 : formatstring(reuse, "%d", row);
1350 : }
1351 : else
1352 : {
1353 0 : copystring(reuse, "");
1354 : }
1355 0 : newshader(s.type, varname, vschanged ? vsv.data() : reuse, pschanged ? psv.data() : reuse, &s, row);
1356 0 : }
1357 :
1358 0 : static void genfogshader(std::string &vs, std::string &ps)
1359 : {
1360 : //unused PRAGMA_LEN
1361 : //constexpr int PRAGMA_LEN = std::string_view("//:fog").size() + 1;
1362 :
1363 0 : size_t vspragma = vs.find("//:fog"),
1364 0 : pspragma = ps.find("//:fog");
1365 :
1366 0 : if(vspragma == std::string::npos && pspragma == std::string::npos)
1367 : {
1368 0 : return;
1369 : }
1370 :
1371 0 : size_t vsmain = findglslmain(vs),
1372 0 : vsend = vs.rfind('}');
1373 :
1374 0 : if(vsmain != std::string::npos && vsend != std::string::npos)
1375 : {
1376 0 : if(vs.find("lineardepth") == std::string::npos)
1377 : {
1378 0 : constexpr std::string_view FOG_PARAMS = "\nuniform vec2 lineardepthscale;\nvarying float lineardepth;\n";
1379 0 : constexpr std::string_view VS_FOG = "\nlineardepth = dot(lineardepthscale, gl_Position.zw);\n";
1380 :
1381 0 : vs.insert(vsend, VS_FOG);
1382 0 : vs.insert(vsmain, FOG_PARAMS);
1383 : }
1384 : }
1385 :
1386 0 : size_t psmain = findglslmain(ps),
1387 0 : psend = ps.rfind('}');
1388 :
1389 0 : if(psmain != std::string::npos && psend != std::string::npos)
1390 : {
1391 0 : std::string params;
1392 :
1393 0 : if(ps.find("lineardepth") == std::string::npos)
1394 : {
1395 0 : params = "\nvarying float lineardepth;\n";
1396 : }
1397 :
1398 : std::string fogparams =
1399 : "\nuniform vec3 fogcolor;\n"
1400 : "uniform vec2 fogdensity;\n"
1401 : "uniform vec4 radialfogscale;\n"
1402 0 : "#define fogcoord lineardepth*length(vec3(gl_FragCoord.xy*radialfogscale.xy + radialfogscale.zw, 1.0))\n";
1403 :
1404 0 : params += fogparams;
1405 :
1406 0 : std::string psfog = "\nfragcolor.rgb = mix((fogcolor).rgb, fragcolor.rgb, clamp(exp2(fogcoord*-fogdensity.x)*fogdensity.y, 0.0, 1.0));\n";
1407 0 : ps.insert(psend, psfog);
1408 0 : ps.insert(psmain, params);
1409 0 : }
1410 : }
1411 :
1412 1 : static void genuniformdefs(std::string &vs, std::string &ps, const Shader *variant = nullptr)
1413 : {
1414 1 : if(variant ? variant->defaultparams.empty() : slotparams.empty())
1415 : {
1416 1 : return;
1417 : }
1418 :
1419 1 : size_t vsmain = findglslmain(vs),
1420 1 : psmain = findglslmain(ps);
1421 :
1422 1 : if(vsmain == std::string::npos || psmain == std::string::npos)
1423 : {
1424 1 : return;
1425 : }
1426 :
1427 0 : std::string params;
1428 0 : if(variant)
1429 : {
1430 0 : for(const auto ¶m : variant->defaultparams)
1431 : {
1432 0 : DEF_FORMAT_STRING(uni, "\nuniform vec4 %s;\n", param.name.c_str());
1433 0 : params += uni;
1434 : }
1435 : }
1436 : else
1437 : {
1438 0 : for(const auto ¶m : slotparams)
1439 : {
1440 0 : DEF_FORMAT_STRING(uni, "\nuniform vec4 %s;\n", param.name);
1441 0 : params += uni;
1442 : }
1443 : }
1444 :
1445 0 : vs.insert(vsmain, params);
1446 0 : ps.insert(psmain, params);
1447 0 : }
1448 :
1449 0 : void setupshaders()
1450 : {
1451 0 : if(!glslversion)
1452 : {
1453 0 : conoutf(Console_Error, "Cannot setup GLSL shaders without GLSL initialized, operation not performed");
1454 0 : return;
1455 : }
1456 : GLint val;
1457 0 : glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &val);
1458 0 : maxvsuniforms = val/4;
1459 0 : glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &val);
1460 0 : maxfsuniforms = val/4;
1461 :
1462 0 : glGetIntegerv(GL_MIN_PROGRAM_TEXEL_OFFSET, &val);
1463 0 : mintexoffset = val;
1464 0 : glGetIntegerv(GL_MAX_PROGRAM_TEXEL_OFFSET, &val);
1465 0 : maxtexoffset = val;
1466 :
1467 0 : standardshaders = true;
1468 0 : nullshader = newshader(0, "<init>null",
1469 : "attribute vec4 vvertex;\n"
1470 : "void main(void) {\n"
1471 : " gl_Position = vvertex;\n"
1472 : "}\n",
1473 : "fragdata(0) vec4 fragcolor;\n"
1474 : "void main(void) {\n"
1475 : " fragcolor = vec4(1.0, 0.0, 1.0, 1.0);\n"
1476 : "}\n");
1477 0 : hudshader = newshader(0, "<init>hud",
1478 : "attribute vec4 vvertex, vcolor;\n"
1479 : "attribute vec2 vtexcoord0;\n"
1480 : "uniform mat4 hudmatrix;\n"
1481 : "varying vec2 texcoord0;\n"
1482 : "varying vec4 colorscale;\n"
1483 : "void main(void) {\n"
1484 : " gl_Position = hudmatrix * vvertex;\n"
1485 : " texcoord0 = vtexcoord0;\n"
1486 : " colorscale = vcolor;\n"
1487 : "}\n",
1488 : "uniform sampler2D tex0;\n"
1489 : "varying vec2 texcoord0;\n"
1490 : "varying vec4 colorscale;\n"
1491 : "fragdata(0) vec4 fragcolor;\n"
1492 : "void main(void) {\n"
1493 : " vec4 color = texture2D(tex0, texcoord0);\n"
1494 : " fragcolor = colorscale * color;\n"
1495 : "}\n");
1496 0 : hudtextshader = newshader(0, "<init>hudtext",
1497 : "attribute vec4 vvertex, vcolor;\n"
1498 : "attribute vec2 vtexcoord0;\n"
1499 : "uniform mat4 hudmatrix;\n"
1500 : "varying vec2 texcoord0;\n"
1501 : "varying vec4 colorscale;\n"
1502 : "void main(void) {\n"
1503 : " gl_Position = hudmatrix * vvertex;\n"
1504 : " texcoord0 = vtexcoord0;\n"
1505 : " colorscale = vcolor;\n"
1506 : "}\n",
1507 : "uniform sampler2D tex0;\n"
1508 : "uniform vec4 textparams;\n"
1509 : "varying vec2 texcoord0;\n"
1510 : "varying vec4 colorscale;\n"
1511 : "fragdata(0) vec4 fragcolor;\n"
1512 : "void main(void) {\n"
1513 : " float dist = texture2D(tex0, texcoord0).r;\n"
1514 : " float border = smoothstep(textparams.x, textparams.y, dist);\n"
1515 : " float outline = smoothstep(textparams.z, textparams.w, dist);\n"
1516 : " fragcolor = vec4(colorscale.rgb * outline, colorscale.a * border);\n"
1517 : "}\n");
1518 0 : hudnotextureshader = newshader(0, "<init>hudnotexture",
1519 : "attribute vec4 vvertex, vcolor;\n"
1520 : "uniform mat4 hudmatrix;"
1521 : "varying vec4 color;\n"
1522 : "void main(void) {\n"
1523 : " gl_Position = hudmatrix * vvertex;\n"
1524 : " color = vcolor;\n"
1525 : "}\n",
1526 : "varying vec4 color;\n"
1527 : "fragdata(0) vec4 fragcolor;\n"
1528 : "void main(void) {\n"
1529 : " fragcolor = color;\n"
1530 : "}\n");
1531 0 : standardshaders = false;
1532 0 : if(!nullshader || !hudshader || !hudtextshader || !hudnotextureshader)
1533 : {
1534 0 : fatal("failed to setup shaders");
1535 : }
1536 0 : dummyslot.shader = nullshader;
1537 : }
1538 :
1539 : VAR(defershaders, 0, 1, 1);
1540 :
1541 1 : void defershader(const int *type, const char *name, const char *contents)
1542 : {
1543 1 : auto itr = shaders.find(name);
1544 1 : const Shader *exists = (itr != shaders.end()) ? &(*itr).second : nullptr;
1545 1 : if(exists && !exists->invalid())
1546 : {
1547 0 : return;
1548 : }
1549 1 : if(!defershaders)
1550 : {
1551 0 : execute(contents);
1552 0 : return;
1553 : }
1554 1 : char *rname = exists ? exists->name : newstring(name);
1555 1 : if(!exists)
1556 : {
1557 1 : itr = shaders.insert( { rname, Shader() } ).first;
1558 : }
1559 1 : Shader &s = (*itr).second;
1560 1 : s.name = rname;
1561 1 : delete[] s.defer;
1562 1 : s.defer = newstring(contents);
1563 1 : s.type = Shader_Deferred | (*type & ~Shader_Invalid);
1564 1 : s.standard = standardshaders;
1565 : }
1566 :
1567 :
1568 0 : void Shader::force()
1569 : {
1570 0 : if(!deferred() || !defer)
1571 : {
1572 0 : return;
1573 : }
1574 0 : char *cmd = defer;
1575 0 : defer = nullptr;
1576 0 : bool wasstandard = standardshaders,
1577 0 : wasforcing = forceshaders;
1578 0 : int oldflags = identflags;
1579 0 : standardshaders = standard;
1580 0 : forceshaders = false;
1581 0 : identflags &= ~Idf_Persist;
1582 0 : slotparams.clear();
1583 0 : execute(cmd);
1584 0 : identflags = oldflags;
1585 0 : forceshaders = wasforcing;
1586 0 : standardshaders = wasstandard;
1587 0 : delete[] cmd;
1588 :
1589 0 : if(deferred())
1590 : {
1591 0 : delete[] defer;
1592 0 : defer = nullptr;
1593 0 : type = Shader_Invalid;
1594 : }
1595 : }
1596 :
1597 0 : int Shader::uniformlocversion()
1598 : {
1599 : static int version = 0;
1600 0 : if(++version >= 0)
1601 : {
1602 0 : return version;
1603 : }
1604 0 : version = 0;
1605 0 : for(auto &[k, s] : shaders)
1606 : {
1607 0 : for(UniformLoc &j : s.uniformlocs)
1608 : {
1609 0 : j.version = -1;
1610 : }
1611 : }
1612 0 : return version;
1613 : }
1614 :
1615 1 : Shader *useshaderbyname(const char *name)
1616 : {
1617 1 : auto itr = shaders.find(name);
1618 1 : if(itr == shaders.end())
1619 : {
1620 1 : return nullptr;
1621 : }
1622 0 : Shader *s = &(*itr).second;
1623 0 : if(s->deferred())
1624 : {
1625 0 : s->force();
1626 : }
1627 0 : s->forced = true;
1628 0 : return s;
1629 : }
1630 :
1631 1 : void shader(const int *type, const char *name, const char *vs, const char *ps)
1632 : {
1633 1 : if(lookupshaderbyname(name))
1634 : {
1635 0 : return;
1636 : }
1637 1 : DEF_FORMAT_STRING(info, "shader %s", name);
1638 1 : renderprogress(loadprogress, info);
1639 2 : std::string vs_string(vs), ps_string(ps);
1640 :
1641 1 : if(!slotparams.empty())
1642 : {
1643 1 : genuniformdefs(vs_string, ps_string);
1644 : }
1645 :
1646 1 : if(vs_string.find("//:fog") != std::string::npos || ps_string.find("//:fog") != std::string::npos)
1647 : {
1648 0 : genfogshader(vs_string, ps_string);
1649 : }
1650 :
1651 1 : Shader *s = newshader(*type, name, vs_string.c_str(), ps_string.c_str());
1652 1 : if(s)
1653 : {
1654 0 : if(vs_string.find("//:variant") != std::string::npos || ps_string.find("//:variant") != std::string::npos)
1655 : {
1656 0 : gengenericvariant(*s, name, vs_string.c_str(), ps_string.c_str());
1657 : }
1658 : }
1659 1 : slotparams.clear();
1660 1 : }
1661 :
1662 : static bool adding_shader = false;
1663 : static std::vector<std::pair<std::string, std::string>> shader_defines;
1664 : static std::vector<std::string> shader_includes_vs, shader_includes_fs;
1665 : static std::string shader_path_vs, shader_path_fs;
1666 :
1667 1 : static std::string shader_make_defines()
1668 : {
1669 1 : std::string defines;
1670 :
1671 1 : for(const std::pair<std::string, std::string> &define : shader_defines)
1672 : {
1673 0 : defines += "#define " + define.first + " " + define.second + "\n";
1674 : }
1675 :
1676 1 : return defines;
1677 0 : }
1678 :
1679 1 : static void shader_clear_defines()
1680 : {
1681 1 : shader_defines.clear();
1682 1 : shader_includes_vs.clear();
1683 1 : shader_includes_fs.clear();
1684 1 : shader_path_vs.clear();
1685 1 : shader_path_fs.clear();
1686 1 : }
1687 :
1688 1 : static void shader_assemble(std::string &vs, std::string &ps)
1689 : {
1690 1 : std::string defines;
1691 :
1692 1 : defines = shader_make_defines();
1693 :
1694 1 : if(!shader_path_vs.empty())
1695 : {
1696 0 : char *vs_file = loadfile(path(shader_path_vs).c_str(), nullptr);
1697 0 : if(!vs_file)
1698 : {
1699 0 : conoutf(Console_Error, "could not load vertex shader %s", shader_path_vs.c_str());
1700 0 : adding_shader = false;
1701 0 : return;
1702 : }
1703 :
1704 0 : vs = vs_file;
1705 :
1706 0 : std::string includes;
1707 0 : for(const std::string &include : shader_includes_vs)
1708 : {
1709 0 : char *vs_include = loadfile(path(include).c_str(), nullptr);
1710 :
1711 0 : if(!vs_include)
1712 : {
1713 0 : conoutf(Console_Error, "could not load vertex shader include %s", include.c_str());
1714 0 : adding_shader = false;
1715 0 : return;
1716 : }
1717 :
1718 0 : includes += std::string(vs_include) + "\n";
1719 : }
1720 :
1721 0 : vs = defines + includes + vs;
1722 0 : }
1723 :
1724 1 : if(!shader_path_fs.empty())
1725 : {
1726 0 : char *ps_file = loadfile(path(shader_path_fs).c_str(), nullptr);
1727 0 : if(!ps_file)
1728 : {
1729 0 : conoutf(Console_Error, "could not load fragment shader %s", shader_path_fs.c_str());
1730 0 : adding_shader = false;
1731 0 : return;
1732 : }
1733 :
1734 0 : ps = ps_file;
1735 :
1736 0 : std::string includes;
1737 0 : for(const std::string &include : shader_includes_fs)
1738 : {
1739 0 : char *ps_include = loadfile(path(include).c_str(), nullptr);
1740 :
1741 0 : if(!ps_include)
1742 : {
1743 0 : conoutf(Console_Error, "could not load fragment shader include %s", include.c_str());
1744 0 : adding_shader = false;
1745 0 : return;
1746 : }
1747 :
1748 0 : includes += std::string(ps_include) + "\n";
1749 : }
1750 :
1751 0 : ps = defines + includes + ps;
1752 0 : }
1753 1 : }
1754 :
1755 1 : static void shader_new(const int *type, const char *name, const uint *code)
1756 : {
1757 1 : if(lookupshaderbyname(name))
1758 : {
1759 0 : return;
1760 : }
1761 :
1762 1 : adding_shader = true;
1763 1 : shader_clear_defines();
1764 :
1765 1 : execute(code);
1766 :
1767 1 : std::string vs, ps;
1768 1 : shader_assemble(vs, ps);
1769 :
1770 1 : DEF_FORMAT_STRING(info, "shader %s", name);
1771 1 : renderprogress(loadprogress, info);
1772 :
1773 1 : if(!slotparams.empty())
1774 : {
1775 0 : genuniformdefs(vs, ps);
1776 : }
1777 :
1778 1 : if(vs.find("//:fog") != std::string::npos || ps.find("//:fog") != std::string::npos)
1779 : {
1780 0 : genfogshader(vs, ps);
1781 : }
1782 :
1783 1 : Shader *s = newshader(*type, name, vs.c_str(), ps.c_str());
1784 1 : if(s)
1785 : {
1786 0 : if(vs.find("//:variant") != std::string::npos || ps.find("//:variant") != std::string::npos)
1787 : {
1788 0 : gengenericvariant(*s, name, vs.c_str(), ps.c_str());
1789 : }
1790 : }
1791 1 : slotparams.clear();
1792 :
1793 1 : adding_shader = false;
1794 1 : }
1795 :
1796 1 : static void shader_define(char *name, char *value)
1797 : {
1798 1 : if(!adding_shader)
1799 : {
1800 1 : return;
1801 : }
1802 :
1803 0 : shader_defines.emplace_back(name, value);
1804 : }
1805 :
1806 1 : static void shader_get_defines()
1807 : {
1808 1 : if(!adding_shader)
1809 : {
1810 1 : return;
1811 : }
1812 :
1813 0 : std::string res;
1814 :
1815 0 : for(const std::pair<std::string, std::string> &define : shader_defines)
1816 : {
1817 0 : res += " [" + define.first + " " + define.second + "]";
1818 : }
1819 :
1820 0 : result(res.c_str());
1821 0 : }
1822 :
1823 1 : static void shader_include_vs(char *path)
1824 : {
1825 1 : if(!adding_shader)
1826 : {
1827 1 : return;
1828 : }
1829 :
1830 0 : shader_includes_vs.emplace_back(path);
1831 : }
1832 :
1833 1 : static void shader_get_includes_vs()
1834 : {
1835 1 : if(!adding_shader)
1836 : {
1837 1 : return;
1838 : }
1839 :
1840 0 : std::string res;
1841 :
1842 0 : for(const std::string &include : shader_includes_vs)
1843 : {
1844 0 : res += " \"" + include + "\"";
1845 : }
1846 :
1847 0 : result(res.c_str());
1848 0 : }
1849 :
1850 1 : static void shader_include_fs(char *path)
1851 : {
1852 1 : if(!adding_shader)
1853 : {
1854 1 : return;
1855 : }
1856 :
1857 0 : shader_includes_fs.emplace_back(path);
1858 : }
1859 :
1860 1 : static void shader_get_includes_fs()
1861 : {
1862 1 : if(!adding_shader)
1863 : {
1864 1 : return;
1865 : }
1866 :
1867 0 : std::string res;
1868 :
1869 0 : for(const std::string &include : shader_includes_fs)
1870 : {
1871 0 : res += " \"" + include + "\"";
1872 : }
1873 :
1874 0 : result(res.c_str());
1875 0 : }
1876 :
1877 1 : static void shader_source(const char *vs, const char *fs)
1878 : {
1879 1 : if(!adding_shader)
1880 : {
1881 1 : return;
1882 : }
1883 :
1884 0 : shader_path_vs = vs;
1885 0 : shader_path_fs = fs;
1886 : }
1887 :
1888 1 : void variantshader(const int *type, const char *name, const int *row, const char *vs, const char *ps, const int *maxvariants)
1889 : {
1890 1 : if(*row < 0)
1891 : {
1892 0 : shader(type, name, vs, ps);
1893 1 : return;
1894 : }
1895 1 : else if(*row >= maxvariantrows)
1896 : {
1897 0 : return;
1898 : }
1899 1 : Shader *s = lookupshaderbyname(name);
1900 1 : if(!s)
1901 : {
1902 1 : return;
1903 : }
1904 0 : DEF_FORMAT_STRING(varname, "<variant:%d,%d>%s", s->numvariants(*row), *row, name);
1905 0 : if(*maxvariants > 0)
1906 : {
1907 0 : DEF_FORMAT_STRING(info, "shader %s", name);
1908 0 : renderprogress(std::min(s->variants.size() / static_cast<float>(*maxvariants), 1.0f), info);
1909 : }
1910 :
1911 0 : std::string vs_string(vs), ps_string(ps);
1912 :
1913 0 : if(!s->defaultparams.empty())
1914 : {
1915 0 : genuniformdefs(vs_string, ps_string, s);
1916 : }
1917 :
1918 0 : if(vs_string.find("//:fog") != std::string::npos || ps_string.find("//:fog") != std::string::npos)
1919 : {
1920 0 : genfogshader(vs_string, ps_string);
1921 : }
1922 :
1923 0 : const Shader *v = newshader(*type, varname, vs_string.c_str(), ps_string.c_str(), s, *row);
1924 0 : if(v)
1925 : {
1926 0 : if(vs_string.find("//:variant") != std::string::npos || ps_string.find("//:variant") != std::string::npos)
1927 : {
1928 0 : gengenericvariant(*s, varname, vs_string.c_str(), ps_string.c_str(), *row);
1929 : }
1930 : }
1931 0 : }
1932 :
1933 1 : void variantshader_new(const int *type, const char *name, const int *row, const int *maxvariants, const uint *code)
1934 : {
1935 1 : if(*row < 0)
1936 : {
1937 0 : shader_new(type, name, code);
1938 1 : return;
1939 : }
1940 1 : else if(*row >= maxvariantrows)
1941 : {
1942 0 : return;
1943 : }
1944 1 : Shader *s = lookupshaderbyname(name);
1945 1 : if(!s)
1946 : {
1947 1 : return;
1948 : }
1949 :
1950 0 : adding_shader = true;
1951 0 : shader_clear_defines();
1952 :
1953 0 : execute(code);
1954 :
1955 0 : std::string vs, ps;
1956 0 : shader_assemble(vs, ps);
1957 :
1958 0 : DEF_FORMAT_STRING(varname, "<variant:%d,%d>%s", s->numvariants(*row), *row, name);
1959 0 : if(*maxvariants > 0)
1960 : {
1961 0 : DEF_FORMAT_STRING(info, "shader %s", name);
1962 0 : renderprogress(std::min(s->variants.size() / static_cast<float>(*maxvariants), 1.0f), info);
1963 : }
1964 :
1965 0 : if(!s->defaultparams.empty())
1966 : {
1967 0 : genuniformdefs(vs, ps, s);
1968 : }
1969 :
1970 0 : if(vs.find("//:fog") != std::string::npos || ps.find("//:fog") != std::string::npos)
1971 : {
1972 0 : genfogshader(vs, ps);
1973 : }
1974 :
1975 0 : const Shader *v = newshader(*type, varname, vs.c_str(), ps.c_str(), s, *row);
1976 0 : if(v)
1977 : {
1978 0 : if(vs.find("//:variant") != std::string::npos || ps.find("//:variant") != std::string::npos)
1979 : {
1980 0 : gengenericvariant(*s, varname, vs.c_str(), ps.c_str(), *row);
1981 : }
1982 : }
1983 :
1984 0 : adding_shader = false;
1985 0 : }
1986 :
1987 : //==============================================================================
1988 :
1989 :
1990 1 : void setshader(const char *name)
1991 : {
1992 1 : slotparams.clear();
1993 1 : auto itr = shaders.find(name);
1994 1 : if(itr == shaders.end())
1995 : {
1996 0 : conoutf(Console_Error, "no such shader: %s", name);
1997 : }
1998 : else
1999 : {
2000 1 : slotshader = &(*itr).second;
2001 : }
2002 1 : }
2003 :
2004 :
2005 0 : void resetslotshader()
2006 : {
2007 0 : slotshader = nullptr;
2008 0 : slotparams.clear();
2009 0 : }
2010 :
2011 0 : void setslotshader(Slot &s)
2012 : {
2013 0 : s.shader = slotshader;
2014 0 : if(!s.shader)
2015 : {
2016 0 : s.shader = stdworldshader;
2017 0 : return;
2018 : }
2019 0 : for(uint i = 0; i < slotparams.size(); i++)
2020 : {
2021 0 : s.params.push_back(slotparams[i]);
2022 : }
2023 : }
2024 :
2025 0 : static void linkslotshaderparams(std::vector<SlotShaderParam> ¶ms, const Shader &sh, bool load)
2026 : {
2027 0 : if(sh.loaded())
2028 : {
2029 0 : for(SlotShaderParam ¶m : params)
2030 : {
2031 0 : int loc = -1;
2032 0 : for(uint j = 0; j < sh.defaultparams.size(); j++)
2033 : {
2034 0 : const SlotShaderParamState &dparam = sh.defaultparams[j];
2035 0 : if(dparam.name==param.name)
2036 : {
2037 0 : if(std::memcmp(param.val, &dparam.val[0], sizeof(param.val)))
2038 : {
2039 0 : loc = j;
2040 : }
2041 0 : break;
2042 : }
2043 : }
2044 0 : param.loc = loc;
2045 : }
2046 : }
2047 0 : else if(load)
2048 : {
2049 0 : for(uint i = 0; i < params.size(); i++)
2050 : {
2051 0 : params[i].loc = SIZE_MAX;
2052 : }
2053 : }
2054 0 : }
2055 :
2056 0 : void linkslotshader(Slot &s, bool load)
2057 : {
2058 0 : if(!s.shader)
2059 : {
2060 0 : return;
2061 : }
2062 0 : if(load && s.shader->deferred())
2063 : {
2064 0 : s.shader->force();
2065 : }
2066 0 : linkslotshaderparams(s.params, *s.shader, load);
2067 : }
2068 :
2069 0 : void linkvslotshader(VSlot &s, bool load)
2070 : {
2071 0 : if(!s.slot->shader)
2072 : {
2073 0 : return;
2074 : }
2075 0 : linkslotshaderparams(s.params, *(s.slot->shader), load);
2076 0 : if(!s.slot->shader->loaded())
2077 : {
2078 0 : return;
2079 : }
2080 0 : if(s.slot->texmask&(1 << Tex_Glow))
2081 : {
2082 0 : static const char *paramname = getshaderparamname("glowcolor");
2083 0 : const float *param = findslotparam(s, paramname);
2084 0 : if(param)
2085 : {
2086 0 : s.glowcolor = vec(param).clamp(0, 1);
2087 : }
2088 : }
2089 : }
2090 :
2091 0 : bool shouldreuseparams(const Slot &s, const VSlot &p)
2092 : {
2093 0 : if(!s.shader)
2094 : {
2095 0 : return false;
2096 : }
2097 0 : const Shader &sh = *s.shader;
2098 0 : for(const SlotShaderParamState ¶m : sh.defaultparams)
2099 : {
2100 0 : if(param.flags & SlotShaderParam::REUSE)
2101 : {
2102 0 : const float *val = findslotparam(p, param.name.c_str());
2103 0 : if(val && std::memcmp(¶m.val[0], val, param.val.size()))
2104 : {
2105 0 : for(const SlotShaderParam &j : s.params)
2106 : {
2107 0 : if(j.name == param.name)
2108 : {
2109 0 : goto notreused; //bail out of for loop
2110 : }
2111 : }
2112 0 : return true;
2113 0 : notreused:;
2114 : }
2115 : }
2116 : }
2117 0 : return false;
2118 : }
2119 :
2120 :
2121 : static std::unordered_set<std::string> shaderparamnames;
2122 :
2123 2 : const char *getshaderparamname(const char *name, bool insert)
2124 : {
2125 2 : auto itr = shaderparamnames.find(name);
2126 2 : if(itr != shaderparamnames.end() || !insert)
2127 : {
2128 1 : return (*itr).c_str();
2129 : }
2130 1 : return (*shaderparamnames.insert(name).first).c_str();
2131 : }
2132 :
2133 2 : void addslotparam(const char *name, float x, float y, float z, float w, int flags = 0)
2134 : {
2135 2 : if(name)
2136 : {
2137 2 : name = getshaderparamname(name);
2138 : }
2139 2 : for(SlotShaderParam &i : slotparams)
2140 : {
2141 1 : if(i.name==name)
2142 : {
2143 1 : i.val[0] = x;
2144 1 : i.val[1] = y;
2145 1 : i.val[2] = z;
2146 1 : i.val[3] = w;
2147 1 : i.flags |= flags;
2148 1 : return;
2149 : }
2150 : }
2151 1 : SlotShaderParam param = {name, SIZE_MAX, flags, {x, y, z, w}};
2152 1 : slotparams.push_back(param);
2153 : }
2154 :
2155 0 : void cleanupshaders()
2156 : {
2157 0 : cleanuppostfx(true);
2158 :
2159 0 : loadedshaders = false;
2160 0 : nullshader = hudshader = hudnotextureshader = nullptr;
2161 0 : for(auto &[k, s] : shaders)
2162 : {
2163 0 : s.cleanup();
2164 : }
2165 0 : Shader::lastshader = nullptr;
2166 0 : glUseProgram(0);
2167 0 : }
2168 :
2169 0 : void Shader::reusecleanup()
2170 : {
2171 0 : if((reusevs && reusevs->invalid()) ||
2172 0 : (reuseps && reuseps->invalid()) ||
2173 0 : !compile())
2174 : {
2175 0 : cleanup(true);
2176 : }
2177 0 : }
2178 :
2179 0 : void reloadshaders()
2180 : {
2181 0 : identflags &= ~Idf_Persist;
2182 0 : loadshaders();
2183 0 : identflags |= Idf_Persist;
2184 0 : linkslotshaders();
2185 0 : for(auto &[k, s] : shaders)
2186 : {
2187 0 : if(!s.standard && s.loaded() && !s.variantshader)
2188 : {
2189 0 : DEF_FORMAT_STRING(info, "shader %s", s.name);
2190 0 : renderprogress(0.0, info);
2191 0 : if(!s.compile())
2192 : {
2193 0 : s.cleanup(true);
2194 : }
2195 0 : for(Shader *&v : s.variants)
2196 : {
2197 0 : v->reusecleanup();
2198 : }
2199 : }
2200 0 : if(s.forced && s.deferred())
2201 : {
2202 0 : s.force();
2203 : }
2204 : }
2205 0 : }
2206 :
2207 1 : void resetshaders()
2208 : {
2209 1 : if(!glslversion)
2210 : {
2211 1 : conoutf(Console_Error, "Cannot reset GLSL shaders without GLSL initialized, operation not performed");
2212 1 : return;
2213 : }
2214 0 : clearchanges(Change_Shaders);
2215 :
2216 0 : cleanuplights();
2217 0 : cleanupmodels();
2218 0 : cleanupshaders();
2219 0 : setupshaders();
2220 0 : initgbuffer();
2221 0 : reloadshaders();
2222 0 : rootworld.allchanged(true);
2223 0 : glerror();
2224 : }
2225 :
2226 : FVAR(blursigma, 0.005f, 0.5f, 2.0f);
2227 :
2228 : /*
2229 : * radius: sets number of weights & offsets for blurring to be made
2230 : * weights: array of length at least radius + 1
2231 : * offsets: array of length at least radius + 1
2232 : */
2233 0 : void setupblurkernel(int radius, float *weights, float *offsets)
2234 : {
2235 0 : if(radius<1 || radius>maxblurradius)
2236 : {
2237 0 : return;
2238 : }
2239 0 : float sigma = blursigma*2*radius,
2240 0 : total = 1.0f/sigma;
2241 0 : weights[0] = total;
2242 0 : offsets[0] = 0;
2243 : // rely on bilinear filtering to sample 2 pixels at once
2244 : // transforms a*X + b*Y into (u+v)*[X*u/(u+v) + Y*(1 - u/(u+v))]
2245 0 : for(int i = 0; i < radius; ++i)
2246 : {
2247 0 : float weight1 = std::exp(-((2*i)*(2*i)) / (2*sigma*sigma)) / sigma,
2248 0 : weight2 = std::exp(-((2*i+1)*(2*i+1)) / (2*sigma*sigma)) / sigma,
2249 0 : scale = weight1 + weight2,
2250 0 : offset = 2*i+1 + weight2 / scale;
2251 0 : weights[i+1] = scale;
2252 0 : offsets[i+1] = offset;
2253 0 : total += 2*scale;
2254 : }
2255 0 : for(int i = 0; i < radius+1; ++i)
2256 : {
2257 0 : weights[i] /= total;
2258 : }
2259 0 : for(int i = radius+1; i <= maxblurradius; i++)
2260 : {
2261 0 : weights[i] = offsets[i] = 0;
2262 : }
2263 : }
2264 :
2265 0 : void setblurshader(int pass, int size, int radius, const float *weights, const float *offsets, GLenum target)
2266 : {
2267 0 : if(radius<1 || radius>maxblurradius)
2268 : {
2269 0 : return;
2270 : }
2271 : static Shader *blurshader[7][2] = { { nullptr, nullptr }, { nullptr, nullptr }, { nullptr, nullptr }, { nullptr, nullptr }, { nullptr, nullptr }, { nullptr, nullptr }, { nullptr, nullptr } },
2272 : *blurrectshader[7][2] = { { nullptr, nullptr }, { nullptr, nullptr }, { nullptr, nullptr }, { nullptr, nullptr }, { nullptr, nullptr }, { nullptr, nullptr }, { nullptr, nullptr } };
2273 0 : Shader *&s = (target == GL_TEXTURE_RECTANGLE ? blurrectshader : blurshader)[radius-1][pass];
2274 0 : if(!s)
2275 : {
2276 0 : DEF_FORMAT_STRING(name, "blur%c%d%s", 'x'+pass, radius, target == GL_TEXTURE_RECTANGLE ? "rect" : "");
2277 0 : s = lookupshaderbyname(name);
2278 : }
2279 0 : s->set();
2280 0 : LOCALPARAMV(weights, weights, maxblurradius+1);
2281 : std::array<float, maxblurradius+1> scaledoffsets;
2282 0 : for(int k = 0; k < maxblurradius+1; ++k)
2283 : {
2284 0 : scaledoffsets[k] = offsets[k]/size;
2285 : }
2286 0 : LOCALPARAMV(offsets, scaledoffsets.data(), maxblurradius+1);
2287 : }
2288 :
2289 1 : void initshadercmds()
2290 : {
2291 1 : addcommand("defershader", reinterpret_cast<identfun>(defershader), "iss", Id_Command);
2292 1 : addcommand("forceshader", reinterpret_cast<identfun>(useshaderbyname), "s", Id_Command);
2293 1 : addcommand("shader", reinterpret_cast<identfun>(shader), "isss", Id_Command);
2294 1 : addcommand("variantshader", reinterpret_cast<identfun>(variantshader), "isissi", Id_Command);
2295 1 : addcommand("setshader", reinterpret_cast<identfun>(setshader), "s", Id_Command);
2296 2 : addcommand("isshaderdefined", reinterpret_cast<identfun>(+[](const char* name){intret(lookupshaderbyname(name) ? 1 : 0);}), "s", Id_Command);
2297 2 : addcommand("setshaderparam", reinterpret_cast<identfun>(+[](char *name, float *x, float *y, float *z, float *w){addslotparam(name, *x, *y, *z, *w);}), "sfFFf", Id_Command);
2298 2 : addcommand("reuseuniformparam", reinterpret_cast<identfun>(+[](char *name, float *x, float *y, float *z, float *w){addslotparam(name, *x, *y, *z, *w, SlotShaderParam::REUSE);}), "sfFFf", Id_Command);
2299 1 : addcommand("resetshaders", reinterpret_cast<identfun>(resetshaders), "", Id_Command);
2300 :
2301 1 : addcommand("variantshader_new", reinterpret_cast<identfun>(variantshader_new), "isiie", Id_Command);
2302 1 : addcommand("shader_new", reinterpret_cast<identfun>(shader_new), "ise", Id_Command);
2303 1 : addcommand("shader_define", reinterpret_cast<identfun>(shader_define), "ss", Id_Command);
2304 1 : addcommand("shader_source", reinterpret_cast<identfun>(shader_source), "ss", Id_Command);
2305 1 : addcommand("shader_include_vs", reinterpret_cast<identfun>(shader_include_vs), "s", Id_Command);
2306 1 : addcommand("shader_include_fs", reinterpret_cast<identfun>(shader_include_fs), "s", Id_Command);
2307 1 : addcommand("shader_get_defines", reinterpret_cast<identfun>(shader_get_defines), "", Id_Command);
2308 1 : addcommand("shader_get_includes_vs", reinterpret_cast<identfun>(shader_get_includes_vs), "", Id_Command);
2309 1 : addcommand("shader_get_includes_fs", reinterpret_cast<identfun>(shader_get_includes_fs), "", Id_Command);
2310 :
2311 1 : initpostfxcmds();
2312 1 : }
|