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

Generated by: LCOV version 2.0-1