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: 2026-05-09 04:28:55 Functions: 12.3 % 57 7

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

Generated by: LCOV version 2.0-1