LCOV - code coverage report
Current view: top level - engine/render - aa.cpp (source / functions) Coverage Total Hit
Test: Libprimis Test Coverage Lines: 2.8 % 702 20
Test Date: 2025-06-27 04:34:40 Functions: 12.3 % 57 7

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

Generated by: LCOV version 2.0-1