1 #include "engine.h"
2 
3 extern void cleanuptqaa();
4 
5 VARFP(tqaa, 0, 0, 1, cleanupaa());
6 FVAR(tqaareproject, 0, 300, 1e3f);
7 VARF(tqaamovemask, 0, 1, 1, cleanupaa());
8 VARP(tqaaquincunx, 0, 1, 1);
9 FVAR(tqaacolorweightscale, 0, 0.25f, 1e3f);
10 FVAR(tqaacolorweightbias, 0, 0.01f, 1);
11 VAR(tqaaresolvegather, 1, 0, 0);
12 
13 struct tqaaview
14 {
15     int frame;
16     GLuint prevtex, curtex, fbo[2];
17     matrix4 prevscreenmatrix;
18 
tqaaviewtqaaview19     tqaaview() : frame(0), prevtex(0), curtex(0)
20     {
21         memset(fbo, 0, sizeof(fbo));
22     }
23 
cleanuptqaaview24     void cleanup()
25     {
26         if(prevtex) { glDeleteTextures(1, &prevtex); prevtex = 0; }
27         if(curtex) { glDeleteTextures(1, &curtex); curtex = 0; }
28         loopi(2) if(fbo[i]) { glDeleteFramebuffers_(1, &fbo[i]); fbo[i] = 0; }
29         frame = 0;
30     }
31 
setuptqaaview32     void setup(int w, int h)
33     {
34         if(!prevtex) glGenTextures(1, &prevtex);
35         if(!curtex) glGenTextures(1, &curtex);
36         createtexture(prevtex, w, h, NULL, 3, 1, GL_RGBA8, GL_TEXTURE_RECTANGLE);
37         createtexture(curtex, w, h, NULL, 3, 1, GL_RGBA8, GL_TEXTURE_RECTANGLE);
38         loopi(2)
39         {
40             if(!fbo[i]) glGenFramebuffers_(1, &fbo[i]);
41             glBindFramebuffer_(GL_FRAMEBUFFER, fbo[i]);
42             GLuint tex = i ? prevtex : curtex;
43             glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, tex, 0);
44             bindgdepth();
45             if(glCheckFramebufferStatus_(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
46                 fatal("failed allocating TQAA buffer!");
47         }
48         glBindFramebuffer_(GL_FRAMEBUFFER, 0);
49 
50         prevscreenmatrix.identity();
51     }
52 
setaavelocityparamstqaaview53     void setaavelocityparams(GLuint tmu)
54     {
55         if(tmu!=GL_TEXTURE0) glActiveTexture_(tmu);
56         if(msaasamples) glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msdepthtex);
57         else glBindTexture(GL_TEXTURE_RECTANGLE, gdepthtex);
58         matrix4 reproject;
59         reproject.muld(frame ? prevscreenmatrix : screenmatrix, worldmatrix);
60         vec2 jitter = frame&1 ? vec2(0.5f, 0.5f) : vec2(-0.5f, -0.5f);
61         if(multisampledaa()) { jitter.x *= 0.5f; jitter.y *= -0.5f; }
62         if(frame) reproject.jitter(jitter.x, jitter.y);
63         LOCALPARAM(reprojectmatrix, reproject);
64         float maxvel = sqrtf(vieww*vieww + viewh*viewh)/tqaareproject;
65         LOCALPARAMF(maxvelocity, maxvel, 1/maxvel);
66         if(tqaamovemask)
67         {
68             glActiveTexture_(++tmu);
69             if(msaasamples) glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msnormaltex);
70             else glBindTexture(GL_TEXTURE_RECTANGLE, gnormaltex);
71         }
72         if(tmu!=GL_TEXTURE0) glActiveTexture_(GL_TEXTURE0);
73     }
74 
resolvetqaaview75     void resolve(GLuint outfbo)
76     {
77         glBindFramebuffer_(GL_FRAMEBUFFER, outfbo);
78         SETSHADER(tqaaresolve);
79         LOCALPARAMF(colorweight, tqaacolorweightscale, -tqaacolorweightbias*tqaacolorweightscale);
80         glBindTexture(GL_TEXTURE_RECTANGLE, curtex);
81         glActiveTexture_(GL_TEXTURE1);
82         glBindTexture(GL_TEXTURE_RECTANGLE, frame ? prevtex : curtex);
83         setaavelocityparams(GL_TEXTURE2);
84         glActiveTexture_(GL_TEXTURE0);
85         vec4 quincunx(0, 0, 0, 0);
86         if(tqaaquincunx) quincunx = frame&1 ? vec4(0.25f, 0.25f, -0.25f, -0.25f) : vec4(-0.25f, -0.25f, 0.25f, 0.25f);
87         if(multisampledaa()) { quincunx.x *= 0.5f; quincunx.y *= -0.5f; quincunx.z *= 0.5f; quincunx.w *= -0.5f; }
88         LOCALPARAM(quincunx, quincunx);
89         screenquad(vieww, viewh);
90 
91         swap(fbo[0], fbo[1]);
92         swap(curtex, prevtex);
93         prevscreenmatrix = screenmatrix;
94         frame++;
95     }
96 } tqaaviews[2];
97 
98 int tqaatype = -1;
99 
loadtqaashaders()100 void loadtqaashaders()
101 {
102     tqaatype = tqaamovemask ? AA_VELOCITY_MASKED : AA_VELOCITY;
103     loadhdrshaders(tqaatype);
104 
105     useshaderbyname("tqaaresolve");
106 }
107 
setuptqaa(int w,int h)108 void setuptqaa(int w, int h)
109 {
110     loopi(ovr::enabled ? 2 : 1) tqaaviews[i].setup(w, h);
111 
112     loadtqaashaders();
113 }
114 
cleanuptqaa()115 void cleanuptqaa()
116 {
117     tqaatype = -1;
118     loopi(2) tqaaviews[i].cleanup();
119 }
120 
setaavelocityparams(GLenum tmu)121 void setaavelocityparams(GLenum tmu)
122 {
123     tqaaview &tv = tqaaviews[viewidx];
124     tv.setaavelocityparams(tmu);
125 }
126 
dotqaa(tqaaview & tv,GLuint outfbo=0)127 void dotqaa(tqaaview &tv, GLuint outfbo = 0)
128 {
129     timer *tqaatimer = begintimer("tqaa");
130 
131     tv.resolve(outfbo);
132 
133     endtimer(tqaatimer);
134 }
135 
136 GLuint fxaafbo = 0, fxaatex = 0;
137 
138 extern int fxaaquality, fxaagreenluma;
139 
140 int fxaatype = -1;
141 static Shader *fxaashader = NULL;
142 
loadfxaashaders()143 void loadfxaashaders()
144 {
145     fxaatype = tqaatype >= 0 ? tqaatype : (!fxaagreenluma ? AA_LUMA : AA_UNUSED);
146     loadhdrshaders(fxaatype);
147 
148     string opts;
149     int optslen = 0;
150     if(fxaagreenluma || tqaa) opts[optslen++] = 'g';
151     opts[optslen] = '\0';
152 
153     defformatstring(fxaaname, "fxaa%d%s", fxaaquality, opts);
154     fxaashader = generateshader(fxaaname, "fxaashaders %d \"%s\"", fxaaquality, opts);
155 }
156 
clearfxaashaders()157 void clearfxaashaders()
158 {
159     fxaatype = -1;
160     fxaashader = NULL;
161 }
162 
setupfxaa(int w,int h)163 void setupfxaa(int w, int h)
164 {
165     if(!fxaatex) glGenTextures(1, &fxaatex);
166     if(!fxaafbo) glGenFramebuffers_(1, &fxaafbo);
167     glBindFramebuffer_(GL_FRAMEBUFFER, fxaafbo);
168     createtexture(fxaatex, w, h, NULL, 3, 1, tqaa || !fxaagreenluma ? GL_RGBA8 : GL_RGB, GL_TEXTURE_RECTANGLE);
169     glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, fxaatex, 0);
170     bindgdepth();
171     if(glCheckFramebufferStatus_(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
172         fatal("failed allocating FXAA buffer!");
173     glBindFramebuffer_(GL_FRAMEBUFFER, 0);
174 
175     loadfxaashaders();
176 }
177 
cleanupfxaa()178 void cleanupfxaa()
179 {
180     if(fxaafbo) { glDeleteFramebuffers_(1, &fxaafbo); fxaafbo = 0; }
181     if(fxaatex) { glDeleteTextures(1, &fxaatex); fxaatex = 0; }
182 
183     clearfxaashaders();
184 }
185 
186 VARFP(fxaa, 0, 0, 1, cleanupfxaa());
187 VARFP(fxaaquality, 0, 1, 3, cleanupfxaa());
188 VARFP(fxaagreenluma, 0, 0, 1, cleanupfxaa());
189 
dofxaa(GLuint outfbo=0)190 void dofxaa(GLuint outfbo = 0)
191 {
192     timer *fxaatimer = begintimer("fxaa");
193 
194     tqaaview &tv = tqaaviews[viewidx];
195 
196     glBindFramebuffer_(GL_FRAMEBUFFER, tqaa ? tv.fbo[0] : outfbo);
197     fxaashader->set();
198     glBindTexture(GL_TEXTURE_RECTANGLE, fxaatex);
199     screenquad(vieww, viewh);
200 
201     if(tqaa) tv.resolve(outfbo);
202 
203     endtimer(fxaatimer);
204 }
205 
206 GLuint smaaareatex = 0, smaasearchtex = 0, smaafbo[4] = { 0, 0, 0, 0 }, smaatex[5] = { 0, 0, 0, 0, 0 };
207 int smaasubsampleorder = -1;
208 
209 extern int smaaquality, smaagreenluma, smaacoloredge, smaadepthmask, smaastencil;
210 
211 int smaatype = -1;
212 static Shader *smaalumaedgeshader = NULL, *smaacoloredgeshader = NULL, *smaablendweightshader = NULL, *smaaneighborhoodshader = NULL;
213 
loadsmaashaders(bool split=false)214 void loadsmaashaders(bool split = false)
215 {
216     smaatype = tqaatype >= 0 ? tqaatype : (!smaagreenluma && !smaacoloredge ? AA_LUMA : AA_UNUSED);
217     if(split) smaatype += AA_SPLIT;
218     loadhdrshaders(smaatype);
219 
220     string opts;
221     int optslen = 0;
222     if(!hasTRG) opts[optslen++] = 'a';
223     if(smaadepthmask || smaastencil) opts[optslen++] = 'd';
224     if(split) opts[optslen++] = 's';
225     if(smaagreenluma || tqaa) opts[optslen++] = 'g';
226     if(tqaa) opts[optslen++] = 't';
227     opts[optslen] = '\0';
228 
229     defformatstring(lumaedgename, "SMAALumaEdgeDetection%d%s", smaaquality, opts);
230     defformatstring(coloredgename, "SMAAColorEdgeDetection%d%s", smaaquality, opts);
231     defformatstring(blendweightname, "SMAABlendingWeightCalculation%d%s", smaaquality, opts);
232     defformatstring(neighborhoodname, "SMAANeighborhoodBlending%d%s", smaaquality, opts);
233     smaalumaedgeshader = lookupshaderbyname(lumaedgename);
234     smaacoloredgeshader = lookupshaderbyname(coloredgename);
235     smaablendweightshader = lookupshaderbyname(blendweightname);
236     smaaneighborhoodshader = lookupshaderbyname(neighborhoodname);
237 
238     if(smaalumaedgeshader && smaacoloredgeshader && smaablendweightshader && smaaneighborhoodshader) return;
239 
240     generateshader(NULL, "smaashaders %d \"%s\"", smaaquality, opts);
241     smaalumaedgeshader = lookupshaderbyname(lumaedgename);
242     if(!smaalumaedgeshader) smaalumaedgeshader = nullshader;
243     smaacoloredgeshader = lookupshaderbyname(coloredgename);
244     if(!smaacoloredgeshader) smaacoloredgeshader = nullshader;
245     smaablendweightshader = lookupshaderbyname(blendweightname);
246     if(!smaablendweightshader) smaablendweightshader = nullshader;
247     smaaneighborhoodshader = lookupshaderbyname(neighborhoodname);
248     if(!smaaneighborhoodshader) smaaneighborhoodshader = nullshader;
249 }
250 
clearsmaashaders()251 void clearsmaashaders()
252 {
253     smaatype = -1;
254     smaalumaedgeshader = NULL;
255     smaacoloredgeshader = NULL;
256     smaablendweightshader = NULL;
257     smaaneighborhoodshader = NULL;
258 }
259 
260 #define SMAA_SEARCHTEX_WIDTH 66
261 #define SMAA_SEARCHTEX_HEIGHT 33
262 static uchar smaasearchdata[SMAA_SEARCHTEX_WIDTH*SMAA_SEARCHTEX_HEIGHT];
263 static bool smaasearchdatainited = false;
264 
gensmaasearchdata()265 void gensmaasearchdata()
266 {
267     if(smaasearchdatainited) return;
268     int edges[33];
269     memset(edges, -1, sizeof(edges));
270     loop(a, 2) loop(b, 2) loop(c, 2) loop(d, 2) edges[(a*1 + b*3) + (c*7 + d*21)] = a + (b<<1) + (c<<2) + (d<<3);
271     memset(smaasearchdata, 0, sizeof(smaasearchdata));
272     loop(y, 33) loop(x, 33)
273     {
274         int left = edges[x], top = edges[y];
275         if(left < 0 || top < 0) continue;
276         uchar deltaLeft = 0;
277         if(top&(1<<3)) deltaLeft++;
278         if(deltaLeft && top&(1<<2) && !(left&(1<<1)) && !(left&(1<<3))) deltaLeft++;
279         smaasearchdata[y*66 + x] = deltaLeft;
280         uchar deltaRight = 0;
281         if(top&(1<<3) && !(left&(1<<1)) && !(left&(1<<3))) deltaRight++;
282         if(deltaRight && top&(1<<2) && !(left&(1<<0)) && !(left&(1<<2))) deltaRight++;
283         smaasearchdata[y*66 + 33 + x] = deltaRight;
284     }
285     smaasearchdatainited = true;
286 }
287 
areaunderortho(const vec2 & p1,const vec2 & p2,float x)288 vec2 areaunderortho(const vec2 &p1, const vec2 &p2, float x)
289 {
290     vec2 d(p2.x - p1.x, p2.y - p1.y);
291     float y1 = p1.y + (x - p1.x)*d.y/d.x,
292           y2 = p1.y + (x+1 - p1.x)*d.y/d.x;
293     if((x < p1.x || x >= p2.x) && (x+1 <= p1.x || x+1 > p2.x)) return vec2(0, 0);
294     if((y1 < 0) == (y2 < 0) || fabs(y1) < 1e-4f || fabs(y2) < 1e-4f)
295     {
296         float a = (y1 + y2) / 2;
297         return a < 0.0f ? vec2(-a, 0) : vec2(0, a);
298     }
299     x = -p1.y*d.x/d.y + p1.x;
300     float a1 = x > p1.x ? y1*fmod(x, 1.0f)/2 : 0,
301           a2 = x < p2.x ? y2*(1-fmod(x, 1.0f))/2 : 0;
302     vec2 a(fabs(a1), fabs(a2));
303     if((a.x > a.y ? a1 : -a2) >= 0) swap(a.x, a.y);
304     return a;
305 }
306 
307 static const int edgesortho[][2] =
308 {
309     {0, 0}, {3, 0}, {0, 3}, {3, 3}, {1, 0}, {4, 0}, {1, 3}, {4, 3},
310     {0, 1}, {3, 1}, {0, 4}, {3, 4}, {1, 1}, {4, 1}, {1, 4}, {4, 4}
311 };
312 
areaortho(float p1x,float p1y,float p2x,float p2y,float left)313 static inline vec2 areaortho(float p1x, float p1y, float p2x, float p2y, float left)
314 {
315     return areaunderortho(vec2(p1x, p1y), vec2(p2x, p2y), left);
316 }
317 
smootharea(float d,vec2 & a1,vec2 & a2)318 static inline void smootharea(float d, vec2 &a1, vec2 &a2)
319 {
320     vec2 b1(sqrtf(a1.x*2)*0.5f, sqrtf(a1.y*2)*0.5f), b2(sqrtf(a2.x*2)*0.5f, sqrtf(a2.y*2)*0.5f);
321     float p = clamp(d / 32.0f, 0.0f, 1.0f);
322     a1.lerp(b1, a1, p);
323     a2.lerp(b2, a2, p);
324 }
325 
areaortho(int pattern,float left,float right,float offset)326 vec2 areaortho(int pattern, float left, float right, float offset)
327 {
328     float d = left + right + 1, o1 = offset + 0.5f, o2 = offset - 0.5f;
329     switch(pattern)
330     {
331         case 0: return vec2(0, 0);
332         case 1: return left <= right ? areaortho(0, o2, d/2, 0, left) : vec2(0, 0);
333         case 2: return left >= right ? areaortho(d/2, 0, d, o2, left) : vec2(0, 0);
334         case 3:
335         {
336             vec2 a1 = areaortho(0, o2, d/2, 0, left), a2 = areaortho(d/2, 0, d, o2, left);
337             smootharea(d, a1, a2);
338             return a1.add(a2);
339         }
340         case 4: return left <= right ? areaortho(0, o1, d/2, 0, left) : vec2(0, 0);
341         case 5: return vec2(0, 0);
342         case 6:
343         {
344             vec2 a = areaortho(0, o1, d, o2, left);
345             if(fabs(offset) > 0) a.avg(areaortho(0, o1, d/2, 0, left).add(areaortho(d/2, 0, d, o2, left)));
346             return a;
347         }
348         case 7: return areaortho(0, o1, d, o2, left);
349         case 8: return left >= right ? areaortho(d/2, 0, d, o1, left) : vec2(0, 0);
350         case 9:
351         {
352             vec2 a = areaortho(0, o2, d, o1, left);
353             if(fabs(offset) > 0) a.avg(areaortho(0, o2, d/2, 0, left).add(areaortho(d/2, 0, d, o1, left)));
354             return a;
355         }
356         case 10: return vec2(0, 0);
357         case 11: return areaortho(0, o2, d, o1, left);
358         case 12:
359         {
360             vec2 a1 = areaortho(0, o1, d/2, 0, left), a2 = areaortho(d/2, 0, d, o1, left);
361             smootharea(d, a1, a2);
362             return a1.add(a2);
363         }
364         case 13: return areaortho(0, o2, d, o1, left);
365         case 14: return areaortho(0, o1, d, o2, left);
366         case 15: return vec2(0, 0);
367     }
368     return vec2(0, 0);
369 }
370 
areaunderdiag(const vec2 & p1,const vec2 & p2,const vec2 & p)371 float areaunderdiag(const vec2 &p1, const vec2 &p2, const vec2 &p)
372 {
373     vec2 d(p2.y - p1.y, p1.x - p2.x);
374     float dp = d.dot(vec2(p1).sub(p));
375     if(!d.x)
376     {
377         if(!d.y) return 1;
378         return clamp(d.y > 0 ? 1 - dp/d.y : dp/d.y, 0.0f, 1.0f);
379     }
380     if(!d.y) return clamp(d.x > 0 ? 1 - dp/d.x : dp/d.x, 0.0f, 1.0f);
381     float l = dp/d.y, r = (dp-d.x)/d.y, b = dp/d.x, t = (dp-d.y)/d.x;
382     if(0 <= dp)
383     {
384         if(d.y <= dp)
385         {
386             if(d.x <= dp)
387             {
388                 if(d.y+d.x <= dp) return 0;
389                 return 0.5f*(1-r)*(1-t);
390             }
391             if(d.y+d.x > dp) return min(1-b, 1-t) + 0.5f*fabs(b-t);
392             return 0.5f*(1-b)*r;
393         }
394         if(d.x <= dp)
395         {
396             if(d.y+d.x <= dp) return 0.5f*(1-l)*t;
397             return min(1-l, 1-r) + 0.5f*fabs(r-l);
398         }
399         return 1 - 0.5f*l*b;
400     }
401     if(d.y <= dp)
402     {
403         if(d.x <= dp) return 0.5f*l*b;
404         if(d.y+d.x <= dp) return min(l, r) + 0.5f*fabs(r-l);
405         return 1 - 0.5f*(1-l)*t;
406     }
407     if(d.x <= dp)
408     {
409         if(d.y+d.x <= dp) return min(b, t) + 0.5f*fabs(b-t);
410         return 1 - 0.5f*(1-b)*r;
411     }
412     if(d.y+d.x <= dp) return 1 - 0.5f*(1-t)*(1-r);
413     return 1;
414 }
415 
areadiag(const vec2 & p1,const vec2 & p2,float left)416 static inline vec2 areadiag(const vec2 &p1, const vec2 &p2, float left)
417 {
418     return vec2(1 - areaunderdiag(p1, p2, vec2(1, 0).add(left)), areaunderdiag(p1, p2, vec2(1, 1).add(left)));
419 }
420 
421 static const int edgesdiag[][2] =
422 {
423     {0, 0}, {1, 0}, {0, 2}, {1, 2}, {2, 0}, {3, 0}, {2, 2}, {3, 2},
424     {0, 1}, {1, 1}, {0, 3}, {1, 3}, {2, 1}, {3, 1}, {2, 3}, {3, 3}
425 };
426 
areadiag(float p1x,float p1y,float p2x,float p2y,float d,float left,const vec2 & offset,int pattern)427 static inline vec2 areadiag(float p1x, float p1y, float p2x, float p2y, float d, float left, const vec2 &offset, int pattern)
428 {
429     vec2 p1(p1x, p1y), p2(p2x+d, p2y+d);
430     if(edgesdiag[pattern][0]) p1.add(offset);
431     if(edgesdiag[pattern][1]) p2.add(offset);
432     return areadiag(p1, p2, left);
433 }
434 
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)435 static inline 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)
436 {
437     vec2 p1(p1x, p1y), p2(p2x+d, p2y+d), p3(p3x, p3y), p4(p4x+d, p4y+d);
438     if(edgesdiag[pattern][0]) { p1.add(offset); p3.add(offset); }
439     if(edgesdiag[pattern][1]) { p2.add(offset); p4.add(offset); }
440     return areadiag(p1, p2, left).avg(areadiag(p3, p4, left));
441 }
442 
areadiag(int pattern,float left,float right,const vec2 & offset)443 vec2 areadiag(int pattern, float left, float right, const vec2 &offset)
444 {
445     float d = left + right + 1;
446     switch(pattern)
447     {
448         case 0: return areadiag2(1, 1, 1, 1, 1, 0, 1, 0, d, left, offset, pattern);
449         case 1: return areadiag2(1, 0, 0, 0, 1, 0, 1, 0, d, left, offset, pattern);
450         case 2: return areadiag2(0, 0, 1, 0, 1, 0, 1, 0, d, left, offset, pattern);
451         case 3: return areadiag(1, 0, 1, 0, d, left, offset, pattern);
452         case 4: return areadiag2(1, 1, 0, 0, 1, 1, 1, 0, d, left, offset, pattern);
453         case 5: return areadiag2(1, 1, 0, 0, 1, 0, 1, 0, d, left, offset, pattern);
454         case 6: return areadiag(1, 1, 1, 0, d, left, offset, pattern);
455         case 7: return areadiag2(1, 1, 1, 0, 1, 0, 1, 0, d, left, offset, pattern);
456         case 8: return areadiag2(0, 0, 1, 1, 1, 0, 1, 1, d, left, offset, pattern);
457         case 9: return areadiag(1, 0, 1, 1, d, left, offset, pattern);
458         case 10: return areadiag2(0, 0, 1, 1, 1, 0, 1, 0, d, left, offset, pattern);
459         case 11: return areadiag2(1, 0, 1, 1, 1, 0, 1, 0, d, left, offset, pattern);
460         case 12: return areadiag(1, 1, 1, 1, d, left, offset, pattern);
461         case 13: return areadiag2(1, 1, 1, 1, 1, 0, 1, 1, d, left, offset, pattern);
462         case 14: return areadiag2(1, 1, 1, 1, 1, 1, 1, 0, d, left, offset, pattern);
463         case 15: return areadiag2(1, 1, 1, 1, 1, 0, 1, 0, d, left, offset, pattern);
464     }
465     return vec2(0, 0);
466 }
467 
468 static const float offsetsortho[] = { 0.0f, -0.25f, 0.25f, -0.125f, 0.125f, -0.375f, 0.375f };
469 static const float offsetsdiag[][2] = { { 0.0f, 0.0f, }, { 0.25f, -0.25f }, { -0.25f, 0.25f }, { 0.125f, -0.125f }, { -0.125f, 0.125f } };
470 
471 #define SMAA_AREATEX_WIDTH 160
472 #define SMAA_AREATEX_HEIGHT 560
473 static uchar smaaareadata[SMAA_AREATEX_WIDTH*SMAA_AREATEX_HEIGHT*2];
474 static bool smaaareadatainited = false;
475 
gensmaaareadata()476 void gensmaaareadata()
477 {
478     if(smaaareadatainited) return;
479     memset(smaaareadata, 0, sizeof(smaaareadata));
480     loop(offset, sizeof(offsetsortho)/sizeof(offsetsortho[0])) loop(pattern, 16)
481     {
482         int px = edgesortho[pattern][0]*16, py = (5*offset + edgesortho[pattern][1])*16;
483         uchar *dst = &smaaareadata[(py*SMAA_AREATEX_WIDTH + px)*2];
484         loop(y, 16)
485         {
486             loop(x, 16)
487             {
488                 vec2 a = areaortho(pattern, x*x, y*y, offsetsortho[offset]);
489                 dst[0] = uchar(255*a.x);
490                 dst[1] = uchar(255*a.y);
491                 dst += 2;
492             }
493             dst += (SMAA_AREATEX_WIDTH-16)*2;
494         }
495     }
496     loop(offset, sizeof(offsetsdiag)/sizeof(offsetsdiag[0])) loop(pattern, 16)
497     {
498         int px = 5*16 + edgesdiag[pattern][0]*20, py = (4*offset + edgesdiag[pattern][1])*20;
499         uchar *dst = &smaaareadata[(py*SMAA_AREATEX_WIDTH + px)*2];
500         loop(y, 20)
501         {
502             loop(x, 20)
503             {
504                 vec2 a = areadiag(pattern, x, y, vec2(offsetsdiag[offset][0], offsetsdiag[offset][1]));
505                 dst[0] = uchar(255*a.x);
506                 dst[1] = uchar(255*a.y);
507                 dst += 2;
508             }
509             dst += (SMAA_AREATEX_WIDTH-20)*2;
510         }
511     }
512     smaaareadatainited = true;
513 }
514 
515 VAR(smaat2x, 1, 0, 0);
516 VAR(smaas2x, 1, 0, 0);
517 VAR(smaa4x, 1, 0, 0);
518 
setupsmaa(int w,int h)519 void setupsmaa(int w, int h)
520 {
521     if(!smaaareatex) glGenTextures(1, &smaaareatex);
522     if(!smaasearchtex) glGenTextures(1, &smaasearchtex);
523     gensmaasearchdata();
524     gensmaaareadata();
525     createtexture(smaaareatex, SMAA_AREATEX_WIDTH, SMAA_AREATEX_HEIGHT, smaaareadata, 3, 1, hasTRG ? GL_RG8 : GL_LUMINANCE8_ALPHA8, GL_TEXTURE_RECTANGLE, 0, 0, 0, false);
526     createtexture(smaasearchtex, SMAA_SEARCHTEX_WIDTH, SMAA_SEARCHTEX_HEIGHT, smaasearchdata, 3, 0, hasTRG ? GL_R8 : GL_LUMINANCE8, GL_TEXTURE_RECTANGLE, 0, 0, 0, false);
527     bool split = multisampledaa();
528     smaasubsampleorder = split ? (msaapositions[0].x < 0.5f ? 1 : 0) : -1;
529     smaat2x = tqaa ? 1 : 0;
530     smaas2x = split ? 1 : 0;
531     smaa4x = tqaa && split ? 1 : 0;
532     loopi(split ? 4 : 3)
533     {
534         if(!smaatex[i]) glGenTextures(1, &smaatex[i]);
535         if(!smaafbo[i]) glGenFramebuffers_(1, &smaafbo[i]);
536         glBindFramebuffer_(GL_FRAMEBUFFER, smaafbo[i]);
537         GLenum format = GL_RGB;
538         switch(i)
539         {
540             case 0: format = tqaa || (!smaagreenluma && !smaacoloredge) ? GL_RGBA8 : GL_RGB; break;
541             case 1: format = hasTRG ? GL_RG8 : GL_RGBA8; break;
542             case 2: case 3: format = GL_RGBA8; break;
543         }
544         createtexture(smaatex[i], w, h, NULL, 3, 1, format, GL_TEXTURE_RECTANGLE);
545         glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, smaatex[i], 0);
546         if(!i && split)
547         {
548             if(!smaatex[4]) glGenTextures(1, &smaatex[4]);
549             createtexture(smaatex[4], w, h, NULL, 3, 1, format, GL_TEXTURE_RECTANGLE);
550             glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_RECTANGLE, smaatex[4], 0);
551             static const GLenum drawbufs[2] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
552             glDrawBuffers_(2, drawbufs);
553         }
554         if(!i || smaadepthmask || smaastencil) bindgdepth();
555         if(glCheckFramebufferStatus_(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
556             fatal("failed allocating SMAA buffer!");
557     }
558     glBindFramebuffer_(GL_FRAMEBUFFER, 0);
559 
560     loadsmaashaders(split);
561 }
562 
cleanupsmaa()563 void cleanupsmaa()
564 {
565     if(smaaareatex) { glDeleteTextures(1, &smaaareatex); smaaareatex = 0; }
566     if(smaasearchtex) { glDeleteTextures(1, &smaasearchtex); smaasearchtex = 0; }
567     loopi(4) if(smaafbo[i]) { glDeleteFramebuffers_(1, &smaafbo[i]); smaafbo[i] = 0; }
568     loopi(5) if(smaatex[i]) { glDeleteTextures(1, &smaatex[i]); smaatex[i] = 0; }
569     smaasubsampleorder = -1;
570     smaat2x = smaas2x = smaa4x = 0;
571 
572     clearsmaashaders();
573 }
574 
575 VARFP(smaa, 0, 0, 1, cleanupgbuffer());
576 VARFP(smaaspatial, 0, 1, 1, cleanupgbuffer());
577 VARFP(smaaquality, 0, 2, 3, cleanupsmaa());
578 VARFP(smaacoloredge, 0, 0, 1, cleanupsmaa());
579 VARFP(smaagreenluma, 0, 0, 1, cleanupsmaa());
580 VARF(smaadepthmask, 0, 1, 1, cleanupsmaa());
581 VARF(smaastencil, 0, 1, 1, cleanupsmaa());
582 VAR(debugsmaa, 0, 0, 5);
583 
viewsmaa()584 void viewsmaa()
585 {
586     int w = min(hudw, hudh)*1.0f, h = (w*hudh)/hudw, tw = gw, th = gh;
587     SETSHADER(hudrect);
588     gle::colorf(1, 1, 1);
589     switch(debugsmaa)
590     {
591         case 1: glBindTexture(GL_TEXTURE_RECTANGLE, smaatex[0]); break;
592         case 2: glBindTexture(GL_TEXTURE_RECTANGLE, smaatex[1]); break;
593         case 3: glBindTexture(GL_TEXTURE_RECTANGLE, smaatex[2]); break;
594         case 4: glBindTexture(GL_TEXTURE_RECTANGLE, smaaareatex); tw = SMAA_AREATEX_WIDTH; th = SMAA_AREATEX_HEIGHT; break;
595         case 5: glBindTexture(GL_TEXTURE_RECTANGLE, smaasearchtex); tw = SMAA_SEARCHTEX_WIDTH; th = SMAA_SEARCHTEX_HEIGHT; break;
596     }
597     debugquad(0, 0, w, h, 0, 0, tw, th);
598 }
599 
dosmaa(GLuint outfbo=0,bool split=false)600 void dosmaa(GLuint outfbo = 0, bool split = false)
601 {
602     timer *smaatimer = begintimer("smaa");
603 
604     tqaaview &tv = tqaaviews[viewidx];
605 
606     int cleardepth = msaasamples ? GL_DEPTH_BUFFER_BIT | (ghasstencil > 1 ? GL_STENCIL_BUFFER_BIT : 0) : 0;
607     bool stencil = smaastencil && ghasstencil > (msaasamples ? 1 : 0);
608     loop(pass, split ? 2 : 1)
609     {
610         glBindFramebuffer_(GL_FRAMEBUFFER, smaafbo[1]);
611         if(smaadepthmask || stencil)
612         {
613             glClearColor(0, 0, 0, 0);
614             glClear(GL_COLOR_BUFFER_BIT | (!pass ? cleardepth : 0));
615         }
616         if(smaadepthmask)
617         {
618             glEnable(GL_DEPTH_TEST);
619             glDepthFunc(GL_ALWAYS);
620             float depthval = cleardepth ? 0.25f*(pass+1) : 1;
621             glDepthRange(depthval, depthval);
622         }
623         else if(stencil)
624         {
625             glEnable(GL_STENCIL_TEST);
626             glStencilFunc(GL_ALWAYS, 0x10*(pass+1), ~0);
627             glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
628         }
629         if(smaacoloredge) smaacoloredgeshader->set();
630         else smaalumaedgeshader->set();
631         glBindTexture(GL_TEXTURE_RECTANGLE, smaatex[pass ? 4 : 0]);
632         screenquad(vieww, viewh);
633 
634         glBindFramebuffer_(GL_FRAMEBUFFER, smaafbo[2 + pass]);
635         if(smaadepthmask)
636         {
637             glDepthFunc(GL_EQUAL);
638             glDepthMask(GL_FALSE);
639         }
640         else if(stencil)
641         {
642             glStencilFunc(GL_EQUAL, 0x10*(pass+1), ~0);
643             glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
644         }
645         if(smaadepthmask || stencil) glClear(GL_COLOR_BUFFER_BIT);
646         smaablendweightshader->set();
647         vec4 subsamples(0, 0, 0, 0);
648         if(tqaa && split) subsamples = tv.frame&1 ? (pass != smaasubsampleorder ? vec4(6, 4, 2, 4) : vec4(3, 5, 1, 4)) : (pass != smaasubsampleorder ? vec4(4, 6, 2, 3) : vec4(5, 3, 1, 3));
649         else if(tqaa) subsamples = tv.frame&1 ? vec4(2, 2, 2, 0) : vec4(1, 1, 1, 0);
650         else if(split) subsamples = pass != smaasubsampleorder ? vec4(2, 2, 2, 0) : vec4(1, 1, 1, 0);
651         LOCALPARAM(subsamples, subsamples);
652         glBindTexture(GL_TEXTURE_RECTANGLE, smaatex[1]);
653         glActiveTexture_(GL_TEXTURE1);
654         glBindTexture(GL_TEXTURE_RECTANGLE, smaaareatex);
655         glActiveTexture_(GL_TEXTURE2);
656         glBindTexture(GL_TEXTURE_RECTANGLE, smaasearchtex);
657         glActiveTexture_(GL_TEXTURE0);
658         screenquad(vieww, viewh);
659         if(smaadepthmask)
660         {
661             glDisable(GL_DEPTH_TEST);
662             glDepthMask(GL_TRUE);
663             glDepthFunc(GL_LESS);
664             glDepthRange(0, 1);
665         }
666         else if(stencil) glDisable(GL_STENCIL_TEST);
667     }
668 
669     glBindFramebuffer_(GL_FRAMEBUFFER, tqaa ? tv.fbo[0] : outfbo);
670     smaaneighborhoodshader->set();
671     glBindTexture(GL_TEXTURE_RECTANGLE, smaatex[0]);
672     glActiveTexture_(GL_TEXTURE1);
673     glBindTexture(GL_TEXTURE_RECTANGLE, smaatex[2]);
674     if(split)
675     {
676         glActiveTexture_(GL_TEXTURE2);
677         glBindTexture(GL_TEXTURE_RECTANGLE, smaatex[4]);
678         glActiveTexture_(GL_TEXTURE3);
679         glBindTexture(GL_TEXTURE_RECTANGLE, smaatex[3]);
680     }
681     glActiveTexture_(GL_TEXTURE0);
682     screenquad(vieww, viewh);
683 
684     if(tqaa) tv.resolve(outfbo);
685 
686     endtimer(smaatimer);
687 }
688 
setupaa(int w,int h)689 void setupaa(int w, int h)
690 {
691     if(tqaa && !tqaaviews[0].fbo[0]) setuptqaa(w, h);
692 
693     if(smaa) { if(!smaafbo[0]) setupsmaa(w, h); }
694     else if(fxaa) { if(!fxaafbo) setupfxaa(w, h); }
695 }
696 
697 matrix4 nojittermatrix;
698 
jitteraa()699 void jitteraa()
700 {
701     nojittermatrix = projmatrix;
702 
703     if(!drawtex && tqaa)
704     {
705         tqaaview &tv = tqaaviews[viewidx];
706         vec2 jitter = tv.frame&1 ? vec2(0.25f, 0.25f) : vec2(-0.25f, -0.25f);
707         if(multisampledaa()) { jitter.x *= 0.5f; jitter.y *= -0.5f; }
708         projmatrix.jitter(jitter.x*2.0f/vieww, jitter.y*2.0f/viewh);
709     }
710 }
711 
712 int aamaskstencil = -1, aamask = -1;
713 
setaamask(bool on)714 void setaamask(bool on)
715 {
716     int val = on && !drawtex ? 1 : 0;
717     if(aamask == val) return;
718 
719     if(!aamaskstencil)
720     {
721         glStencilOp(GL_KEEP, GL_KEEP, val ? GL_REPLACE : GL_KEEP);
722         if(aamask < 0)
723         {
724             glStencilFunc(GL_ALWAYS, 0x80, ~0);
725             glEnable(GL_STENCIL_TEST);
726         }
727     }
728     else if(aamaskstencil > 0)
729     {
730         if(val) glStencilFunc(GL_ALWAYS, 0x80 | aamaskstencil, ~0);
731         else if(aamask >= 0) glStencilFunc(GL_ALWAYS, aamaskstencil, ~0);
732     }
733 
734     aamask = val;
735 
736     GLOBALPARAMF(aamask, aamask);
737 }
738 
enableaamask(int stencil)739 void enableaamask(int stencil)
740 {
741     aamask = -1;
742     aamaskstencil = !msaasamples && ghasstencil && tqaa && tqaamovemask && !drawtex ? stencil|avatarmask : -1;
743 }
744 
disableaamask()745 void disableaamask()
746 {
747     if(aamaskstencil >= 0 && aamask >= 0)
748     {
749         if(!aamaskstencil) glDisable(GL_STENCIL_TEST);
750         else if(aamask) glStencilFunc(GL_ALWAYS, aamaskstencil, ~0);
751         aamask = -1;
752     }
753 }
754 
multisampledaa()755 bool multisampledaa()
756 {
757     return smaa && smaaspatial && msaasamples == 2;
758 }
759 
maskedaa()760 bool maskedaa()
761 {
762     return tqaa && tqaamovemask;
763 }
764 
doaa(GLuint outfbo,void (* resolve)(GLuint,int))765 void doaa(GLuint outfbo, void (*resolve)(GLuint, int))
766 {
767     if(smaa)
768     {
769         bool split = multisampledaa();
770         resolve(smaafbo[0], smaatype);
771         dosmaa(outfbo, split);
772     }
773     else if(fxaa) { resolve(fxaafbo, fxaatype); dofxaa(outfbo); }
774     else if(tqaa) { tqaaview &tv = tqaaviews[viewidx]; resolve(tv.fbo[0], tqaatype); dotqaa(tv, outfbo); }
775     else resolve(outfbo, AA_UNUSED);
776 }
777 
debugaa()778 bool debugaa()
779 {
780     if(debugsmaa) viewsmaa();
781     else return false;
782     return true;
783 }
784 
cleanupaa()785 void cleanupaa()
786 {
787     cleanupsmaa();
788     cleanupfxaa();
789     cleanuptqaa();
790 }
791 
792