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: 2025-02-18 06:21:28 Functions: 52.9 % 17 9

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

Generated by: LCOV version 2.0-1