1 #include "engine.h"
2
3 int gw = -1, gh = -1, bloomw = -1, bloomh = -1, lasthdraccum = 0;
4 GLuint gfbo = 0, gdepthtex = 0, gcolortex = 0, gnormaltex = 0, gglowtex = 0, gdepthrb = 0, gstencilrb = 0;
5 bool gdepthinit = false;
6 int scalew = -1, scaleh = -1;
7 GLuint scalefbo[2] = { 0, 0 }, scaletex[2] = { 0, 0 };
8 GLuint hdrfbo = 0, hdrtex = 0, bloompbo = 0, bloomfbo[6] = { 0, 0, 0, 0, 0, 0 }, bloomtex[6] = { 0, 0, 0, 0, 0, 0 };
9 int hdrclear = 0;
10 GLuint refractfbo = 0, refracttex = 0;
11 GLenum bloomformat = 0, hdrformat = 0, stencilformat = 0;
12 bool hdrfloat = false;
13 GLuint msfbo = 0, msdepthtex = 0, mscolortex = 0, msnormaltex = 0, msglowtex = 0, msdepthrb = 0, msstencilrb = 0, mshdrfbo = 0, mshdrtex = 0, msrefractfbo = 0, msrefracttex = 0;
14 vector<vec2> msaapositions;
15 int aow = -1, aoh = -1;
16 GLuint aofbo[4] = { 0, 0, 0, 0 }, aotex[4] = { 0, 0, 0, 0 }, aonoisetex = 0;
17 matrix4 eyematrix, worldmatrix, linearworldmatrix, screenmatrix;
18
19 extern int amd_pf_bug;
20
gethdrformat(int prec,int fallback=GL_RGB)21 int gethdrformat(int prec, int fallback = GL_RGB)
22 {
23 if(prec >= 3 && hasTF) return GL_RGB16F;
24 if(prec >= 2 && hasPF && !amd_pf_bug) return GL_R11F_G11F_B10F;
25 if(prec >= 1) return GL_RGB10;
26 return fallback;
27 }
28
29 extern int bloomsize, bloomprec;
30
setupbloom(int w,int h)31 void setupbloom(int w, int h)
32 {
33 int maxsize = ((1<<bloomsize)*5)/4;
34 while(w >= maxsize || h >= maxsize)
35 {
36 w /= 2;
37 h /= 2;
38 }
39 if(w == bloomw && h == bloomh) return;
40 bloomw = w;
41 bloomh = h;
42
43 loopi(5) if(!bloomtex[i]) glGenTextures(1, &bloomtex[i]);
44
45 loopi(5) if(!bloomfbo[i]) glGenFramebuffers_(1, &bloomfbo[i]);
46
47 bloomformat = gethdrformat(bloomprec);
48 createtexture(bloomtex[0], max(gw/2, bloomw), max(gh/2, bloomh), NULL, 3, 1, bloomformat, GL_TEXTURE_RECTANGLE);
49 createtexture(bloomtex[1], max(gw/4, bloomw), max(gh/4, bloomh), NULL, 3, 1, bloomformat, GL_TEXTURE_RECTANGLE);
50 createtexture(bloomtex[2], bloomw, bloomh, NULL, 3, 1, GL_RGB, GL_TEXTURE_RECTANGLE);
51 createtexture(bloomtex[3], bloomw, bloomh, NULL, 3, 1, GL_RGB, GL_TEXTURE_RECTANGLE);
52 if(bloomformat != GL_RGB)
53 {
54 if(!bloomtex[5]) glGenTextures(1, &bloomtex[5]);
55 if(!bloomfbo[5]) glGenFramebuffers_(1, &bloomfbo[5]);
56 createtexture(bloomtex[5], bloomw, bloomh, NULL, 3, 1, bloomformat, GL_TEXTURE_RECTANGLE);
57 }
58
59 if(hwvtexunits < 4)
60 {
61 glGenBuffers_(1, &bloompbo);
62 glBindBuffer_(GL_PIXEL_PACK_BUFFER, bloompbo);
63 glBufferData_(GL_PIXEL_PACK_BUFFER, 4*(hasTF ? sizeof(GLfloat) : sizeof(GLushort))*(hasTRG ? 1 : 3), NULL, GL_DYNAMIC_COPY);
64 glBindBuffer_(GL_PIXEL_PACK_BUFFER, 0);
65 }
66
67 static const uchar gray[12] = { 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32 };
68 static const float grayf[12] = { 0.125f, 0.125f, 0.125f, 0.125f, 0.125f, 0.125f, 0.125f, 0.125f, 0.125f, 0.125f, 0.125f, 0.125f };
69 createtexture(bloomtex[4], bloompbo ? 4 : 1, 1, hasTF ? (const void *)grayf : (const void *)gray, 3, 1, hasTF ? (hasTRG ? GL_R16F : GL_RGB16F) : (hasTRG ? GL_R16 : GL_RGB16));
70
71 loopi(5 + (bloomformat != GL_RGB ? 1 : 0))
72 {
73 glBindFramebuffer_(GL_FRAMEBUFFER, bloomfbo[i]);
74 glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, i==4 ? GL_TEXTURE_2D : GL_TEXTURE_RECTANGLE, bloomtex[i], 0);
75
76 if(glCheckFramebufferStatus_(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
77 fatal("failed allocating bloom buffer!");
78 }
79
80 glBindFramebuffer_(GL_FRAMEBUFFER, 0);
81 }
82
cleanupbloom()83 void cleanupbloom()
84 {
85 if(bloompbo) { glDeleteBuffers_(1, &bloompbo); bloompbo = 0; }
86 loopi(6) if(bloomfbo[i]) { glDeleteFramebuffers_(1, &bloomfbo[i]); bloomfbo[i] = 0; }
87 loopi(6) if(bloomtex[i]) { glDeleteTextures(1, &bloomtex[i]); bloomtex[i] = 0; }
88 bloomw = bloomh = -1;
89 lasthdraccum = 0;
90 }
91
92 extern int ao, aotaps, aoreduce, aoreducedepth, aonoise, aobilateral, aobilateralupscale, aopackdepth, aodepthformat, aoprec, aoderivnormal;
93
94 static Shader *bilateralshader[2] = { NULL, NULL };
95
loadbilateralshader(int pass)96 Shader *loadbilateralshader(int pass)
97 {
98 if(!aobilateral) return nullshader;
99
100 string opts;
101 int optslen = 0;
102
103 bool linear = aoreducedepth && (aoreduce || aoreducedepth > 1),
104 upscale = aoreduce && aobilateralupscale,
105 reduce = aoreduce && (upscale || (!linear && !aopackdepth));
106 if(reduce)
107 {
108 opts[optslen++] = 'r';
109 opts[optslen++] = '0' + aoreduce;
110 }
111 if(upscale) opts[optslen++] = 'u';
112 else if(linear) opts[optslen++] = 'l';
113 if(aopackdepth) opts[optslen++] = 'p';
114 opts[optslen] = '\0';
115
116 defformatstring(name, "bilateral%c%s%d", 'x' + pass, opts, aobilateral);
117 return generateshader(name, "bilateralshader \"%s\" %d %d", opts, aobilateral, reduce ? aoreduce : 0);
118 }
119
loadbilateralshaders()120 void loadbilateralshaders()
121 {
122 loopk(2) bilateralshader[k] = loadbilateralshader(k);
123 }
124
clearbilateralshaders()125 void clearbilateralshaders()
126 {
127 loopk(2) bilateralshader[k] = NULL;
128 }
129
setbilateralshader(int radius,int pass,float depth)130 void setbilateralshader(int radius, int pass, float depth)
131 {
132 bilateralshader[pass]->set();
133 float sigma = blursigma*2*radius;
134 LOCALPARAMF(bilateralparams, 1.0f/(M_LN2*2*sigma*sigma), 1.0f/(M_LN2*depth*depth));
135 }
136
137 static Shader *ambientobscuranceshader = NULL;
138
loadambientobscuranceshader()139 Shader *loadambientobscuranceshader()
140 {
141 string opts;
142 int optslen = 0;
143
144 bool linear = aoreducedepth && (aoreduce || aoreducedepth > 1);
145 if(linear) opts[optslen++] = 'l';
146 if(aoderivnormal) opts[optslen++] = 'd';
147 if(aobilateral && aopackdepth) opts[optslen++] = 'p';
148 opts[optslen] = '\0';
149
150 defformatstring(name, "ambientobscurance%s%d", opts, aotaps);
151 return generateshader(name, "ambientobscuranceshader \"%s\" %d", opts, aotaps);
152 }
153
loadaoshaders()154 void loadaoshaders()
155 {
156 ambientobscuranceshader = loadambientobscuranceshader();
157 }
158
clearaoshaders()159 void clearaoshaders()
160 {
161 ambientobscuranceshader = NULL;
162 }
163
setupao(int w,int h)164 void setupao(int w, int h)
165 {
166 int sw = w>>aoreduce, sh = h>>aoreduce;
167
168 if(sw == aow && sh == aoh) return;
169
170 aow = sw;
171 aoh = sh;
172
173 if(!aonoisetex) glGenTextures(1, &aonoisetex);
174 bvec *noise = new bvec[(1<<aonoise)*(1<<aonoise)];
175 loopk((1<<aonoise)*(1<<aonoise)) noise[k] = bvec(vec(rndscale(2)-1, rndscale(2)-1, 0).normalize());
176 createtexture(aonoisetex, 1<<aonoise, 1<<aonoise, noise, 0, 0, GL_RGB, GL_TEXTURE_2D);
177 delete[] noise;
178
179 bool upscale = aoreduce && aobilateral && aobilateralupscale;
180 GLenum format = aoprec && hasTRG ? GL_R8 : GL_RGBA8,
181 packformat = aobilateral && aopackdepth ? (aodepthformat ? GL_RG16F : GL_RGBA8) : format;
182 int packfilter = upscale && aopackdepth && !aodepthformat ? 0 : 1;
183 loopi(upscale ? 3 : 2)
184 {
185 if(!aotex[i]) glGenTextures(1, &aotex[i]);
186 if(!aofbo[i]) glGenFramebuffers_(1, &aofbo[i]);
187 createtexture(aotex[i], upscale && i ? w : aow, upscale && i >= 2 ? h : aoh, NULL, 3, i < 2 ? packfilter : 1, i < 2 ? packformat : format, GL_TEXTURE_RECTANGLE);
188 glBindFramebuffer_(GL_FRAMEBUFFER, aofbo[i]);
189 glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, aotex[i], 0);
190 if(glCheckFramebufferStatus_(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
191 fatal("failed allocating AO buffer!");
192 if(!upscale && packformat == GL_RG16F)
193 {
194 glClearColor(0, 0, 0, 0);
195 glClear(GL_COLOR_BUFFER_BIT);
196 }
197 }
198
199 if(aoreducedepth && (aoreduce || aoreducedepth > 1))
200 {
201 if(!aotex[3]) glGenTextures(1, &aotex[3]);
202 if(!aofbo[3]) glGenFramebuffers_(1, &aofbo[3]);
203 createtexture(aotex[3], aow, aoh, NULL, 3, 0, aodepthformat > 1 ? GL_R32F : (aodepthformat ? GL_R16F : GL_RGBA8), GL_TEXTURE_RECTANGLE);
204 glBindFramebuffer_(GL_FRAMEBUFFER, aofbo[3]);
205 glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, aotex[3], 0);
206 if(glCheckFramebufferStatus_(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
207 fatal("failed allocating AO buffer!");
208 }
209
210 glBindFramebuffer_(GL_FRAMEBUFFER, 0);
211
212 loadaoshaders();
213 loadbilateralshaders();
214 }
215
cleanupao()216 void cleanupao()
217 {
218 loopi(4) if(aofbo[i]) { glDeleteFramebuffers_(1, &aofbo[i]); aofbo[i] = 0; }
219 loopi(4) if(aotex[i]) { glDeleteTextures(1, &aotex[i]); aotex[i] = 0; }
220 if(aonoisetex) { glDeleteTextures(1, &aonoisetex); aonoisetex = 0; }
221 aow = bloomh = -1;
222
223 clearaoshaders();
224 clearbilateralshaders();
225 }
226
227 VARFP(ao, 0, 1, 1, { cleanupao(); cleardeferredlightshaders(); });
228 FVARR(aoradius, 0, 5, 256);
229 FVAR(aocutoff, 0, 2.0f, 1e3f);
230 FVARR(aodark, 1e-3f, 11.0f, 1e3f);
231 FVARR(aosharp, 1e-3f, 1, 1e3f);
232 FVAR(aoprefilterdepth, 0, 1, 1e3);
233 FVARR(aomin, 0, 0.25f, 1);
234 VARFR(aosun, 0, 1, 1, cleardeferredlightshaders());
235 FVARR(aosunmin, 0, 0.5f, 1);
236 VARP(aoblur, 0, 4, 7);
237 VARP(aoiter, 0, 0, 4);
238 VARFP(aoreduce, 0, 1, 2, cleanupao());
239 VARF(aoreducedepth, 0, 1, 2, cleanupao());
240 VARFP(aofloatdepth, 0, 1, 2, initwarning("AO setup", INIT_LOAD, CHANGE_SHADERS));
241 VARFP(aoprec, 0, 1, 1, cleanupao());
242 VAR(aodepthformat, 1, 0, 0);
243 VARF(aonoise, 0, 5, 8, cleanupao());
244 VARFP(aobilateral, 0, 3, 10, cleanupao());
245 FVARP(aobilateraldepth, 0, 4, 1e3f);
246 VARFP(aobilateralupscale, 0, 0, 1, cleanupao());
247 VARF(aopackdepth, 0, 1, 1, cleanupao());
248 VARFP(aotaps, 1, 5, 12, cleanupao());
249 VARF(aoderivnormal, 0, 0, 1, cleanupao());
250 VAR(debugao, 0, 0, 1);
251
initao()252 void initao()
253 {
254 aodepthformat = aofloatdepth && hasTRG && hasTF ? aofloatdepth : 0;
255 }
256
viewao()257 void viewao()
258 {
259 if(!ao) return;
260 int w = min(hudw, hudh)/2, h = (w*hudh)/hudw;
261 SETSHADER(hudrect);
262 gle::colorf(1, 1, 1);
263 glBindTexture(GL_TEXTURE_RECTANGLE, aotex[2] ? aotex[2] : aotex[0]);
264 int tw = aotex[2] ? gw : aow, th = aotex[2] ? gh : aoh;
265 debugquad(0, 0, w, h, 0, 0, tw, th);
266 }
267
renderao()268 void renderao()
269 {
270 if(!ao) return;
271
272 timer *aotimer = begintimer("ambient obscurance");
273
274 if(msaasamples) glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msdepthtex);
275 else glBindTexture(GL_TEXTURE_RECTANGLE, gdepthtex);
276
277 bool linear = aoreducedepth && (aoreduce || aoreducedepth > 1);
278 float xscale = eyematrix.a.x, yscale = eyematrix.b.y;
279 if(linear)
280 {
281 glBindFramebuffer_(GL_FRAMEBUFFER, aofbo[3]);
282 glViewport(0, 0, aow, aoh);
283 SETSHADER(linearizedepth);
284 screenquad(vieww, viewh);
285
286 xscale *= float(vieww)/aow;
287 yscale *= float(viewh)/aoh;
288
289 glBindTexture(GL_TEXTURE_RECTANGLE, aotex[3]);
290 }
291
292 ambientobscuranceshader->set();
293
294 glBindFramebuffer_(GL_FRAMEBUFFER, aofbo[0]);
295 glViewport(0, 0, aow, aoh);
296 glActiveTexture_(GL_TEXTURE1);
297 if(aoderivnormal)
298 {
299 if(msaasamples) glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msdepthtex);
300 else glBindTexture(GL_TEXTURE_RECTANGLE, gdepthtex);
301 }
302 else
303 {
304 if(msaasamples) glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msnormaltex);
305 else glBindTexture(GL_TEXTURE_RECTANGLE, gnormaltex);
306 LOCALPARAM(normalmatrix, matrix3(cammatrix));
307 }
308 glActiveTexture_(GL_TEXTURE2);
309 glBindTexture(GL_TEXTURE_2D, aonoisetex);
310 glActiveTexture_(GL_TEXTURE0);
311
312 LOCALPARAMF(tapparams, aoradius*eyematrix.d.z/xscale, aoradius*eyematrix.d.z/yscale, aoradius*aoradius*aocutoff*aocutoff);
313 LOCALPARAMF(contrastparams, (2.0f*aodark)/aotaps, aosharp);
314 LOCALPARAMF(offsetscale, xscale/eyematrix.d.z, yscale/eyematrix.d.z, eyematrix.d.x/eyematrix.d.z, eyematrix.d.y/eyematrix.d.z);
315 LOCALPARAMF(prefilterdepth, aoprefilterdepth);
316 screenquad(vieww, viewh, aow/float(1<<aonoise), aoh/float(1<<aonoise));
317
318 if(aobilateral)
319 {
320 if(aoreduce && aobilateralupscale) loopi(2)
321 {
322 setbilateralshader(aobilateral, i, aobilateraldepth);
323 glBindFramebuffer_(GL_FRAMEBUFFER, aofbo[i+1]);
324 glViewport(0, 0, vieww, i ? viewh : aoh);
325 glBindTexture(GL_TEXTURE_RECTANGLE, aotex[i]);
326 glActiveTexture_(GL_TEXTURE1);
327 if(msaasamples) glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msdepthtex);
328 else glBindTexture(GL_TEXTURE_RECTANGLE, gdepthtex);
329 glActiveTexture_(GL_TEXTURE0);
330 screenquad(vieww, viewh, i ? vieww : aow, aoh);
331 }
332 else loopi(2 + 2*aoiter)
333 {
334 setbilateralshader(aobilateral, i%2, aobilateraldepth);
335 glBindFramebuffer_(GL_FRAMEBUFFER, aofbo[(i+1)%2]);
336 glViewport(0, 0, aow, aoh);
337 glBindTexture(GL_TEXTURE_RECTANGLE, aotex[i%2]);
338 glActiveTexture_(GL_TEXTURE1);
339 if(linear) glBindTexture(GL_TEXTURE_RECTANGLE, aotex[3]);
340 else if(msaasamples) glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msdepthtex);
341 else glBindTexture(GL_TEXTURE_RECTANGLE, gdepthtex);
342 glActiveTexture_(GL_TEXTURE0);
343 screenquad(vieww, viewh);
344 }
345 }
346 else if(aoblur)
347 {
348 float blurweights[MAXBLURRADIUS+1], bluroffsets[MAXBLURRADIUS+1];
349 setupblurkernel(aoblur, blurweights, bluroffsets);
350 loopi(2 + 2*aoiter)
351 {
352 glBindFramebuffer_(GL_FRAMEBUFFER, aofbo[(i+1)%2]);
353 glViewport(0, 0, aow, aoh);
354 setblurshader(i%2, 1, aoblur, blurweights, bluroffsets, GL_TEXTURE_RECTANGLE);
355 glBindTexture(GL_TEXTURE_RECTANGLE, aotex[i%2]);
356 screenquad(aow, aoh);
357 }
358 }
359
360 glBindFramebuffer_(GL_FRAMEBUFFER, msaasamples ? msfbo : gfbo);
361 glViewport(0, 0, vieww, viewh);
362
363 endtimer(aotimer);
364 }
365
cleanupscale()366 void cleanupscale()
367 {
368 loopi(2) if(scalefbo[i]) { glDeleteFramebuffers_(1, &scalefbo[i]); scalefbo[i] = 0; }
369 loopi(2) if(scaletex[i]) { glDeleteTextures(1, &scaletex[i]); scaletex[i] = 0; }
370 scalew = scaleh = -1;
371 }
372
373 extern int gscalecubic, gscalenearest;
374
setupscale(int sw,int sh,int w,int h)375 void setupscale(int sw, int sh, int w, int h)
376 {
377 scalew = w;
378 scaleh = h;
379
380 loopi(gscalecubic ? 2 : 1)
381 {
382 if(!scaletex[i]) glGenTextures(1, &scaletex[i]);
383 if(!scalefbo[i]) glGenFramebuffers_(1, &scalefbo[i]);
384
385 glBindFramebuffer_(GL_FRAMEBUFFER, scalefbo[i]);
386
387 createtexture(scaletex[i], sw, i ? h : sh, NULL, 3, gscalecubic || !gscalenearest ? 1 : 0, GL_RGB, GL_TEXTURE_RECTANGLE);
388
389 glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, scaletex[i], 0);
390 if(!i) bindgdepth();
391
392 if(glCheckFramebufferStatus_(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
393 fatal("failed allocating scale buffer!");
394 }
395
396 glBindFramebuffer_(GL_FRAMEBUFFER, 0);
397
398 if(gscalecubic)
399 {
400 useshaderbyname("scalecubicx");
401 useshaderbyname("scalecubicy");
402 }
403 }
404
shouldscale()405 GLuint shouldscale()
406 {
407 return scalefbo[0];
408 }
409
doscale(GLuint outfbo)410 void doscale(GLuint outfbo)
411 {
412 if(!scaletex[0]) return;
413
414 timer *scaletimer = begintimer("scaling");
415
416 if(gscalecubic)
417 {
418 glBindFramebuffer_(GL_FRAMEBUFFER, scalefbo[1]);
419 glViewport(0, 0, gw, hudh);
420 glBindTexture(GL_TEXTURE_RECTANGLE, scaletex[0]);
421 SETSHADER(scalecubicy);
422 screenquad(gw, gh);
423 glBindFramebuffer_(GL_FRAMEBUFFER, outfbo);
424 glViewport(0, 0, hudw, hudh);
425 glBindTexture(GL_TEXTURE_RECTANGLE, scaletex[1]);
426 SETSHADER(scalecubicx);
427 screenquad(gw, hudh);
428 }
429 else
430 {
431 glBindFramebuffer_(GL_FRAMEBUFFER, outfbo);
432 glViewport(0, 0, hudw, hudh);
433 glBindTexture(GL_TEXTURE_RECTANGLE, scaletex[0]);
434 SETSHADER(scalelinear);
435 screenquad(gw, gh);
436 }
437
438 endtimer(scaletimer);
439 }
440
441 VARFP(glineardepth, 0, 0, 3, initwarning("g-buffer setup", INIT_LOAD, CHANGE_SHADERS));
442 VAR(gdepthformat, 1, 0, 0);
443 VARF(gstencil, 0, 0, 1, initwarning("g-buffer setup", INIT_LOAD, CHANGE_SHADERS));
444 VARF(gdepthstencil, 0, 2, 2, initwarning("g-buffer setup", INIT_LOAD, CHANGE_SHADERS));
445 VAR(ghasstencil, 1, 0, 0);
446 VARFP(msaa, 0, 0, 16, initwarning("MSAA setup", INIT_LOAD, CHANGE_SHADERS));
447 VARFP(csaa, 0, 0, 16, initwarning("MSAA setup", INIT_LOAD, CHANGE_SHADERS));
448 VARF(msaadepthstencil, 0, 2, 2, initwarning("MSAA setup", INIT_LOAD, CHANGE_SHADERS));
449 VARF(msaastencil, 0, 0, 1, initwarning("MSAA setup", INIT_LOAD, CHANGE_SHADERS));
450 VARF(msaaedgedetect, 0, 1, 1, cleanupgbuffer());
451 VARFP(msaalineardepth, -1, -1, 3, initwarning("MSAA setup", INIT_LOAD, CHANGE_SHADERS));
452 VARFP(msaatonemap, 0, 0, 1, cleanupgbuffer());
453 VARF(msaatonemapblit, 0, 0, 1, cleanupgbuffer());
454 VAR(msaamaxsamples, 1, 0, 0);
455 VAR(msaamaxdepthtexsamples, 1, 0, 0);
456 VAR(msaamaxcolortexsamples, 1, 0, 0);
457 VAR(msaaminsamples, 1, 0, 0);
458 VAR(msaasamples, 1, 0, 0);
459 VAR(msaamincolorsamples, 1, 0, 0);
460 VAR(msaacolorsamples, 1, 0, 0);
461
checkmsaasamples()462 void checkmsaasamples()
463 {
464 GLuint tex;
465 glGenTextures(1, &tex);
466 glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex);
467
468 GLint samples, colorsamples;
469 if(msaamincolorsamples < msaaminsamples)
470 {
471 glTexImage2DMultisampleCoverageNV_(GL_TEXTURE_2D_MULTISAMPLE, msaaminsamples, msaamincolorsamples, GL_RGBA8, 1, 1, GL_TRUE);
472 glGetTexLevelParameteriv(GL_TEXTURE_2D_MULTISAMPLE, 0, GL_TEXTURE_COVERAGE_SAMPLES_NV, &samples);
473 glGetTexLevelParameteriv(GL_TEXTURE_2D_MULTISAMPLE, 0, GL_TEXTURE_COLOR_SAMPLES_NV, &colorsamples);
474 msaasamples = samples;
475 msaacolorsamples = colorsamples;
476 }
477 else
478 {
479 glTexImage2DMultisample_(GL_TEXTURE_2D_MULTISAMPLE, msaaminsamples, GL_RGBA8, 1, 1, GL_TRUE);
480 glGetTexLevelParameteriv(GL_TEXTURE_2D_MULTISAMPLE, 0, GL_TEXTURE_SAMPLES, &samples);
481 msaacolorsamples = msaasamples = samples;
482 }
483
484 glDeleteTextures(1, &tex);
485 }
486
initgbuffer()487 void initgbuffer()
488 {
489 msaamaxsamples = msaamaxdepthtexsamples = msaamaxcolortexsamples = msaaminsamples = msaasamples = msaamincolorsamples = msaacolorsamples = 0;
490 msaapositions.setsize(0);
491
492 if(hasFBMS && hasFBB && hasTMS)
493 {
494 GLint val;
495 glGetIntegerv(GL_MAX_SAMPLES, &val);
496 msaamaxsamples = val;
497 glGetIntegerv(GL_MAX_DEPTH_TEXTURE_SAMPLES, &val);
498 msaamaxdepthtexsamples = val;
499 glGetIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &val);
500 msaamaxcolortexsamples = val;
501 }
502
503 int maxsamples = min(msaamaxsamples, msaamaxcolortexsamples), reqsamples = min(max(msaa, csaa), maxsamples);
504 if(reqsamples >= 2)
505 {
506 msaaminsamples = 2;
507 while(msaaminsamples*2 <= reqsamples) msaaminsamples *= 2;
508 if(hasNVFBMSC && hasNVTMS)
509 {
510 if(msaa)
511 {
512 int colorsamples = min(msaa, maxsamples);
513 msaamincolorsamples = 2;
514 while(msaamincolorsamples*2 <= colorsamples) msaamincolorsamples *= 2;
515 }
516 }
517 else msaamincolorsamples = msaaminsamples;
518 }
519
520 int lineardepth = glineardepth;
521 if(msaaminsamples)
522 {
523 if(msaamaxdepthtexsamples < msaaminsamples)
524 {
525 if(msaalineardepth > 0) lineardepth = msaalineardepth;
526 else if(!lineardepth) lineardepth = 1;
527 }
528 else if(msaalineardepth >= 0) lineardepth = msaalineardepth;
529 }
530
531 if(lineardepth > 1 && (!hasAFBO || !hasTF || !hasTRG)) gdepthformat = 1;
532 else gdepthformat = lineardepth;
533
534 if(msaaminsamples)
535 {
536 ghasstencil = (msaadepthstencil > 1 || (msaadepthstencil && gdepthformat)) && hasDS ? 2 : (msaastencil ? 1 : 0);
537
538 checkmsaasamples();
539 }
540 else ghasstencil = (gdepthstencil > 1 || (gdepthstencil && gdepthformat)) && hasDS ? 2 : (gstencil ? 1 : 0);
541
542 initao();
543 }
544
545 VARF(forcepacknorm, 0, 0, 1, initwarning("g-buffer setup", INIT_LOAD, CHANGE_SHADERS));
546
usepacknorm()547 bool usepacknorm() { return forcepacknorm || msaasamples || (!useavatarmask() && gdepthformat!=1); }
548 ICOMMAND(usepacknorm, "", (), intret(usepacknorm() ? 1 : 0));
549
maskgbuffer(const char * mask)550 void maskgbuffer(const char *mask)
551 {
552 GLenum drawbufs[4];
553 int numbufs = 0;
554 while(*mask) switch(*mask++)
555 {
556 case 'c': drawbufs[numbufs++] = GL_COLOR_ATTACHMENT0; break;
557 case 'n': drawbufs[numbufs++] = GL_COLOR_ATTACHMENT1; break;
558 case 'd': if(gdepthformat) drawbufs[numbufs++] = GL_COLOR_ATTACHMENT3; break;
559 case 'g': drawbufs[numbufs++] = GL_COLOR_ATTACHMENT2; break;
560 }
561 glDrawBuffers_(numbufs, drawbufs);
562 }
563
564 extern int hdrprec, gscale;
565
cleanupmsbuffer()566 void cleanupmsbuffer()
567 {
568 if(msfbo) { glDeleteFramebuffers_(1, &msfbo); msfbo = 0; }
569 if(msdepthtex) { glDeleteTextures(1, &msdepthtex); msdepthtex = 0; }
570 if(mscolortex) { glDeleteTextures(1, &mscolortex); mscolortex = 0; }
571 if(msnormaltex) { glDeleteTextures(1, &msnormaltex); msnormaltex = 0; }
572 if(msglowtex) { glDeleteTextures(1, &msglowtex); msglowtex = 0; }
573 if(msstencilrb) { glDeleteRenderbuffers_(1, &msstencilrb); msstencilrb = 0; }
574 if(msdepthrb) { glDeleteRenderbuffers_(1, &msdepthrb); msdepthrb = 0; }
575 if(mshdrfbo) { glDeleteFramebuffers_(1, &mshdrfbo); mshdrfbo = 0; }
576 if(mshdrtex) { glDeleteTextures(1, &mshdrtex); mshdrtex = 0; }
577 if(msrefractfbo) { glDeleteFramebuffers_(1, &msrefractfbo); msrefractfbo = 0; }
578 if(msrefracttex) { glDeleteTextures(1, &msrefracttex); msrefracttex = 0; }
579 msaacolorsamples = 0;
580 }
581
bindmsdepth()582 void bindmsdepth()
583 {
584 if(gdepthformat)
585 {
586 glFramebufferRenderbuffer_(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, msdepthrb);
587 if(ghasstencil > 1) glFramebufferRenderbuffer_(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, msdepthrb);
588 else if(ghasstencil) glFramebufferRenderbuffer_(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, msstencilrb);
589 }
590 else
591 {
592 glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D_MULTISAMPLE, msdepthtex, 0);
593 if(ghasstencil > 1) glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D_MULTISAMPLE, msdepthtex, 0);
594 else if(ghasstencil) glFramebufferRenderbuffer_(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, msstencilrb);
595 }
596 }
597
texms(GLenum format,int w,int h)598 static void texms(GLenum format, int w, int h)
599 {
600 if(msaacolorsamples < msaasamples)
601 glTexImage2DMultisampleCoverageNV_(GL_TEXTURE_2D_MULTISAMPLE, msaasamples, msaacolorsamples, format, w, h, GL_TRUE);
602 else
603 glTexImage2DMultisample_(GL_TEXTURE_2D_MULTISAMPLE, msaasamples, format, w, h, GL_TRUE);
604 }
605
rbms(GLenum format,int w,int h)606 static void rbms(GLenum format, int w, int h)
607 {
608 if(msaacolorsamples < msaasamples)
609 glRenderbufferStorageMultisampleCoverageNV_(GL_RENDERBUFFER, msaasamples, msaacolorsamples, format, w, h);
610 else
611 glRenderbufferStorageMultisample_(GL_RENDERBUFFER, msaasamples, format, w, h);
612 }
613
setupmsbuffer(int w,int h)614 void setupmsbuffer(int w, int h)
615 {
616 if(!msdepthtex) glGenTextures(1, &msdepthtex);
617 if(!mshdrtex) glGenTextures(1, &mshdrtex);
618 if(!mshdrfbo) glGenFramebuffers_(1, &mshdrfbo);
619
620 glBindFramebuffer_(GL_FRAMEBUFFER, mshdrfbo);
621
622 stencilformat = ghasstencil > 1 ? GL_DEPTH24_STENCIL8 : (ghasstencil ? GL_STENCIL_INDEX8 : 0);
623
624 if(gdepthformat)
625 {
626 if(!msdepthrb) glGenRenderbuffers_(1, &msdepthrb);
627 glBindRenderbuffer_(GL_RENDERBUFFER, msdepthrb);
628 rbms(ghasstencil > 1 ? stencilformat : GL_DEPTH_COMPONENT, w, h);
629 glBindRenderbuffer_(GL_RENDERBUFFER, 0);
630 }
631 if(ghasstencil == 1)
632 {
633 if(!msstencilrb) glGenRenderbuffers_(1, &msstencilrb);
634 glBindRenderbuffer_(GL_RENDERBUFFER, msstencilrb);
635 rbms(GL_STENCIL_INDEX8, w, h);
636 glBindRenderbuffer_(GL_RENDERBUFFER, 0);
637 }
638
639 static const GLenum depthformats[] = { GL_RGBA8, GL_R16F, GL_R32F };
640 GLenum depthformat = gdepthformat ? depthformats[gdepthformat-1] : (ghasstencil > 1 ? stencilformat : GL_DEPTH_COMPONENT);
641 glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msdepthtex);
642 texms(depthformat, w, h);
643
644 bindmsdepth();
645
646 hdrformat = 0;
647 for(int prec = hdrprec; prec >= 0; prec--)
648 {
649 GLenum format = gethdrformat(prec);
650 glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mshdrtex);
651 glGetError();
652 texms(format, w, h);
653 if(glGetError() == GL_NO_ERROR)
654 {
655 glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, mshdrtex, 0);
656 if(glCheckFramebufferStatus_(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE)
657 {
658 hdrformat = format;
659 break;
660 }
661 }
662 }
663
664 if(!hdrformat || glCheckFramebufferStatus_(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
665 fatal("failed allocating MSAA HDR buffer!");
666
667 if(!mscolortex) glGenTextures(1, &mscolortex);
668 if(!msnormaltex) glGenTextures(1, &msnormaltex);
669 if(!msglowtex) glGenTextures(1, &msglowtex);
670 if(!msfbo) glGenFramebuffers_(1, &msfbo);
671
672 glBindFramebuffer_(GL_FRAMEBUFFER, msfbo);
673
674 maskgbuffer("cndg");
675
676 glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mscolortex);
677 texms(GL_RGBA8, w, h);
678 glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msnormaltex);
679 texms(GL_RGBA8, w, h);
680 glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msglowtex);
681 texms(hasAFBO ? hdrformat : GL_RGBA8, w, h);
682
683 bindmsdepth();
684 glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, mscolortex, 0);
685 glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D_MULTISAMPLE, msnormaltex, 0);
686 glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D_MULTISAMPLE, msglowtex, 0);
687 if(gdepthformat) glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D_MULTISAMPLE, msdepthtex, 0);
688
689 if(glCheckFramebufferStatus_(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
690 {
691 if(hasAFBO)
692 {
693 glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msglowtex);
694 texms(hasAFBO ? hdrformat : GL_RGBA8, w, h);
695 glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D_MULTISAMPLE, msglowtex, 0);
696 if(glCheckFramebufferStatus_(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
697 fatal("failed allocating MSAA g-buffer!");
698 }
699 else fatal("failed allocating MSAA g-buffer!");
700 }
701
702 glClearColor(0, 0, 0, 0);
703 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | (ghasstencil ? GL_STENCIL_BUFFER_BIT : 0));
704
705 msaapositions.setsize(0);
706 loopi(msaasamples)
707 {
708 GLfloat vals[2];
709 glGetMultisamplefv_(GL_SAMPLE_POSITION, i, vals);
710 msaapositions.add(vec2(vals[0], vals[1]));
711 }
712
713 if(!msrefracttex) glGenTextures(1, &msrefracttex);
714 if(!msrefractfbo) glGenFramebuffers_(1, &msrefractfbo);
715
716 glBindFramebuffer_(GL_FRAMEBUFFER, msrefractfbo);
717
718 glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msrefracttex);
719 texms(GL_RGB, w, h);
720
721 glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, msrefracttex, 0);
722 bindmsdepth();
723
724 if(glCheckFramebufferStatus_(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
725 fatal("failed allocating MSAA refraction buffer!");
726
727 glBindFramebuffer_(GL_FRAMEBUFFER, 0);
728
729 useshaderbyname("msaaedgedetect");
730 useshaderbyname("msaaresolve");
731 useshaderbyname("msaareducew");
732 useshaderbyname("msaareduce");
733 if((hasMSS || msaasamples==2) && msaatonemap)
734 {
735 useshaderbyname("msaatonemap");
736 if(hasMSS) useshaderbyname("msaatonemapsample");
737 }
738 }
739
bindgdepth()740 void bindgdepth()
741 {
742 if(gdepthformat || msaasamples)
743 {
744 glFramebufferRenderbuffer_(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, gdepthrb);
745 if(ghasstencil > 1) glFramebufferRenderbuffer_(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, gdepthrb);
746 else if(!msaasamples || ghasstencil) glFramebufferRenderbuffer_(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, gstencilrb);
747 }
748 else
749 {
750 glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_RECTANGLE, gdepthtex, 0);
751 if(ghasstencil > 1) glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_RECTANGLE, gdepthtex, 0);
752 else if(ghasstencil) glFramebufferRenderbuffer_(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, gstencilrb);
753 }
754 }
755
setupgbuffer()756 void setupgbuffer()
757 {
758 int sw = renderw, sh = renderh;
759 if(gscale != 100)
760 {
761 sw = max((renderw*gscale + 99)/100, 1);
762 sh = max((renderh*gscale + 99)/100, 1);
763 }
764
765 if(gw == sw && gh == sh && ((sw >= hudw && sh >= hudh && !scalefbo[0]) || (scalew == hudw && scaleh == hudh))) return;
766
767 cleanupscale();
768 cleanupbloom();
769 cleanupao();
770 cleanupaa();
771 cleanuppostfx();
772
773 gw = sw;
774 gh = sh;
775
776 hdrformat = gethdrformat(hdrprec);
777 stencilformat = ghasstencil > 1 ? GL_DEPTH24_STENCIL8 : (ghasstencil ? GL_STENCIL_INDEX8 : 0);
778
779 if(msaasamples) setupmsbuffer(gw, gh);
780
781 hdrfloat = floatformat(hdrformat);
782 hdrclear = 3;
783 gdepthinit = false;
784
785 if(gdepthformat || msaasamples)
786 {
787 if(!gdepthrb) glGenRenderbuffers_(1, &gdepthrb);
788 glBindRenderbuffer_(GL_RENDERBUFFER, gdepthrb);
789 glRenderbufferStorage_(GL_RENDERBUFFER, ghasstencil > 1 ? stencilformat : GL_DEPTH_COMPONENT, gw, gh);
790 glBindRenderbuffer_(GL_RENDERBUFFER, 0);
791 }
792 if(!msaasamples && ghasstencil == 1)
793 {
794 if(!gstencilrb) glGenRenderbuffers_(1, &gstencilrb);
795 glBindRenderbuffer_(GL_RENDERBUFFER, gstencilrb);
796 glRenderbufferStorage_(GL_RENDERBUFFER, GL_STENCIL_INDEX8, gw, gh);
797 glBindRenderbuffer_(GL_RENDERBUFFER, 0);
798 }
799
800 if(!msaasamples)
801 {
802 if(!gdepthtex) glGenTextures(1, &gdepthtex);
803 if(!gcolortex) glGenTextures(1, &gcolortex);
804 if(!gnormaltex) glGenTextures(1, &gnormaltex);
805 if(!gglowtex) glGenTextures(1, &gglowtex);
806 if(!gfbo) glGenFramebuffers_(1, &gfbo);
807
808 glBindFramebuffer_(GL_FRAMEBUFFER, gfbo);
809
810 maskgbuffer("cndg");
811
812 static const GLenum depthformats[] = { GL_RGBA8, GL_R16F, GL_R32F };
813 GLenum depthformat = gdepthformat ? depthformats[gdepthformat-1] : (ghasstencil > 1 ? stencilformat : GL_DEPTH_COMPONENT);
814 createtexture(gdepthtex, gw, gh, NULL, 3, 0, depthformat, GL_TEXTURE_RECTANGLE);
815
816 createtexture(gcolortex, gw, gh, NULL, 3, 0, GL_RGBA8, GL_TEXTURE_RECTANGLE);
817 createtexture(gnormaltex, gw, gh, NULL, 3, 0, GL_RGBA8, GL_TEXTURE_RECTANGLE);
818 createtexture(gglowtex, gw, gh, NULL, 3, 0, hasAFBO ? hdrformat : GL_RGBA8, GL_TEXTURE_RECTANGLE);
819
820 bindgdepth();
821 glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, gcolortex, 0);
822 glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_RECTANGLE, gnormaltex, 0);
823 glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_RECTANGLE, gglowtex, 0);
824 if(gdepthformat) glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_RECTANGLE, gdepthtex, 0);
825
826 if(glCheckFramebufferStatus_(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
827 {
828 if(hasAFBO)
829 {
830 createtexture(gglowtex, gw, gh, NULL, 3, 0, GL_RGBA8, GL_TEXTURE_RECTANGLE);
831 glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_RECTANGLE, gglowtex, 0);
832 if(glCheckFramebufferStatus_(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
833 fatal("failed allocating g-buffer!");
834 }
835 else fatal("failed allocating g-buffer!");
836 }
837
838 glClearColor(0, 0, 0, 0);
839 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | (ghasstencil ? GL_STENCIL_BUFFER_BIT : 0));
840 }
841
842 if(!hdrtex) glGenTextures(1, &hdrtex);
843 if(!hdrfbo) glGenFramebuffers_(1, &hdrfbo);
844
845 glBindFramebuffer_(GL_FRAMEBUFFER, hdrfbo);
846
847 createtexture(hdrtex, gw, gh, NULL, 3, 1, hdrformat, GL_TEXTURE_RECTANGLE);
848
849 glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, hdrtex, 0);
850 bindgdepth();
851
852 if(glCheckFramebufferStatus_(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
853 fatal("failed allocating HDR buffer!");
854
855 if(!msaasamples || (hasMSS && msaatonemap && msaatonemapblit))
856 {
857 if(!refracttex) glGenTextures(1, &refracttex);
858 if(!refractfbo) glGenFramebuffers_(1, &refractfbo);
859
860 glBindFramebuffer_(GL_FRAMEBUFFER, refractfbo);
861
862 createtexture(refracttex, gw, gh, NULL, 3, 0, GL_RGB, GL_TEXTURE_RECTANGLE);
863
864 glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, refracttex, 0);
865 bindgdepth();
866
867 if(glCheckFramebufferStatus_(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
868 fatal("failed allocating refraction buffer!");
869 }
870
871 glBindFramebuffer_(GL_FRAMEBUFFER, 0);
872
873 if(gw < hudw || gh < hudh) setupscale(gw, gh, hudw, hudh);
874 }
875
cleanupgbuffer()876 void cleanupgbuffer()
877 {
878 if(gfbo) { glDeleteFramebuffers_(1, &gfbo); gfbo = 0; }
879 if(gdepthtex) { glDeleteTextures(1, &gdepthtex); gdepthtex = 0; }
880 if(gcolortex) { glDeleteTextures(1, &gcolortex); gcolortex = 0; }
881 if(gnormaltex) { glDeleteTextures(1, &gnormaltex); gnormaltex = 0; }
882 if(gglowtex) { glDeleteTextures(1, &gglowtex); gglowtex = 0; }
883 if(gstencilrb) { glDeleteRenderbuffers_(1, &gstencilrb); gstencilrb = 0; }
884 if(gdepthrb) { glDeleteRenderbuffers_(1, &gdepthrb); gdepthrb = 0; }
885 if(hdrfbo) { glDeleteFramebuffers_(1, &hdrfbo); hdrfbo = 0; }
886 if(hdrtex) { glDeleteTextures(1, &hdrtex); hdrtex = 0; }
887 if(refractfbo) { glDeleteFramebuffers_(1, &refractfbo); refractfbo = 0; }
888 if(refracttex) { glDeleteTextures(1, &refracttex); refracttex = 0; }
889 gw = gh = -1;
890 cleanupscale();
891 cleanupmsbuffer();
892 cleardeferredlightshaders();
893 }
894
resolvemsaacolor(int w=vieww,int h=viewh)895 void resolvemsaacolor(int w = vieww, int h = viewh)
896 {
897 if(!msaasamples) return;
898
899 timer *resolvetimer = drawtex ? NULL : begintimer("msaa resolve");
900
901 glBindFramebuffer_(GL_READ_FRAMEBUFFER, mshdrfbo);
902 glBindFramebuffer_(GL_DRAW_FRAMEBUFFER, hdrfbo);
903 glBlitFramebuffer_(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
904
905 glBindFramebuffer_(GL_FRAMEBUFFER, hdrfbo);
906
907 endtimer(resolvetimer);
908 }
909
910 FVAR(bloomthreshold, 1e-3f, 0.8f, 1e3f);
911 FVARP(bloomscale, 0, 1.0f, 1e3f);
912 VARP(bloomblur, 0, 7, 7);
913 VARP(bloomiter, 0, 0, 4);
914 VARFP(bloomsize, 6, 9, 11, cleanupbloom());
915 VARFP(bloomprec, 0, 2, 3, cleanupbloom());
916 FVAR(hdraccumscale, 0, 0.98f, 1);
917 VAR(hdraccummillis, 1, 33, 1000);
918 VAR(hdrreduce, 0, 2, 2);
919 VARFP(hdrprec, 0, 2, 3, cleanupgbuffer());
920 FVARFP(hdrgamma, 1e-3f, 2, 1e3f, initwarning("HDR setup", INIT_LOAD, CHANGE_SHADERS));
921 FVARR(hdrbright, 1e-4f, 1.0f, 1e4f);
922 FVAR(hdrsaturate, 1e-3f, 0.8f, 1e3f);
923 VARFP(gscale, 25, 100, 100, cleanupgbuffer());
924 VARFP(gscalecubic, 0, 0, 1, cleanupgbuffer());
925 VARFP(gscalenearest, 0, 0, 1, cleanupgbuffer());
926 FVARFP(gscalecubicsoft, 0, 0, 1, initwarning("scaling setup", INIT_LOAD, CHANGE_SHADERS));
927
928 float ldrscale = 1.0f, ldrscaleb = 1.0f/255;
929
copyhdr(int sw,int sh,GLuint fbo,int dw,int dh,bool flipx,bool flipy,bool swapxy)930 void copyhdr(int sw, int sh, GLuint fbo, int dw, int dh, bool flipx, bool flipy, bool swapxy)
931 {
932 if(!dw) dw = sw;
933 if(!dh) dh = sh;
934
935 if(msaasamples) resolvemsaacolor(sw, sh);
936 GLERROR;
937
938 glBindFramebuffer_(GL_FRAMEBUFFER, fbo);
939 glViewport(0, 0, dw, dh);
940 SETSHADER(hdrnop);
941 glBindTexture(GL_TEXTURE_RECTANGLE, hdrtex);
942 screenquadreorient(sw, sh, flipx, flipy, swapxy);
943 GLERROR;
944
945 hdrclear = 3;
946 }
947
loadhdrshaders(int aa)948 void loadhdrshaders(int aa)
949 {
950 switch(aa)
951 {
952 case AA_LUMA:
953 useshaderbyname("hdrtonemapluma");
954 useshaderbyname("hdrnopluma");
955 if(msaasamples && (hasMSS || msaasamples==2) && msaatonemap) useshaderbyname("msaatonemapluma");
956 break;
957 case AA_VELOCITY:
958 useshaderbyname("hdrtonemapvelocity");
959 useshaderbyname("hdrnopvelocity");
960 if(msaasamples && (hasMSS || msaasamples==2) && msaatonemap) useshaderbyname("msaatonemapvelocity");
961 break;
962 case AA_VELOCITY_MASKED:
963 if(!msaasamples && ghasstencil) useshaderbyname("hdrtonemapvelocity");
964 else
965 {
966 useshaderbyname("hdrtonemapvelocitymasked");
967 useshaderbyname("hdrnopvelocitymasked");
968 if(msaasamples && (hasMSS || msaasamples==2) && msaatonemap) useshaderbyname("msaatonemapvelocitymasked");
969 }
970 break;
971 case AA_SPLIT:
972 useshaderbyname("msaatonemapsplit");
973 break;
974 case AA_SPLIT_LUMA:
975 useshaderbyname("msaatonemapsplitluma");
976 break;
977 case AA_SPLIT_VELOCITY:
978 useshaderbyname("msaatonemapsplitvelocity");
979 break;
980 case AA_SPLIT_VELOCITY_MASKED:
981 useshaderbyname("msaatonemapsplitvelocitymasked");
982 break;
983 default:
984 break;
985 }
986 }
987
processhdr(GLuint outfbo,int aa)988 void processhdr(GLuint outfbo, int aa)
989 {
990 timer *hdrtimer = begintimer("hdr processing");
991
992 GLOBALPARAMF(hdrparams, hdrbright, hdrsaturate, bloomthreshold, bloomscale);
993
994 GLuint b0fbo = bloomfbo[1], b0tex = bloomtex[1], b1fbo = bloomfbo[0], b1tex = bloomtex[0], ptex = hdrtex;
995 int b0w = max(vieww/4, bloomw), b0h = max(viewh/4, bloomh), b1w = max(vieww/2, bloomw), b1h = max(viewh/2, bloomh),
996 pw = vieww, ph = viewh;
997 if(msaasamples)
998 {
999 if(aa < AA_SPLIT && (!(hasMSS || msaasamples==2) || !msaatonemap))
1000 {
1001 glBindFramebuffer_(GL_READ_FRAMEBUFFER, mshdrfbo);
1002 glBindFramebuffer_(GL_DRAW_FRAMEBUFFER, hdrfbo);
1003 glBlitFramebuffer_(0, 0, vieww, viewh, 0, 0, vieww, viewh, GL_COLOR_BUFFER_BIT, GL_NEAREST);
1004 }
1005 else if(hasFBMSBS && (vieww > bloomw || viewh > bloomh))
1006 {
1007 int cw = max(vieww/2, bloomw), ch = max(viewh/2, bloomh);
1008 glBindFramebuffer_(GL_READ_FRAMEBUFFER, mshdrfbo);
1009 glBindFramebuffer_(GL_DRAW_FRAMEBUFFER, hdrfbo);
1010 glBlitFramebuffer_(0, 0, vieww, viewh, 0, 0, cw, ch, GL_COLOR_BUFFER_BIT, GL_SCALED_RESOLVE_FASTEST_EXT);
1011 pw = cw;
1012 ph = ch;
1013 }
1014 else
1015 {
1016 glBindFramebuffer_(GL_FRAMEBUFFER, hdrfbo);
1017 if(vieww/2 >= bloomw)
1018 {
1019 pw = vieww/2;
1020 if(viewh/2 >= bloomh)
1021 {
1022 ph = viewh/2;
1023 glViewport(0, 0, pw, ph);
1024 SETSHADER(msaareduce);
1025 }
1026 else
1027 {
1028 glViewport(0, 0, pw, viewh);
1029 SETSHADER(msaareducew);
1030 }
1031 }
1032 else
1033 {
1034 glViewport(0, 0, vieww, viewh);
1035 SETSHADER(msaaresolve);
1036 }
1037 glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mshdrtex);
1038 screenquad(vieww, viewh);
1039 }
1040 }
1041 if(hdrreduce) while(pw > bloomw || ph > bloomh)
1042 {
1043 GLuint cfbo = b1fbo, ctex = b1tex;
1044 int cw = max(pw/2, bloomw), ch = max(ph/2, bloomh);
1045
1046 if(hdrreduce > 1 && cw/2 >= bloomw)
1047 {
1048 cw /= 2;
1049 if(ch/2 >= bloomh)
1050 {
1051 ch /= 2;
1052 SETSHADER(hdrreduce2);
1053 }
1054 else SETSHADER(hdrreduce2w);
1055 }
1056 else SETSHADER(hdrreduce);
1057 if(cw == bloomw && ch == bloomh) { if(bloomfbo[5]) { cfbo = bloomfbo[5]; ctex = bloomtex[5]; } else { cfbo = bloomfbo[2]; ctex = bloomtex[2]; } }
1058 glBindFramebuffer_(GL_FRAMEBUFFER, cfbo);
1059 glViewport(0, 0, cw, ch);
1060 glBindTexture(GL_TEXTURE_RECTANGLE, ptex);
1061 screenquad(pw, ph);
1062
1063 ptex = ctex;
1064 pw = cw;
1065 ph = ch;
1066 swap(b0fbo, b1fbo);
1067 swap(b0tex, b1tex);
1068 swap(b0w, b1w);
1069 swap(b0h, b1h);
1070 }
1071
1072 if(!lasthdraccum || lastmillis - lasthdraccum >= hdraccummillis)
1073 {
1074 GLuint ltex = ptex;
1075 int lw = pw, lh = ph;
1076 for(int i = 0; lw > 2 || lh > 2; i++)
1077 {
1078 int cw = max(lw/2, 2), ch = max(lh/2, 2);
1079
1080 if(hdrreduce > 1 && cw/2 >= 2)
1081 {
1082 cw /= 2;
1083 if(ch/2 >= 2)
1084 {
1085 ch /= 2;
1086 if(i) SETSHADER(hdrreduce2); else SETSHADER(hdrluminance2);
1087 }
1088 else if(i) SETSHADER(hdrreduce2w); else SETSHADER(hdrluminance2w);
1089 }
1090 else if(i) SETSHADER(hdrreduce); else SETSHADER(hdrluminance);
1091 glBindFramebuffer_(GL_FRAMEBUFFER, b1fbo);
1092 glViewport(0, 0, cw, ch);
1093 glBindTexture(GL_TEXTURE_RECTANGLE, ltex);
1094 screenquad(lw, lh);
1095
1096 ltex = b1tex;
1097 lw = cw;
1098 lh = ch;
1099 swap(b0fbo, b1fbo);
1100 swap(b0tex, b1tex);
1101 swap(b0w, b1w);
1102 swap(b0h, b1h);
1103 }
1104
1105 glBindFramebuffer_(GL_FRAMEBUFFER, bloomfbo[4]);
1106 glViewport(0, 0, bloompbo ? 4 : 1, 1);
1107 glEnable(GL_BLEND);
1108 glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
1109 SETSHADER(hdraccum);
1110 glBindTexture(GL_TEXTURE_RECTANGLE, b0tex);
1111 LOCALPARAMF(accumscale, lasthdraccum ? pow(hdraccumscale, float(lastmillis - lasthdraccum)/hdraccummillis) : 0);
1112 screenquad(2, 2);
1113 glDisable(GL_BLEND);
1114
1115 if(bloompbo)
1116 {
1117 glBindBuffer_(GL_PIXEL_PACK_BUFFER, bloompbo);
1118 glPixelStorei(GL_PACK_ALIGNMENT, 1);
1119 glReadPixels(0, 0, 4, 1, hasTRG ? GL_RED : GL_RGB, hasTF ? GL_FLOAT : GL_UNSIGNED_SHORT, NULL);
1120 glBindBuffer_(GL_PIXEL_PACK_BUFFER, 0);
1121 }
1122
1123 lasthdraccum = lastmillis;
1124 }
1125
1126 if(bloompbo)
1127 {
1128 glBindBuffer_(GL_ARRAY_BUFFER, bloompbo);
1129 gle::enablecolor();
1130 gle::colorpointer(hasTF ? sizeof(GLfloat) : sizeof(GLushort), (void *)0, hasTF ? GL_FLOAT : GL_UNSIGNED_SHORT, 1);
1131 glBindBuffer_(GL_ARRAY_BUFFER, 0);
1132 }
1133
1134 b0fbo = bloomfbo[3];
1135 b0tex = bloomtex[3];
1136 b1fbo = bloomfbo[2];
1137 b1tex = bloomtex[2];
1138 b0w = b1w = bloomw;
1139 b0h = b1h = bloomh;
1140
1141 glActiveTexture_(GL_TEXTURE2);
1142 glBindTexture(GL_TEXTURE_2D, bloomtex[4]);
1143 glActiveTexture_(GL_TEXTURE0);
1144
1145 glBindFramebuffer_(GL_FRAMEBUFFER, b0fbo);
1146 glViewport(0, 0, b0w, b0h);
1147 SETSHADER(hdrbloom);
1148 glBindTexture(GL_TEXTURE_RECTANGLE, ptex);
1149 screenquad(pw, ph);
1150
1151 if(bloomblur)
1152 {
1153 float blurweights[MAXBLURRADIUS+1], bluroffsets[MAXBLURRADIUS+1];
1154 setupblurkernel(bloomblur, blurweights, bluroffsets);
1155 loopi(2 + 2*bloomiter)
1156 {
1157 glBindFramebuffer_(GL_FRAMEBUFFER, b1fbo);
1158 glViewport(0, 0, b1w, b1h);
1159 setblurshader(i%2, 1, bloomblur, blurweights, bluroffsets, GL_TEXTURE_RECTANGLE);
1160 glBindTexture(GL_TEXTURE_RECTANGLE, b0tex);
1161 screenquad(b0w, b0h);
1162 swap(b0w, b1w);
1163 swap(b0h, b1h);
1164 swap(b0tex, b1tex);
1165 swap(b0fbo, b1fbo);
1166 }
1167 }
1168
1169 if(aa >= AA_SPLIT)
1170 {
1171 glBindFramebuffer_(GL_FRAMEBUFFER, outfbo);
1172 glViewport(0, 0, vieww, viewh);
1173 glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mshdrtex);
1174 glActiveTexture_(GL_TEXTURE1);
1175 glBindTexture(GL_TEXTURE_RECTANGLE, b0tex);
1176 glActiveTexture_(GL_TEXTURE0);
1177 switch(aa)
1178 {
1179 case AA_SPLIT_LUMA: SETSHADER(msaatonemapsplitluma); break;
1180 case AA_SPLIT_VELOCITY:
1181 SETSHADER(msaatonemapsplitvelocity);
1182 setaavelocityparams(GL_TEXTURE3);
1183 break;
1184 case AA_SPLIT_VELOCITY_MASKED:
1185 SETSHADER(msaatonemapsplitvelocitymasked);
1186 setaavelocityparams(GL_TEXTURE3);
1187 break;
1188 default: SETSHADER(msaatonemapsplit); break;
1189 }
1190 screenquad(vieww, viewh, b0w, b0h);
1191 }
1192 else if(!msaasamples || !(hasMSS || msaasamples==2) || !msaatonemap)
1193 {
1194 glBindFramebuffer_(GL_FRAMEBUFFER, outfbo);
1195 glViewport(0, 0, vieww, viewh);
1196 glBindTexture(GL_TEXTURE_RECTANGLE, hdrtex);
1197 glActiveTexture_(GL_TEXTURE1);
1198 glBindTexture(GL_TEXTURE_RECTANGLE, b0tex);
1199 glActiveTexture_(GL_TEXTURE0);
1200 switch(aa)
1201 {
1202 case AA_LUMA: SETSHADER(hdrtonemapluma); break;
1203 case AA_VELOCITY:
1204 SETSHADER(hdrtonemapvelocity);
1205 setaavelocityparams(GL_TEXTURE3);
1206 break;
1207 case AA_VELOCITY_MASKED:
1208 if(!msaasamples && ghasstencil)
1209 {
1210 glStencilFunc(GL_EQUAL, 0, 0x80);
1211 glEnable(GL_STENCIL_TEST);
1212 SETSHADER(hdrtonemapvelocity);
1213 setaavelocityparams(GL_TEXTURE3);
1214 screenquad(vieww, viewh, b0w, b0h);
1215
1216 glStencilFunc(GL_EQUAL, 0x80, 0x80);
1217 SETSHADER(hdrtonemap);
1218 screenquad(vieww, viewh, b0w, b0h);
1219 glDisable(GL_STENCIL_TEST);
1220 goto done;
1221 }
1222 SETSHADER(hdrtonemapvelocitymasked);
1223 setaavelocityparams(GL_TEXTURE3);
1224 break;
1225 default: SETSHADER(hdrtonemap); break;
1226 }
1227 screenquad(vieww, viewh, b0w, b0h);
1228 }
1229 else
1230 {
1231 bool blit = hasMSS && msaatonemapblit && (!aa || !outfbo);
1232
1233 glBindFramebuffer_(GL_FRAMEBUFFER, blit ? msrefractfbo : outfbo);
1234 glViewport(0, 0, vieww, viewh);
1235 glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mshdrtex);
1236 glActiveTexture_(GL_TEXTURE1);
1237 glBindTexture(GL_TEXTURE_RECTANGLE, b0tex);
1238 glActiveTexture_(GL_TEXTURE0);
1239
1240 if(blit) SETSHADER(msaatonemapsample);
1241 else switch(aa)
1242 {
1243 case AA_LUMA: SETSHADER(msaatonemapluma); break;
1244 case AA_VELOCITY:
1245 SETSHADER(msaatonemapvelocity);
1246 setaavelocityparams(GL_TEXTURE3);
1247 break;
1248 case AA_VELOCITY_MASKED:
1249 SETSHADER(msaatonemapvelocitymasked);
1250 setaavelocityparams(GL_TEXTURE3);
1251 break;
1252 default: SETSHADER(msaatonemap); break;
1253 }
1254 screenquad(vieww, viewh, b0w, b0h);
1255
1256 if(blit)
1257 {
1258 glBindFramebuffer_(GL_READ_FRAMEBUFFER, msrefractfbo);
1259 glBindFramebuffer_(GL_DRAW_FRAMEBUFFER, aa || !outfbo ? refractfbo : outfbo);
1260 glBlitFramebuffer_(0, 0, vieww, viewh, 0, 0, vieww, viewh, GL_COLOR_BUFFER_BIT, GL_NEAREST);
1261
1262 if(!outfbo)
1263 {
1264 glBindFramebuffer_(GL_FRAMEBUFFER, outfbo);
1265 glViewport(0, 0, vieww, viewh);
1266 if(!blit) SETSHADER(hdrnop);
1267 else switch(aa)
1268 {
1269 case AA_LUMA: SETSHADER(hdrnopluma); break;
1270 case AA_VELOCITY:
1271 SETSHADER(hdrnopvelocity);
1272 setaavelocityparams(GL_TEXTURE3);
1273 break;
1274 case AA_VELOCITY_MASKED:
1275 SETSHADER(hdrnopvelocitymasked);
1276 setaavelocityparams(GL_TEXTURE3);
1277 break;
1278 default: SETSHADER(hdrnop); break;
1279 }
1280 glBindTexture(GL_TEXTURE_RECTANGLE, refracttex);
1281 screenquad(vieww, viewh);
1282 }
1283 }
1284 }
1285
1286 done:
1287 if(bloompbo) gle::disablecolor();
1288
1289 endtimer(hdrtimer);
1290 }
1291
1292 VAR(debugdepth, 0, 0, 1);
1293
viewdepth()1294 void viewdepth()
1295 {
1296 int w = min(hudw, hudh)/2, h = (w*hudh)/hudw;
1297 SETSHADER(hudrect);
1298 gle::colorf(1, 1, 1);
1299 glBindTexture(GL_TEXTURE_RECTANGLE, gdepthtex);
1300 debugquad(0, 0, w, h, 0, 0, gw, gh);
1301 }
1302
1303 VAR(debugstencil, 0, 0, 0xFF);
1304
viewstencil()1305 void viewstencil()
1306 {
1307 if(!ghasstencil || !hdrfbo) return;
1308 glBindFramebuffer_(GL_FRAMEBUFFER, hdrfbo);
1309 glViewport(0, 0, gw, gh);
1310
1311 glClearColor(0, 0, 0, 0);
1312 glClear(GL_COLOR_BUFFER_BIT);
1313
1314 glStencilFunc(GL_NOTEQUAL, 0, debugstencil);
1315 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1316 glEnable(GL_STENCIL_TEST);
1317 SETSHADER(hudnotexture);
1318 gle::colorf(1, 1, 1);
1319 debugquad(0, 0, hudw, hudh, 0, 0, gw, gh);
1320 glDisable(GL_STENCIL_TEST);
1321
1322 glBindFramebuffer_(GL_FRAMEBUFFER, 0);
1323 glViewport(0, 0, hudw, hudh);
1324
1325 int w = min(hudw, hudh)/2, h = (w*hudh)/hudw;
1326 SETSHADER(hudrect);
1327 gle::colorf(1, 1, 1);
1328 glBindTexture(GL_TEXTURE_RECTANGLE, hdrtex);
1329 debugquad(0, 0, w, h, 0, 0, gw, gh);
1330 }
1331
1332 VAR(debugrefract, 0, 0, 1);
1333
viewrefract()1334 void viewrefract()
1335 {
1336 int w = min(hudw, hudh)/2, h = (w*hudh)/hudw;
1337 SETSHADER(hudrect);
1338 gle::colorf(1, 1, 1);
1339 glBindTexture(GL_TEXTURE_RECTANGLE, refracttex);
1340 debugquad(0, 0, w, h, 0, 0, gw, gh);
1341 }
1342
1343 #define RH_MAXSPLITS 4
1344 #define RH_MAXGRID 64
1345
1346 GLuint rhtex[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }, rhfbo = 0;
1347 uint rhclearmasks[2][RH_MAXSPLITS][(RH_MAXGRID+2+31)/32];
1348 GLuint rsmdepthtex = 0, rsmcolortex = 0, rsmnormaltex = 0, rsmfbo = 0;
1349
1350 extern int rhrect, rhgrid, rhsplits, rhborder, rhprec, rhtaps, rhcache, rhforce, rsmprec, rsmdepthprec, rsmsize;
1351
1352 static Shader *radiancehintsshader = NULL;
1353 Shader *rsmworldshader = NULL;
1354
loadradiancehintsshader()1355 Shader *loadradiancehintsshader()
1356 {
1357 defformatstring(name, "radiancehints%d", rhtaps);
1358 return generateshader(name, "radiancehintsshader %d", rhtaps);
1359 }
1360
loadrhshaders()1361 void loadrhshaders()
1362 {
1363 if(rhborder) useshaderbyname("radiancehintsborder");
1364 if(rhcache) useshaderbyname("radiancehintscached");
1365 useshaderbyname("radiancehintsdisable");
1366 radiancehintsshader = loadradiancehintsshader();
1367 rsmworldshader = useshaderbyname("rsmworld");
1368 useshaderbyname("rsmsky");
1369 }
1370
clearrhshaders()1371 void clearrhshaders()
1372 {
1373 radiancehintsshader = NULL;
1374 rsmworldshader = NULL;
1375 }
1376
setupradiancehints()1377 void setupradiancehints()
1378 {
1379 GLenum rhformat = hasTF && rhprec >= 1 ? GL_RGBA16F : GL_RGBA8;
1380
1381 loopi(!rhrect && rhcache ? 8 : 4)
1382 {
1383 if(!rhtex[i]) glGenTextures(1, &rhtex[i]);
1384 create3dtexture(rhtex[i], rhgrid+2*rhborder, rhgrid+2*rhborder, (rhgrid+2*rhborder)*rhsplits, NULL, 7, 1, rhformat);
1385 if(rhborder)
1386 {
1387 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
1388 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
1389 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER);
1390 GLfloat border[4] = { 0.5f, 0.5f, 0.5f, 0 };
1391 glTexParameterfv(GL_TEXTURE_3D, GL_TEXTURE_BORDER_COLOR, border);
1392 }
1393 }
1394
1395 if(!rhfbo) glGenFramebuffers_(1, &rhfbo);
1396 glBindFramebuffer_(GL_FRAMEBUFFER, rhfbo);
1397
1398 if(rhrect) loopi(4)
1399 {
1400 if(!rhtex[4+i]) glGenTextures(1, &rhtex[4+i]);
1401 createtexture(rhtex[4+i], (rhgrid + 2*rhborder)*(rhgrid + 2*rhborder), (rhgrid + 2*rhborder)*rhsplits, NULL, 3, 0, rhformat, GL_TEXTURE_RECTANGLE);
1402 glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_RECTANGLE, rhtex[4+i], 0);
1403 }
1404 else loopi(4) glFramebufferTexture3D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_3D, rhtex[i], 0, 0);
1405
1406 static const GLenum drawbufs[4] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3 };
1407 glDrawBuffers_(4, drawbufs);
1408
1409 if(glCheckFramebufferStatus_(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
1410 fatal("failed allocating radiance hints buffer!");
1411
1412 if(!rsmdepthtex) glGenTextures(1, &rsmdepthtex);
1413 if(!rsmcolortex) glGenTextures(1, &rsmcolortex);
1414 if(!rsmnormaltex) glGenTextures(1, &rsmnormaltex);
1415
1416 if(!rsmfbo) glGenFramebuffers_(1, &rsmfbo);
1417
1418 glBindFramebuffer_(GL_FRAMEBUFFER, rsmfbo);
1419
1420 GLenum rsmformat = gethdrformat(rsmprec, GL_RGBA8);
1421
1422 createtexture(rsmdepthtex, rsmsize, rsmsize, NULL, 3, 0, rsmdepthprec > 1 ? GL_DEPTH_COMPONENT32 : (rsmdepthprec ? GL_DEPTH_COMPONENT24 : GL_DEPTH_COMPONENT16), GL_TEXTURE_RECTANGLE);
1423 createtexture(rsmcolortex, rsmsize, rsmsize, NULL, 3, 0, rsmformat, GL_TEXTURE_RECTANGLE);
1424 createtexture(rsmnormaltex, rsmsize, rsmsize, NULL, 3, 0, rsmformat, GL_TEXTURE_RECTANGLE);
1425
1426 glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_RECTANGLE, rsmdepthtex, 0);
1427 glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, rsmcolortex, 0);
1428 glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_RECTANGLE, rsmnormaltex, 0);
1429
1430 glDrawBuffers_(2, drawbufs);
1431
1432 if(glCheckFramebufferStatus_(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
1433 fatal("failed allocating RSM buffer!");
1434
1435 glBindFramebuffer_(GL_FRAMEBUFFER, 0);
1436
1437 loadrhshaders();
1438
1439 clearradiancehintscache();
1440 }
1441
cleanupradiancehints()1442 void cleanupradiancehints()
1443 {
1444 clearradiancehintscache();
1445
1446 loopi(8) if(rhtex[i]) { glDeleteTextures(1, &rhtex[i]); rhtex[i] = 0; }
1447 if(rhfbo) { glDeleteFramebuffers_(1, &rhfbo); rhfbo = 0; }
1448 if(rsmdepthtex) { glDeleteTextures(1, &rsmdepthtex); rsmdepthtex = 0; }
1449 if(rsmcolortex) { glDeleteTextures(1, &rsmcolortex); rsmcolortex = 0; }
1450 if(rsmnormaltex) { glDeleteTextures(1, &rsmnormaltex); rsmnormaltex = 0; }
1451 if(rsmfbo) { glDeleteFramebuffers_(1, &rsmfbo); rsmfbo = 0; }
1452
1453 clearrhshaders();
1454 }
1455
1456 VARF(rhrect, 0, 0, 1, cleanupradiancehints());
1457 VARF(rhsplits, 1, 2, RH_MAXSPLITS, { cleardeferredlightshaders(); cleanupradiancehints(); });
1458 VARF(rhborder, 0, 1, 1, cleanupradiancehints());
1459 VARF(rsmsize, 64, 384, 2048, cleanupradiancehints());
1460 VARF(rhnearplane, 1, 1, 16, clearradiancehintscache());
1461 VARF(rhfarplane, 64, 1024, 16384, clearradiancehintscache());
1462 FVARF(rsmpradiustweak, 1e-3f, 1, 1e3f, clearradiancehintscache());
1463 FVARF(rhpradiustweak, 1e-3f, 1, 1e3f, clearradiancehintscache());
1464 FVARF(rsmdepthrange, 0, 1024, 1e6f, clearradiancehintscache());
1465 FVARF(rsmdepthmargin, 0, 0.1f, 1e3f, clearradiancehintscache());
1466 VARFP(rhprec, 0, 0, 1, cleanupradiancehints());
1467 VARFP(rsmprec, 0, 0, 3, cleanupradiancehints());
1468 VARFP(rsmdepthprec, 0, 0, 2, cleanupradiancehints());
1469 FVAR(rhnudge, 0, 0.5f, 4);
1470 FVARF(rhworldbias, 0, 0.5f, 10, clearradiancehintscache());
1471 FVARF(rhsplitweight, 0.20f, 0.6f, 0.95f, clearradiancehintscache());
1472 VARF(rhgrid, 3, 27, RH_MAXGRID, cleanupradiancehints());
1473 FVARF(rsmspread, 0, 0.15f, 1, clearradiancehintscache());
1474 VAR(rhclipgrid, 0, 1, 1);
1475 VARF(rhcache, 0, 1, 1, cleanupradiancehints());
1476 VARF(rhforce, 0, 0, 1, cleanupradiancehints());
1477 VAR(rsmcull, 0, 1, 1);
1478 VARFP(rhtaps, 0, 20, 32, cleanupradiancehints());
1479 VAR(rhdyntex, 0, 0, 1);
1480 VAR(rhdynmm, 0, 0, 1);
1481 VARFR(gidist, 0, 384, 1024, { clearradiancehintscache(); cleardeferredlightshaders(); if(!gidist) cleanupradiancehints(); });
1482 FVARFR(giscale, 0, 1.5f, 1e3f, { cleardeferredlightshaders(); if(!giscale) cleanupradiancehints(); });
1483 FVARR(giaoscale, 0, 3, 1e3f);
1484 VARFP(gi, 0, 1, 1, { cleardeferredlightshaders(); cleanupradiancehints(); });
1485
1486 VAR(debugrsm, 0, 0, 2);
viewrsm()1487 void viewrsm()
1488 {
1489 int w = min(hudw, hudh)/2, h = (w*hudh)/hudw, x = hudw-w, y = hudh-h;
1490 SETSHADER(hudrect);
1491 gle::colorf(1, 1, 1);
1492 glBindTexture(GL_TEXTURE_RECTANGLE, debugrsm == 2 ? rsmnormaltex : rsmcolortex);
1493 debugquad(x, y, w, h, 0, 0, rsmsize, rsmsize);
1494 }
1495
1496 VAR(debugrh, -1, 0, RH_MAXSPLITS*(RH_MAXGRID + 2));
viewrh()1497 void viewrh()
1498 {
1499 int w = min(hudw, hudh)/2, h = (w*hudh)/hudw, x = hudw-w, y = hudh-h;
1500 gle::colorf(1, 1, 1);
1501 if(debugrh < 0 && rhrect)
1502 {
1503 SETSHADER(hudrect);
1504 glBindTexture(GL_TEXTURE_RECTANGLE, rhtex[5]);
1505 float tw = (rhgrid+2*rhborder)*(rhgrid+2*rhborder), th = (rhgrid+2*rhborder)*rhsplits;
1506 gle::defvertex(2);
1507 gle::deftexcoord0(2);
1508 gle::begin(GL_TRIANGLE_STRIP);
1509 gle::attribf(x, y); gle::attribf(0, 0);
1510 gle::attribf(x+w, y); gle::attribf(tw, 0);
1511 gle::attribf(x, y+h); gle::attribf(0, th);
1512 gle::attribf(x+w, y+h); gle::attribf(tw, th);
1513 gle::end();
1514 }
1515 else
1516 {
1517 SETSHADER(hud3d);
1518 glBindTexture(GL_TEXTURE_3D, rhtex[1]);
1519 float z = (max(debugrh, 1)-1+0.5f)/float((rhgrid+2*rhborder)*rhsplits);
1520 gle::defvertex(2);
1521 gle::deftexcoord0(3);
1522 gle::begin(GL_TRIANGLE_STRIP);
1523 gle::attribf(x, y); gle::attribf(0, 0, z);
1524 gle::attribf(x+w, y); gle::attribf(1, 0, z);
1525 gle::attribf(x, y+h); gle::attribf(0, 1, z);
1526 gle::attribf(x+w, y+h); gle::attribf(1, 1, z);
1527 gle::end();
1528 }
1529 gle::disable();
1530 }
1531
1532 #define SHADOWATLAS_SIZE 4096
1533
1534 PackNode shadowatlaspacker(0, 0, SHADOWATLAS_SIZE, SHADOWATLAS_SIZE);
1535
1536 extern int smminradius;
1537
1538 struct lightinfo
1539 {
1540 float sx1, sy1, sx2, sy2, sz1, sz2;
1541 int ent, shadowmap, flags;
1542 vec o, color;
1543 float radius;
1544 vec dir, spotx, spoty;
1545 int spot;
1546 float dist;
1547 occludequery *query;
1548
calcspotlightinfo1549 void calcspot(const vec &spotdir, int spotangle)
1550 {
1551 dir = spotdir;
1552 spot = spotangle;
1553 quat orient(dir, vec(0, 0, dir.z < 0 ? -1 : 1));
1554 spotx = orient.invertedrotate(vec(1, 0, 0));
1555 spoty = orient.invertedrotate(vec(0, 1, 0));
1556 }
1557
noshadowlightinfo1558 bool noshadow() const { return flags&L_NOSHADOW || radius <= smminradius; }
1559
addscissorlightinfo1560 void addscissor(float &dx1, float &dy1, float &dx2, float &dy2, float &dz1, float &dz2) const
1561 {
1562 dx1 = min(dx1, sx1);
1563 dy1 = min(dy1, sy1);
1564 dx2 = max(dx2, sx2);
1565 dy2 = max(dy2, sy2);
1566 dz1 = min(dz1, sz1);
1567 dz2 = max(dz2, sz2);
1568 }
1569 };
1570
1571 struct shadowcachekey
1572 {
1573 vec o;
1574 float radius;
1575 vec dir;
1576 int spot;
1577
shadowcachekeyshadowcachekey1578 shadowcachekey() {}
shadowcachekeyshadowcachekey1579 shadowcachekey(const lightinfo &l) : o(l.o), radius(l.radius), dir(l.dir), spot(l.spot) {}
1580 };
1581
hthash(const shadowcachekey & k)1582 static inline uint hthash(const shadowcachekey &k)
1583 {
1584 return hthash(k.o);
1585 }
1586
htcmp(const shadowcachekey & x,const shadowcachekey & y)1587 static inline bool htcmp(const shadowcachekey &x, const shadowcachekey &y)
1588 {
1589 return x.o == y.o && x.radius == y.radius && x.dir == y.dir && x.spot == y.spot;
1590 }
1591
1592 struct shadowcacheval;
1593
1594 struct shadowmapinfo
1595 {
1596 ushort x, y, size, sidemask;
1597 int light;
1598 shadowcacheval *cached;
1599 };
1600
1601 struct shadowcacheval
1602 {
1603 ushort x, y, size, sidemask;
1604
shadowcachevalshadowcacheval1605 shadowcacheval() {}
shadowcachevalshadowcacheval1606 shadowcacheval(const shadowmapinfo &sm) : x(sm.x), y(sm.y), size(sm.size), sidemask(sm.sidemask) {}
1607 };
1608
1609 struct shadowcache : hashtable<shadowcachekey, shadowcacheval>
1610 {
shadowcacheshadowcache1611 shadowcache() : hashtable<shadowcachekey, shadowcacheval>(256) {}
1612
resetshadowcache1613 void reset()
1614 {
1615 clear();
1616 }
1617 };
1618
1619 extern int smcache, smfilter, smgather;
1620
1621 #define SHADOWCACHE_EVICT 2
1622
1623 GLuint shadowatlastex = 0, shadowatlasfbo = 0;
1624 GLenum shadowatlastarget = GL_NONE;
1625 shadowcache shadowcache;
1626 bool shadowcachefull = false;
1627 int evictshadowcache = 0;
1628
setsmnoncomparemode()1629 static inline void setsmnoncomparemode() // use texture gather
1630 {
1631 glTexParameteri(shadowatlastarget, GL_TEXTURE_COMPARE_MODE, GL_NONE);
1632 glTexParameteri(shadowatlastarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1633 glTexParameteri(shadowatlastarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1634 }
1635
setsmcomparemode()1636 static inline void setsmcomparemode() // use embedded shadow cmp
1637 {
1638 glTexParameteri(shadowatlastarget, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
1639 glTexParameteri(shadowatlastarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1640 glTexParameteri(shadowatlastarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1641 }
1642
1643 extern int usetexgather;
usegatherforsm()1644 static inline bool usegatherforsm() { return smfilter > 1 && smgather && hasTG && usetexgather; }
usesmcomparemode()1645 static inline bool usesmcomparemode() { return !usegatherforsm() || (hasTG && hasGPU5 && usetexgather > 1); }
1646
viewshadowatlas()1647 void viewshadowatlas()
1648 {
1649 int w = min(hudw, hudh)/2, h = (w*hudh)/hudw, x = hudw-w, y = hudh-h;
1650 float tw = 1, th = 1;
1651 if(shadowatlastarget == GL_TEXTURE_RECTANGLE)
1652 {
1653 tw = shadowatlaspacker.w;
1654 th = shadowatlaspacker.h;
1655 SETSHADER(hudrect);
1656 }
1657 else hudshader->set();
1658 gle::colorf(1, 1, 1);
1659 glBindTexture(shadowatlastarget, shadowatlastex);
1660 if(usesmcomparemode()) setsmnoncomparemode();
1661 debugquad(x, y, w, h, 0, 0, tw, th);
1662 if(usesmcomparemode()) setsmcomparemode();
1663 }
1664 VAR(debugshadowatlas, 0, 0, 1);
1665
1666 extern int smdepthprec, smsize;
1667
setupshadowatlas()1668 void setupshadowatlas()
1669 {
1670 int size = min((1<<smsize), hwtexsize);
1671 shadowatlaspacker.resize(size, size);
1672
1673 if(!shadowatlastex) glGenTextures(1, &shadowatlastex);
1674
1675 shadowatlastarget = usegatherforsm() ? GL_TEXTURE_2D : GL_TEXTURE_RECTANGLE;
1676 createtexture(shadowatlastex, shadowatlaspacker.w, shadowatlaspacker.h, NULL, 3, 1, smdepthprec > 1 ? GL_DEPTH_COMPONENT32 : (smdepthprec ? GL_DEPTH_COMPONENT24 : GL_DEPTH_COMPONENT16), shadowatlastarget);
1677 glTexParameteri(shadowatlastarget, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
1678 glTexParameteri(shadowatlastarget, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
1679
1680 if(!shadowatlasfbo) glGenFramebuffers_(1, &shadowatlasfbo);
1681
1682 glBindFramebuffer_(GL_FRAMEBUFFER, shadowatlasfbo);
1683
1684 glDrawBuffer(GL_NONE);
1685 glReadBuffer(GL_NONE);
1686
1687 glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, shadowatlastarget, shadowatlastex, 0);
1688
1689 if(glCheckFramebufferStatus_(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
1690 fatal("failed allocating shadow atlas!");
1691
1692 glBindFramebuffer_(GL_FRAMEBUFFER, 0);
1693 }
1694
cleanupshadowatlas()1695 void cleanupshadowatlas()
1696 {
1697 if(shadowatlastex) { glDeleteTextures(1, &shadowatlastex); shadowatlastex = 0; }
1698 if(shadowatlasfbo) { glDeleteFramebuffers_(1, &shadowatlasfbo); shadowatlasfbo = 0; }
1699 clearshadowcache();
1700 }
1701
1702 const matrix4 cubeshadowviewmatrix[6] =
1703 {
1704 // sign-preserving cubemap projections
1705 matrix4(vec(0, 0, 1), vec(0, 1, 0), vec(-1, 0, 0)), // +X
1706 matrix4(vec(0, 0, 1), vec(0, 1, 0), vec( 1, 0, 0)), // -X
1707 matrix4(vec(1, 0, 0), vec(0, 0, 1), vec(0, -1, 0)), // +Y
1708 matrix4(vec(1, 0, 0), vec(0, 0, 1), vec(0, 1, 0)), // -Y
1709 matrix4(vec(1, 0, 0), vec(0, 1, 0), vec(0, 0, -1)), // +Z
1710 matrix4(vec(1, 0, 0), vec(0, 1, 0), vec(0, 0, 1)) // -Z
1711 };
1712
1713 FVAR(smpolyfactor, -1e3f, 1, 1e3f);
1714 FVAR(smpolyoffset, -1e3f, 0, 1e3f);
1715 FVAR(smbias, -1e6f, 0.01f, 1e6f);
1716 FVAR(smpolyfactor2, -1e3f, 1.5f, 1e3f);
1717 FVAR(smpolyoffset2, -1e3f, 0, 1e3f);
1718 FVAR(smbias2, -1e6f, 0.02f, 1e6f);
1719 FVAR(smprec, 1e-3f, 1, 1e3f);
1720 FVAR(smcubeprec, 1e-3f, 1, 1e3f);
1721 FVAR(smspotprec, 1e-3f, 1, 1e3f);
1722
1723 VARFP(smsize, 10, 12, 14, cleanupshadowatlas());
1724 VARFP(smdepthprec, 0, 0, 2, cleanupshadowatlas());
1725 VAR(smsidecull, 0, 1, 1);
1726 VAR(smviscull, 0, 1, 1);
1727 VAR(smborder, 0, 3, 16);
1728 VAR(smborder2, 0, 4, 16);
1729 VAR(smminradius, 0, 16, 10000);
1730 VAR(smminsize, 1, 96, 1024);
1731 VAR(smmaxsize, 1, 384, 1024);
1732 //VAR(smmaxsize, 1, 4096, 4096);
1733 VAR(smused, 1, 0, 0);
1734 VAR(smquery, 0, 1, 1);
1735 VARF(smcullside, 0, 1, 1, cleanupshadowatlas());
1736 VARF(smcache, 0, 1, 2, cleanupshadowatlas());
1737 VARFP(smfilter, 0, 2, 3, { cleardeferredlightshaders(); cleanupshadowatlas(); });
1738 VARFP(smgather, 0, 0, 1, { cleardeferredlightshaders(); cleanupshadowatlas(); });
1739 VAR(smnoshadow, 0, 0, 1);
1740 VAR(smdynshadow, 0, 1, 1);
1741 VAR(lighttilesused, 1, 0, 0);
1742 VAR(lightpassesused, 1, 0, 0);
1743
1744 int shadowmapping = 0;
1745
1746 struct lightstrip
1747 {
1748 short x, y, w;
1749
insidelightstrip1750 bool inside(int tx1, int ty1, int tx2, int ty2, const uint *tilemask) const
1751 {
1752 return x + w > tx1 && x < tx2 && y >= ty1 && y < ty2 && (!tilemask || (tilemask[y]>>x)&((1<<w)-1));
1753 }
1754
extendlightstrip1755 bool extend(int ex, int ey)
1756 {
1757 if(y != ey || x+w != ex) return false;
1758 ++w;
1759 return true;
1760 }
1761 };
1762
1763 struct lighttile
1764 {
1765 int band;
1766 vector<ushort> lights;
1767
resetlighttile1768 void reset()
1769 {
1770 lights.setsize(0);
1771 }
1772 };
1773
1774 struct lighttileslice
1775 {
1776 lighttile *tile;
1777 ushort priority, offset, numlights;
1778
lighttileslicelighttileslice1779 lighttileslice() {}
lighttileslicelighttileslice1780 lighttileslice(lighttile *tile, int priority, int offset, int numlights) : tile(tile), priority(priority), offset(offset), numlights(numlights) {}
1781 };
1782
1783 struct lightbatch : lighttileslice
1784 {
1785 vector<lightstrip> strips;
1786
resetlightbatch1787 void reset()
1788 {
1789 strips.setsize(0);
1790 }
1791
insidelightbatch1792 bool inside(int tx1, int ty1, int tx2, int ty2, const uint *tilemask) const
1793 {
1794 if(!tx1 && !ty1 && tx2 >= lighttilew && ty2 >= lighttileh && !tilemask) return true;
1795 loopv(strips) if(strips[i].inside(tx1, ty1, tx2, ty2, tilemask)) return true;
1796 return false;
1797 }
1798 };
1799
htrecycle(lightbatch & l)1800 static inline void htrecycle(lightbatch &l)
1801 {
1802 l.reset();
1803 }
1804
hthash(const lighttileslice & l)1805 static inline uint hthash(const lighttileslice &l)
1806 {
1807 uint h = 0;
1808 loopi(l.numlights) h = ((h<<8)+h)^l.tile->lights[l.offset + i];
1809 return h;
1810 }
1811
htcmp(const lighttileslice & x,const lighttileslice & y)1812 static inline bool htcmp(const lighttileslice &x, const lighttileslice &y)
1813 {
1814 return x.tile->band == y.tile->band &&
1815 x.priority == y.priority &&
1816 x.numlights == y.numlights &&
1817 (!x.numlights || !memcmp(&x.tile->lights[x.offset], &y.tile->lights[y.offset], x.numlights*sizeof(ushort)));
1818 }
1819
1820 vector<lightinfo> lights;
1821 vector<int> lightorder;
1822 lighttile lighttiles[LIGHTTILE_MAXH][LIGHTTILE_MAXW];
1823 hashset<lightbatch> lightbatcher(128);
1824 vector<lightbatch *> lightbatches;
1825 vector<shadowmapinfo> shadowmaps;
1826
clearshadowcache()1827 void clearshadowcache()
1828 {
1829 shadowmaps.setsize(0);
1830
1831 clearradiancehintscache();
1832 clearshadowmeshes();
1833 }
1834
addshadowmap(ushort x,ushort y,int size,int & idx)1835 static shadowmapinfo *addshadowmap(ushort x, ushort y, int size, int &idx)
1836 {
1837 idx = shadowmaps.length();
1838 shadowmapinfo *sm = &shadowmaps.add();
1839 sm->x = x;
1840 sm->y = y;
1841 sm->size = size;
1842 sm->light = -1;
1843 sm->sidemask = 0;
1844 sm->cached = NULL;
1845 return sm;
1846 }
1847
1848 #define CSM_MAXSPLITS 8
1849
1850 VARF(csmmaxsize, 256, 768, 2048, clearshadowcache());
1851 VARF(csmsplits, 1, 3, CSM_MAXSPLITS, { cleardeferredlightshaders(); clearshadowcache(); });
1852 FVAR(csmsplitweight, 0.20f, 0.75f, 0.95f);
1853 VARF(csmshadowmap, 0, 1, 1, { cleardeferredlightshaders(); clearshadowcache(); });
1854
1855 // cascaded shadow maps
1856 struct cascadedshadowmap
1857 {
1858 struct splitinfo
1859 {
1860 float nearplane; // split distance to near plane
1861 float farplane; // split distance to farplane
1862 matrix4 proj; // one projection per split
1863 vec scale, offset; // scale and offset of the projection
1864 int idx; // shadowmapinfo indices
1865 vec center, bounds; // max extents of shadowmap in sunlight model space
1866 plane cull[4]; // world space culling planes of the split's projected sides
1867 };
1868 matrix4 model; // model view is shared by all splits
1869 splitinfo splits[CSM_MAXSPLITS]; // per-split parameters
1870 vec lightview; // view vector for light
1871 void setup(); // insert shadowmaps for each split frustum if there is sunlight
1872 void updatesplitdist(); // compute split frustum distances
1873 void getmodelmatrix(); // compute the shared model matrix
1874 void getprojmatrix(); // compute each cropped projection matrix
1875 void gencullplanes(); // generate culling planes for the mvp matrix
1876 void bindparams(); // bind any shader params necessary for lighting
1877 };
1878
setup()1879 void cascadedshadowmap::setup()
1880 {
1881 int size = (csmmaxsize * shadowatlaspacker.w) / SHADOWATLAS_SIZE;
1882 loopi(csmsplits)
1883 {
1884 ushort smx = USHRT_MAX, smy = USHRT_MAX;
1885 splits[i].idx = -1;
1886 if(shadowatlaspacker.insert(smx, smy, size, size))
1887 addshadowmap(smx, smy, size, splits[i].idx);
1888 }
1889 getmodelmatrix();
1890 getprojmatrix();
1891 gencullplanes();
1892 }
1893
1894 VAR(csmnearplane, 1, 1, 16);
1895 VAR(csmfarplane, 64, 1024, 16384);
1896 FVAR(csmpradiustweak, 1e-3f, 1, 1e3f);
1897 FVAR(csmdepthrange, 0, 1024, 1e6f);
1898 FVAR(csmdepthmargin, 0, 0.1f, 1e3f);
1899 FVAR(csmpolyfactor, -1e3f, 2, 1e3f);
1900 FVAR(csmpolyoffset, -1e4f, 0, 1e4f);
1901 FVAR(csmbias, -1e6f, 1e-4f, 1e6f);
1902 FVAR(csmpolyfactor2, -1e3f, 3, 1e3f);
1903 FVAR(csmpolyoffset2, -1e4f, 0, 1e4f);
1904 FVAR(csmbias2, -1e16f, 2e-4f, 1e6f);
1905 VAR(csmcull, 0, 1, 1);
1906
updatesplitdist()1907 void cascadedshadowmap::updatesplitdist()
1908 {
1909 float lambda = csmsplitweight, nd = csmnearplane, fd = csmfarplane, ratio = fd/nd;
1910 splits[0].nearplane = nd;
1911 for(int i = 1; i < csmsplits; ++i)
1912 {
1913 float si = i / float(csmsplits);
1914 splits[i].nearplane = lambda*(nd*pow(ratio, si)) + (1-lambda)*(nd + (fd - nd)*si);
1915 splits[i-1].farplane = splits[i].nearplane * 1.005f;
1916 }
1917 splits[csmsplits-1].farplane = fd;
1918 }
1919
getmodelmatrix()1920 void cascadedshadowmap::getmodelmatrix()
1921 {
1922 model = viewmatrix;
1923 model.rotate_around_x(sunlightpitch*RAD);
1924 model.rotate_around_z((180-sunlightyaw)*RAD);
1925 }
1926
getprojmatrix()1927 void cascadedshadowmap::getprojmatrix()
1928 {
1929 lightview = vec(sunlightdir).neg();
1930
1931 // compute the split frustums
1932 updatesplitdist();
1933
1934 // find z extent
1935 float minz = lightview.project_bb(worldmin, worldmax), maxz = lightview.project_bb(worldmax, worldmin),
1936 zmargin = max((maxz - minz)*csmdepthmargin, 0.5f*(csmdepthrange - (maxz - minz)));
1937 minz -= zmargin;
1938 maxz += zmargin;
1939
1940 // compute each split projection matrix
1941 loopi(csmsplits)
1942 {
1943 splitinfo &split = splits[i];
1944 if(split.idx < 0) continue;
1945 const shadowmapinfo &sm = shadowmaps[split.idx];
1946
1947 vec c;
1948 float radius = calcfrustumboundsphere(split.nearplane, split.farplane, camera1->o, camdir, c);
1949
1950 // compute the projected bounding box of the sphere
1951 vec tc;
1952 model.transform(c, tc);
1953 int border = smfilter > 2 ? smborder2 : smborder;
1954 const float pradius = ceil(radius * csmpradiustweak), step = (2*pradius) / (sm.size - 2*border);
1955 vec2 offset = vec2(tc).sub(pradius).div(step);
1956 offset.x = floor(offset.x);
1957 offset.y = floor(offset.y);
1958 split.center = vec(vec2(offset).mul(step).add(pradius), -0.5f*(minz + maxz));
1959 split.bounds = vec(pradius, pradius, 0.5f*(maxz - minz));
1960
1961 // modify mvp with a scale and offset
1962 // now compute the update model view matrix for this split
1963 split.scale = vec(1/step, 1/step, -1/(maxz - minz));
1964 split.offset = vec(border - offset.x, border - offset.y, -minz/(maxz - minz));
1965
1966 split.proj.identity();
1967 split.proj.settranslation(2*split.offset.x/sm.size - 1, 2*split.offset.y/sm.size - 1, 2*split.offset.z - 1);
1968 split.proj.setscale(2*split.scale.x/sm.size, 2*split.scale.y/sm.size, 2*split.scale.z);
1969
1970 const float bias = (smfilter > 2 ? csmbias2 : csmbias) * (-512.0f / sm.size) * (split.farplane - split.nearplane) / (splits[0].farplane - splits[0].nearplane);
1971 split.offset.add(vec(sm.x, sm.y, bias));
1972 }
1973 }
1974
gencullplanes()1975 void cascadedshadowmap::gencullplanes()
1976 {
1977 loopi(csmsplits)
1978 {
1979 splitinfo &split = splits[i];
1980 matrix4 mvp;
1981 mvp.mul(split.proj, model);
1982 vec4 px = mvp.rowx(), py = mvp.rowy(), pw = mvp.roww();
1983 split.cull[0] = plane(vec4(pw).add(px)).normalize(); // left plane
1984 split.cull[1] = plane(vec4(pw).sub(px)).normalize(); // right plane
1985 split.cull[2] = plane(vec4(pw).add(py)).normalize(); // bottom plane
1986 split.cull[3] = plane(vec4(pw).sub(py)).normalize(); // top plane
1987 }
1988 }
1989
bindparams()1990 void cascadedshadowmap::bindparams()
1991 {
1992 static GlobalShaderParam splitcenter("splitcenter"), splitbounds("splitbounds"), splitscale("splitscale"), splitoffset("splitoffset");
1993 vec *splitcenterv = splitcenter.reserve<vec>(csmsplits),
1994 *splitboundsv = splitbounds.reserve<vec>(csmsplits),
1995 *splitscalev = splitscale.reserve<vec>(csmsplits),
1996 *splitoffsetv = splitoffset.reserve<vec>(csmsplits);
1997 loopi(csmsplits)
1998 {
1999 cascadedshadowmap::splitinfo &split = splits[i];
2000 if(split.idx < 0) continue;
2001 splitcenterv[i] = split.center;
2002 splitboundsv[i] = split.bounds;
2003 splitscalev[i] = split.scale;
2004 splitoffsetv[i] = split.offset;
2005 }
2006 GLOBALPARAM(csmmatrix, matrix3(model));
2007 }
2008
2009 cascadedshadowmap csm;
2010
calcbbcsmsplits(const ivec & bbmin,const ivec & bbmax)2011 int calcbbcsmsplits(const ivec &bbmin, const ivec &bbmax)
2012 {
2013 int mask = (1<<csmsplits)-1;
2014 if(!csmcull) return mask;
2015 loopi(csmsplits)
2016 {
2017 const cascadedshadowmap::splitinfo &split = csm.splits[i];
2018 int k;
2019 for(k = 0; k < 4; k++)
2020 {
2021 const plane &p = split.cull[k];
2022 ivec omin, omax;
2023 if(p.x > 0) { omin.x = bbmin.x; omax.x = bbmax.x; } else { omin.x = bbmax.x; omax.x = bbmin.x; }
2024 if(p.y > 0) { omin.y = bbmin.y; omax.y = bbmax.y; } else { omin.y = bbmax.y; omax.y = bbmin.y; }
2025 if(p.z > 0) { omin.z = bbmin.z; omax.z = bbmax.z; } else { omin.z = bbmax.z; omax.z = bbmin.z; }
2026 if(omax.dist(p) < 0) { mask &= ~(1<<i); goto nextsplit; }
2027 if(omin.dist(p) < 0) goto notinside;
2028 }
2029 mask &= (2<<i)-1;
2030 break;
2031 notinside:
2032 while(++k < 4)
2033 {
2034 const plane &p = split.cull[k];
2035 ivec omax(p.x > 0 ? bbmax.x : bbmin.x, p.y > 0 ? bbmax.y : bbmin.y, p.z > 0 ? bbmax.z : bbmin.z);
2036 if(omax.dist(p) < 0) { mask &= ~(1<<i); break; }
2037 }
2038 nextsplit:;
2039 }
2040 return mask;
2041 }
2042
calcspherecsmsplits(const vec & center,float radius)2043 int calcspherecsmsplits(const vec ¢er, float radius)
2044 {
2045 int mask = (1<<csmsplits)-1;
2046 if(!csmcull) return mask;
2047 loopi(csmsplits)
2048 {
2049 const cascadedshadowmap::splitinfo &split = csm.splits[i];
2050 int k;
2051 for(k = 0; k < 4; k++)
2052 {
2053 const plane &p = split.cull[k];
2054 float dist = p.dist(center);
2055 if(dist < -radius) { mask &= ~(1<<i); goto nextsplit; }
2056 if(dist < radius) goto notinside;
2057 }
2058 mask &= (2<<i)-1;
2059 break;
2060 notinside:
2061 while(++k < 4)
2062 {
2063 const plane &p = split.cull[k];
2064 if(p.dist(center) < -radius) { mask &= ~(1<<i); break; }
2065 }
2066 nextsplit:;
2067 }
2068 return mask;
2069 }
2070
2071 struct reflectiveshadowmap
2072 {
2073 matrix4 model, proj;
2074 vec lightview;
2075 plane cull[4];
2076 vec scale, offset;
2077 vec center, bounds;
2078 void setup();
2079 void getmodelmatrix();
2080 void getprojmatrix();
2081 void gencullplanes();
2082 } rsm;
2083
setup()2084 void reflectiveshadowmap::setup()
2085 {
2086 getmodelmatrix();
2087 getprojmatrix();
2088 gencullplanes();
2089 }
2090
getmodelmatrix()2091 void reflectiveshadowmap::getmodelmatrix()
2092 {
2093 model = viewmatrix;
2094 model.rotate_around_x(sunlightpitch*RAD);
2095 model.rotate_around_z((180-sunlightyaw)*RAD);
2096 }
2097
getprojmatrix()2098 void reflectiveshadowmap::getprojmatrix()
2099 {
2100 lightview = vec(sunlightdir).neg();
2101
2102 // find z extent
2103 float minz = lightview.project_bb(worldmin, worldmax), maxz = lightview.project_bb(worldmax, worldmin),
2104 zmargin = max((maxz - minz)*rsmdepthmargin, 0.5f*(rsmdepthrange - (maxz - minz)));
2105 minz -= zmargin;
2106 maxz += zmargin;
2107
2108 vec c;
2109 float radius = calcfrustumboundsphere(rhnearplane, rhfarplane, camera1->o, camdir, c);
2110
2111 // compute the projected bounding box of the sphere
2112 vec tc;
2113 model.transform(c, tc);
2114 const float pradius = ceil((radius + gidist) * rsmpradiustweak), step = (2*pradius) / rsmsize;
2115 vec2 tcoff = vec2(tc).sub(pradius).div(step);
2116 tcoff.x = floor(tcoff.x);
2117 tcoff.y = floor(tcoff.y);
2118 center = vec(vec2(tcoff).mul(step).add(pradius), -0.5f*(minz + maxz));
2119 bounds = vec(pradius, pradius, 0.5f*(maxz - minz));
2120
2121 scale = vec(1/step, 1/step, -1/(maxz - minz));
2122 offset = vec(-tcoff.x, -tcoff.y, -minz/(maxz - minz));
2123
2124 proj.identity();
2125 proj.settranslation(2*offset.x/rsmsize - 1, 2*offset.y/rsmsize - 1, 2*offset.z - 1);
2126 proj.setscale(2*scale.x/rsmsize, 2*scale.y/rsmsize, 2*scale.z);
2127 }
2128
gencullplanes()2129 void reflectiveshadowmap::gencullplanes()
2130 {
2131 matrix4 mvp;
2132 mvp.mul(proj, model);
2133 vec4 px = mvp.rowx(), py = mvp.rowy(), pw = mvp.roww();
2134 cull[0] = plane(vec4(pw).add(px)).normalize(); // left plane
2135 cull[1] = plane(vec4(pw).sub(px)).normalize(); // right plane
2136 cull[2] = plane(vec4(pw).add(py)).normalize(); // bottom plane
2137 cull[3] = plane(vec4(pw).sub(py)).normalize(); // top plane
2138 }
2139
calcbbrsmsplits(const ivec & bbmin,const ivec & bbmax)2140 int calcbbrsmsplits(const ivec &bbmin, const ivec &bbmax)
2141 {
2142 if(!rsmcull) return 1;
2143 loopk(4)
2144 {
2145 const plane &p = rsm.cull[k];
2146 ivec omin, omax;
2147 if(p.x > 0) { omin.x = bbmin.x; omax.x = bbmax.x; } else { omin.x = bbmax.x; omax.x = bbmin.x; }
2148 if(p.y > 0) { omin.y = bbmin.y; omax.y = bbmax.y; } else { omin.y = bbmax.y; omax.y = bbmin.y; }
2149 if(p.z > 0) { omin.z = bbmin.z; omax.z = bbmax.z; } else { omin.z = bbmax.z; omax.z = bbmin.z; }
2150 if(omax.dist(p) < 0) return 0;
2151 if(omin.dist(p) < 0) while(++k < 4)
2152 {
2153 const plane &p = rsm.cull[k];
2154 ivec omax(p.x > 0 ? bbmax.x : bbmin.x, p.y > 0 ? bbmax.y : bbmin.y, p.z > 0 ? bbmax.z : bbmin.z);
2155 if(omax.dist(p) < 0) return 0;
2156 }
2157 }
2158 return 1;
2159 }
2160
calcspherersmsplits(const vec & center,float radius)2161 int calcspherersmsplits(const vec ¢er, float radius)
2162 {
2163 if(!rsmcull) return 1;
2164 loopk(4)
2165 {
2166 const plane &p = rsm.cull[k];
2167 float dist = p.dist(center);
2168 if(dist < -radius) return 0;
2169 if(dist < radius) while(++k < 4)
2170 {
2171 const plane &p = rsm.cull[k];
2172 if(p.dist(center) < -radius) return 0;
2173 }
2174 }
2175 return 1;
2176 }
2177
2178 struct radiancehints
2179 {
2180 struct splitinfo
2181 {
2182 float nearplane, farplane;
2183 vec offset, scale;
2184 vec center; float bounds;
2185 vec cached;
2186
splitinforadiancehints::splitinfo2187 splitinfo() : center(-1e16f, -1e16f, -1e16f), bounds(-1e16f), cached(-1e16f, -1e16f, -1e16f) {}
2188
clearcacheradiancehints::splitinfo2189 void clearcache() { bounds = -1e16f; }
2190 } splits[RH_MAXSPLITS];
2191
2192 vec dynmin, dynmax, prevdynmin, prevdynmax;
2193
radiancehintsradiancehints2194 radiancehints() : dynmin(1e16f, 1e16f, 1e16f), dynmax(-1e16f, -1e16f, -1e16f), prevdynmin(1e16f, 1e16f, 1e16f), prevdynmax(-1e16f, -1e16f, -1e16f) {}
2195
2196 void setup();
2197 void updatesplitdist();
2198 void bindparams();
2199 void renderslices();
2200
clearcacheradiancehints2201 void clearcache() { loopi(RH_MAXSPLITS) splits[i].clearcache(); }
allcachedradiancehints2202 bool allcached() const { loopi(rhsplits) if(splits[i].cached != splits[i].center) return false; return true; }
2203 } rh;
2204
clearradiancehintscache()2205 void clearradiancehintscache()
2206 {
2207 rh.clearcache();
2208 memset(rhclearmasks, 0, sizeof(rhclearmasks));
2209 }
2210
updatesplitdist()2211 void radiancehints::updatesplitdist()
2212 {
2213 float lambda = rhsplitweight, nd = rhnearplane, fd = rhfarplane, ratio = fd/nd;
2214 splits[0].nearplane = nd;
2215 for(int i = 1; i < rhsplits; ++i)
2216 {
2217 float si = i / float(rhsplits);
2218 splits[i].nearplane = lambda*(nd*pow(ratio, si)) + (1-lambda)*(nd + (fd - nd)*si);
2219 splits[i-1].farplane = splits[i].nearplane * 1.005f;
2220 }
2221 splits[rhsplits-1].farplane = fd;
2222 }
2223
setup()2224 void radiancehints::setup()
2225 {
2226 updatesplitdist();
2227
2228 loopi(rhsplits)
2229 {
2230 splitinfo &split = splits[i];
2231
2232 vec c;
2233 float radius = calcfrustumboundsphere(split.nearplane, split.farplane, camera1->o, camdir, c);
2234
2235 // compute the projected bounding box of the sphere
2236 const float pradius = ceil(radius * rhpradiustweak), step = (2*pradius) / rhgrid;
2237 vec offset = vec(c).sub(pradius).div(step);
2238 offset.x = floor(offset.x);
2239 offset.y = floor(offset.y);
2240 offset.z = floor(offset.z);
2241 split.cached = split.bounds == pradius ? split.center : vec(-1e16f, -1e16f, -1e16f);
2242 split.center = vec(offset).mul(step).add(pradius);
2243 split.bounds = pradius;
2244
2245 // modify mvp with a scale and offset
2246 // now compute the update model view matrix for this split
2247 split.scale = vec(1/(step*(rhgrid+2*rhborder)), 1/(step*(rhgrid+2*rhborder)), 1/(step*(rhgrid+2*rhborder)*rhsplits));
2248 split.offset = vec(-(offset.x-rhborder)/(rhgrid+2*rhborder), -(offset.y-rhborder)/(rhgrid+2*rhborder), (i - (offset.z-rhborder)/(rhgrid+2*rhborder))/float(rhsplits));
2249 }
2250 }
2251
bindparams()2252 void radiancehints::bindparams()
2253 {
2254 static GlobalShaderParam rhbb("rhbb"), rhscale("rhscale"), rhoffset("rhoffset");
2255 vec4 *rhbbv = rhbb.reserve<vec4>(rhsplits);
2256 vec *rhscalev = rhscale.reserve<vec>(rhsplits),
2257 *rhoffsetv = rhoffset.reserve<vec>(rhsplits);
2258 loopi(rhsplits)
2259 {
2260 splitinfo &split = splits[i];
2261 rhbbv[i] = vec4(split.center, split.bounds*(1 + rhborder*2*0.5f/rhgrid));
2262 rhscalev[i] = split.scale;
2263 rhoffsetv[i] = split.offset;
2264 }
2265 float step = 2*splits[0].bounds/rhgrid;
2266 GLOBALPARAMF(rhnudge, rhnudge*step);
2267 }
2268
useradiancehints()2269 bool useradiancehints()
2270 {
2271 return !sunlight.iszero() && csmshadowmap && gi && giscale && gidist;
2272 }
2273
2274 FVAR(avatarshadowdist, 0, 8, 100);
2275 FVAR(avatarshadowbias, 0, 8, 100);
2276 VARF(avatarshadowstencil, 0, 1, 2, initwarning("g-buffer setup", INIT_LOAD, CHANGE_SHADERS));
2277
2278 int avatarmask = 0;
2279
useavatarmask()2280 bool useavatarmask() { return avatarshadowstencil && ghasstencil && (!msaasamples || avatarshadowstencil > 1); }
2281
enableavatarmask()2282 void enableavatarmask()
2283 {
2284 if(useavatarmask())
2285 {
2286 avatarmask = 0x40;
2287 glStencilFunc(GL_ALWAYS, avatarmask, ~0);
2288 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
2289 glEnable(GL_STENCIL_TEST);
2290 }
2291 }
2292
disableavatarmask()2293 void disableavatarmask()
2294 {
2295 if(avatarmask)
2296 {
2297 avatarmask = 0;
2298 glDisable(GL_STENCIL_TEST);
2299 }
2300 }
2301
2302 static Shader *deferredlightshader = NULL, *deferredminimapshader = NULL, *deferredmsaapixelshader = NULL, *deferredmsaasampleshader = NULL;
2303
cleardeferredlightshaders()2304 void cleardeferredlightshaders()
2305 {
2306 deferredlightshader = NULL;
2307 deferredminimapshader = NULL;
2308 deferredmsaapixelshader = NULL;
2309 deferredmsaasampleshader = NULL;
2310 }
2311
2312 VARF(lighttilebatch, 0, 8, 8, cleardeferredlightshaders());
2313 VARF(batchsunlight, 0, 2, 2, cleardeferredlightshaders());
2314
2315 extern int spotlights;
2316
loaddeferredlightshader(const char * type=NULL)2317 Shader *loaddeferredlightshader(const char *type = NULL)
2318 {
2319 string common, shadow, sun;
2320 int commonlen = 0, shadowlen = 0, sunlen = 0;
2321
2322 bool minimap = false;
2323 if(type)
2324 {
2325 if(type[0] == 'm') minimap = true;
2326 copystring(common, type);
2327 commonlen = strlen(common);
2328 }
2329 if(lighttilebatch)
2330 {
2331 common[commonlen++] = 'n';
2332 common[commonlen++] = '0' + lighttilebatch;
2333 }
2334 if(usegatherforsm()) common[commonlen++] = smfilter > 2 ? 'G' : 'g';
2335 else if(smfilter) common[commonlen++] = smfilter > 2 ? 'E' : (smfilter > 1 ? 'F' : 'f');
2336 if(spotlights) common[commonlen++] = 's';
2337 if(!minimap) common[commonlen++] = 't';
2338 if(useavatarmask()) common[commonlen++] = 'd';
2339 common[commonlen] = '\0';
2340
2341 shadow[shadowlen++] = 'p';
2342 shadow[shadowlen] = '\0';
2343
2344 int usecsm = 0, userh = 0;
2345 if(!minimap && ao) sun[sunlen++] = 'a';
2346 if(!sunlight.iszero() && csmshadowmap)
2347 {
2348 usecsm = csmsplits;
2349 sun[sunlen++] = 'c';
2350 sun[sunlen++] = '0' + csmsplits;
2351 if(!minimap)
2352 {
2353 if(ao && aosun) sun[sunlen++] = 'A';
2354 if(gi && giscale && gidist)
2355 {
2356 userh = rhsplits;
2357 sun[sunlen++] = 'r';
2358 sun[sunlen++] = '0' + rhsplits;
2359 }
2360 }
2361 }
2362 if(lighttilebatch && (!usecsm || batchsunlight > (userh ? 1 : 0))) sun[sunlen++] = 'b';
2363 sun[sunlen] = '\0';
2364
2365 defformatstring(name, "deferredlight%s%s%s", common, shadow, sun);
2366 return generateshader(name, "deferredlightshader \"%s\" \"%s\" \"%s\" %d %d %d", common, shadow, sun, usecsm, userh, lighttilebatch);
2367 }
2368
loaddeferredlightshaders()2369 void loaddeferredlightshaders()
2370 {
2371 if(msaasamples)
2372 {
2373 string opts;
2374 if(hasMSS) copystring(opts, "MS");
2375 else if(msaasamples==2) copystring(opts, ghasstencil || !msaaedgedetect ? "MO" : "MOT");
2376 else formatstring(opts, ghasstencil || !msaaedgedetect ? "MR%d" : "MRT%d", msaasamples);
2377 deferredmsaasampleshader = loaddeferredlightshader(opts);
2378 deferredmsaapixelshader = loaddeferredlightshader("M");
2379 deferredlightshader = deferredmsaapixelshader;
2380 }
2381 else deferredlightshader = loaddeferredlightshader();
2382 }
2383
sortlights(int x,int y)2384 static inline bool sortlights(int x, int y)
2385 {
2386 const lightinfo &xl = lights[x], &yl = lights[y];
2387 if(!xl.spot) { if(yl.spot) return true; }
2388 else if(!yl.spot) return false;
2389 if(!xl.noshadow()) { if(yl.noshadow()) return true; }
2390 else if(!yl.noshadow()) return false;
2391 if(xl.sz1 < yl.sz1) return true;
2392 else if(xl.sz1 > yl.sz1) return false;
2393 return xl.dist - xl.radius < yl.dist - yl.radius;
2394 }
2395
2396 VAR(lighttilealignw, 1, 16, 256);
2397 VAR(lighttilealignh, 1, 16, 256);
2398 VARN(lighttilew, lighttilemaxw, 1, 10, LIGHTTILE_MAXW);
2399 VARN(lighttileh, lighttilemaxh, 1, 10, LIGHTTILE_MAXH);
2400
2401 int lighttilew = 0, lighttileh = 0, lighttilevieww = 0, lighttileviewh = 0;
2402
calctilesize()2403 void calctilesize()
2404 {
2405 lighttilevieww = (vieww + lighttilealignw - 1)/lighttilealignw;
2406 lighttileviewh = (viewh + lighttilealignh - 1)/lighttilealignh;
2407 lighttilew = min(lighttilevieww, lighttilemaxw);
2408 lighttileh = min(lighttileviewh, lighttilemaxh);
2409 }
2410
resetlights()2411 void resetlights()
2412 {
2413 shadowcache.reset();
2414 if(smcache)
2415 {
2416 int evictx = ((evictshadowcache%SHADOWCACHE_EVICT)*shadowatlaspacker.w)/SHADOWCACHE_EVICT,
2417 evicty = ((evictshadowcache/SHADOWCACHE_EVICT)*shadowatlaspacker.h)/SHADOWCACHE_EVICT,
2418 evictx2 = (((evictshadowcache%SHADOWCACHE_EVICT)+1)*shadowatlaspacker.w)/SHADOWCACHE_EVICT,
2419 evicty2 = (((evictshadowcache/SHADOWCACHE_EVICT)+1)*shadowatlaspacker.h)/SHADOWCACHE_EVICT;
2420 loopv(shadowmaps)
2421 {
2422 shadowmapinfo &sm = shadowmaps[i];
2423 if(sm.light < 0) continue;
2424 lightinfo &l = lights[sm.light];
2425 if(sm.cached && shadowcachefull)
2426 {
2427 int w = l.spot ? sm.size : sm.size*3, h = l.spot ? sm.size : sm.size*2;
2428 if(sm.x < evictx2 && sm.x + w > evictx && sm.y < evicty2 && sm.y + h > evicty) continue;
2429 }
2430 shadowcache[l] = sm;
2431 }
2432 if(shadowcachefull)
2433 {
2434 evictshadowcache = (evictshadowcache + 1)%(SHADOWCACHE_EVICT*SHADOWCACHE_EVICT);
2435 shadowcachefull = false;
2436 }
2437 }
2438
2439 lights.setsize(0);
2440 lightorder.setsize(0);
2441 loopi(LIGHTTILE_MAXH) loopj(LIGHTTILE_MAXW) lighttiles[i][j].reset();
2442
2443 shadowmaps.setsize(0);
2444 shadowatlaspacker.reset();
2445
2446 calctilesize();
2447 }
2448
2449 static vec *lightsphereverts = NULL;
2450 static GLushort *lightsphereindices = NULL;
2451 static int lightspherenumverts = 0, lightspherenumindices = 0;
2452 static GLuint lightspherevbuf = 0, lightsphereebuf = 0;
2453
initlightsphere(int slices,int stacks)2454 static void initlightsphere(int slices, int stacks)
2455 {
2456 lightspherenumverts = (stacks+1)*(slices+1);
2457 lightsphereverts = new vec[lightspherenumverts];
2458 float ds = 1.0f/slices, dt = 1.0f/stacks, t = 1.0f;
2459 loopi(stacks+1)
2460 {
2461 float rho = M_PI*(1-t), s = 0.0f;
2462 loopj(slices+1)
2463 {
2464 float theta = j==slices ? 0 : 2*M_PI*s;
2465 lightsphereverts[i*(slices+1) + j] = vec(-sin(theta)*sin(rho), -cos(theta)*sin(rho), cos(rho));
2466 s += ds;
2467 }
2468 t -= dt;
2469 }
2470
2471 lightspherenumindices = stacks*slices*3*2;
2472 lightsphereindices = new ushort[lightspherenumindices];
2473 GLushort *curindex = lightsphereindices;
2474 loopi(stacks)
2475 {
2476 loopk(slices)
2477 {
2478 int j = i%2 ? slices-k-1 : k;
2479
2480 *curindex++ = i*(slices+1)+j;
2481 *curindex++ = i*(slices+1)+j+1;
2482 *curindex++ = (i+1)*(slices+1)+j;
2483
2484 *curindex++ = i*(slices+1)+j+1;
2485 *curindex++ = (i+1)*(slices+1)+j+1;
2486 *curindex++ = (i+1)*(slices+1)+j;
2487 }
2488 }
2489
2490 if(!lightspherevbuf) glGenBuffers_(1, &lightspherevbuf);
2491 glBindBuffer_(GL_ARRAY_BUFFER, lightspherevbuf);
2492 glBufferData_(GL_ARRAY_BUFFER, lightspherenumverts*sizeof(vec), lightsphereverts, GL_STATIC_DRAW);
2493 DELETEA(lightsphereverts);
2494
2495 if(!lightsphereebuf) glGenBuffers_(1, &lightsphereebuf);
2496 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER, lightsphereebuf);
2497 glBufferData_(GL_ELEMENT_ARRAY_BUFFER, lightspherenumindices*sizeof(GLushort), lightsphereindices, GL_STATIC_DRAW);
2498 DELETEA(lightsphereindices);
2499 }
2500
cleanuplightsphere()2501 void cleanuplightsphere()
2502 {
2503 if(lightspherevbuf) { glDeleteBuffers_(1, &lightspherevbuf); lightspherevbuf = 0; }
2504 if(lightsphereebuf) { glDeleteBuffers_(1, &lightsphereebuf); lightsphereebuf = 0; }
2505 }
2506
2507 VAR(depthtestlights, 0, 2, 2);
2508 FVAR(depthtestlightsclamp, 0, 0.999995f, 1);
2509 VAR(depthfaillights, 0, 1, 1);
2510 FVAR(lightradiustweak, 1, 1.11f, 2);
2511
2512 VAR(lighttilestrip, 0, 1, 1);
2513 VAR(lighttilebands, 0, 1, LIGHTTILE_MAXH);
2514
lightquad(float z=-1,float sx1=-1,float sy1=-1,float sx2=1,float sy2=1)2515 static inline void lightquad(float z = -1, float sx1 = -1, float sy1 = -1, float sx2 = 1, float sy2 = 1)
2516 {
2517 gle::begin(GL_TRIANGLE_STRIP);
2518 gle::attribf(sx2, sy1, z);
2519 gle::attribf(sx1, sy1, z);
2520 gle::attribf(sx2, sy2, z);
2521 gle::attribf(sx1, sy2, z);
2522 gle::end();
2523 }
2524
lightquads(float z,float sx1,float sy1,float sx2,float sy2)2525 static inline void lightquads(float z, float sx1, float sy1, float sx2, float sy2)
2526 {
2527 gle::attribf(sx1, sy2, z);
2528 gle::attribf(sx2, sy2, z);
2529 gle::attribf(sx2, sy1, z);
2530 gle::attribf(sx1, sy1, z);
2531 }
2532
lightquad(float sz1,float bsx1,float bsy1,float bsx2,float bsy2,const uint * tilemask)2533 static void lightquad(float sz1, float bsx1, float bsy1, float bsx2, float bsy2, const uint *tilemask)
2534 {
2535 int btx1, bty1, btx2, bty2;
2536 calctilebounds(bsx1, bsy1, bsx2, bsy2, btx1, bty1, btx2, bty2);
2537
2538 gle::begin(GL_QUADS);
2539 for(int y = bty1; y < bty2; y++) for(int x = btx1, end = btx2; x < end;)
2540 {
2541 int start;
2542 if(tilemask)
2543 {
2544 while(x < end && !(tilemask[y]&(1<<x))) x++;
2545 if(x >= end) break;
2546 start = x;
2547 do ++x; while(x < end && tilemask[y]&(1<<x));
2548 }
2549 else
2550 {
2551 start = x;
2552 x = end;
2553 }
2554 int tx1 = max(int(floor((bsx1*0.5f+0.5f)*vieww)), ((start*lighttilevieww)/lighttilew)*lighttilealignw),
2555 ty1 = max(int(floor((bsy1*0.5f+0.5f)*viewh)), ((y*lighttileviewh)/lighttileh)*lighttilealignh),
2556 tx2 = min(int(ceil((bsx2*0.5f+0.5f)*vieww)), min(((x*lighttilevieww)/lighttilew)*lighttilealignw, vieww)),
2557 ty2 = min(int(ceil((bsy2*0.5f+0.5f)*viewh)), min((((y+1)*lighttileviewh)/lighttileh)*lighttilealignh, viewh));
2558 lightquads(sz1, (tx1*2.0f)/vieww-1.0f, (ty1*2.0f)/viewh-1.0f, (tx2*2.0f)/vieww-1.0f, (ty2*2.0f)/viewh-1.0f);
2559 }
2560 gle::end();
2561 }
2562
bindlighttexs(int msaapass=0,bool transparent=false)2563 static void bindlighttexs(int msaapass = 0, bool transparent = false)
2564 {
2565 if(msaapass) glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mscolortex);
2566 else glBindTexture(GL_TEXTURE_RECTANGLE, gcolortex);
2567 glActiveTexture_(GL_TEXTURE1);
2568 if(msaapass) glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msnormaltex);
2569 else glBindTexture(GL_TEXTURE_RECTANGLE, gnormaltex);
2570 if(transparent)
2571 {
2572 glActiveTexture_(GL_TEXTURE2);
2573 if(msaapass) glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msglowtex);
2574 else glBindTexture(GL_TEXTURE_RECTANGLE, gglowtex);
2575 }
2576 glActiveTexture_(GL_TEXTURE3);
2577 if(msaapass) glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msdepthtex);
2578 else glBindTexture(GL_TEXTURE_RECTANGLE, gdepthtex);
2579 glActiveTexture_(GL_TEXTURE4);
2580 glBindTexture(shadowatlastarget, shadowatlastex);
2581 if(usesmcomparemode()) setsmcomparemode(); else setsmnoncomparemode();
2582 if(ao)
2583 {
2584 glActiveTexture_(GL_TEXTURE5);
2585 glBindTexture(GL_TEXTURE_RECTANGLE, aotex[2] ? aotex[2] : aotex[0]);
2586 }
2587 if(useradiancehints()) loopi(4)
2588 {
2589 glActiveTexture_(GL_TEXTURE6 + i);
2590 glBindTexture(GL_TEXTURE_3D, rhtex[i]);
2591 }
2592 glActiveTexture_(GL_TEXTURE0);
2593 }
2594
setlightglobals(bool transparent=false)2595 static inline void setlightglobals(bool transparent = false)
2596 {
2597 GLOBALPARAMF(shadowatlasscale, 1.0f/shadowatlaspacker.w, 1.0f/shadowatlaspacker.h);
2598 if(ao)
2599 {
2600 if(transparent || drawtex || (editmode && fullbright))
2601 {
2602 GLOBALPARAMF(aoscale, 0.0f, 0.0f);
2603 GLOBALPARAMF(aoparams, 1.0f, 0.0f, 1.0f, 0.0f);
2604 }
2605 else
2606 {
2607 GLOBALPARAM(aoscale, aotex[2] ? vec2(1, 1) : vec2(float(aow)/vieww, float(aoh)/viewh));
2608 GLOBALPARAMF(aoparams, aomin, 1.0f-aomin, aosunmin, 1.0f-aosunmin);
2609 }
2610 }
2611 float lightscale = 2.0f*ldrscaleb;
2612 if(!drawtex && editmode && fullbright)
2613 GLOBALPARAMF(lightscale, fullbrightlevel*lightscale, fullbrightlevel*lightscale, fullbrightlevel*lightscale, 255*lightscale);
2614 else
2615 GLOBALPARAMF(lightscale, ambient.x*lightscale*ambientscale, ambient.y*lightscale*ambientscale, ambient.z*lightscale*ambientscale, 255*lightscale);
2616
2617 if(!sunlight.iszero() && csmshadowmap)
2618 {
2619 csm.bindparams();
2620 rh.bindparams();
2621 if(!drawtex && editmode && fullbright)
2622 {
2623 GLOBALPARAMF(sunlightdir, 0, 0, 0);
2624 GLOBALPARAMF(sunlightcolor, 0, 0, 0);
2625 GLOBALPARAMF(giscale, 0);
2626 GLOBALPARAMF(skylightcolor, 0, 0, 0);
2627 }
2628 else
2629 {
2630 GLOBALPARAM(sunlightdir, sunlightdir);
2631 GLOBALPARAMF(sunlightcolor, sunlight.x*lightscale*sunlightscale, sunlight.y*lightscale*sunlightscale, sunlight.z*lightscale*sunlightscale);
2632 GLOBALPARAMF(giscale, 2*giscale);
2633 GLOBALPARAMF(skylightcolor, 2*giaoscale*skylight.x*lightscale*skylightscale, 2*giaoscale*skylight.y*lightscale*skylightscale, 2*giaoscale*skylight.z*lightscale*skylightscale);
2634 }
2635 }
2636
2637 matrix4 lightmatrix;
2638 lightmatrix.identity();
2639 GLOBALPARAM(lightmatrix, lightmatrix);
2640 }
2641
2642 static LocalShaderParam lightpos("lightpos"), lightcolor("lightcolor"), spotparams("spotparams"), shadowparams("shadowparams"), shadowoffset("shadowoffset");
2643 static vec4 lightposv[8], spotparamsv[8], shadowparamsv[8];
2644 static vec lightcolorv[8];
2645 static vec2 shadowoffsetv[8];
2646
setlightparams(int i,const lightinfo & l)2647 static inline void setlightparams(int i, const lightinfo &l)
2648 {
2649 lightposv[i] = vec4(l.o, 1).div(l.radius);
2650 lightcolorv[i] = vec(l.color).mul(2*ldrscaleb);
2651 if(l.spot > 0) spotparamsv[i] = vec4(l.dir, 1/(1 - cos360(l.spot)));
2652 if(l.shadowmap >= 0)
2653 {
2654 shadowmapinfo &sm = shadowmaps[l.shadowmap];
2655 float smnearclip = SQRT3 / l.radius, smfarclip = SQRT3,
2656 bias = (smfilter > 2 ? smbias2 : smbias) * (smcullside ? 1 : -1) * smnearclip * (1024.0f / sm.size);
2657 int border = smfilter > 2 ? smborder2 : smborder;
2658 if(l.spot > 0)
2659 {
2660 shadowparamsv[i] = vec4(
2661 0.5f * sm.size * cotan360(l.spot),
2662 (-smnearclip * smfarclip / (smfarclip - smnearclip) - 0.5f*bias),
2663 1 / (1 + fabs(l.dir.z)),
2664 0.5f + 0.5f * (smfarclip + smnearclip) / (smfarclip - smnearclip));
2665 }
2666 else
2667 {
2668 shadowparamsv[i] = vec4(
2669 0.5f * (sm.size - border),
2670 -smnearclip * smfarclip / (smfarclip - smnearclip) - 0.5f*bias,
2671 sm.size,
2672 0.5f + 0.5f * (smfarclip + smnearclip) / (smfarclip - smnearclip));
2673 }
2674 shadowoffsetv[i] = vec2(sm.x + 0.5f*sm.size, sm.y + 0.5f*sm.size);
2675 }
2676 }
2677
setlightshader(Shader * s,int n,bool baselight,bool shadowmap,bool spotlight,bool transparent=false,bool avatar=false)2678 static inline void setlightshader(Shader *s, int n, bool baselight, bool shadowmap, bool spotlight, bool transparent = false, bool avatar = false)
2679 {
2680 s->setvariant(n-1, (shadowmap ? 1 : 0) + (baselight ? 0 : 2) + (spotlight ? 4 : 0) + (transparent ? 8 : 0) + (avatar ? 24 : 0));
2681 lightpos.setv(lightposv, n);
2682 lightcolor.setv(lightcolorv, n);
2683 if(spotlight) spotparams.setv(spotparamsv, n);
2684 if(shadowmap)
2685 {
2686 shadowparams.setv(shadowparamsv, n);
2687 shadowoffset.setv(shadowoffsetv, n);
2688 }
2689 }
2690
setavatarstencil(int stencilref,bool on)2691 static inline void setavatarstencil(int stencilref, bool on)
2692 {
2693 glStencilFunc(GL_EQUAL, (on ? 0x40 : 0) | stencilref, !(stencilref&0x08) && !hasMSS && msaasamples==2 ? 0x47 : 0x4F);
2694 }
2695
rendersunpass(Shader * s,int stencilref,bool transparent,float bsx1,float bsy1,float bsx2,float bsy2,const uint * tilemask)2696 static void rendersunpass(Shader *s, int stencilref, bool transparent, float bsx1, float bsy1, float bsx2, float bsy2, const uint *tilemask)
2697 {
2698 if(hasDBT && depthtestlights > 1) glDepthBounds_(0, depthtestlightsclamp);
2699
2700 int tx1 = max(int(floor((bsx1*0.5f+0.5f)*vieww)), 0), ty1 = max(int(floor((bsy1*0.5f+0.5f)*viewh)), 0),
2701 tx2 = min(int(ceil((bsx2*0.5f+0.5f)*vieww)), vieww), ty2 = min(int(ceil((bsy2*0.5f+0.5f)*viewh)), viewh);
2702 s->setvariant(transparent ? 0 : -1, 16);
2703 lightquad(-1, (tx1*2.0f)/vieww-1.0f, (ty1*2.0f)/viewh-1.0f, (tx2*2.0f)/vieww-1.0f, (ty2*2.0f)/viewh-1.0f, tilemask);
2704 lightpassesused++;
2705
2706 if(stencilref >= 0)
2707 {
2708 setavatarstencil(stencilref, true);
2709
2710 s->setvariant(0, 17);
2711 lightquad(-1, (tx1*2.0f)/vieww-1.0f, (ty1*2.0f)/viewh-1.0f, (tx2*2.0f)/vieww-1.0f, (ty2*2.0f)/viewh-1.0f, tilemask);
2712 lightpassesused++;
2713
2714 setavatarstencil(stencilref, false);
2715 }
2716 }
2717
renderlightsnobatch(Shader * s,int stencilref,bool transparent,float bsx1,float bsy1,float bsx2,float bsy2)2718 static void renderlightsnobatch(Shader *s, int stencilref, bool transparent, float bsx1, float bsy1, float bsx2, float bsy2)
2719 {
2720 if(!lightspherevbuf) initlightsphere(8, 4);
2721 glBindBuffer_(GL_ARRAY_BUFFER, lightspherevbuf);
2722 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER, lightsphereebuf);
2723 gle::vertexpointer(sizeof(vec), lightsphereverts);
2724 gle::enablevertex();
2725
2726 glEnable(GL_SCISSOR_TEST);
2727
2728 bool outside = true;
2729 loop(avatarpass, stencilref >= 0 ? 2 : 1)
2730 {
2731 if(avatarpass) setavatarstencil(stencilref, true);
2732
2733 loopv(lightorder)
2734 {
2735 const lightinfo &l = lights[lightorder[i]];
2736 float sx1 = max(bsx1, l.sx1), sy1 = max(bsy1, l.sy1),
2737 sx2 = min(bsx2, l.sx2), sy2 = min(bsy2, l.sy2);
2738 if(sx1 >= sx2 || sy1 >= sy2 || l.sz1 >= l.sz2 || (avatarpass && l.dist - l.radius > avatarshadowdist)) continue;
2739
2740 matrix4 lightmatrix = camprojmatrix;
2741 lightmatrix.translate(l.o);
2742 lightmatrix.scale(l.radius*lightradiustweak);
2743 GLOBALPARAM(lightmatrix, lightmatrix);
2744
2745 setlightparams(0, l);
2746 setlightshader(s, 1, false, l.shadowmap >= 0, l.spot > 0, transparent, avatarpass > 0);
2747
2748 int tx1 = int(floor((sx1*0.5f+0.5f)*vieww)), ty1 = int(floor((sy1*0.5f+0.5f)*viewh)),
2749 tx2 = int(ceil((sx2*0.5f+0.5f)*vieww)), ty2 = int(ceil((sy2*0.5f+0.5f)*viewh));
2750 glScissor(tx1, ty1, tx2-tx1, ty2-ty1);
2751
2752 if(hasDBT && depthtestlights > 1) glDepthBounds_(l.sz1*0.5f + 0.5f, min(l.sz2*0.5f + 0.5f, depthtestlightsclamp));
2753
2754 if(camera1->o.dist(l.o) <= l.radius*lightradiustweak + nearplane + 1 && depthfaillights)
2755 {
2756 if(outside)
2757 {
2758 outside = false;
2759 glDepthFunc(GL_GEQUAL);
2760 glCullFace(GL_FRONT);
2761 }
2762 }
2763 else if(!outside)
2764 {
2765 outside = true;
2766 glDepthFunc(GL_LESS);
2767 glCullFace(GL_BACK);
2768 }
2769
2770 glDrawRangeElements_(GL_TRIANGLES, 0, lightspherenumverts-1, lightspherenumindices, GL_UNSIGNED_SHORT, lightsphereindices);
2771 xtraverts += lightspherenumindices;
2772 glde++;
2773
2774 lightpassesused++;
2775 }
2776
2777 if(avatarpass) setavatarstencil(stencilref, false);
2778 }
2779
2780 if(!outside)
2781 {
2782 outside = true;
2783 glDepthFunc(GL_LESS);
2784 glCullFace(GL_BACK);
2785 }
2786
2787 glDisable(GL_SCISSOR_TEST);
2788
2789 gle::disablevertex();
2790 glBindBuffer_(GL_ARRAY_BUFFER, 0);
2791 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER, 0);
2792 }
2793
renderlightbatches(Shader * s,int stencilref,bool transparent,float bsx1,float bsy1,float bsx2,float bsy2,const uint * tilemask)2794 static void renderlightbatches(Shader *s, int stencilref, bool transparent, float bsx1, float bsy1, float bsx2, float bsy2, const uint *tilemask)
2795 {
2796 bool sunpass = !sunlight.iszero() && csmshadowmap && batchsunlight <= (gi && giscale && gidist ? 1 : 0);
2797 int btx1, bty1, btx2, bty2;
2798 calctilebounds(bsx1, bsy1, bsx2, bsy2, btx1, bty1, btx2, bty2);
2799 loopv(lightbatches)
2800 {
2801 lightbatch &batch = *lightbatches[i];
2802 if(!batch.inside(btx1, bty1, btx2, bty2, tilemask)) continue;
2803
2804 lighttile &tile = *batch.tile;
2805 int offset = batch.offset, n = batch.numlights;
2806 float sx1 = 1, sy1 = 1, sx2 = -1, sy2 = -1, sz1 = 1, sz2 = -1;
2807 loopj(n)
2808 {
2809 const lightinfo &l = lights[tile.lights[offset+j]];
2810 setlightparams(j, l);
2811 l.addscissor(sx1, sy1, sx2, sy2, sz1, sz2);
2812 }
2813
2814 if(!offset && !sunpass) { sx1 = bsx1; sy1 = bsy1; sx2 = bsx2; sy2 = bsy2; sz1 = -1; sz2 = 1; }
2815 else
2816 {
2817 sx1 = max(sx1, bsx1); sy1 = max(sy1, bsy1); sx2 = min(sx2, bsx2); sy2 = min(sy2, bsy2);
2818 if(sx1 >= sx2 || sy1 >= sy2 || sz1 >= sz2) continue;
2819 }
2820
2821 if(n)
2822 {
2823 const lightinfo &l = lights[tile.lights[offset]];
2824 setlightshader(s, n, !offset && !sunpass, l.shadowmap >= 0, l.spot > 0, transparent);
2825 }
2826 else s->setvariant(transparent ? 0 : -1, 16);
2827
2828 lightpassesused++;
2829
2830 if(hasDBT && depthtestlights > 1) glDepthBounds_(sz1*0.5f + 0.5f, min(sz2*0.5f + 0.5f, depthtestlightsclamp));
2831 gle::begin(GL_QUADS);
2832 loopvj(batch.strips)
2833 {
2834 lightstrip &s = batch.strips[j];
2835 if(s.y >= bty1 && s.y < bty2) for(int x = max(int(s.x), btx1), end = min(int(s.x + s.w), btx2); x < end;)
2836 {
2837 int start;
2838 if(tilemask)
2839 {
2840 while(x < end && !(tilemask[s.y]&(1<<x))) x++;
2841 if(x >= end) break;
2842 start = x;
2843 do ++x; while(x < end && tilemask[s.y]&(1<<x));
2844 }
2845 else
2846 {
2847 start = x;
2848 x = end;
2849 }
2850 int tx1 = max(int(floor((sx1*0.5f+0.5f)*vieww)), ((start*lighttilevieww)/lighttilew)*lighttilealignw),
2851 ty1 = max(int(floor((sy1*0.5f+0.5f)*viewh)), ((s.y*lighttileviewh)/lighttileh)*lighttilealignh),
2852 tx2 = min(int(ceil((sx2*0.5f+0.5f)*vieww)), min(((x*lighttilevieww)/lighttilew)*lighttilealignw, vieww)),
2853 ty2 = min(int(ceil((sy2*0.5f+0.5f)*viewh)), min((((s.y+1)*lighttileviewh)/lighttileh)*lighttilealignh, viewh));
2854 lightquads(sz1, (tx1*2.0f)/vieww-1.0f, (ty1*2.0f)/viewh-1.0f, (tx2*2.0f)/vieww-1.0f, (ty2*2.0f)/viewh-1.0f);
2855 }
2856 }
2857 gle::end();
2858 }
2859
2860 if(stencilref >= 0)
2861 {
2862 setavatarstencil(stencilref, true);
2863
2864 bool baselight = !sunpass;
2865 for(int offset = 0; baselight || offset < lightorder.length(); baselight = false)
2866 {
2867 int n = 0;
2868 bool shadowmap = false, spotlight = false;
2869 float sx1 = 1, sy1 = 1, sx2 = -1, sy2 = -1, sz1 = 1, sz2 = -1;
2870 for(; offset < lightorder.length(); offset++)
2871 {
2872 const lightinfo &l = lights[lightorder[offset]];
2873 if(l.dist - l.radius > avatarshadowdist) continue;
2874 if(!n)
2875 {
2876 shadowmap = l.shadowmap >= 0;
2877 spotlight = l.spot > 0;
2878 }
2879 else if(n >= lighttilebatch || (l.shadowmap >= 0) != shadowmap || (l.spot > 0) != spotlight) break;
2880 setlightparams(n++, l);
2881 l.addscissor(sx1, sy1, sx2, sy2, sz1, sz2);
2882 }
2883 if(baselight) { sx1 = bsx1; sy1 = bsy1; sx2 = bsx2; sy2 = bsy2; sz1 = -1; sz2 = 1; }
2884 else
2885 {
2886 if(!n) break;
2887 sx1 = max(sx1, bsx1); sy1 = max(sy1, bsy1); sx2 = min(sx2, bsx2); sy2 = min(sy2, bsy2);
2888 if(sx1 >= sx2 || sy1 >= sy2 || sz1 >= sz2) continue;
2889 }
2890
2891 if(n) setlightshader(s, n, baselight, shadowmap, spotlight, false, true);
2892 else s->setvariant(0, 17);
2893
2894 if(hasDBT && depthtestlights > 1) glDepthBounds_(sz1*0.5f + 0.5f, min(sz2*0.5f + 0.5f, depthtestlightsclamp));
2895 lightquad(sz1, sx1, sy1, sx2, sy2, tilemask);
2896 lightpassesused++;
2897 }
2898
2899 setavatarstencil(stencilref, false);
2900 }
2901 }
2902
renderlights(float bsx1=-1,float bsy1=-1,float bsx2=1,float bsy2=1,const uint * tilemask=NULL,int stencilmask=0,int msaapass=0,bool transparent=false)2903 void renderlights(float bsx1 = -1, float bsy1 = -1, float bsx2 = 1, float bsy2 = 1, const uint *tilemask = NULL, int stencilmask = 0, int msaapass = 0, bool transparent = false)
2904 {
2905 Shader *s = drawtex == DRAWTEX_MINIMAP ? deferredminimapshader : (msaapass <= 0 ? deferredlightshader : (msaapass > 1 ? deferredmsaasampleshader : deferredmsaapixelshader));
2906 if(!s || s == nullshader) return;
2907
2908 bool depth = true;
2909 if(!depthtestlights) { glDisable(GL_DEPTH_TEST); depth = false; }
2910 else glDepthMask(GL_FALSE);
2911
2912 gle::defvertex(3);
2913
2914 bool avatar = useavatarmask() && !transparent && !drawtex;
2915 int stencilref = -1;
2916 if(msaapass == 1 && ghasstencil)
2917 {
2918 int tx1 = max(int(floor((bsx1*0.5f+0.5f)*vieww)), 0), ty1 = max(int(floor((bsy1*0.5f+0.5f)*viewh)), 0),
2919 tx2 = min(int(ceil((bsx2*0.5f+0.5f)*vieww)), vieww), ty2 = min(int(ceil((bsy2*0.5f+0.5f)*viewh)), viewh);
2920 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
2921 if(stencilmask) glStencilFunc(GL_EQUAL, stencilmask|0x08, 0x07);
2922 else
2923 {
2924 glStencilFunc(GL_ALWAYS, 0x08, ~0);
2925 glEnable(GL_STENCIL_TEST);
2926 }
2927 if(avatar) glStencilMask(~0x40);
2928 if(depthtestlights && depth) { glDisable(GL_DEPTH_TEST); depth = false; }
2929 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
2930 SETSHADER(msaaedgedetect);
2931 lightquad(-1, (tx1*2.0f)/vieww-1.0f, (ty1*2.0f)/viewh-1.0f, (tx2*2.0f)/vieww-1.0f, (ty2*2.0f)/viewh-1.0f, tilemask);
2932 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
2933 glStencilFunc(GL_EQUAL, stencilref = stencilmask, (avatar ? 0x40 : 0) | (!hasMSS && msaasamples==2 ? 0x07 : 0x0F));
2934 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
2935 if(avatar) glStencilMask(~0);
2936 else if(!hasMSS && msaasamples==2 && !stencilmask) glDisable(GL_STENCIL_TEST);
2937 }
2938 else if(msaapass == 2)
2939 {
2940 if(ghasstencil) glStencilFunc(GL_EQUAL, stencilref = stencilmask|0x08, avatar ? 0x4F : 0x0F);
2941 if(!hasMSS && msaasamples==2) { glSampleMaski_(0, 2); glEnable(GL_SAMPLE_MASK); }
2942 }
2943 else if(ghasstencil && (stencilmask || avatar))
2944 {
2945 if(!stencilmask) glEnable(GL_STENCIL_TEST);
2946 glStencilFunc(GL_EQUAL, stencilref = stencilmask, avatar ? 0x4F : 0x0F);
2947 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
2948 }
2949
2950 if(!avatar) stencilref = -1;
2951
2952 bindlighttexs(msaapass, transparent);
2953
2954 setlightglobals(transparent);
2955
2956 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
2957 glEnable(GL_BLEND);
2958
2959 if(hasDBT && depthtestlights > 1) glEnable(GL_DEPTH_BOUNDS_TEST_EXT);
2960
2961 bool sunpass = !lighttilebatch || (!sunlight.iszero() && csmshadowmap && batchsunlight <= (gi && giscale && gidist ? 1 : 0));
2962 if(sunpass)
2963 {
2964 if(depthtestlights && depth) { glDisable(GL_DEPTH_TEST); depth = false; }
2965 rendersunpass(s, stencilref, transparent, bsx1, bsy1, bsx2, bsy2, tilemask);
2966 }
2967
2968 if(depthtestlights && !depth) { glEnable(GL_DEPTH_TEST); depth = true; }
2969
2970 if(!lighttilebatch)
2971 {
2972 gle::disable();
2973 renderlightsnobatch(s, stencilref, transparent, bsx1, bsy1, bsx2, bsy2);
2974 }
2975 else
2976 {
2977 renderlightbatches(s, stencilref, transparent, bsx1, bsy1, bsx2, bsy2, tilemask);
2978 gle::disable();
2979 }
2980
2981 if(msaapass == 1 && ghasstencil)
2982 {
2983 if(!hasMSS && msaasamples==2 && !stencilmask && !avatar) glEnable(GL_STENCIL_TEST);
2984 }
2985 else if(msaapass == 2)
2986 {
2987 if(ghasstencil && !stencilmask) glDisable(GL_STENCIL_TEST);
2988 if(!hasMSS && msaasamples==2) glDisable(GL_SAMPLE_MASK);
2989 }
2990 else if(avatar && !stencilmask) glDisable(GL_STENCIL_TEST);
2991
2992 glDisable(GL_BLEND);
2993
2994 if(!depthtestlights) glEnable(GL_DEPTH_TEST);
2995 else
2996 {
2997 glDepthMask(GL_TRUE);
2998 if(hasDBT && depthtestlights > 1) glDisable(GL_DEPTH_BOUNDS_TEST_EXT);
2999 }
3000 }
3001
3002 VAR(oqlights, 0, 1, 1);
3003 VAR(debuglightscissor, 0, 0, 1);
3004
viewlightscissor()3005 void viewlightscissor()
3006 {
3007 vector<extentity *> &ents = entities::getents();
3008 gle::defvertex(2);
3009 loopv(entgroup)
3010 {
3011 int idx = entgroup[i];
3012 if(ents.inrange(idx) && ents[idx]->type == ET_LIGHT)
3013 {
3014 extentity &e = *ents[idx];
3015 loopvj(lights) if(lights[j].o == e.o)
3016 {
3017 lightinfo &l = lights[j];
3018 if(l.sx1 >= l.sx2 || l.sy1 >= l.sy2 || l.sz1 >= l.sz2) break;
3019 gle::colorf(l.color.x/255, l.color.y/255, l.color.z/255);
3020 float x1 = (l.sx1+1)/2*hudw, x2 = (l.sx2+1)/2*hudw,
3021 y1 = (1-l.sy1)/2*hudh, y2 = (1-l.sy2)/2*hudh;
3022 gle::begin(GL_TRIANGLE_STRIP);
3023 gle::attribf(x1, y1);
3024 gle::attribf(x2, y1);
3025 gle::attribf(x1, y2);
3026 gle::attribf(x2, y2);
3027 gle::end();
3028 }
3029 }
3030 }
3031 gle::disable();
3032 }
3033
calclightscissor(lightinfo & l)3034 static inline bool calclightscissor(lightinfo &l)
3035 {
3036 float sx1 = -1, sy1 = -1, sx2 = 1, sy2 = 1, sz1 = -1, sz2 = 1;
3037 if(l.spot > 0) calcspotscissor(l.o, l.radius, l.dir, l.spot, l.spotx, l.spoty, sx1, sy1, sx2, sy2, sz1, sz2);
3038 else calcspherescissor(l.o, l.radius, sx1, sy1, sx2, sy2, sz1, sz2);
3039 l.sx1 = sx1;
3040 l.sx2 = sx2;
3041 l.sy1 = sy1;
3042 l.sy2 = sy2;
3043 l.sz1 = sz1;
3044 l.sz2 = sz2;
3045 return sx1 < sx2 && sy1 < sy2 && sz1 < sz2;
3046 }
3047
collectlights()3048 void collectlights()
3049 {
3050 // point lights processed here
3051 const vector<extentity *> &ents = entities::getents();
3052 if(!editmode || !fullbright) loopv(ents)
3053 {
3054 extentity *e = ents[i];
3055 if(e->type != ET_LIGHT || e->attr1 <= 0) continue;
3056
3057 if(smviscull)
3058 {
3059 if(isfoggedsphere(e->attr1, e->o)) continue;
3060 if(pvsoccludedsphere(e->o, e->attr1)) continue;
3061 }
3062
3063 lightinfo &l = lights.add();
3064 l.ent = i;
3065 l.shadowmap = -1;
3066 l.flags = e->attr5;
3067 l.query = NULL;
3068 l.o = e->o;
3069 l.color = vec(e->attr2, e->attr3, e->attr4);
3070 l.radius = e->attr1;
3071 if(e->attached && e->attached->type == ET_SPOTLIGHT)
3072 {
3073 l.calcspot(vec(e->attached->o).sub(e->o).normalize(), clamp(int(e->attached->attr1), 1, 89));
3074 }
3075 else
3076 {
3077 l.dir = vec(0, 0, 0);
3078 l.spot = 0;
3079 }
3080 l.dist = camera1->o.dist(e->o);
3081
3082 if(calclightscissor(l)) lightorder.add(lights.length()-1);
3083 }
3084
3085 int numdynlights = 0;
3086 if(!drawtex)
3087 {
3088 updatedynlights();
3089 numdynlights = finddynlights();
3090 }
3091 loopi(numdynlights)
3092 {
3093 vec o, color, dir;
3094 float radius;
3095 int spot;
3096 if(!getdynlight(i, o, radius, color, dir, spot)) continue;
3097
3098 lightinfo &l = lights.add();
3099 l.ent = -1;
3100 l.shadowmap = -1;
3101 l.flags = 0;
3102 l.query = NULL;
3103 l.o = o;
3104 l.color = vec(color).mul(255);
3105 l.radius = radius;
3106 if(spot > 0)
3107 {
3108 l.calcspot(dir, spot);
3109 }
3110 else
3111 {
3112 l.dir = vec(0, 0, 0);
3113 l.spot = 0;
3114 }
3115 l.dist = camera1->o.dist(o);
3116
3117 if(calclightscissor(l)) lightorder.add(lights.length()-1);
3118 }
3119
3120 lightorder.sort(sortlights);
3121
3122 bool queried = false;
3123 if(!drawtex && smquery && oqfrags && oqlights) loopv(lightorder)
3124 {
3125 int idx = lightorder[i];
3126 lightinfo &l = lights[idx];
3127 if(l.noshadow() || l.radius >= worldsize) continue;
3128 vec bbmin, bbmax;
3129 if(l.spot > 0)
3130 {
3131 float spotscale = l.radius * tan360(l.spot);
3132 vec up = vec(l.spotx).mul(spotscale).abs(), right = vec(l.spoty).mul(spotscale).abs(), center = vec(l.dir).mul(l.radius).add(l.o);
3133 bbmin = bbmax = center;
3134 bbmin.sub(up).sub(right);
3135 bbmax.add(up).add(right);
3136 bbmin.min(l.o);
3137 bbmax.max(l.o);
3138 }
3139 else
3140 {
3141 bbmin = vec(l.o).sub(l.radius);
3142 bbmax = vec(l.o).add(l.radius);
3143 }
3144 if(camera1->o.x < bbmin.x - 2 || camera1->o.x > bbmax.x + 2 ||
3145 camera1->o.y < bbmin.y - 2 || camera1->o.y > bbmax.y + 2 ||
3146 camera1->o.z < bbmin.z - 2 || camera1->o.z > bbmax.z + 2)
3147 {
3148 l.query = newquery(&l);
3149 if(l.query)
3150 {
3151 if(!queried)
3152 {
3153 gle::defvertex();
3154 queried = true;
3155 }
3156 startquery(l.query);
3157 ivec bo = bbmin, br = bbmax;
3158 br.sub(bo).add(1);
3159 drawbb(bo, br);
3160 endquery(l.query);
3161 }
3162 }
3163 }
3164 if(queried)
3165 {
3166 gle::disable();
3167 glFlush();
3168 }
3169
3170 if(rhinoq && oqfrags && !drawtex && (!wireframe || !editmode)) renderradiancehints();
3171 }
3172
addlighttiles(const lightinfo & l,int idx)3173 static inline void addlighttiles(const lightinfo &l, int idx)
3174 {
3175 int tx1, ty1, tx2, ty2;
3176 calctilebounds(l.sx1, l.sy1, l.sx2, l.sy2, tx1, ty1, tx2, ty2);
3177 for(int y = ty1; y < ty2; y++) for(int x = tx1; x < tx2; x++) { lighttiles[y][x].lights.add(idx); lighttilesused++; }
3178 }
3179
3180 VAR(lightsvisible, 1, 0, 0);
3181 VAR(lightsoccluded, 1, 0, 0);
3182 VARN(lightbatches, lightbatchesused, 1, 0, 0);
3183
sortlightbatches(const lightbatch * x,const lightbatch * y)3184 static inline bool sortlightbatches(const lightbatch *x, const lightbatch *y)
3185 {
3186 if(x->tile->band < y->tile->band) return true;
3187 if(x->tile->band > y->tile->band) return false;
3188 if(x->priority < y->priority) return true;
3189 if(x->priority > y->priority) return false;
3190 return x->numlights > y->numlights;
3191 }
3192
packlights()3193 void packlights()
3194 {
3195 lightsvisible = lightsoccluded = 0;
3196 lighttilesused = lightpassesused = 0;
3197 smused = 0;
3198
3199 if(smcache && !smnoshadow && shadowcache.numelems) loopv(lightorder)
3200 {
3201 int idx = lightorder[i];
3202 lightinfo &l = lights[idx];
3203 if(l.noshadow()) continue;
3204 if(l.query && l.query->owner == &l && checkquery(l.query)) continue;
3205
3206 float prec = smprec, lod;
3207 int w, h;
3208 if(l.spot) { w = 1; h = 1; prec *= tan360(l.spot); lod = smspotprec; }
3209 else { w = 3; h = 2; lod = smcubeprec; }
3210 lod *= clamp(l.radius * prec / sqrtf(max(1.0f, l.dist/l.radius)), float(smminsize), float(smmaxsize));
3211 int size = clamp(int(ceil((lod * shadowatlaspacker.w) / SHADOWATLAS_SIZE)), 1, shadowatlaspacker.w / w);
3212 w *= size;
3213 h *= size;
3214 ushort x = USHRT_MAX, y = USHRT_MAX;
3215 shadowmapinfo *sm = NULL;
3216 int smidx = -1;
3217 shadowcacheval *cached = shadowcache.access(l);
3218 if(!cached || cached->size != size) continue;
3219 x = cached->x;
3220 y = cached->y;
3221 shadowatlaspacker.reserve(x, y, w, h);
3222 sm = addshadowmap(x, y, size, smidx);
3223 sm->light = idx;
3224 sm->cached = cached;
3225 l.shadowmap = smidx;
3226 smused += w*h;
3227
3228 addlighttiles(l, idx);
3229 }
3230 loopv(lightorder)
3231 {
3232 int idx = lightorder[i];
3233 lightinfo &l = lights[idx];
3234 if(l.shadowmap >= 0) continue;
3235
3236 if(!l.noshadow() && !smnoshadow)
3237 {
3238 if(l.query && l.query->owner == &l && checkquery(l.query)) { lightsoccluded++; continue; }
3239 float prec = smprec, lod;
3240 int w, h;
3241 if(l.spot) { w = 1; h = 1; prec *= tan360(l.spot); lod = smspotprec; }
3242 else { w = 3; h = 2; lod = smcubeprec; }
3243 lod *= clamp(l.radius * prec / sqrtf(max(1.0f, l.dist/l.radius)), float(smminsize), float(smmaxsize));
3244 int size = clamp(int(ceil((lod * shadowatlaspacker.w) / SHADOWATLAS_SIZE)), 1, shadowatlaspacker.w / w);
3245 w *= size;
3246 h *= size;
3247 ushort x = USHRT_MAX, y = USHRT_MAX;
3248 shadowmapinfo *sm = NULL;
3249 int smidx = -1;
3250 if(shadowatlaspacker.insert(x, y, w, h))
3251 {
3252 sm = addshadowmap(x, y, size, smidx);
3253 sm->light = idx;
3254 l.shadowmap = smidx;
3255 smused += w*h;
3256 }
3257 else if(smcache) shadowcachefull = true;
3258 }
3259
3260 addlighttiles(l, idx);
3261 }
3262
3263 lightsvisible = lightorder.length() - lightsoccluded;
3264
3265 lightbatcher.recycle();
3266 lightbatches.setsize(0);
3267 if(lighttilebatch) loop(y, lighttileh)
3268 {
3269 int band = lighttilebands && lighttilebands < lighttileh ? (y * lighttilebands) / lighttileh : y;
3270 bool sunpass = !sunlight.iszero() && csmshadowmap && batchsunlight < (gi && giscale && gidist ? 1 : 0);
3271 loop(x, lighttilew)
3272 {
3273 lighttile &tile = lighttiles[y][x];
3274 tile.band = band;
3275 for(int offset = 0;;)
3276 {
3277 int n = min(tile.lights.length() - offset, lighttilebatch);
3278 bool shadowmap = false, spotlight = false;
3279 if(n)
3280 {
3281 lightinfo &l = lights[tile.lights[offset]];
3282 shadowmap = l.shadowmap >= 0;
3283 spotlight = l.spot > 0;
3284 }
3285 loopj(n)
3286 {
3287 lightinfo &l = lights[tile.lights[offset+j]];
3288 if((l.shadowmap >= 0) != shadowmap || (l.spot > 0) != spotlight) { n = j; break; }
3289 }
3290 int priority = (offset || sunpass ? 4 : 0) + (shadowmap ? 0 : 2) + (spotlight ? 1 : 0);
3291 lighttileslice slice(&tile, priority, offset, n);
3292 lightbatch &batch = lightbatcher[slice];
3293 if(batch.strips.empty() || !lighttilestrip || !batch.strips.last().extend(x, y))
3294 {
3295 if(batch.strips.empty())
3296 {
3297 (lighttileslice &)batch = slice;
3298 lightbatches.add(&batch);
3299 }
3300 lightstrip &strip = batch.strips.add();
3301 strip.x = x;
3302 strip.y = y;
3303 strip.w = 1;
3304 }
3305 offset += n;
3306 if(offset >= tile.lights.length()) break;
3307 }
3308 }
3309 }
3310 lightbatches.sort(sortlightbatches);
3311 lightbatchesused = lightbatches.length();
3312 }
3313
nogiquad(int x,int y,int w,int h)3314 static inline void nogiquad(int x, int y, int w, int h)
3315 {
3316 gle::attribf(x, y+h);
3317 gle::attribf(x+w, y+h);
3318 gle::attribf(x+w, y);
3319 gle::attribf(x, y);
3320 }
3321
rendernogi(cube * c,const ivec & o,int size,const ivec & bbmin,const ivec & bbmax,int minsize)3322 static inline bool rendernogi(cube *c, const ivec &o, int size, const ivec &bbmin, const ivec &bbmax, int minsize)
3323 {
3324 ivec mid = ivec(o).add(size);
3325 uchar overlap = 0;
3326 if(bbmin.y < mid.y)
3327 {
3328 if(bbmin.x < mid.x)
3329 {
3330 if((bbmin.z < mid.z && (c[0].children ? rendernogi(c[0].children, ivec(o.x, o.y, o.z), size>>1, bbmin, bbmax, minsize) : c[0].material&MAT_NOGI)) ||
3331 (bbmax.z > mid.z && (c[4].children ? rendernogi(c[4].children, ivec(o.x, o.y, mid.z), size>>1, bbmin, bbmax, minsize) : c[4].material&MAT_NOGI)))
3332 overlap |= 1;
3333 }
3334 if(bbmax.x > mid.x)
3335 {
3336 if((bbmin.z < mid.z && (c[1].children ? rendernogi(c[1].children, ivec(mid.x, o.y, o.z), size>>1, bbmin, bbmax, minsize) : c[1].material&MAT_NOGI)) ||
3337 (bbmax.z > mid.z && (c[5].children ? rendernogi(c[5].children, ivec(mid.x, o.y, mid.z), size>>1, bbmin, bbmax, minsize) : c[5].material&MAT_NOGI)))
3338 overlap |= 2;
3339 }
3340 }
3341 if(bbmax.y > mid.y)
3342 {
3343 if(bbmin.x < mid.x)
3344 {
3345 if((bbmin.z < mid.z && (c[2].children ? rendernogi(c[2].children, ivec(o.x, mid.y, o.z), size>>1, bbmin, bbmax, minsize) : c[2].material&MAT_NOGI)) ||
3346 (bbmax.z > mid.z && (c[6].children ? rendernogi(c[6].children, ivec(o.x, mid.y, mid.z), size>>1, bbmin, bbmax, minsize) : c[6].material&MAT_NOGI)))
3347 overlap |= 4;
3348 }
3349 if(bbmax.x > mid.x)
3350 {
3351 if((bbmin.z < mid.z && (c[3].children ? rendernogi(c[3].children, ivec(mid.x, mid.y, o.z), size>>1, bbmin, bbmax, minsize) : c[3].material&MAT_NOGI)) ||
3352 (bbmax.z > mid.z && (c[7].children ? rendernogi(c[7].children, ivec(mid.x, mid.y, mid.z), size>>1, bbmin, bbmax, minsize) : c[7].material&MAT_NOGI)))
3353 overlap |= 8;
3354 }
3355 }
3356 if(!overlap) return false;
3357 if(overlap == 0xF || size <= minsize) return true;
3358 if(overlap&1)
3359 {
3360 if(overlap&2) nogiquad(o.x, o.y, 2*size, size);
3361 else nogiquad(o.x, o.y, size, size);
3362 }
3363 else if(overlap&2) nogiquad(o.x+size, o.y, size, size);
3364 if(overlap&4)
3365 {
3366 if(overlap&8) nogiquad(o.x, o.y+size, 2*size, size);
3367 else nogiquad(o.x, o.y+size, size, size);
3368 }
3369 else if(overlap&8) nogiquad(o.x+size, o.y+size, size, size);
3370 return false;
3371 }
3372
rendernogi(const ivec & bbmin,const ivec & bbmax,int minsize)3373 static inline void rendernogi(const ivec &bbmin, const ivec &bbmax, int minsize)
3374 {
3375 if(rendernogi(worldroot, ivec(0, 0, 0), worldsize>>1, ivec(bbmin).max(nogimin), ivec(bbmax).min(nogimax), minsize))
3376 nogiquad(0, 0, worldsize, worldsize);
3377 }
3378
rhquad(float x1,float y1,float x2,float y2,float tx1,float ty1,float tx2,float ty2,float tz)3379 static inline void rhquad(float x1, float y1, float x2, float y2, float tx1, float ty1, float tx2, float ty2, float tz)
3380 {
3381 gle::begin(GL_TRIANGLE_STRIP);
3382 gle::attribf(x2, y1); gle::attribf(tx2, ty1, tz);
3383 gle::attribf(x1, y1); gle::attribf(tx1, ty1, tz);
3384 gle::attribf(x2, y2); gle::attribf(tx2, ty2, tz);
3385 gle::attribf(x1, y2); gle::attribf(tx1, ty2, tz);
3386 gle::end();
3387 }
3388
rhquad(float dx1,float dy1,float dx2,float dy2,float dtx1,float dty1,float dtx2,float dty2,float dtz,float px1,float py1,float px2,float py2,float ptx1,float pty1,float ptx2,float pty2,float ptz)3389 static inline void rhquad(float dx1, float dy1, float dx2, float dy2, float dtx1, float dty1, float dtx2, float dty2, float dtz,
3390 float px1, float py1, float px2, float py2, float ptx1, float pty1, float ptx2, float pty2, float ptz)
3391 {
3392 gle::begin(GL_TRIANGLE_STRIP);
3393 gle::attribf(dx2, dy1); gle::attribf(dtx2, dty1, dtz);
3394 gle::attribf(px2, py1); gle::attribf(ptx2, pty1, ptz);
3395 gle::attribf(dx1, dy1); gle::attribf(dtx1, dty1, dtz);
3396 gle::attribf(px1, py1); gle::attribf(ptx1, pty1, ptz);
3397 gle::attribf(dx1, dy2); gle::attribf(dtx1, dty2, dtz);
3398 gle::attribf(px1, py2); gle::attribf(ptx1, pty2, ptz);
3399 gle::attribf(dx2, dy2); gle::attribf(dtx2, dty2, dtz);
3400 gle::attribf(px2, py2); gle::attribf(ptx2, pty2, ptz);
3401 gle::attribf(dx2, dy1); gle::attribf(dtx2, dty1, dtz);
3402 gle::attribf(px2, py1); gle::attribf(ptx2, pty1, ptz);
3403 gle::end();
3404 }
3405
renderslices()3406 void radiancehints::renderslices()
3407 {
3408 int sw = rhgrid+2*rhborder, sh = rhgrid+2*rhborder;
3409 glBindFramebuffer_(GL_FRAMEBUFFER, rhfbo);
3410 if(!rhrect)
3411 {
3412 glViewport(0, 0, sw, sh);
3413 if(rhcache) loopi(4) swap(rhtex[i], rhtex[i+4]);
3414 }
3415
3416 GLOBALPARAMF(rhatten, 1.0f/(gidist*gidist));
3417 GLOBALPARAMF(rsmspread, gidist*rsmspread*rsm.scale.x, gidist*rsmspread*rsm.scale.y);
3418 GLOBALPARAMF(rhaothreshold, splits[0].bounds/rhgrid);
3419 GLOBALPARAMF(rhaoatten, 1.0f/(gidist*rsmspread));
3420 GLOBALPARAMF(rhaoheight, gidist*rsmspread);
3421
3422 matrix4 rsmtcmatrix;
3423 rsmtcmatrix.identity();
3424 rsmtcmatrix.settranslation(rsm.offset);
3425 rsmtcmatrix.setscale(rsm.scale);
3426 rsmtcmatrix.mul(rsm.model);
3427 GLOBALPARAM(rsmtcmatrix, rsmtcmatrix);
3428
3429 matrix4 rsmworldmatrix;
3430 rsmworldmatrix.invert(rsmtcmatrix);
3431 GLOBALPARAM(rsmworldmatrix, rsmworldmatrix);
3432
3433 glBindTexture(GL_TEXTURE_RECTANGLE, rsmdepthtex);
3434 glActiveTexture_(GL_TEXTURE1);
3435 glBindTexture(GL_TEXTURE_RECTANGLE, rsmcolortex);
3436 glActiveTexture_(GL_TEXTURE2);
3437 glBindTexture(GL_TEXTURE_RECTANGLE, rsmnormaltex);
3438 if(rhborder) loopi(4)
3439 {
3440 glActiveTexture_(GL_TEXTURE3 + i);
3441 glBindTexture(GL_TEXTURE_3D, rhtex[i]);
3442 }
3443 if(rhcache) loopi(4)
3444 {
3445 glActiveTexture_(GL_TEXTURE7 + i);
3446 glBindTexture(GL_TEXTURE_3D, rhtex[rhrect ? i : 4+i]);
3447 }
3448 glActiveTexture_(GL_TEXTURE0);
3449
3450 glClearColor(0.5f, 0.5f, 0.5f, 0);
3451 if(rhrect) glEnable(GL_SCISSOR_TEST);
3452
3453 gle::defvertex(2);
3454 gle::deftexcoord0(3);
3455
3456 memset(rhclearmasks[0], 0xFF, sizeof(rhclearmasks[0]));
3457
3458 loopirev(rhsplits)
3459 {
3460 splitinfo &split = splits[i];
3461 if((rhrect || !rhcache || hasCI) && split.cached == split.center && !rhforce)
3462 {
3463 bool bordercached = true;
3464 if(rhborder) for(int k = i+1; k < rhsplits; k++) if(splits[k].cached != splits[k].center) { bordercached = false; break; }
3465 if(bordercached)
3466 {
3467 if(rhrect || !rhcache) continue;
3468 loopk(4) glCopyImageSubData_(rhtex[4+k], GL_TEXTURE_3D, 0, 0, 0, i*sh, rhtex[k], GL_TEXTURE_3D, 0, 0, 0, i*sh, sw, sh, sh);
3469 continue;
3470 }
3471 }
3472
3473 float cellradius = split.bounds/rhgrid, step = 2*cellradius, nudge = rhnudge*2*splits[0].bounds/rhgrid + rhworldbias*step;
3474 GLOBALPARAM(rhcenter, split.center);
3475 GLOBALPARAMF(rhbounds, split.bounds);
3476 GLOBALPARAMF(rhspread, cellradius);
3477
3478 vec cmin, cmax, bmin(1e16f, 1e16f, 1e16f), bmax(-1e16f, -1e16f, -1e16f), dmin(1e16f, 1e16f, 1e16f), dmax(-1e16f, -1e16f, -1e16f);
3479 loopk(3)
3480 {
3481 cmin[k] = floor((worldmin[k] - nudge - (split.center[k] - split.bounds))/step)*step + split.center[k] - split.bounds;
3482 cmax[k] = ceil((worldmax[k] + nudge - (split.center[k] - split.bounds))/step)*step + split.center[k] - split.bounds;
3483 }
3484 if(prevdynmin.z < prevdynmax.z) loopk(3)
3485 {
3486 dmin[k] = min(dmin[k], (float)floor((prevdynmin[k] - gidist - cellradius - (split.center[k] - split.bounds))/step)*step + split.center[k] - split.bounds);
3487 dmax[k] = max(dmax[k], (float)ceil((prevdynmax[k] + gidist + cellradius - (split.center[k] - split.bounds))/step)*step + split.center[k] - split.bounds);
3488 }
3489 if(dynmin.z < dynmax.z) loopk(3)
3490 {
3491 dmin[k] = min(dmin[k], (float)floor((dynmin[k] - gidist - cellradius - (split.center[k] - split.bounds))/step)*step + split.center[k] - split.bounds);
3492 dmax[k] = max(dmax[k], (float)ceil((dynmax[k] + gidist + cellradius - (split.center[k] - split.bounds))/step)*step + split.center[k] - split.bounds);
3493 }
3494
3495 if(rhborder && i + 1 < rhsplits)
3496 {
3497 GLOBALPARAMF(bordercenter, 0.5f, 0.5f, float(i+1 + 0.5f)/rhsplits);
3498 GLOBALPARAMF(borderrange, 0.5f - 0.5f/(rhgrid+2), 0.5f - 0.5f/(rhgrid+2), (0.5f - 0.5f/(rhgrid+2))/rhsplits);
3499 GLOBALPARAMF(borderscale, rhgrid+2, rhgrid+2, (rhgrid+2)*rhsplits);
3500 splitinfo &next = splits[i+1];
3501 loopk(3)
3502 {
3503 bmin[k] = floor((max(float(worldmin[k] - nudge), next.center[k] - next.bounds) - (split.center[k] - split.bounds))/step)*step + split.center[k] - split.bounds;
3504 bmax[k] = ceil((min(float(worldmax[k] + nudge), next.center[k] + next.bounds) - (split.center[k] - split.bounds))/step)*step + split.center[k] - split.bounds;
3505 }
3506 }
3507
3508 int sy = rhrect ? i*sh : 0;
3509 loopjrev(sh)
3510 {
3511 int sx = rhrect ? j*sw : 0;
3512 if(rhrect)
3513 {
3514 glViewport(sx, sy, sw, sh);
3515 glScissor(sx, sy, sw, sh);
3516 }
3517 else
3518 {
3519 glFramebufferTexture3D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_3D, rhtex[0], 0, i*sh + j);
3520 glFramebufferTexture3D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_3D, rhtex[1], 0, i*sh + j);
3521 glFramebufferTexture3D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_3D, rhtex[2], 0, i*sh + j);
3522 glFramebufferTexture3D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_3D, rhtex[3], 0, i*sh + j);
3523 }
3524
3525 float x1 = split.center.x - split.bounds, x2 = split.center.x + split.bounds,
3526 y1 = split.center.y - split.bounds, y2 = split.center.y + split.bounds,
3527 z = split.center.z - split.bounds + (j-rhborder+0.5f)*step,
3528 vx1 = -1 + rhborder*2.0f/(rhgrid+2), vx2 = 1 - rhborder*2.0f/(rhgrid+2), vy1 = -1 + rhborder*2.0f/(rhgrid+2), vy2 = 1 - rhborder*2.0f/(rhgrid+2),
3529 tx1 = x1, tx2 = x2, ty1 = y1, ty2 = y2;
3530
3531 if(rhborder && i + 1 < rhsplits)
3532 {
3533 splitinfo &next = splits[i+1];
3534 float bx1 = x1-step, bx2 = x2+step, by1 = y1-step, by2 = y2+step, bz = z,
3535 bvx1 = -1, bvx2 = 1, bvy1 = -1, bvy2 = 1,
3536 btx1 = bx1, btx2 = bx2, bty1 = by1, bty2 = by2;
3537
3538 if(rhclipgrid)
3539 {
3540 if(bz < bmin.z || bz > bmax.z) goto noborder;
3541 if(bx1 < bmin.x || bx2 > bmax.x || by1 < bmin.y || by2 > bmax.y)
3542 {
3543 btx1 = max(bx1, bmin.x);
3544 btx2 = min(bx2, bmax.x);
3545 bty1 = max(by1, bmin.y);
3546 bty2 = min(by2, bmax.y);
3547 if(btx1 > tx2 || bty1 > bty2) goto noborder;
3548 bvx1 += 2*(btx1 - bx1)/(bx2 - bx1);
3549 bvx2 += 2*(btx2 - bx2)/(bx2 - bx1);
3550 bvy1 += 2*(bty1 - by1)/(by2 - by1);
3551 bvy2 += 2*(bty2 - by2)/(by2 - by1);
3552
3553 glClear(GL_COLOR_BUFFER_BIT);
3554 }
3555 }
3556
3557 btx1 = btx1*next.scale.x + next.offset.x;
3558 btx2 = btx2*next.scale.x + next.offset.x;
3559 bty1 = bty1*next.scale.y + next.offset.y;
3560 bty2 = bty2*next.scale.y + next.offset.y;
3561 bz = bz*next.scale.z + next.offset.z;
3562
3563 SETSHADER(radiancehintsborder);
3564 rhquad(bvx1, bvy1, bvx2, bvy2, btx1, bty1, btx2, bty2, bz);
3565
3566 rhclearmasks[0][i][j/32] &= ~(1 << (j%32));
3567 }
3568 else
3569 {
3570 noborder:
3571 if(rhborder) glClear(GL_COLOR_BUFFER_BIT);
3572 }
3573
3574 if(j < rhborder || j >= rhgrid + rhborder) continue;
3575
3576 if(rhclipgrid)
3577 {
3578 if(z < cmin.z || z > cmax.z)
3579 {
3580 if(!rhborder) glClear(GL_COLOR_BUFFER_BIT);
3581 continue;
3582 }
3583 if(x1 < cmin.x || x2 > cmax.x || y1 < cmin.y || y2 > cmax.y)
3584 {
3585 if(!rhborder) glClear(GL_COLOR_BUFFER_BIT);
3586 tx1 = max(x1, cmin.x);
3587 tx2 = min(x2, cmax.x);
3588 ty1 = max(y1, cmin.y);
3589 ty2 = min(y2, cmax.y);
3590 if(tx1 > tx2 || ty1 > ty2) continue;
3591 vx1 += 2*rhgrid/float(sw)*(tx1 - x1)/(x2 - x1);
3592 vx2 += 2*rhgrid/float(sw)*(tx2 - x2)/(x2 - x1);
3593 vy1 += 2*rhgrid/float(sh)*(ty1 - y1)/(y2 - y1);
3594 vy2 += 2*rhgrid/float(sh)*(ty2 - y2)/(y2 - y1);
3595 }
3596 }
3597
3598 rhclearmasks[0][i][j/32] &= ~(1 << (j%32));
3599
3600 if(rhcache && z > split.cached.z - split.bounds && z < split.cached.z + split.bounds)
3601 {
3602 float px1 = max(tx1, split.cached.x - split.bounds), px2 = min(tx2, split.cached.x + split.bounds),
3603 py1 = max(ty1, split.cached.y - split.bounds), py2 = min(ty2, split.cached.y + split.bounds);
3604 if(px1 < px2 && py1 < py2)
3605 {
3606 float pvx1 = -1 + rhborder*2.0f/(rhgrid+2) + 2*rhgrid/float(sw)*(px1 - x1)/(x2 - x1),
3607 pvx2 = 1 - rhborder*2.0f/(rhgrid+2) + 2*rhgrid/float(sw)*(px2 - x2)/(x2 - x1),
3608 pvy1 = -1 + rhborder*2.0f/(rhgrid+2) + 2*rhgrid/float(sh)*(py1 - y1)/(y2 - y1),
3609 pvy2 = 1 - rhborder*2.0f/(rhgrid+2) + 2*rhgrid/float(sh)*(py2 - y2)/(y2 - y1),
3610 ptx1 = (px1 + split.center.x - split.cached.x)*split.scale.x + split.offset.x,
3611 ptx2 = (px2 + split.center.x - split.cached.x)*split.scale.x + split.offset.x,
3612 pty1 = (py1 + split.center.y - split.cached.y)*split.scale.y + split.offset.y,
3613 pty2 = (py2 + split.center.y - split.cached.y)*split.scale.y + split.offset.y,
3614 pz = (z + split.center.z - split.cached.z)*split.scale.z + split.offset.z;
3615
3616 if(px1 != tx1 || px2 != tx2 || py1 != ty1 || py2 != ty2)
3617 {
3618 radiancehintsshader->set();
3619 rhquad(pvx1, pvy1, pvx2, pvy2, px1, py1, px2, py2, z,
3620 vx1, vy1, vx2, vy2, tx1, ty1, tx2, ty2, z);
3621 }
3622
3623 if(z > dmin.z && z < dmax.z)
3624 {
3625 float dx1 = max(px1, dmin.x), dx2 = min(px2, dmax.x),
3626 dy1 = max(py1, dmin.y), dy2 = min(py2, dmax.y);
3627 if(dx1 < dx2 && dy1 < dy2)
3628 {
3629 float dvx1 = -1 + rhborder*2.0f/(rhgrid+2) + 2*rhgrid/float(sw)*(dx1 - x1)/(x2 - x1),
3630 dvx2 = 1 - rhborder*2.0f/(rhgrid+2) + 2*rhgrid/float(sw)*(dx2 - x2)/(x2 - x1),
3631 dvy1 = -1 + rhborder*2.0f/(rhgrid+2) + 2*rhgrid/float(sh)*(dy1 - y1)/(y2 - y1),
3632 dvy2 = 1 - rhborder*2.0f/(rhgrid+2) + 2*rhgrid/float(sh)*(dy2 - y2)/(y2 - y1),
3633 dtx1 = (dx1 + split.center.x - split.cached.x)*split.scale.x + split.offset.x,
3634 dtx2 = (dx2 + split.center.x - split.cached.x)*split.scale.x + split.offset.x,
3635 dty1 = (dy1 + split.center.y - split.cached.y)*split.scale.y + split.offset.y,
3636 dty2 = (dy2 + split.center.y - split.cached.y)*split.scale.y + split.offset.y,
3637 dz = (z + split.center.z - split.cached.z)*split.scale.z + split.offset.z;
3638
3639 if(dx1 != px1 || dx2 != px2 || dy1 != py1 || dy2 != py2)
3640 {
3641 SETSHADER(radiancehintscached);
3642 rhquad(dvx1, dvy1, dvx2, dvy2, dtx1, dty1, dtx2, dty2, dz,
3643 pvx1, pvy1, pvx2, pvy2, ptx1, pty1, ptx2, pty2, pz);
3644 }
3645
3646 radiancehintsshader->set();
3647 rhquad(dvx1, dvy1, dvx2, dvy2, dx1, dy1, dx2, dy2, z);
3648 goto maskslice;
3649 }
3650 }
3651
3652 SETSHADER(radiancehintscached);
3653 rhquad(pvx1, pvy1, pvx2, pvy2, ptx1, pty1, ptx2, pty2, pz);
3654 goto maskslice;
3655 }
3656 }
3657
3658 radiancehintsshader->set();
3659 rhquad(vx1, vy1, vx2, vy2, tx1, ty1, tx2, ty2, z);
3660
3661 maskslice:
3662 if(i) continue;
3663 rendernogi(ivec::floor(vec(x1, y1, z - 0.5f*step)), ivec::ceil(vec(x2, y2, z + 0.5f*step)), int(step));
3664 if(gle::attribbuf.empty()) continue;
3665 SETSHADER(radiancehintsdisable);
3666 if(rhborder)
3667 {
3668 glScissor(sx + rhborder, sy + rhborder, sw - 2*rhborder, sh - 2*rhborder);
3669 if(!rhrect) glEnable(GL_SCISSOR_TEST);
3670 }
3671 gle::defvertex(2);
3672 gle::begin(GL_QUADS);
3673 gle::end();
3674 if(rhborder && !rhrect) glDisable(GL_SCISSOR_TEST);
3675 gle::defvertex(2);
3676 gle::deftexcoord0(3);
3677 }
3678 if(rhrect) loopk(4)
3679 {
3680 glReadBuffer(GL_COLOR_ATTACHMENT0+k);
3681 glBindTexture(GL_TEXTURE_3D, rhtex[k]);
3682 loopj(sh)
3683 {
3684 if(rhclearmasks[0][i][j/32] & rhclearmasks[1][i][j/32] & (1 << (j%32))) continue;
3685 glCopyTexSubImage3D_(GL_TEXTURE_3D, 0, 0, 0, sy+j, j*sw, sy, sw, sh);
3686 }
3687 }
3688 memcpy(rhclearmasks[1][i], rhclearmasks[0][i], sizeof(rhclearmasks[0][i]));
3689 }
3690
3691 gle::disable();
3692
3693 if(rhrect) glDisable(GL_SCISSOR_TEST);
3694 }
3695
3696 VAR(rhinoq, 0, 1, 1);
3697
renderradiancehints()3698 void renderradiancehints()
3699 {
3700 if(!useradiancehints()) return;
3701
3702 timer *rhcputimer = begintimer("radiance hints", false);
3703 timer *rhtimer = begintimer("radiance hints");
3704
3705 rh.setup();
3706 rsm.setup();
3707
3708 shadowmapping = SM_REFLECT;
3709 shadowside = 0;
3710 shadoworigin = vec(0, 0, 0);
3711 shadowdir = rsm.lightview;
3712 shadowbias = rsm.lightview.project_bb(worldmin, worldmax);
3713 shadowradius = fabs(rsm.lightview.project_bb(worldmax, worldmin));
3714
3715 findshadowvas();
3716 findshadowmms();
3717
3718 shadowmaskbatchedmodels(false);
3719 batchshadowmapmodels();
3720
3721 rh.prevdynmin = rh.dynmin;
3722 rh.prevdynmax = rh.dynmax;
3723 rh.dynmin = vec(1e16f, 1e16f, 1e16f);
3724 rh.dynmax = vec(-1e16f, -1e16f, -1e16f);
3725 if(rhdyntex) dynamicshadowvabounds(1<<shadowside, rh.dynmin, rh.dynmax);
3726 if(rhdynmm) batcheddynamicmodelbounds(1<<shadowside, rh.dynmin, rh.dynmax);
3727
3728 if(rhforce || rh.prevdynmin.z < rh.prevdynmax.z || rh.dynmin.z < rh.dynmax.z || !rh.allcached())
3729 {
3730 if(rhinoq && oqfrags && !drawtex)
3731 {
3732 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
3733 glDepthMask(GL_TRUE);
3734 }
3735
3736 glBindFramebuffer_(GL_FRAMEBUFFER, rsmfbo);
3737
3738 shadowmatrix.mul(rsm.proj, rsm.model);
3739 GLOBALPARAM(rsmmatrix, shadowmatrix);
3740 GLOBALPARAMF(rsmdir, -rsm.lightview.x, -rsm.lightview.y, -rsm.lightview.z);
3741
3742 glViewport(0, 0, rsmsize, rsmsize);
3743 glClearColor(0, 0, 0, 0);
3744 glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
3745
3746 renderrsmgeom(rhdyntex!=0);
3747 rendershadowmodelbatches(rhdynmm!=0);
3748
3749 rh.renderslices();
3750
3751 if(rhinoq && oqfrags && !drawtex)
3752 {
3753 glBindFramebuffer_(GL_FRAMEBUFFER, msaasamples ? msfbo : gfbo);
3754 glViewport(0, 0, vieww, viewh);
3755
3756 glFlush();
3757 }
3758 }
3759
3760 clearbatchedmapmodels();
3761
3762 shadowmapping = 0;
3763
3764 endtimer(rhtimer);
3765 endtimer(rhcputimer);
3766 }
3767
rendercsmshadowmaps()3768 void rendercsmshadowmaps()
3769 {
3770 shadowmapping = SM_CASCADE;
3771 shadoworigin = vec(0, 0, 0);
3772 shadowdir = csm.lightview;
3773 shadowbias = csm.lightview.project_bb(worldmin, worldmax);
3774 shadowradius = fabs(csm.lightview.project_bb(worldmax, worldmin));
3775
3776 float polyfactor = csmpolyfactor, polyoffset = csmpolyoffset;
3777 if(smfilter > 2) { polyfactor = csmpolyfactor2; polyoffset = csmpolyoffset2; }
3778 if(polyfactor || polyoffset)
3779 {
3780 glPolygonOffset(polyfactor, polyoffset);
3781 glEnable(GL_POLYGON_OFFSET_FILL);
3782 }
3783
3784 findshadowvas();
3785 findshadowmms();
3786
3787 shadowmaskbatchedmodels(smdynshadow!=0);
3788 batchshadowmapmodels();
3789
3790 loopi(csmsplits) if(csm.splits[i].idx >= 0)
3791 {
3792 const shadowmapinfo &sm = shadowmaps[csm.splits[i].idx];
3793
3794 shadowmatrix.mul(csm.splits[i].proj, csm.model);
3795 GLOBALPARAM(shadowmatrix, shadowmatrix);
3796
3797 glViewport(sm.x, sm.y, sm.size, sm.size);
3798 glScissor(sm.x, sm.y, sm.size, sm.size);
3799 glClear(GL_DEPTH_BUFFER_BIT);
3800
3801 shadowside = i;
3802
3803 rendershadowmapworld();
3804 rendershadowmodelbatches();
3805 }
3806
3807 clearbatchedmapmodels();
3808
3809 if(polyfactor || polyoffset) glDisable(GL_POLYGON_OFFSET_FILL);
3810
3811 shadowmapping = 0;
3812 }
3813
calcshadowinfo(const extentity & e,vec & origin,float & radius,vec & spotloc,int & spotangle,float & bias)3814 int calcshadowinfo(const extentity &e, vec &origin, float &radius, vec &spotloc, int &spotangle, float &bias)
3815 {
3816 if(e.attr5&L_NOSHADOW || e.attr1 <= smminradius) return SM_NONE;
3817
3818 origin = e.o;
3819 radius = e.attr1;
3820 int type, w, border;
3821 float lod;
3822 if(e.attached && e.attached->type == ET_SPOTLIGHT)
3823 {
3824 type = SM_SPOT;
3825 w = 1;
3826 border = 0;
3827 lod = smspotprec;
3828 spotloc = e.attached->o;
3829 spotangle = clamp(int(e.attached->attr1), 1, 89);
3830 }
3831 else
3832 {
3833 type = SM_CUBEMAP;
3834 w = 3;
3835 lod = smcubeprec;
3836 border = smfilter > 2 ? smborder2 : smborder;
3837 spotloc = e.o;
3838 spotangle = 0;
3839 }
3840
3841 lod *= smminsize;
3842 int size = clamp(int(ceil((lod * shadowatlaspacker.w) / SHADOWATLAS_SIZE)), 1, shadowatlaspacker.w / w);
3843 bias = border / float(size - border);
3844
3845 return type;
3846 }
3847
3848 matrix4 shadowmatrix;
3849
rendershadowmaps()3850 void rendershadowmaps()
3851 {
3852 float polyfactor = smpolyfactor, polyoffset = smpolyoffset;
3853 if(smfilter > 2) { polyfactor = smpolyfactor2; polyoffset = smpolyoffset2; }
3854 if(polyfactor || polyoffset)
3855 {
3856 glPolygonOffset(polyfactor, polyoffset);
3857 glEnable(GL_POLYGON_OFFSET_FILL);
3858 }
3859
3860 const vector<extentity *> &ents = entities::getents();
3861 loopv(shadowmaps)
3862 {
3863 shadowmapinfo &sm = shadowmaps[i];
3864 if(sm.light < 0) continue;
3865
3866 lightinfo &l = lights[sm.light];
3867 extentity *e = l.ent >= 0 ? ents[l.ent] : NULL;
3868
3869 int border, sidemask;
3870 if(l.spot)
3871 {
3872 shadowmapping = SM_SPOT;
3873 border = 0;
3874 sidemask = 1;
3875 }
3876 else
3877 {
3878 shadowmapping = SM_CUBEMAP;
3879 border = smfilter > 2 ? smborder2 : smborder;
3880 sidemask = smsidecull ? cullfrustumsides(l.o, l.radius, sm.size, border) : 0x3F;
3881 }
3882
3883 sm.sidemask = sidemask;
3884
3885 shadoworigin = l.o;
3886 shadowradius = l.radius;
3887 shadowbias = border / float(sm.size - border);
3888 shadowdir = l.dir;
3889 shadowspot = l.spot;
3890
3891 shadowmesh *mesh = e ? findshadowmesh(l.ent, *e) : NULL;
3892
3893 findshadowvas();
3894 findshadowmms();
3895
3896 shadowmaskbatchedmodels(!(l.flags&L_NODYNSHADOW) && smdynshadow);
3897 batchshadowmapmodels(mesh != NULL);
3898
3899 shadowcacheval *cached = NULL;
3900 int cachemask = 0;
3901 if(smcache)
3902 {
3903 int dynmask = smcache <= 1 ? batcheddynamicmodels() : 0;
3904 cached = sm.cached;
3905 if(cached)
3906 {
3907 if(!debugshadowatlas) cachemask = cached->sidemask & ~dynmask;
3908 sm.sidemask |= cachemask;
3909 }
3910 sm.sidemask &= ~dynmask;
3911
3912 sidemask &= ~cachemask;
3913 if(!sidemask) { clearbatchedmapmodels(); continue; }
3914 }
3915
3916 float smnearclip = SQRT3 / l.radius, smfarclip = SQRT3;
3917 matrix4 smprojmatrix(vec4(float(sm.size - border) / sm.size, 0, 0, 0),
3918 vec4(0, float(sm.size - border) / sm.size, 0, 0),
3919 vec4(0, 0, -(smfarclip + smnearclip) / (smfarclip - smnearclip), -1),
3920 vec4(0, 0, -2*smnearclip*smfarclip / (smfarclip - smnearclip), 0));
3921
3922 if(shadowmapping == SM_SPOT)
3923 {
3924 glViewport(sm.x, sm.y, sm.size, sm.size);
3925 glScissor(sm.x, sm.y, sm.size, sm.size);
3926 glClear(GL_DEPTH_BUFFER_BIT);
3927
3928 float invradius = 1.0f / l.radius, spotscale = invradius * cotan360(l.spot);
3929 matrix4 spotmatrix(vec(l.spotx).mul(spotscale), vec(l.spoty).mul(spotscale), vec(l.dir).mul(-invradius));
3930 spotmatrix.translate(vec(l.o).neg());
3931 shadowmatrix.mul(smprojmatrix, spotmatrix);
3932 GLOBALPARAM(shadowmatrix, shadowmatrix);
3933
3934 glCullFace((l.dir.z >= 0) == (smcullside != 0) ? GL_BACK : GL_FRONT);
3935
3936 shadowside = 0;
3937
3938 if(mesh) rendershadowmesh(mesh); else rendershadowmapworld();
3939 rendershadowmodelbatches();
3940 }
3941 else
3942 {
3943 if(!cachemask)
3944 {
3945 int cx1 = sidemask & 0x03 ? 0 : (sidemask & 0xC ? sm.size : 2 * sm.size),
3946 cx2 = sidemask & 0x30 ? 3 * sm.size : (sidemask & 0xC ? 2 * sm.size : sm.size),
3947 cy1 = sidemask & 0x15 ? 0 : sm.size,
3948 cy2 = sidemask & 0x2A ? 2 * sm.size : sm.size;
3949 glScissor(sm.x + cx1, sm.y + cy1, cx2 - cx1, cy2 - cy1);
3950 glClear(GL_DEPTH_BUFFER_BIT);
3951 }
3952 loop(side, 6) if(sidemask&(1<<side))
3953 {
3954 int sidex = (side>>1)*sm.size, sidey = (side&1)*sm.size;
3955 glViewport(sm.x + sidex, sm.y + sidey, sm.size, sm.size);
3956 glScissor(sm.x + sidex, sm.y + sidey, sm.size, sm.size);
3957 if(cachemask) glClear(GL_DEPTH_BUFFER_BIT);
3958
3959 matrix4 cubematrix(cubeshadowviewmatrix[side]);
3960 cubematrix.scale(1.0f/l.radius);
3961 cubematrix.translate(vec(l.o).neg());
3962 shadowmatrix.mul(smprojmatrix, cubematrix);
3963 GLOBALPARAM(shadowmatrix, shadowmatrix);
3964
3965 glCullFace((side & 1) ^ (side >> 2) ^ smcullside ? GL_FRONT : GL_BACK);
3966
3967 shadowside = side;
3968
3969 if(mesh) rendershadowmesh(mesh); else rendershadowmapworld();
3970 rendershadowmodelbatches();
3971 }
3972 }
3973
3974 clearbatchedmapmodels();
3975 }
3976
3977 if(polyfactor || polyoffset) glDisable(GL_POLYGON_OFFSET_FILL);
3978
3979 shadowmapping = 0;
3980 }
3981
rendershadowatlas()3982 void rendershadowatlas()
3983 {
3984 timer *smcputimer = begintimer("shadow map", false);
3985 timer *smtimer = begintimer("shadow map");
3986
3987 glBindFramebuffer_(GL_FRAMEBUFFER, shadowatlasfbo);
3988 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
3989
3990 if(debugshadowatlas)
3991 {
3992 glClearDepth(0);
3993 glClear(GL_DEPTH_BUFFER_BIT);
3994 glClearDepth(1);
3995 }
3996
3997 glEnable(GL_SCISSOR_TEST);
3998
3999 // sun light
4000 if(!sunlight.iszero() && csmshadowmap)
4001 {
4002 csm.setup();
4003 rendercsmshadowmaps();
4004 }
4005
4006 packlights();
4007
4008 // point lights
4009 rendershadowmaps();
4010
4011 glCullFace(GL_BACK);
4012 glDisable(GL_SCISSOR_TEST);
4013 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4014
4015 endtimer(smtimer);
4016 endtimer(smcputimer);
4017 }
4018
4019 FVAR(refractmargin, 0, 0.1f, 1);
4020 FVAR(refractdepth, 1e-3f, 16, 1e3f);
4021
rendertransparent()4022 void rendertransparent()
4023 {
4024 int hasalphavas = findalphavas();
4025 int hasmats = findmaterials();
4026 bool hasmodels = transmdlsx1 < transmdlsx2 && transmdlsy1 < transmdlsy2;
4027 if(!hasalphavas && !hasmats && !hasmodels)
4028 {
4029 if(!editmode) renderparticles();
4030 return;
4031 }
4032
4033 if(!editmode && particlelayers && ghasstencil) renderparticles(PL_UNDER);
4034
4035 timer *transtimer = begintimer("transparent");
4036
4037 if(hasalphavas&4 || hasmats&4)
4038 {
4039 glBindFramebuffer_(GL_FRAMEBUFFER, msaasamples ? msrefractfbo : refractfbo);
4040 glDepthMask(GL_FALSE);
4041 if(msaasamples) glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msdepthtex);
4042 else glBindTexture(GL_TEXTURE_RECTANGLE, gdepthtex);
4043 float sx1 = min(alpharefractsx1, matrefractsx1), sy1 = min(alpharefractsy1, matrefractsy1),
4044 sx2 = max(alpharefractsx2, matrefractsx2), sy2 = max(alpharefractsy2, matrefractsy2);
4045 bool scissor = sx1 > -1 || sy1 > -1 || sx2 < 1 || sy2 < 1;
4046 if(scissor)
4047 {
4048 int x1 = int(floor(max(sx1*0.5f+0.5f-refractmargin*viewh/vieww, 0.0f)*vieww)),
4049 y1 = int(floor(max(sy1*0.5f+0.5f-refractmargin, 0.0f)*viewh)),
4050 x2 = int(ceil(min(sx2*0.5f+0.5f+refractmargin*viewh/vieww, 1.0f)*vieww)),
4051 y2 = int(ceil(min(sy2*0.5f+0.5f+refractmargin, 1.0f)*viewh));
4052 glEnable(GL_SCISSOR_TEST);
4053 glScissor(x1, y1, x2 - x1, y2 - y1);
4054 }
4055 glClearColor(0, 0, 0, 0);
4056 glClear(GL_COLOR_BUFFER_BIT);
4057 if(scissor) glDisable(GL_SCISSOR_TEST);
4058 GLOBALPARAMF(refractdepth, 1.0f/refractdepth);
4059 SETSHADER(refractmask);
4060 if(hasalphavas&4) renderrefractmask();
4061 if(hasmats&4) rendermaterialmask();
4062
4063 glDepthMask(GL_TRUE);
4064 }
4065
4066 glActiveTexture_(GL_TEXTURE7);
4067 if(msaasamples) glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msrefracttex);
4068 else glBindTexture(GL_TEXTURE_RECTANGLE, refracttex);
4069 glActiveTexture_(GL_TEXTURE8);
4070 if(msaasamples) glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mshdrtex);
4071 else glBindTexture(GL_TEXTURE_RECTANGLE, hdrtex);
4072 glActiveTexture_(GL_TEXTURE9);
4073 if(msaasamples) glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msdepthtex);
4074 else glBindTexture(GL_TEXTURE_RECTANGLE, gdepthtex);
4075 glActiveTexture_(GL_TEXTURE0);
4076
4077 if(ghasstencil) glEnable(GL_STENCIL_TEST);
4078
4079 matrix4 raymatrix(vec(-0.5f*vieww*projmatrix.a.x, 0, 0.5f*vieww - 0.5f*vieww*projmatrix.c.x),
4080 vec(0, -0.5f*viewh*projmatrix.b.y, 0.5f*viewh - 0.5f*viewh*projmatrix.c.y));
4081 raymatrix.muld(cammatrix);
4082 GLOBALPARAM(raymatrix, raymatrix);
4083 GLOBALPARAM(linearworldmatrix, linearworldmatrix);
4084
4085 uint tiles[LIGHTTILE_MAXH];
4086 float allsx1 = 1, allsy1 = 1, allsx2 = -1, allsy2 = -1, sx1, sy1, sx2, sy2;
4087
4088 loop(layer, 4)
4089 {
4090 switch(layer)
4091 {
4092 case 0:
4093 if(!(hasmats&1)) continue;
4094 sx1 = matliquidsx1; sy1 = matliquidsy1; sx2 = matliquidsx2; sy2 = matliquidsy2;
4095 memcpy(tiles, matliquidtiles, sizeof(tiles));
4096 break;
4097 case 1:
4098 if(!(hasalphavas&1)) continue;
4099 sx1 = alphabacksx1; sy1 = alphabacksy1; sx2 = alphabacksx2; sy2 = alphabacksy2;
4100 memcpy(tiles, alphatiles, sizeof(tiles));
4101 break;
4102 case 2:
4103 if(!(hasalphavas&2) && !(hasmats&2)) continue;
4104 sx1 = alphafrontsx1; sy1 = alphafrontsy1; sx2 = alphafrontsx2; sy2 = alphafrontsy2;
4105 memcpy(tiles, alphatiles, sizeof(tiles));
4106 if(hasmats&2)
4107 {
4108 sx1 = min(sx1, matsolidsx1);
4109 sy1 = min(sy1, matsolidsy1);
4110 sx2 = max(sx2, matsolidsx2);
4111 sy2 = max(sy2, matsolidsy2);
4112 loopj(LIGHTTILE_MAXH) tiles[j] |= matsolidtiles[j];
4113 }
4114 break;
4115 case 3:
4116 if(!hasmodels) continue;
4117 sx1 = transmdlsx1; sy1 = transmdlsy1; sx2 = transmdlsx2; sy2 = transmdlsy2;
4118 memcpy(tiles, transmdltiles, sizeof(tiles));
4119 break;
4120
4121 default:
4122 continue;
4123 }
4124
4125 allsx1 = min(allsx1, sx1);
4126 allsy1 = min(allsy1, sy1);
4127 allsx2 = max(allsx2, sx2);
4128 allsy2 = max(allsy2, sy2);
4129
4130 glBindFramebuffer_(GL_FRAMEBUFFER, msaasamples ? msfbo : gfbo);
4131 if(ghasstencil)
4132 {
4133 glStencilFunc(GL_ALWAYS, layer+1, ~0);
4134 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
4135 }
4136 else
4137 {
4138 bool scissor = sx1 > -1 || sy1 > -1 || sx2 < 1 || sy2 < 1;
4139 if(scissor)
4140 {
4141 int x1 = int(floor((sx1*0.5f+0.5f)*vieww)), y1 = int(floor((sy1*0.5f+0.5f)*viewh)),
4142 x2 = int(ceil((sx2*0.5f+0.5f)*vieww)), y2 = int(ceil((sy2*0.5f+0.5f)*viewh));
4143 glEnable(GL_SCISSOR_TEST);
4144 glScissor(x1, y1, x2 - x1, y2 - y1);
4145 }
4146
4147 maskgbuffer("n");
4148 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
4149 glClearColor(0, 0, 0, 0);
4150 glClear(GL_COLOR_BUFFER_BIT);
4151 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4152 if(scissor) glDisable(GL_SCISSOR_TEST);
4153 }
4154 maskgbuffer("cndg");
4155
4156 if(wireframe && editmode) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
4157
4158 switch(layer)
4159 {
4160 case 0:
4161 renderliquidmaterials();
4162 break;
4163 case 1:
4164 renderalphageom(1);
4165 break;
4166 case 2:
4167 if(hasalphavas&2) renderalphageom(2);
4168 if(hasmats&2) rendersolidmaterials();
4169 renderstains(STAINBUF_TRANSPARENT, true);
4170 break;
4171 case 3:
4172 rendertransparentmodelbatches(layer+1);
4173 break;
4174 }
4175
4176 if(wireframe && editmode) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
4177
4178 if(msaasamples)
4179 {
4180 glBindFramebuffer_(GL_FRAMEBUFFER, mshdrfbo);
4181 if((ghasstencil && msaaedgedetect) || (!hasMSS && msaasamples==2)) loopi(2) renderlights(sx1, sy1, sx2, sy2, tiles, layer+1, i+1, true);
4182 else renderlights(sx1, sy1, sx2, sy2, tiles, layer+1, 3, true);
4183 }
4184 else
4185 {
4186 glBindFramebuffer_(GL_FRAMEBUFFER, hdrfbo);
4187 renderlights(sx1, sy1, sx2, sy2, tiles, layer+1, 0, true);
4188 }
4189
4190 switch(layer)
4191 {
4192 case 2:
4193 if(ghasstencil)
4194 {
4195 glStencilFunc(GL_EQUAL, layer+1, 0x07);
4196 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
4197 }
4198 renderstains(STAINBUF_TRANSPARENT, false);
4199 break;
4200 }
4201 }
4202
4203 if(ghasstencil) glDisable(GL_STENCIL_TEST);
4204
4205 endtimer(transtimer);
4206
4207 if(editmode) return;
4208
4209 if(particlelayers && ghasstencil)
4210 {
4211 bool scissor = allsx1 > -1 || allsy1 > -1 || allsx2 < 1 || allsy2 < 1;
4212 if(scissor)
4213 {
4214 int x1 = int(floor((allsx1*0.5f+0.5f)*vieww)), y1 = int(floor((allsy1*0.5f+0.5f)*viewh)),
4215 x2 = int(ceil((allsx2*0.5f+0.5f)*vieww)), y2 = int(ceil((allsy2*0.5f+0.5f)*viewh));
4216 glEnable(GL_SCISSOR_TEST);
4217 glScissor(x1, y1, x2 - x1, y2 - y1);
4218 }
4219 glStencilFunc(GL_NOTEQUAL, 0, 0x07);
4220 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
4221 glEnable(GL_STENCIL_TEST);
4222 renderparticles(PL_OVER);
4223 glDisable(GL_STENCIL_TEST);
4224 if(scissor) glDisable(GL_SCISSOR_TEST);
4225
4226 renderparticles(PL_NOLAYER);
4227 }
4228 else renderparticles();
4229 }
4230
4231 VAR(gdepthclear, 0, 1, 1);
4232 VAR(gcolorclear, 0, 1, 1);
4233
preparegbuffer(bool depthclear)4234 void preparegbuffer(bool depthclear)
4235 {
4236 glBindFramebuffer_(GL_FRAMEBUFFER, msaasamples ? msfbo : gfbo);
4237 glViewport(0, 0, vieww, viewh);
4238
4239 if(drawtex && gdepthinit)
4240 {
4241 glEnable(GL_SCISSOR_TEST);
4242 glScissor(0, 0, vieww, viewh);
4243 }
4244 if(gdepthformat && gdepthclear)
4245 {
4246 maskgbuffer("d");
4247 if(gdepthformat == 1) glClearColor(1, 1, 1, 1);
4248 else glClearColor(-farplane, 0, 0, 0);
4249 glClear(GL_COLOR_BUFFER_BIT);
4250 maskgbuffer("cn");
4251 }
4252 else maskgbuffer("cnd");
4253 if(gcolorclear) glClearColor(0, 0, 0, 0);
4254 glClear((depthclear ? GL_DEPTH_BUFFER_BIT : 0)|(gcolorclear ? GL_COLOR_BUFFER_BIT : 0)|(depthclear && ghasstencil ? GL_STENCIL_BUFFER_BIT : 0));
4255 if(gdepthformat && gdepthclear) maskgbuffer("cnd");
4256 if(drawtex && gdepthinit) glDisable(GL_SCISSOR_TEST);
4257 gdepthinit = true;
4258
4259 matrix4 invscreenmatrix;
4260 invscreenmatrix.identity();
4261 invscreenmatrix.settranslation(-1.0f, -1.0f, -1.0f);
4262 invscreenmatrix.setscale(2.0f/vieww, 2.0f/viewh, 2.0f);
4263 eyematrix.muld(invprojmatrix, invscreenmatrix);
4264 if(drawtex == DRAWTEX_MINIMAP)
4265 {
4266 linearworldmatrix.muld(invcamprojmatrix, invscreenmatrix);
4267 if(!gdepthformat) worldmatrix = linearworldmatrix;
4268 linearworldmatrix.a.z = invcammatrix.a.z;
4269 linearworldmatrix.b.z = invcammatrix.b.z;
4270 linearworldmatrix.c.z = invcammatrix.c.z;
4271 linearworldmatrix.d.z = invcammatrix.d.z;
4272 if(gdepthformat) worldmatrix = linearworldmatrix;
4273
4274 GLOBALPARAMF(radialfogscale, 0, 0, 0, 0);
4275 }
4276 else
4277 {
4278 float xscale = eyematrix.a.x, yscale = eyematrix.b.y, xoffset = eyematrix.d.x, yoffset = eyematrix.d.y, zscale = eyematrix.d.z;
4279 matrix4 depthmatrix(vec(xscale/zscale, 0, xoffset/zscale), vec(0, yscale/zscale, yoffset/zscale));
4280 linearworldmatrix.muld(invcammatrix, depthmatrix);
4281 if(gdepthformat) worldmatrix = linearworldmatrix;
4282 else worldmatrix.muld(invcamprojmatrix, invscreenmatrix);
4283
4284 GLOBALPARAMF(radialfogscale, xscale/zscale, yscale/zscale, xoffset/zscale, yoffset/zscale);
4285 }
4286
4287 screenmatrix.identity();
4288 screenmatrix.settranslation(0.5f*vieww, 0.5f*viewh, 0.5f);
4289 screenmatrix.setscale(0.5f*vieww, 0.5f*viewh, 0.5f);
4290 screenmatrix.muld(camprojmatrix);
4291
4292 GLOBALPARAMF(viewsize, vieww, viewh, 1.0f/vieww, 1.0f/viewh);
4293 GLOBALPARAMF(gdepthscale, eyematrix.d.z, eyematrix.c.w, eyematrix.d.w);
4294 GLOBALPARAMF(gdepthpackparams, -1.0f/farplane, -255.0f/farplane, -(255.0f*255.0f)/farplane);
4295 GLOBALPARAMF(gdepthunpackparams, -farplane, -farplane/255.0f, -farplane/(255.0f*255.0f));
4296 GLOBALPARAM(worldmatrix, worldmatrix);
4297
4298 GLOBALPARAMF(ldrscale, ldrscale);
4299 GLOBALPARAMF(hdrgamma, hdrgamma, 1.0f/hdrgamma);
4300 GLOBALPARAM(camera, camera1->o);
4301 GLOBALPARAMF(millis, lastmillis/1000.0f);
4302
4303 GLERROR;
4304 }
4305
rendergbuffer(bool depthclear)4306 void rendergbuffer(bool depthclear)
4307 {
4308 timer *gcputimer = drawtex ? NULL : begintimer("g-buffer", false);
4309 timer *gtimer = drawtex ? NULL : begintimer("g-buffer");
4310
4311 preparegbuffer(depthclear);
4312
4313 if(limitsky())
4314 {
4315 renderexplicitsky();
4316 GLERROR;
4317 }
4318 rendergeom();
4319 GLERROR;
4320 renderdecals();
4321 GLERROR;
4322 resetmodelbatches();
4323 rendermapmodels();
4324 GLERROR;
4325
4326 if(drawtex == DRAWTEX_MINIMAP)
4327 {
4328 renderminimapmaterials();
4329 }
4330 else if(!drawtex)
4331 {
4332 game::rendergame();
4333 rendermodelbatches();
4334 GLERROR;
4335 renderstains(STAINBUF_OPAQUE, true);
4336 GLERROR;
4337 renderavatar();
4338 GLERROR;
4339 }
4340
4341 endtimer(gtimer);
4342 endtimer(gcputimer);
4343 }
4344
shademinimap(const vec & color)4345 void shademinimap(const vec &color)
4346 {
4347 GLERROR;
4348
4349 glBindFramebuffer_(GL_FRAMEBUFFER, msaasamples ? mshdrfbo : hdrfbo);
4350 glViewport(0, 0, vieww, viewh);
4351
4352 if(color.x >= 0)
4353 {
4354 glClearColor(color.x, color.y, color.z, 0);
4355 glClear(GL_COLOR_BUFFER_BIT);
4356 }
4357
4358 renderlights(-1, -1, 1, 1, NULL, 0, msaasamples ? -1 : 0);
4359 GLERROR;
4360 }
4361
shademodelpreview(int x,int y,int w,int h,bool background,bool scissor)4362 void shademodelpreview(int x, int y, int w, int h, bool background, bool scissor)
4363 {
4364 GLERROR;
4365
4366 glBindFramebuffer_(GL_FRAMEBUFFER, ovr::lensfbo[viewidx]);
4367 glViewport(x, y, w, h);
4368
4369 if(msaasamples) glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mscolortex);
4370 else glBindTexture(GL_TEXTURE_RECTANGLE, gcolortex);
4371 glActiveTexture_(GL_TEXTURE1);
4372 if(msaasamples) glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msnormaltex);
4373 else glBindTexture(GL_TEXTURE_RECTANGLE, gnormaltex);
4374 glActiveTexture_(GL_TEXTURE3);
4375 if(msaasamples) glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msdepthtex);
4376 else glBindTexture(GL_TEXTURE_RECTANGLE, gdepthtex);
4377 glActiveTexture_(GL_TEXTURE0);
4378
4379 float lightscale = 2.0f*ldrscale;
4380 GLOBALPARAMF(lightscale, 0.1f*lightscale, 0.1f*lightscale, 0.1f*lightscale, lightscale);
4381 GLOBALPARAM(sunlightdir, vec(0, -1, 2).normalize());
4382 GLOBALPARAMF(sunlightcolor, 0.6f*lightscale, 0.6f*lightscale, 0.6f*lightscale);
4383
4384 SETSHADER(modelpreview);
4385
4386 LOCALPARAMF(cutout, background ? 0 : 1);
4387
4388 if(scissor) glEnable(GL_SCISSOR_TEST);
4389 screenquad(vieww, viewh);
4390 if(scissor) glDisable(GL_SCISSOR_TEST);
4391
4392 GLERROR;
4393
4394 glViewport(0, 0, hudw, hudh);
4395 }
4396
shadesky()4397 void shadesky()
4398 {
4399 glBindFramebuffer_(GL_FRAMEBUFFER, msaasamples ? mshdrfbo : hdrfbo);
4400 glViewport(0, 0, vieww, viewh);
4401
4402 drawskybox((hdrclear > 0 ? hdrclear-- : msaasamples) > 0);
4403 }
4404
shadegbuffer()4405 void shadegbuffer()
4406 {
4407 GLERROR;
4408
4409 timer *shcputimer = begintimer("deferred shading", false);
4410 timer *shtimer = begintimer("deferred shading");
4411
4412 shadesky();
4413
4414 if(msaasamples)
4415 {
4416 if((ghasstencil && msaaedgedetect) || (!hasMSS && msaasamples==2)) loopi(2) renderlights(-1, -1, 1, 1, NULL, 0, i+1);
4417 else renderlights(-1, -1, 1, 1, NULL, 0, drawtex ? -1 : 3);
4418 }
4419 else renderlights();
4420 GLERROR;
4421
4422 if(!drawtex) renderstains(STAINBUF_OPAQUE, false);
4423
4424 endtimer(shtimer);
4425 endtimer(shcputimer);
4426 }
4427
setuplights()4428 void setuplights()
4429 {
4430 GLERROR;
4431 setupgbuffer();
4432 if(bloomw < 0 || bloomh < 0) setupbloom(gw, gh);
4433 if(ao && (aow < 0 || aoh < 0)) setupao(gw, gh);
4434 if(!shadowatlasfbo) setupshadowatlas();
4435 if(useradiancehints() && !rhfbo) setupradiancehints();
4436 if(!deferredlightshader) loaddeferredlightshaders();
4437 if(drawtex == DRAWTEX_MINIMAP && !deferredminimapshader) deferredminimapshader = loaddeferredlightshader(msaasamples ? "mM" : "m");
4438 setupaa(gw, gh);
4439 GLERROR;
4440 }
4441
debuglights()4442 bool debuglights()
4443 {
4444 if(debugshadowatlas) viewshadowatlas();
4445 else if(debugao) viewao();
4446 else if(debugdepth) viewdepth();
4447 else if(debugstencil) viewstencil();
4448 else if(debugrefract) viewrefract();
4449 else if(debuglightscissor) viewlightscissor();
4450 else if(debugrsm) viewrsm();
4451 else if(debugrh) viewrh();
4452 else if(!debugaa()) return false;
4453 return true;
4454 }
4455
cleanuplights()4456 void cleanuplights()
4457 {
4458 cleanupgbuffer();
4459 cleanupbloom();
4460 cleanupao();
4461 cleanupshadowatlas();
4462 cleanupradiancehints();
4463 cleanuplightsphere();
4464 cleanupaa();
4465 }
4466
4467