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: 2026-06-16 06:16:16 Functions: 0.0 % 2 0

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

Generated by: LCOV version 2.0-1