LCOV - code coverage report
Current view: top level - engine/render - postfx.cpp (source / functions) Hit Total Coverage
Test: Libprimis Test Coverage Lines: 41 147 27.9 %
Date: 2024-11-22 05:07:59 Functions: 9 17 52.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 1.14