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

Generated by: LCOV version 2.0-1