LCOV - code coverage report
Current view: top level - engine/render - postfx.cpp (source / functions) Coverage Total Hit
Test: Libprimis Test Coverage Lines: 27.9 % 147 41
Test Date: 2026-08-20 06:51:03 Functions: 52.9 % 17 9

            Line data    Source code
       1              : /**
       2              :  * @file postfx.cpp
       3              :  * @brief screenspace shader post effects
       4              :  */
       5              : #include "../libprimis-headers/cube.h"
       6              : 
       7              : #include "rendergl.h"
       8              : #include "renderlights.h"
       9              : #include "rendertimers.h"
      10              : #include "shader.h"
      11              : #include "shaderparam.h"
      12              : #include "texture.h"
      13              : 
      14              : #include "interface/console.h"
      15              : 
      16              : class PostFx final
      17              : {
      18              :     public:
      19            2 :         void cleanuppostfx(bool fullclean)
      20              :         {
      21            2 :             if(fullclean && postfxfb)
      22              :             {
      23            0 :                 glDeleteFramebuffers(1, &postfxfb);
      24            0 :                 postfxfb = 0;
      25              :             }
      26            2 :             for(const postfxtex &i : postfxtexs)
      27              :             {
      28            0 :                 glDeleteTextures(1, &i.id);
      29              :             }
      30            2 :             postfxtexs.clear();
      31            2 :             postfxw = 0;
      32            2 :             postfxh = 0;
      33            2 :         }
      34              : 
      35            2 :         void clearpostfx()
      36              :         {
      37            2 :             postfxpasses.clear();
      38            2 :             cleanuppostfx(false);
      39            2 :         }
      40              : 
      41            1 :         void addpostfx(const char *name, const int *bind, const int *scale, const char *inputs, const float &x, const float &y, const float &z, const float &w)
      42              :         {
      43            1 :             int inputmask = inputs[0] ? 0 : 1,
      44            1 :                 freemask = inputs[0] ? 0 : 1;
      45            1 :             bool freeinputs = true;
      46            1 :             for(; *inputs; inputs++)
      47              :             {
      48            0 :                 if(isdigit(*inputs))
      49              :                 {
      50            0 :                     inputmask |= 1<<(*inputs-'0');
      51            0 :                     if(freeinputs)
      52              :                     {
      53            0 :                         freemask |= 1<<(*inputs-'0');
      54              :                     }
      55              :                 }
      56            0 :                 else if(*inputs=='+')
      57              :                 {
      58            0 :                     freeinputs = false;
      59              :                 }
      60            0 :                 else if(*inputs=='-')
      61              :                 {
      62            0 :                     freeinputs = true;
      63              :                 }
      64              :             }
      65            1 :             inputmask &= (1<<numpostfxbinds)-1;
      66            1 :             freemask &= (1<<numpostfxbinds)-1;
      67            1 :             addpostfx(name, std::clamp(*bind, 0, numpostfxbinds-1), std::max(*scale, 0), inputmask, freemask, vec4<float>(x, y, z, w));
      68            1 :         }
      69              : 
      70            1 :         void setpostfx(const char *name, const float &x, const float &y, const float &z, const float &w)
      71              :         {
      72            1 :             clearpostfx();
      73            1 :             if(name[0])
      74              :             {
      75            0 :                 addpostfx(name, 0, 0, 1, 1, vec4<float>(x, y, z, w));
      76              :             }
      77            1 :         } //add a postfx shader to the class field, with name & 4d pos vector
      78              : 
      79            0 :         GLuint setuppostfx(const GBuffer &buf, int w, int h, GLuint outfbo)
      80              :         {
      81            0 :             if(postfxpasses.empty())
      82              :             {
      83            0 :                 return outfbo;
      84              :             }
      85            0 :             if(postfxw != w || postfxh != h)
      86              :             {
      87            0 :                 cleanuppostfx(false);
      88            0 :                 postfxw = w;
      89            0 :                 postfxh = h;
      90              :             }
      91            0 :             for(int i = 0; i < numpostfxbinds; ++i)
      92              :             {
      93            0 :                 postfxbinds[i] = -1;
      94              :             }
      95            0 :             for(postfxtex &i : postfxtexs)
      96              :             {
      97            0 :                 i.used = -1;
      98              :             }
      99            0 :             if(!postfxfb)
     100              :             {
     101            0 :                 glGenFramebuffers(1, &postfxfb);
     102              :             }
     103            0 :             glBindFramebuffer(GL_FRAMEBUFFER, postfxfb);
     104            0 :             int tex = allocatepostfxtex(0);
     105            0 :             glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, postfxtexs[tex].id, 0);
     106            0 :             buf.bindgdepth();
     107              : 
     108            0 :             postfxbinds[0] = tex;
     109            0 :             postfxtexs[tex].used = 0;
     110              : 
     111            0 :             return postfxfb;
     112              :         }
     113              : 
     114            0 :         void renderpostfx(GLuint outfbo)
     115              :         {
     116            0 :             if(postfxpasses.empty())
     117              :             {
     118            0 :                 return;
     119              :             }
     120            0 :             timer *postfxtimer = begintimer("postfx");
     121            0 :             for(size_t i = 0; i < postfxpasses.size(); i++)
     122              :             {
     123            0 :                 PostFxPass &p = postfxpasses[i];
     124              : 
     125            0 :                 int tex = -1;
     126            0 :                 if(!(postfxpasses.size() < i+1))
     127              :                 {
     128            0 :                     glBindFramebuffer(GL_FRAMEBUFFER, outfbo);
     129              :                 }
     130              :                 else
     131              :                 {
     132            0 :                     tex = allocatepostfxtex(p.outputscale);
     133            0 :                     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, postfxtexs[tex].id, 0);
     134              :                 }
     135            0 :                 const int w = tex >= 0 ? std::max(postfxw>>postfxtexs[tex].scale, 1) : postfxw,
     136            0 :                           h = tex >= 0 ? std::max(postfxh>>postfxtexs[tex].scale, 1) : postfxh;
     137            0 :                 glViewport(0, 0, w, h);
     138            0 :                 p.shader->set();
     139            0 :                 LOCALPARAM(params, p.params);
     140            0 :                 int tw = w,
     141            0 :                     th = h,
     142            0 :                     tmu = 0;
     143            0 :                 for(int j = 0; j < numpostfxbinds; ++j)
     144              :                 {
     145            0 :                     if(p.inputs&(1<<j) && postfxbinds[j] >= 0)
     146              :                     {
     147            0 :                         if(!tmu)
     148              :                         {
     149            0 :                             tw = std::max(postfxw>>postfxtexs[postfxbinds[j]].scale, 1);
     150            0 :                             th = std::max(postfxh>>postfxtexs[postfxbinds[j]].scale, 1);
     151              :                         }
     152              :                         else
     153              :                         {
     154            0 :                             glActiveTexture(GL_TEXTURE0 + tmu);
     155              :                         }
     156            0 :                         glBindTexture(GL_TEXTURE_RECTANGLE, postfxtexs[postfxbinds[j]].id);
     157            0 :                         ++tmu;
     158              :                     }
     159              :                 }
     160            0 :                 if(tmu)
     161              :                 {
     162            0 :                     glActiveTexture(GL_TEXTURE0);
     163              :                 }
     164            0 :                 screenquad(tw, th);
     165            0 :                 for(int j = 0; j < numpostfxbinds; ++j)
     166              :                 {
     167            0 :                     if(p.freeinputs&(1<<j) && postfxbinds[j] >= 0)
     168              :                     {
     169            0 :                         postfxtexs[postfxbinds[j]].used = -1;
     170            0 :                         postfxbinds[j] = -1;
     171              :                     }
     172              :                 }
     173            0 :                 if(tex >= 0)
     174              :                 {
     175            0 :                     if(postfxbinds[p.outputbind] >= 0)
     176              :                     {
     177            0 :                         postfxtexs[postfxbinds[p.outputbind]].used = -1;
     178              :                     }
     179            0 :                     postfxbinds[p.outputbind] = tex;
     180            0 :                     postfxtexs[tex].used = p.outputbind;
     181              :                 }
     182              :             }
     183            0 :             endtimer(postfxtimer);
     184              :         }
     185              : 
     186              :     private:
     187              :         static constexpr int numpostfxbinds = 10;
     188              : 
     189            0 :         int allocatepostfxtex(int scale)
     190              :         {
     191            0 :             for(size_t i = 0; i < postfxtexs.size(); i++)
     192              :             {
     193            0 :                 const postfxtex &t = postfxtexs[i];
     194            0 :                 if(t.scale==scale && t.used < 0)
     195              :                 {
     196            0 :                     return i;
     197              :                 }
     198              :             }
     199            0 :             postfxtex t;
     200            0 :             t.scale = scale;
     201            0 :             glGenTextures(1, &t.id);
     202            0 :             createtexture(t.id, std::max(postfxw>>scale, 1), std::max(postfxh>>scale, 1), nullptr, 3, 1, GL_RGB, GL_TEXTURE_RECTANGLE);
     203            0 :             postfxtexs.push_back(t);
     204            0 :             return postfxtexs.size()-1;
     205              :         }
     206              : 
     207              :         //adds to the global postfxpasses vector a postfx by the given name
     208            1 :         bool addpostfx(const char *name, int outputbind, int outputscale, uint inputs, uint freeinputs, const vec4<float> &params)
     209              :         {
     210            1 :             if(!*name)
     211              :             {
     212            1 :                 return false;
     213              :             }
     214            0 :             Shader *s = useshaderbyname(name);
     215            0 :             if(!s)
     216              :             {
     217            0 :                 conoutf(Console_Error, "no such postfx shader: %s", name);
     218            0 :                 return false;
     219              :             }
     220            0 :             PostFxPass p;
     221            0 :             p.shader = s;
     222            0 :             p.outputbind = outputbind;
     223            0 :             p.outputscale = outputscale;
     224            0 :             p.inputs = inputs;
     225            0 :             p.freeinputs = freeinputs;
     226            0 :             p.params = params;
     227            0 :             postfxpasses.push_back(p);
     228            0 :             return true;
     229              :         }
     230              : 
     231              :         struct postfxtex final
     232              :         {
     233              :             GLuint id;
     234              :             int scale, used;
     235            0 :             postfxtex() : id(0), scale(0), used(-1) {}
     236              :         };
     237              :         std::vector<postfxtex> postfxtexs;
     238              :         std::array<int, numpostfxbinds> postfxbinds;
     239              :         GLuint postfxfb = 0;
     240              :         int postfxw = 0,
     241              :             postfxh = 0;
     242              :         struct PostFxPass final
     243              :         {
     244              :             Shader *shader;
     245              :             vec4<float> params;
     246              :             uint inputs, freeinputs;
     247              :             int outputbind, outputscale;
     248              : 
     249            0 :             PostFxPass() : shader(nullptr), inputs(1), freeinputs(1), outputbind(0), outputscale(0) {}
     250              :         };
     251              :         std::vector<PostFxPass> postfxpasses;
     252              : };
     253              : 
     254              : namespace
     255              : {
     256              :     PostFx pfx;
     257              : 
     258            1 :     void addpostfxcmd(const char *name, const int *bind, const int *scale, const char *inputs, const float *x, const float *y, const float *z, const float *w)
     259              :     {
     260            1 :         pfx.addpostfx(name, bind, scale, inputs, *x, *y, *z, *w);
     261            1 :     }
     262              : 
     263            1 :     void clearpostfx()
     264              :     {
     265            1 :         pfx.clearpostfx();
     266            1 :     }
     267              : 
     268            1 :     void setpostfx(const char *name, const float *x, const float *y, const float *z, const float *w)
     269              :     {
     270            1 :         pfx.setpostfx(name, *x, *y, *z, *w);
     271            1 :     }
     272              : }
     273              : 
     274              : //extern functions
     275              : 
     276            0 : GLuint setuppostfx(const GBuffer &buf, int w, int h, GLuint outfbo)
     277              : {
     278            0 :     return pfx.setuppostfx(buf, w, h, outfbo);
     279              : }
     280              : 
     281            0 : void renderpostfx(GLuint outfbo)
     282              : {
     283            0 :     pfx.renderpostfx(outfbo);
     284            0 : }
     285              : 
     286            0 : void cleanuppostfx(bool fullclean)
     287              : {
     288            0 :     pfx.cleanuppostfx(fullclean);
     289            0 : }
     290              : 
     291            1 : void initpostfxcmds()
     292              : {
     293            1 :     addcommand("clearpostfx", reinterpret_cast<identfun>(clearpostfx), "", Id_Command);
     294            1 :     addcommand("addpostfx", reinterpret_cast<identfun>(addpostfxcmd), "siisffff", Id_Command);
     295            1 :     addcommand("setpostfx", reinterpret_cast<identfun>(setpostfx), "sffff", Id_Command);
     296            1 : }
        

Generated by: LCOV version 2.0-1