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