LCOV - code coverage report
Current view: top level - engine/render - renderalpha.cpp (source / functions) Coverage Total Hit
Test: Libprimis Test Coverage Lines: 0.0 % 201 0
Test Date: 2025-08-24 05:32:49 Functions: 0.0 % 2 0

            Line data    Source code
       1              : /**
       2              :  * @brief alpha geoemtry rendering
       3              :  *
       4              :  * Libprimis has support for a single level of alpha geometry, which is rendered
       5              :  * using a single stencil layer over the base geometry
       6              :  *
       7              :  * Combinations of alpha materials (glass, alpha, water) therefore do not stack
       8              :  * since there is only one stencil and only the nearest layer in the view frustum
       9              :  * is rendered
      10              :  *
      11              :  * All of the methods and variables in this file are part of the GBuffer object.
      12              :  * See renderlights.h for the declaration of this object.
      13              :  *
      14              :  */
      15              : #include "../libprimis-headers/cube.h"
      16              : #include "../../shared/geomexts.h"
      17              : #include "../../shared/glexts.h"
      18              : 
      19              : #include "hdr.h"
      20              : #include "rendergl.h"
      21              : #include "renderlights.h"
      22              : #include "rendermodel.h"
      23              : #include "renderparticles.h"
      24              : #include "rendertimers.h"
      25              : #include "renderva.h"
      26              : #include "shader.h"
      27              : #include "shaderparam.h"
      28              : #include "stain.h"
      29              : #include "texture.h"
      30              : 
      31              : #include "world/material.h"
      32              : #include "world/octaedit.h"
      33              : 
      34              : FVAR(GBuffer::refractmargin, 0, 0.1f, 1);     //margin for gl scissoring around refractive materials
      35              : FVAR(GBuffer::refractdepth, 1e-3f, 16, 1e3f); //sets depth for refract shader effect
      36              : 
      37              : //sets up alpha handling as needed then executes main particle rendering routine
      38              : //private method of gbuffer
      39            0 : void GBuffer::alphaparticles(float allsx1, float allsy1, float allsx2, float allsy2) const
      40              : {
      41            0 :     if(particlelayers && ghasstencil)
      42              :     {
      43            0 :         bool scissor = allsx1 > -1 || allsy1 > -1 || allsx2 < 1 || allsy2 < 1;
      44            0 :         if(scissor)
      45              :         {
      46            0 :             int x1 = static_cast<int>(std::floor((allsx1*0.5f+0.5f)*static_cast<float>(vieww))),
      47            0 :                 y1 = static_cast<int>(std::floor((allsy1*0.5f+0.5f)*static_cast<float>(viewh))),
      48            0 :                 x2 = static_cast<int>(std::ceil((allsx2*0.5f+0.5f)*static_cast<float>(vieww))),
      49            0 :                 y2 = static_cast<int>(std::ceil((allsy2*0.5f+0.5f)*static_cast<float>(viewh)));
      50            0 :             glEnable(GL_SCISSOR_TEST);
      51            0 :             glScissor(x1, y1, x2 - x1, y2 - y1);
      52              :         }
      53            0 :         glStencilFunc(GL_NOTEQUAL, 0, 0x07);
      54            0 :         glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
      55            0 :         glEnable(GL_STENCIL_TEST);
      56            0 :         renderparticles(ParticleLayer_Over);
      57            0 :         glDisable(GL_STENCIL_TEST);
      58            0 :         if(scissor)
      59              :         {
      60            0 :             glDisable(GL_SCISSOR_TEST);
      61              :         }
      62            0 :         renderparticles(ParticleLayer_NoLayer);
      63            0 :     }
      64              :     else
      65              :     {
      66            0 :         renderparticles();
      67              :     }
      68            0 : }
      69              : 
      70              : //externally relevant functionality
      71              : 
      72            0 : void GBuffer::rendertransparent()
      73              : {
      74            0 :     const MaterialInfo &mi = findmaterials(); //generate mat* vars
      75            0 :     const AlphaInfo &ai = findalphavas(); //generate mat* vars
      76            0 :     int hasalphavas = ai.hasalphavas;
      77            0 :     int hasmats = mi.hasmats;
      78            0 :     bool hasmodels = tmodelinfo.mdlsx1 < tmodelinfo.mdlsx2 && tmodelinfo.mdlsy1 < tmodelinfo.mdlsy2;
      79            0 :     if(!hasalphavas && !hasmats && !hasmodels) //don't transparent render if there is no alpha
      80              :     {
      81            0 :         if(!editmode)
      82              :         {
      83            0 :             renderparticles();
      84              :         }
      85            0 :         return;
      86              :     }
      87            0 :     if(!editmode && particlelayers && ghasstencil)
      88              :     {
      89            0 :         renderparticles(ParticleLayer_Under);
      90              :     }
      91            0 :     timer *transtimer = begintimer("transparent");
      92            0 :     if(hasalphavas&4 || hasmats&4)
      93              :     {
      94            0 :         glBindFramebuffer(GL_FRAMEBUFFER, msaalight ? msrefractfbo : refractfbo);
      95            0 :         glDepthMask(GL_FALSE);
      96            0 :         if(msaalight)
      97              :         {
      98            0 :             glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msdepthtex);
      99              :         }
     100              :         else
     101              :         {
     102            0 :             glBindTexture(GL_TEXTURE_RECTANGLE, gdepthtex);
     103              :         }
     104            0 :         float sx1 = std::min(ai.alpharefractsx1, mi.matrefractsx1),
     105            0 :               sy1 = std::min(ai.alpharefractsy1, mi.matrefractsy1),
     106            0 :               sx2 = std::max(ai.alpharefractsx2, mi.matrefractsx2),
     107            0 :               sy2 = std::max(ai.alpharefractsy2, mi.matrefractsy2);
     108            0 :         bool scissor = sx1 > -1 || sy1 > -1 || sx2 < 1 || sy2 < 1;
     109            0 :         if(scissor)
     110              :         {
     111            0 :             int x1 = static_cast<int>(std::floor(std::max(sx1*0.5f+0.5f-refractmargin*static_cast<float>(viewh)/static_cast<float>(vieww), 0.0f)*static_cast<float>(vieww))),
     112            0 :                 y1 = static_cast<int>(std::floor(std::max(sy1*0.5f+0.5f-refractmargin, 0.0f)*static_cast<float>(viewh))),
     113            0 :                 x2 = static_cast<int>(std::ceil(std::min(sx2*0.5f+0.5f+refractmargin*static_cast<float>(viewh)/static_cast<float>(vieww), 1.0f)*static_cast<float>(vieww))),
     114            0 :                 y2 = static_cast<int>(std::ceil(std::min(sy2*0.5f+0.5f+refractmargin, 1.0f)*static_cast<float>(viewh)));
     115            0 :             glEnable(GL_SCISSOR_TEST);
     116            0 :             glScissor(x1, y1, x2 - x1, y2 - y1);
     117              :         }
     118            0 :         glClearColor(0, 0, 0, 0);
     119            0 :         glClear(GL_COLOR_BUFFER_BIT);
     120            0 :         if(scissor)
     121              :         {
     122            0 :             glDisable(GL_SCISSOR_TEST);
     123              :         }
     124            0 :         GLOBALPARAMF(refractdepth, 1.0f/refractdepth);
     125            0 :         SETSHADER(refractmask);
     126            0 :         if(hasalphavas&4)
     127              :         {
     128            0 :             renderrefractmask();
     129              :         }
     130            0 :         if(hasmats&4)
     131              :         {
     132            0 :             rendermaterialmask();
     133              :         }
     134            0 :         glDepthMask(GL_TRUE);
     135              :     }
     136              : 
     137            0 :     glActiveTexture(GL_TEXTURE7);
     138            0 :     if(msaalight)
     139              :     {
     140            0 :         glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msrefracttex);
     141              :     }
     142              :     else
     143              :     {
     144            0 :         glBindTexture(GL_TEXTURE_RECTANGLE, refracttex);
     145              :     }
     146            0 :     glActiveTexture(GL_TEXTURE8);
     147            0 :     if(msaalight)
     148              :     {
     149            0 :         glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mshdrtex);
     150              :     }
     151              :     else
     152              :     {
     153            0 :         glBindTexture(GL_TEXTURE_RECTANGLE, hdrtex);
     154              :     }
     155            0 :     glActiveTexture(GL_TEXTURE9);
     156            0 :     if(msaalight)
     157              :     {
     158            0 :         glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msdepthtex);
     159              :     }
     160              :     else
     161              :     {
     162            0 :         glBindTexture(GL_TEXTURE_RECTANGLE, gdepthtex);
     163              :     }
     164            0 :     glActiveTexture(GL_TEXTURE0);
     165            0 :     if(ghasstencil)
     166              :     {
     167            0 :         glEnable(GL_STENCIL_TEST);
     168              :     }
     169            0 :     matrix4 raymatrix(vec(-0.5f*static_cast<float>(vieww)*projmatrix.a.x, 0, 0.5f*static_cast<float>(vieww) - 0.5f*static_cast<float>(vieww)*projmatrix.c.x),
     170            0 :                       vec(0, -0.5f*static_cast<float>(viewh)*projmatrix.b.y, 0.5f*static_cast<float>(viewh) - 0.5f*static_cast<float>(viewh)*projmatrix.c.y));
     171            0 :     raymatrix.muld(cammatrix);
     172            0 :     GLOBALPARAM(raymatrix, raymatrix);
     173            0 :     GLOBALPARAM(linearworldmatrix, linearworldmatrix);
     174              : 
     175              :     std::array<uint, lighttilemaxheight> tiles;
     176            0 :     float allsx1 =  1,
     177            0 :           allsy1 =  1,
     178            0 :           allsx2 = -1,
     179            0 :           allsy2 = -1;
     180              :     float sx1, sy1, sx2, sy2;
     181              : 
     182            0 :     for(int layer = 0; layer < 4; ++layer)
     183              :     {
     184            0 :         switch(layer)
     185              :         {
     186            0 :             case 0:
     187              :             {
     188            0 :                 if(!(hasmats&1))
     189              :                 {
     190            0 :                     continue;
     191              :                 }
     192            0 :                 sx1 = mi.matliquidsx1;
     193            0 :                 sy1 = mi.matliquidsy1;
     194            0 :                 sx2 = mi.matliquidsx2;
     195            0 :                 sy2 = mi.matliquidsy2;
     196            0 :                 std::memcpy(tiles.data(), mi.matliquidtiles, sizeof(tiles));
     197            0 :                 break;
     198              :             }
     199            0 :             case 1:
     200              :             {
     201            0 :                 if(!(hasalphavas&1))
     202              :                 {
     203            0 :                     continue;
     204              :                 }
     205            0 :                 sx1 = ai.alphabacksx1;
     206            0 :                 sy1 = ai.alphabacksy1;
     207            0 :                 sx2 = ai.alphabacksx2;
     208            0 :                 sy2 = ai.alphabacksy2;
     209            0 :                 std::memcpy(tiles.data(), alphatiles, tiles.size()*sizeof(uint));
     210            0 :                 break;
     211              :             }
     212            0 :             case 2:
     213              :             {
     214            0 :                 if(!(hasalphavas&2) && !(hasmats&2))
     215              :                 {
     216            0 :                     continue;
     217              :                 }
     218            0 :                 sx1 = ai.alphafrontsx1;
     219            0 :                 sy1 = ai.alphafrontsy1;
     220            0 :                 sx2 = ai.alphafrontsx2;
     221            0 :                 sy2 = ai.alphafrontsy2;
     222            0 :                 std::memcpy(tiles.data(), alphatiles, tiles.size()*sizeof(uint));
     223            0 :                 if(hasmats&2)
     224              :                 {
     225            0 :                     sx1 = std::min(sx1, mi.matsolidsx1);
     226            0 :                     sy1 = std::min(sy1, mi.matsolidsy1);
     227            0 :                     sx2 = std::max(sx2, mi.matsolidsx2);
     228            0 :                     sy2 = std::max(sy2, mi.matsolidsy2);
     229            0 :                     for(int j = 0; j < lighttilemaxheight; ++j)
     230              :                     {
     231            0 :                         tiles[j] |= mi.matsolidtiles[j];
     232              :                     }
     233              :                 }
     234            0 :                 break;
     235              :             }
     236            0 :             case 3:
     237              :             {
     238            0 :                 if(!hasmodels)
     239              :                 {
     240            0 :                     continue;
     241              :                 }
     242            0 :                 sx1 = tmodelinfo.mdlsx1;
     243            0 :                 sy1 = tmodelinfo.mdlsy1;
     244            0 :                 sx2 = tmodelinfo.mdlsx2;
     245            0 :                 sy2 = tmodelinfo.mdlsy2;
     246            0 :                 std::memcpy(tiles.data(), tmodelinfo.mdltiles.data(), tiles.size()*sizeof(uint));
     247            0 :                 break;
     248              :             }
     249            0 :             default:
     250              :             {
     251            0 :                 continue;
     252              :             }
     253            0 :         }
     254            0 :         transparentlayer = layer+1;
     255            0 :         allsx1 = std::min(allsx1, sx1);
     256            0 :         allsy1 = std::min(allsy1, sy1);
     257            0 :         allsx2 = std::max(allsx2, sx2);
     258            0 :         allsy2 = std::max(allsy2, sy2);
     259              : 
     260            0 :         glBindFramebuffer(GL_FRAMEBUFFER, msaalight ? msfbo : gfbo);
     261            0 :         if(ghasstencil)
     262              :         {
     263            0 :             glStencilFunc(GL_ALWAYS, layer+1, ~0);
     264            0 :             glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
     265              :         }
     266              :         else
     267              :         {
     268            0 :             bool scissor = sx1 > -1 || sy1 > -1 || sx2 < 1 || sy2 < 1;
     269            0 :             if(scissor)
     270              :             {
     271            0 :                 int x1 = static_cast<int>(std::floor((sx1*0.5f+0.5f)*static_cast<float>(vieww))),
     272            0 :                     y1 = static_cast<int>(std::floor((sy1*0.5f+0.5f)*static_cast<float>(viewh))),
     273            0 :                     x2 = static_cast<int>(std::ceil((sx2*0.5f+0.5f)*static_cast<float>(vieww))),
     274            0 :                     y2 = static_cast<int>(std::ceil((sy2*0.5f+0.5f)*static_cast<float>(viewh)));
     275            0 :                 glEnable(GL_SCISSOR_TEST);
     276            0 :                 glScissor(x1, y1, x2 - x1, y2 - y1);
     277              :             }
     278              : 
     279            0 :             maskgbuffer("n");
     280            0 :             glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
     281            0 :             glClearColor(0, 0, 0, 0);
     282            0 :             glClear(GL_COLOR_BUFFER_BIT);
     283            0 :             glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
     284            0 :             if(scissor)
     285              :             {
     286            0 :                 glDisable(GL_SCISSOR_TEST);
     287              :             }
     288              :         }
     289            0 :         maskgbuffer("cndg");
     290              : 
     291            0 :         if(wireframe && editmode)
     292              :         {
     293            0 :             glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
     294              :         }
     295              : 
     296            0 :         switch(layer)
     297              :         {
     298            0 :             case 0:
     299              :             {
     300            0 :                 renderliquidmaterials();
     301            0 :                 break;
     302              :             }
     303            0 :             case 1:
     304              :             {
     305            0 :                 renderalphageom(1);
     306            0 :                 break;
     307              :             }
     308            0 :             case 2:
     309              :             {
     310            0 :                 if(hasalphavas&2)
     311              :                 {
     312            0 :                     renderalphageom(2);
     313              :                 }
     314            0 :                 if(hasmats&2)
     315              :                 {
     316            0 :                     rendersolidmaterials();
     317              :                 }
     318            0 :                 renderstains(StainBuffer_Transparent, true, layer+1);
     319            0 :                 break;
     320              :             }
     321            0 :             case 3:
     322              :             {
     323            0 :                 batching::rendertransparentmodelbatches(layer+1);
     324            0 :                 break;
     325              :             }
     326              :         }
     327              : 
     328            0 :         if(wireframe && editmode)
     329              :         {
     330            0 :             glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
     331              :         }
     332              : 
     333            0 :         if(msaalight)
     334              :         {
     335            0 :             glBindFramebuffer(GL_FRAMEBUFFER, mshdrfbo);
     336            0 :             if((ghasstencil && msaaedgedetect) || msaalight==2)
     337              :             {
     338            0 :                 for(int i = 0; i < 2; ++i)
     339              :                 {
     340            0 :                     renderlights(sx1, sy1, sx2, sy2, tiles.data(), layer+1, i+1, true);
     341              :                 }
     342            0 :             }
     343              :             else
     344              :             {
     345            0 :                 renderlights(sx1, sy1, sx2, sy2, tiles.data(), layer+1, 3, true);
     346              :             }
     347              :         }
     348              :         else
     349              :         {
     350            0 :             glBindFramebuffer(GL_FRAMEBUFFER, hdrfbo);
     351            0 :             renderlights(sx1, sy1, sx2, sy2, tiles.data(), layer+1, 0, true);
     352              :         }
     353              : 
     354            0 :         switch(layer)
     355              :         {
     356            0 :             case 2:
     357              :             {
     358            0 :                 renderstains(StainBuffer_Transparent, false, layer+1);
     359            0 :                 break;
     360              :             }
     361              :         }
     362              :     }
     363              : 
     364            0 :     transparentlayer = 0;
     365              : 
     366            0 :     if(ghasstencil)
     367              :     {
     368            0 :         glDisable(GL_STENCIL_TEST);
     369              :     }
     370              : 
     371            0 :     endtimer(transtimer);
     372              : 
     373            0 :     if(editmode)
     374              :     {
     375            0 :         return;
     376              :     }
     377            0 :     alphaparticles(allsx1, allsy1, allsx2, allsy2);
     378              : }
        

Generated by: LCOV version 2.0-1