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 : static VAR(maxfsuniforms, 1, 0, 0);
48 : static VAR(mintexoffset, 1, 0, 0);
49 : static VAR(maxtexoffset, 1, 0, 0);
50 : static 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(std::string_view name)
82 : {
83 5 : std::unordered_map<std::string, Shader>::iterator itr = shaders.find(name.data());
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(std::string_view name, const char *fmt, ...)
92 : {
93 0 : if(!loadedshaders)
94 : {
95 0 : return nullptr;
96 : }
97 0 : Shader *s = name.size() ? 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.size() ? 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(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 : std::array<const char *, 16> parts;
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(size_t i = 0; i < 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, static_cast<const GLchar **>(parts.data()), 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.data(), 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.data(), 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(size_t 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(size_t j = 0; j < uniformlocs.size(); j++)
464 : {
465 0 : if(uniformlocs[j].loc == loc)
466 : {
467 0 : return;
468 : }
469 : }
470 0 : for(size_t j = 0; j < globalparams.size(); j++)
471 : {
472 0 : if(globalparams[j].loc == loc)
473 : {
474 0 : return;
475 : }
476 : }
477 0 : for(size_t 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 : void GlobalShaderParamState::changed()
556 : {
557 0 : if(++nextversion < 0)
558 : {
559 0 : resetversions();
560 : }
561 0 : version = nextversion;
562 0 : }
563 :
564 0 : static const float *findslotparam(const Slot &s, const char *name, const float *noval = nullptr)
565 : {
566 0 : for(const SlotShaderParam ¶m : s.params)
567 : {
568 0 : if(name == param.name)
569 : {
570 0 : return ¶m.val[0];
571 : }
572 : }
573 0 : for(const SlotShaderParamState ¶m : s.shader->defaultparams)
574 : {
575 0 : if(name == param.name)
576 : {
577 0 : return ¶m.val[0];
578 : }
579 : }
580 0 : return noval;
581 : }
582 :
583 0 : static const float *findslotparam(const VSlot &s, const char *name, const float *noval = nullptr)
584 : {
585 0 : for(const SlotShaderParam ¶m : s.params)
586 : {
587 0 : if(name == param.name)
588 : {
589 0 : return ¶m.val[0];
590 : }
591 : }
592 0 : return findslotparam(*s.slot, name, noval);
593 : }
594 :
595 0 : static void setslotparam(const SlotShaderParamState &l, const float *val)
596 : {
597 0 : switch(l.format)
598 : {
599 0 : case GL_BOOL:
600 : case GL_FLOAT:
601 : {
602 0 : glUniform1fv(l.loc, 1, val);
603 0 : break;
604 : }
605 0 : case GL_BOOL_VEC2:
606 : case GL_FLOAT_VEC2:
607 : {
608 0 : glUniform2fv(l.loc, 1, val);
609 0 : break;
610 : }
611 0 : case GL_BOOL_VEC3:
612 : case GL_FLOAT_VEC3:
613 : {
614 0 : glUniform3fv(l.loc, 1, val);
615 0 : break;
616 : }
617 0 : case GL_BOOL_VEC4:
618 : case GL_FLOAT_VEC4:
619 : {
620 0 : glUniform4fv(l.loc, 1, val);
621 0 : break;
622 : }
623 0 : case GL_INT:
624 : {
625 0 : glUniform1i(l.loc, static_cast<int>(val[0]));
626 0 : break;
627 : }
628 0 : case GL_INT_VEC2:
629 : {
630 0 : glUniform2i(l.loc, static_cast<int>(val[0]), static_cast<int>(val[1]));
631 0 : break;
632 : }
633 0 : case GL_INT_VEC3:
634 : {
635 0 : glUniform3i(l.loc, static_cast<int>(val[0]), static_cast<int>(val[1]), static_cast<int>(val[2]));
636 0 : break;
637 : }
638 0 : case GL_INT_VEC4:
639 : {
640 0 : glUniform4i(l.loc, static_cast<int>(val[0]), static_cast<int>(val[1]), static_cast<int>(val[2]), static_cast<int>(val[3]));
641 0 : break;
642 : }
643 0 : case GL_UNSIGNED_INT:
644 : {
645 0 : glUniform1ui(l.loc, static_cast<uint>(val[0]));
646 0 : break;
647 : }
648 0 : case GL_UNSIGNED_INT_VEC2:
649 : {
650 0 : glUniform2ui(l.loc, static_cast<uint>(val[0]), static_cast<uint>(val[1]));
651 0 : break;
652 : }
653 0 : case GL_UNSIGNED_INT_VEC3:
654 : {
655 0 : glUniform3ui(l.loc, static_cast<uint>(val[0]), static_cast<uint>(val[1]), static_cast<uint>(val[2]));
656 0 : break;
657 : }
658 0 : case GL_UNSIGNED_INT_VEC4:
659 : {
660 0 : glUniform4ui(l.loc, static_cast<uint>(val[0]), static_cast<uint>(val[1]), static_cast<uint>(val[2]), static_cast<uint>(val[3]));
661 0 : break;
662 : }
663 : }
664 0 : }
665 :
666 0 : static void setslotparam(const SlotShaderParamState& l, uint& mask, uint i, const float* val)
667 : {
668 0 : if(!(mask&(1<<i)))
669 : {
670 0 : mask |= 1<<i;
671 0 : setslotparam(l, val);
672 : }
673 0 : }
674 :
675 0 : static void setslotparams(uint& unimask, const std::vector<SlotShaderParamState>& defaultparams)
676 : {
677 0 : for(const SlotShaderParam &p : slotparams)
678 : {
679 0 : if(!(defaultparams.size() > p.loc))
680 : {
681 0 : continue;
682 : }
683 0 : const SlotShaderParamState &l = defaultparams.at(p.loc);
684 0 : setslotparam(l, unimask, p.loc, p.val);
685 : }
686 0 : }
687 :
688 0 : static void setdefaultparams(const std::vector<SlotShaderParamState>& defaultparams, uint& unimask)
689 : {
690 0 : for(size_t i = 0; i < defaultparams.size(); i++)
691 : {
692 0 : const SlotShaderParamState &l = defaultparams.at(i);
693 0 : setslotparam(l, unimask, i, &l.val[0]);
694 : }
695 0 : }
696 :
697 : //shader
698 :
699 2 : 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)
700 : {
701 2 : }
702 :
703 4 : Shader::~Shader()
704 : {
705 4 : delete[] name;
706 4 : delete[] vsstr;
707 4 : delete[] psstr;
708 4 : delete[] defer;
709 4 : delete[] variantrows;
710 4 : }
711 :
712 0 : void Shader::flushparams()
713 : {
714 0 : if(!used)
715 : {
716 0 : allocglslactiveuniforms();
717 0 : used = true;
718 : }
719 0 : for(GlobalShaderParamUse &i : globalparams)
720 : {
721 0 : i.flush();
722 : }
723 0 : }
724 :
725 0 : bool Shader::invalid() const
726 : {
727 0 : return (type & Shader_Invalid) != 0;
728 : }
729 0 : bool Shader::deferred() const
730 : {
731 0 : return (type & Shader_Deferred) != 0;
732 : }
733 5 : bool Shader::loaded() const
734 : {
735 5 : return !(type&(Shader_Deferred | Shader_Invalid));
736 : }
737 :
738 0 : bool Shader::isdynamic() const
739 : {
740 0 : return (type & Shader_Dynamic) != 0;
741 : }
742 :
743 0 : int Shader::numvariants(int row) const
744 : {
745 0 : if(row < 0 || row >= maxvariantrows || !variantrows)
746 : {
747 0 : return 0;
748 : }
749 0 : return variantrows[row+1] - variantrows[row];
750 : }
751 :
752 0 : const Shader *Shader::getvariant(int col, int row) const
753 : {
754 0 : if(row < 0 || row >= maxvariantrows || col < 0 || !variantrows)
755 : {
756 0 : return nullptr;
757 : }
758 0 : int start = variantrows[row],
759 0 : end = variantrows[row+1];
760 0 : return col < end - start ? variants[start + col] : nullptr;
761 : }
762 :
763 0 : void Shader::addvariant(int row, Shader *s)
764 : {
765 0 : if(row < 0 || row >= maxvariantrows || variants.size() >= USHRT_MAX)
766 : {
767 0 : return;
768 : }
769 0 : if(!variantrows)
770 : {
771 0 : variantrows = new ushort[maxvariantrows+1];
772 0 : std::memset(variantrows, 0, (maxvariantrows+1)*sizeof(ushort));
773 : }
774 0 : variants.insert(variants.begin() + variantrows[row+1], s);
775 0 : for(int i = row+1; i <= maxvariantrows; ++i)
776 : {
777 0 : ++variantrows[i];
778 : }
779 : }
780 :
781 0 : void Shader::setvariant_(int col, int row)
782 : {
783 0 : Shader *s = this;
784 0 : if(variantrows)
785 : {
786 0 : int start = variantrows[row],
787 0 : end = variantrows[row+1];
788 0 : for(col = std::min(start + col, end-1); col >= start; --col)
789 : {
790 0 : if(!variants[col]->invalid())
791 : {
792 0 : s = variants[col];
793 0 : break;
794 : }
795 : }
796 : }
797 0 : if(lastshader!=s)
798 : {
799 0 : s->bindprograms();
800 : }
801 0 : }
802 :
803 0 : void Shader::setvariant(int col, int row)
804 : {
805 0 : if(!loaded())
806 : {
807 0 : return;
808 : }
809 0 : setvariant_(col, row);
810 0 : lastshader->flushparams();
811 : }
812 :
813 0 : void Shader::setvariantandslot(int col, int row)
814 : {
815 0 : if(!loaded())
816 : {
817 0 : return;
818 : }
819 0 : setvariant_(col, row);
820 0 : lastshader->flushparams();
821 0 : lastshader->setslotparams();
822 : }
823 :
824 0 : void Shader::setvariant(int col, int row, const Slot &slot, const VSlot &vslot)
825 : {
826 0 : if(!loaded())
827 : {
828 0 : return;
829 : }
830 0 : setvariant_(col, row);
831 0 : lastshader->flushparams();
832 0 : lastshader->setslotparams(slot, vslot);
833 : }
834 :
835 0 : void Shader::set_()
836 : {
837 0 : if(lastshader!=this)
838 : {
839 0 : bindprograms();
840 : }
841 0 : }
842 :
843 0 : void Shader::set()
844 : {
845 0 : if(!loaded())
846 : {
847 0 : return;
848 : }
849 0 : set_();
850 0 : lastshader->flushparams();
851 : }
852 :
853 0 : void Shader::setslot()
854 : {
855 0 : if(!loaded())
856 : {
857 0 : return;
858 : }
859 0 : set_();
860 0 : lastshader->flushparams();
861 0 : lastshader->setslotparams();
862 : }
863 :
864 0 : void Shader::set(const Slot &slot, const VSlot &vslot)
865 : {
866 0 : if(!loaded())
867 : {
868 0 : return;
869 : }
870 0 : set_();
871 0 : lastshader->flushparams();
872 0 : lastshader->setslotparams(slot, vslot);
873 : }
874 :
875 0 : void Shader::setslotparams()
876 : {
877 0 : uint unimask = 0;
878 0 : ::setslotparams(unimask, defaultparams);
879 0 : setdefaultparams(defaultparams, unimask);
880 0 : }
881 :
882 0 : void Shader::setslotparams(const Slot &slot, const VSlot &vslot)
883 : {
884 : static bool thrown = false; //only throw error message once (will spam per frame otherwise)
885 0 : uint unimask = 0;
886 0 : if(vslot.slot == &slot)
887 : {
888 0 : ::setslotparams(unimask, defaultparams);
889 0 : for(size_t i = 0; i < slot.params.size(); i++)
890 : {
891 0 : const SlotShaderParam &p = slot.params.at(i);
892 0 : if(!(defaultparams.size() > p.loc))
893 : {
894 0 : continue;
895 : }
896 0 : if(p.loc == SIZE_MAX)
897 : {
898 0 : if(!thrown)
899 : {
900 0 : std::printf("Invalid slot shader param index: some slot shaders may not be in use\n");
901 0 : thrown = true;
902 : }
903 : }
904 0 : else if(!(unimask&(1<<p.loc)))
905 : {
906 0 : const SlotShaderParamState &l = defaultparams.at(p.loc);
907 0 : unimask |= 1<<p.loc;
908 0 : setslotparam(l, p.val);
909 : }
910 : }
911 0 : setdefaultparams(defaultparams, unimask);
912 : }
913 : else
914 : {
915 0 : ::setslotparams(unimask, defaultparams);
916 0 : for(size_t i = 0; i < defaultparams.size(); i++)
917 : {
918 0 : const SlotShaderParamState &l = defaultparams.at(i);
919 0 : setslotparam(l, unimask, i, l.flags&SlotShaderParam::REUSE ? findslotparam(vslot, l.name.c_str(), &l.val[0]) : &l.val[0]);
920 : }
921 : }
922 0 : }
923 :
924 0 : void Shader::bindprograms()
925 : {
926 0 : if(this == lastshader || !loaded())
927 : {
928 0 : return;
929 : }
930 0 : glUseProgram(program);
931 0 : lastshader = this;
932 : }
933 :
934 2 : bool Shader::compile()
935 : {
936 2 : if(!vsstr)
937 : {
938 0 : vsobj = !reusevs || reusevs->invalid() ? 0 : reusevs->vsobj;
939 : }
940 : else
941 : {
942 2 : compileglslshader(GL_VERTEX_SHADER, vsobj, vsstr, name, debugshader || !variantshader);
943 : }
944 2 : if(!psstr)
945 : {
946 0 : psobj = !reuseps || reuseps->invalid() ? 0 : reuseps->psobj;
947 : }
948 : else
949 : {
950 2 : compileglslshader(GL_FRAGMENT_SHADER, psobj, psstr, name, debugshader || !variantshader);
951 : }
952 2 : linkglslprogram(!variantshader);
953 2 : return program!=0;
954 : }
955 :
956 2 : void Shader::cleanup(bool full)
957 : {
958 2 : used = false;
959 2 : if(vsobj)
960 : {
961 0 : if(!reusevs)
962 : {
963 0 : glDeleteShader(vsobj); vsobj = 0;
964 : }
965 : }
966 2 : if(psobj)
967 : {
968 0 : if(!reuseps)
969 : {
970 0 : glDeleteShader(psobj);
971 0 : psobj = 0;
972 : }
973 : }
974 2 : if(program)
975 : {
976 0 : glDeleteProgram(program);
977 0 : program = 0;
978 : }
979 2 : localparams.clear();
980 2 : localparamremap.clear();
981 2 : globalparams.clear();
982 2 : if(standard || full)
983 : {
984 2 : type = Shader_Invalid;
985 :
986 2 : delete[] vsstr;
987 2 : delete[] psstr;
988 2 : delete[] defer;
989 :
990 2 : vsstr = nullptr;
991 2 : psstr = nullptr;
992 2 : defer = nullptr;
993 :
994 2 : variants.clear();
995 :
996 2 : delete[] variantrows;
997 2 : variantrows = nullptr;
998 :
999 2 : defaultparams.clear();
1000 2 : attriblocs.clear();
1001 2 : uniformlocs.clear();
1002 2 : reusevs = reuseps = nullptr;
1003 : }
1004 : else
1005 : {
1006 0 : for(SlotShaderParamState &i : defaultparams)
1007 : {
1008 0 : i.loc = -1;
1009 : }
1010 : }
1011 2 : }
1012 : //ShaderParamBinding
1013 :
1014 1 : ShaderParamBinding::ShaderParamBinding(GLint loc, GLsizei size, GLenum format) :
1015 1 : loc(loc), size(size), format(format)
1016 : {
1017 1 : }
1018 :
1019 : // globalshaderparamuse
1020 :
1021 0 : GlobalShaderParamUse::GlobalShaderParamUse(GLint loc, GLsizei size, GLenum format, const GlobalShaderParamState *param, int version) :
1022 0 : ShaderParamBinding(loc, size, format), param(param), version(version)
1023 : {
1024 0 : }
1025 :
1026 0 : void GlobalShaderParamUse::flush()
1027 : {
1028 0 : if(version == param->version)
1029 : {
1030 0 : return;
1031 : }
1032 0 : switch(format)
1033 : {
1034 0 : case GL_BOOL:
1035 : case GL_FLOAT:
1036 : {
1037 0 : glUniform1fv(loc, size, param->fval.data());
1038 0 : break;
1039 : }
1040 0 : case GL_BOOL_VEC2:
1041 : case GL_FLOAT_VEC2:
1042 : {
1043 0 : glUniform2fv(loc, size, param->fval.data());
1044 0 : break;
1045 : }
1046 0 : case GL_BOOL_VEC3:
1047 : case GL_FLOAT_VEC3:
1048 : {
1049 0 : glUniform3fv(loc, size, param->fval.data());
1050 0 : break;
1051 : }
1052 0 : case GL_BOOL_VEC4:
1053 : case GL_FLOAT_VEC4:
1054 : {
1055 0 : glUniform4fv(loc, size, param->fval.data());
1056 0 : break;
1057 : }
1058 0 : case GL_INT:
1059 : {
1060 0 : glUniform1iv(loc, size, param->ival.data());
1061 0 : break;
1062 : }
1063 0 : case GL_INT_VEC2:
1064 : {
1065 0 : glUniform2iv(loc, size, param->ival.data());
1066 0 : break;
1067 : }
1068 0 : case GL_INT_VEC3:
1069 : {
1070 0 : glUniform3iv(loc, size, param->ival.data());
1071 0 : break;
1072 : }
1073 0 : case GL_INT_VEC4:
1074 : {
1075 0 : glUniform4iv(loc, size, param->ival.data());
1076 0 : break;
1077 : }
1078 0 : case GL_UNSIGNED_INT:
1079 : {
1080 0 : glUniform1uiv(loc, size, param->uval.data());
1081 0 : break;
1082 : }
1083 0 : case GL_UNSIGNED_INT_VEC2:
1084 : {
1085 0 : glUniform2uiv(loc, size, param->uval.data());
1086 0 : break;
1087 : }
1088 0 : case GL_UNSIGNED_INT_VEC3:
1089 : {
1090 0 : glUniform3uiv(loc, size, param->uval.data());
1091 0 : break;
1092 : }
1093 0 : case GL_UNSIGNED_INT_VEC4:
1094 : {
1095 0 : glUniform4uiv(loc, size, param->uval.data());
1096 0 : break;
1097 : }
1098 0 : case GL_FLOAT_MAT2:
1099 : {
1100 0 : glUniformMatrix2fv(loc, 1, GL_FALSE, param->fval.data());
1101 0 : break;
1102 : }
1103 0 : case GL_FLOAT_MAT3:
1104 : {
1105 0 : glUniformMatrix3fv(loc, 1, GL_FALSE, param->fval.data());
1106 0 : break;
1107 : }
1108 0 : case GL_FLOAT_MAT4:
1109 : {
1110 0 : glUniformMatrix4fv(loc, 1, GL_FALSE, param->fval.data());
1111 0 : break;
1112 : }
1113 : }
1114 0 : version = param->version;
1115 : }
1116 :
1117 : //localshaderparamstate
1118 :
1119 1 : LocalShaderParamState::LocalShaderParamState(GLint loc, GLsizei size, GLenum format) :
1120 1 : ShaderParamBinding(loc, size, format)
1121 : {
1122 1 : }
1123 :
1124 :
1125 2 : void Shader::genattriblocs(const char *vs, const Shader *reusevs)
1126 : {
1127 : static int len = std::strlen("//:attrib");
1128 : string name;
1129 : int loc;
1130 2 : if(reusevs)
1131 : {
1132 0 : attriblocs = reusevs->attriblocs;
1133 : }
1134 : else
1135 : {
1136 2 : while((vs = std::strstr(vs, "//:attrib")))
1137 : {
1138 0 : if(std::sscanf(vs, "//:attrib %100s %d", name, &loc) == 2)
1139 : {
1140 0 : attriblocs.emplace_back(Shader::AttribLoc(getshaderparamname(name), loc));
1141 : }
1142 0 : vs += len;
1143 : }
1144 : }
1145 2 : }
1146 :
1147 : // adds to uniformlocs vector defined uniformlocs
1148 2 : void Shader::genuniformlocs(const char *vs, const Shader *reusevs)
1149 : {
1150 : static int len = std::strlen("//:uniform");
1151 : string name, blockname;
1152 : int binding, stride;
1153 2 : if(reusevs)
1154 : {
1155 0 : uniformlocs = reusevs->uniformlocs;
1156 : }
1157 : else
1158 : {
1159 2 : while((vs = std::strstr(vs, "//:uniform")))
1160 : {
1161 0 : int numargs = std::sscanf(vs, "//:uniform %100s %100s %d %d", name, blockname, &binding, &stride);
1162 0 : if(numargs >= 3)
1163 : {
1164 0 : uniformlocs.emplace_back(UniformLoc(getshaderparamname(name), getshaderparamname(blockname), binding, numargs >= 4 ? stride : 0));
1165 : }
1166 0 : else if(numargs >= 1)
1167 : {
1168 0 : uniformlocs.emplace_back(UniformLoc(getshaderparamname(name)));
1169 : }
1170 0 : vs += len;
1171 : }
1172 : }
1173 2 : }
1174 :
1175 2 : static Shader *newshader(int type, std::string_view name, std::string_view vs, std::string_view ps, Shader *variant = nullptr, int row = 0)
1176 : {
1177 2 : if(Shader::lastshader)
1178 : {
1179 0 : glUseProgram(0);
1180 0 : Shader::lastshader = nullptr;
1181 : }
1182 2 : std::unordered_map<std::string, Shader>::iterator itr = shaders.find(name.data());
1183 2 : Shader *exists = (itr != shaders.end()) ? &(*itr).second : nullptr;
1184 2 : char *rname = exists ? exists->name : newstring(name.data());
1185 2 : if(!exists)
1186 : {
1187 0 : itr = shaders.insert( { rname, Shader() } ).first;
1188 : }
1189 2 : Shader *retval = (*itr).second.setupshader(type, rname, ps.data(), vs.data(), variant, row);
1190 2 : return retval; //can be nullptr or s
1191 : }
1192 :
1193 2 : Shader *Shader::setupshader(int newtype, char *rname, const char *ps, const char *vs, Shader *variant, int row)
1194 : {
1195 2 : name = rname;
1196 2 : vsstr = newstring(vs);
1197 2 : psstr = newstring(ps);
1198 :
1199 2 : delete[] defer;
1200 2 : defer = nullptr;
1201 :
1202 2 : type = newtype & ~(Shader_Invalid | Shader_Deferred);
1203 2 : variantshader = variant;
1204 2 : standard = standardshaders;
1205 2 : if(forceshaders)
1206 : {
1207 2 : forced = true;
1208 : }
1209 2 : reusevs = reuseps = nullptr;
1210 2 : if(variant)
1211 : {
1212 0 : int row = 0,
1213 0 : col = 0;
1214 0 : if(!vs[0] || std::sscanf(vs, "%d , %d", &row, &col) >= 1)
1215 : {
1216 0 : delete[] vsstr;
1217 0 : vsstr = nullptr;
1218 0 : reusevs = !vs[0] ? variant : variant->getvariant(col, row);
1219 : }
1220 0 : row = col = 0;
1221 0 : if(!ps[0] || std::sscanf(ps, "%d , %d", &row, &col) >= 1)
1222 : {
1223 0 : delete[] psstr;
1224 0 : psstr = nullptr;
1225 0 : reuseps = !ps[0] ? variant : variant->getvariant(col, row);
1226 : }
1227 : }
1228 2 : if(variant)
1229 : {
1230 0 : for(size_t i = 0; i < variant->defaultparams.size(); i++)
1231 : {
1232 0 : defaultparams.emplace_back(variant->defaultparams[i]);
1233 : }
1234 : }
1235 : else
1236 : {
1237 3 : for(size_t i = 0; i < slotparams.size(); i++)
1238 : {
1239 1 : defaultparams.emplace_back(slotparams[i]);
1240 : }
1241 : }
1242 2 : attriblocs.clear();
1243 2 : uniformlocs.clear();
1244 2 : genattriblocs(vs, reusevs);
1245 2 : genuniformlocs(vs, reusevs);
1246 2 : if(!compile())
1247 : {
1248 2 : cleanup(true);
1249 2 : if(variant)
1250 : {
1251 0 : shaders.erase(rname);
1252 : }
1253 2 : return nullptr;
1254 : }
1255 0 : if(variant)
1256 : {
1257 0 : variant->addvariant(row, this);
1258 : }
1259 0 : return this;
1260 : }
1261 :
1262 : /**
1263 : * @brief Returns the location of the start of the line containing "main"
1264 : *
1265 : * Returns std::string::npos if no `main` is defined for the glsl code passed.
1266 : *
1267 : * Returns the beginning of the `main` call and all following lines until the closing '}'
1268 : *
1269 : * @param s the string to parse
1270 : *
1271 : * @return std::string::npos if no main() found, or the index preceeding 'main'
1272 : */
1273 2 : static size_t findglslmain(const std::string &s)
1274 : {
1275 2 : size_t main = s.find("main");
1276 2 : if(main == std::string::npos)
1277 : {
1278 2 : return std::string::npos;
1279 : }
1280 0 : for(;main != static_cast<size_t>(-1); main--) //note reverse iteration
1281 : {
1282 0 : switch(s[main])
1283 : {
1284 0 : case '\r':
1285 : case '\n':
1286 : case ';':
1287 : {
1288 0 : return main + 1;
1289 : }
1290 : }
1291 : }
1292 0 : return 0;
1293 : }
1294 :
1295 0 : static void gengenericvariant(Shader &s, const char *sname, const char *vs, const char *ps, int row = 0)
1296 : {
1297 0 : int rowoffset = 0;
1298 0 : bool vschanged = false,
1299 0 : pschanged = false;
1300 0 : std::vector<char> vsv, psv;
1301 0 : for(size_t i = 0; i < std::strlen(vs)+1; ++i)
1302 : {
1303 0 : vsv.push_back(vs[i]);
1304 : }
1305 0 : for(size_t i = 0; i < std::strlen(ps)+1; ++i)
1306 : {
1307 0 : psv.push_back(ps[i]);
1308 : }
1309 :
1310 : //cannot be constexpr-- strlen is not compile time
1311 : static const int len = std::strlen("//:variant"),
1312 : olen = std::strlen("override");
1313 0 : for(char *vspragma = vsv.data();; vschanged = true)
1314 : {
1315 0 : vspragma = std::strstr(vspragma, "//:variant");
1316 0 : if(!vspragma)
1317 : {
1318 0 : break;
1319 : }
1320 0 : if(std::sscanf(vspragma + len, "row %d", &rowoffset) == 1)
1321 : {
1322 0 : continue;
1323 : }
1324 0 : std::memset(vspragma, ' ', len);
1325 0 : vspragma += len;
1326 0 : if(!std::strncmp(vspragma, "override", olen))
1327 : {
1328 0 : std::memset(vspragma, ' ', olen);
1329 0 : vspragma += olen;
1330 0 : char *end = vspragma + std::strcspn(vspragma, "\n\r");
1331 0 : end += std::strspn(end, "\n\r");
1332 0 : int endlen = std::strcspn(end, "\n\r");
1333 0 : std::memset(end, ' ', endlen);
1334 : }
1335 0 : }
1336 0 : for(char *pspragma = psv.data();; pschanged = true)
1337 : {
1338 0 : pspragma = std::strstr(pspragma, "//:variant");
1339 0 : if(!pspragma)
1340 : {
1341 0 : break;
1342 : }
1343 0 : if(std::sscanf(pspragma + len, "row %d", &rowoffset) == 1)
1344 : {
1345 0 : continue;
1346 : }
1347 0 : std::memset(pspragma, ' ', len);
1348 0 : pspragma += len;
1349 0 : if(!std::strncmp(pspragma, "override", olen))
1350 : {
1351 0 : std::memset(pspragma, ' ', olen);
1352 0 : pspragma += olen;
1353 0 : char *end = pspragma + std::strcspn(pspragma, "\n\r");
1354 0 : end += std::strspn(end, "\n\r");
1355 0 : int endlen = std::strcspn(end, "\n\r");
1356 0 : std::memset(end, ' ', endlen);
1357 : }
1358 0 : }
1359 0 : row += rowoffset;
1360 0 : if(row < 0 || row >= maxvariantrows)
1361 : {
1362 0 : return;
1363 : }
1364 0 : int col = s.numvariants(row);
1365 0 : DEF_FORMAT_STRING(varname, "<variant:%d,%d>%s", col, row, sname);
1366 : string reuse;
1367 0 : if(col)
1368 : {
1369 0 : formatstring(reuse, "%d", row);
1370 : }
1371 : else
1372 : {
1373 0 : copystring(reuse, "");
1374 : }
1375 0 : newshader(s.type, varname, vschanged ? vsv.data() : reuse, pschanged ? psv.data() : reuse, &s, row);
1376 0 : }
1377 :
1378 0 : static void genfogshader(std::string &vs, std::string &ps)
1379 : {
1380 : //unused PRAGMA_LEN
1381 : //constexpr int PRAGMA_LEN = std::string_view("//:fog").size() + 1;
1382 :
1383 0 : size_t vspragma = vs.find("//:fog"),
1384 0 : pspragma = ps.find("//:fog");
1385 :
1386 0 : if(vspragma == std::string::npos && pspragma == std::string::npos)
1387 : {
1388 0 : return;
1389 : }
1390 :
1391 0 : size_t vsmain = findglslmain(vs),
1392 0 : vsend = vs.rfind('}');
1393 :
1394 0 : if(vsmain != std::string::npos && vsend != std::string::npos)
1395 : {
1396 0 : if(vs.find("lineardepth") == std::string::npos)
1397 : {
1398 0 : constexpr std::string_view FOG_PARAMS = "\nuniform vec2 lineardepthscale;\nvarying float lineardepth;\n";
1399 0 : constexpr std::string_view VS_FOG = "\nlineardepth = dot(lineardepthscale, gl_Position.zw);\n";
1400 :
1401 0 : vs.insert(vsend, VS_FOG);
1402 0 : vs.insert(vsmain, FOG_PARAMS);
1403 : }
1404 : }
1405 :
1406 0 : size_t psmain = findglslmain(ps),
1407 0 : psend = ps.rfind('}');
1408 :
1409 0 : if(psmain != std::string::npos && psend != std::string::npos)
1410 : {
1411 0 : std::string params;
1412 :
1413 0 : if(ps.find("lineardepth") == std::string::npos)
1414 : {
1415 0 : params = "\nvarying float lineardepth;\n";
1416 : }
1417 :
1418 : std::string fogparams =
1419 : "\nuniform vec3 fogcolor;\n"
1420 : "uniform vec2 fogdensity;\n"
1421 : "uniform vec4 radialfogscale;\n"
1422 0 : "#define fogcoord lineardepth*length(vec3(gl_FragCoord.xy*radialfogscale.xy + radialfogscale.zw, 1.0))\n";
1423 :
1424 0 : params += fogparams;
1425 :
1426 0 : std::string psfog = "\nfragcolor.rgb = mix((fogcolor).rgb, fragcolor.rgb, clamp(exp2(fogcoord*-fogdensity.x)*fogdensity.y, 0.0, 1.0));\n";
1427 0 : ps.insert(psend, psfog);
1428 0 : ps.insert(psmain, params);
1429 0 : }
1430 : }
1431 :
1432 1 : static void genuniformdefs(std::string &vs, std::string &ps, const Shader *variant = nullptr)
1433 : {
1434 1 : if(variant ? variant->defaultparams.empty() : slotparams.empty())
1435 : {
1436 1 : return;
1437 : }
1438 :
1439 1 : size_t vsmain = findglslmain(vs),
1440 1 : psmain = findglslmain(ps);
1441 :
1442 1 : if(vsmain == std::string::npos || psmain == std::string::npos)
1443 : {
1444 1 : return;
1445 : }
1446 :
1447 0 : std::string params;
1448 0 : if(variant)
1449 : {
1450 0 : for(const auto ¶m : variant->defaultparams)
1451 : {
1452 0 : DEF_FORMAT_STRING(uni, "\nuniform vec4 %s;\n", param.name.c_str());
1453 0 : params += uni;
1454 : }
1455 : }
1456 : else
1457 : {
1458 0 : for(const auto ¶m : slotparams)
1459 : {
1460 0 : DEF_FORMAT_STRING(uni, "\nuniform vec4 %s;\n", param.name);
1461 0 : params += uni;
1462 : }
1463 : }
1464 :
1465 0 : vs.insert(vsmain, params);
1466 0 : ps.insert(psmain, params);
1467 0 : }
1468 :
1469 0 : void setupshaders()
1470 : {
1471 0 : if(!glslversion)
1472 : {
1473 0 : conoutf(Console_Error, "Cannot setup GLSL shaders without GLSL initialized, operation not performed");
1474 0 : return;
1475 : }
1476 : GLint val;
1477 0 : glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &val);
1478 0 : maxvsuniforms = val/4;
1479 0 : glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &val);
1480 0 : maxfsuniforms = val/4;
1481 :
1482 0 : glGetIntegerv(GL_MIN_PROGRAM_TEXEL_OFFSET, &val);
1483 0 : mintexoffset = val;
1484 0 : glGetIntegerv(GL_MAX_PROGRAM_TEXEL_OFFSET, &val);
1485 0 : maxtexoffset = val;
1486 :
1487 0 : standardshaders = true;
1488 0 : nullshader = newshader(0, "<init>null",
1489 : "attribute vec4 vvertex;\n"
1490 : "void main(void) {\n"
1491 : " gl_Position = vvertex;\n"
1492 : "}\n",
1493 : "fragdata(0) vec4 fragcolor;\n"
1494 : "void main(void) {\n"
1495 : " fragcolor = vec4(1.0, 0.0, 1.0, 1.0);\n"
1496 : "}\n");
1497 0 : hudshader = newshader(0, "<init>hud",
1498 : "attribute vec4 vvertex, vcolor;\n"
1499 : "attribute vec2 vtexcoord0;\n"
1500 : "uniform mat4 hudmatrix;\n"
1501 : "varying vec2 texcoord0;\n"
1502 : "varying vec4 colorscale;\n"
1503 : "void main(void) {\n"
1504 : " gl_Position = hudmatrix * vvertex;\n"
1505 : " texcoord0 = vtexcoord0;\n"
1506 : " colorscale = vcolor;\n"
1507 : "}\n",
1508 : "uniform sampler2D tex0;\n"
1509 : "varying vec2 texcoord0;\n"
1510 : "varying vec4 colorscale;\n"
1511 : "fragdata(0) vec4 fragcolor;\n"
1512 : "void main(void) {\n"
1513 : " vec4 color = texture2D(tex0, texcoord0);\n"
1514 : " fragcolor = colorscale * color;\n"
1515 : "}\n");
1516 0 : hudtextshader = newshader(0, "<init>hudtext",
1517 : "attribute vec4 vvertex, vcolor;\n"
1518 : "attribute vec2 vtexcoord0;\n"
1519 : "uniform mat4 hudmatrix;\n"
1520 : "varying vec2 texcoord0;\n"
1521 : "varying vec4 colorscale;\n"
1522 : "void main(void) {\n"
1523 : " gl_Position = hudmatrix * vvertex;\n"
1524 : " texcoord0 = vtexcoord0;\n"
1525 : " colorscale = vcolor;\n"
1526 : "}\n",
1527 : "uniform sampler2D tex0;\n"
1528 : "uniform vec4 textparams;\n"
1529 : "varying vec2 texcoord0;\n"
1530 : "varying vec4 colorscale;\n"
1531 : "fragdata(0) vec4 fragcolor;\n"
1532 : "void main(void) {\n"
1533 : " float dist = texture2D(tex0, texcoord0).r;\n"
1534 : " float border = smoothstep(textparams.x, textparams.y, dist);\n"
1535 : " float outline = smoothstep(textparams.z, textparams.w, dist);\n"
1536 : " fragcolor = vec4(colorscale.rgb * outline, colorscale.a * border);\n"
1537 : "}\n");
1538 0 : hudnotextureshader = newshader(0, "<init>hudnotexture",
1539 : "attribute vec4 vvertex, vcolor;\n"
1540 : "uniform mat4 hudmatrix;"
1541 : "varying vec4 color;\n"
1542 : "void main(void) {\n"
1543 : " gl_Position = hudmatrix * vvertex;\n"
1544 : " color = vcolor;\n"
1545 : "}\n",
1546 : "varying vec4 color;\n"
1547 : "fragdata(0) vec4 fragcolor;\n"
1548 : "void main(void) {\n"
1549 : " fragcolor = color;\n"
1550 : "}\n");
1551 0 : standardshaders = false;
1552 0 : if(!nullshader || !hudshader || !hudtextshader || !hudnotextureshader)
1553 : {
1554 0 : fatal("failed to setup shaders");
1555 : }
1556 0 : dummyslot.shader = nullshader;
1557 : }
1558 :
1559 : static VAR(defershaders, 0, 1, 1);
1560 :
1561 1 : static void defershader(const int *type, const char *name, const char *contents)
1562 : {
1563 1 : std::unordered_map<std::string, Shader>::iterator itr = shaders.find(name);
1564 1 : const Shader *exists = (itr != shaders.end()) ? &(*itr).second : nullptr;
1565 1 : if(exists && !exists->invalid())
1566 : {
1567 0 : return;
1568 : }
1569 1 : if(!defershaders)
1570 : {
1571 0 : execute(contents);
1572 0 : return;
1573 : }
1574 1 : char *rname = exists ? exists->name : newstring(name);
1575 1 : if(!exists)
1576 : {
1577 1 : itr = shaders.insert( { rname, Shader() } ).first;
1578 : }
1579 1 : Shader &s = (*itr).second;
1580 1 : s.name = rname;
1581 1 : delete[] s.defer;
1582 1 : s.defer = newstring(contents);
1583 1 : s.type = Shader_Deferred | (*type & ~Shader_Invalid);
1584 1 : s.standard = standardshaders;
1585 : }
1586 :
1587 :
1588 0 : void Shader::force()
1589 : {
1590 0 : if(!deferred() || !defer)
1591 : {
1592 0 : return;
1593 : }
1594 0 : char *cmd = defer;
1595 0 : defer = nullptr;
1596 0 : bool wasstandard = standardshaders,
1597 0 : wasforcing = forceshaders;
1598 0 : int oldflags = identflags;
1599 0 : standardshaders = standard;
1600 0 : forceshaders = false;
1601 0 : identflags &= ~Idf_Persist;
1602 0 : slotparams.clear();
1603 0 : execute(cmd);
1604 0 : identflags = oldflags;
1605 0 : forceshaders = wasforcing;
1606 0 : standardshaders = wasstandard;
1607 0 : delete[] cmd;
1608 :
1609 0 : if(deferred())
1610 : {
1611 0 : delete[] defer;
1612 0 : defer = nullptr;
1613 0 : type = Shader_Invalid;
1614 : }
1615 : }
1616 :
1617 0 : int Shader::uniformlocversion()
1618 : {
1619 : static int version = 0;
1620 0 : if(++version >= 0)
1621 : {
1622 0 : return version;
1623 : }
1624 0 : version = 0;
1625 0 : for(auto &[k, s] : shaders)
1626 : {
1627 0 : for(UniformLoc &j : s.uniformlocs)
1628 : {
1629 0 : j.version = -1;
1630 : }
1631 : }
1632 0 : return version;
1633 : }
1634 :
1635 1 : Shader *useshaderbyname(std::string_view name)
1636 : {
1637 1 : std::unordered_map<std::string, Shader>::iterator itr = shaders.find(name.data());
1638 1 : if(itr == shaders.end())
1639 : {
1640 1 : return nullptr;
1641 : }
1642 0 : Shader *s = &(*itr).second;
1643 0 : if(s->deferred())
1644 : {
1645 0 : s->force();
1646 : }
1647 0 : s->forced = true;
1648 0 : return s;
1649 : }
1650 :
1651 1 : static void shader(const int *type, const char *name, const char *vs, const char *ps)
1652 : {
1653 1 : if(lookupshaderbyname(name))
1654 : {
1655 0 : return;
1656 : }
1657 1 : DEF_FORMAT_STRING(info, "shader %s", name);
1658 1 : renderprogress(loadprogress, info);
1659 3 : std::string vs_string(vs), ps_string(ps);
1660 :
1661 1 : if(!slotparams.empty())
1662 : {
1663 1 : genuniformdefs(vs_string, ps_string);
1664 : }
1665 :
1666 1 : if(vs_string.find("//:fog") != std::string::npos || ps_string.find("//:fog") != std::string::npos)
1667 : {
1668 0 : genfogshader(vs_string, ps_string);
1669 : }
1670 :
1671 1 : Shader *s = newshader(*type, name, vs_string.c_str(), ps_string.c_str());
1672 1 : if(s)
1673 : {
1674 0 : if(vs_string.find("//:variant") != std::string::npos || ps_string.find("//:variant") != std::string::npos)
1675 : {
1676 0 : gengenericvariant(*s, name, vs_string.c_str(), ps_string.c_str());
1677 : }
1678 : }
1679 1 : slotparams.clear();
1680 1 : }
1681 :
1682 : namespace ShaderMgr
1683 : {
1684 : static bool adding_shader = false;
1685 : static std::vector<std::pair<std::string, std::string>> shader_defines;
1686 : static std::vector<std::string> shader_includes_vs, shader_includes_fs;
1687 : static std::string shader_path_vs, shader_path_fs;
1688 :
1689 1 : static std::string shader_make_defines()
1690 : {
1691 1 : std::string defines;
1692 :
1693 1 : for(const std::pair<std::string, std::string> &define : shader_defines)
1694 : {
1695 0 : defines += "#define " + define.first + " " + define.second + "\n";
1696 : }
1697 :
1698 1 : return defines;
1699 0 : }
1700 :
1701 1 : static void shader_clear_defines()
1702 : {
1703 1 : shader_defines.clear();
1704 1 : shader_includes_vs.clear();
1705 1 : shader_includes_fs.clear();
1706 1 : shader_path_vs.clear();
1707 1 : shader_path_fs.clear();
1708 1 : }
1709 :
1710 : //loads the vertex and pixel shaders at the indicated paths and returns them to vs, ps
1711 1 : static void shader_assemble(std::string vs_path, std::string fs_path, std::string &vs, std::string &ps)
1712 : {
1713 1 : std::string defines;
1714 :
1715 1 : defines = shader_make_defines();
1716 :
1717 1 : if(!shader_path_vs.empty())
1718 : {
1719 0 : const char *vs_file = loadfile(path(vs_path).c_str(), nullptr);
1720 0 : if(!vs_file)
1721 : {
1722 0 : conoutf(Console_Error, "could not load vertex shader %s", vs_path.c_str());
1723 0 : adding_shader = false;
1724 0 : return;
1725 : }
1726 :
1727 0 : vs = vs_file;
1728 :
1729 0 : std::string includes;
1730 0 : for(const std::string &include : shader_includes_vs)
1731 : {
1732 0 : const char *vs_include = loadfile(path(include).c_str(), nullptr);
1733 :
1734 0 : if(!vs_include)
1735 : {
1736 0 : conoutf(Console_Error, "could not load vertex shader include %s", include.c_str());
1737 0 : adding_shader = false;
1738 0 : return;
1739 : }
1740 :
1741 0 : includes += std::string(vs_include) + "\n";
1742 : }
1743 :
1744 0 : vs = defines + includes + vs;
1745 0 : }
1746 :
1747 1 : if(!fs_path.empty())
1748 : {
1749 0 : char *ps_file = loadfile(path(fs_path).c_str(), nullptr);
1750 0 : if(!ps_file)
1751 : {
1752 0 : conoutf(Console_Error, "could not load fragment shader %s", fs_path.c_str());
1753 0 : adding_shader = false;
1754 0 : return;
1755 : }
1756 :
1757 0 : ps = ps_file;
1758 :
1759 0 : std::string includes;
1760 0 : for(const std::string &include : shader_includes_fs)
1761 : {
1762 0 : char *ps_include = loadfile(path(include).c_str(), nullptr);
1763 :
1764 0 : if(!ps_include)
1765 : {
1766 0 : conoutf(Console_Error, "could not load fragment shader include %s", include.c_str());
1767 0 : adding_shader = false;
1768 0 : return;
1769 : }
1770 :
1771 0 : includes += std::string(ps_include) + "\n";
1772 : }
1773 :
1774 0 : ps = defines + includes + ps;
1775 0 : }
1776 1 : }
1777 :
1778 1 : static void shader_new(const int *type, const char *name, const uint *code)
1779 : {
1780 1 : if(lookupshaderbyname(name))
1781 : {
1782 0 : return;
1783 : }
1784 :
1785 1 : adding_shader = true;
1786 1 : shader_clear_defines();
1787 :
1788 1 : execute(code);
1789 :
1790 1 : std::string vs, ps;
1791 1 : shader_assemble(shader_path_vs, shader_path_fs, vs, ps);
1792 :
1793 1 : DEF_FORMAT_STRING(info, "shader %s", name);
1794 1 : renderprogress(loadprogress, info);
1795 :
1796 1 : if(!slotparams.empty())
1797 : {
1798 0 : genuniformdefs(vs, ps);
1799 : }
1800 :
1801 1 : if(vs.find("//:fog") != std::string::npos || ps.find("//:fog") != std::string::npos)
1802 : {
1803 0 : genfogshader(vs, ps);
1804 : }
1805 :
1806 1 : Shader *s = newshader(*type, name, vs.c_str(), ps.c_str());
1807 1 : if(s)
1808 : {
1809 0 : if(vs.find("//:variant") != std::string::npos || ps.find("//:variant") != std::string::npos)
1810 : {
1811 0 : gengenericvariant(*s, name, vs.c_str(), ps.c_str());
1812 : }
1813 : }
1814 1 : slotparams.clear();
1815 :
1816 1 : adding_shader = false;
1817 1 : }
1818 :
1819 1 : static void shader_define(std::string_view name, std::string_view value)
1820 : {
1821 1 : if(!adding_shader)
1822 : {
1823 1 : return;
1824 : }
1825 :
1826 0 : shader_defines.emplace_back(name, value);
1827 : }
1828 :
1829 1 : static void shader_get_defines()
1830 : {
1831 1 : if(!adding_shader)
1832 : {
1833 1 : return;
1834 : }
1835 :
1836 0 : std::string res;
1837 :
1838 0 : for(auto &[name, value] : shader_defines)
1839 : {
1840 0 : res += " [" + name + " " + value + "]";
1841 : }
1842 :
1843 0 : result(res.c_str());
1844 0 : }
1845 :
1846 1 : static void shader_include_vs(std::string_view path)
1847 : {
1848 1 : if(!adding_shader)
1849 : {
1850 1 : return;
1851 : }
1852 :
1853 0 : shader_includes_vs.emplace_back(path);
1854 : }
1855 :
1856 1 : static void shader_get_includes_vs()
1857 : {
1858 1 : if(!adding_shader)
1859 : {
1860 1 : return;
1861 : }
1862 :
1863 0 : std::string res;
1864 :
1865 0 : for(const std::string &include : shader_includes_vs)
1866 : {
1867 0 : res += " \"" + include + "\"";
1868 : }
1869 :
1870 0 : result(res.c_str());
1871 0 : }
1872 :
1873 1 : static void shader_include_fs(std::string_view path)
1874 : {
1875 1 : if(!adding_shader)
1876 : {
1877 1 : return;
1878 : }
1879 :
1880 0 : shader_includes_fs.emplace_back(path);
1881 : }
1882 :
1883 1 : static void shader_get_includes_fs()
1884 : {
1885 1 : if(!adding_shader)
1886 : {
1887 1 : return;
1888 : }
1889 :
1890 0 : std::string res;
1891 :
1892 0 : for(const std::string &include : shader_includes_fs)
1893 : {
1894 0 : res += " \"" + include + "\"";
1895 : }
1896 :
1897 0 : result(res.c_str());
1898 0 : }
1899 :
1900 1 : static void shader_source(std::string_view vs, std::string_view fs)
1901 : {
1902 1 : if(!adding_shader)
1903 : {
1904 1 : return;
1905 : }
1906 :
1907 0 : shader_path_vs = vs;
1908 0 : shader_path_fs = fs;
1909 : }
1910 :
1911 1 : static void variantshader(const int *type, const char *name, const int *row, const char *vs, const char *ps, const int *maxvariants)
1912 : {
1913 1 : if(*row < 0)
1914 : {
1915 0 : shader(type, name, vs, ps);
1916 1 : return;
1917 : }
1918 1 : else if(*row >= maxvariantrows)
1919 : {
1920 0 : return;
1921 : }
1922 1 : Shader *s = lookupshaderbyname(name);
1923 1 : if(!s)
1924 : {
1925 1 : return;
1926 : }
1927 0 : DEF_FORMAT_STRING(varname, "<variant:%d,%d>%s", s->numvariants(*row), *row, name);
1928 0 : if(*maxvariants > 0)
1929 : {
1930 0 : DEF_FORMAT_STRING(info, "shader %s", name);
1931 0 : renderprogress(std::min(s->variants.size() / static_cast<float>(*maxvariants), 1.0f), info);
1932 : }
1933 :
1934 0 : std::string vs_string(vs), ps_string(ps);
1935 :
1936 0 : if(!s->defaultparams.empty())
1937 : {
1938 0 : genuniformdefs(vs_string, ps_string, s);
1939 : }
1940 :
1941 0 : if(vs_string.find("//:fog") != std::string::npos || ps_string.find("//:fog") != std::string::npos)
1942 : {
1943 0 : genfogshader(vs_string, ps_string);
1944 : }
1945 :
1946 0 : const Shader *v = newshader(*type, varname, vs_string.c_str(), ps_string.c_str(), s, *row);
1947 0 : if(v)
1948 : {
1949 0 : if(vs_string.find("//:variant") != std::string::npos || ps_string.find("//:variant") != std::string::npos)
1950 : {
1951 0 : gengenericvariant(*s, varname, vs_string.c_str(), ps_string.c_str(), *row);
1952 : }
1953 : }
1954 0 : }
1955 :
1956 1 : static void variantshader_new(const int *type, const char *name, const int *row, const int *maxvariants, const uint *code)
1957 : {
1958 1 : if(*row < 0)
1959 : {
1960 0 : shader_new(type, name, code);
1961 1 : return;
1962 : }
1963 1 : else if(*row >= maxvariantrows)
1964 : {
1965 0 : return;
1966 : }
1967 1 : Shader *s = lookupshaderbyname(name);
1968 1 : if(!s)
1969 : {
1970 1 : return;
1971 : }
1972 :
1973 0 : adding_shader = true;
1974 0 : shader_clear_defines();
1975 :
1976 0 : execute(code);
1977 :
1978 0 : std::string vs, ps;
1979 0 : shader_assemble(shader_path_vs, shader_path_fs, vs, ps);
1980 :
1981 0 : DEF_FORMAT_STRING(varname, "<variant:%d,%d>%s", s->numvariants(*row), *row, name);
1982 0 : if(*maxvariants > 0)
1983 : {
1984 0 : DEF_FORMAT_STRING(info, "shader %s", name);
1985 0 : renderprogress(std::min(s->variants.size() / static_cast<float>(*maxvariants), 1.0f), info);
1986 : }
1987 :
1988 0 : if(!s->defaultparams.empty())
1989 : {
1990 0 : genuniformdefs(vs, ps, s);
1991 : }
1992 :
1993 0 : if(vs.find("//:fog") != std::string::npos || ps.find("//:fog") != std::string::npos)
1994 : {
1995 0 : genfogshader(vs, ps);
1996 : }
1997 :
1998 0 : const Shader *v = newshader(*type, varname, vs.c_str(), ps.c_str(), s, *row);
1999 0 : if(v)
2000 : {
2001 0 : if(vs.find("//:variant") != std::string::npos || ps.find("//:variant") != std::string::npos)
2002 : {
2003 0 : gengenericvariant(*s, varname, vs.c_str(), ps.c_str(), *row);
2004 : }
2005 : }
2006 :
2007 0 : adding_shader = false;
2008 0 : }
2009 : }
2010 :
2011 : //==============================================================================
2012 :
2013 1 : static void setshader(const char *name)
2014 : {
2015 1 : slotparams.clear();
2016 1 : std::unordered_map<std::string, Shader>::iterator itr = shaders.find(name);
2017 1 : if(itr == shaders.end())
2018 : {
2019 0 : conoutf(Console_Error, "no such shader: %s", name);
2020 : }
2021 : else
2022 : {
2023 1 : slotshader = &(*itr).second;
2024 : }
2025 1 : }
2026 :
2027 0 : void resetslotshader()
2028 : {
2029 0 : slotshader = nullptr;
2030 0 : slotparams.clear();
2031 0 : }
2032 :
2033 0 : void setslotshader(Slot &s)
2034 : {
2035 0 : s.shader = slotshader;
2036 0 : if(!s.shader)
2037 : {
2038 0 : s.shader = stdworldshader;
2039 0 : return;
2040 : }
2041 0 : for(size_t i = 0; i < slotparams.size(); i++)
2042 : {
2043 0 : s.params.push_back(slotparams[i]);
2044 : }
2045 : }
2046 :
2047 0 : static void linkslotshaderparams(std::vector<SlotShaderParam> ¶ms, const Shader &sh, bool load)
2048 : {
2049 0 : if(sh.loaded())
2050 : {
2051 0 : for(SlotShaderParam ¶m : params)
2052 : {
2053 0 : int loc = -1;
2054 0 : for(size_t j = 0; j < sh.defaultparams.size(); j++)
2055 : {
2056 0 : const SlotShaderParamState &dparam = sh.defaultparams[j];
2057 0 : if(dparam.name==param.name)
2058 : {
2059 0 : if(std::memcmp(param.val, &dparam.val[0], sizeof(param.val)))
2060 : {
2061 0 : loc = j;
2062 : }
2063 0 : break;
2064 : }
2065 : }
2066 0 : param.loc = loc;
2067 : }
2068 : }
2069 0 : else if(load)
2070 : {
2071 0 : for(SlotShaderParam &p : params)
2072 : {
2073 0 : p.loc = SIZE_MAX;
2074 : }
2075 : }
2076 0 : }
2077 :
2078 0 : void linkslotshader(Slot &s, bool load)
2079 : {
2080 0 : if(!s.shader)
2081 : {
2082 0 : return;
2083 : }
2084 0 : if(load && s.shader->deferred())
2085 : {
2086 0 : s.shader->force();
2087 : }
2088 0 : linkslotshaderparams(s.params, *s.shader, load);
2089 : }
2090 :
2091 0 : void linkvslotshader(VSlot &s, bool load)
2092 : {
2093 0 : if(!s.slot->shader)
2094 : {
2095 0 : return;
2096 : }
2097 0 : linkslotshaderparams(s.params, *(s.slot->shader), load);
2098 0 : if(!s.slot->shader->loaded())
2099 : {
2100 0 : return;
2101 : }
2102 0 : if(s.slot->texmask&(1 << Tex_Glow))
2103 : {
2104 0 : static const char *paramname = getshaderparamname("glowcolor");
2105 0 : const float *param = findslotparam(s, paramname);
2106 0 : if(param)
2107 : {
2108 0 : s.glowcolor = vec(param).clamp(0, 1);
2109 : }
2110 : }
2111 : }
2112 :
2113 0 : bool shouldreuseparams(const Slot &s, const VSlot &p)
2114 : {
2115 0 : if(!s.shader)
2116 : {
2117 0 : return false;
2118 : }
2119 0 : const Shader &sh = *s.shader;
2120 0 : for(const SlotShaderParamState ¶m : sh.defaultparams)
2121 : {
2122 0 : if(param.flags & SlotShaderParam::REUSE)
2123 : {
2124 0 : const float *val = findslotparam(p, param.name.c_str());
2125 0 : if(val && std::memcmp(¶m.val[0], val, param.val.size()))
2126 : {
2127 0 : for(const SlotShaderParam &j : s.params)
2128 : {
2129 0 : if(j.name == param.name)
2130 : {
2131 0 : goto notreused; //bail out of for loop
2132 : }
2133 : }
2134 0 : return true;
2135 0 : notreused:;
2136 : }
2137 : }
2138 : }
2139 0 : return false;
2140 : }
2141 :
2142 :
2143 : static std::unordered_set<std::string> shaderparamnames;
2144 :
2145 2 : const char *getshaderparamname(const char *name, bool insert)
2146 : {
2147 2 : auto itr = shaderparamnames.find(name);
2148 2 : if(itr != shaderparamnames.end() || !insert)
2149 : {
2150 1 : return (*itr).c_str();
2151 : }
2152 2 : return (*shaderparamnames.insert(name).first).c_str();
2153 : }
2154 :
2155 2 : void addslotparam(const char *name, float x, float y, float z, float w, int flags = 0)
2156 : {
2157 2 : if(name)
2158 : {
2159 2 : name = getshaderparamname(name);
2160 : }
2161 2 : for(SlotShaderParam &i : slotparams)
2162 : {
2163 1 : if(i.name==name)
2164 : {
2165 1 : i.val[0] = x;
2166 1 : i.val[1] = y;
2167 1 : i.val[2] = z;
2168 1 : i.val[3] = w;
2169 1 : i.flags |= flags;
2170 1 : return;
2171 : }
2172 : }
2173 1 : SlotShaderParam param = {name, SIZE_MAX, flags, {x, y, z, w}};
2174 1 : slotparams.push_back(param);
2175 : }
2176 :
2177 0 : void cleanupshaders()
2178 : {
2179 0 : cleanuppostfx(true);
2180 :
2181 0 : loadedshaders = false;
2182 0 : nullshader = hudshader = hudnotextureshader = nullptr;
2183 0 : for(auto &[k, s] : shaders)
2184 : {
2185 0 : s.cleanup();
2186 : }
2187 0 : Shader::lastshader = nullptr;
2188 0 : glUseProgram(0);
2189 0 : }
2190 :
2191 0 : void Shader::reusecleanup()
2192 : {
2193 0 : if((reusevs && reusevs->invalid()) ||
2194 0 : (reuseps && reuseps->invalid()) ||
2195 0 : !compile())
2196 : {
2197 0 : cleanup(true);
2198 : }
2199 0 : }
2200 :
2201 0 : void reloadshaders()
2202 : {
2203 0 : identflags &= ~Idf_Persist;
2204 0 : loadshaders();
2205 0 : identflags |= Idf_Persist;
2206 0 : linkslotshaders();
2207 0 : for(auto &[k, s] : shaders)
2208 : {
2209 0 : if(!s.standard && s.loaded() && !s.variantshader)
2210 : {
2211 0 : DEF_FORMAT_STRING(info, "shader %s", s.name);
2212 0 : renderprogress(0.0, info);
2213 0 : if(!s.compile())
2214 : {
2215 0 : s.cleanup(true);
2216 : }
2217 0 : for(Shader *&v : s.variants)
2218 : {
2219 0 : v->reusecleanup();
2220 : }
2221 : }
2222 0 : if(s.forced && s.deferred())
2223 : {
2224 0 : s.force();
2225 : }
2226 : }
2227 0 : }
2228 :
2229 1 : void resetshaders()
2230 : {
2231 1 : if(!glslversion)
2232 : {
2233 1 : conoutf(Console_Error, "Cannot reset GLSL shaders without GLSL initialized, operation not performed");
2234 1 : return;
2235 : }
2236 0 : clearchanges(Change_Shaders);
2237 :
2238 0 : cleanuplights();
2239 0 : cleanupmodels();
2240 0 : cleanupshaders();
2241 0 : setupshaders();
2242 0 : initgbuffer();
2243 0 : reloadshaders();
2244 0 : rootworld.allchanged(true);
2245 0 : glerror();
2246 : }
2247 :
2248 : FVAR(blursigma, 0.005f, 0.5f, 2.0f);
2249 :
2250 0 : void setupblurkernel(int radius, std::array<float, maxblurradius + 1> &weights, std::array<float, maxblurradius + 1> &offsets)
2251 : {
2252 0 : if(radius<1 || radius>maxblurradius)
2253 : {
2254 0 : return;
2255 : }
2256 0 : float sigma = blursigma*2*radius,
2257 0 : total = 1.0f/sigma;
2258 0 : weights[0] = total;
2259 0 : offsets[0] = 0;
2260 : // rely on bilinear filtering to sample 2 pixels at once
2261 : // transforms a*X + b*Y into (u+v)*[X*u/(u+v) + Y*(1 - u/(u+v))]
2262 0 : for(int i = 0; i < radius; ++i)
2263 : {
2264 0 : float weight1 = std::exp(-((2*i)*(2*i)) / (2*sigma*sigma)) / sigma,
2265 0 : weight2 = std::exp(-((2*i+1)*(2*i+1)) / (2*sigma*sigma)) / sigma,
2266 0 : scale = weight1 + weight2,
2267 0 : offset = 2*i+1 + weight2 / scale;
2268 0 : weights[i+1] = scale;
2269 0 : offsets[i+1] = offset;
2270 0 : total += 2*scale;
2271 : }
2272 0 : for(int i = 0; i < radius+1; ++i)
2273 : {
2274 0 : weights[i] /= total;
2275 : }
2276 0 : for(int i = radius+1; i <= maxblurradius; i++)
2277 : {
2278 0 : weights[i] = offsets[i] = 0;
2279 : }
2280 : }
2281 :
2282 0 : void setblurshader(int pass, int size, int radius, std::array<float, maxblurradius + 1> &weights, std::array<float, maxblurradius + 1> &offsets, GLenum target)
2283 : {
2284 0 : if(radius<1 || radius>maxblurradius)
2285 : {
2286 0 : return;
2287 : }
2288 : static Shader *blurshader[7][2] = { { nullptr, nullptr }, { nullptr, nullptr }, { nullptr, nullptr }, { nullptr, nullptr }, { nullptr, nullptr }, { nullptr, nullptr }, { nullptr, nullptr } },
2289 : *blurrectshader[7][2] = { { nullptr, nullptr }, { nullptr, nullptr }, { nullptr, nullptr }, { nullptr, nullptr }, { nullptr, nullptr }, { nullptr, nullptr }, { nullptr, nullptr } };
2290 0 : Shader *&s = (target == GL_TEXTURE_RECTANGLE ? blurrectshader : blurshader)[radius-1][pass];
2291 0 : if(!s)
2292 : {
2293 0 : DEF_FORMAT_STRING(name, "blur%c%d%s", 'x'+pass, radius, target == GL_TEXTURE_RECTANGLE ? "rect" : "");
2294 0 : s = lookupshaderbyname(name);
2295 : }
2296 0 : s->set();
2297 0 : LOCALPARAMV(weights.data(), weights.data(), maxblurradius+1);
2298 : std::array<float, maxblurradius+1> scaledoffsets;
2299 0 : for(int k = 0; k < maxblurradius+1; ++k)
2300 : {
2301 0 : scaledoffsets[k] = offsets[k]/size;
2302 : }
2303 0 : LOCALPARAMV(offsets.data(), scaledoffsets.data(), maxblurradius+1);
2304 : }
2305 :
2306 1 : void initshadercmds()
2307 : {
2308 1 : addcommand("defershader", reinterpret_cast<identfun>(defershader), "iss", Id_Command);
2309 2 : addcommand("forceshader", reinterpret_cast<identfun>(+[](const char *name){useshaderbyname(name);}), "s", Id_Command);
2310 1 : addcommand("shader", reinterpret_cast<identfun>(shader), "isss", Id_Command);
2311 1 : addcommand("variantshader", reinterpret_cast<identfun>(ShaderMgr::variantshader), "isissi", Id_Command);
2312 1 : addcommand("setshader", reinterpret_cast<identfun>(setshader), "s", Id_Command);
2313 2 : addcommand("isshaderdefined", reinterpret_cast<identfun>(+[](const char *name){intret(lookupshaderbyname(name) ? 1 : 0);}), "s", Id_Command);
2314 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);
2315 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);
2316 1 : addcommand("resetshaders", reinterpret_cast<identfun>(resetshaders), "", Id_Command);
2317 :
2318 1 : addcommand("variantshader_new", reinterpret_cast<identfun>(ShaderMgr::variantshader_new), "isiie", Id_Command);
2319 1 : addcommand("shader_new", reinterpret_cast<identfun>(ShaderMgr::shader_new), "ise", Id_Command);
2320 1 : addcommand("shader_define", reinterpret_cast<identfun>(ShaderMgr::shader_define), "ss", Id_Command);
2321 1 : addcommand("shader_source", reinterpret_cast<identfun>(ShaderMgr::shader_source), "ss", Id_Command);
2322 1 : addcommand("shader_include_vs", reinterpret_cast<identfun>(ShaderMgr::shader_include_vs), "s", Id_Command);
2323 1 : addcommand("shader_include_fs", reinterpret_cast<identfun>(ShaderMgr::shader_include_fs), "s", Id_Command);
2324 1 : addcommand("shader_get_defines", reinterpret_cast<identfun>(ShaderMgr::shader_get_defines), "", Id_Command);
2325 1 : addcommand("shader_get_includes_vs", reinterpret_cast<identfun>(ShaderMgr::shader_get_includes_vs), "", Id_Command);
2326 1 : addcommand("shader_get_includes_fs", reinterpret_cast<identfun>(ShaderMgr::shader_get_includes_fs), "", Id_Command);
2327 :
2328 1 : initpostfxcmds();
2329 1 : }
|