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