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.c_str(), "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 : smaatex[5] = { 0, 0, 0, 0, 0 };
332 : //affects subsample vector direction
333 : int smaasubsampleorder = -1;
334 : Shader *smaalumaedgeshader = nullptr,
335 : *smaacoloredgeshader = nullptr,
336 : *smaablendweightshader = nullptr,
337 : *smaaneighborhoodshader = nullptr;
338 :
339 : static constexpr int smaaareatexwidth = 160,
340 : smaaareatexheight = 560;
341 :
342 : static constexpr int smaasearchtexwidth = 66,
343 : smaasearchtexheight = 33;
344 :
345 : std::array<uchar, smaasearchtexwidth*smaasearchtexheight> smaasearchdata;
346 : std::array<uchar, smaaareatexwidth*smaaareatexheight*2> smaaareadata;
347 :
348 : bool smaasearchdatainited = false;
349 : bool smaaareadatainited = false;
350 :
351 : static constexpr int orthoedges[][2] =
352 : {
353 : {0, 0}, {3, 0}, {0, 3}, {3, 3}, {1, 0}, {4, 0}, {1, 3}, {4, 3},
354 : {0, 1}, {3, 1}, {0, 4}, {3, 4}, {1, 1}, {4, 1}, {1, 4}, {4, 4}
355 : };
356 : static constexpr int edgesdiag[][2] =
357 : {
358 : {0, 0}, {1, 0}, {0, 2}, {1, 2}, {2, 0}, {3, 0}, {2, 2}, {3, 2},
359 : {0, 1}, {1, 1}, {0, 3}, {1, 3}, {2, 1}, {3, 1}, {2, 3}, {3, 3}
360 : };
361 :
362 : static constexpr float offsetsortho[] = { 0.0f, -0.25f, 0.25f, -0.125f, 0.125f, -0.375f, 0.375f };
363 : 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 } };
364 :
365 : void gensmaasearchdata();
366 : vec2 areaunderortho(const vec2 &p1, const vec2 &p2, float x);
367 : void loadsmaashaders(bool split = false);
368 : void clearsmaashaders();
369 : vec2 areaortho(float p1x, float p1y, float p2x, float p2y, float left);
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(float p1x, float p1y, float p2x, float p2y, float p3x, float p3y, float p4x, float p4y, 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.c_str());
547 0 : smaacoloredgeshader = lookupshaderbyname(coloredgename.c_str());
548 0 : smaablendweightshader = lookupshaderbyname(blendweightname.c_str());
549 0 : smaaneighborhoodshader = lookupshaderbyname(neighborhoodname.c_str());
550 :
551 0 : if(smaalumaedgeshader && smaacoloredgeshader && smaablendweightshader && smaaneighborhoodshader)
552 : {
553 0 : return;
554 : }
555 0 : generateshader(nullptr, "smaashaders %d \"%s\"", props[SMAAProp::Quality].get_int(), opts.c_str());
556 0 : smaalumaedgeshader = lookupshaderbyname(lumaedgename.c_str());
557 0 : if(!smaalumaedgeshader)
558 : {
559 0 : smaalumaedgeshader = nullshader;
560 : }
561 0 : smaacoloredgeshader = lookupshaderbyname(coloredgename.c_str());
562 0 : if(!smaacoloredgeshader)
563 : {
564 0 : smaacoloredgeshader = nullshader;
565 : }
566 0 : smaablendweightshader = lookupshaderbyname(blendweightname.c_str());
567 0 : if(!smaablendweightshader)
568 : {
569 0 : smaablendweightshader = nullshader;
570 : }
571 0 : smaaneighborhoodshader = lookupshaderbyname(neighborhoodname.c_str());
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 : vec2 subpixelaa::areaortho(float p1x, float p1y, float p2x, float p2y, float left)
670 : {
671 0 : return areaunderortho(vec2(p1x, p1y), vec2(p2x, p2y), left);
672 : }
673 :
674 0 : void subpixelaa::smootharea(float d, vec2 &a1, vec2 &a2)
675 : {
676 0 : vec2 b1(sqrtf(a1.x*2)*0.5f, sqrtf(a1.y*2)*0.5f),
677 0 : b2(sqrtf(a2.x*2)*0.5f, sqrtf(a2.y*2)*0.5f);
678 0 : float p = std::clamp(d / 32.0f, 0.0f, 1.0f);
679 0 : a1.lerp(b1, a1, p);
680 0 : a2.lerp(b2, a2, p);
681 0 : }
682 :
683 0 : vec2 subpixelaa::areaortho(int pattern, float left, float right, float offset)
684 : {
685 0 : float d = left + right + 1,
686 0 : o1 = offset + 0.5f,
687 0 : o2 = offset - 0.5f;
688 0 : switch(pattern)
689 : {
690 0 : case 0:
691 : {
692 0 : return vec2(0, 0);
693 : }
694 0 : case 1:
695 : {
696 0 : return left <= right ? areaortho(0, o2, d/2, 0, left) : vec2(0, 0);
697 : }
698 0 : case 2:
699 : {
700 0 : return left >= right ? areaortho(d/2, 0, d, o2, left) : vec2(0, 0);
701 : }
702 0 : case 3:
703 : {
704 0 : vec2 a1 = areaortho(0, o2, d/2, 0, left), a2 = areaortho(d/2, 0, d, o2, left);
705 0 : smootharea(d, a1, a2);
706 0 : return a1.add(a2);
707 : }
708 0 : case 4:
709 : {
710 0 : return left <= right ? areaortho(0, o1, d/2, 0, left) : vec2(0, 0);
711 : }
712 0 : case 5:
713 : {
714 0 : return vec2(0, 0);
715 : }
716 0 : case 6:
717 : {
718 0 : vec2 a = areaortho(0, o1, d, o2, left);
719 0 : if(std::fabs(offset) > 0)
720 : {
721 0 : a.avg(areaortho(0, o1, d/2, 0, left).add(areaortho(d/2, 0, d, o2, left)));
722 : }
723 0 : return a;
724 : }
725 0 : case 7:
726 : {
727 0 : return areaortho(0, o1, d, o2, left);
728 : }
729 0 : case 8:
730 : {
731 0 : return left >= right ? areaortho(d/2, 0, d, o1, left) : vec2(0, 0);
732 : }
733 0 : case 9:
734 : {
735 0 : vec2 a = areaortho(0, o2, d, o1, left);
736 0 : if(std::fabs(offset) > 0)
737 : {
738 0 : a.avg(areaortho(0, o2, d/2, 0, left).add(areaortho(d/2, 0, d, o1, left)));
739 : }
740 0 : return a;
741 : }
742 0 : case 10:
743 : {
744 0 : return vec2(0, 0);
745 : }
746 0 : case 11:
747 : {
748 0 : return areaortho(0, o2, d, o1, left);
749 : }
750 0 : case 12:
751 : {
752 0 : vec2 a1 = areaortho(0, o1, d/2, 0, left),
753 0 : a2 = areaortho(d/2, 0, d, o1, left);
754 0 : smootharea(d, a1, a2);
755 0 : return a1.add(a2);
756 : }
757 0 : case 13:
758 : {
759 0 : return areaortho(0, o2, d, o1, left);
760 : }
761 0 : case 14:
762 : {
763 0 : return areaortho(0, o1, d, o2, left);
764 : }
765 0 : case 15:
766 : {
767 0 : return vec2(0, 0);
768 : }
769 : }
770 0 : return vec2(0, 0);
771 : }
772 :
773 0 : float subpixelaa::areaunderdiag(const vec2 &p1, const vec2 &p2, const vec2 &p)
774 : {
775 0 : vec2 d(p2.y - p1.y, p1.x - p2.x);
776 0 : float dp = d.dot(vec2(p1).sub(p));
777 0 : if(!d.x)
778 : {
779 0 : if(!d.y)
780 : {
781 0 : return 1;
782 : }
783 0 : return std::clamp(d.y > 0 ? 1 - dp/d.y : dp/d.y, 0.0f, 1.0f);
784 : }
785 0 : if(!d.y)
786 : {
787 0 : return std::clamp(d.x > 0 ? 1 - dp/d.x : dp/d.x, 0.0f, 1.0f);
788 : }
789 0 : float l = dp/d.y,
790 0 : r = (dp-d.x)/d.y,
791 0 : b = dp/d.x,
792 0 : t = (dp-d.y)/d.x;
793 0 : if(0 <= dp)
794 : {
795 0 : if(d.y <= dp)
796 : {
797 0 : if(d.x <= dp)
798 : {
799 0 : if(d.y+d.x <= dp)
800 : {
801 0 : return 0;
802 : }
803 0 : return 0.5f*(1-r)*(1-t);
804 : }
805 0 : if(d.y+d.x > dp)
806 : {
807 0 : return std::min(1-b, 1-t) + 0.5f*std::fabs(b-t);
808 : }
809 0 : return 0.5f*(1-b)*r;
810 : }
811 0 : if(d.x <= dp)
812 : {
813 0 : if(d.y+d.x <= dp)
814 : {
815 0 : return 0.5f*(1-l)*t;
816 : }
817 0 : return std::min(1-l, 1-r) + 0.5f*std::fabs(r-l);
818 : }
819 0 : return 1 - 0.5f*l*b;
820 : }
821 0 : if(d.y <= dp)
822 : {
823 0 : if(d.x <= dp)
824 : {
825 0 : return 0.5f*l*b;
826 : }
827 0 : if(d.y+d.x <= dp)
828 : {
829 0 : return std::min(l, r) + 0.5f*std::fabs(r-l);
830 : }
831 0 : return 1 - 0.5f*(1-l)*t;
832 : }
833 0 : if(d.x <= dp)
834 : {
835 0 : if(d.y+d.x <= dp)
836 : {
837 0 : return std::min(b, t) + 0.5f*std::fabs(b-t);
838 : }
839 0 : return 1 - 0.5f*(1-b)*r;
840 : }
841 0 : if(d.y+d.x <= dp)
842 : {
843 0 : return 1 - 0.5f*(1-t)*(1-r);
844 : }
845 0 : return 1;
846 : }
847 :
848 0 : vec2 subpixelaa::areadiag(const vec2 &p1, const vec2 &p2, float left)
849 : {
850 0 : return vec2(1 - areaunderdiag(p1, p2, vec2(1, 0).add(left)), areaunderdiag(p1, p2, vec2(1, 1).add(left)));
851 : }
852 :
853 0 : vec2 subpixelaa::areadiag(float p1x, float p1y, float p2x, float p2y, float d, float left, const vec2 &offset, int pattern)
854 : {
855 0 : vec2 p1(p1x, p1y),
856 0 : p2(p2x+d, p2y+d);
857 0 : if(edgesdiag[pattern][0])
858 : {
859 0 : p1.add(offset);
860 : }
861 0 : if(edgesdiag[pattern][1])
862 : {
863 0 : p2.add(offset);
864 : }
865 0 : return areadiag(p1, p2, left);
866 : }
867 :
868 0 : vec2 subpixelaa::areadiag2(float p1x, float p1y, float p2x, float p2y, float p3x, float p3y, float p4x, float p4y, float d, float left, const vec2 &offset, int pattern)
869 : {
870 0 : vec2 p1(p1x, p1y),
871 0 : p2(p2x+d, p2y+d),
872 0 : p3(p3x, p3y),
873 0 : p4(p4x+d, p4y+d);
874 0 : if(edgesdiag[pattern][0])
875 : {
876 0 : p1.add(offset);
877 0 : p3.add(offset);
878 : }
879 0 : if(edgesdiag[pattern][1])
880 : {
881 0 : p2.add(offset);
882 0 : p4.add(offset);
883 : }
884 0 : return areadiag(p1, p2, left).avg(areadiag(p3, p4, left));
885 : }
886 :
887 0 : vec2 subpixelaa::areadiag(int pattern, float left, float right, const vec2 &offset)
888 : {
889 0 : float d = left + right + 1;
890 0 : switch(pattern)
891 : {
892 0 : case 0: return areadiag2(1, 1, 1, 1, 1, 0, 1, 0, d, left, offset, pattern);
893 0 : case 1: return areadiag2(1, 0, 0, 0, 1, 0, 1, 0, d, left, offset, pattern);
894 0 : case 2: return areadiag2(0, 0, 1, 0, 1, 0, 1, 0, d, left, offset, pattern);
895 0 : case 3: return areadiag(1, 0, 1, 0, d, left, offset, pattern);
896 0 : case 4: return areadiag2(1, 1, 0, 0, 1, 1, 1, 0, d, left, offset, pattern);
897 0 : case 5: return areadiag2(1, 1, 0, 0, 1, 0, 1, 0, d, left, offset, pattern);
898 0 : case 6: return areadiag(1, 1, 1, 0, d, left, offset, pattern);
899 0 : case 7: return areadiag2(1, 1, 1, 0, 1, 0, 1, 0, d, left, offset, pattern);
900 0 : case 8: return areadiag2(0, 0, 1, 1, 1, 0, 1, 1, d, left, offset, pattern);
901 0 : case 9: return areadiag(1, 0, 1, 1, d, left, offset, pattern);
902 0 : case 10: return areadiag2(0, 0, 1, 1, 1, 0, 1, 0, d, left, offset, pattern);
903 0 : case 11: return areadiag2(1, 0, 1, 1, 1, 0, 1, 0, d, left, offset, pattern);
904 0 : case 12: return areadiag(1, 1, 1, 1, d, left, offset, pattern);
905 0 : case 13: return areadiag2(1, 1, 1, 1, 1, 0, 1, 1, d, left, offset, pattern);
906 0 : case 14: return areadiag2(1, 1, 1, 1, 1, 1, 1, 0, d, left, offset, pattern);
907 0 : case 15: return areadiag2(1, 1, 1, 1, 1, 0, 1, 0, d, left, offset, pattern);
908 : }
909 0 : return vec2(0, 0);
910 : }
911 :
912 0 : void subpixelaa::gensmaaareadata()
913 : {
914 0 : if(smaaareadatainited)
915 : {
916 0 : return;
917 : }
918 0 : smaaareadata.fill(0);
919 0 : for(int offset = 0; offset < static_cast<int>(sizeof(offsetsortho)/sizeof(offsetsortho[0])); ++offset)
920 : {
921 0 : for(int pattern = 0; pattern < 16; ++pattern)
922 : {
923 0 : int px = orthoedges[pattern][0]*16,
924 0 : py = (5*offset + orthoedges[pattern][1])*16;
925 0 : uchar *dst = &smaaareadata[(py*smaaareatexwidth + px)*2];
926 0 : for(int y = 0; y < 16; ++y)
927 : {
928 0 : for(int x = 0; x < 16; ++x)
929 : {
930 0 : vec2 a = areaortho(pattern, x*x, y*y, offsetsortho[offset]);
931 0 : dst[0] = static_cast<uchar>(255*a.x);
932 0 : dst[1] = static_cast<uchar>(255*a.y);
933 0 : dst += 2;
934 : }
935 0 : dst += (smaaareatexwidth-16)*2;
936 : }
937 : }
938 : }
939 0 : for(int offset = 0; offset < static_cast<int>(sizeof(offsetsdiag)/sizeof(offsetsdiag[0])); ++offset)
940 : {
941 0 : for(int pattern = 0; pattern < 16; ++pattern)
942 : {
943 0 : int px = 5*16 + edgesdiag[pattern][0]*20,
944 0 : py = (4*offset + edgesdiag[pattern][1])*20;
945 0 : uchar *dst = &smaaareadata[(py*smaaareatexwidth + px)*2];
946 0 : for(int y = 0; y < 20; ++y)
947 : {
948 0 : for(int x = 0; x < 20; ++x)
949 : {
950 0 : vec2 a = areadiag(pattern, x, y, vec2(offsetsdiag[offset][0], offsetsdiag[offset][1]));
951 0 : dst[0] = static_cast<uchar>(255*a.x);
952 0 : dst[1] = static_cast<uchar>(255*a.y);
953 0 : dst += 2;
954 : }
955 0 : dst += (smaaareatexwidth-20)*2;
956 : }
957 : }
958 : }
959 0 : smaaareadatainited = true;
960 : }
961 :
962 0 : void subpixelaa::setupsmaa(GBuffer &buf, int w, int h)
963 : {
964 0 : if(!smaaareatex)
965 : {
966 0 : glGenTextures(1, &smaaareatex);
967 : }
968 0 : if(!smaasearchtex)
969 : {
970 0 : glGenTextures(1, &smaasearchtex);
971 : }
972 0 : gensmaasearchdata();
973 0 : gensmaaareadata();
974 0 : createtexture( smaaareatex, smaaareatexwidth, smaaareatexheight, smaaareadata.data(), 3, 1, GL_RG8, GL_TEXTURE_RECTANGLE, 0, 0, 0, false);
975 0 : createtexture(smaasearchtex, smaasearchtexwidth, smaasearchtexheight, smaasearchdata.data(), 3, 0, GL_R8, GL_TEXTURE_2D, 0, 0, 0, false);
976 0 : bool split = multisampledaa();
977 0 : smaasubsampleorder = split ? (msaapositions[0].x < 0.5f ? 1 : 0) : -1;
978 0 : props[SMAAProp::T2X].set_no_cb(tqaa ? 1 : 0);
979 0 : props[SMAAProp::S2X].set_no_cb(split ? 1 : 0);
980 0 : props[SMAAProp::X4].set_no_cb(tqaa && split ? 1 : 0);
981 0 : for(int i = 0; i < (split ? 4 : 3); ++i)
982 : {
983 0 : if(!smaatex[i])
984 : {
985 0 : glGenTextures(1, &smaatex[i]);
986 : }
987 0 : if(!smaafbo[i])
988 : {
989 0 : glGenFramebuffers(1, &smaafbo[i]);
990 : }
991 0 : glBindFramebuffer(GL_FRAMEBUFFER, smaafbo[i]);
992 0 : GLenum format = GL_RGB;
993 0 : switch(i)
994 : {
995 0 : case 0:
996 : {
997 0 : format = tqaa || (!props[SMAAProp::GreenLuma].get_int() && !intel_texalpha_bug && !props[SMAAProp::ColorEdge].get_int()) ? GL_RGBA8 : GL_RGB;
998 0 : break;
999 : }
1000 0 : case 1:
1001 : {
1002 0 : format = GL_RG8;
1003 0 : break;
1004 : }
1005 0 : case 2:
1006 : case 3:
1007 : {
1008 0 : format = GL_RGBA8;
1009 0 : break;
1010 : }
1011 : }
1012 0 : createtexture(smaatex[i], w, h, nullptr, 3, 1, format, GL_TEXTURE_RECTANGLE);
1013 0 : glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, smaatex[i], 0);
1014 0 : if(!i && split)
1015 : {
1016 0 : if(!smaatex[4])
1017 : {
1018 0 : glGenTextures(1, &smaatex[4]);
1019 : }
1020 0 : createtexture(smaatex[4], w, h, nullptr, 3, 1, format, GL_TEXTURE_RECTANGLE);
1021 0 : glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_RECTANGLE, smaatex[4], 0);
1022 : static const GLenum drawbufs[2] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
1023 0 : glDrawBuffers(2, drawbufs);
1024 : }
1025 0 : if(!i || (props[SMAAProp::DepthMask].get_int() && (!tqaa || msaalight)) || (props[SMAAProp::Stencil].get_int() && ghasstencil > (msaasamples ? 1 : 0)))
1026 : {
1027 0 : buf.bindgdepth();
1028 : }
1029 0 : if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
1030 : {
1031 0 : fatal("failed allocating SMAA buffer!");
1032 : }
1033 : }
1034 0 : glBindFramebuffer(GL_FRAMEBUFFER, 0);
1035 :
1036 0 : loadsmaashaders(split);
1037 0 : }
1038 :
1039 0 : void subpixelaa::cleanupsmaa()
1040 : {
1041 0 : if(smaaareatex)
1042 : {
1043 0 : glDeleteTextures(1, &smaaareatex);
1044 0 : smaaareatex = 0;
1045 : }
1046 0 : if(smaasearchtex)
1047 : {
1048 0 : glDeleteTextures(1, &smaasearchtex);
1049 0 : smaasearchtex = 0;
1050 : }
1051 0 : for(GLuint i : smaafbo)
1052 : {
1053 0 : if(i)
1054 : {
1055 0 : glDeleteFramebuffers(1, &i);
1056 0 : i = 0;
1057 : }
1058 : }
1059 0 : for(int i = 0; i < 5; ++i)
1060 : {
1061 0 : if(smaatex[i])
1062 : {
1063 0 : glDeleteTextures(1, &smaatex[i]);
1064 0 : smaatex[i] = 0;
1065 : }
1066 : }
1067 0 : smaasubsampleorder = -1;
1068 0 : props[SMAAProp::T2X].set_no_cb(0);
1069 0 : props[SMAAProp::S2X].set_no_cb(0);
1070 0 : props[SMAAProp::X4].set_no_cb(0);
1071 :
1072 0 : clearsmaashaders();
1073 0 : }
1074 :
1075 0 : void subpixelaa::viewsmaa()
1076 : {
1077 0 : int w = debugfullscreen ? hudw() : std::min(hudw(), hudh())/2,
1078 0 : h = debugfullscreen ? hudh() : (w*hudh())/hudw(),
1079 0 : tw = gw,
1080 0 : th = gh;
1081 0 : SETSHADER(hudrect,);
1082 0 : gle::colorf(1, 1, 1);
1083 : /* debugsmaa levels:
1084 : * 1: show the output tex resulting from smaa
1085 : * 2: show the raw filtering output applied to the screen buffer
1086 : * 3: show the refined filtering output applied to the screen buffer
1087 : * 4: show the buffer of edge-detect patterns
1088 : * 5: show the smaa search texture
1089 : */
1090 0 : switch(props[SMAAProp::Debug].get_int())
1091 : {
1092 0 : case 1:
1093 : {
1094 0 : glBindTexture(GL_TEXTURE_RECTANGLE, smaatex[0]);
1095 0 : break;
1096 : }
1097 0 : case 2:
1098 : {
1099 0 : glBindTexture(GL_TEXTURE_RECTANGLE, smaatex[1]);
1100 0 : break;
1101 : }
1102 0 : case 3:
1103 : {
1104 0 : glBindTexture(GL_TEXTURE_RECTANGLE, smaatex[2]);
1105 0 : break;
1106 : }
1107 0 : case 4:
1108 : {
1109 0 : glBindTexture(GL_TEXTURE_RECTANGLE, smaaareatex);
1110 0 : tw = smaaareatexwidth;
1111 0 : th = smaaareatexheight;
1112 0 : break;
1113 : }
1114 0 : case 5:
1115 : {
1116 0 : glBindTexture(GL_TEXTURE_2D, smaasearchtex);
1117 0 : tw = 1;
1118 0 : th = 1;
1119 0 : break;
1120 : }
1121 : }
1122 0 : debugquad(0, 0, w, h, 0, 0, tw, th);
1123 0 : }
1124 :
1125 0 : void subpixelaa::dosmaa(GLuint outfbo, bool split)
1126 : {
1127 0 : timer *smaatimer = begintimer("smaa");
1128 :
1129 0 : int cleardepth = msaalight ? GL_DEPTH_BUFFER_BIT | (ghasstencil > 1 ? GL_STENCIL_BUFFER_BIT : 0) : 0;
1130 0 : bool depthmask = props[SMAAProp::DepthMask].get_int() && (!tqaa || msaalight),
1131 0 : stencil = props[SMAAProp::Stencil].get_int() && ghasstencil > (msaasamples ? 1 : 0);
1132 0 : for(int pass = 0; pass < (split ? 2 : 1); ++pass) // loop through multiple passes if doing multisample aa
1133 : {
1134 0 : glBindFramebuffer(GL_FRAMEBUFFER, smaafbo[1]);
1135 0 : if(depthmask || stencil)
1136 : {
1137 0 : glClearColor(0, 0, 0, 0);
1138 0 : glClear(GL_COLOR_BUFFER_BIT | (!pass ? cleardepth : 0));
1139 : }
1140 0 : if(depthmask)
1141 : {
1142 0 : glEnable(GL_DEPTH_TEST);
1143 0 : glDepthFunc(GL_ALWAYS);
1144 0 : float depthval = cleardepth ? 0.25f*(pass+1) : 1;
1145 0 : glDepthRange(depthval, depthval);
1146 : }
1147 0 : else if(stencil)
1148 : {
1149 0 : glEnable(GL_STENCIL_TEST);
1150 0 : glStencilFunc(GL_ALWAYS, 0x10*(pass+1), ~0);
1151 0 : glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
1152 : }
1153 0 : if(props[SMAAProp::ColorEdge].get_int())
1154 : {
1155 0 : smaacoloredgeshader->set();
1156 : }
1157 0 : else if(smaalumaedgeshader)
1158 : {
1159 0 : smaalumaedgeshader->set();
1160 : }
1161 0 : glBindTexture(GL_TEXTURE_RECTANGLE, smaatex[pass ? 4 : 0]);
1162 0 : screenquad(vieww, viewh);
1163 0 : glBindFramebuffer(GL_FRAMEBUFFER, smaafbo[2 + pass]);
1164 0 : if(depthmask)
1165 : {
1166 0 : glDepthFunc(GL_EQUAL);
1167 0 : glDepthMask(GL_FALSE);
1168 : }
1169 0 : else if(stencil)
1170 : {
1171 0 : glStencilFunc(GL_EQUAL, 0x10*(pass+1), ~0);
1172 0 : glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1173 : }
1174 0 : if(depthmask || stencil)
1175 : {
1176 0 : glClear(GL_COLOR_BUFFER_BIT);
1177 : }
1178 0 : if(smaablendweightshader)
1179 : {
1180 0 : smaablendweightshader->set();
1181 : }
1182 0 : vec4<float> subsamples(0, 0, 0, 0);
1183 0 : if(tqaa && split)
1184 : {
1185 0 : subsamples = tqaaframe&1 ?
1186 0 : (pass != smaasubsampleorder ? vec4<float>(6, 4, 2, 4) : vec4<float>(3, 5, 1, 4)) :
1187 0 : (pass != smaasubsampleorder ? vec4<float>(4, 6, 2, 3) : vec4<float>(5, 3, 1, 3));
1188 : }
1189 0 : else if(tqaa)
1190 : {
1191 0 : subsamples = tqaaframe&1 ? vec4<float>(2, 2, 2, 0) : vec4<float>(1, 1, 1, 0);
1192 : }
1193 0 : else if(split)
1194 : {
1195 0 : subsamples = pass != smaasubsampleorder ? vec4<float>(2, 2, 2, 0) : vec4<float>(1, 1, 1, 0);
1196 : }
1197 0 : LOCALPARAM(subsamples, subsamples);
1198 0 : glBindTexture(GL_TEXTURE_RECTANGLE, smaatex[1]);
1199 0 : glActiveTexture(GL_TEXTURE1);
1200 0 : glBindTexture(GL_TEXTURE_RECTANGLE, smaaareatex);
1201 0 : glActiveTexture(GL_TEXTURE2);
1202 0 : glBindTexture(GL_TEXTURE_2D, smaasearchtex);
1203 0 : glActiveTexture(GL_TEXTURE0);
1204 0 : screenquad(vieww, viewh);
1205 0 : if(depthmask)
1206 : {
1207 0 : glDisable(GL_DEPTH_TEST);
1208 0 : glDepthMask(GL_TRUE);
1209 0 : glDepthFunc(GL_LESS);
1210 0 : glDepthRange(0, 1);
1211 : }
1212 0 : else if(stencil)
1213 : {
1214 0 : glDisable(GL_STENCIL_TEST);
1215 : }
1216 : }
1217 0 : glBindFramebuffer(GL_FRAMEBUFFER, tqaa ? tqaafbo[0] : outfbo);
1218 0 : if(smaaneighborhoodshader)
1219 : {
1220 0 : smaaneighborhoodshader->set();
1221 : }
1222 0 : glBindTexture(GL_TEXTURE_RECTANGLE, smaatex[0]);
1223 0 : glActiveTexture(GL_TEXTURE1);
1224 0 : glBindTexture(GL_TEXTURE_RECTANGLE, smaatex[2]);
1225 0 : if(split)
1226 : {
1227 0 : glActiveTexture(GL_TEXTURE2);
1228 0 : glBindTexture(GL_TEXTURE_RECTANGLE, smaatex[4]);
1229 0 : glActiveTexture(GL_TEXTURE3);
1230 0 : glBindTexture(GL_TEXTURE_RECTANGLE, smaatex[3]);
1231 : }
1232 0 : glActiveTexture(GL_TEXTURE0);
1233 0 : screenquad(vieww, viewh);
1234 0 : if(tqaa)
1235 : {
1236 0 : resolvetqaa(outfbo);
1237 : }
1238 0 : endtimer(smaatimer);
1239 0 : }
1240 : //end of SMAA code
1241 :
1242 : /* general antialiasing control functions */
1243 : ////////////////////////////////////////////
1244 : }
1245 :
1246 : //for temporal aa, called externally
1247 0 : void GBuffer::setaavelocityparams(GLenum tmu)
1248 : {
1249 0 : glActiveTexture(tmu);
1250 0 : if(msaalight)
1251 : {
1252 0 : glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msdepthtex);
1253 : }
1254 : else
1255 : {
1256 0 : glBindTexture(GL_TEXTURE_RECTANGLE, gdepthtex);
1257 : }
1258 0 : glActiveTexture(++tmu);
1259 0 : if(msaasamples)
1260 : {
1261 0 : glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msnormaltex);
1262 : }
1263 : else
1264 : {
1265 0 : glBindTexture(GL_TEXTURE_RECTANGLE, gnormaltex);
1266 : }
1267 0 : glActiveTexture(GL_TEXTURE0);
1268 :
1269 0 : matrix4 reproject;
1270 0 : reproject.muld(tqaaframe ? tqaaprevscreenmatrix : screenmatrix, worldmatrix);
1271 0 : vec2 jitter = tqaaframe&1 ? vec2(0.5f, 0.5f) : vec2(-0.5f, -0.5f);
1272 0 : if(multisampledaa())
1273 : {
1274 0 : jitter.x *= 0.5f;
1275 0 : jitter.y *= -0.5f;
1276 : }
1277 0 : if(tqaaframe)
1278 : {
1279 0 : reproject.jitter(jitter.x, jitter.y);
1280 : }
1281 0 : LOCALPARAM(reprojectmatrix, reproject);
1282 0 : float maxvel = sqrtf(vieww*vieww + viewh*viewh)/tqaareproject;
1283 0 : LOCALPARAMF(maxvelocity, maxvel, 1/maxvel);
1284 0 : }
1285 :
1286 : //general aa fxns
1287 0 : void setupaa(GBuffer &buf, int w, int h)
1288 : {
1289 0 : if(tqaa && !tqaafbo[0])
1290 : {
1291 0 : setuptqaa(buf, w, h);
1292 : }
1293 0 : if(smaarenderer.getsmaaproperty(subpixelaa::SMAA).get_int())
1294 : {
1295 0 : if(!smaarenderer.smaafbo[0])
1296 : {
1297 0 : smaarenderer.setupsmaa(buf, w, h);
1298 : }
1299 : }
1300 0 : else if(fxaarenderer.usefxaa)
1301 : {
1302 0 : if(!fxaarenderer.fxaafbo)
1303 : {
1304 0 : fxaarenderer.setupfxaa(buf, w, h);
1305 : }
1306 : }
1307 0 : }
1308 :
1309 0 : void jitteraa()
1310 : {
1311 0 : nojittermatrix = projmatrix;
1312 0 : if(!drawtex && tqaa)
1313 : {
1314 0 : vec2 jitter = tqaaframe&1 ? vec2(0.25f, 0.25f) : vec2(-0.25f, -0.25f);
1315 0 : if(multisampledaa())
1316 : {
1317 0 : jitter.x *= 0.5f;
1318 0 : jitter.y *= -0.5f;
1319 : }
1320 0 : projmatrix.jitter(jitter.x*2.0f/vieww, jitter.y*2.0f/viewh);
1321 : }
1322 0 : }
1323 :
1324 : // aa mask
1325 :
1326 : namespace aamask
1327 : {
1328 : static int aamaskstencil = -1,
1329 : aamask = -1;
1330 :
1331 0 : void set(bool on)
1332 : {
1333 0 : int val = on && !drawtex ? 1 : 0;
1334 0 : if(aamask == val)
1335 : {
1336 0 : return;
1337 : }
1338 0 : if(!aamaskstencil)
1339 : {
1340 0 : glStencilOp(GL_KEEP, GL_KEEP, val ? GL_REPLACE : GL_KEEP);
1341 0 : if(aamask < 0)
1342 : {
1343 0 : glStencilFunc(GL_ALWAYS, 0x80, ~0);
1344 0 : glEnable(GL_STENCIL_TEST);
1345 : }
1346 : }
1347 0 : else if(aamaskstencil > 0)
1348 : {
1349 0 : if(val)
1350 : {
1351 0 : glStencilFunc(GL_ALWAYS, 0x80 | aamaskstencil, ~0);
1352 : }
1353 0 : else if(aamask >= 0)
1354 : {
1355 0 : glStencilFunc(GL_ALWAYS, aamaskstencil, ~0);
1356 : }
1357 : }
1358 0 : aamask = val;
1359 0 : GLOBALPARAMF(aamask, aamask);
1360 : }
1361 :
1362 0 : void enable(int stencil)
1363 : {
1364 0 : aamask = -1;
1365 0 : aamaskstencil = !msaasamples && ghasstencil && tqaa && tqaamovemask && !drawtex ? stencil|avatarmask : -1;
1366 0 : }
1367 :
1368 0 : void disable()
1369 : {
1370 0 : if(aamaskstencil >= 0 && aamask >= 0)
1371 : {
1372 0 : if(!aamaskstencil)
1373 : {
1374 0 : glDisable(GL_STENCIL_TEST);
1375 : }
1376 0 : else if(aamask)
1377 : {
1378 0 : glStencilFunc(GL_ALWAYS, aamaskstencil, ~0);
1379 : }
1380 0 : aamask = -1;
1381 : }
1382 0 : }
1383 : }
1384 :
1385 0 : bool multisampledaa()
1386 : {
1387 0 : return msaasamples == 2 &&
1388 0 : (smaarenderer.getsmaaproperty(subpixelaa::SMAA).get_int() ? msaalight &&
1389 0 : smaarenderer.getsmaaproperty(subpixelaa::Spatial).get_int() : tqaa);
1390 : }
1391 :
1392 : //used by rendergl
1393 :
1394 : /* doaa: executes one type of screenspace aa
1395 : *
1396 : * only one screenspace aa can be used at a time, and smaa will always be used
1397 : * instead of fxaa or tqaa; fxaa will always be used instead of tqaa
1398 : *
1399 : * does not apply to multisample aa, msaa is not a screenspace aa
1400 : *
1401 : * method pointer resolve is used to setup the fbo for the specified aa
1402 : */
1403 0 : void doaa(GLuint outfbo, GBuffer &gbuffer)
1404 : {
1405 0 : if(smaarenderer.getsmaaproperty(subpixelaa::SMAA).get_int())
1406 : {
1407 0 : bool split = multisampledaa();
1408 0 : gbuffer.processhdr(smaarenderer.smaafbo[0], smaarenderer.smaatype);
1409 0 : smaarenderer.dosmaa(outfbo, split);
1410 : }
1411 0 : else if(fxaarenderer.usefxaa)
1412 : {
1413 0 : gbuffer.processhdr(fxaarenderer.fxaafbo, fxaarenderer.fxaatype);
1414 0 : fxaarenderer.dofxaa(outfbo);
1415 : }
1416 0 : else if(tqaa)
1417 : {
1418 0 : gbuffer.processhdr(tqaafbo[0], tqaatype);
1419 0 : dotqaa(outfbo);
1420 : }
1421 : else
1422 : {
1423 0 : gbuffer.processhdr(outfbo, AA_Unused);
1424 : }
1425 0 : }
1426 :
1427 0 : bool debugaa()
1428 : {
1429 0 : if(smaarenderer.getsmaaproperty(subpixelaa::Debug).get_int())
1430 : {
1431 0 : smaarenderer.viewsmaa();
1432 : }
1433 0 : else if(debugtqaa)
1434 : {
1435 0 : viewtqaa();
1436 : }
1437 : else
1438 : {
1439 0 : return false;
1440 : }
1441 0 : return true;
1442 : }
1443 :
1444 0 : void cleanupaa()
1445 : {
1446 0 : smaarenderer.cleanupsmaa();
1447 0 : fxaarenderer.cleanupfxaa();
1448 0 : cleanuptqaa();
1449 0 : }
1450 :
1451 1 : void initaacmds()
1452 : {
1453 1 : addcommand("getsmaaproperty", reinterpret_cast<identfun>(+[] (char* name)
1454 : {
1455 1 : const prop::Property<>* prop = smaarenderer.getsmaaproperty(std::string(name));
1456 1 : if(prop) prop->cmd_result();
1457 2 : }), "s", Id_Command);
1458 :
1459 1 : addcommand("setsmaaproperty", reinterpret_cast<identfun>(+[] (char* name, int* value)
1460 : {
1461 1 : smaarenderer.setsmaaproperty(std::string(name), *value);
1462 2 : }), "si", Id_Command);
1463 1 : }
|