LCOV - code coverage report
Current view: top level - engine/render - aa.cpp (source / functions) Hit Total Coverage
Test: Libprimis Test Coverage Lines: 20 706 2.8 %
Date: 2024-11-22 05:07:59 Functions: 7 58 12.1 %

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

Generated by: LCOV version 1.14