Line data Source code
1 : /**
2 : * @file aa.cpp
3 : * @brief Screenspace antialiasing
4 : *
5 : * screenspace antialiasing methods (does NOT include multisample [MSAA]):
6 : * TQAA (temporal quincunx antialiasing)
7 : * FXAA (fast approximate antialiasing)
8 : * SMAA (subpixel morphological antialiasing)
9 : */
10 : #include "../libprimis-headers/cube.h"
11 : #include "../libprimis-headers/prop.h"
12 : #include "../../shared/geomexts.h"
13 : #include "../../shared/glemu.h"
14 : #include "../../shared/glexts.h"
15 :
16 : #include "aa.h"
17 : #include "hdr.h"
18 : #include "rendergl.h"
19 : #include "renderlights.h"
20 : #include "rendertimers.h"
21 : #include "renderwindow.h"
22 : #include "shader.h"
23 : #include "shaderparam.h"
24 : #include "texture.h"
25 :
26 : #include "interface/control.h"
27 :
28 : //externally used vars
29 : VAR(tqaaresolvegather, 1, 0, 0);
30 : matrix4 nojittermatrix;
31 :
32 : bool multisampledaa();
33 :
34 : namespace //internal functions incl. AA implementations
35 : {
36 : /* TQAA: Temporal Quincunx Anti Aliasing */
37 : ///////////////////////////////////////////
38 :
39 0 : VARFP(tqaa, 0, 0, 1, cleanupaa()); //`t`emporal `q`uincunx `a`nti `a`liasing: toggles temporal/quincunx antialiasing in general
40 : FVAR(tqaareproject, 0, 75, 1e3f); // `t`emporal `q`uincunx `a`nti `a`liasing `re-project`: factor which determines how much the tqaa algo is allowed to shift frame to frame (lower = more movementallowed)
41 0 : VARF(tqaamovemask, 0, 1, 1, cleanupaa());
42 : VARP(tqaaquincunx, 0, 1, 1); // `t`emporal `q`uincunx `a`nti `a`liasing `quincunx` toggles quincunx antialiasing for temporal AA (half pixel offset)
43 : FVAR(tqaacolorweightscale, 0, 0.25f, 1e3f);
44 : FVAR(tqaacolorweightbias, 0, 0.01f, 1);
45 :
46 :
47 : int tqaaframe = 0;
48 : GLuint tqaatex[2] = { 0, 0 },
49 : tqaafbo[2] = { 0, 0 };
50 : matrix4 tqaaprevscreenmatrix;
51 : int tqaatype = -1;
52 :
53 0 : void loadtqaashaders()
54 : {
55 0 : tqaatype = tqaamovemask ? AA_Masked : AA_Unused;
56 0 : loadhdrshaders(tqaatype);
57 0 : useshaderbyname("tqaaresolve");
58 0 : }
59 :
60 0 : void setuptqaa(GBuffer &buf, int w, int h)
61 : {
62 0 : for(int i = 0; i < 2; ++i)
63 : {
64 0 : if(!tqaatex[i])
65 : {
66 0 : glGenTextures(1, &tqaatex[i]);
67 : }
68 0 : if(!tqaafbo[i])
69 : {
70 0 : glGenFramebuffers(1, &tqaafbo[i]);
71 : }
72 0 : glBindFramebuffer(GL_FRAMEBUFFER, tqaafbo[i]);
73 0 : createtexture(tqaatex[i], w, h, nullptr, 3, 1, GL_RGBA8, GL_TEXTURE_RECTANGLE);
74 0 : glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, tqaatex[i], 0);
75 0 : buf.bindgdepth();
76 0 : if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
77 : {
78 0 : fatal("failed allocating TQAA buffer!");
79 : }
80 : }
81 0 : glBindFramebuffer(GL_FRAMEBUFFER, 0);
82 0 : tqaaprevscreenmatrix.identity();
83 0 : loadtqaashaders();
84 0 : }
85 :
86 0 : void cleanuptqaa()
87 : {
88 0 : tqaatype = -1;
89 0 : for(int i = 0; i < 2; ++i)
90 : {
91 0 : if(tqaatex[i])
92 : {
93 0 : glDeleteTextures(1, &tqaatex[i]);
94 0 : tqaatex[i] = 0;
95 : }
96 : }
97 0 : for(int i = 0; i < 2; ++i)
98 : {
99 0 : if(tqaafbo[i])
100 : {
101 0 : glDeleteFramebuffers(1, &tqaafbo[i]);
102 0 : tqaafbo[i] = 0;
103 : }
104 : }
105 0 : tqaaframe = 0;
106 0 : }
107 :
108 : VAR(debugtqaa, 0, 0, 2); //renders either the first or second tqaa texture at 1 or 2
109 :
110 0 : void viewtqaa()
111 : {
112 0 : int w = debugfullscreen ? hudw() : std::min(hudw(), hudh())/2,
113 0 : h = debugfullscreen ? hudh() : (w*hudh())/hudw(),
114 0 : tw = gw,
115 0 : th = gh;
116 0 : SETSHADER(hudrect);
117 0 : gle::colorf(1, 1, 1);
118 0 : switch(debugtqaa)
119 : {
120 0 : case 1:
121 : {
122 0 : glBindTexture(GL_TEXTURE_RECTANGLE, tqaatex[0]);
123 0 : break;
124 : }
125 0 : case 2:
126 : {
127 0 : glBindTexture(GL_TEXTURE_RECTANGLE, tqaatex[1]);
128 0 : break;
129 : }
130 : }
131 0 : debugquad(0, 0, w, h, 0, 0, tw, th);
132 0 : }
133 :
134 0 : void resolvetqaa(GLuint outfbo)
135 : {
136 0 : glBindFramebuffer(GL_FRAMEBUFFER, outfbo);
137 0 : SETSHADER(tqaaresolve);
138 0 : LOCALPARAMF(colorweight, tqaacolorweightscale, -tqaacolorweightbias*tqaacolorweightscale);
139 0 : glBindTexture(GL_TEXTURE_RECTANGLE, tqaatex[0]);
140 0 : glActiveTexture(GL_TEXTURE1);
141 0 : glBindTexture(GL_TEXTURE_RECTANGLE, tqaaframe ? tqaatex[1] : tqaatex[0]);
142 0 : gbuf.setaavelocityparams(GL_TEXTURE2);
143 0 : glActiveTexture(GL_TEXTURE0);
144 0 : vec4<float> quincunx(0, 0, 0, 0);
145 0 : if(tqaaquincunx)
146 : {
147 0 : quincunx = tqaaframe&1 ? vec4<float>(0.25f, 0.25f, -0.25f, -0.25f) : vec4<float>(-0.25f, -0.25f, 0.25f, 0.25f);
148 : }
149 0 : if(multisampledaa())
150 : {
151 0 : quincunx.x *= 0.5f;
152 0 : quincunx.y *= -0.5f;
153 0 : quincunx.z *= 0.5f;
154 0 : quincunx.w *= -0.5f;
155 : }
156 0 : LOCALPARAM(quincunx, quincunx);
157 0 : screenquad(vieww, viewh);
158 :
159 0 : std::swap(tqaafbo[0], tqaafbo[1]);
160 0 : std::swap(tqaatex[0], tqaatex[1]);
161 0 : tqaaprevscreenmatrix = screenmatrix;
162 0 : tqaaframe++;
163 0 : }
164 :
165 0 : void dotqaa(GLuint outfbo = 0)
166 : {
167 0 : timer *tqaatimer = begintimer("tqaa");
168 :
169 0 : resolvetqaa(outfbo);
170 :
171 0 : endtimer(tqaatimer);
172 0 : }
173 : //end of TQAA code
174 :
175 : /* FXAA: Fast approXimate Anti Aliasing */
176 : //////////////////////////////////////////
177 :
178 : class fxaa final
179 : {
180 : public:
181 : GLuint fxaafbo = 0;
182 : int fxaatype = -1;
183 : int usefxaa;
184 :
185 : void cleanupfxaa();
186 : void dofxaa(GLuint outfbo = 0);
187 : void setupfxaa(GBuffer &buf, int w, int h);
188 :
189 : fxaa();
190 : private:
191 :
192 : GLuint fxaatex = 0;
193 : Shader *fxaashader = nullptr;
194 :
195 : void loadfxaashaders();
196 : void clearfxaashaders();
197 :
198 : int fxaaquality;
199 : int fxaagreenluma;
200 : };
201 :
202 : fxaa fxaarenderer;
203 :
204 1 : fxaa::fxaa()
205 : {
206 1 : variable("usefxaa", 0, 0, 1, &usefxaa, [] (ident *) { fxaarenderer.cleanupfxaa(); }, Idf_Persist);
207 1 : variable("fxaaquality", 0, 1, 3, &fxaaquality, [] (ident *) { fxaarenderer.cleanupfxaa(); }, Idf_Persist);
208 1 : variable("fxaagreenluma", 0, 0, 1, &fxaagreenluma, [] (ident *) { fxaarenderer.cleanupfxaa(); }, Idf_Persist);
209 1 : };
210 :
211 0 : void fxaa::loadfxaashaders()
212 : {
213 0 : fxaatype = tqaatype >= 0 ? tqaatype : (!fxaagreenluma && !intel_texalpha_bug ? AA_Luma : AA_Unused);
214 0 : loadhdrshaders(fxaatype);
215 0 : std::string opts;
216 0 : if(tqaa || fxaagreenluma || intel_texalpha_bug)
217 : {
218 0 : opts.push_back('g');
219 : }
220 0 : std::string fxaaname = std::string("fxaa").append(std::to_string(fxaaquality)).append(opts);
221 0 : fxaashader = generateshader(fxaaname, "fxaashaders %d \"%s\"", fxaaquality, opts.c_str());
222 0 : }
223 :
224 0 : void fxaa::clearfxaashaders()
225 : {
226 0 : fxaatype = -1;
227 0 : fxaashader = nullptr;
228 0 : }
229 :
230 0 : void fxaa::setupfxaa(GBuffer &buf, int w, int h)
231 : {
232 0 : if(!fxaatex)
233 : {
234 0 : glGenTextures(1, &fxaatex);
235 : }
236 0 : if(!fxaafbo)
237 : {
238 0 : glGenFramebuffers(1, &fxaafbo);
239 : }
240 0 : glBindFramebuffer(GL_FRAMEBUFFER, fxaafbo);
241 0 : createtexture(fxaatex, w, h, nullptr, 3, 1, tqaa || (!fxaagreenluma && !intel_texalpha_bug) ? GL_RGBA8 : GL_RGB, GL_TEXTURE_RECTANGLE);
242 0 : glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, fxaatex, 0);
243 0 : buf.bindgdepth();
244 0 : if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
245 : {
246 0 : fatal("failed allocating FXAA buffer!");
247 : }
248 0 : glBindFramebuffer(GL_FRAMEBUFFER, 0);
249 :
250 0 : loadfxaashaders();
251 0 : }
252 :
253 0 : void fxaa::cleanupfxaa()
254 : {
255 0 : if(fxaafbo)
256 : {
257 0 : glDeleteFramebuffers(1, &fxaafbo);
258 0 : fxaafbo = 0;
259 : }
260 0 : if(fxaatex)
261 : {
262 0 : glDeleteTextures(1, &fxaatex);
263 0 : fxaatex = 0;
264 : }
265 0 : clearfxaashaders();
266 0 : }
267 :
268 0 : void fxaa::dofxaa(GLuint outfbo )
269 : {
270 0 : timer *fxaatimer = begintimer("fxaa");
271 0 : glBindFramebuffer(GL_FRAMEBUFFER, tqaa ? tqaafbo[0] : outfbo);
272 0 : fxaashader->set();
273 0 : glBindTexture(GL_TEXTURE_RECTANGLE, fxaatex);
274 0 : screenquad(vieww, viewh);
275 0 : if(tqaa)
276 : {
277 0 : resolvetqaa(outfbo);
278 : }
279 0 : endtimer(fxaatimer);
280 0 : }
281 : //end of FXAA code
282 : /* SMAA: Subpixel Morphological Anti Aliasing */
283 : ////////////////////////////////////////////////
284 :
285 : class subpixelaa final
286 : {
287 : public:
288 : enum SMAAProp
289 : {
290 : T2X = 0,
291 : S2X,
292 : X4,
293 : SMAA,
294 : Spatial,
295 : Quality,
296 : ColorEdge,
297 : GreenLuma,
298 : DepthMask,
299 : Stencil,
300 : Debug,
301 :
302 : Count
303 : };
304 :
305 : private:
306 : static const prop::PropertyMeta prop_meta[SMAAProp::Count];
307 :
308 : public:
309 : std::array<GLuint, 4> smaafbo {0, 0, 0, 0};
310 : int smaatype = -1;
311 :
312 : void cleanupsmaa();
313 : void setupsmaa(GBuffer &buf, int w, int h);
314 :
315 : //executes the smaa process on the given output framebuffer object (outfbo)
316 : //split toggles splitting process into two passes
317 : void dosmaa(GLuint outfbo = 0, bool split = false);
318 :
319 : //debug view for smaa buffers
320 : void viewsmaa();
321 :
322 : subpixelaa(GBuffer &buf);
323 :
324 : bool setsmaaproperty(std::string name, int value);
325 : const prop::Property<>* getsmaaproperty(std::string) const;
326 : const prop::Property<>& getsmaaproperty(SMAAProp prop) const;
327 :
328 : private:
329 : GBuffer &buf;
330 : //smaa graphics buffers
331 : GLuint smaaareatex = 0,
332 : smaasearchtex = 0;
333 :
334 : std::array<GLuint, 5> smaatex = { 0, 0, 0, 0, 0 };
335 : //affects subsample vector direction
336 : int smaasubsampleorder = -1;
337 : Shader *smaalumaedgeshader = nullptr,
338 : *smaacoloredgeshader = nullptr,
339 : *smaablendweightshader = nullptr,
340 : *smaaneighborhoodshader = nullptr;
341 :
342 : static constexpr int smaaareatexwidth = 160,
343 : smaaareatexheight = 560;
344 :
345 : static constexpr int smaasearchtexwidth = 66,
346 : smaasearchtexheight = 33;
347 :
348 : std::array<uchar, smaasearchtexwidth*smaasearchtexheight> smaasearchdata;
349 : std::array<uchar, smaaareatexwidth*smaaareatexheight*2> smaaareadata;
350 :
351 : bool smaasearchdatainited = false;
352 : bool smaaareadatainited = false;
353 :
354 : static constexpr int orthoedges[18][2] =
355 : {
356 : {0, 0}, {3, 0}, {0, 3}, {3, 3}, {1, 0}, {4, 0}, {1, 3}, {4, 3},
357 : {0, 1}, {3, 1}, {0, 4}, {3, 4}, {1, 1}, {4, 1}, {1, 4}, {4, 4}
358 : };
359 : static constexpr int edgesdiag[18][2] =
360 : {
361 : {0, 0}, {1, 0}, {0, 2}, {1, 2}, {2, 0}, {3, 0}, {2, 2}, {3, 2},
362 : {0, 1}, {1, 1}, {0, 3}, {1, 3}, {2, 1}, {3, 1}, {2, 3}, {3, 3}
363 : };
364 :
365 : static constexpr float offsetsortho[] = { 0.0f, -0.25f, 0.25f, -0.125f, 0.125f, -0.375f, 0.375f };
366 : static constexpr float offsetsdiag[][2] = {{ 0.0f, 0.0f, }, { 0.25f, -0.25f }, { -0.25f, 0.25f }, { 0.125f, -0.125f }, { -0.125f, 0.125f } };
367 :
368 : void gensmaasearchdata();
369 : vec2 areaunderortho(const vec2 &p1, const vec2 &p2, float x);
370 : void loadsmaashaders(bool split = false);
371 : void clearsmaashaders();
372 : void smootharea(float d, vec2 &a1, vec2 &a2);
373 : vec2 areaortho(int pattern, float left, float right, float offset);
374 :
375 : float areaunderdiag(const vec2 &p1, const vec2 &p2, const vec2 &p);
376 : vec2 areadiag(const vec2 &p1, const vec2 &p2, float left);
377 : vec2 areadiag(float p1x, float p1y, float p2x, float p2y, float d, float left, const vec2 &offset, int pattern);
378 : vec2 areadiag2(vec2 p1, vec2 p2, vec2 p3, vec2 p4, float d, float left, const vec2 &offset, int pattern);
379 : vec2 areadiag(int pattern, float left, float right, const vec2 &offset);
380 : void gensmaaareadata();
381 :
382 : /* smaa vars are set by `setupsmaa()` automatically: if TQAA and/or MSAA are
383 : * enabled, the following variables will be set to 1
384 : *
385 : * generally, do not change these vars from ingame
386 : */
387 :
388 : std::array<prop::Property<>, SMAAProp::Count> props =
389 : prop::make_props_array<SMAAProp::Count, prop::Property<>>(prop_meta);
390 : };
391 :
392 : const prop::PropertyMeta subpixelaa::prop_meta[SMAAProp::Count] =
393 : {
394 : prop::PropertyMeta
395 : (
396 : "t2x",
397 : prop::PropertyType::Int,
398 : 0, 0, 1
399 : ),
400 : prop::PropertyMeta
401 : (
402 : "s2x",
403 : prop::PropertyType::Int,
404 : 0, 0, 1
405 : ),
406 : prop::PropertyMeta
407 : (
408 : "x4",
409 : prop::PropertyType::Int,
410 : 0, 0, 1
411 : ),
412 : prop::PropertyMeta
413 : (
414 : "enabled",
415 : prop::PropertyType::Int,
416 : 0, 0, 1,
417 0 : [](std::any smaarenderer)
418 : {
419 0 : subpixelaa* smaa = std::any_cast<subpixelaa*>(smaarenderer);
420 0 : smaa->buf.cleanupgbuffer();
421 0 : }
422 : ),
423 : prop::PropertyMeta
424 : (
425 : "spatial",
426 : prop::PropertyType::Int,
427 : 0, 1, 1,
428 0 : [](std::any smaarenderer)
429 : {
430 0 : subpixelaa* smaa = std::any_cast<subpixelaa*>(smaarenderer);
431 0 : smaa->cleanupsmaa();
432 0 : }
433 : ),
434 : prop::PropertyMeta
435 : (
436 : "quality",
437 : prop::PropertyType::Int,
438 : 0, 2, 3,
439 0 : [](std::any smaarenderer)
440 : {
441 0 : subpixelaa* smaa = std::any_cast<subpixelaa*>(smaarenderer);
442 0 : smaa->cleanupsmaa();
443 0 : }
444 : ),
445 : prop::PropertyMeta
446 : (
447 : "coloredge",
448 : prop::PropertyType::Int,
449 : 0, 0, 1,
450 0 : [](std::any smaarenderer)
451 : {
452 0 : subpixelaa* smaa = std::any_cast<subpixelaa*>(smaarenderer);
453 0 : smaa->cleanupsmaa();
454 0 : }
455 : ),
456 : prop::PropertyMeta
457 : (
458 : "greenluma",
459 : prop::PropertyType::Int,
460 : 0, 0, 1,
461 0 : [](std::any smaarenderer)
462 : {
463 0 : subpixelaa* smaa = std::any_cast<subpixelaa*>(smaarenderer);
464 0 : smaa->cleanupsmaa();
465 0 : }
466 : ),
467 : prop::PropertyMeta
468 : (
469 : "depthmask",
470 : prop::PropertyType::Int,
471 : 0, 1, 1,
472 0 : [](std::any smaarenderer)
473 : {
474 0 : subpixelaa* smaa = std::any_cast<subpixelaa*>(smaarenderer);
475 0 : smaa->cleanupsmaa();
476 0 : }
477 : ),
478 : prop::PropertyMeta
479 : (
480 : "stencil",
481 : prop::PropertyType::Int,
482 : 0, 1, 1,
483 0 : [](std::any smaarenderer)
484 : {
485 0 : subpixelaa* smaa = std::any_cast<subpixelaa*>(smaarenderer);
486 0 : smaa->cleanupsmaa();
487 0 : }
488 : ),
489 : prop::PropertyMeta
490 : (
491 : "debug",
492 : prop::PropertyType::Int,
493 : 0, 0, 5
494 : )
495 : };
496 :
497 : subpixelaa smaarenderer(gbuf);
498 :
499 1 : bool subpixelaa::setsmaaproperty(std::string name, int value)
500 : {
501 1 : return set_prop(name, value, props, this);
502 : }
503 :
504 1 : const prop::Property<>* subpixelaa::getsmaaproperty(std::string name) const
505 : {
506 1 : return prop::find_prop(name, props);
507 : }
508 :
509 0 : const prop::Property<>& subpixelaa::getsmaaproperty(SMAAProp prop) const
510 : {
511 0 : return props[prop];
512 : }
513 :
514 1 : subpixelaa::subpixelaa(GBuffer &inbuf) : buf(inbuf)
515 : {
516 1 : }
517 :
518 0 : void subpixelaa::loadsmaashaders(bool split)
519 : {
520 0 : smaatype = tqaatype >= 0 ? tqaatype : (!props[SMAAProp::GreenLuma].get_int() && !intel_texalpha_bug && !props[SMAAProp::ColorEdge].get_int() ? AA_Luma : AA_Unused);
521 0 : if(split)
522 : {
523 0 : smaatype += AA_Split;
524 : }
525 0 : loadhdrshaders(smaatype);
526 :
527 0 : std::string opts;
528 0 : if((props[SMAAProp::DepthMask].get_int() && (!tqaa || msaalight)) || (props[SMAAProp::Stencil].get_int() && ghasstencil > (msaasamples ? 1 : 0)))
529 : {
530 0 : opts.push_back('d');
531 : }
532 0 : if(split)
533 : {
534 0 : opts.push_back('s');
535 : }
536 0 : if(tqaa || props[SMAAProp::GreenLuma].get_int() || intel_texalpha_bug)
537 : {
538 0 : opts.push_back('g');
539 : }
540 0 : if(tqaa)
541 : {
542 0 : opts.push_back('t');
543 : }
544 0 : std::string lumaedgename = std::string("SMAALumaEdgeDetection").append(props[SMAAProp::Quality].to_string()).append(opts);
545 0 : std::string coloredgename = std::string("SMAAColorEdgeDetection").append(props[SMAAProp::Quality].to_string()).append(opts);
546 0 : std::string blendweightname = std::string("SMAABlendingWeightCalculation").append(props[SMAAProp::Quality].to_string()).append(opts);
547 0 : std::string neighborhoodname = std::string("SMAANeighborhoodBlending").append(props[SMAAProp::Quality].to_string()).append(opts);
548 0 : smaalumaedgeshader = lookupshaderbyname(lumaedgename);
549 0 : smaacoloredgeshader = lookupshaderbyname(coloredgename);
550 0 : smaablendweightshader = lookupshaderbyname(blendweightname);
551 0 : smaaneighborhoodshader = lookupshaderbyname(neighborhoodname);
552 :
553 0 : if(smaalumaedgeshader && smaacoloredgeshader && smaablendweightshader && smaaneighborhoodshader)
554 : {
555 0 : return;
556 : }
557 0 : generateshader("", "smaashaders %d \"%s\"", props[SMAAProp::Quality].get_int(), opts.c_str());
558 0 : smaalumaedgeshader = lookupshaderbyname(lumaedgename);
559 0 : if(!smaalumaedgeshader)
560 : {
561 0 : smaalumaedgeshader = nullshader;
562 : }
563 0 : smaacoloredgeshader = lookupshaderbyname(coloredgename);
564 0 : if(!smaacoloredgeshader)
565 : {
566 0 : smaacoloredgeshader = nullshader;
567 : }
568 0 : smaablendweightshader = lookupshaderbyname(blendweightname);
569 0 : if(!smaablendweightshader)
570 : {
571 0 : smaablendweightshader = nullshader;
572 : }
573 0 : smaaneighborhoodshader = lookupshaderbyname(neighborhoodname);
574 0 : if(!smaaneighborhoodshader)
575 : {
576 0 : smaaneighborhoodshader = nullshader;
577 : }
578 0 : }
579 :
580 0 : void subpixelaa::clearsmaashaders()
581 : {
582 0 : smaatype = -1;
583 0 : smaalumaedgeshader = nullptr;
584 0 : smaacoloredgeshader = nullptr;
585 0 : smaablendweightshader = nullptr;
586 0 : smaaneighborhoodshader = nullptr;
587 0 : }
588 :
589 0 : void subpixelaa::gensmaasearchdata()
590 : {
591 0 : if(smaasearchdatainited)
592 : {
593 0 : return;
594 : }
595 : std::array<int, 33> edges;
596 0 : edges.fill(-1);
597 0 : for(int i = 0; i < 2; ++i)
598 : {
599 0 : for(int j = 0; j < 2; ++j)
600 : {
601 0 : for(int k = 0; k < 2; ++k)
602 : {
603 0 : for(int l = 0; l < 2; ++l)
604 : {
605 0 : edges[(i*1 + j*3) + (k*7 + l*21)] = i + (j<<1) + (k<<2) + (l<<3);
606 : }
607 : }
608 : }
609 : }
610 0 : smaasearchdata.fill(0);
611 0 : for(int y = 0; y < 33; ++y)
612 : {
613 0 : for(int x = 0; x < 33; ++x)
614 : {
615 0 : int left = edges[x],
616 0 : top = edges[y];
617 0 : if(left < 0 || top < 0)
618 : {
619 0 : continue;
620 : }
621 0 : uchar deltaLeft = 0;
622 0 : if(top&(1<<3))
623 : {
624 0 : deltaLeft++;
625 : }
626 0 : if(deltaLeft && top&(1<<2) && !(left&(1<<1)) && !(left&(1<<3)))
627 : {
628 0 : deltaLeft++;
629 : }
630 0 : smaasearchdata[y*66 + x] = deltaLeft;
631 0 : uchar deltaRight = 0;
632 0 : if(top&(1<<3) && !(left&(1<<1)) && !(left&(1<<3)))
633 : {
634 0 : deltaRight++;
635 : }
636 0 : if(deltaRight && top&(1<<2) && !(left&(1<<0)) && !(left&(1<<2)))
637 : {
638 0 : deltaRight++;
639 : }
640 0 : smaasearchdata[y*66 + 33 + x] = deltaRight;
641 : }
642 : }
643 0 : smaasearchdatainited = true;
644 : }
645 :
646 0 : vec2 subpixelaa::areaunderortho(const vec2 &p1, const vec2 &p2, float x)
647 : {
648 0 : vec2 d(p2.x - p1.x, p2.y - p1.y);
649 0 : float y1 = p1.y + (x - p1.x)*d.y/d.x,
650 0 : y2 = p1.y + (x+1 - p1.x)*d.y/d.x;
651 0 : if((x < p1.x || x >= p2.x) && (x+1 <= p1.x || x+1 > p2.x))
652 : {
653 0 : return vec2(0, 0);
654 : }
655 0 : if((y1 < 0) == (y2 < 0) || std::fabs(y1) < 1e-4f || std::fabs(y2) < 1e-4f)
656 : {
657 0 : float a = (y1 + y2) / 2;
658 0 : return a < 0.0f ? vec2(-a, 0) : vec2(0, a);
659 : }
660 0 : x = -p1.y*d.x/d.y + p1.x;
661 0 : float a1 = x > p1.x ? y1*std::fmod(x, 1.0f)/2 : 0,
662 0 : a2 = x < p2.x ? y2*(1-std::fmod(x, 1.0f))/2 : 0;
663 0 : vec2 a(std::fabs(a1), std::fabs(a2));
664 0 : if((a.x > a.y ? a1 : -a2) >= 0)
665 : {
666 0 : std::swap(a.x, a.y);
667 : }
668 0 : return a;
669 : }
670 :
671 0 : void subpixelaa::smootharea(float d, vec2 &a1, vec2 &a2)
672 : {
673 0 : vec2 b1(sqrtf(a1.x*2)*0.5f, sqrtf(a1.y*2)*0.5f),
674 0 : b2(sqrtf(a2.x*2)*0.5f, sqrtf(a2.y*2)*0.5f);
675 0 : float p = std::clamp(d / 32.0f, 0.0f, 1.0f);
676 0 : a1.lerp(b1, a1, p);
677 0 : a2.lerp(b2, a2, p);
678 0 : }
679 :
680 0 : vec2 subpixelaa::areaortho(int pattern, float left, float right, float offset)
681 : {
682 0 : float d = left + right + 1,
683 0 : o1 = offset + 0.5f,
684 0 : o2 = offset - 0.5f;
685 0 : switch(pattern)
686 : {
687 0 : case 0:
688 : {
689 0 : return vec2(0, 0);
690 : }
691 0 : case 1:
692 : {
693 0 : return left <= right ? areaunderortho({0, o2}, {d/2, 0}, left) : vec2(0, 0);
694 : }
695 0 : case 2:
696 : {
697 0 : return left >= right ? areaunderortho({d/2, 0}, {d, o2}, left) : vec2(0, 0);
698 : }
699 0 : case 3:
700 : {
701 0 : vec2 a1 = areaunderortho({0, o2}, {d/2, 0}, left), a2 = areaunderortho({d/2, 0}, {d, o2}, left);
702 0 : smootharea(d, a1, a2);
703 0 : return a1.add(a2);
704 : }
705 0 : case 4:
706 : {
707 0 : return left <= right ? areaunderortho({0, o1}, {d/2, 0}, left) : vec2(0, 0);
708 : }
709 0 : case 5:
710 : {
711 0 : return vec2(0, 0);
712 : }
713 0 : case 6:
714 : {
715 0 : vec2 a = areaunderortho({0, o1}, {d, o2}, left);
716 0 : if(std::fabs(offset) > 0)
717 : {
718 0 : a.avg(areaunderortho({0, o1}, {d/2, 0}, left).add(areaunderortho({d/2, 0}, {d, o2}, left)));
719 : }
720 0 : return a;
721 : }
722 0 : case 7:
723 : {
724 0 : return areaunderortho({0, o1}, {d, o2}, left);
725 : }
726 0 : case 8:
727 : {
728 0 : return left >= right ? areaunderortho({d/2, 0}, {d, o1}, left) : vec2(0, 0);
729 : }
730 0 : case 9:
731 : {
732 0 : vec2 a = areaunderortho({0, o2}, {d, o1}, left);
733 0 : if(std::fabs(offset) > 0)
734 : {
735 0 : a.avg(areaunderortho({0, o2}, {d/2, 0}, left).add(areaunderortho({d/2, 0}, {d, o1}, left)));
736 : }
737 0 : return a;
738 : }
739 0 : case 10:
740 : {
741 0 : return vec2(0, 0);
742 : }
743 0 : case 11:
744 : {
745 0 : return areaunderortho({0, o2}, {d, o1}, left);
746 : }
747 0 : case 12:
748 : {
749 0 : vec2 a1 = areaunderortho({0, o1}, {d/2, 0}, left),
750 0 : a2 = areaunderortho({d/2, 0}, {d, o1}, left);
751 0 : smootharea(d, a1, a2);
752 0 : return a1.add(a2);
753 : }
754 0 : case 13:
755 : {
756 0 : return areaunderortho({0, o2}, {d, o1}, left);
757 : }
758 0 : case 14:
759 : {
760 0 : return areaunderortho({0, o1}, {d, o2}, left);
761 : }
762 0 : case 15:
763 : {
764 0 : return vec2(0, 0);
765 : }
766 : }
767 0 : return vec2(0, 0);
768 : }
769 :
770 0 : float subpixelaa::areaunderdiag(const vec2 &p1, const vec2 &p2, const vec2 &p)
771 : {
772 0 : vec2 d(p2.y - p1.y, p1.x - p2.x);
773 0 : float dp = d.dot(vec2(p1).sub(p));
774 0 : if(!d.x)
775 : {
776 0 : if(!d.y)
777 : {
778 0 : return 1;
779 : }
780 0 : return std::clamp(d.y > 0 ? 1 - dp/d.y : dp/d.y, 0.0f, 1.0f);
781 : }
782 0 : if(!d.y)
783 : {
784 0 : return std::clamp(d.x > 0 ? 1 - dp/d.x : dp/d.x, 0.0f, 1.0f);
785 : }
786 0 : float l = dp/d.y,
787 0 : r = (dp-d.x)/d.y,
788 0 : b = dp/d.x,
789 0 : t = (dp-d.y)/d.x;
790 0 : if(0 <= dp)
791 : {
792 0 : if(d.y <= dp)
793 : {
794 0 : if(d.x <= dp)
795 : {
796 0 : if(d.y+d.x <= dp)
797 : {
798 0 : return 0;
799 : }
800 0 : return 0.5f*(1-r)*(1-t);
801 : }
802 0 : if(d.y+d.x > dp)
803 : {
804 0 : return std::min(1-b, 1-t) + 0.5f*std::fabs(b-t);
805 : }
806 0 : return 0.5f*(1-b)*r;
807 : }
808 0 : if(d.x <= dp)
809 : {
810 0 : if(d.y+d.x <= dp)
811 : {
812 0 : return 0.5f*(1-l)*t;
813 : }
814 0 : return std::min(1-l, 1-r) + 0.5f*std::fabs(r-l);
815 : }
816 0 : return 1 - 0.5f*l*b;
817 : }
818 0 : if(d.y <= dp)
819 : {
820 0 : if(d.x <= dp)
821 : {
822 0 : return 0.5f*l*b;
823 : }
824 0 : if(d.y+d.x <= dp)
825 : {
826 0 : return std::min(l, r) + 0.5f*std::fabs(r-l);
827 : }
828 0 : return 1 - 0.5f*(1-l)*t;
829 : }
830 0 : if(d.x <= dp)
831 : {
832 0 : if(d.y+d.x <= dp)
833 : {
834 0 : return std::min(b, t) + 0.5f*std::fabs(b-t);
835 : }
836 0 : return 1 - 0.5f*(1-b)*r;
837 : }
838 0 : if(d.y+d.x <= dp)
839 : {
840 0 : return 1 - 0.5f*(1-t)*(1-r);
841 : }
842 0 : return 1;
843 : }
844 :
845 0 : vec2 subpixelaa::areadiag(const vec2 &p1, const vec2 &p2, float left)
846 : {
847 0 : return vec2(1 - areaunderdiag(p1, p2, vec2(1, 0).add(left)), areaunderdiag(p1, p2, vec2(1, 1).add(left)));
848 : }
849 :
850 0 : vec2 subpixelaa::areadiag(float p1x, float p1y, float p2x, float p2y, float d, float left, const vec2 &offset, int pattern)
851 : {
852 0 : vec2 p1(p1x, p1y),
853 0 : p2(p2x+d, p2y+d);
854 0 : if(edgesdiag[pattern][0])
855 : {
856 0 : p1.add(offset);
857 : }
858 0 : if(edgesdiag[pattern][1])
859 : {
860 0 : p2.add(offset);
861 : }
862 0 : return areadiag(p1, p2, left);
863 : }
864 :
865 0 : vec2 subpixelaa::areadiag2(vec2 p1, vec2 p2, vec2 p3, vec2 p4, float d, float left, const vec2 &offset, int pattern)
866 : {
867 0 : p2.add(d);
868 0 : p4.add(d);
869 0 : if(edgesdiag[pattern][0])
870 : {
871 0 : p1.add(offset);
872 0 : p3.add(offset);
873 : }
874 0 : if(edgesdiag[pattern][1])
875 : {
876 0 : p2.add(offset);
877 0 : p4.add(offset);
878 : }
879 0 : return areadiag(p1, p2, left).avg(areadiag(p3, p4, left));
880 : }
881 :
882 0 : vec2 subpixelaa::areadiag(int pattern, float left, float right, const vec2 &offset)
883 : {
884 0 : float d = left + right + 1;
885 0 : switch(pattern)
886 : {
887 0 : case 0: return areadiag2({1, 1}, {1, 1}, {1, 0}, {1, 0}, d, left, offset, pattern);
888 0 : case 1: return areadiag2({1, 0}, {0, 0}, {1, 0}, {1, 0}, d, left, offset, pattern);
889 0 : case 2: return areadiag2({0, 0}, {1, 0}, {1, 0}, {1, 0}, d, left, offset, pattern);
890 0 : case 3: return areadiag(1, 0, 1, 0, d, left, offset, pattern);
891 0 : case 4: return areadiag2({1, 1}, {0, 0}, {1, 1}, {1, 0}, d, left, offset, pattern);
892 0 : case 5: return areadiag2({1, 1}, {0, 0}, {1, 0}, {1, 0}, d, left, offset, pattern);
893 0 : case 6: return areadiag(1, 1, 1, 0, d, left, offset, pattern);
894 0 : case 7: return areadiag2({1, 1}, {1, 0}, {1, 0}, {1, 0}, d, left, offset, pattern);
895 0 : case 8: return areadiag2({0, 0}, {1, 1}, {1, 0}, {1, 1}, d, left, offset, pattern);
896 0 : case 9: return areadiag(1, 0, 1, 1, d, left, offset, pattern);
897 0 : case 10: return areadiag2({0, 0}, {1, 1}, {1, 0}, {1, 0}, d, left, offset, pattern);
898 0 : case 11: return areadiag2({1, 0}, {1, 1}, {1, 0}, {1, 0}, d, left, offset, pattern);
899 0 : case 12: return areadiag(1, 1, 1, 1, d, left, offset, pattern);
900 0 : case 13: return areadiag2({1, 1}, {1, 1}, {1, 0}, {1, 1}, d, left, offset, pattern);
901 0 : case 14: return areadiag2({1, 1}, {1, 1}, {1, 1}, {1, 0}, d, left, offset, pattern);
902 0 : case 15: return areadiag2({1, 1}, {1, 1}, {1, 0}, {1, 0}, d, left, offset, pattern);
903 : }
904 0 : return vec2(0, 0);
905 : }
906 :
907 0 : void subpixelaa::gensmaaareadata()
908 : {
909 0 : if(smaaareadatainited)
910 : {
911 0 : return;
912 : }
913 0 : smaaareadata.fill(0);
914 0 : for(int offset = 0; offset < static_cast<int>(sizeof(offsetsortho)/sizeof(offsetsortho[0])); ++offset)
915 : {
916 0 : for(int pattern = 0; pattern < 16; ++pattern)
917 : {
918 0 : int px = orthoedges[pattern][0]*16,
919 0 : py = (5*offset + orthoedges[pattern][1])*16;
920 0 : uchar *dst = &smaaareadata[(py*smaaareatexwidth + px)*2];
921 0 : for(int y = 0; y < 16; ++y)
922 : {
923 0 : for(int x = 0; x < 16; ++x)
924 : {
925 0 : vec2 a = areaortho(pattern, x*x, y*y, offsetsortho[offset]);
926 0 : dst[0] = static_cast<uchar>(255*a.x);
927 0 : dst[1] = static_cast<uchar>(255*a.y);
928 0 : dst += 2;
929 : }
930 0 : dst += (smaaareatexwidth-16)*2;
931 : }
932 : }
933 : }
934 0 : for(int offset = 0; offset < static_cast<int>(sizeof(offsetsdiag)/sizeof(offsetsdiag[0])); ++offset)
935 : {
936 0 : for(int pattern = 0; pattern < 16; ++pattern)
937 : {
938 0 : int px = 5*16 + edgesdiag[pattern][0]*20,
939 0 : py = (4*offset + edgesdiag[pattern][1])*20;
940 0 : uchar *dst = &smaaareadata[(py*smaaareatexwidth + px)*2];
941 0 : for(int y = 0; y < 20; ++y)
942 : {
943 0 : for(int x = 0; x < 20; ++x)
944 : {
945 0 : vec2 a = areadiag(pattern, x, y, vec2(offsetsdiag[offset][0], offsetsdiag[offset][1]));
946 0 : dst[0] = static_cast<uchar>(255*a.x);
947 0 : dst[1] = static_cast<uchar>(255*a.y);
948 0 : dst += 2;
949 : }
950 0 : dst += (smaaareatexwidth-20)*2;
951 : }
952 : }
953 : }
954 0 : smaaareadatainited = true;
955 : }
956 :
957 0 : void subpixelaa::setupsmaa(GBuffer &buf, int w, int h)
958 : {
959 0 : if(!smaaareatex)
960 : {
961 0 : glGenTextures(1, &smaaareatex);
962 : }
963 0 : if(!smaasearchtex)
964 : {
965 0 : glGenTextures(1, &smaasearchtex);
966 : }
967 0 : gensmaasearchdata();
968 0 : gensmaaareadata();
969 0 : createtexture( smaaareatex, smaaareatexwidth, smaaareatexheight, smaaareadata.data(), 3, 1, GL_RG8, GL_TEXTURE_RECTANGLE, 0, 0, 0, false);
970 0 : createtexture(smaasearchtex, smaasearchtexwidth, smaasearchtexheight, smaasearchdata.data(), 3, 0, GL_R8, GL_TEXTURE_2D, 0, 0, 0, false);
971 0 : bool split = multisampledaa();
972 0 : smaasubsampleorder = split ? (msaapositions[0].x < 0.5f ? 1 : 0) : -1;
973 0 : props[SMAAProp::T2X].set_no_cb(tqaa ? 1 : 0);
974 0 : props[SMAAProp::S2X].set_no_cb(split ? 1 : 0);
975 0 : props[SMAAProp::X4].set_no_cb(tqaa && split ? 1 : 0);
976 0 : for(int i = 0; i < (split ? 4 : 3); ++i)
977 : {
978 0 : if(!smaatex[i])
979 : {
980 0 : glGenTextures(1, &smaatex[i]);
981 : }
982 0 : if(!smaafbo[i])
983 : {
984 0 : glGenFramebuffers(1, &smaafbo[i]);
985 : }
986 0 : glBindFramebuffer(GL_FRAMEBUFFER, smaafbo[i]);
987 0 : GLenum format = GL_RGB;
988 0 : switch(i)
989 : {
990 0 : case 0:
991 : {
992 0 : format = tqaa || (!props[SMAAProp::GreenLuma].get_int() && !intel_texalpha_bug && !props[SMAAProp::ColorEdge].get_int()) ? GL_RGBA8 : GL_RGB;
993 0 : break;
994 : }
995 0 : case 1:
996 : {
997 0 : format = GL_RG8;
998 0 : break;
999 : }
1000 0 : case 2:
1001 : case 3:
1002 : {
1003 0 : format = GL_RGBA8;
1004 0 : break;
1005 : }
1006 : }
1007 0 : createtexture(smaatex[i], w, h, nullptr, 3, 1, format, GL_TEXTURE_RECTANGLE);
1008 0 : glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, smaatex[i], 0);
1009 0 : if(!i && split)
1010 : {
1011 0 : if(!smaatex[4])
1012 : {
1013 0 : glGenTextures(1, &smaatex[4]);
1014 : }
1015 0 : createtexture(smaatex[4], w, h, nullptr, 3, 1, format, GL_TEXTURE_RECTANGLE);
1016 0 : glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_RECTANGLE, smaatex[4], 0);
1017 : static const GLenum drawbufs[2] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
1018 0 : glDrawBuffers(2, drawbufs);
1019 : }
1020 0 : if(!i || (props[SMAAProp::DepthMask].get_int() && (!tqaa || msaalight)) || (props[SMAAProp::Stencil].get_int() && ghasstencil > (msaasamples ? 1 : 0)))
1021 : {
1022 0 : buf.bindgdepth();
1023 : }
1024 0 : if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
1025 : {
1026 0 : fatal("failed allocating SMAA buffer!");
1027 : }
1028 : }
1029 0 : glBindFramebuffer(GL_FRAMEBUFFER, 0);
1030 :
1031 0 : loadsmaashaders(split);
1032 0 : }
1033 :
1034 0 : void subpixelaa::cleanupsmaa()
1035 : {
1036 0 : if(smaaareatex)
1037 : {
1038 0 : glDeleteTextures(1, &smaaareatex);
1039 0 : smaaareatex = 0;
1040 : }
1041 0 : if(smaasearchtex)
1042 : {
1043 0 : glDeleteTextures(1, &smaasearchtex);
1044 0 : smaasearchtex = 0;
1045 : }
1046 0 : for(GLuint i : smaafbo)
1047 : {
1048 0 : if(i)
1049 : {
1050 0 : glDeleteFramebuffers(1, &i);
1051 0 : i = 0;
1052 : }
1053 : }
1054 0 : for(int i = 0; i < 5; ++i)
1055 : {
1056 0 : if(smaatex[i])
1057 : {
1058 0 : glDeleteTextures(1, &smaatex[i]);
1059 0 : smaatex[i] = 0;
1060 : }
1061 : }
1062 0 : smaasubsampleorder = -1;
1063 0 : props[SMAAProp::T2X].set_no_cb(0);
1064 0 : props[SMAAProp::S2X].set_no_cb(0);
1065 0 : props[SMAAProp::X4].set_no_cb(0);
1066 :
1067 0 : clearsmaashaders();
1068 0 : }
1069 :
1070 0 : void subpixelaa::viewsmaa()
1071 : {
1072 0 : int w = debugfullscreen ? hudw() : std::min(hudw(), hudh())/2,
1073 0 : h = debugfullscreen ? hudh() : (w*hudh())/hudw(),
1074 0 : tw = gw,
1075 0 : th = gh;
1076 0 : SETSHADER(hudrect);
1077 0 : gle::colorf(1, 1, 1);
1078 : /* debugsmaa levels:
1079 : * 1: show the output tex resulting from smaa
1080 : * 2: show the raw filtering output applied to the screen buffer
1081 : * 3: show the refined filtering output applied to the screen buffer
1082 : * 4: show the buffer of edge-detect patterns
1083 : * 5: show the smaa search texture
1084 : */
1085 0 : switch(props[SMAAProp::Debug].get_int())
1086 : {
1087 0 : case 1:
1088 : {
1089 0 : glBindTexture(GL_TEXTURE_RECTANGLE, smaatex[0]);
1090 0 : break;
1091 : }
1092 0 : case 2:
1093 : {
1094 0 : glBindTexture(GL_TEXTURE_RECTANGLE, smaatex[1]);
1095 0 : break;
1096 : }
1097 0 : case 3:
1098 : {
1099 0 : glBindTexture(GL_TEXTURE_RECTANGLE, smaatex[2]);
1100 0 : break;
1101 : }
1102 0 : case 4:
1103 : {
1104 0 : glBindTexture(GL_TEXTURE_RECTANGLE, smaaareatex);
1105 0 : tw = smaaareatexwidth;
1106 0 : th = smaaareatexheight;
1107 0 : break;
1108 : }
1109 0 : case 5:
1110 : {
1111 0 : glBindTexture(GL_TEXTURE_2D, smaasearchtex);
1112 0 : tw = 1;
1113 0 : th = 1;
1114 0 : break;
1115 : }
1116 : }
1117 0 : debugquad(0, 0, w, h, 0, 0, tw, th);
1118 0 : }
1119 :
1120 0 : void subpixelaa::dosmaa(GLuint outfbo, bool split)
1121 : {
1122 0 : timer *smaatimer = begintimer("smaa");
1123 :
1124 0 : int cleardepth = msaalight ? GL_DEPTH_BUFFER_BIT | (ghasstencil > 1 ? GL_STENCIL_BUFFER_BIT : 0) : 0;
1125 0 : bool depthmask = props[SMAAProp::DepthMask].get_int() && (!tqaa || msaalight),
1126 0 : stencil = props[SMAAProp::Stencil].get_int() && ghasstencil > (msaasamples ? 1 : 0);
1127 0 : for(int pass = 0; pass < (split ? 2 : 1); ++pass) // loop through multiple passes if doing multisample aa
1128 : {
1129 0 : glBindFramebuffer(GL_FRAMEBUFFER, smaafbo[1]);
1130 0 : if(depthmask || stencil)
1131 : {
1132 0 : glClearColor(0, 0, 0, 0);
1133 0 : glClear(GL_COLOR_BUFFER_BIT | (!pass ? cleardepth : 0));
1134 : }
1135 0 : if(depthmask)
1136 : {
1137 0 : glEnable(GL_DEPTH_TEST);
1138 0 : glDepthFunc(GL_ALWAYS);
1139 0 : float depthval = cleardepth ? 0.25f*(pass+1) : 1;
1140 0 : glDepthRange(depthval, depthval);
1141 : }
1142 0 : else if(stencil)
1143 : {
1144 0 : glEnable(GL_STENCIL_TEST);
1145 0 : glStencilFunc(GL_ALWAYS, 0x10*(pass+1), ~0);
1146 0 : glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
1147 : }
1148 0 : if(props[SMAAProp::ColorEdge].get_int())
1149 : {
1150 0 : smaacoloredgeshader->set();
1151 : }
1152 0 : else if(smaalumaedgeshader)
1153 : {
1154 0 : smaalumaedgeshader->set();
1155 : }
1156 0 : glBindTexture(GL_TEXTURE_RECTANGLE, smaatex[pass ? 4 : 0]);
1157 0 : screenquad(vieww, viewh);
1158 0 : glBindFramebuffer(GL_FRAMEBUFFER, smaafbo[2 + pass]);
1159 0 : if(depthmask)
1160 : {
1161 0 : glDepthFunc(GL_EQUAL);
1162 0 : glDepthMask(GL_FALSE);
1163 : }
1164 0 : else if(stencil)
1165 : {
1166 0 : glStencilFunc(GL_EQUAL, 0x10*(pass+1), ~0);
1167 0 : glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1168 : }
1169 0 : if(depthmask || stencil)
1170 : {
1171 0 : glClear(GL_COLOR_BUFFER_BIT);
1172 : }
1173 0 : if(smaablendweightshader)
1174 : {
1175 0 : smaablendweightshader->set();
1176 : }
1177 0 : vec4<float> subsamples(0, 0, 0, 0);
1178 0 : if(tqaa && split)
1179 : {
1180 0 : subsamples = tqaaframe&1 ?
1181 0 : (pass != smaasubsampleorder ? vec4<float>(6, 4, 2, 4) : vec4<float>(3, 5, 1, 4)) :
1182 0 : (pass != smaasubsampleorder ? vec4<float>(4, 6, 2, 3) : vec4<float>(5, 3, 1, 3));
1183 : }
1184 0 : else if(tqaa)
1185 : {
1186 0 : subsamples = tqaaframe&1 ? vec4<float>(2, 2, 2, 0) : vec4<float>(1, 1, 1, 0);
1187 : }
1188 0 : else if(split)
1189 : {
1190 0 : subsamples = pass != smaasubsampleorder ? vec4<float>(2, 2, 2, 0) : vec4<float>(1, 1, 1, 0);
1191 : }
1192 0 : LOCALPARAM(subsamples, subsamples);
1193 0 : glBindTexture(GL_TEXTURE_RECTANGLE, smaatex[1]);
1194 0 : glActiveTexture(GL_TEXTURE1);
1195 0 : glBindTexture(GL_TEXTURE_RECTANGLE, smaaareatex);
1196 0 : glActiveTexture(GL_TEXTURE2);
1197 0 : glBindTexture(GL_TEXTURE_2D, smaasearchtex);
1198 0 : glActiveTexture(GL_TEXTURE0);
1199 0 : screenquad(vieww, viewh);
1200 0 : if(depthmask)
1201 : {
1202 0 : glDisable(GL_DEPTH_TEST);
1203 0 : glDepthMask(GL_TRUE);
1204 0 : glDepthFunc(GL_LESS);
1205 0 : glDepthRange(0, 1);
1206 : }
1207 0 : else if(stencil)
1208 : {
1209 0 : glDisable(GL_STENCIL_TEST);
1210 : }
1211 : }
1212 0 : glBindFramebuffer(GL_FRAMEBUFFER, tqaa ? tqaafbo[0] : outfbo);
1213 0 : if(smaaneighborhoodshader)
1214 : {
1215 0 : smaaneighborhoodshader->set();
1216 : }
1217 0 : glBindTexture(GL_TEXTURE_RECTANGLE, smaatex[0]);
1218 0 : glActiveTexture(GL_TEXTURE1);
1219 0 : glBindTexture(GL_TEXTURE_RECTANGLE, smaatex[2]);
1220 0 : if(split)
1221 : {
1222 0 : glActiveTexture(GL_TEXTURE2);
1223 0 : glBindTexture(GL_TEXTURE_RECTANGLE, smaatex[4]);
1224 0 : glActiveTexture(GL_TEXTURE3);
1225 0 : glBindTexture(GL_TEXTURE_RECTANGLE, smaatex[3]);
1226 : }
1227 0 : glActiveTexture(GL_TEXTURE0);
1228 0 : screenquad(vieww, viewh);
1229 0 : if(tqaa)
1230 : {
1231 0 : resolvetqaa(outfbo);
1232 : }
1233 0 : endtimer(smaatimer);
1234 0 : }
1235 : //end of SMAA code
1236 :
1237 : /* general antialiasing control functions */
1238 : ////////////////////////////////////////////
1239 : }
1240 :
1241 : //for temporal aa, called externally
1242 0 : void GBuffer::setaavelocityparams(GLenum tmu)
1243 : {
1244 0 : glActiveTexture(tmu);
1245 0 : if(msaalight)
1246 : {
1247 0 : glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msdepthtex);
1248 : }
1249 : else
1250 : {
1251 0 : glBindTexture(GL_TEXTURE_RECTANGLE, gdepthtex);
1252 : }
1253 0 : glActiveTexture(++tmu);
1254 0 : if(msaasamples)
1255 : {
1256 0 : glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msnormaltex);
1257 : }
1258 : else
1259 : {
1260 0 : glBindTexture(GL_TEXTURE_RECTANGLE, gnormaltex);
1261 : }
1262 0 : glActiveTexture(GL_TEXTURE0);
1263 :
1264 0 : matrix4 reproject;
1265 0 : reproject.muld(tqaaframe ? tqaaprevscreenmatrix : screenmatrix, worldmatrix);
1266 0 : vec2 jitter = tqaaframe&1 ? vec2(0.5f, 0.5f) : vec2(-0.5f, -0.5f);
1267 0 : if(multisampledaa())
1268 : {
1269 0 : jitter.x *= 0.5f;
1270 0 : jitter.y *= -0.5f;
1271 : }
1272 0 : if(tqaaframe)
1273 : {
1274 0 : reproject.jitter(jitter.x, jitter.y);
1275 : }
1276 0 : LOCALPARAM(reprojectmatrix, reproject);
1277 0 : float maxvel = sqrtf(vieww*vieww + viewh*viewh)/tqaareproject;
1278 0 : LOCALPARAMF(maxvelocity, maxvel, 1/maxvel);
1279 0 : }
1280 :
1281 : //general aa fxns
1282 0 : void setupaa(GBuffer &buf, int w, int h)
1283 : {
1284 0 : if(tqaa && !tqaafbo[0])
1285 : {
1286 0 : setuptqaa(buf, w, h);
1287 : }
1288 0 : if(smaarenderer.getsmaaproperty(subpixelaa::SMAA).get_int())
1289 : {
1290 0 : if(!smaarenderer.smaafbo[0])
1291 : {
1292 0 : smaarenderer.setupsmaa(buf, w, h);
1293 : }
1294 : }
1295 0 : else if(fxaarenderer.usefxaa)
1296 : {
1297 0 : if(!fxaarenderer.fxaafbo)
1298 : {
1299 0 : fxaarenderer.setupfxaa(buf, w, h);
1300 : }
1301 : }
1302 0 : }
1303 :
1304 0 : void jitteraa()
1305 : {
1306 0 : nojittermatrix = projmatrix;
1307 0 : if(!drawtex && tqaa)
1308 : {
1309 0 : vec2 jitter = tqaaframe&1 ? vec2(0.25f, 0.25f) : vec2(-0.25f, -0.25f);
1310 0 : if(multisampledaa())
1311 : {
1312 0 : jitter.x *= 0.5f;
1313 0 : jitter.y *= -0.5f;
1314 : }
1315 0 : projmatrix.jitter(jitter.x*2.0f/vieww, jitter.y*2.0f/viewh);
1316 : }
1317 0 : }
1318 :
1319 : // aa mask
1320 :
1321 : namespace aamask
1322 : {
1323 : static int aamaskstencil = -1,
1324 : aamask = -1;
1325 :
1326 0 : void set(bool on)
1327 : {
1328 0 : int val = on && !drawtex ? 1 : 0;
1329 0 : if(aamask == val)
1330 : {
1331 0 : return;
1332 : }
1333 0 : if(!aamaskstencil)
1334 : {
1335 0 : glStencilOp(GL_KEEP, GL_KEEP, val ? GL_REPLACE : GL_KEEP);
1336 0 : if(aamask < 0)
1337 : {
1338 0 : glStencilFunc(GL_ALWAYS, 0x80, ~0);
1339 0 : glEnable(GL_STENCIL_TEST);
1340 : }
1341 : }
1342 0 : else if(aamaskstencil > 0)
1343 : {
1344 0 : if(val)
1345 : {
1346 0 : glStencilFunc(GL_ALWAYS, 0x80 | aamaskstencil, ~0);
1347 : }
1348 0 : else if(aamask >= 0)
1349 : {
1350 0 : glStencilFunc(GL_ALWAYS, aamaskstencil, ~0);
1351 : }
1352 : }
1353 0 : aamask = val;
1354 0 : GLOBALPARAMF(aamask, aamask);
1355 : }
1356 :
1357 0 : void enable(int stencil)
1358 : {
1359 0 : aamask = -1;
1360 0 : aamaskstencil = !msaasamples && ghasstencil && tqaa && tqaamovemask && !drawtex ? stencil|avatarmask : -1;
1361 0 : }
1362 :
1363 0 : void disable()
1364 : {
1365 0 : if(aamaskstencil >= 0 && aamask >= 0)
1366 : {
1367 0 : if(!aamaskstencil)
1368 : {
1369 0 : glDisable(GL_STENCIL_TEST);
1370 : }
1371 0 : else if(aamask)
1372 : {
1373 0 : glStencilFunc(GL_ALWAYS, aamaskstencil, ~0);
1374 : }
1375 0 : aamask = -1;
1376 : }
1377 0 : }
1378 : }
1379 :
1380 0 : bool multisampledaa()
1381 : {
1382 0 : return msaasamples == 2 &&
1383 0 : (smaarenderer.getsmaaproperty(subpixelaa::SMAA).get_int() ? msaalight &&
1384 0 : smaarenderer.getsmaaproperty(subpixelaa::Spatial).get_int() : tqaa);
1385 : }
1386 :
1387 : //used by rendergl
1388 :
1389 0 : void doaa(GLuint outfbo, GBuffer &gbuffer)
1390 : {
1391 0 : if(smaarenderer.getsmaaproperty(subpixelaa::SMAA).get_int())
1392 : {
1393 0 : bool split = multisampledaa();
1394 0 : gbuffer.processhdr(smaarenderer.smaafbo[0], smaarenderer.smaatype);
1395 0 : smaarenderer.dosmaa(outfbo, split);
1396 : }
1397 0 : else if(fxaarenderer.usefxaa)
1398 : {
1399 0 : gbuffer.processhdr(fxaarenderer.fxaafbo, fxaarenderer.fxaatype);
1400 0 : fxaarenderer.dofxaa(outfbo);
1401 : }
1402 0 : else if(tqaa)
1403 : {
1404 0 : gbuffer.processhdr(tqaafbo[0], tqaatype);
1405 0 : dotqaa(outfbo);
1406 : }
1407 : else
1408 : {
1409 0 : gbuffer.processhdr(outfbo, AA_Unused);
1410 : }
1411 0 : }
1412 :
1413 0 : bool debugaa()
1414 : {
1415 0 : if(smaarenderer.getsmaaproperty(subpixelaa::Debug).get_int())
1416 : {
1417 0 : smaarenderer.viewsmaa();
1418 : }
1419 0 : else if(debugtqaa)
1420 : {
1421 0 : viewtqaa();
1422 : }
1423 : else
1424 : {
1425 0 : return false;
1426 : }
1427 0 : return true;
1428 : }
1429 :
1430 0 : void cleanupaa()
1431 : {
1432 0 : smaarenderer.cleanupsmaa();
1433 0 : fxaarenderer.cleanupfxaa();
1434 0 : cleanuptqaa();
1435 0 : }
1436 :
1437 1 : void initaacmds()
1438 : {
1439 2 : addcommand("getsmaaproperty", reinterpret_cast<identfun>(+[] (const char* name)
1440 : {
1441 1 : const prop::Property<>* prop = smaarenderer.getsmaaproperty(std::string(name));
1442 1 : if(prop) prop->cmd_result();
1443 2 : }), "s", Id_Command);
1444 :
1445 1 : addcommand("setsmaaproperty", reinterpret_cast<identfun>(+[] (const char* name, const int* value)
1446 : {
1447 2 : smaarenderer.setsmaaproperty(std::string(name), *value);
1448 2 : }), "si", Id_Command);
1449 1 : }
|