diff --git a/src.cmake b/src.cmake index daf96a588f..7fc6d7c758 100644 --- a/src.cmake +++ b/src.cmake @@ -102,6 +102,10 @@ set(RENDERERLIST ${ENGINE_DIR}/renderer/tr_font.cpp ${ENGINE_DIR}/renderer/InternalImage.cpp ${ENGINE_DIR}/renderer/InternalImage.h + ${ENGINE_DIR}/renderer/Material.cpp + ${ENGINE_DIR}/renderer/Material.h + ${ENGINE_DIR}/renderer/TextureManager.cpp + ${ENGINE_DIR}/renderer/TextureManager.h ${ENGINE_DIR}/renderer/tr_image.cpp ${ENGINE_DIR}/renderer/tr_image.h ${ENGINE_DIR}/renderer/tr_image_crn.cpp @@ -141,6 +145,8 @@ set(RENDERERLIST ) set(GLSLSOURCELIST + ${ENGINE_DIR}/renderer/glsl_source/material_vp.glsl + ${ENGINE_DIR}/renderer/glsl_source/material_fp.glsl ${ENGINE_DIR}/renderer/glsl_source/skybox_vp.glsl ${ENGINE_DIR}/renderer/glsl_source/ssao_fp.glsl ${ENGINE_DIR}/renderer/glsl_source/ssao_vp.glsl diff --git a/src/engine/renderer/Material.cpp b/src/engine/renderer/Material.cpp new file mode 100644 index 0000000000..2c199f6a89 --- /dev/null +++ b/src/engine/renderer/Material.cpp @@ -0,0 +1,1897 @@ +/* +=========================================================================== + +Daemon BSD Source Code +Copyright (c) 2024 Daemon Developers +All rights reserved. + +This file is part of the Daemon BSD Source Code (Daemon Source Code). + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Daemon developers nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL DAEMON DEVELOPERS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=========================================================================== +*/ +// Material.cpp + +#include "Material.h" + +#include "tr_local.h" + +GLSSBO materialsSSBO( "materials", 0 ); +GLIndirectBuffer commandBuffer( "drawCommands" ); +MaterialSystem materialSystem; + +static void ComputeDynamics( shaderStage_t* pStage ) { + // TODO: Move color and texMatrices stuff to a compute shader + switch ( pStage->rgbGen ) { + case colorGen_t::CGEN_IDENTITY: + case colorGen_t::CGEN_ONE_MINUS_VERTEX: + default: + case colorGen_t::CGEN_IDENTITY_LIGHTING: + /* Historically CGEN_IDENTITY_LIGHTING was done this way: + + tess.svars.color = Color::White * tr.identityLight; + + But tr.identityLight is always 1.0f in Dæmon engine + as the as the overbright bit implementation is fully + software. */ + case colorGen_t::CGEN_VERTEX: + case colorGen_t::CGEN_CONST: + case colorGen_t::CGEN_ENTITY: + case colorGen_t::CGEN_ONE_MINUS_ENTITY: + { + // TODO: Move this to some entity buffer once this is extended past BSP surfaces + if ( backEnd.currentEntity ) { + // + } else { + // + } + pStage->colorDynamic = false; + + break; + } + + case colorGen_t::CGEN_WAVEFORM: + case colorGen_t::CGEN_CUSTOM_RGB: + case colorGen_t::CGEN_CUSTOM_RGBs: + { + pStage->colorDynamic = true; + break; + } + } + + switch ( pStage->alphaGen ) { + default: + case alphaGen_t::AGEN_IDENTITY: + case alphaGen_t::AGEN_ONE_MINUS_VERTEX: + case alphaGen_t::AGEN_VERTEX: + case alphaGen_t::AGEN_CONST: { + case alphaGen_t::AGEN_ENTITY: + case alphaGen_t::AGEN_ONE_MINUS_ENTITY: + // TODO: Move this to some entity buffer once this is extended past BSP surfaces + /* if ( backEnd.currentEntity ) { + } else { + } */ + pStage->colorDynamic = false; + break; + } + + case alphaGen_t::AGEN_WAVEFORM: + case alphaGen_t::AGEN_CUSTOM: + { + pStage->colorDynamic = true; + break; + } + } + + for ( textureBundle_t& bundle : pStage->bundle ) { + for ( size_t i = 0; i < bundle.numTexMods; i++ ) { + switch ( bundle.texMods[i].type ) { + case texMod_t::TMOD_NONE: + case texMod_t::TMOD_SCALE: + case texMod_t::TMOD_TRANSFORM: + break; + + case texMod_t::TMOD_TURBULENT: + case texMod_t::TMOD_ENTITY_TRANSLATE: + case texMod_t::TMOD_SCROLL: + { + pStage->texMatricesDynamic = true; + break; + } + + case texMod_t::TMOD_STRETCH: + { + if( bundle.texMods->wave.func != genFunc_t::GF_NONE ) { + pStage->texMatricesDynamic = true; + } + break; + } + + case texMod_t::TMOD_ROTATE: + { + pStage->texMatricesDynamic = true; + break; + } + + case texMod_t::TMOD_SCROLL2: + case texMod_t::TMOD_SCALE2: + case texMod_t::TMOD_CENTERSCALE: + case texMod_t::TMOD_SHEAR: + { + if ( bundle.texMods[i].sExp.active || bundle.texMods[i].tExp.active ) { + pStage->texMatricesDynamic = true; + } + break; + } + + case texMod_t::TMOD_ROTATE2: + { + if( bundle.texMods[i].rExp.active ) { + pStage->texMatricesDynamic = true; + } + break; + } + + default: + break; + } + } + } + + // TODO: Move this to a different buffer? + for ( const textureBundle_t& bundle : pStage->bundle ) { + if ( bundle.isVideoMap || bundle.numImages > 1 ) { + pStage->texturesDynamic = true; + break; + } + } + + // Can we move this to a compute shader too? + // Doesn't seem to be used much if at all, so probably not worth the effort to do that + pStage->dynamic = pStage->dynamic || pStage->ifExp.active; + pStage->dynamic = pStage->dynamic || pStage->alphaExp.active || pStage->alphaTestExp.active; + pStage->dynamic = pStage->dynamic || pStage->rgbExp.active || pStage->redExp.active || pStage->greenExp.active || pStage->blueExp.active; + pStage->dynamic = pStage->dynamic || pStage->deformMagnitudeExp.active; + pStage->dynamic = pStage->dynamic || pStage->depthScaleExp.active || pStage->etaExp.active || pStage->etaDeltaExp.active + || pStage->fogDensityExp.active || pStage->fresnelBiasExp.active || pStage->fresnelPowerExp.active + || pStage->fresnelScaleExp.active || pStage->normalIntensityExp.active || pStage->refractionIndexExp.active; + + pStage->dynamic = pStage->dynamic || pStage->colorDynamic || pStage->texMatricesDynamic || pStage->texturesDynamic; +} + +static image_t* GetLightMap( drawSurf_t* drawSurf ) { + if ( static_cast( drawSurf->lightmapNum() ) < tr.lightmaps.size() ) { + return tr.lightmaps[drawSurf->lightmapNum()]; + } else { + return tr.whiteImage; + } +} + +static image_t* GetDeluxeMap( drawSurf_t* drawSurf ) { + if ( static_cast( drawSurf->lightmapNum() ) < tr.deluxemaps.size() ) { + return tr.deluxemaps[drawSurf->lightmapNum()]; + } else { + return tr.blackImage; + } +} + +// UpdateSurface*() functions will actually write the uniform values to the SSBO +// Mirrors parts of the Render_*() functions in tr_shade.cpp + +static void UpdateSurfaceDataGeneric( uint32_t* materials, Material& material, drawSurf_t* drawSurf, const uint32_t stage ) { + shader_t* shader = drawSurf->shader; + shaderStage_t* pStage = &shader->stages[stage]; + + const uint32_t paddedOffset = drawSurf->materialsSSBOOffset[stage] * material.shader->GetPaddedSize(); + materials += paddedOffset; + + bool updated = !drawSurf->initialized[stage] || pStage->colorDynamic || pStage->texMatricesDynamic || pStage->dynamic; + if ( !updated ) { + return; + } + drawSurf->initialized[stage] = true; + + gl_genericShaderMaterial->BindProgram( material.deformIndex ); + + gl_genericShaderMaterial->SetUniform_ModelMatrix( backEnd.orientation.transformMatrix ); + gl_genericShaderMaterial->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[glState.stackIndex] ); + + // u_AlphaThreshold + gl_genericShaderMaterial->SetUniform_AlphaTest( pStage->stateBits ); + + // u_InverseLightFactor + // We should cancel overbrightBits if there is no light, + // and it's not using blendFunc dst_color. + bool blendFunc_dstColor = ( pStage->stateBits & GLS_SRCBLEND_BITS ) == GLS_SRCBLEND_DST_COLOR; + float inverseLightFactor = ( pStage->shaderHasNoLight && !blendFunc_dstColor ) ? tr.mapInverseLightFactor : 1.0f; + gl_genericShaderMaterial->SetUniform_InverseLightFactor( inverseLightFactor ); + + // u_ColorModulate + colorGen_t rgbGen; + alphaGen_t alphaGen; + SetRgbaGen( pStage, &rgbGen, &alphaGen ); + gl_genericShaderMaterial->SetUniform_ColorModulate( rgbGen, alphaGen ); + + Tess_ComputeColor( pStage ); + gl_genericShaderMaterial->SetUniform_Color( tess.svars.color ); + + Tess_ComputeTexMatrices( pStage ); + gl_genericShaderMaterial->SetUniform_TextureMatrix( tess.svars.texMatrices[TB_COLORMAP] ); + + // u_DeformGen + gl_genericShaderMaterial->SetUniform_Time( backEnd.refdef.floatTime - backEnd.currentEntity->e.shaderTime ); + + // bind u_ColorMap= + if ( pStage->type == stageType_t::ST_STYLELIGHTMAP ) { + gl_genericShaderMaterial->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, GetLightMap( drawSurf ) ) + ); + } else { + gl_genericShaderMaterial->SetUniform_ColorMapBindless( BindAnimatedImage( 0, &pStage->bundle[TB_COLORMAP] ) ); + } + + bool needDepthMap = pStage->hasDepthFade || shader->autoSpriteMode; + if ( needDepthMap ) { + gl_genericShaderMaterial->SetUniform_DepthMapBindless( GL_BindToTMU( 1, tr.currentDepthImage ) ); + } + + bool hasDepthFade = pStage->hasDepthFade && !shader->autoSpriteMode; + if ( hasDepthFade ) { + gl_genericShaderMaterial->SetUniform_DepthScale( pStage->depthFadeValue ); + } + + gl_genericShaderMaterial->SetUniform_VertexInterpolation( false ); + + gl_genericShaderMaterial->WriteUniformsToBuffer( materials ); +} + +static void UpdateSurfaceDataLightMapping( uint32_t* materials, Material& material, drawSurf_t* drawSurf, const uint32_t stage ) { + shader_t* shader = drawSurf->shader; + shaderStage_t* pStage = &shader->stages[stage]; + + const uint32_t paddedOffset = drawSurf->materialsSSBOOffset[stage] * material.shader->GetPaddedSize(); + materials += paddedOffset; + + bool updated = !drawSurf->initialized[stage] || pStage->colorDynamic || pStage->texMatricesDynamic || pStage->dynamic; + if ( !updated ) { + return; + } + drawSurf->initialized[stage] = true; + + gl_lightMappingShaderMaterial->BindProgram( material.deformIndex ); + + gl_lightMappingShaderMaterial->SetUniform_ModelMatrix( backEnd.orientation.transformMatrix ); + + lightMode_t lightMode = lightMode_t::FULLBRIGHT; + deluxeMode_t deluxeMode = deluxeMode_t::NONE; + + /* TODO: investigate what this is. It's probably a hack to detect some + specific use case. Without knowing which use case this takes care about, + any change in the following code may break it. Or it may be a hack we + should drop if it is for a bug we don't have anymore. */ + bool hack = shader->lastStage != shader->stages + && shader->stages[0].rgbGen == colorGen_t::CGEN_VERTEX; + + if ( ( shader->surfaceFlags & SURF_NOLIGHTMAP ) && !hack ) { + // Use fullbright on “surfaceparm nolightmap” materials. + } else if ( pStage->type == stageType_t::ST_COLLAPSE_COLORMAP ) { + /* Use fullbright for collapsed stages without lightmaps, + for example: + + { + map textures/texture_d + heightMap textures/texture_h + } + + This is doable for some complex multi-stage materials. */ + } else if ( drawSurf->bspSurface ) { + lightMode = tr.worldLight; + deluxeMode = tr.worldDeluxe; + + if ( lightMode == lightMode_t::MAP ) { + bool hasLightMap = static_cast( drawSurf->lightmapNum() ) < tr.lightmaps.size(); + + if ( !hasLightMap ) { + lightMode = lightMode_t::VERTEX; + deluxeMode = deluxeMode_t::NONE; + } + } + } else { + lightMode = tr.modelLight; + deluxeMode = tr.modelDeluxe; + } + + // u_Map, u_DeluxeMap + image_t* lightmap = tr.whiteImage; + image_t* deluxemap = tr.whiteImage; + + // u_ColorModulate + colorGen_t rgbGen; + alphaGen_t alphaGen; + SetRgbaGen( pStage, &rgbGen, &alphaGen ); + + switch ( lightMode ) { + case lightMode_t::VERTEX: + // Do not rewrite pStage->rgbGen. + rgbGen = colorGen_t::CGEN_VERTEX; + tess.svars.color.SetRed( 0.0f ); + tess.svars.color.SetGreen( 0.0f ); + tess.svars.color.SetBlue( 0.0f ); + break; + + case lightMode_t::GRID: + // Store lightGrid1 as lightmap, + // the GLSL code will know how to deal with it. + lightmap = tr.lightGrid1Image; + break; + + case lightMode_t::MAP: + lightmap = GetLightMap( drawSurf ); + + break; + + default: + break; + } + + switch ( deluxeMode ) { + case deluxeMode_t::MAP: + // Deluxe mapping for world surface. + deluxemap = GetDeluxeMap( drawSurf ); + break; + + case deluxeMode_t::GRID: + // Deluxe mapping emulation from grid light for game models. + // Store lightGrid2 as deluxemap, + // the GLSL code will know how to deal with it. + deluxemap = tr.lightGrid2Image; + break; + + default: + break; + } + + bool enableGridLighting = ( lightMode == lightMode_t::GRID ); + bool enableGridDeluxeMapping = ( deluxeMode == deluxeMode_t::GRID ); + + // TODO: Update this when this is extended to MDV support + gl_lightMappingShaderMaterial->SetUniform_VertexInterpolation( false ); + + if ( glConfig2.dynamicLight ) { + gl_lightMappingShaderMaterial->SetUniformBlock_Lights( tr.dlightUBO ); + + // bind u_LightTiles + if ( r_dynamicLightRenderer.Get() == Util::ordinal( dynamicLightRenderer_t::TILED ) ) { + gl_lightMappingShaderMaterial->SetUniform_LightTilesIntBindless( + GL_BindToTMU( BIND_LIGHTTILES, tr.lighttileRenderImage ) + ); + } + } + + // u_DeformGen + gl_lightMappingShaderMaterial->SetUniform_Time( backEnd.refdef.floatTime - backEnd.currentEntity->e.shaderTime ); + + // u_InverseLightFactor + /* HACK: use sign to know if there is a light or not, and + then if it will receive overbright multiplication or not. */ + bool blendFunc_dstColor = ( pStage->stateBits & GLS_SRCBLEND_BITS ) == GLS_SRCBLEND_DST_COLOR; + bool noLight = pStage->shaderHasNoLight || lightMode == lightMode_t::FULLBRIGHT; + float inverseLightFactor = ( noLight && !blendFunc_dstColor ) ? tr.mapInverseLightFactor : -tr.mapInverseLightFactor; + gl_lightMappingShaderMaterial->SetUniform_InverseLightFactor( inverseLightFactor ); + + // u_ColorModulate + gl_lightMappingShaderMaterial->SetUniform_ColorModulate( rgbGen, alphaGen ); + + // u_Color + Tess_ComputeColor( pStage ); + gl_lightMappingShaderMaterial->SetUniform_Color( tess.svars.color ); + + // u_AlphaThreshold + gl_lightMappingShaderMaterial->SetUniform_AlphaTest( pStage->stateBits ); + + // bind u_HeightMap + if ( pStage->enableReliefMapping ) { + float depthScale = RB_EvalExpression( &pStage->depthScaleExp, r_reliefDepthScale->value ); + depthScale *= shader->reliefDepthScale; + + gl_lightMappingShaderMaterial->SetUniform_ReliefDepthScale( depthScale ); + gl_lightMappingShaderMaterial->SetUniform_ReliefOffsetBias( shader->reliefOffsetBias ); + + // FIXME: if there is both, embedded heightmap in normalmap is used instead of standalone heightmap + if ( !pStage->hasHeightMapInNormalMap ) { + gl_lightMappingShaderMaterial->SetUniform_HeightMapBindless( + GL_BindToTMU( BIND_HEIGHTMAP, pStage->bundle[TB_HEIGHTMAP].image[0] ) + ); + } + } + + // bind u_DiffuseMap + gl_lightMappingShaderMaterial->SetUniform_DiffuseMapBindless( + GL_BindToTMU( BIND_DIFFUSEMAP, pStage->bundle[TB_DIFFUSEMAP].image[0] ) + ); + + if ( pStage->type != stageType_t::ST_LIGHTMAP ) { + Tess_ComputeTexMatrices( pStage ); + gl_lightMappingShaderMaterial->SetUniform_TextureMatrix( tess.svars.texMatrices[TB_DIFFUSEMAP] ); + } + + // bind u_NormalMap + if ( !!r_normalMapping->integer || pStage->hasHeightMapInNormalMap ) { + gl_lightMappingShaderMaterial->SetUniform_NormalMapBindless( + GL_BindToTMU( BIND_NORMALMAP, pStage->bundle[TB_NORMALMAP].image[0] ) + ); + } + + // bind u_NormalScale + if ( pStage->enableNormalMapping ) { + vec3_t normalScale; + SetNormalScale( pStage, normalScale ); + + gl_lightMappingShaderMaterial->SetUniform_NormalScale( normalScale ); + } + + // bind u_MaterialMap + if ( pStage->enableSpecularMapping || pStage->enablePhysicalMapping ) { + gl_lightMappingShaderMaterial->SetUniform_MaterialMapBindless( + GL_BindToTMU( BIND_MATERIALMAP, pStage->bundle[TB_MATERIALMAP].image[0] ) + ); + } + + if ( pStage->enableSpecularMapping ) { + float specExpMin = RB_EvalExpression( &pStage->specularExponentMin, r_specularExponentMin->value ); + float specExpMax = RB_EvalExpression( &pStage->specularExponentMax, r_specularExponentMax->value ); + + gl_lightMappingShaderMaterial->SetUniform_SpecularExponent( specExpMin, specExpMax ); + } + + // TODO: Move this to a per-entity buffer + // specular reflection + if ( tr.cubeHashTable != nullptr ) { + cubemapProbe_t* cubeProbeNearest; + cubemapProbe_t* cubeProbeSecondNearest; + + image_t* cubeMap0 = nullptr; + image_t* cubeMap1 = nullptr; + + float interpolation = 0.0; + + bool isWorldEntity = backEnd.currentEntity == &tr.worldEntity; + + if ( backEnd.currentEntity && !isWorldEntity ) { + R_FindTwoNearestCubeMaps( backEnd.currentEntity->e.origin, &cubeProbeNearest, &cubeProbeSecondNearest ); + } else { + // FIXME position + R_FindTwoNearestCubeMaps( backEnd.viewParms.orientation.origin, &cubeProbeNearest, &cubeProbeSecondNearest ); + } + + if ( cubeProbeNearest == nullptr && cubeProbeSecondNearest == nullptr ) { + GLimp_LogComment( "cubeProbeNearest && cubeProbeSecondNearest == NULL\n" ); + + cubeMap0 = tr.whiteCubeImage; + cubeMap1 = tr.whiteCubeImage; + } else if ( cubeProbeNearest == nullptr ) { + GLimp_LogComment( "cubeProbeNearest == NULL\n" ); + + cubeMap0 = cubeProbeSecondNearest->cubemap; + } else if ( cubeProbeSecondNearest == nullptr ) { + GLimp_LogComment( "cubeProbeSecondNearest == NULL\n" ); + + cubeMap0 = cubeProbeNearest->cubemap; + } else { + float cubeProbeNearestDistance, cubeProbeSecondNearestDistance; + + if ( backEnd.currentEntity && !isWorldEntity ) { + cubeProbeNearestDistance = Distance( backEnd.currentEntity->e.origin, cubeProbeNearest->origin ); + cubeProbeSecondNearestDistance = Distance( backEnd.currentEntity->e.origin, cubeProbeSecondNearest->origin ); + } else { + // FIXME position + cubeProbeNearestDistance = Distance( backEnd.viewParms.orientation.origin, cubeProbeNearest->origin ); + cubeProbeSecondNearestDistance = Distance( backEnd.viewParms.orientation.origin, cubeProbeSecondNearest->origin ); + } + + interpolation = cubeProbeNearestDistance / ( cubeProbeNearestDistance + cubeProbeSecondNearestDistance ); + + if ( r_logFile->integer ) { + GLimp_LogComment( va( "cubeProbeNearestDistance = %f, cubeProbeSecondNearestDistance = %f, interpolation = %f\n", + cubeProbeNearestDistance, cubeProbeSecondNearestDistance, interpolation ) ); + } + + cubeMap0 = cubeProbeNearest->cubemap; + cubeMap1 = cubeProbeSecondNearest->cubemap; + } + + /* TODO: Check why it is required to test for this, why + cubeProbeNearest->cubemap and cubeProbeSecondNearest->cubemap + can be nullptr while cubeProbeNearest and cubeProbeSecondNearest + are not. Maybe this is only required while cubemaps are building. */ + if ( cubeMap0 == nullptr ) { + cubeMap0 = tr.whiteCubeImage; + } + + if ( cubeMap1 == nullptr ) { + cubeMap1 = tr.whiteCubeImage; + } + + // bind u_EnvironmentMap0 + gl_lightMappingShaderMaterial->SetUniform_EnvironmentMap0Bindless( + GL_BindToTMU( BIND_ENVIRONMENTMAP0, cubeMap0 ) + ); + + // bind u_EnvironmentMap1 + gl_lightMappingShaderMaterial->SetUniform_EnvironmentMap1Bindless( + GL_BindToTMU( BIND_ENVIRONMENTMAP1, cubeMap1 ) + ); + + // bind u_EnvironmentInterpolation + gl_lightMappingShaderMaterial->SetUniform_EnvironmentInterpolation( interpolation ); + + updated = true; + } + + // bind u_LightMap + if ( !enableGridLighting ) { + gl_lightMappingShaderMaterial->SetUniform_LightMapBindless( + GL_BindToTMU( BIND_LIGHTMAP, lightmap ) + ); + } else { + gl_lightMappingShaderMaterial->SetUniform_LightGrid1Bindless( GL_BindToTMU( BIND_LIGHTMAP, lightmap ) ); + } + + // bind u_DeluxeMap + if ( !enableGridDeluxeMapping ) { + gl_lightMappingShaderMaterial->SetUniform_DeluxeMapBindless( + GL_BindToTMU( BIND_DELUXEMAP, deluxemap ) + ); + } else { + gl_lightMappingShaderMaterial->SetUniform_LightGrid2Bindless( GL_BindToTMU( BIND_DELUXEMAP, deluxemap ) ); + } + + // bind u_GlowMap + if ( !!r_glowMapping->integer ) { + gl_lightMappingShaderMaterial->SetUniform_GlowMapBindless( + GL_BindToTMU( BIND_GLOWMAP, pStage->bundle[TB_GLOWMAP].image[0] ) + ); + } + + gl_lightMappingShaderMaterial->WriteUniformsToBuffer( materials ); +} + +static void UpdateSurfaceDataReflection( uint32_t* materials, Material& material, drawSurf_t* drawSurf, const uint32_t stage ) { + shader_t* shader = drawSurf->shader; + shaderStage_t* pStage = &shader->stages[stage]; + + const uint32_t paddedOffset = drawSurf->materialsSSBOOffset[stage] * material.shader->GetPaddedSize(); + materials += paddedOffset; + + bool updated = !drawSurf->initialized[stage] || pStage->colorDynamic || pStage->texMatricesDynamic || pStage->dynamic; + if ( !updated ) { + return; + } + drawSurf->initialized[stage] = true; + + gl_reflectionShaderMaterial->SetUniform_VertexInterpolation( false ); + + // bind u_NormalMap + gl_reflectionShaderMaterial->SetUniform_NormalMapBindless( + GL_BindToTMU( 1, pStage->bundle[TB_NORMALMAP].image[0] ) + ); + + // bind u_ColorMap + if ( backEnd.currentEntity && ( backEnd.currentEntity != &tr.worldEntity ) ) { + GL_BindNearestCubeMap( gl_reflectionShaderMaterial->GetUniformLocation_ColorMap(), backEnd.currentEntity->e.origin ); + } else { + GL_BindNearestCubeMap( gl_reflectionShaderMaterial->GetUniformLocation_ColorMap(), backEnd.viewParms.orientation.origin ); + } + + if ( pStage->enableNormalMapping ) { + vec3_t normalScale; + SetNormalScale( pStage, normalScale ); + + gl_reflectionShaderMaterial->SetUniform_NormalScale( normalScale ); + } + + // bind u_HeightMap u_depthScale u_reliefOffsetBias + if ( pStage->enableReliefMapping ) { + float depthScale = RB_EvalExpression( &pStage->depthScaleExp, r_reliefDepthScale->value ); + float reliefDepthScale = shader->reliefDepthScale; + depthScale *= reliefDepthScale == 0 ? 1 : reliefDepthScale; + gl_reflectionShaderMaterial->SetUniform_ReliefDepthScale( depthScale ); + gl_reflectionShaderMaterial->SetUniform_ReliefOffsetBias( shader->reliefOffsetBias ); + + // FIXME: if there is both, embedded heightmap in normalmap is used instead of standalone heightmap + if ( !pStage->hasHeightMapInNormalMap ) { + gl_reflectionShaderMaterial->SetUniform_HeightMapBindless( + GL_BindToTMU( 15, pStage->bundle[TB_HEIGHTMAP].image[0] ) + ); + } + } + + gl_reflectionShaderMaterial->WriteUniformsToBuffer( materials ); +} + +static void UpdateSurfaceDataSkybox( uint32_t* materials, Material& material, drawSurf_t* drawSurf, const uint32_t stage ) { + shader_t* shader = drawSurf->shader; + shaderStage_t* pStage = &shader->stages[stage]; + + const uint32_t paddedOffset = drawSurf->materialsSSBOOffset[stage] * material.shader->GetPaddedSize(); + materials += paddedOffset; + + bool updated = !drawSurf->initialized[stage] || pStage->colorDynamic || pStage->texMatricesDynamic || pStage->dynamic; + if ( !updated ) { + return; + } + drawSurf->initialized[stage] = true; + + gl_skyboxShaderMaterial->BindProgram( material.deformIndex ); + + // bind u_ColorMap + gl_skyboxShaderMaterial->SetUniform_ColorMapCubeBindless( + GL_BindToTMU( 0, pStage->bundle[TB_COLORMAP].image[0] ) + ); + + // u_AlphaThreshold + gl_skyboxShaderMaterial->SetUniform_AlphaTest( GLS_ATEST_NONE ); + + // u_InverseLightFactor + gl_skyboxShaderMaterial->SetUniform_InverseLightFactor( tr.mapInverseLightFactor ); + + gl_skyboxShaderMaterial->WriteUniformsToBuffer( materials ); +} + +static void UpdateSurfaceDataScreen( uint32_t* materials, Material& material, drawSurf_t* drawSurf, const uint32_t stage ) { + shader_t* shader = drawSurf->shader; + shaderStage_t* pStage = &shader->stages[stage]; + + const uint32_t paddedOffset = drawSurf->materialsSSBOOffset[stage] * material.shader->GetPaddedSize(); + materials += paddedOffset; + + bool updated = !drawSurf->initialized[stage] || pStage->colorDynamic || pStage->texMatricesDynamic || pStage->dynamic; + if ( !updated ) { + return; + } + drawSurf->initialized[stage] = true; + + gl_screenShaderMaterial->BindProgram( pStage->deformIndex ); + + // bind u_CurrentMap + gl_screenShaderMaterial->SetUniform_CurrentMapBindless( BindAnimatedImage( 0, &drawSurf->shader->stages[stage].bundle[TB_COLORMAP] ) ); + + gl_screenShaderMaterial->WriteUniformsToBuffer( materials ); +} + +static void UpdateSurfaceDataHeatHaze( uint32_t* materials, Material& material, drawSurf_t* drawSurf, const uint32_t stage ) { + shader_t* shader = drawSurf->shader; + shaderStage_t* pStage = &shader->stages[stage]; + + const uint32_t paddedOffset = drawSurf->materialsSSBOOffset[stage] * material.shader->GetPaddedSize(); + materials += paddedOffset; + + bool updated = !drawSurf->initialized[stage] || pStage->colorDynamic || pStage->texMatricesDynamic || pStage->dynamic; + if ( !updated ) { + return; + } + drawSurf->initialized[stage] = true; + + // bind u_NormalMap + gl_heatHazeShaderMaterial->SetUniform_NormalMapBindless( + GL_BindToTMU( 0, pStage->bundle[TB_NORMALMAP].image[0] ) + ); + + float deformMagnitude = RB_EvalExpression( &pStage->deformMagnitudeExp, 1.0 ); + gl_heatHazeShaderMaterial->SetUniform_DeformMagnitude( deformMagnitude ); + + if ( pStage->enableNormalMapping ) { + vec3_t normalScale; + SetNormalScale( pStage, normalScale ); + + // bind u_NormalScale + gl_heatHazeShaderMaterial->SetUniform_NormalScale( normalScale ); + } + + // bind u_CurrentMap + gl_heatHazeShaderMaterial->SetUniform_CurrentMapBindless( + GL_BindToTMU( 1, tr.currentRenderImage[backEnd.currentMainFBO] ) + ); + + gl_heatHazeShaderMaterial->WriteUniformsToBuffer( materials ); +} + +static void UpdateSurfaceDataLiquid( uint32_t* materials, Material& material, drawSurf_t* drawSurf, const uint32_t stage ) { + shader_t* shader = drawSurf->shader; + shaderStage_t* pStage = &shader->stages[stage]; + + const uint32_t paddedOffset = drawSurf->materialsSSBOOffset[stage] * material.shader->GetPaddedSize(); + materials += paddedOffset; + + bool updated = !drawSurf->initialized[stage] || pStage->colorDynamic || pStage->texMatricesDynamic || pStage->dynamic; + if ( !updated ) { + return; + } + drawSurf->initialized[stage] = true; + + float fogDensity = RB_EvalExpression( &pStage->fogDensityExp, 0.001 ); + vec4_t fogColor; + Tess_ComputeColor( pStage ); + VectorCopy( tess.svars.color.ToArray(), fogColor ); + + gl_liquidShaderMaterial->SetUniform_RefractionIndex( RB_EvalExpression( &pStage->refractionIndexExp, 1.0 ) ); + gl_liquidShaderMaterial->SetUniform_FresnelPower( RB_EvalExpression( &pStage->fresnelPowerExp, 2.0 ) ); + gl_liquidShaderMaterial->SetUniform_FresnelScale( RB_EvalExpression( &pStage->fresnelScaleExp, 1.0 ) ); + gl_liquidShaderMaterial->SetUniform_FresnelBias( RB_EvalExpression( &pStage->fresnelBiasExp, 0.05 ) ); + gl_liquidShaderMaterial->SetUniform_FogDensity( fogDensity ); + gl_liquidShaderMaterial->SetUniform_FogColor( fogColor ); + + gl_liquidShaderMaterial->SetUniform_UnprojectMatrix( backEnd.viewParms.unprojectionMatrix ); + gl_liquidShaderMaterial->SetUniform_ModelMatrix( backEnd.orientation.transformMatrix ); + gl_liquidShaderMaterial->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[glState.stackIndex] ); + + // NOTE: specular component is computed by shader. + // FIXME: physical mapping is not implemented. + if ( pStage->enableSpecularMapping ) { + float specMin = RB_EvalExpression( &pStage->specularExponentMin, r_specularExponentMin->value ); + float specMax = RB_EvalExpression( &pStage->specularExponentMax, r_specularExponentMax->value ); + gl_liquidShaderMaterial->SetUniform_SpecularExponent( specMin, specMax ); + } + + // bind u_CurrentMap + gl_liquidShaderMaterial->SetUniform_CurrentMapBindless( GL_BindToTMU( 0, tr.currentRenderImage[backEnd.currentMainFBO] ) ); + + // bind u_PortalMap + gl_liquidShaderMaterial->SetUniform_PortalMapBindless( GL_BindToTMU( 1, tr.portalRenderImage ) ); + + // depth texture + gl_liquidShaderMaterial->SetUniform_DepthMapBindless( GL_BindToTMU( 2, tr.currentDepthImage ) ); + + // bind u_HeightMap u_depthScale u_reliefOffsetBias + if ( pStage->enableReliefMapping ) { + float depthScale; + float reliefDepthScale; + + depthScale = RB_EvalExpression( &pStage->depthScaleExp, r_reliefDepthScale->value ); + reliefDepthScale = tess.surfaceShader->reliefDepthScale; + depthScale *= reliefDepthScale == 0 ? 1 : reliefDepthScale; + gl_liquidShaderMaterial->SetUniform_ReliefDepthScale( depthScale ); + gl_liquidShaderMaterial->SetUniform_ReliefOffsetBias( tess.surfaceShader->reliefOffsetBias ); + + // FIXME: if there is both, embedded heightmap in normalmap is used instead of standalone heightmap + if ( !pStage->hasHeightMapInNormalMap ) { + gl_liquidShaderMaterial->SetUniform_HeightMapBindless( GL_BindToTMU( 15, pStage->bundle[TB_HEIGHTMAP].image[0] ) ); + } + } + + // bind u_NormalMap + gl_liquidShaderMaterial->SetUniform_NormalMapBindless( GL_BindToTMU( 3, pStage->bundle[TB_NORMALMAP].image[0] ) ); + + // bind u_NormalScale + if ( pStage->enableNormalMapping ) { + vec3_t normalScale; + // FIXME: NormalIntensity default was 0.5 + SetNormalScale( pStage, normalScale ); + + gl_liquidShaderMaterial->SetUniform_NormalScale( normalScale ); + } + + gl_liquidShaderMaterial->WriteUniformsToBuffer( materials ); +} + +/* +* Buffer layout: +* // Static surfaces data: +* // Material0 +* // Surface/stage0_0: +* uniform0_0 +* uniform0_1 +* .. +* uniform0_x +* optional_struct_padding +* // Surface/stage0_1: +* .. +* // Surface/stage0_y: +* uniform0_0 +* uniform0_1 +* .. +* uniform0_x +* optional_struct_padding +* optional_material1_padding +* // Material1 +* // Surface/stage1_0: +* .. +* // Surface/stage1_y: +* .. +* .. +* // Materialz: +* .. +* .. +* // Dynamic surfaces data: +* // Same as the static layout +*/ +// Buffer is separated into static and dynamic parts so we can just update the whole dynamic range at once +// This will generate the actual buffer with per-stage values AFTER materials are generated +void MaterialSystem::GenerateWorldMaterialsBuffer() { + Log::Debug( "Generating materials buffer" ); + + uint32_t offset = 0; + + materialsSSBO.BindBuffer(); + + // Compute data size for static surfaces + for ( MaterialPack& pack : materialPacks ) { + for ( Material& material : pack.materials ) { + // Any new material in the buffer must start on an offset that is an integer multiple of + // the padded size of the material struct + const uint32_t paddedSize = material.shader->GetPaddedSize(); + const uint32_t padding = ( offset % paddedSize == 0 ) ? 0 : paddedSize - ( offset % paddedSize ); + + offset += padding; + material.staticMaterialsSSBOOffset = offset; + offset += paddedSize * material.totalStaticDrawSurfCount; + } + } + + dynamicDrawSurfsOffset = offset; + + // Compute data size for dynamic surfaces + for ( MaterialPack& pack : materialPacks ) { + for ( Material& material : pack.materials ) { + // Any new material in the buffer must start on an offset that is an integer multiple of + // the padded size of the material struct + const uint32_t paddedSize = material.shader->GetPaddedSize(); + const uint32_t padding = ( offset % paddedSize == 0 ) ? 0 : paddedSize - ( offset % paddedSize ); + + offset += padding; + material.dynamicMaterialsSSBOOffset = offset; + offset += paddedSize * material.totalDynamicDrawSurfCount; + } + } + + dynamicDrawSurfsSize = offset - dynamicDrawSurfsOffset; + + // 4 bytes per component + glBufferData( GL_SHADER_STORAGE_BUFFER, offset * sizeof( uint32_t ), nullptr, GL_DYNAMIC_DRAW ); + uint32_t* materialsData = materialsSSBO.MapBufferRange( offset ); + memset( materialsData, 0, offset * sizeof( uint32_t ) ); + + for ( uint32_t materialPackID = 0; materialPackID < 3; materialPackID++ ) { + for ( Material& material : materialPacks[materialPackID].materials ) { + + for ( drawSurf_t* drawSurf : material.drawSurfs ) { + bool hasDynamicStages = false; + + uint32_t stage = 0; + for ( shaderStage_t* pStage = drawSurf->shader->stages; pStage < drawSurf->shader->lastStage; pStage++ ) { + if ( drawSurf->materialIDs[stage] != material.id || drawSurf->materialPackIDs[stage] != materialPackID ) { + continue; + } + + uint32_t SSBOOffset = 0; + uint32_t drawSurfCount = 0; + if ( pStage->dynamic ) { + SSBOOffset = material.dynamicMaterialsSSBOOffset; + drawSurfCount = material.currentDynamicDrawSurfCount; + material.currentDynamicDrawSurfCount++; + } else { + SSBOOffset = material.staticMaterialsSSBOOffset; + drawSurfCount = material.currentStaticDrawSurfCount; + material.currentStaticDrawSurfCount++; + } + + drawSurf->materialsSSBOOffset[stage] = ( SSBOOffset + drawSurfCount * material.shader->GetPaddedSize() ) / + material.shader->GetPaddedSize(); + + if ( pStage->dynamic ) { + hasDynamicStages = true; + } + + AddStageTextures( drawSurf, pStage, &material ); + + switch ( pStage->type ) { + case stageType_t::ST_COLORMAP: + // generic2D + UpdateSurfaceDataGeneric( materialsData, material, drawSurf, stage ); + break; + case stageType_t::ST_STYLELIGHTMAP: + case stageType_t::ST_STYLECOLORMAP: + UpdateSurfaceDataGeneric( materialsData, material, drawSurf, stage ); + break; + case stageType_t::ST_LIGHTMAP: + case stageType_t::ST_DIFFUSEMAP: + case stageType_t::ST_COLLAPSE_COLORMAP: + case stageType_t::ST_COLLAPSE_DIFFUSEMAP: + UpdateSurfaceDataLightMapping( materialsData, material, drawSurf, stage ); + break; + case stageType_t::ST_REFLECTIONMAP: + case stageType_t::ST_COLLAPSE_REFLECTIONMAP: + UpdateSurfaceDataReflection( materialsData, material, drawSurf, stage ); + break; + case stageType_t::ST_REFRACTIONMAP: + case stageType_t::ST_DISPERSIONMAP: + // Not implemented yet + break; + case stageType_t::ST_SKYBOXMAP: + UpdateSurfaceDataSkybox( materialsData, material, drawSurf, stage ); + break; + case stageType_t::ST_SCREENMAP: + UpdateSurfaceDataScreen( materialsData, material, drawSurf, stage ); + break; + case stageType_t::ST_PORTALMAP: + // This is supposedly used for alphagen portal and portal surfaces should never get here + ASSERT_UNREACHABLE(); + break; + case stageType_t::ST_HEATHAZEMAP: + UpdateSurfaceDataHeatHaze( materialsData, material, drawSurf, stage ); + break; + case stageType_t::ST_LIQUIDMAP: + UpdateSurfaceDataLiquid( materialsData, material, drawSurf, stage ); + break; + + default: + break; + } + + tess.currentDrawSurf = drawSurf; + + tess.currentSSBOOffset = tess.currentDrawSurf->materialsSSBOOffset[stage]; + tess.materialID = tess.currentDrawSurf->materialIDs[stage]; + tess.materialPackID = tess.currentDrawSurf->materialPackIDs[stage]; + + tess.multiDrawPrimitives = 0; + tess.numIndexes = 0; + tess.numVertexes = 0; + tess.attribsSet = 0; + + rb_surfaceTable[Util::ordinal( *drawSurf->surface )]( drawSurf->surface ); + + pStage->colorRenderer( pStage ); + + if ( pStage->dynamic ) { + drawSurf->materialsSSBOOffset[stage] = ( SSBOOffset - dynamicDrawSurfsOffset + drawSurfCount * + material.shader->GetPaddedSize() ) / material.shader->GetPaddedSize(); + } + + stage++; + } + + if ( hasDynamicStages ) { + // We need a copy here because the memory pointed to by drawSurf will change later + // We'll probably need a separate buffer for entities other than world entity + ensure we don't store a drawSurf with + // invalid pointers + dynamicDrawSurfs.emplace_back( *drawSurf ); + } + } + } + } + + materialsSSBO.UnmapBuffer(); +} + +// This generates the buffer GLIndirect commands +void MaterialSystem::GenerateWorldCommandBuffer() { + Log::Debug( "Generating world command buffer" ); + + uint32_t count = 0; + for ( const MaterialPack& pack : materialPacks ) { + for ( const Material& material : pack.materials ) { + count += material.drawCommands.size(); + } + } + + if ( count == 0 ) { + return; + } + + Log::Debug( "CmdBuffer size: %u", count ); + + commandBuffer.BindBuffer(); + glBufferData( GL_DRAW_INDIRECT_BUFFER, count * sizeof( GLIndirectBuffer::GLIndirectCommand ), nullptr, GL_STATIC_DRAW ); + + GLIndirectBuffer::GLIndirectCommand* commands = commandBuffer.MapBufferRange( count ); + uint32_t offset = 0; + for ( MaterialPack& pack : materialPacks ) { + for ( Material& material : pack.materials ) { + material.staticCommandOffset = offset; + + for ( const DrawCommand& drawCmd : material.drawCommands ) { + memcpy( commands, &drawCmd.cmd, sizeof( GLIndirectBuffer::GLIndirectCommand ) ); + commands++; + offset++; + } + } + } + + commandBuffer.UnmapBuffer(); + GL_CheckErrors(); +} + +static void BindShaderGeneric( Material* material ) { + gl_genericShaderMaterial->SetVertexAnimation( material->vertexAnimation ); + + gl_genericShaderMaterial->SetTCGenEnvironment( material->tcGenEnvironment ); + gl_genericShaderMaterial->SetTCGenLightmap( material->tcGen_Lightmap ); + + gl_genericShaderMaterial->SetDepthFade( material->hasDepthFade ); + gl_genericShaderMaterial->SetVertexSprite( material->vboVertexSprite ); + + gl_genericShaderMaterial->BindProgram( material->deformIndex ); +} + +static void BindShaderLightMapping( Material* material ) { + gl_lightMappingShaderMaterial->SetVertexAnimation( material->vertexAnimation ); + gl_lightMappingShaderMaterial->SetBspSurface( material->bspSurface ); + + gl_lightMappingShaderMaterial->SetDeluxeMapping( material->enableDeluxeMapping ); + + gl_lightMappingShaderMaterial->SetGridLighting( material->enableGridLighting ); + + gl_lightMappingShaderMaterial->SetGridDeluxeMapping( material->enableGridDeluxeMapping ); + + gl_lightMappingShaderMaterial->SetHeightMapInNormalMap( material->hasHeightMapInNormalMap ); + + gl_lightMappingShaderMaterial->SetReliefMapping( material->enableReliefMapping ); + + gl_lightMappingShaderMaterial->SetReflectiveSpecular( material->enableNormalMapping && tr.cubeHashTable != nullptr ); + + gl_lightMappingShaderMaterial->SetPhysicalShading( material->enablePhysicalMapping ); + + gl_lightMappingShaderMaterial->BindProgram( material->deformIndex ); +} + +static void BindShaderReflection( Material* material ) { + gl_reflectionShaderMaterial->SetHeightMapInNormalMap( material->hasHeightMapInNormalMap ); + + gl_reflectionShaderMaterial->SetReliefMapping( material->enableReliefMapping ); + + gl_reflectionShaderMaterial->SetVertexAnimation( material->vertexAnimation ); + + gl_reflectionShaderMaterial->BindProgram( material->deformIndex ); +} + +static void BindShaderSkybox( Material* material ) { + gl_skyboxShaderMaterial->BindProgram( material->deformIndex ); +} + +static void BindShaderScreen( Material* material ) { + gl_screenShaderMaterial->BindProgram( material->deformIndex ); +} + +static void BindShaderHeatHaze( Material* material ) { + gl_heatHazeShaderMaterial->SetVertexAnimation( material->vertexAnimation ); + + gl_heatHazeShaderMaterial->SetVertexSprite( material->vboVertexSprite ); + + gl_heatHazeShaderMaterial->BindProgram( material->deformIndex ); +} + +static void BindShaderLiquid( Material* material ) { + gl_liquidShaderMaterial->SetHeightMapInNormalMap( material->hasHeightMapInNormalMap ); + + gl_liquidShaderMaterial->SetReliefMapping( material->enableReliefMapping ); + + gl_liquidShaderMaterial->BindProgram( material->deformIndex ); +} + +// ProcessMaterial*() are essentially same as BindShader*(), but only set the GL program id to the material, +// without actually binding it +static void ProcessMaterialGeneric( Material* material, shaderStage_t* pStage, shader_t* shader ) { + material->shader = gl_genericShaderMaterial; + + material->vertexAnimation = false; + material->tcGenEnvironment = pStage->tcGen_Environment; + material->tcGen_Lightmap = pStage->tcGen_Lightmap; + material->vboVertexSprite = shader->autoSpriteMode != 0; + material->deformIndex = pStage->deformIndex; + + gl_genericShaderMaterial->SetVertexAnimation( false ); + + gl_genericShaderMaterial->SetTCGenEnvironment( pStage->tcGen_Environment ); + gl_genericShaderMaterial->SetTCGenLightmap( pStage->tcGen_Lightmap ); + + bool hasDepthFade = pStage->hasDepthFade && !shader->autoSpriteMode; + material->hasDepthFade = hasDepthFade; + gl_genericShaderMaterial->SetDepthFade( hasDepthFade ); + gl_genericShaderMaterial->SetVertexSprite( shader->autoSpriteMode != 0 ); + + material->program = gl_genericShaderMaterial->GetProgram( pStage->deformIndex ); +} + +static void ProcessMaterialLightMapping( Material* material, shaderStage_t* pStage, drawSurf_t* drawSurf ) { + material->shader = gl_lightMappingShaderMaterial; + + material->vertexAnimation = false; + material->bspSurface = false; + + gl_lightMappingShaderMaterial->SetVertexAnimation( false ); + gl_lightMappingShaderMaterial->SetBspSurface( drawSurf->bspSurface ); + + lightMode_t lightMode = lightMode_t::FULLBRIGHT; + deluxeMode_t deluxeMode = deluxeMode_t::NONE; + + bool hack = drawSurf->shader->lastStage != drawSurf->shader->stages + && drawSurf->shader->stages[0].rgbGen == colorGen_t::CGEN_VERTEX; + if ( ( tess.surfaceShader->surfaceFlags & SURF_NOLIGHTMAP ) && !hack ) { + // Use fullbright on “surfaceparm nolightmap” materials. + } else if ( pStage->type == stageType_t::ST_COLLAPSE_COLORMAP ) { + /* Use fullbright for collapsed stages without lightmaps, + for example: + { + map textures/texture_d + heightMap textures/texture_h + } + + This is doable for some complex multi-stage materials. */ + } else if ( drawSurf->bspSurface ) { + lightMode = tr.worldLight; + deluxeMode = tr.worldDeluxe; + + if ( lightMode == lightMode_t::MAP ) { + bool hasLightMap = ( drawSurf->lightmapNum() >= 0 ); + + if ( !hasLightMap ) { + lightMode = lightMode_t::VERTEX; + deluxeMode = deluxeMode_t::NONE; + } + } + } else { + lightMode = tr.modelLight; + deluxeMode = tr.modelDeluxe; + } + + bool enableDeluxeMapping = ( deluxeMode == deluxeMode_t::MAP ); + bool enableGridLighting = ( lightMode == lightMode_t::GRID ); + bool enableGridDeluxeMapping = ( deluxeMode == deluxeMode_t::GRID ); + + DAEMON_ASSERT( !( enableDeluxeMapping && enableGridDeluxeMapping ) ); + + material->enableDeluxeMapping = enableDeluxeMapping; + material->enableGridLighting = enableGridLighting; + material->enableGridDeluxeMapping = enableGridDeluxeMapping; + material->hasHeightMapInNormalMap = pStage->hasHeightMapInNormalMap; + material->enableReliefMapping = pStage->enableReliefMapping; + material->enableNormalMapping = pStage->enableNormalMapping && tr.cubeHashTable != nullptr; + material->enablePhysicalMapping = pStage->enablePhysicalMapping; + material->deformIndex = pStage->deformIndex; + + gl_lightMappingShaderMaterial->SetDeluxeMapping( enableDeluxeMapping ); + + gl_lightMappingShaderMaterial->SetGridLighting( enableGridLighting ); + + gl_lightMappingShaderMaterial->SetGridDeluxeMapping( enableGridDeluxeMapping ); + + gl_lightMappingShaderMaterial->SetHeightMapInNormalMap( pStage->hasHeightMapInNormalMap ); + + gl_lightMappingShaderMaterial->SetReliefMapping( pStage->enableReliefMapping ); + + gl_lightMappingShaderMaterial->SetReflectiveSpecular( pStage->enableNormalMapping && tr.cubeHashTable != nullptr ); + + gl_lightMappingShaderMaterial->SetPhysicalShading( pStage->enablePhysicalMapping ); + + material->program = gl_lightMappingShaderMaterial->GetProgram( pStage->deformIndex ); +} + +static void ProcessMaterialReflection( Material* material, shaderStage_t* pStage ) { + material->shader = gl_reflectionShaderMaterial; + + material->hasHeightMapInNormalMap = pStage->hasHeightMapInNormalMap; + material->enableReliefMapping = pStage->enableReliefMapping; + material->vertexAnimation = false; + material->deformIndex = pStage->deformIndex; + + gl_reflectionShaderMaterial->SetHeightMapInNormalMap( pStage->hasHeightMapInNormalMap ); + + gl_reflectionShaderMaterial->SetReliefMapping( pStage->enableReliefMapping ); + + gl_reflectionShaderMaterial->SetVertexAnimation( false ); + + material->program = gl_reflectionShaderMaterial->GetProgram( pStage->deformIndex ); +} + +static void ProcessMaterialSkybox( Material* material, shaderStage_t* pStage ) { + material->shader = gl_skyboxShaderMaterial; + + material->deformIndex = pStage->deformIndex; + + material->program = gl_skyboxShaderMaterial->GetProgram( pStage->deformIndex ); +} + +static void ProcessMaterialScreen( Material* material, shaderStage_t* pStage ) { + material->shader = gl_screenShaderMaterial; + + material->deformIndex = pStage->deformIndex; + + material->program = gl_screenShaderMaterial->GetProgram( pStage->deformIndex ); +} + +static void ProcessMaterialHeatHaze( Material* material, shaderStage_t* pStage, shader_t* shader ) { + material->shader = gl_heatHazeShaderMaterial; + + material->vertexAnimation = false; + material->deformIndex = pStage->deformIndex; + + gl_heatHazeShaderMaterial->SetVertexAnimation( false ); + if ( shader->autoSpriteMode ) { + gl_heatHazeShaderMaterial->SetVertexSprite( true ); + } else { + gl_heatHazeShaderMaterial->SetVertexSprite( false ); + } + + material->program = gl_heatHazeShaderMaterial->GetProgram( pStage->deformIndex ); +} +static void ProcessMaterialLiquid( Material* material, shaderStage_t* pStage ) { + material->shader = gl_liquidShaderMaterial; + + material->hasHeightMapInNormalMap = pStage->hasHeightMapInNormalMap; + material->enableReliefMapping = pStage->enableReliefMapping; + material->deformIndex = pStage->deformIndex; + + gl_liquidShaderMaterial->SetHeightMapInNormalMap( pStage->hasHeightMapInNormalMap ); + + gl_liquidShaderMaterial->SetReliefMapping( pStage->enableReliefMapping ); + + material->program = gl_liquidShaderMaterial->GetProgram( pStage->deformIndex ); +} + +/* This will only generate the materials themselves +* A material represents a distinct global OpenGL state (e. g. blend function, depth test, depth write etc.) +* Materials can have a dependency on other materials to make sure that consecutive stages are rendered in the proper order */ +void MaterialSystem::GenerateWorldMaterials() { + const int current_r_nocull = r_nocull->integer; + const int current_r_drawworld = r_drawworld->integer; + r_nocull->integer = 1; + r_drawworld->integer = 1; + generatingWorldCommandBuffer = true; + + Log::Debug( "Generating world materials" ); + + R_AddWorldSurfaces(); + + Log::Notice( "World bounds: min: %f %f %f max: %f %f %f", tr.viewParms.visBounds[0][0], tr.viewParms.visBounds[0][1], + tr.viewParms.visBounds[0][2], tr.viewParms.visBounds[1][0], tr.viewParms.visBounds[1][1], tr.viewParms.visBounds[1][2] ); + VectorCopy( tr.viewParms.visBounds[0], worldViewBounds[0] ); + VectorCopy( tr.viewParms.visBounds[1], worldViewBounds[1] ); + + backEnd.currentEntity = &tr.worldEntity; + + drawSurf_t* drawSurf; + + uint32_t id = 0; + uint32_t previousMaterialID = 0; + uint32_t packIDs[3] = { 0, 0, 0 }; + skipDrawCommands = true; + + for ( int i = 0; i < tr.refdef.numDrawSurfs; i++ ) { + drawSurf = &tr.refdef.drawSurfs[i]; + if ( drawSurf->entity != &tr.worldEntity ) { + continue; + } + + shader_t* shader = drawSurf->shader; + if ( !shader ) { + continue; + } + + shader = shader->remappedShader ? shader->remappedShader : shader; + if ( shader->isSky || shader->isPortal ) { + continue; + } + + // Don't add SF_SKIP surfaces + if ( *drawSurf->surface == surfaceType_t::SF_SKIP ) { + continue; + } + + rb_surfaceTable[Util::ordinal( *( drawSurf->surface ) )]( drawSurf->surface ); + + uint32_t stage = 0; + for ( shaderStage_t* pStage = drawSurf->shader->stages; pStage < drawSurf->shader->lastStage; pStage++ ) { + Material material; + + uint32_t materialPack = 0; + if ( shader->sort == Util::ordinal( shaderSort_t::SS_DEPTH ) ) { + materialPack = 0; + } else if ( shader->sort >= Util::ordinal( shaderSort_t::SS_ENVIRONMENT_FOG ) + && shader->sort <= Util::ordinal( shaderSort_t::SS_OPAQUE ) ) { + materialPack = 1; + } else { + materialPack = 2; + } + id = packIDs[materialPack]; + + // In surfaces with multiple stages each consecutive stage must be drawn after the previous stage, + // except if an opaque stage follows a transparent stage etc. + if ( stage > 0 ) { + material.useSync = true; + material.syncMaterial = previousMaterialID; + } + + material.stateBits = pStage->stateBits; + // GLS_ATEST_BITS don't matter here as they don't change GL state + material.stateBits &= GLS_DEPTHFUNC_BITS | GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS | GLS_POLYMODE_LINE | GLS_DEPTHTEST_DISABLE + | GLS_COLORMASK_BITS | GLS_DEPTHMASK_TRUE; + material.stageType = pStage->type; + material.cullType = shader->cullType; + material.usePolygonOffset = shader->polygonOffset; + + material.vbo = glState.currentVBO; + material.ibo = glState.currentIBO; + + ComputeDynamics( pStage ); + + if ( pStage->texturesDynamic ) { + drawSurf->texturesDynamic[stage] = true; + } + + switch ( pStage->type ) { + case stageType_t::ST_COLORMAP: + // generic2D also uses this, but it's for ui only, so skip that for now + ProcessMaterialGeneric( &material, pStage, drawSurf->shader ); + break; + case stageType_t::ST_STYLELIGHTMAP: + case stageType_t::ST_STYLECOLORMAP: + ProcessMaterialGeneric( &material, pStage, drawSurf->shader ); + break; + case stageType_t::ST_LIGHTMAP: + case stageType_t::ST_DIFFUSEMAP: + case stageType_t::ST_COLLAPSE_COLORMAP: + case stageType_t::ST_COLLAPSE_DIFFUSEMAP: + ProcessMaterialLightMapping( &material, pStage, drawSurf ); + break; + case stageType_t::ST_REFLECTIONMAP: + case stageType_t::ST_COLLAPSE_REFLECTIONMAP: + ProcessMaterialReflection( &material, pStage ); + break; + case stageType_t::ST_REFRACTIONMAP: + case stageType_t::ST_DISPERSIONMAP: + // Not implemented yet + break; + case stageType_t::ST_SKYBOXMAP: + ProcessMaterialSkybox( &material, pStage ); + break; + case stageType_t::ST_SCREENMAP: + ProcessMaterialScreen( &material, pStage ); + break; + case stageType_t::ST_PORTALMAP: + // This is supposedly used for alphagen portal and portal surfaces should never get here + ASSERT_UNREACHABLE(); + break; + case stageType_t::ST_HEATHAZEMAP: + // FIXME: This requires 2 draws per surface stage rather than 1 + ProcessMaterialHeatHaze( &material, pStage, drawSurf->shader ); + break; + case stageType_t::ST_LIQUIDMAP: + ProcessMaterialLiquid( &material, pStage ); + break; + + default: + break; + } + + std::vector& materials = materialPacks[materialPack].materials; + std::vector::iterator currentSearchIt = materials.begin(); + std::vector::iterator materialIt; + // Look for this material in the ones we already have + while( true ) { + materialIt = std::find( currentSearchIt, materials.end(), material ); + if ( materialIt == materials.end() ) { + break; + } + if ( material.useSync && materialIt->id < material.syncMaterial ) { + currentSearchIt = materialIt + 1; + } else { + break; + } + } + + // Add it at the back if not found + if ( materialIt == materials.end() ) { + material.id = id; + previousMaterialID = id; + materials.emplace_back( material ); + id++; + } else { + previousMaterialID = materialIt->id; + } + + pStage->useMaterialSystem = true; + materials[previousMaterialID].totalDrawSurfCount++; + if ( pStage->dynamic ) { + materials[previousMaterialID].totalDynamicDrawSurfCount++; + } else { + materials[previousMaterialID].totalStaticDrawSurfCount++; + } + + if ( std::find( materials[previousMaterialID].drawSurfs.begin(), materials[previousMaterialID].drawSurfs.end(), drawSurf ) + == materials[previousMaterialID].drawSurfs.end() ) { + materials[previousMaterialID].drawSurfs.emplace_back( drawSurf ); + } + + drawSurf->materialIDs[stage] = previousMaterialID; + drawSurf->materialPackIDs[stage] = materialPack; + + packIDs[materialPack] = id; + + stage++; + } + } + skipDrawCommands = false; + + GenerateWorldMaterialsBuffer(); + + uint32_t totalCount = 0; + for ( MaterialPack& pack : materialPacks ) { + totalCount += pack.materials.size(); + } + Log::Notice( "Generated %u materials from %u surfaces", totalCount, tr.refdef.numDrawSurfs ); + /* for ( const MaterialPack& materialPack : materialPacks ) { + Log::Notice( "materialPack sort: %i %i", Util::ordinal( materialPack.fromSort ), Util::ordinal( materialPack.toSort ) ); + for ( const Material& material : materialPack.materials ) { + Log::Notice( "id: %u, useSync: %b, sync: %u, program: %i, stateBits: %u, totalDrawSurfCount: %u, shader: %s, vbo: %s, ibo: %s" + ", staticDrawSurfs: %u, dynamicDrawSurfs: %u, culling: %i", + material.id, material.useSync, material.syncMaterial, material.program, material.stateBits, material.totalDrawSurfCount, + material.shader->GetName(), material.vbo->name, material.ibo->name, material.currentStaticDrawSurfCount, + material.currentDynamicDrawSurfCount, material.cullType ); + } + } */ + + r_nocull->integer = current_r_nocull; + r_drawworld->integer = current_r_drawworld; + AddAllWorldSurfaces(); + + skipDrawCommands = true; + GeneratePortalBoundingSpheres(); + skipDrawCommands = false; + + generatedWorldCommandBuffer = true; +} + +void MaterialSystem::AddAllWorldSurfaces() { + GenerateWorldCommandBuffer(); + + generatingWorldCommandBuffer = false; +} + +void MaterialSystem::AddStageTextures( drawSurf_t* drawSurf, shaderStage_t* pStage, Material* material ) { + for ( const textureBundle_t& bundle : pStage->bundle ) { + if ( bundle.isVideoMap ) { + material->AddTexture( tr.cinematicImage[bundle.videoMapHandle]->texture ); + continue; + } + + for ( image_t* image : bundle.image ) { + if ( image ) { + material->AddTexture( image->texture ); + } + } + } + + // Add lightmap and deluxemap for this surface to the material as well + + lightMode_t lightMode = lightMode_t::FULLBRIGHT; + deluxeMode_t deluxeMode = deluxeMode_t::NONE; + + bool hack = drawSurf->shader->lastStage != drawSurf->shader->stages + && drawSurf->shader->stages[0].rgbGen == colorGen_t::CGEN_VERTEX; + + if ( ( drawSurf->shader->surfaceFlags & SURF_NOLIGHTMAP ) && !hack ) { + // Use fullbright on “surfaceparm nolightmap” materials. + } else if ( pStage->type == stageType_t::ST_COLLAPSE_COLORMAP ) { + /* Use fullbright for collapsed stages without lightmaps, + for example: + + { + map textures/texture_d + heightMap textures/texture_h + } + + This is doable for some complex multi-stage materials. */ + } else if ( drawSurf->bspSurface ) { + lightMode = tr.worldLight; + deluxeMode = tr.worldDeluxe; + + if ( lightMode == lightMode_t::MAP ) { + bool hasLightMap = static_cast< size_t >( drawSurf->lightmapNum() ) < tr.lightmaps.size(); + + if ( !hasLightMap ) { + lightMode = lightMode_t::VERTEX; + deluxeMode = deluxeMode_t::NONE; + } + } + } else { + lightMode = tr.modelLight; + deluxeMode = tr.modelDeluxe; + } + + // u_Map, u_DeluxeMap + image_t* lightmap = tr.whiteImage; + image_t* deluxemap = tr.whiteImage; + + switch ( lightMode ) { + case lightMode_t::VERTEX: + break; + + case lightMode_t::GRID: + lightmap = tr.lightGrid1Image; + break; + + case lightMode_t::MAP: + lightmap = GetLightMap( drawSurf ); + break; + + default: + break; + } + + switch ( deluxeMode ) { + case deluxeMode_t::MAP: + deluxemap = GetDeluxeMap( drawSurf ); + break; + + case deluxeMode_t::GRID: + deluxemap = tr.lightGrid2Image; + break; + + default: + break; + } + + material->AddTexture( lightmap->texture ); + material->AddTexture( deluxemap->texture ); + + if ( glConfig2.dynamicLight ) { + if ( r_dynamicLightRenderer.Get() == Util::ordinal( dynamicLightRenderer_t::TILED ) ) { + material->AddTexture( tr.lighttileRenderImage->texture ); + } + } +} + +// Dynamic surfaces are those whose values in the SSBO can be updated +void MaterialSystem::UpdateDynamicSurfaces() { + if ( dynamicDrawSurfsSize == 0 ) { + return; + } + + materialsSSBO.BindBuffer(); + uint32_t* materialsData = materialsSSBO.MapBufferRange( dynamicDrawSurfsOffset, dynamicDrawSurfsSize ); + // Shader uniforms are set to 0 if they're not specified, so make sure we do that here too + memset( materialsData, 0, 4 * dynamicDrawSurfsSize ); + for ( drawSurf_t& drawSurf : dynamicDrawSurfs ) { + uint32_t stage = 0; + for ( shaderStage_t* pStage = drawSurf.shader->stages; pStage < drawSurf.shader->lastStage; pStage++ ) { + Material& material = materialPacks[drawSurf.materialPackIDs[stage]].materials[drawSurf.materialIDs[stage]]; + + switch ( pStage->type ) { + case stageType_t::ST_COLORMAP: + // generic2D also uses this, but it's for ui only, so skip that for now + UpdateSurfaceDataGeneric( materialsData, material, &drawSurf, stage ); + break; + case stageType_t::ST_STYLELIGHTMAP: + case stageType_t::ST_STYLECOLORMAP: + UpdateSurfaceDataGeneric( materialsData, material, &drawSurf, stage ); + break; + case stageType_t::ST_LIGHTMAP: + case stageType_t::ST_DIFFUSEMAP: + case stageType_t::ST_COLLAPSE_COLORMAP: + case stageType_t::ST_COLLAPSE_DIFFUSEMAP: + UpdateSurfaceDataLightMapping( materialsData, material, &drawSurf, stage ); + break; + case stageType_t::ST_REFLECTIONMAP: + case stageType_t::ST_COLLAPSE_REFLECTIONMAP: + UpdateSurfaceDataReflection( materialsData, material, &drawSurf, stage ); + break; + case stageType_t::ST_REFRACTIONMAP: + case stageType_t::ST_DISPERSIONMAP: + // Not implemented yet + break; + case stageType_t::ST_SKYBOXMAP: + UpdateSurfaceDataSkybox( materialsData, material, &drawSurf, stage ); + break; + case stageType_t::ST_SCREENMAP: + UpdateSurfaceDataScreen( materialsData, material, &drawSurf, stage ); + break; + case stageType_t::ST_PORTALMAP: + // This is supposedly used for alphagen portal and portal surfaces should never get here + ASSERT_UNREACHABLE(); + break; + case stageType_t::ST_HEATHAZEMAP: + UpdateSurfaceDataHeatHaze( materialsData, material, &drawSurf, stage ); + break; + case stageType_t::ST_LIQUIDMAP: + UpdateSurfaceDataLiquid( materialsData, material, &drawSurf, stage ); + break; + + default: + break; + } + + stage++; + } + } + materialsSSBO.UnmapBuffer(); +} + +void MaterialSystem::GeneratePortalBoundingSpheres() { + Log::Debug( "Generating portal bounding spheres" ); + + for ( drawSurf_t* drawSurf : portalSurfacesTmp ) { + tess.numVertexes = 0; + rb_surfaceTable[Util::ordinal( *( drawSurf->surface ) )]( drawSurf->surface ); + const int numVerts = tess.numVertexes; + vec3_t portalCenter{ 0.0, 0.0, 0.0 }; + for ( int vertIndex = 0; vertIndex < numVerts; vertIndex++ ) { + VectorAdd( portalCenter, tess.verts[vertIndex].xyz, portalCenter ); + } + VectorScale( portalCenter, 1.0 / numVerts, portalCenter ); + + float furthestDistance = 0.0; + for ( int vertIndex = 0; vertIndex < numVerts; vertIndex++ ) { + const float distance = Distance( portalCenter, tess.verts[vertIndex].xyz ); + furthestDistance = distance > furthestDistance ? distance : furthestDistance; + } + + portalSurfaces.emplace_back( *drawSurf ); + drawSurfBoundingSphere sphere; + VectorCopy( portalCenter, sphere.origin ); + sphere.radius = furthestDistance; + sphere.drawSurfID = portalSurfaces.size() - 1; + + portalBounds.emplace_back( sphere ); + } + + portalSurfacesTmp.clear(); +} + +void MaterialSystem::Free() { + generatedWorldCommandBuffer = false; + + dynamicDrawSurfs.clear(); + portalSurfaces.clear(); + portalSurfacesTmp.clear(); + portalBounds.clear(); + skyShaders.clear(); + renderedMaterials.clear(); + + for ( MaterialPack& pack : materialPacks ) { + for ( Material& material : pack.materials ) { + material.drawCommands.clear(); + material.drawSurfs.clear(); + } + pack.materials.clear(); + } +} + +// This gets the information for the surface vertex/index data through Tess +void MaterialSystem::AddDrawCommand( const uint32_t materialID, const uint32_t materialPackID, const uint32_t materialsSSBOOffset, + const GLuint count, const GLuint firstIndex ) { + // Don't add surfaces here if we're just trying to get some VBO/IBO information + if ( skipDrawCommands ) { + return; + } + + cmd.cmd.count = count; + cmd.cmd.instanceCount = 1; + cmd.cmd.firstIndex = firstIndex; + cmd.cmd.baseVertex = 0; + cmd.cmd.baseInstance = materialsSSBOOffset; + cmd.materialsSSBOOffset = materialsSSBOOffset; + + materialPacks[materialPackID].materials[materialID].drawCommands.emplace_back(cmd); + cmd.textureCount = 0; +} + +void MaterialSystem::AddTexture( Texture* texture ) { + if ( cmd.textureCount > MAX_DRAWCOMMAND_TEXTURES ) { + Sys::Drop( "Exceeded max DrawCommand textures" ); + } + cmd.textures[cmd.textureCount] = texture; + cmd.textureCount++; +} + +void MaterialSystem::AddPortalSurfaces() { + // Very inefficient + // TODO: Mark portals in the cull shader and do a readback to only add portals that can actually be seen + std::sort( portalBounds.begin(), portalBounds.end(), + []( const drawSurfBoundingSphere& lhs, const drawSurfBoundingSphere& rhs ) { + return Distance( backEnd.viewParms.orientation.origin, lhs.origin ) - lhs.radius < + Distance( backEnd.viewParms.orientation.origin, rhs.origin ) - rhs.radius; + } ); + for ( const drawSurfBoundingSphere& sphere : portalBounds ) { + R_MirrorViewBySurface( &portalSurfaces[sphere.drawSurfID] ); + } +} + +void MaterialSystem::RenderMaterials( const shaderSort_t fromSort, const shaderSort_t toSort ) { + if ( !r_drawworld->integer ) { + return; + } + + if ( frameStart ) { + renderedMaterials.clear(); + UpdateDynamicSurfaces(); + frameStart = false; + } + + materialsSSBO.BindBufferBase(); + + for ( MaterialPack& materialPack : materialPacks ) { + if ( materialPack.fromSort >= fromSort && materialPack.toSort <= toSort ) { + for ( Material& material : materialPack.materials ) { + RenderMaterial( material ); + renderedMaterials.emplace_back( &material ); + } + } + } + + // Draw the skybox here because we skipped R_AddWorldSurfaces() + const bool environmentFogDraw = ( fromSort <= shaderSort_t::SS_ENVIRONMENT_FOG ) && ( toSort >= shaderSort_t::SS_ENVIRONMENT_FOG ); + const bool environmentNoFogDraw = ( fromSort <= shaderSort_t::SS_ENVIRONMENT_NOFOG ) && toSort >= ( shaderSort_t::SS_ENVIRONMENT_NOFOG ); + if ( tr.hasSkybox && ( environmentFogDraw || environmentNoFogDraw ) ) { + const bool noFogPass = toSort >= shaderSort_t::SS_ENVIRONMENT_NOFOG; + for ( shader_t* skyShader : skyShaders ) { + if ( skyShader->noFog != noFogPass ) { + continue; + } + + tr.drawingSky = true; + Tess_Begin( Tess_StageIteratorSky, skyShader, nullptr, false, -1, 0, false ); + Tess_End(); + } + } +} + +void MaterialSystem::RenderMaterial( Material& material ) { + backEnd.currentEntity = &tr.worldEntity; + + GL_State( material.stateBits ); + if ( material.usePolygonOffset ) { + glEnable( GL_POLYGON_OFFSET_FILL ); + GL_PolygonOffset( r_offsetFactor->value, r_offsetUnits->value ); + } else { + glDisable( GL_POLYGON_OFFSET_FILL ); + } + GL_Cull( material.cullType ); + + backEnd.orientation = backEnd.viewParms.world; + GL_LoadModelViewMatrix( backEnd.orientation.modelViewMatrix ); + + switch ( material.stageType ) { + case stageType_t::ST_COLORMAP: + case stageType_t::ST_STYLELIGHTMAP: + case stageType_t::ST_STYLECOLORMAP: + BindShaderGeneric( &material ); + + if ( material.tcGenEnvironment || material.vboVertexSprite ) { + gl_genericShaderMaterial->SetUniform_ViewOrigin( backEnd.orientation.viewOrigin ); + gl_genericShaderMaterial->SetUniform_ViewUp( backEnd.orientation.axis[2] ); + } + + gl_genericShaderMaterial->SetUniform_ModelMatrix( backEnd.orientation.transformMatrix ); + gl_genericShaderMaterial->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[glState.stackIndex] ); + break; + case stageType_t::ST_LIGHTMAP: + case stageType_t::ST_DIFFUSEMAP: + case stageType_t::ST_COLLAPSE_COLORMAP: + case stageType_t::ST_COLLAPSE_DIFFUSEMAP: + BindShaderLightMapping( &material ); + if ( tr.world ) { + gl_lightMappingShaderMaterial->SetUniform_LightGridOrigin( tr.world->lightGridGLOrigin ); + gl_lightMappingShaderMaterial->SetUniform_LightGridScale( tr.world->lightGridGLScale ); + } + // FIXME: else + + gl_lightMappingShaderMaterial->SetUniform_ViewOrigin( backEnd.orientation.viewOrigin ); + gl_lightMappingShaderMaterial->SetUniform_numLights( backEnd.refdef.numLights ); + gl_lightMappingShaderMaterial->SetUniform_ModelMatrix( backEnd.orientation.transformMatrix ); + gl_lightMappingShaderMaterial->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[glState.stackIndex] ); + break; + case stageType_t::ST_LIQUIDMAP: + BindShaderLiquid( &material ); + gl_liquidShaderMaterial->SetUniform_ViewOrigin( backEnd.viewParms.orientation.origin ); + gl_liquidShaderMaterial->SetUniform_ModelMatrix( backEnd.orientation.transformMatrix ); + gl_liquidShaderMaterial->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[glState.stackIndex] ); + break; + case stageType_t::ST_REFLECTIONMAP: + case stageType_t::ST_COLLAPSE_REFLECTIONMAP: + BindShaderReflection( &material ); + gl_reflectionShaderMaterial->SetUniform_ViewOrigin( backEnd.viewParms.orientation.origin ); + gl_reflectionShaderMaterial->SetUniform_ModelMatrix( backEnd.orientation.transformMatrix ); + gl_reflectionShaderMaterial->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[glState.stackIndex] ); + break; + case stageType_t::ST_REFRACTIONMAP: + case stageType_t::ST_DISPERSIONMAP: + // Not implemented yet + break; + case stageType_t::ST_SKYBOXMAP: + BindShaderSkybox( &material ); + gl_skyboxShaderMaterial->SetUniform_ViewOrigin( backEnd.viewParms.orientation.origin ); + gl_skyboxShaderMaterial->SetUniform_ModelMatrix( backEnd.orientation.transformMatrix ); + gl_skyboxShaderMaterial->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[glState.stackIndex] ); + break; + case stageType_t::ST_SCREENMAP: + BindShaderScreen( &material ); + gl_screenShaderMaterial->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[glState.stackIndex] ); + break; + case stageType_t::ST_PORTALMAP: + // This is supposedly used for alphagen portal and portal surfaces should never get here + ASSERT_UNREACHABLE(); + break; + case stageType_t::ST_HEATHAZEMAP: + // FIXME: This requires 2 draws per surface stage rather than 1 + BindShaderHeatHaze( &material ); + + if ( material.vboVertexSprite ) { + gl_heatHazeShaderMaterial->SetUniform_ViewOrigin( backEnd.orientation.viewOrigin ); + gl_heatHazeShaderMaterial->SetUniform_ViewUp( backEnd.orientation.axis[2] ); + } + + gl_heatHazeShaderMaterial->SetUniform_ModelMatrix( backEnd.orientation.transformMatrix ); + gl_heatHazeShaderMaterial->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[glState.stackIndex] ); + break; + default: + break; + } + + R_BindVBO( material.vbo ); + R_BindIBO( material.ibo ); + material.shader->SetRequiredVertexPointers(); + + if ( !material.texturesResident ) { + for ( Texture* texture : material.textures ) { + if ( !texture->IsResident() ) { + texture->MakeResident(); + + bool resident = glIsTextureHandleResidentARB( texture->bindlessTextureHandle ); + + if ( resident ) { + continue; + } + + for ( Material* mat : renderedMaterials ) { + Log::Warn( "Making material %u textures non-resident (%u)", mat->id, mat->textures.size() ); + for ( Texture* tex : mat->textures ) { + if ( tex->IsResident() ) { + tex->MakeNonResident(); + } + } + mat->texturesResident = false; + } + + texture->MakeResident(); + + resident = glIsTextureHandleResidentARB( texture->bindlessTextureHandle ); + + if( !resident ) { + Log::Warn( "Not enough texture space! Some textures may be missing" ); + break; + } + } + } + } + material.texturesResident = true; + + glMultiDrawElementsIndirect( GL_TRIANGLES, GL_UNSIGNED_INT, + BUFFER_OFFSET( material.staticCommandOffset * sizeof( GLIndirectBuffer::GLIndirectCommand ) ), + material.drawCommands.size(), 0 ); + + if ( material.usePolygonOffset ) { + glDisable( GL_POLYGON_OFFSET_FILL ); + } +} diff --git a/src/engine/renderer/Material.h b/src/engine/renderer/Material.h new file mode 100644 index 0000000000..664f8913ca --- /dev/null +++ b/src/engine/renderer/Material.h @@ -0,0 +1,201 @@ +/* +=========================================================================== + +Daemon BSD Source Code +Copyright (c) 2024 Daemon Developers +All rights reserved. + +This file is part of the Daemon BSD Source Code (Daemon Source Code). + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Daemon developers nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL DAEMON DEVELOPERS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=========================================================================== +*/ +// Material.h + +#ifndef MATERIAL_H +#define MATERIAL_H + +#include + +#include "gl_shader.h" +#include "tr_local.h" + +static constexpr uint32_t MAX_DRAWCOMMAND_TEXTURES = 64; + +struct DrawCommand { + GLIndirectBuffer::GLIndirectCommand cmd; + uint32_t materialsSSBOOffset = 0; + uint32_t textureCount = 0; + Texture* textures[MAX_DRAWCOMMAND_TEXTURES]; + + DrawCommand() { + } + + DrawCommand( const DrawCommand& other ) { + cmd = other.cmd; + materialsSSBOOffset = other.materialsSSBOOffset; + textureCount = other.textureCount; + memcpy( textures, other.textures, textureCount * sizeof( Texture* ) ); + } +}; + +struct Material { + uint32_t materialsSSBOOffset = 0; + uint32_t staticMaterialsSSBOOffset = 0; + uint32_t dynamicMaterialsSSBOOffset = 0; + uint32_t totalDrawSurfCount = 0; + uint32_t totalStaticDrawSurfCount = 0; + uint32_t totalDynamicDrawSurfCount = 0; + uint32_t currentDrawSurfCount = 0; + uint32_t currentStaticDrawSurfCount = 0; + uint32_t currentDynamicDrawSurfCount = 0; + + uint32_t staticCommandOffset = 0; + + uint32_t id = 0; + bool useSync = false; + uint32_t syncMaterial = 0; // Must not be drawn before the material with this id + + uint32_t stateBits = 0; + stageType_t stageType; + GLuint program = 0; + GLShader* shader; + + int deformIndex; + bool vertexAnimation; + bool tcGenEnvironment; + bool tcGen_Lightmap; + bool hasDepthFade; + bool vboVertexSprite; + bool alphaTest; + + bool bspSurface; + bool enableDeluxeMapping; + bool enableGridLighting; + bool enableGridDeluxeMapping; + bool hasHeightMapInNormalMap; + bool enableReliefMapping; + bool enableNormalMapping; + bool enablePhysicalMapping; + + cullType_t cullType; + + bool usePolygonOffset = false; + + VBO_t* vbo; + IBO_t* ibo; + + std::vector drawSurfs; + std::vector drawCommands; + bool texturesResident = false; + std::vector textures; + + bool operator==( const Material& other ) { + return program == other.program && stateBits == other.stateBits && vbo == other.vbo && ibo == other.ibo + && cullType == other.cullType && usePolygonOffset == other.usePolygonOffset; + } + + void AddTexture( Texture* texture ) { + if ( !texture->hasBindlessHandle ) { + texture->GenBindlessHandle(); + } + + if ( std::find( textures.begin(), textures.end(), texture ) == textures.end() ) { + textures.emplace_back( texture ); + } + } +}; + +struct drawSurfBoundingSphere { + vec3_t origin; + float radius; + + uint32_t drawSurfID; +}; + +class MaterialSystem { + public: + bool generatedWorldCommandBuffer = false; + bool skipDrawCommands; + bool generatingWorldCommandBuffer = false; + vec3_t worldViewBounds[2] = {}; + + std::vector portalSurfacesTmp; + std::vector portalSurfaces; + std::vector portalBounds; + std::vector skyShaders; + + std::vector renderedMaterials; + + struct MaterialPack { + const shaderSort_t fromSort; + const shaderSort_t toSort; + std::vector materials; + + MaterialPack( const shaderSort_t newFromSort, const shaderSort_t newToSort ) : + fromSort( newFromSort ), + toSort( newToSort ) { + } + }; + + MaterialPack materialPacks[3]{ + { shaderSort_t::SS_DEPTH, shaderSort_t::SS_DEPTH }, + { shaderSort_t::SS_ENVIRONMENT_FOG, shaderSort_t::SS_OPAQUE }, + { shaderSort_t::SS_ENVIRONMENT_NOFOG, shaderSort_t::SS_POST_PROCESS } + }; + + bool frameStart = true; + + void AddTexture( Texture* texture ); + void AddDrawCommand( const uint32_t materialID, const uint32_t materialPackID, const uint32_t materialsSSBOOffset, + const GLuint count, const GLuint firstIndex ); + + void AddPortalSurfaces(); + void RenderMaterials( const shaderSort_t fromSort, const shaderSort_t toSort ); + void UpdateDynamicSurfaces(); + + void AddStageTextures( drawSurf_t* drawSurf, shaderStage_t* pStage, Material* material ); + void GenerateWorldMaterials(); + void GenerateWorldMaterialsBuffer(); + void GenerateWorldCommandBuffer(); + void GeneratePortalBoundingSpheres(); + + void AddAllWorldSurfaces(); + + void Free(); + + private: + DrawCommand cmd; + std::vector dynamicDrawSurfs; + uint32_t dynamicDrawSurfsOffset = 0; + uint32_t dynamicDrawSurfsSize = 0; + + void RenderMaterial( Material& material ); +}; + +extern GLSSBO materialsSSBO; +extern GLIndirectBuffer commandBuffer; +extern MaterialSystem materialSystem; + +#endif // MATERIAL_H diff --git a/src/engine/renderer/TextureManager.cpp b/src/engine/renderer/TextureManager.cpp new file mode 100644 index 0000000000..192fac60f6 --- /dev/null +++ b/src/engine/renderer/TextureManager.cpp @@ -0,0 +1,121 @@ +/* +=========================================================================== + +Daemon BSD Source Code +Copyright (c) 2024 Daemon Developers +All rights reserved. + +This file is part of the Daemon BSD Source Code (Daemon Source Code). + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Daemon developers nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL DAEMON DEVELOPERS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=========================================================================== +*/ +// TextureManager.cpp + +#include "TextureManager.h" +#include "tr_local.h" + +Texture::Texture() { +} + +Texture::~Texture() { + if ( bindlessTextureResident ) { + MakeNonResident(); + } +} + +bool Texture::IsResident() const { + return bindlessTextureResident; +} + +void Texture::MakeResident() { + glMakeTextureHandleResidentARB( bindlessTextureHandle ); + bindlessTextureResident = true; +} + +void Texture::MakeNonResident() { + glMakeTextureHandleNonResidentARB( bindlessTextureHandle ); + bindlessTextureResident = false; +} + +void Texture::GenBindlessHandle() { + bindlessTextureHandle = glGetTextureHandleARB( textureHandle ); + + if ( bindlessTextureHandle == 0 ) { + Sys::Drop( "Failed to generate bindless texture handle" ); + } + + hasBindlessHandle = true; +} + +TextureManager::TextureManager() = default; +TextureManager::~TextureManager() = default; + +GLuint64 TextureManager::BindTexture( const GLint location, Texture *texture ) { + if( location == -1 ) { + return 0; + } + + if ( texture->IsResident() ) { + return texture->bindlessTextureHandle; + } + + if( std::find( textures.begin(), textures.end(), texture ) == textures.end() ) { + textures.push_back( texture ); + } + + // Bindless textures make the texture state immutable, so generate the handle as late as possible + if ( !texture->hasBindlessHandle ) { + texture->GenBindlessHandle(); + } + + texture->MakeResident(); + + // Make lowest priority textures non-resident first + int i = textures.size() - 1; + while ( !glIsTextureHandleResidentARB( texture->bindlessTextureHandle ) ) { + if ( i < 0 ) { + Sys::Drop( "No texture space available" ); + } + + if ( textures[i]->IsResident() ) { + textures[i]->MakeNonResident(); + texture->MakeResident(); + } + i--; + } + + GL_CheckErrors(); + + return texture->bindlessTextureHandle; +} + +void TextureManager::BindReservedTexture( const GLenum target, const GLuint handle ) { + glActiveTexture( GL_TEXTURE0 ); + glBindTexture( target, handle ); +} + +void TextureManager::FreeTextures() { + textures.clear(); +} diff --git a/src/engine/renderer/TextureManager.h b/src/engine/renderer/TextureManager.h new file mode 100644 index 0000000000..75c28b3bd9 --- /dev/null +++ b/src/engine/renderer/TextureManager.h @@ -0,0 +1,76 @@ +/* +=========================================================================== + +Daemon BSD Source Code +Copyright (c) 2024 Daemon Developers +All rights reserved. + +This file is part of the Daemon BSD Source Code (Daemon Source Code). + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Daemon developers nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL DAEMON DEVELOPERS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=========================================================================== +*/ +// TextureManager.h + +#ifndef TEXTURE_MANAGER_H +#define TEXTURE_MANAGER_H + +#include +#include "GL/glew.h" + +class Texture { + public: + GLuint textureHandle = 0; + GLuint64 bindlessTextureHandle = 0; + bool hasBindlessHandle = false; + + GLenum target = GL_TEXTURE_2D; + + Texture(); + ~Texture(); + + bool IsResident() const; + void MakeResident(); + void MakeNonResident(); + + void GenBindlessHandle();; + + private: + bool bindlessTextureResident = false; +}; + +class TextureManager { + public: + TextureManager(); + ~TextureManager(); + + GLuint64 BindTexture( const GLint location, Texture* texture ); + void BindReservedTexture( const GLenum target, const GLuint handle ); + void FreeTextures(); + + private: + std::vector textures; +}; + +#endif // TEXTURE_MANAGER_H diff --git a/src/engine/renderer/gl_shader.cpp b/src/engine/renderer/gl_shader.cpp index 2f0cbe4ff1..f782d015d0 100644 --- a/src/engine/renderer/gl_shader.cpp +++ b/src/engine/renderer/gl_shader.cpp @@ -41,17 +41,24 @@ ShaderKind shaderKind = ShaderKind::Unknown; GLShader_generic2D *gl_generic2DShader = nullptr; GLShader_generic *gl_genericShader = nullptr; +GLShader_genericMaterial *gl_genericShaderMaterial = nullptr; GLShader_lightMapping *gl_lightMappingShader = nullptr; +GLShader_lightMappingMaterial *gl_lightMappingShaderMaterial = nullptr; GLShader_forwardLighting_omniXYZ *gl_forwardLightingShader_omniXYZ = nullptr; GLShader_forwardLighting_projXYZ *gl_forwardLightingShader_projXYZ = nullptr; GLShader_forwardLighting_directionalSun *gl_forwardLightingShader_directionalSun = nullptr; GLShader_shadowFill *gl_shadowFillShader = nullptr; GLShader_reflection *gl_reflectionShader = nullptr; +GLShader_reflectionMaterial *gl_reflectionShaderMaterial = nullptr; GLShader_skybox *gl_skyboxShader = nullptr; +GLShader_skyboxMaterial *gl_skyboxShaderMaterial = nullptr; GLShader_fogQuake3 *gl_fogQuake3Shader = nullptr; +GLShader_fogQuake3Material *gl_fogQuake3ShaderMaterial = nullptr; GLShader_fogGlobal *gl_fogGlobalShader = nullptr; GLShader_heatHaze *gl_heatHazeShader = nullptr; +GLShader_heatHazeMaterial *gl_heatHazeShaderMaterial = nullptr; GLShader_screen *gl_screenShader = nullptr; +GLShader_screenMaterial *gl_screenShaderMaterial = nullptr; GLShader_portal *gl_portalShader = nullptr; GLShader_contrast *gl_contrastShader = nullptr; GLShader_cameraEffects *gl_cameraEffectsShader = nullptr; @@ -59,6 +66,7 @@ GLShader_blurX *gl_blurXShader = nullptr; GLShader_blurY *gl_blurYShader = nullptr; GLShader_debugShadowMap *gl_debugShadowMapShader = nullptr; GLShader_liquid *gl_liquidShader = nullptr; +GLShader_liquidMaterial *gl_liquidShaderMaterial = nullptr; GLShader_motionblur *gl_motionblurShader = nullptr; GLShader_ssao *gl_ssaoShader = nullptr; GLShader_depthtile1 *gl_depthtile1Shader = nullptr; @@ -374,14 +382,12 @@ static std::string BuildDeformSteps( deformStage_t *deforms, int numDeforms ) return steps; } -static void addExtension( std::string &str, bool available, int minGlslVersion, const std::string &name ) { - if ( !available ) - { +static void addExtension( std::string& str, bool available, int minGlslVersion, const std::string& name ) { + if ( !available ) { return; } - if( glConfig2.shadingLanguageVersion < minGlslVersion ) - { + if ( ( glConfig2.shadingLanguageVersion < minGlslVersion ) || ( minGlslVersion == -1 ) ) { str += Str::Format( "#extension GL_%s : require\n", name ); } @@ -406,8 +412,8 @@ static void AddConst( std::string& str, const std::string& name, float v1, float static std::string GenVersionDeclaration() { // Basic version declaration std::string str = Str::Format( "#version %d %s\n", - glConfig2.shadingLanguageVersion, - glConfig2.shadingLanguageVersion >= 150 ? (glConfig2.glCoreProfile ? "core" : "compatibility") : ""); + glConfig2.shadingLanguageVersion, + glConfig2.shadingLanguageVersion >= 150 ? ( glConfig2.glCoreProfile ? "core" : "compatibility" ) : "" ); // add supported GLSL extensions struct extension_t { @@ -423,10 +429,13 @@ static std::string GenVersionDeclaration() { { glConfig2.textureIntegerAvailable, 0, "EXT_texture_integer" }, { glConfig2.textureRGAvailable, 0, "ARB_texture_rg" }, { glConfig2.uniformBufferObjectAvailable, 140, "ARB_uniform_buffer_object" }, + { glConfig2.bindlessTexturesAvailable, -1, "ARB_bindless_texture" }, + // ARB_shader_draw_parameters set to -1, because we might get a 4.6 GL context, where the core variables have different names + { glConfig2.shaderDrawParametersAvailable, -1, "ARB_shader_draw_parameters" }, + { glConfig2.SSBOAvailable, 430, "ARB_shader_storage_buffer_object" }, }; - for ( const auto& extension : extensions ) - { + for ( const auto& extension : extensions ) { addExtension( str, extension.available, extension.minGlslVersion, extension.name ); } @@ -488,6 +497,13 @@ static std::string GenVertexHeader() { "#define OUT(mode) varying\n"; } + if ( glConfig2.shaderDrawParametersAvailable ) { + str += "OUT(flat) int in_drawID;\n"; + str += "OUT(flat) int in_baseInstance;\n"; + str += "#define drawID gl_DrawIDARB\n"; + str += "#define baseInstance gl_BaseInstanceARB\n\n"; + } + return str; } @@ -511,6 +527,17 @@ static std::string GenFragmentHeader() { "#define DECLARE_OUTPUT(type) /* empty*/\n"; } + if ( glConfig2.bindlessTexturesAvailable ) { + str += "layout(bindless_sampler) uniform;\n"; + } + + if ( glConfig2.shaderDrawParametersAvailable ) { + str += "IN(flat) int in_drawID;\n"; + str += "IN(flat) int in_baseInstance;\n"; + str += "#define drawID in_drawID\n"; + str += "#define baseInstance in_baseInstance\n\n"; + } + return str; } @@ -745,9 +772,8 @@ int GLShaderManager::getDeformShaderIndex( deformStage_t *deforms, int numDeform } std::string GLShaderManager::BuildGPUShaderText( Str::StringRef mainShaderName, - Str::StringRef libShaderNames, - GLenum shaderType ) const -{ + Str::StringRef libShaderNames, + GLenum shaderType ) const { char filename[MAX_QPATH]; const char* libNames = libShaderNames.c_str(); @@ -806,14 +832,14 @@ std::string GLShaderManager::BuildGPUShaderText( Str::StringRef mainShaderNa AddDefine( env, "r_SpecularScale", r_specularScale->value ); AddDefine( env, "r_zNear", r_znear->value ); - AddDefine( env, "M_PI", static_cast( M_PI ) ); + AddDefine( env, "M_PI", static_cast< float >( M_PI ) ); AddDefine( env, "MAX_SHADOWMAPS", MAX_SHADOWMAPS ); AddDefine( env, "MAX_REF_LIGHTS", MAX_REF_LIGHTS ); AddDefine( env, "TILE_SIZE", TILE_SIZE ); AddDefine( env, "r_FBufSize", glConfig.vidWidth, glConfig.vidHeight ); - AddDefine( env, "r_tileStep", glState.tileStep[ 0 ], glState.tileStep[ 1 ] ); + AddDefine( env, "r_tileStep", glState.tileStep[0], glState.tileStep[1] ); // We added a lot of stuff but if we do something bad // in the GLSL shaders then we want the proper line @@ -976,22 +1002,21 @@ void GLShaderManager::buildAll() Log::Notice( "glsl shaders took %d msec to build", _totalBuildTime ); } -void GLShaderManager::InitShader( GLShader *shader ) -{ - shader->_shaderPrograms = std::vector( static_cast(1) << shader->_compileMacros.size() ); +void GLShaderManager::InitShader( GLShader* shader ) { + shader->_shaderPrograms = std::vector( static_cast< size_t >( 1 ) << shader->_compileMacros.size() ); + + shader->PostProcessUniforms(); shader->_uniformStorageSize = 0; - for ( std::size_t i = 0; i < shader->_uniforms.size(); i++ ) - { - GLUniform *uniform = shader->_uniforms[ i ]; + for ( std::size_t i = 0; i < shader->_uniforms.size(); i++ ) { + GLUniform* uniform = shader->_uniforms[i]; uniform->SetLocationIndex( i ); uniform->SetFirewallIndex( shader->_uniformStorageSize ); shader->_uniformStorageSize += uniform->GetSize(); } - for ( std::size_t i = 0; i < shader->_uniformBlocks.size(); i++ ) - { - GLUniformBlock *uniformBlock = shader->_uniformBlocks[ i ]; + for ( std::size_t i = 0; i < shader->_uniformBlocks.size(); i++ ) { + GLUniformBlock* uniformBlock = shader->_uniformBlocks[i]; uniformBlock->SetLocationIndex( i ); } @@ -1014,6 +1039,11 @@ void GLShaderManager::InitShader( GLShader *shader ) shader->_computeShaderText = BuildGPUShaderText( shader->GetMainShaderName(), computeInlines, GL_COMPUTE_SHADER ); } + if ( glConfig2.materialSystemAvailable && shader->_useMaterialSystem ) { + shader->_vertexShaderText = ShaderPostProcess( shader, shader->_vertexShaderText ); + shader->_fragmentShaderText = ShaderPostProcess( shader, shader->_fragmentShaderText ); + } + std::string combinedShaderText; if ( shader->_hasVertexShader || shader->_hasFragmentShader ) { combinedShaderText = @@ -1266,6 +1296,108 @@ void GLShaderManager::CompileAndLinkGPUShaderProgram( GLShader *shader, shaderPr LinkProgram( program->program ); } +// This will generate all the extra code for material system shaders +std::string GLShaderManager::ShaderPostProcess( GLShader *shader, const std::string& shaderText ) { + std::string newShaderText; + std::string materialStruct = "\nstruct Material {\n"; + std::string materialBlock = "layout(std430, binding = 0) readonly buffer materialsSSBO {\n" + " Material materials[];\n" + "};\n\n"; + std::string materialDefines; + + /* Generate the struct and defines in the form of: + * struct Material { + * type uniform0; + * type uniform1; + * .. + * type uniformn; + * } + * + * #define uniformx materials[baseInstance].uniformx + */ + + for( GLUniform* uniform : shader->_uniforms ) { + if ( uniform->IsGlobal() ) { + continue; + } + + if ( uniform->IsTexture() ) { + materialStruct += " uvec2 "; + materialStruct += uniform->GetName(); + } else { + materialStruct += " " + uniform->GetType() + " " + uniform->GetName(); + } + + if ( uniform->GetComponentSize() ) { + materialStruct += "[ " + std::to_string( uniform->GetComponentSize() ) + " ]"; + } + materialStruct += ";\n"; + + // vec3 is aligned to 4 components, so just pad it with int + // TODO: Try to move 1 component uniforms here to avoid wasting memory + if ( uniform->GetSTD430Size() == 3 ) { + materialStruct += " int "; + materialStruct += uniform->GetName(); + materialStruct += "_padding;\n"; + } + + materialDefines += "#define "; + materialDefines += uniform->GetName(); + + if ( uniform->IsTexture() ) { // Driver bug: AMD compiler crashes when using the SSBO value directly + materialDefines += "_initial uvec2("; // We'll need this to create sampler objects later + } + + materialDefines += " materials[baseInstance]."; + materialDefines += uniform->GetName(); + + if ( uniform->IsTexture() ) { + materialDefines += " )"; + } + + materialDefines += "\n"; + } + + // Array of structs is aligned to the largest member of the struct + for ( uint i = 0; i < shader->padding; i++ ) { + materialStruct += " int material_padding" + std::to_string( i ); + materialStruct += ";\n"; + } + + materialStruct += "};\n\n"; + materialDefines += "\n"; + + std::istringstream shaderTextStream( shaderText ); + std::string shaderMain; + + std::string line; + + /* Remove local uniform declarations, but avoid removing uniform / storage blocks; + * their values will be sourced from a buffer instead + * Global uniforms (like u_ViewUp and u_ViewOrigin) will still be set as regular uniforms */ + while( std::getline( shaderTextStream, line, '\n' ) ) { + if( !( line.find( "uniform" ) == std::string::npos || line.find( ";" ) == std::string::npos ) ) { + continue; + } + shaderMain += line + "\n"; + } + + for ( GLUniform* uniform : shader->_uniforms ) { + if ( uniform->IsGlobal() ) { + materialDefines += "uniform " + uniform->GetType() + " " + uniform->GetName(); + if ( uniform->GetComponentSize() ) { + materialDefines += "[ " + std::to_string( uniform->GetComponentSize() ) + " ]"; + } + materialDefines += ";\n"; + } + } + + materialDefines += "\n"; + + newShaderText = "#define USE_MATERIAL_SYSTEM\n" + materialStruct + materialBlock + materialDefines + shaderMain; + return newShaderText; +} + GLuint GLShaderManager::CompileShader( Str::StringRef programName, Str::StringRef shaderText, std::initializer_list headers, @@ -1601,6 +1733,87 @@ bool GLCompileMacro_USE_BSP_SURFACE::HasConflictingMacros(size_t permutation, co return false; } +GLuint GLUniform::GetSTD430Size() const { + return _std430Size; +} + +GLuint GLUniform::GetSTD430Alignment() const { + return _std430Alignment; +} + +uint32_t* GLUniform::WriteToBuffer( uint32_t* buffer ) { + return buffer; +} + +void GLShader::RegisterUniform( GLUniform* uniform ) { + _uniforms.push_back( uniform ); + textureCount += uniform->IsTexture(); +} + +GLint GLShader::GetUniformLocation( const GLchar *uniformName ) const { + shaderProgram_t* p = GetProgram(); + return glGetUniformLocation( p->program, uniformName ); +} + +// Compute std430 size/alignment and sort uniforms from highest to lowest alignment +void GLShader::PostProcessUniforms() { + if ( !_useMaterialSystem ) { + return; + } + + std::vector tmp; + + std::vector globalUniforms; + for ( GLUniform* uniform : _uniforms ) { + if ( uniform->IsGlobal() ) { + globalUniforms.emplace_back( uniform ); + } + } + for ( GLUniform* uniform : globalUniforms ) { + _uniforms.erase( std::remove( _uniforms.begin(), _uniforms.end(), uniform ), _uniforms.end() ); + } + + // Sort uniforms from highest to lowest alignment so we don't need to pad uniforms (other than vec3s) + const uint numUniforms = _uniforms.size(); + GLuint structAlignment = 0; + GLuint structSize = 0; + while ( tmp.size() < numUniforms ) { + // Higher-alignment uniforms first to avoid wasting memory + GLuint highestAlignment = 0; + int highestUniform = 0; + for( uint i = 0; i < _uniforms.size(); i++ ) { + if ( _uniforms[i]->GetSTD430Alignment() > highestAlignment ) { + highestAlignment = _uniforms[i]->GetSTD430Alignment(); + highestUniform = i; + } + if ( highestAlignment > structAlignment ) { + structAlignment = highestAlignment; + } + if ( highestAlignment == 4 ) { + break; // 4-component is the highest alignment in std430 + } + } + + const GLuint size = _uniforms[highestUniform]->GetSTD430Size(); + if ( _uniforms[highestUniform]->GetComponentSize() != 0 ) { + structSize += ( size == 3 ) ? 4 * _uniforms[highestUniform]->GetComponentSize() : + size * _uniforms[highestUniform]->GetComponentSize(); + } else { + structSize += ( size == 3 ) ? 4 : size; + } + + tmp.emplace_back( _uniforms[highestUniform] ); + _uniforms.erase( _uniforms.begin() + highestUniform ); + } + _uniforms = tmp; + + padding = ( structAlignment - ( structSize % structAlignment ) ) % structAlignment; + std430Size = structSize; + for ( GLUniform* uniform : globalUniforms ) { + _uniforms.emplace_back( uniform ); + } +} + bool GLShader::GetCompileMacrosString( size_t permutation, std::string &compileMacrosOut ) const { compileMacrosOut.clear(); @@ -1643,6 +1856,38 @@ int GLShader::SelectProgram() return index; } +GLuint GLShader::GetProgram( int deformIndex ) { + int macroIndex = SelectProgram(); + size_t index = macroIndex + ( size_t( deformIndex ) << _compileMacros.size() ); + + // program may not be loaded yet because the shader manager hasn't yet gotten to it + // so try to load it now + if ( index >= _shaderPrograms.size() || !_shaderPrograms[index].program ) { + _shaderManager->buildPermutation( this, macroIndex, deformIndex ); + } + + // program is still not loaded + if ( index >= _shaderPrograms.size() || !_shaderPrograms[index].program ) { + std::string activeMacros; + size_t numMacros = _compileMacros.size(); + + for ( size_t j = 0; j < numMacros; j++ ) { + GLCompileMacro* macro = _compileMacros[j]; + + int bit = macro->GetBit(); + + if ( IsMacroSet( bit ) ) { + activeMacros += macro->GetName(); + activeMacros += " "; + } + } + + ThrowShaderError( Str::Format( "Invalid shader configuration: shader = '%s', macros = '%s'", _name, activeMacros ) ); + } + + return _shaderPrograms[index].program; +} + void GLShader::BindProgram( int deformIndex ) { int macroIndex = SelectProgram(); @@ -1722,8 +1967,19 @@ void GLShader::SetRequiredVertexPointers( bool vboVertexSprite ) GL_VertexAttribsState( attribs ); } +void GLShader::WriteUniformsToBuffer( uint32_t* buffer ) { + uint32_t* bufPtr = buffer; + for ( GLUniform* uniform : _uniforms ) { + if ( !uniform->IsGlobal() ) { + bufPtr = uniform->WriteToBuffer( bufPtr ); + } + } +} + GLShader_generic2D::GLShader_generic2D( GLShaderManager *manager ) : GLShader( "generic2D", "generic", ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT, manager ), + u_ColorMap( this ), + u_DepthMap( this ), u_TextureMatrix( this ), u_AlphaThreshold( this ), u_ModelMatrix( this ), @@ -1754,6 +2010,8 @@ void GLShader_generic2D::SetShaderProgramUniforms( shaderProgram_t *shaderProgra GLShader_generic::GLShader_generic( GLShaderManager *manager ) : GLShader( "generic", ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT, manager ), + u_ColorMap( this ), + u_DepthMap( this ), u_TextureMatrix( this ), u_ViewOrigin( this ), u_ViewUp( this ), @@ -1787,9 +2045,57 @@ void GLShader_generic::SetShaderProgramUniforms( shaderProgram_t *shaderProgram glUniform1i( glGetUniformLocation( shaderProgram->program, "u_DepthMap" ), 1 ); } +GLShader_genericMaterial::GLShader_genericMaterial( GLShaderManager* manager ) : + GLShader( "genericMaterial", "generic", true, ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT, manager ), + u_ColorMap( this ), + u_DepthMap( this ), + u_TextureMatrix( this ), + u_ViewOrigin( this ), + u_ViewUp( this ), + u_AlphaThreshold( this ), + u_ModelMatrix( this ), + u_ModelViewProjectionMatrix( this ), + u_InverseLightFactor( this ), + u_ColorModulate( this ), + u_Color( this ), + // u_Bones( this ), + u_VertexInterpolation( this ), + u_DepthScale( this ), + GLDeformStage( this ), + // GLCompileMacro_USE_VERTEX_SKINNING( this ), + GLCompileMacro_USE_VERTEX_ANIMATION( this ), + GLCompileMacro_USE_VERTEX_SPRITE( this ), + GLCompileMacro_USE_TCGEN_ENVIRONMENT( this ), + GLCompileMacro_USE_TCGEN_LIGHTMAP( this ), + GLCompileMacro_USE_DEPTH_FADE( this ) { +} + +void GLShader_genericMaterial::BuildShaderVertexLibNames( std::string& vertexInlines ) { + vertexInlines += "vertexSimple vertexSkinning vertexAnimation vertexSprite "; +} + +void GLShader_genericMaterial::SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) { + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_ColorMap" ), 0 ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_DepthMap" ), 1 ); +} + GLShader_lightMapping::GLShader_lightMapping( GLShaderManager *manager ) : GLShader( "lightMapping", ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT | ATTR_COLOR, manager ), + u_DiffuseMap( this ), + u_NormalMap( this ), + u_HeightMap( this ), + u_MaterialMap( this ), + u_LightMap( this ), + u_DeluxeMap( this ), + u_GlowMap( this ), + u_EnvironmentMap0( this ), + u_EnvironmentMap1( this ), + u_LightGrid1( this ), + u_LightGrid2( this ), + u_LightTiles( this ), + u_LightTilesInt( this ), + u_LightsTexture( this ), u_TextureMatrix( this ), u_SpecularExponent( this ), u_ColorModulate( this ), @@ -1842,20 +2148,106 @@ void GLShader_lightMapping::SetShaderProgramUniforms( shaderProgram_t *shaderPro glUniform1i( glGetUniformLocation( shaderProgram->program, "u_DiffuseMap" ), BIND_DIFFUSEMAP ); glUniform1i( glGetUniformLocation( shaderProgram->program, "u_NormalMap" ), BIND_NORMALMAP ); glUniform1i( glGetUniformLocation( shaderProgram->program, "u_HeightMap" ), BIND_HEIGHTMAP ); - glUniform1i( glGetUniformLocation( shaderProgram->program, "u_MaterialMap" ), BIND_MATERIALMAP ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_MaterialMap" ), BIND_MATERIALMAP ); glUniform1i( glGetUniformLocation( shaderProgram->program, "u_LightMap" ), BIND_LIGHTMAP ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_LightGrid1" ), BIND_LIGHTMAP ); glUniform1i( glGetUniformLocation( shaderProgram->program, "u_DeluxeMap" ), BIND_DELUXEMAP ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_LightGrid2" ), BIND_DELUXEMAP ); glUniform1i( glGetUniformLocation( shaderProgram->program, "u_GlowMap" ), BIND_GLOWMAP ); glUniform1i( glGetUniformLocation( shaderProgram->program, "u_EnvironmentMap0" ), BIND_ENVIRONMENTMAP0 ); glUniform1i( glGetUniformLocation( shaderProgram->program, "u_EnvironmentMap1" ), BIND_ENVIRONMENTMAP1 ); glUniform1i( glGetUniformLocation( shaderProgram->program, "u_LightTiles" ), BIND_LIGHTTILES ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_LightTilesInt" ), BIND_LIGHTTILES ); if( !glConfig2.uniformBufferObjectAvailable ) { glUniform1i( glGetUniformLocation( shaderProgram->program, "u_Lights" ), BIND_LIGHTS ); } } +GLShader_lightMappingMaterial::GLShader_lightMappingMaterial( GLShaderManager* manager ) : + GLShader( "lightMappingMaterial", "lightMapping", true, + ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT | ATTR_COLOR, manager ), + u_DiffuseMap( this ), + u_NormalMap( this ), + u_HeightMap( this ), + u_MaterialMap( this ), + u_LightMap( this ), + u_DeluxeMap( this ), + u_GlowMap( this ), + u_EnvironmentMap0( this ), + u_EnvironmentMap1( this ), + u_LightGrid1( this ), + u_LightGrid2( this ), + u_LightTilesInt( this ), + u_TextureMatrix( this ), + u_SpecularExponent( this ), + u_ColorModulate( this ), + u_Color( this ), + u_AlphaThreshold( this ), + u_ViewOrigin( this ), + u_ModelMatrix( this ), + u_ModelViewProjectionMatrix( this ), + u_InverseLightFactor( this ), + // u_Bones( this ), + u_VertexInterpolation( this ), + u_ReliefDepthScale( this ), + u_ReliefOffsetBias( this ), + u_NormalScale( this ), + u_EnvironmentInterpolation( this ), + u_LightGridOrigin( this ), + u_LightGridScale( this ), + u_numLights( this ), + u_Lights( this ), + GLDeformStage( this ), + GLCompileMacro_USE_BSP_SURFACE( this ), + // GLCompileMacro_USE_VERTEX_SKINNING( this ), + GLCompileMacro_USE_VERTEX_ANIMATION( this ), + GLCompileMacro_USE_DELUXE_MAPPING( this ), + GLCompileMacro_USE_GRID_LIGHTING( this ), + GLCompileMacro_USE_GRID_DELUXE_MAPPING( this ), + GLCompileMacro_USE_HEIGHTMAP_IN_NORMALMAP( this ), + GLCompileMacro_USE_RELIEF_MAPPING( this ), + GLCompileMacro_USE_REFLECTIVE_SPECULAR( this ), + GLCompileMacro_USE_PHYSICAL_MAPPING( this ) { +} + +void GLShader_lightMappingMaterial::BuildShaderVertexLibNames( std::string& vertexInlines ) { + vertexInlines += "vertexSimple vertexSkinning vertexAnimation vertexSprite "; +} + +void GLShader_lightMappingMaterial::BuildShaderFragmentLibNames( std::string& fragmentInlines ) { + fragmentInlines += "computeLight reliefMapping"; +} + +void GLShader_lightMappingMaterial::BuildShaderCompileMacros( std::string& /*compileMacros*/ ) { +} + +void GLShader_lightMappingMaterial::SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) { + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_DiffuseMap" ), BIND_DIFFUSEMAP ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_NormalMap" ), BIND_NORMALMAP ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_HeightMap" ), BIND_HEIGHTMAP ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_MaterialMap" ), BIND_MATERIALMAP ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_LightMap" ), BIND_LIGHTMAP ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_DeluxeMap" ), BIND_DELUXEMAP ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_GlowMap" ), BIND_GLOWMAP ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_EnvironmentMap0" ), BIND_ENVIRONMENTMAP0 ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_EnvironmentMap1" ), BIND_ENVIRONMENTMAP1 ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_LightTiles" ), BIND_LIGHTTILES ); + if ( !glConfig2.uniformBufferObjectAvailable ) { + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_Lights" ), BIND_LIGHTS ); + } +} + GLShader_forwardLighting_omniXYZ::GLShader_forwardLighting_omniXYZ( GLShaderManager *manager ): GLShader("forwardLighting_omniXYZ", "forwardLighting", ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT, manager), + u_DiffuseMap( this ), + u_NormalMap( this ), + u_MaterialMap( this ), + u_AttenuationMapXY( this ), + u_AttenuationMapZ( this ), + u_ShadowMap( this ), + u_ShadowClipMap( this ), + u_RandomMap( this ), + u_HeightMap( this ), u_TextureMatrix( this ), u_SpecularExponent( this ), u_AlphaThreshold( this ), @@ -1915,6 +2307,15 @@ void GLShader_forwardLighting_omniXYZ::SetShaderProgramUniforms( shaderProgram_t GLShader_forwardLighting_projXYZ::GLShader_forwardLighting_projXYZ( GLShaderManager *manager ): GLShader("forwardLighting_projXYZ", "forwardLighting", ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT, manager), + u_DiffuseMap( this ), + u_NormalMap( this ), + u_MaterialMap( this ), + u_AttenuationMapXY( this ), + u_AttenuationMapZ( this ), + u_ShadowMap0( this ), + u_ShadowClipMap0( this ), + u_RandomMap( this ), + u_HeightMap( this ), u_TextureMatrix( this ), u_SpecularExponent( this ), u_AlphaThreshold( this ), @@ -1976,6 +2377,20 @@ void GLShader_forwardLighting_projXYZ::SetShaderProgramUniforms( shaderProgram_t GLShader_forwardLighting_directionalSun::GLShader_forwardLighting_directionalSun( GLShaderManager *manager ): GLShader("forwardLighting_directionalSun", "forwardLighting", ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT, manager), + u_DiffuseMap( this ), + u_NormalMap( this ), + u_MaterialMap( this ), + u_ShadowMap0( this ), + u_ShadowMap1( this ), + u_ShadowMap2( this ), + u_ShadowMap3( this ), + u_ShadowMap4( this ), + u_ShadowClipMap0( this ), + u_ShadowClipMap1( this ), + u_ShadowClipMap2( this ), + u_ShadowClipMap3( this ), + u_ShadowClipMap4( this ), + u_HeightMap( this ), u_TextureMatrix( this ), u_SpecularExponent( this ), u_AlphaThreshold( this ), @@ -2046,6 +2461,7 @@ void GLShader_forwardLighting_directionalSun::SetShaderProgramUniforms( shaderPr GLShader_shadowFill::GLShader_shadowFill( GLShaderManager *manager ) : GLShader( "shadowFill", ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT, manager ), + u_ColorMap( this ), u_TextureMatrix( this ), u_ViewOrigin( this ), u_AlphaThreshold( this ), @@ -2075,6 +2491,9 @@ void GLShader_shadowFill::SetShaderProgramUniforms( shaderProgram_t *shaderProgr GLShader_reflection::GLShader_reflection( GLShaderManager *manager ): GLShader("reflection", "reflection_CB", ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT, manager ), + u_ColorMap( this ), + u_NormalMap( this ), + u_HeightMap( this ), u_TextureMatrix( this ), u_ViewOrigin( this ), u_ModelMatrix( this ), @@ -2113,8 +2532,48 @@ void GLShader_reflection::SetShaderProgramUniforms( shaderProgram_t *shaderProgr glUniform1i( glGetUniformLocation( shaderProgram->program, "u_HeightMap" ), 15 ); } +GLShader_reflectionMaterial::GLShader_reflectionMaterial( GLShaderManager* manager ) : + GLShader( "reflectionMaterial", "reflection", true, ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT, manager ), + u_ColorMap( this ), + u_NormalMap( this ), + u_HeightMap( this ), + u_TextureMatrix( this ), + u_ViewOrigin( this ), + u_ModelMatrix( this ), + u_ModelViewProjectionMatrix( this ), + // u_Bones( this ), + u_ReliefDepthScale( this ), + u_ReliefOffsetBias( this ), + u_NormalScale( this ), + u_VertexInterpolation( this ), + GLDeformStage( this ), + // GLCompileMacro_USE_VERTEX_SKINNING( this ), + GLCompileMacro_USE_VERTEX_ANIMATION( this ), + GLCompileMacro_USE_HEIGHTMAP_IN_NORMALMAP( this ), + GLCompileMacro_USE_RELIEF_MAPPING( this ) { +} + +void GLShader_reflectionMaterial::BuildShaderVertexLibNames( std::string& vertexInlines ) { + vertexInlines += "vertexSimple vertexSkinning vertexAnimation "; +} + +void GLShader_reflectionMaterial::BuildShaderFragmentLibNames( std::string& fragmentInlines ) { + fragmentInlines += "reliefMapping"; +} + +void GLShader_reflectionMaterial::BuildShaderCompileMacros( std::string& ) { +} + +void GLShader_reflectionMaterial::SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) { + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_ColorMap" ), 0 ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_NormalMap" ), 1 ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_HeightMap" ), 15 ); +} + GLShader_skybox::GLShader_skybox( GLShaderManager *manager ) : GLShader( "skybox", ATTR_POSITION, manager ), + u_ColorMapCube( this ), + u_CloudMap( this ), u_TextureMatrix( this ), u_ViewOrigin( this ), u_CloudHeight( this ), @@ -2129,12 +2588,33 @@ GLShader_skybox::GLShader_skybox( GLShaderManager *manager ) : void GLShader_skybox::SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) { + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_ColorMapCube" ), 0 ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_CloudMap" ), 1 ); +} + +GLShader_skyboxMaterial::GLShader_skyboxMaterial( GLShaderManager* manager ) : + GLShader( "skyboxMaterial", "skybox", true, ATTR_POSITION, manager ), + u_ColorMapCube( this ), + u_CloudMap( this ), + u_TextureMatrix( this ), + u_ViewOrigin( this ), + u_CloudHeight( this ), + u_UseCloudMap( this ), + u_AlphaThreshold( this ), + u_ModelMatrix( this ), + u_ModelViewProjectionMatrix( this ), + u_InverseLightFactor( this ), + GLDeformStage( this ) { +} + +void GLShader_skyboxMaterial::SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) { glUniform1i( glGetUniformLocation( shaderProgram->program, "u_ColorMap" ), 0 ); glUniform1i( glGetUniformLocation( shaderProgram->program, "u_CloudMap" ), 1 ); } GLShader_fogQuake3::GLShader_fogQuake3( GLShaderManager *manager ) : GLShader( "fogQuake3", ATTR_POSITION | ATTR_QTANGENT, manager ), + u_ColorMap( this ), u_ModelMatrix( this ), u_ModelViewProjectionMatrix( this ), u_InverseLightFactor( this ), @@ -2160,8 +2640,35 @@ void GLShader_fogQuake3::SetShaderProgramUniforms( shaderProgram_t *shaderProgra glUniform1i( glGetUniformLocation( shaderProgram->program, "u_ColorMap" ), 0 ); } +GLShader_fogQuake3Material::GLShader_fogQuake3Material( GLShaderManager* manager ) : + GLShader( "fogQuake3Material", "fogQuake3", true, ATTR_POSITION | ATTR_QTANGENT, manager ), + u_ColorMap( this ), + u_ModelMatrix( this ), + u_ModelViewProjectionMatrix( this ), + u_InverseLightFactor( this ), + u_Color( this ), + // u_Bones( this ), + u_VertexInterpolation( this ), + u_FogDistanceVector( this ), + u_FogDepthVector( this ), + u_FogEyeT( this ), + GLDeformStage( this ), + // GLCompileMacro_USE_VERTEX_SKINNING( this ), + GLCompileMacro_USE_VERTEX_ANIMATION( this ) { +} + +void GLShader_fogQuake3Material::BuildShaderVertexLibNames( std::string& vertexInlines ) { + vertexInlines += "vertexSimple vertexSkinning vertexAnimation "; +} + +void GLShader_fogQuake3Material::SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) { + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_ColorMap" ), 0 ); +} + GLShader_fogGlobal::GLShader_fogGlobal( GLShaderManager *manager ) : GLShader( "fogGlobal", ATTR_POSITION, manager ), + u_ColorMap( this ), + u_DepthMap( this ), u_ViewOrigin( this ), u_ViewMatrix( this ), u_ModelViewProjectionMatrix( this ), @@ -2181,6 +2688,9 @@ void GLShader_fogGlobal::SetShaderProgramUniforms( shaderProgram_t *shaderProgra GLShader_heatHaze::GLShader_heatHaze( GLShaderManager *manager ) : GLShader( "heatHaze", ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT, manager ), + u_CurrentMap( this ), + u_NormalMap( this ), + u_HeightMap( this ), u_TextureMatrix( this ), u_ViewOrigin( this ), u_ViewUp( this ), @@ -2218,8 +2728,47 @@ void GLShader_heatHaze::SetShaderProgramUniforms( shaderProgram_t *shaderProgram glUniform1i( glGetUniformLocation( shaderProgram->program, "u_HeightMap" ), 15 ); } +GLShader_heatHazeMaterial::GLShader_heatHazeMaterial( GLShaderManager* manager ) : + GLShader( "heatHazeMaterial", "heatHaze", true, ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT, manager ), + u_CurrentMap( this ), + u_NormalMap( this ), + u_HeightMap( this ), + u_TextureMatrix( this ), + u_ViewOrigin( this ), + u_ViewUp( this ), + u_DeformMagnitude( this ), + u_ModelMatrix( this ), + u_ModelViewProjectionMatrix( this ), + u_ModelViewMatrixTranspose( this ), + u_ProjectionMatrixTranspose( this ), + u_ColorModulate( this ), + u_Color( this ), + // u_Bones( this ), + u_NormalScale( this ), + u_VertexInterpolation( this ), + GLDeformStage( this ), + // GLCompileMacro_USE_VERTEX_SKINNING( this ), + GLCompileMacro_USE_VERTEX_ANIMATION( this ), + GLCompileMacro_USE_VERTEX_SPRITE( this ) { +} + +void GLShader_heatHazeMaterial::BuildShaderVertexLibNames( std::string& vertexInlines ) { + vertexInlines += "vertexSimple vertexSkinning vertexAnimation vertexSprite "; +} + +void GLShader_heatHazeMaterial::BuildShaderFragmentLibNames( std::string& fragmentInlines ) { + fragmentInlines += "reliefMapping"; +} + +void GLShader_heatHazeMaterial::SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) { + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_NormalMap" ), 0 ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_CurrentMap" ), 1 ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_HeightMap" ), 15 ); +} + GLShader_screen::GLShader_screen( GLShaderManager *manager ) : GLShader( "screen", ATTR_POSITION, manager ), + u_CurrentMap( this ), u_ModelViewProjectionMatrix( this ) { } @@ -2229,8 +2778,19 @@ void GLShader_screen::SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) glUniform1i( glGetUniformLocation( shaderProgram->program, "u_CurrentMap" ), 0 ); } +GLShader_screenMaterial::GLShader_screenMaterial( GLShaderManager* manager ) : + GLShader( "screenMaterial", "screen", true, ATTR_POSITION, manager ), + u_CurrentMap( this ), + u_ModelViewProjectionMatrix( this ) { +} + +void GLShader_screenMaterial::SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) { + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_CurrentMap" ), 0 ); +} + GLShader_portal::GLShader_portal( GLShaderManager *manager ) : GLShader( "portal", ATTR_POSITION, manager ), + u_CurrentMap( this ), u_ModelViewMatrix( this ), u_ModelViewProjectionMatrix( this ), u_PortalRange( this ) @@ -2244,6 +2804,7 @@ void GLShader_portal::SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) GLShader_contrast::GLShader_contrast( GLShaderManager *manager ) : GLShader( "contrast", ATTR_POSITION, manager ), + u_ColorMap( this ), u_ModelViewProjectionMatrix( this ), u_InverseLightFactor( this ) { @@ -2256,6 +2817,8 @@ void GLShader_contrast::SetShaderProgramUniforms( shaderProgram_t *shaderProgram GLShader_cameraEffects::GLShader_cameraEffects( GLShaderManager *manager ) : GLShader( "cameraEffects", ATTR_POSITION | ATTR_TEXCOORD, manager ), + u_ColorMap3D( this ), + u_CurrentMap( this ), u_ColorModulate( this ), u_TextureMatrix( this ), u_ModelViewProjectionMatrix( this ), @@ -2268,11 +2831,12 @@ GLShader_cameraEffects::GLShader_cameraEffects( GLShaderManager *manager ) : void GLShader_cameraEffects::SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) { glUniform1i( glGetUniformLocation( shaderProgram->program, "u_CurrentMap" ), 0 ); - glUniform1i( glGetUniformLocation( shaderProgram->program, "u_ColorMap" ), 3 ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_ColorMap3D" ), 3 ); } GLShader_blurX::GLShader_blurX( GLShaderManager *manager ) : GLShader( "blurX", ATTR_POSITION, manager ), + u_ColorMap( this ), u_ModelViewProjectionMatrix( this ), u_DeformMagnitude( this ), u_TexScale( this ) @@ -2286,6 +2850,7 @@ void GLShader_blurX::SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) GLShader_blurY::GLShader_blurY( GLShaderManager *manager ) : GLShader( "blurY", ATTR_POSITION, manager ), + u_ColorMap( this ), u_ModelViewProjectionMatrix( this ), u_DeformMagnitude( this ), u_TexScale( this ) @@ -2299,6 +2864,7 @@ void GLShader_blurY::SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) GLShader_debugShadowMap::GLShader_debugShadowMap( GLShaderManager *manager ) : GLShader( "debugShadowMap", ATTR_POSITION, manager ), + u_CurrentMap( this ), u_ModelViewProjectionMatrix( this ) { } @@ -2310,6 +2876,13 @@ void GLShader_debugShadowMap::SetShaderProgramUniforms( shaderProgram_t *shaderP GLShader_liquid::GLShader_liquid( GLShaderManager *manager ) : GLShader( "liquid", ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT, manager ), + u_CurrentMap( this ), + u_DepthMap( this ), + u_NormalMap( this ), + u_PortalMap( this ), + u_LightGrid1( this ), + u_LightGrid2( this ), + u_HeightMap( this ), u_TextureMatrix( this ), u_ViewOrigin( this ), u_RefractionIndex( this ), @@ -2337,7 +2910,52 @@ void GLShader_liquid::BuildShaderFragmentLibNames( std::string& fragmentInlines fragmentInlines += "computeLight reliefMapping"; } -void GLShader_liquid::SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) +void GLShader_liquid::SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) { + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_CurrentMap" ), 0 ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_PortalMap" ), 1 ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_DepthMap" ), 2 ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_NormalMap" ), 3 ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_LightGrid1" ), 6 ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_LightGrid2" ), 7 ); + glUniform1i( glGetUniformLocation( shaderProgram->program, "u_HeightMap" ), 15 ); +} + +GLShader_liquidMaterial::GLShader_liquidMaterial( GLShaderManager* manager ) : + GLShader( "liquidMaterial", "liquid", true, ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT, manager ), + u_CurrentMap( this ), + u_DepthMap( this ), + u_NormalMap( this ), + u_PortalMap( this ), + u_LightGrid1( this ), + u_LightGrid2( this ), + u_HeightMap( this ), + u_TextureMatrix( this ), + u_ViewOrigin( this ), + u_RefractionIndex( this ), + u_ModelMatrix( this ), + u_ModelViewProjectionMatrix( this ), + u_UnprojectMatrix( this ), + u_FresnelPower( this ), + u_FresnelScale( this ), + u_FresnelBias( this ), + u_ReliefDepthScale( this ), + u_ReliefOffsetBias( this ), + u_NormalScale( this ), + u_FogDensity( this ), + u_FogColor( this ), + u_LightTilesInt( this ), + u_SpecularExponent( this ), + u_LightGridOrigin( this ), + u_LightGridScale( this ), + GLCompileMacro_USE_HEIGHTMAP_IN_NORMALMAP( this ), + GLCompileMacro_USE_RELIEF_MAPPING( this ) { +} + +void GLShader_liquidMaterial::BuildShaderFragmentLibNames( std::string& fragmentInlines ) { + fragmentInlines += "computeLight reliefMapping"; +} + +void GLShader_liquidMaterial::SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) { glUniform1i( glGetUniformLocation( shaderProgram->program, "u_CurrentMap" ), 0 ); glUniform1i( glGetUniformLocation( shaderProgram->program, "u_PortalMap" ), 1 ); @@ -2350,6 +2968,8 @@ void GLShader_liquid::SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) GLShader_motionblur::GLShader_motionblur( GLShaderManager *manager ) : GLShader( "motionblur", ATTR_POSITION, manager ), + u_ColorMap( this ), + u_DepthMap( this ), u_ModelViewProjectionMatrix( this ), u_blurVec( this ) { @@ -2363,6 +2983,7 @@ void GLShader_motionblur::SetShaderProgramUniforms( shaderProgram_t *shaderProgr GLShader_ssao::GLShader_ssao( GLShaderManager *manager ) : GLShader( "ssao", ATTR_POSITION, manager ), + u_DepthMap( this ), u_ModelViewProjectionMatrix( this ), u_UnprojectionParams( this ), u_zFar( this ) @@ -2376,6 +2997,7 @@ void GLShader_ssao::SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) GLShader_depthtile1::GLShader_depthtile1( GLShaderManager *manager ) : GLShader( "depthtile1", ATTR_POSITION, manager ), + u_DepthMap( this ), u_ModelViewProjectionMatrix( this ), u_zFar( this ) { @@ -2388,6 +3010,7 @@ void GLShader_depthtile1::SetShaderProgramUniforms( shaderProgram_t *shaderProgr GLShader_depthtile2::GLShader_depthtile2( GLShaderManager *manager ) : GLShader( "depthtile2", ATTR_POSITION, manager ), + u_DepthMap( this ), u_ModelViewProjectionMatrix( this ) { } @@ -2399,10 +3022,12 @@ void GLShader_depthtile2::SetShaderProgramUniforms( shaderProgram_t *shaderProgr GLShader_lighttile::GLShader_lighttile( GLShaderManager *manager ) : GLShader( "lighttile", ATTR_POSITION | ATTR_TEXCOORD, manager ), - u_ModelMatrix( this ), + u_DepthMap( this ), + u_Lights( this ), + u_LightsTexture( this ), u_numLights( this ), u_lightLayer( this ), - u_Lights( this ), + u_ModelMatrix( this ), u_zFar( this ) { } @@ -2418,6 +3043,7 @@ void GLShader_lighttile::SetShaderProgramUniforms( shaderProgram_t *shaderProgra GLShader_fxaa::GLShader_fxaa( GLShaderManager *manager ) : GLShader( "fxaa", ATTR_POSITION, manager ), + u_ColorMap( this ), u_ModelViewProjectionMatrix( this ) { } diff --git a/src/engine/renderer/gl_shader.h b/src/engine/renderer/gl_shader.h index e3ef96ed7b..bc6898bb47 100644 --- a/src/engine/renderer/gl_shader.h +++ b/src/engine/renderer/gl_shader.h @@ -61,6 +61,7 @@ struct GLBinaryHeader }; class GLUniform; +class GLShader; class GLUniformBlock; class GLCompileMacro; class GLShaderManager; @@ -99,6 +100,10 @@ class GLShader std::string _name; std::string _mainShaderName; + const bool _useMaterialSystem; + GLuint std430Size = 0; + uint padding = 0; + uint textureCount = 0; protected: int _activeMacros; unsigned int _checkSum; @@ -129,6 +134,7 @@ class GLShader const bool hasVertexShader = true, const bool hasFragmentShader = true, const bool hasComputeShader = false ) : _name( name ), _mainShaderName( name ), + _useMaterialSystem( false ), _activeMacros( 0 ), _checkSum( 0 ), _currentProgram( nullptr ), @@ -146,6 +152,7 @@ class GLShader const bool hasVertexShader = true, const bool hasFragmentShader = true, const bool hasComputeShader = false ) : _name( name ), _mainShaderName( mainShaderName ), + _useMaterialSystem( false ), _activeMacros( 0 ), _checkSum( 0 ), _currentProgram( nullptr ), @@ -159,6 +166,24 @@ class GLShader { } + GLShader( const std::string& name, const std::string& mainShaderName, const bool useMaterialSystem, uint32_t vertexAttribsRequired, + GLShaderManager* manager, + const bool hasVertexShader = true, const bool hasFragmentShader = true, const bool hasComputeShader = false ) : + _name( name ), + _mainShaderName( mainShaderName ), + _useMaterialSystem( useMaterialSystem ), + _activeMacros( 0 ), + _checkSum( 0 ), + _currentProgram( nullptr ), + _vertexAttribsRequired( vertexAttribsRequired ), + _vertexAttribs( 0 ), + _shaderManager( manager ), + _hasVertexShader( hasVertexShader ), + _hasFragmentShader( hasFragmentShader ), + _hasComputeShader( hasComputeShader ), + _uniformStorageSize( 0 ) { + } + public: virtual ~GLShader() { @@ -202,10 +227,7 @@ class GLShader } } - void RegisterUniform( GLUniform *uniform ) - { - _uniforms.push_back( uniform ); - } + void RegisterUniform( GLUniform* uniform ); void RegisterUniformBlock( GLUniformBlock *uniformBlock ) { @@ -227,6 +249,8 @@ class GLShader return _compileMacros.size(); } + GLint GetUniformLocation( const GLchar *uniformName ) const; + shaderProgram_t *GetProgram() const { return _currentProgram; @@ -243,6 +267,7 @@ class GLShader } protected: + void PostProcessUniforms(); bool GetCompileMacrosString( size_t permutation, std::string &compileMacrosOut ) const; virtual void BuildShaderVertexLibNames( std::string& /*vertexInlines*/ ) { }; virtual void BuildShaderFragmentLibNames( std::string& /*fragmentInlines*/ ) { }; @@ -251,6 +276,7 @@ class GLShader virtual void SetShaderProgramUniforms( shaderProgram_t* /*shaderProgram*/ ) { }; int SelectProgram(); public: + GLuint GetProgram( int deformIndex ); void BindProgram( int deformIndex ); void DispatchCompute( const GLuint globalWorkgroupX, const GLuint globalWorkgroupY, const GLuint globalWorkgroupZ ); void DispatchComputeIndirect( const GLintptr indirectBuffer ); @@ -285,6 +311,28 @@ class GLShader { _vertexAttribs &= ~bit; } + + GLuint GetSTD430Size() const { + return std430Size; + } + + uint GetPadding() const { + return padding; + } + + uint GetPaddedSize() const { + return std430Size + padding; + } + + uint GetTextureCount() const { + return textureCount; + } + + bool UseMaterialSystem() const { + return _useMaterialSystem; + } + + void WriteUniformsToBuffer( uint32_t* buffer ); }; class GLShaderManager @@ -342,6 +390,7 @@ class GLShaderManager const std::string &compileMacros ); void CompileAndLinkGPUShaderProgram( GLShader *shader, shaderProgram_t *program, Str::StringRef compileMacros, int deformIndex ); + std::string ShaderPostProcess( GLShader *shader, const std::string& shaderText ); std::string BuildDeformShaderText( const std::string& steps ); std::string BuildGPUShaderText( Str::StringRef mainShader, Str::StringRef libShaders, GLenum shaderType ) const; void LinkProgram( GLuint program ) const; @@ -357,12 +406,29 @@ class GLUniform protected: GLShader *_shader; std::string _name; + const std::string _type; + + // In multiples of 4 bytes + const GLuint _std430Size; + const GLuint _std430Alignment; + + const bool _global; // This uniform won't go into materials SSBO if true + const int _components; + const bool _isTexture; + size_t _firewallIndex; size_t _locationIndex; - GLUniform( GLShader *shader, const char *name ) : + GLUniform( GLShader *shader, const char *name, const char* type, const GLuint std430Size, const GLuint std430Alignment, + const bool global, const int components = 0, const bool isTexture = false ) : _shader( shader ), _name( name ), + _type( type ), + _std430Size( std430Size ), + _std430Alignment( std430Alignment ), + _global( global ), + _components( components ), + _isTexture( isTexture ), _firewallIndex( 0 ), _locationIndex( 0 ) { @@ -387,6 +453,29 @@ class GLUniform return _name.c_str(); } + const std::string GetType() const { + return _type; + } + + GLuint GetSTD430Size() const; + + GLuint GetSTD430Alignment() const; + + int GetComponentSize() const { + return _components; + } + + bool IsGlobal() const { + return _global; + } + + bool IsTexture() const { + return _isTexture; + } + + // This should return a pointer to the memory right after the one this uniform wrote to + virtual uint32_t* WriteToBuffer( uint32_t* buffer ); + void UpdateShaderProgramUniformLocation( shaderProgram_t *shaderProgram ) { shaderProgram->uniformLocations[ _locationIndex ] = glGetUniformLocation( shaderProgram->program, GetName() ); @@ -398,11 +487,176 @@ class GLUniform } }; +class GLUniformSampler : protected GLUniform { + protected: + GLUniformSampler( GLShader* shader, const char* name, const char* type, const GLuint size ) : + GLUniform( shader, name, type, glConfig2.bindlessTexturesAvailable ? size * 2 : size, + glConfig2.bindlessTexturesAvailable ? size * 2 : size, false, 0, true ) { + } + + inline GLint GetLocation() { + shaderProgram_t* p = _shader->GetProgram(); + + if ( _global || !_shader->UseMaterialSystem() ) { + ASSERT_EQ( p, glState.currentProgram ); + } + + return p->uniformLocations[_locationIndex]; + } + + inline size_t GetFirewallIndex() const { + return _firewallIndex; + } + + public: + size_t GetSize() override { + return sizeof( GLuint64 ); + } + + void SetValue( GLuint value ) { + currentValue = value; + } + + void SetValueBindless( GLint64 value ) { + currentValueBindless = value; + + if ( glConfig2.bindlessTexturesAvailable && ( !_shader->UseMaterialSystem() || _global ) ) { + glUniformHandleui64ARB( GetLocation(), currentValueBindless ); + } + } + + uint32_t* WriteToBuffer( uint32_t* buffer ) override { + uint32_t* bufferNext = buffer; + if ( glConfig2.bindlessTexturesAvailable ) { + memcpy( buffer, ¤tValueBindless, sizeof( GLuint64 ) ); + bufferNext += 2; + } else { + memcpy( buffer, ¤tValue, sizeof( GLint ) ); + bufferNext += 1; + } + return bufferNext; + } + + private: + GLuint64 currentValueBindless = 0; + GLuint currentValue = 0; +}; + +class GLUniformSampler1D : protected GLUniformSampler { + protected: + GLUniformSampler1D( GLShader* shader, const char* name ) : + GLUniformSampler( shader, name, "sampler1D", 1 ) { + } + + inline GLint GetLocation() { + shaderProgram_t* p = _shader->GetProgram(); + + if ( _global || !_shader->UseMaterialSystem() ) { + ASSERT_EQ( p, glState.currentProgram ); + } + + return p->uniformLocations[_locationIndex]; + } + + public: + size_t GetSize() override { + return sizeof( GLuint64 ); + } +}; + +class GLUniformSampler2D : protected GLUniformSampler { + protected: + GLUniformSampler2D( GLShader* shader, const char* name ) : + GLUniformSampler( shader, name, "sampler2D", 1 ) { + } + + inline GLint GetLocation() { + shaderProgram_t* p = _shader->GetProgram(); + + if ( _global || !_shader->UseMaterialSystem() ) { + ASSERT_EQ( p, glState.currentProgram ); + } + + return p->uniformLocations[_locationIndex]; + } + + public: + size_t GetSize() override { + return sizeof( GLuint64 ); + } +}; + +class GLUniformSampler3D : protected GLUniformSampler { + protected: + GLUniformSampler3D( GLShader* shader, const char* name ) : + GLUniformSampler( shader, name, "sampler3D", 1 ) { + } + + inline GLint GetLocation() { + shaderProgram_t* p = _shader->GetProgram(); + + if ( _global || !_shader->UseMaterialSystem() ) { + ASSERT_EQ( p, glState.currentProgram ); + } + + return p->uniformLocations[_locationIndex]; + } + + public: + size_t GetSize() override { + return sizeof( GLuint64 ); + } +}; + +class GLUniformUSampler3D : protected GLUniformSampler { + protected: + GLUniformUSampler3D( GLShader* shader, const char* name ) : + GLUniformSampler( shader, name, "usampler3D", 1 ) { + } + + inline GLint GetLocation() { + shaderProgram_t* p = _shader->GetProgram(); + + if ( _global || !_shader->UseMaterialSystem() ) { + ASSERT_EQ( p, glState.currentProgram ); + } + + return p->uniformLocations[_locationIndex]; + } + + public: + size_t GetSize() override { + return sizeof( GLuint64 ); + } +}; + +class GLUniformSamplerCube : protected GLUniformSampler { + protected: + GLUniformSamplerCube( GLShader* shader, const char* name ) : + GLUniformSampler( shader, name, "samplerCube", 1 ) { + } + + inline GLint GetLocation() { + shaderProgram_t* p = _shader->GetProgram(); + + if ( _global || !_shader->UseMaterialSystem() ) { + ASSERT_EQ( p, glState.currentProgram ); + } + + return p->uniformLocations[_locationIndex]; + } + + public: + size_t GetSize() override { + return sizeof( GLuint64 ); + } +}; + class GLUniform1i : protected GLUniform { protected: - GLUniform1i( GLShader *shader, const char *name ) : - GLUniform( shader, name ) + GLUniform1i( GLShader *shader, const char *name, const bool global = false ) : + GLUniform( shader, name, "int", 1, 1, global ) { } @@ -410,7 +664,9 @@ class GLUniform1i : protected GLUniform { shaderProgram_t *p = _shader->GetProgram(); - ASSERT_EQ(p, glState.currentProgram); + if ( _global || !_shader->UseMaterialSystem() ) { + ASSERT_EQ( p, glState.currentProgram ); + } #if defined( LOG_GLSL_UNIFORMS ) if ( r_logFile->integer ) @@ -419,6 +675,12 @@ class GLUniform1i : protected GLUniform this->GetName(), _shader->GetName().c_str(), value ) ); } #endif + + if ( _shader->UseMaterialSystem() && !_global ) { + currentValue = value; + return; + } + #if defined( USE_UNIFORM_FIREWALL ) int *firewall = ( int * ) &p->uniformFirewall[ _firewallIndex ]; @@ -436,13 +698,73 @@ class GLUniform1i : protected GLUniform { return sizeof( int ); } + + uint32_t* WriteToBuffer( uint32_t* buffer ) override { + memcpy( buffer, ¤tValue, sizeof( int ) ); + return buffer + 1; + } + + private: + int currentValue = 0; +}; + +class GLUniform1Bool : protected GLUniform { + protected: + // GLSL std430 bool is always 4 bytes, which might not correspond to C++ bool + GLUniform1Bool( GLShader* shader, const char* name ) : + GLUniform( shader, name, "bool", 1, 1, false ) { + } + + inline void SetValue( int value ) { + shaderProgram_t* p = _shader->GetProgram(); + + if ( _global || !_shader->UseMaterialSystem() ) { + ASSERT_EQ( p, glState.currentProgram ); + } + +#if defined( LOG_GLSL_UNIFORMS ) + if ( r_logFile->integer ) { + GLimp_LogComment( va( "GLSL_SetUniform1i( %s, shader: %s, value: %d ) ---\n", + this->GetName(), _shader->GetName().c_str(), value ) ); + } +#endif + + if ( _shader->UseMaterialSystem() && !_global ) { + currentValue = value; + return; + } + +#if defined( USE_UNIFORM_FIREWALL ) + int* firewall = ( int* ) &p->uniformFirewall[_firewallIndex]; + + if ( *firewall == value ) { + return; + } + + *firewall = value; +#endif + glUniform1i( p->uniformLocations[_locationIndex], value ); + } + + public: + size_t GetSize() override { + return sizeof( int ); + } + + uint32_t* WriteToBuffer( uint32_t *buffer ) override { + memcpy( buffer, ¤tValue, sizeof( bool ) ); + return buffer + 1; + } + + private: + int currentValue = 0; }; class GLUniform1f : protected GLUniform { protected: GLUniform1f( GLShader *shader, const char *name ) : - GLUniform( shader, name ) + GLUniform( shader, name, "float", 1, 1, false ) { } @@ -450,7 +772,9 @@ class GLUniform1f : protected GLUniform { shaderProgram_t *p = _shader->GetProgram(); - ASSERT_EQ(p, glState.currentProgram); + if ( _global || !_shader->UseMaterialSystem() ) { + ASSERT_EQ( p, glState.currentProgram ); + } #if defined( LOG_GLSL_UNIFORMS ) if ( r_logFile->integer ) @@ -459,6 +783,12 @@ class GLUniform1f : protected GLUniform this->GetName(), _shader->GetName().c_str(), value ) ); } #endif + + if ( _shader->UseMaterialSystem() && !_global ) { + currentValue = value; + return; + } + #if defined( USE_UNIFORM_FIREWALL ) float *firewall = ( float * ) &p->uniformFirewall[ _firewallIndex ]; @@ -476,21 +806,32 @@ class GLUniform1f : protected GLUniform { return sizeof( float ); } + + uint32_t* WriteToBuffer( uint32_t* buffer ) override { + memcpy( buffer, ¤tValue, sizeof( float ) ); + return buffer + 1; + } + + private: + float currentValue = 0; }; class GLUniform1fv : protected GLUniform { protected: - GLUniform1fv( GLShader *shader, const char *name ) : - GLUniform( shader, name ) + GLUniform1fv( GLShader *shader, const char *name, const int size ) : + GLUniform( shader, name, "float", 1, 1, false, size ) { + currentValue.reserve( size ); } inline void SetValue( int numFloats, float *f ) { shaderProgram_t *p = _shader->GetProgram(); - ASSERT_EQ(p, glState.currentProgram); + if ( _global || !_shader->UseMaterialSystem() ) { + ASSERT_EQ( p, glState.currentProgram ); + } #if defined( LOG_GLSL_UNIFORMS ) if ( r_logFile->integer ) @@ -499,23 +840,41 @@ class GLUniform1fv : protected GLUniform this->GetName(), _shader->GetName().c_str(), numFloats ) ); } #endif + + if ( _shader->UseMaterialSystem() && !_global ) { + memcpy( currentValue.data(), f, numFloats * sizeof( float ) ); + return; + } + glUniform1fv( p->uniformLocations[ _locationIndex ], numFloats, f ); } + + uint32_t* WriteToBuffer( uint32_t* buffer ) override { + memcpy( buffer, currentValue.data(), currentValue.size() * sizeof( float ) ); + return buffer + _components; + } + + private: + std::vector currentValue; }; class GLUniform2f : protected GLUniform { protected: GLUniform2f( GLShader *shader, const char *name ) : - GLUniform( shader, name ) + GLUniform( shader, name, "vec2", 2, 2, false ) { + currentValue[0] = 0.0; + currentValue[1] = 0.0; } inline void SetValue( const vec2_t v ) { shaderProgram_t *p = _shader->GetProgram(); - ASSERT_EQ(p, glState.currentProgram); + if ( _global || !_shader->UseMaterialSystem() ) { + ASSERT_EQ( p, glState.currentProgram ); + } #if defined( LOG_GLSL_UNIFORMS ) if ( r_logFile->integer ) @@ -524,6 +883,12 @@ class GLUniform2f : protected GLUniform this->GetName(), _shader->GetName().c_str(), v[ 0 ], v[ 1 ] ) ); } #endif + + if ( _shader->UseMaterialSystem() && !_global ) { + Vector2Copy( v, currentValue ); + return; + } + #if defined( USE_UNIFORM_FIREWALL ) vec2_t *firewall = ( vec2_t * ) &p->uniformFirewall[ _firewallIndex ]; @@ -542,21 +907,34 @@ class GLUniform2f : protected GLUniform { return sizeof( vec2_t ); } + + uint32_t* WriteToBuffer( uint32_t* buffer ) override { + memcpy( buffer, ¤tValue, sizeof( vec2_t ) ); + return buffer + 2; + } + + private: + vec2_t currentValue; }; class GLUniform3f : protected GLUniform { protected: - GLUniform3f( GLShader *shader, const char *name ) : - GLUniform( shader, name ) + GLUniform3f( GLShader *shader, const char *name, const bool global = false ) : + GLUniform( shader, name, "vec3", 3, 4, global ) { + currentValue[0] = 0.0; + currentValue[1] = 0.0; + currentValue[2] = 0.0; } inline void SetValue( const vec3_t v ) { shaderProgram_t *p = _shader->GetProgram(); - ASSERT_EQ(p, glState.currentProgram); + if ( _global || !_shader->UseMaterialSystem() ) { + ASSERT_EQ( p, glState.currentProgram ); + } #if defined( LOG_GLSL_UNIFORMS ) if ( r_logFile->integer ) @@ -565,6 +943,12 @@ class GLUniform3f : protected GLUniform this->GetName(), _shader->GetName().c_str(), v[ 0 ], v[ 1 ], v[ 2 ] ) ); } #endif + + if ( _shader->UseMaterialSystem() && !_global ) { + VectorCopy( v, currentValue ); + return; + } + #if defined( USE_UNIFORM_FIREWALL ) vec3_t *firewall = ( vec3_t * ) &p->uniformFirewall[ _firewallIndex ]; @@ -582,21 +966,35 @@ class GLUniform3f : protected GLUniform { return sizeof( vec3_t ); } + + uint32_t* WriteToBuffer( uint32_t* buffer ) override { + memcpy( buffer, ¤tValue, sizeof( vec3_t ) ); + return buffer + 4; // vec3 is aligned to 4 components + } + + private: + vec3_t currentValue; }; class GLUniform4f : protected GLUniform { protected: GLUniform4f( GLShader *shader, const char *name ) : - GLUniform( shader, name ) + GLUniform( shader, name, "vec4", 4, 4, false ) { + currentValue[0] = 0.0; + currentValue[1] = 0.0; + currentValue[2] = 0.0; + currentValue[3] = 0.0; } inline void SetValue( const vec4_t v ) { shaderProgram_t *p = _shader->GetProgram(); - ASSERT_EQ(p, glState.currentProgram); + if ( _global || !_shader->UseMaterialSystem() ) { + ASSERT_EQ( p, glState.currentProgram ); + } #if defined( LOG_GLSL_UNIFORMS ) if ( r_logFile->integer ) @@ -605,6 +1003,12 @@ class GLUniform4f : protected GLUniform this->GetName(), _shader->GetName().c_str(), v[ 0 ], v[ 1 ], v[ 2 ], v[ 3 ] ) ); } #endif + + if ( _shader->UseMaterialSystem() && !_global ) { + Vector4Copy( v, currentValue ); + return; + } + #if defined( USE_UNIFORM_FIREWALL ) vec4_t *firewall = ( vec4_t * ) &p->uniformFirewall[ _firewallIndex ]; @@ -622,21 +1026,32 @@ class GLUniform4f : protected GLUniform { return sizeof( vec4_t ); } + + uint32_t* WriteToBuffer( uint32_t* buffer ) override { + memcpy( buffer, ¤tValue, sizeof( vec4_t ) ); + return buffer + 4; + } + + private: + vec4_t currentValue; }; class GLUniform4fv : protected GLUniform { protected: - GLUniform4fv( GLShader *shader, const char *name ) : - GLUniform( shader, name ) + GLUniform4fv( GLShader *shader, const char *name, const int size ) : + GLUniform( shader, name, "vec4", 4, 4, false, size ) { + currentValue.reserve( size ); } inline void SetValue( int numV, vec4_t *v ) { shaderProgram_t *p = _shader->GetProgram(); - ASSERT_EQ(p, glState.currentProgram); + if ( _global || !_shader->UseMaterialSystem() ) { + ASSERT_EQ( p, glState.currentProgram ); + } #if defined( LOG_GLSL_UNIFORMS ) if ( r_logFile->integer ) @@ -645,23 +1060,41 @@ class GLUniform4fv : protected GLUniform this->GetName(), _shader->GetName().c_str(), numV ) ); } #endif + + if ( _shader->UseMaterialSystem() && !_global ) { + memcpy( currentValue.data(), v, numV * sizeof( vec4_t ) ); + return; + } + glUniform4fv( p->uniformLocations[ _locationIndex ], numV, &v[ 0 ][ 0 ] ); } + + public: + uint32_t* WriteToBuffer( uint32_t* buffer ) override { + memcpy( buffer, currentValue.data(), currentValue.size() * sizeof( float ) ); + return buffer + 4 * _components; + } + + private: + std::vector currentValue; }; class GLUniformMatrix4f : protected GLUniform { protected: - GLUniformMatrix4f( GLShader *shader, const char *name ) : - GLUniform( shader, name ) + GLUniformMatrix4f( GLShader *shader, const char *name, const bool global = false ) : + GLUniform( shader, name, "mat4", 16, 4, global ) { + MatrixIdentity( currentValue ); } inline void SetValue( GLboolean transpose, const matrix_t m ) { shaderProgram_t *p = _shader->GetProgram(); - ASSERT_EQ(p, glState.currentProgram); + if ( _global || !_shader->UseMaterialSystem() ) { + ASSERT_EQ( p, glState.currentProgram ); + } #if defined( LOG_GLSL_UNIFORMS ) if ( r_logFile->integer ) @@ -672,6 +1105,12 @@ class GLUniformMatrix4f : protected GLUniform m[ 13 ], m[ 14 ], m[ 15 ] ) ); } #endif + + if ( _shader->UseMaterialSystem() && !_global ) { + MatrixCopy( m, currentValue ); + return; + } + #if defined( USE_UNIFORM_FIREWALL ) matrix_t *firewall = ( matrix_t * ) &p->uniformFirewall[ _firewallIndex ]; @@ -689,21 +1128,32 @@ class GLUniformMatrix4f : protected GLUniform { return sizeof( matrix_t ); } + + uint32_t* WriteToBuffer( uint32_t* buffer ) override { + memcpy( buffer, ¤tValue, sizeof( matrix_t ) ); + return buffer + 16; + } + + private: + matrix_t currentValue; }; class GLUniformMatrix4fv : protected GLUniform { protected: - GLUniformMatrix4fv( GLShader *shader, const char *name ) : - GLUniform( shader, name ) + GLUniformMatrix4fv( GLShader *shader, const char *name, const int size ) : + GLUniform( shader, name, "mat4", 16, 4, false, size ) { + currentValue.reserve( size * 16 ); } inline void SetValue( int numMatrices, GLboolean transpose, const matrix_t *m ) { shaderProgram_t *p = _shader->GetProgram(); - ASSERT_EQ(p, glState.currentProgram); + if ( _global || !_shader->UseMaterialSystem() ) { + ASSERT_EQ( p, glState.currentProgram ); + } #if defined( LOG_GLSL_UNIFORMS ) if ( r_logFile->integer ) @@ -712,15 +1162,30 @@ class GLUniformMatrix4fv : protected GLUniform this->GetName(), _shader->GetName().c_str(), numMatrices, transpose ) ); } #endif + + if ( _shader->UseMaterialSystem() && !_global ) { + memcpy( currentValue.data(), m, numMatrices * sizeof( matrix_t ) ); + return; + } + glUniformMatrix4fv( p->uniformLocations[ _locationIndex ], numMatrices, transpose, &m[ 0 ][ 0 ] ); } + + public: + uint32_t* WriteToBuffer( uint32_t* buffer ) override { + memcpy( buffer, currentValue.data(), currentValue.size() * sizeof( float ) ); + return buffer + 16 * _components; + } + + private: + std::vector currentValue; }; class GLUniformMatrix34fv : protected GLUniform { protected: - GLUniformMatrix34fv( GLShader *shader, const char *name ) : - GLUniform( shader, name ) + GLUniformMatrix34fv( GLShader *shader, const char *name, const int size ) : + GLUniform( shader, name, "mat3x4", 12, 4, false, size ) { } @@ -728,7 +1193,10 @@ class GLUniformMatrix34fv : protected GLUniform { shaderProgram_t *p = _shader->GetProgram(); - ASSERT_EQ(p, glState.currentProgram); + if ( _global || !_shader->UseMaterialSystem() ) { + ASSERT_EQ( p, glState.currentProgram ); + } + #if defined( LOG_GLSL_UNIFORMS ) if ( r_logFile->integer ) { @@ -736,8 +1204,23 @@ class GLUniformMatrix34fv : protected GLUniform this->GetName(), _shader->GetName().c_str(), numMatrices, transpose ) ); } #endif + + if ( _shader->UseMaterialSystem() && !_global ) { + memcpy( currentValue.data(), m, numMatrices * sizeof( matrix_t ) ); + return; + } + glUniformMatrix3x4fv( p->uniformLocations[ _locationIndex ], numMatrices, transpose, m ); } + + public: + uint32_t* WriteToBuffer( uint32_t* buffer ) override { + memcpy( buffer, currentValue.data(), currentValue.size() * sizeof( float ) ); + return buffer + 12 * _components; + } + + private: + std::vector currentValue; }; class GLUniformBlock @@ -783,16 +1266,129 @@ class GLUniformBlock } }; -class GLCompileMacro -{ -private: - int _bit; +class GLSSBO { + public: + std::string _name; + const GLuint _bindingPoint; -protected: - GLShader *_shader; + GLSSBO( const char* name, const GLuint bindingPoint ) : + _name( name ), + _bindingPoint( bindingPoint ) { + } - GLCompileMacro( GLShader *shader ) : - _shader( shader ) + public: + const char* GetName() { + return _name.c_str(); + } + + void BindBufferBase() { + glBindBufferBase( GL_SHADER_STORAGE_BUFFER, _bindingPoint, handle ); + } + + void BindBuffer() { + glBindBuffer( GL_SHADER_STORAGE_BUFFER, handle ); + } + + uint32_t* MapBufferRange( const GLuint count ) { + if ( !mapped ) { + mapped = true; + data = ( uint32_t* ) glMapBufferRange( GL_SHADER_STORAGE_BUFFER, + 0, count * sizeof( uint32_t ), + GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT ); + } + + return data; + } + + uint32_t* MapBufferRange( const GLuint offset, const GLuint count ) { + if ( !mapped ) { + mapped = true; + data = ( uint32_t* ) glMapBufferRange( GL_SHADER_STORAGE_BUFFER, + offset * sizeof( uint32_t ), count * sizeof( uint32_t ), + GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT ); + } + + return data; + } + + void UnmapBuffer() { + mapped = false; + glUnmapBuffer( GL_SHADER_STORAGE_BUFFER ); + } + + void GenBuffer() { + glGenBuffers( 1, &handle ); + } + + void DelBuffer() { + glDeleteBuffers( 1, &handle ); + } + + private: + GLuint handle; + bool mapped = false; + uint32_t* data; +}; + +class GLIndirectBuffer { + public: + + struct GLIndirectCommand { + GLuint count; + GLuint instanceCount; + GLuint firstIndex; + GLint baseVertex; + GLuint baseInstance; + }; + + std::string _name; + + GLIndirectBuffer( const char* name ) : + _name( name ) { + } + + public: + + const char* GetName() { + return _name.c_str(); + } + + void BindBuffer() { + glBindBuffer( GL_DRAW_INDIRECT_BUFFER, handle ); + } + + GLIndirectCommand* MapBufferRange( const GLuint count ) { + return (GLIndirectCommand*) glMapBufferRange( GL_DRAW_INDIRECT_BUFFER, + 0, count * sizeof( GLIndirectCommand ), + GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT ); + } + + void UnmapBuffer() const { + glUnmapBuffer( GL_DRAW_INDIRECT_BUFFER ); + } + + void GenBuffer() { + glGenBuffers( 1, &handle ); + } + + void DelBuffer() { + glDeleteBuffers( 1, &handle ); + } + + private: + GLuint handle; +}; + +class GLCompileMacro +{ +private: + int _bit; + +protected: + GLShader *_shader; + + GLCompileMacro( GLShader *shader ) : + _shader( shader ) { _bit = BIT( _shader->GetNumOfCompiledMacros() ); _shader->RegisterCompileMacro( this ); @@ -1191,140 +1787,716 @@ class GLCompileMacro_USE_REFLECTIVE_SPECULAR : return EGLCompileMacro::USE_REFLECTIVE_SPECULAR; } - void SetReflectiveSpecular( bool enable ) - { - SetMacro( enable ); + void SetReflectiveSpecular( bool enable ) + { + SetMacro( enable ); + } +}; + +class GLCompileMacro_LIGHT_DIRECTIONAL : + GLCompileMacro +{ +public: + GLCompileMacro_LIGHT_DIRECTIONAL( GLShader *shader ) : + GLCompileMacro( shader ) + { + } + + const char *GetName() const override + { + return "LIGHT_DIRECTIONAL"; + } + + EGLCompileMacro GetType() const override + { + return EGLCompileMacro::LIGHT_DIRECTIONAL; + } + + void SetMacro_LIGHT_DIRECTIONAL( bool enable ) + { + SetMacro( enable ); + } +}; + +class GLCompileMacro_USE_SHADOWING : + GLCompileMacro +{ +public: + GLCompileMacro_USE_SHADOWING( GLShader *shader ) : + GLCompileMacro( shader ) + { + } + + const char *GetName() const override + { + return "USE_SHADOWING"; + } + + EGLCompileMacro GetType() const override + { + return EGLCompileMacro::USE_SHADOWING; + } + + void SetShadowing( bool enable ) + { + SetMacro( enable ); + } +}; + +class GLCompileMacro_USE_DEPTH_FADE : + GLCompileMacro +{ +public: + GLCompileMacro_USE_DEPTH_FADE( GLShader *shader ) : + GLCompileMacro( shader ) + { + } + + const char *GetName() const override + { + return "USE_DEPTH_FADE"; + } + + bool HasConflictingMacros(size_t permutation, const std::vector ¯os) const override; + EGLCompileMacro GetType() const override + { + return EGLCompileMacro::USE_DEPTH_FADE; + } + + void SetDepthFade( bool enable ) + { + SetMacro( enable ); + } +}; + +class GLCompileMacro_USE_PHYSICAL_MAPPING : + GLCompileMacro +{ +public: + GLCompileMacro_USE_PHYSICAL_MAPPING( GLShader *shader ) : + GLCompileMacro( shader ) + { + } + + const char *GetName() const override + { + return "USE_PHYSICAL_MAPPING"; + } + + EGLCompileMacro GetType() const override + { + return USE_PHYSICAL_MAPPING; + } + + void SetPhysicalShading( bool enable ) + { + SetMacro( enable ); + } +}; + +class u_LightFactor : + GLUniform1f +{ +public: + u_LightFactor( GLShader *shader ) : + GLUniform1f( shader, "u_LightFactor" ) + { + } + + void SetUniform_LightFactor( const float lightFactor ) + { + this->SetValue( lightFactor ); + } +}; + +class u_InverseLightFactor : + GLUniform1f +{ +public: + u_InverseLightFactor( GLShader *shader ) : + GLUniform1f( shader, "u_InverseLightFactor" ) + { + } + + void SetUniform_InverseLightFactor( const float inverseLightFactor ) + { + this->SetValue( inverseLightFactor ); + } +}; + +class u_ColorMap : + GLUniformSampler2D { + public: + u_ColorMap( GLShader* shader ) : + GLUniformSampler2D( shader, "u_ColorMap" ) { + } + + void SetUniform_ColorMapBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_ColorMap() { + return this->GetLocation(); + } +}; + +class u_ColorMap3D : + GLUniformSampler3D { + public: + u_ColorMap3D( GLShader* shader ) : + GLUniformSampler3D( shader, "u_ColorMap3D" ) { + } + + void SetUniform_ColorMap3DBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_ColorMap3D() { + return this->GetLocation(); + } +}; + +class u_ColorMapCube : + GLUniformSamplerCube { + public: + u_ColorMapCube( GLShader* shader ) : + GLUniformSamplerCube( shader, "u_ColorMapCube" ) { + } + + void SetUniform_ColorMapCubeBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_ColorMapCube() { + return this->GetLocation(); + } +}; + +class u_DepthMap : + GLUniformSampler2D { + public: + u_DepthMap( GLShader* shader ) : + GLUniformSampler2D( shader, "u_DepthMap" ) { + } + + void SetUniform_DepthMapBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_DepthMap() { + return this->GetLocation(); + } +}; + +class u_DiffuseMap : + GLUniformSampler2D { + public: + u_DiffuseMap( GLShader* shader ) : + GLUniformSampler2D( shader, "u_DiffuseMap" ) { + } + + void SetUniform_DiffuseMapBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_DiffuseMap() { + return this->GetLocation(); + } +}; + +class u_HeightMap : + GLUniformSampler2D { + public: + u_HeightMap( GLShader* shader ) : + GLUniformSampler2D( shader, "u_HeightMap" ) { + } + + void SetUniform_HeightMapBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_HeightMap() { + return this->GetLocation(); + } +}; + +class u_NormalMap : + GLUniformSampler2D { + public: + u_NormalMap( GLShader* shader ) : + GLUniformSampler2D( shader, "u_NormalMap" ) { + } + + void SetUniform_NormalMapBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_NormalMap() { + return this->GetLocation(); + } +}; + +class u_MaterialMap : + GLUniformSampler2D { + public: + u_MaterialMap( GLShader* shader ) : + GLUniformSampler2D( shader, "u_MaterialMap" ) { + } + + void SetUniform_MaterialMapBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_MaterialMap() { + return this->GetLocation(); + } +}; + +class u_LightMap : + GLUniformSampler { + public: + u_LightMap( GLShader* shader ) : + GLUniformSampler( shader, "u_LightMap", "sampler2D", 1 ) { + } + + void SetUniform_LightMapBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_LightMap() { + return this->GetLocation(); + } +}; + +class u_DeluxeMap : + GLUniformSampler { + public: + u_DeluxeMap( GLShader* shader ) : + GLUniformSampler( shader, "u_DeluxeMap", "sampler2D", 1 ) { + } + + void SetUniform_DeluxeMapBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_DeluxeMap() { + return this->GetLocation(); + } +}; + +class u_GlowMap : + GLUniformSampler2D { + public: + u_GlowMap( GLShader* shader ) : + GLUniformSampler2D( shader, "u_GlowMap" ) { + } + + void SetUniform_GlowMapBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_GlowMap() { + return this->GetLocation(); + } +}; + +class u_RandomMap : + GLUniformSampler2D { + public: + u_RandomMap( GLShader* shader ) : + GLUniformSampler2D( shader, "u_RandomMap" ) { + } + + void SetUniform_RandomMapBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_RandomMap() { + return this->GetLocation(); + } +}; + +class u_PortalMap : + GLUniformSampler2D { + public: + u_PortalMap( GLShader* shader ) : + GLUniformSampler2D( shader, "u_PortalMap" ) { + } + + void SetUniform_PortalMapBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_PortalMap() { + return this->GetLocation(); + } +}; + +class u_CloudMap : + GLUniformSampler2D { + public: + u_CloudMap( GLShader* shader ) : + GLUniformSampler2D( shader, "u_CloudMap" ) { + } + + void SetUniform_CloudMapBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_CloudMap() { + return this->GetLocation(); + } +}; + +class u_LightsTexture : + GLUniformSampler2D { + public: + u_LightsTexture( GLShader* shader ) : + GLUniformSampler2D( shader, "u_LightsTexture" ) { + } + + void SetUniform_LightsTextureBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_LightsTexture() { + return this->GetLocation(); + } +}; + +class u_LightTiles : + GLUniformSampler3D { + public: + u_LightTiles( GLShader* shader ) : + GLUniformSampler3D( shader, "u_LightTiles" ) { + } + + void SetUniform_LightTilesBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_LightTiles() { + return this->GetLocation(); + } +}; + +class u_LightTilesInt : + GLUniformUSampler3D { + public: + u_LightTilesInt( GLShader* shader ) : + GLUniformUSampler3D( shader, "u_LightTilesInt" ) { + } + + void SetUniform_LightTilesIntBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_LightTilesInt() { + return this->GetLocation(); + } +}; + +class u_LightGrid1 : + GLUniformSampler3D { + public: + u_LightGrid1( GLShader* shader ) : + GLUniformSampler3D( shader, "u_LightGrid1" ) { + } + + void SetUniform_LightGrid1Bindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_LightGrid1() { + return this->GetLocation(); + } +}; + +class u_LightGrid2 : + GLUniformSampler3D { + public: + u_LightGrid2( GLShader* shader ) : + GLUniformSampler3D( shader, "u_LightGrid2" ) { + } + + void SetUniform_LightGrid2Bindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_LightGrid2() { + return this->GetLocation(); + } +}; + +class u_EnvironmentMap0 : + GLUniformSamplerCube { + public: + u_EnvironmentMap0( GLShader* shader ) : + GLUniformSamplerCube( shader, "u_EnvironmentMap0" ) { + } + + void SetUniform_EnvironmentMap0Bindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_EnvironmentMap0() { + return this->GetLocation(); + } +}; + +class u_EnvironmentMap1 : + GLUniformSamplerCube { + public: + u_EnvironmentMap1( GLShader* shader ) : + GLUniformSamplerCube( shader, "u_EnvironmentMap1" ) { + } + + void SetUniform_EnvironmentMap1Bindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_EnvironmentMap1() { + return this->GetLocation(); + } +}; + +class u_CurrentMap : + GLUniformSampler2D { + public: + u_CurrentMap( GLShader* shader ) : + GLUniformSampler2D( shader, "u_CurrentMap" ) { + } + + void SetUniform_CurrentMapBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_CurrentMap() { + return this->GetLocation(); + } +}; + +class u_AttenuationMapXY : + GLUniformSampler2D { + public: + u_AttenuationMapXY( GLShader* shader ) : + GLUniformSampler2D( shader, "u_AttenuationMapXY" ) { + } + + void SetUniform_AttenuationMapXYBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_AttenuationMapXY() { + return this->GetLocation(); + } +}; + +class u_AttenuationMapZ : + GLUniformSampler2D { + public: + u_AttenuationMapZ( GLShader* shader ) : + GLUniformSampler2D( shader, "u_AttenuationMapZ" ) { + } + + void SetUniform_AttenuationMapZBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_AttenuationMapZ() { + return this->GetLocation(); + } +}; + +class u_ShadowMap : + GLUniformSampler2D { + public: + u_ShadowMap( GLShader* shader ) : + GLUniformSampler2D( shader, "u_ShadowMap" ) { + } + + void SetUniform_ShadowMapBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_ShadowMap() { + return this->GetLocation(); + } +}; + +class u_ShadowMap0 : + GLUniformSampler2D { + public: + u_ShadowMap0( GLShader* shader ) : + GLUniformSampler2D( shader, "u_ShadowMap0" ) { + } + + void SetUniform_ShadowMap0Bindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_ShadowMap0() { + return this->GetLocation(); + } +}; + +class u_ShadowMap1 : + GLUniformSampler2D { + public: + u_ShadowMap1( GLShader* shader ) : + GLUniformSampler2D( shader, "u_ShadowMap1" ) { + } + + void SetUniform_ShadowMap1Bindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_ShadowMap1() { + return this->GetLocation(); + } +}; + +class u_ShadowMap2 : + GLUniformSampler2D { + public: + u_ShadowMap2( GLShader* shader ) : + GLUniformSampler2D( shader, "u_ShadowMap2" ) { + } + + void SetUniform_ShadowMap2Bindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_ShadowMap2() { + return this->GetLocation(); + } +}; + +class u_ShadowMap3 : + GLUniformSampler2D { + public: + u_ShadowMap3( GLShader* shader ) : + GLUniformSampler2D( shader, "u_ShadowMap3" ) { + } + + void SetUniform_ShadowMap3Bindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); } -}; -class GLCompileMacro_LIGHT_DIRECTIONAL : - GLCompileMacro -{ -public: - GLCompileMacro_LIGHT_DIRECTIONAL( GLShader *shader ) : - GLCompileMacro( shader ) - { + GLint GetUniformLocation_ShadowMap3() { + return this->GetLocation(); } +}; - const char *GetName() const override - { - return "LIGHT_DIRECTIONAL"; +class u_ShadowMap4 : + GLUniformSampler2D { + public: + u_ShadowMap4( GLShader* shader ) : + GLUniformSampler2D( shader, "u_ShadowMap4" ) { } - EGLCompileMacro GetType() const override - { - return EGLCompileMacro::LIGHT_DIRECTIONAL; + void SetUniform_ShadowMap4Bindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); } - void SetMacro_LIGHT_DIRECTIONAL( bool enable ) - { - SetMacro( enable ); + GLint GetUniformLocation_ShadowMap4() { + return this->GetLocation(); } }; -class GLCompileMacro_USE_SHADOWING : - GLCompileMacro -{ -public: - GLCompileMacro_USE_SHADOWING( GLShader *shader ) : - GLCompileMacro( shader ) - { +class u_ShadowClipMap : + GLUniformSampler2D { + public: + u_ShadowClipMap( GLShader* shader ) : + GLUniformSampler2D( shader, "u_ShadowClipMap" ) { } - const char *GetName() const override - { - return "USE_SHADOWING"; + void SetUniform_ShadowClipMapBindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); } - EGLCompileMacro GetType() const override - { - return EGLCompileMacro::USE_SHADOWING; + GLint GetUniformLocation_ShadowClipMap() { + return this->GetLocation(); } +}; - void SetShadowing( bool enable ) - { - SetMacro( enable ); +class u_ShadowClipMap0 : + GLUniformSampler2D { + public: + u_ShadowClipMap0( GLShader* shader ) : + GLUniformSampler2D( shader, "u_ShadowClipMap0" ) { } -}; -class GLCompileMacro_USE_DEPTH_FADE : - GLCompileMacro -{ -public: - GLCompileMacro_USE_DEPTH_FADE( GLShader *shader ) : - GLCompileMacro( shader ) - { + void SetUniform_ShadowClipMap0Bindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); } - const char *GetName() const override - { - return "USE_DEPTH_FADE"; + GLint GetUniformLocation_ShadowClipMap0() { + return this->GetLocation(); } +}; - bool HasConflictingMacros(size_t permutation, const std::vector ¯os) const override; - EGLCompileMacro GetType() const override - { - return EGLCompileMacro::USE_DEPTH_FADE; +class u_ShadowClipMap1 : + GLUniformSampler2D { + public: + u_ShadowClipMap1( GLShader* shader ) : + GLUniformSampler2D( shader, "u_ShadowClipMap1" ) { } - void SetDepthFade( bool enable ) - { - SetMacro( enable ); + void SetUniform_ShadowClipMap1Bindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); } -}; -class GLCompileMacro_USE_PHYSICAL_MAPPING : - GLCompileMacro -{ -public: - GLCompileMacro_USE_PHYSICAL_MAPPING( GLShader *shader ) : - GLCompileMacro( shader ) - { + GLint GetUniformLocation_ShadowClipMap1() { + return this->GetLocation(); } +}; - const char *GetName() const override - { - return "USE_PHYSICAL_MAPPING"; +class u_ShadowClipMap2 : + GLUniformSampler2D { + public: + u_ShadowClipMap2( GLShader* shader ) : + GLUniformSampler2D( shader, "u_ShadowClipMap2" ) { } - EGLCompileMacro GetType() const override - { - return USE_PHYSICAL_MAPPING; + void SetUniform_ShadowClipMap2Bindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); } - void SetPhysicalShading( bool enable ) - { - SetMacro( enable ); + GLint GetUniformLocation_ShadowClipMap2() { + return this->GetLocation(); } }; -class u_LightFactor : - GLUniform1f -{ -public: - u_LightFactor( GLShader *shader ) : - GLUniform1f( shader, "u_LightFactor" ) - { +class u_ShadowClipMap3 : + GLUniformSampler2D { + public: + u_ShadowClipMap3( GLShader* shader ) : + GLUniformSampler2D( shader, "u_ShadowClipMap3" ) { } - void SetUniform_LightFactor( const float lightFactor ) - { - this->SetValue( lightFactor ); + void SetUniform_ShadowClipMap3Bindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_ShadowClipMap3() { + return this->GetLocation(); } }; -class u_InverseLightFactor : - GLUniform1f -{ -public: - u_InverseLightFactor( GLShader *shader ) : - GLUniform1f( shader, "u_InverseLightFactor" ) - { +class u_ShadowClipMap4 : + GLUniformSampler2D { + public: + u_ShadowClipMap4( GLShader* shader ) : + GLUniformSampler2D( shader, "u_ShadowClipMap4" ) { } - void SetUniform_InverseLightFactor( const float inverseLightFactor ) - { - this->SetValue( inverseLightFactor ); + void SetUniform_ShadowClipMap4Bindless( GLuint64 bindlessHandle ) { + this->SetValueBindless( bindlessHandle ); + } + + GLint GetUniformLocation_ShadowClipMap4() { + return this->GetLocation(); } }; @@ -1406,7 +2578,7 @@ class u_ViewOrigin : { public: u_ViewOrigin( GLShader *shader ) : - GLUniform3f( shader, "u_ViewOrigin" ) + GLUniform3f( shader, "u_ViewOrigin", true ) { } @@ -1421,7 +2593,7 @@ class u_ViewUp : { public: u_ViewUp( GLShader *shader ) : - GLUniform3f( shader, "u_ViewUp" ) + GLUniform3f( shader, "u_ViewUp", true ) { } @@ -1526,7 +2698,7 @@ class u_LightFrustum : { public: u_LightFrustum( GLShader *shader ) : - GLUniform4fv( shader, "u_LightFrustum" ) + GLUniform4fv( shader, "u_LightFrustum", 6 ) { } @@ -1571,7 +2743,7 @@ class u_ShadowMatrix : { public: u_ShadowMatrix( GLShader *shader ) : - GLUniformMatrix4fv( shader, "u_ShadowMatrix" ) + GLUniformMatrix4fv( shader, "u_ShadowMatrix", MAX_SHADOWMAPS ) { } @@ -1735,7 +2907,7 @@ class u_ModelMatrix : { public: u_ModelMatrix( GLShader *shader ) : - GLUniformMatrix4f( shader, "u_ModelMatrix" ) + GLUniformMatrix4f( shader, "u_ModelMatrix", true ) { } @@ -1810,7 +2982,7 @@ class u_ModelViewProjectionMatrix : { public: u_ModelViewProjectionMatrix( GLShader *shader ) : - GLUniformMatrix4f( shader, "u_ModelViewProjectionMatrix" ) + GLUniformMatrix4f( shader, "u_ModelViewProjectionMatrix", true ) { } @@ -1836,10 +3008,10 @@ class u_UnprojectMatrix : }; class u_UseCloudMap : - GLUniform1i { + GLUniform1Bool { public: u_UseCloudMap( GLShader* shader ) : - GLUniform1i( shader, "u_UseCloudMap" ) { + GLUniform1Bool( shader, "u_UseCloudMap" ) { } void SetUniform_UseCloudMap( const bool useCloudMap ) { @@ -1852,7 +3024,7 @@ class u_Bones : { public: u_Bones( GLShader *shader ) : - GLUniform4fv( shader, "u_Bones" ) + GLUniform4fv( shader, "u_Bones", MAX_BONES * 0 + 1 ) { } @@ -2176,7 +3348,7 @@ class u_LightGridOrigin : { public: u_LightGridOrigin( GLShader *shader ) : - GLUniform3f( shader, "u_LightGridOrigin" ) + GLUniform3f( shader, "u_LightGridOrigin", true ) { } @@ -2191,7 +3363,7 @@ class u_LightGridScale : { public: u_LightGridScale( GLShader *shader ) : - GLUniform3f( shader, "u_LightGridScale" ) + GLUniform3f( shader, "u_LightGridScale", true ) { } @@ -2233,7 +3405,7 @@ class u_numLights : { public: u_numLights( GLShader *shader ) : - GLUniform1i( shader, "u_numLights" ) + GLUniform1i( shader, "u_numLights", true ) { } @@ -2279,6 +3451,8 @@ class u_Lights : // TODO: Write a more minimal 2D rendering shader. class GLShader_generic2D : public GLShader, + public u_ColorMap, + public u_DepthMap, public u_TextureMatrix, public u_AlphaThreshold, public u_ModelMatrix, @@ -2298,6 +3472,8 @@ class GLShader_generic2D : class GLShader_generic : public GLShader, + public u_ColorMap, + public u_DepthMap, public u_TextureMatrix, public u_ViewOrigin, public u_ViewUp, @@ -2324,8 +3500,51 @@ class GLShader_generic : void SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) override; }; +class GLShader_genericMaterial : + public GLShader, + public u_ColorMap, + public u_DepthMap, + public u_TextureMatrix, + public u_ViewOrigin, + public u_ViewUp, + public u_AlphaThreshold, + public u_ModelMatrix, + public u_ModelViewProjectionMatrix, + public u_InverseLightFactor, + public u_ColorModulate, + public u_Color, + // public u_Bones, + public u_VertexInterpolation, + public u_DepthScale, + public GLDeformStage, + // public GLCompileMacro_USE_VERTEX_SKINNING, + public GLCompileMacro_USE_VERTEX_ANIMATION, + public GLCompileMacro_USE_VERTEX_SPRITE, + public GLCompileMacro_USE_TCGEN_ENVIRONMENT, + public GLCompileMacro_USE_TCGEN_LIGHTMAP, + public GLCompileMacro_USE_DEPTH_FADE { + public: + GLShader_genericMaterial( GLShaderManager* manager ); + void BuildShaderVertexLibNames( std::string& vertexInlines ) override; + void SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) override; +}; + class GLShader_lightMapping : public GLShader, + public u_DiffuseMap, + public u_NormalMap, + public u_HeightMap, + public u_MaterialMap, + public u_LightMap, + public u_DeluxeMap, + public u_GlowMap, + public u_EnvironmentMap0, + public u_EnvironmentMap1, + public u_LightGrid1, + public u_LightGrid2, + public u_LightTiles, + public u_LightTilesInt, + public u_LightsTexture, public u_TextureMatrix, public u_SpecularExponent, public u_ColorModulate, @@ -2365,8 +3584,69 @@ class GLShader_lightMapping : void SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) override; }; +class GLShader_lightMappingMaterial : + public GLShader, + public u_DiffuseMap, + public u_NormalMap, + public u_HeightMap, + public u_MaterialMap, + public u_LightMap, + public u_DeluxeMap, + public u_GlowMap, + public u_EnvironmentMap0, + public u_EnvironmentMap1, + public u_LightGrid1, + public u_LightGrid2, + public u_LightTilesInt, + public u_TextureMatrix, + public u_SpecularExponent, + public u_ColorModulate, + public u_Color, + public u_AlphaThreshold, + public u_ViewOrigin, + public u_ModelMatrix, + public u_ModelViewProjectionMatrix, + public u_InverseLightFactor, + // public u_Bones, + public u_VertexInterpolation, + public u_ReliefDepthScale, + public u_ReliefOffsetBias, + public u_NormalScale, + public u_EnvironmentInterpolation, + public u_LightGridOrigin, + public u_LightGridScale, + public u_numLights, + public u_Lights, + public GLDeformStage, + public GLCompileMacro_USE_BSP_SURFACE, + // public GLCompileMacro_USE_VERTEX_SKINNING, + public GLCompileMacro_USE_VERTEX_ANIMATION, + public GLCompileMacro_USE_DELUXE_MAPPING, + public GLCompileMacro_USE_GRID_LIGHTING, + public GLCompileMacro_USE_GRID_DELUXE_MAPPING, + public GLCompileMacro_USE_HEIGHTMAP_IN_NORMALMAP, + public GLCompileMacro_USE_RELIEF_MAPPING, + public GLCompileMacro_USE_REFLECTIVE_SPECULAR, + public GLCompileMacro_USE_PHYSICAL_MAPPING { + public: + GLShader_lightMappingMaterial( GLShaderManager* manager ); + void BuildShaderVertexLibNames( std::string& vertexInlines ) override; + void BuildShaderFragmentLibNames( std::string& fragmentInlines ) override; + void BuildShaderCompileMacros( std::string& compileMacros ) override; + void SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) override; +}; + class GLShader_forwardLighting_omniXYZ : public GLShader, + public u_DiffuseMap, + public u_NormalMap, + public u_MaterialMap, + public u_AttenuationMapXY, + public u_AttenuationMapZ, + public u_ShadowMap, + public u_ShadowClipMap, + public u_RandomMap, + public u_HeightMap, public u_TextureMatrix, public u_SpecularExponent, public u_AlphaThreshold, @@ -2405,6 +3685,15 @@ class GLShader_forwardLighting_omniXYZ : class GLShader_forwardLighting_projXYZ : public GLShader, + public u_DiffuseMap, + public u_NormalMap, + public u_MaterialMap, + public u_AttenuationMapXY, + public u_AttenuationMapZ, + public u_ShadowMap0, + public u_ShadowClipMap0, + public u_RandomMap, + public u_HeightMap, public u_TextureMatrix, public u_SpecularExponent, public u_AlphaThreshold, @@ -2444,6 +3733,20 @@ class GLShader_forwardLighting_projXYZ : class GLShader_forwardLighting_directionalSun : public GLShader, + public u_DiffuseMap, + public u_NormalMap, + public u_MaterialMap, + public u_ShadowMap0, + public u_ShadowMap1, + public u_ShadowMap2, + public u_ShadowMap3, + public u_ShadowMap4, + public u_ShadowClipMap0, + public u_ShadowClipMap1, + public u_ShadowClipMap2, + public u_ShadowClipMap3, + public u_ShadowClipMap4, + public u_HeightMap, public u_TextureMatrix, public u_SpecularExponent, public u_AlphaThreshold, @@ -2485,6 +3788,7 @@ class GLShader_forwardLighting_directionalSun : class GLShader_shadowFill : public GLShader, + public u_ColorMap, public u_TextureMatrix, public u_ViewOrigin, public u_AlphaThreshold, @@ -2508,6 +3812,9 @@ class GLShader_shadowFill : class GLShader_reflection : public GLShader, + public u_ColorMap, + public u_NormalMap, + public u_HeightMap, public u_TextureMatrix, public u_ViewOrigin, public u_ModelMatrix, @@ -2531,8 +3838,37 @@ class GLShader_reflection : void SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) override; }; +class GLShader_reflectionMaterial : + public GLShader, + public u_ColorMap, + public u_NormalMap, + public u_HeightMap, + public u_TextureMatrix, + public u_ViewOrigin, + public u_ModelMatrix, + public u_ModelViewProjectionMatrix, + // public u_Bones, + public u_ReliefDepthScale, + public u_ReliefOffsetBias, + public u_NormalScale, + public u_VertexInterpolation, + public GLDeformStage, + // public GLCompileMacro_USE_VERTEX_SKINNING, + public GLCompileMacro_USE_VERTEX_ANIMATION, + public GLCompileMacro_USE_HEIGHTMAP_IN_NORMALMAP, + public GLCompileMacro_USE_RELIEF_MAPPING { + public: + GLShader_reflectionMaterial( GLShaderManager* manager ); + void BuildShaderVertexLibNames( std::string& vertexInlines ) override; + void BuildShaderFragmentLibNames( std::string& fragmentInlines ) override; + void BuildShaderCompileMacros( std::string& compileMacros ) override; + void SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) override; +}; + class GLShader_skybox : public GLShader, + public u_ColorMapCube, + public u_CloudMap, public u_TextureMatrix, public u_ViewOrigin, public u_CloudHeight, @@ -2548,8 +3884,27 @@ class GLShader_skybox : void SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) override; }; +class GLShader_skyboxMaterial : + public GLShader, + public u_ColorMapCube, + public u_CloudMap, + public u_TextureMatrix, + public u_ViewOrigin, + public u_CloudHeight, + public u_UseCloudMap, + public u_AlphaThreshold, + public u_ModelMatrix, + public u_ModelViewProjectionMatrix, + public u_InverseLightFactor, + public GLDeformStage { + public: + GLShader_skyboxMaterial( GLShaderManager* manager ); + void SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) override; +}; + class GLShader_fogQuake3 : public GLShader, + public u_ColorMap, public u_ModelMatrix, public u_ModelViewProjectionMatrix, public u_InverseLightFactor, @@ -2569,8 +3924,31 @@ class GLShader_fogQuake3 : void SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) override; }; +class GLShader_fogQuake3Material : + public GLShader, + public u_ColorMap, + public u_ModelMatrix, + public u_ModelViewProjectionMatrix, + public u_InverseLightFactor, + public u_Color, + // public u_Bones, + public u_VertexInterpolation, + public u_FogDistanceVector, + public u_FogDepthVector, + public u_FogEyeT, + public GLDeformStage, + // public GLCompileMacro_USE_VERTEX_SKINNING, + public GLCompileMacro_USE_VERTEX_ANIMATION { + public: + GLShader_fogQuake3Material( GLShaderManager* manager ); + void BuildShaderVertexLibNames( std::string& vertexInlines ) override; + void SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) override; +}; + class GLShader_fogGlobal : public GLShader, + public u_ColorMap, + public u_DepthMap, public u_ViewOrigin, public u_ViewMatrix, public u_ModelViewProjectionMatrix, @@ -2587,6 +3965,9 @@ class GLShader_fogGlobal : class GLShader_heatHaze : public GLShader, + public u_CurrentMap, + public u_NormalMap, + public u_HeightMap, public u_TextureMatrix, public u_ViewOrigin, public u_ViewUp, @@ -2612,8 +3993,38 @@ class GLShader_heatHaze : void SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) override; }; +class GLShader_heatHazeMaterial : + public GLShader, + public u_CurrentMap, + public u_NormalMap, + public u_HeightMap, + public u_TextureMatrix, + public u_ViewOrigin, + public u_ViewUp, + public u_DeformMagnitude, + public u_ModelMatrix, + public u_ModelViewProjectionMatrix, + public u_ModelViewMatrixTranspose, + public u_ProjectionMatrixTranspose, + public u_ColorModulate, + public u_Color, + // public u_Bones, + public u_NormalScale, + public u_VertexInterpolation, + public GLDeformStage, + // public GLCompileMacro_USE_VERTEX_SKINNING, + public GLCompileMacro_USE_VERTEX_ANIMATION, + public GLCompileMacro_USE_VERTEX_SPRITE { + public: + GLShader_heatHazeMaterial( GLShaderManager* manager ); + void BuildShaderVertexLibNames( std::string& vertexInlines ) override; + void BuildShaderFragmentLibNames( std::string& fragmentInlines ) override; + void SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) override; +}; + class GLShader_screen : public GLShader, + public u_CurrentMap, public u_ModelViewProjectionMatrix { public: @@ -2621,8 +4032,18 @@ class GLShader_screen : void SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) override; }; +class GLShader_screenMaterial : + public GLShader, + public u_CurrentMap, + public u_ModelViewProjectionMatrix { + public: + GLShader_screenMaterial( GLShaderManager* manager ); + void SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) override; +}; + class GLShader_portal : public GLShader, + public u_CurrentMap, public u_ModelViewMatrix, public u_ModelViewProjectionMatrix, public u_PortalRange @@ -2634,6 +4055,7 @@ class GLShader_portal : class GLShader_contrast : public GLShader, + public u_ColorMap, public u_ModelViewProjectionMatrix, public u_InverseLightFactor { @@ -2644,6 +4066,8 @@ class GLShader_contrast : class GLShader_cameraEffects : public GLShader, + public u_ColorMap3D, + public u_CurrentMap, public u_ColorModulate, public u_TextureMatrix, public u_ModelViewProjectionMatrix, @@ -2658,6 +4082,7 @@ class GLShader_cameraEffects : class GLShader_blurX : public GLShader, + public u_ColorMap, public u_ModelViewProjectionMatrix, public u_DeformMagnitude, public u_TexScale @@ -2669,6 +4094,7 @@ class GLShader_blurX : class GLShader_blurY : public GLShader, + public u_ColorMap, public u_ModelViewProjectionMatrix, public u_DeformMagnitude, public u_TexScale @@ -2680,6 +4106,7 @@ class GLShader_blurY : class GLShader_debugShadowMap : public GLShader, + public u_CurrentMap, public u_ModelViewProjectionMatrix { public: @@ -2689,6 +4116,13 @@ class GLShader_debugShadowMap : class GLShader_liquid : public GLShader, + public u_CurrentMap, + public u_DepthMap, + public u_NormalMap, + public u_PortalMap, + public u_LightGrid1, + public u_LightGrid2, + public u_HeightMap, public u_TextureMatrix, public u_ViewOrigin, public u_RefractionIndex, @@ -2715,8 +4149,45 @@ class GLShader_liquid : void SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) override; }; +class GLShader_liquidMaterial : + public GLShader, + public u_CurrentMap, + public u_DepthMap, + public u_NormalMap, + public u_PortalMap, + public u_LightGrid1, + public u_LightGrid2, + public u_HeightMap, + public u_TextureMatrix, + public u_ViewOrigin, + public u_RefractionIndex, + public u_ModelMatrix, + public u_ModelViewProjectionMatrix, + public u_UnprojectMatrix, + public u_FresnelPower, + public u_FresnelScale, + public u_FresnelBias, + public u_ReliefDepthScale, + public u_ReliefOffsetBias, + public u_NormalScale, + public u_FogDensity, + public u_FogColor, + public u_LightTilesInt, + public u_SpecularExponent, + public u_LightGridOrigin, + public u_LightGridScale, + public GLCompileMacro_USE_HEIGHTMAP_IN_NORMALMAP, + public GLCompileMacro_USE_RELIEF_MAPPING { + public: + GLShader_liquidMaterial( GLShaderManager* manager ); + void BuildShaderFragmentLibNames( std::string& fragmentInlines ) override; + void SetShaderProgramUniforms( shaderProgram_t* shaderProgram ) override; +}; + class GLShader_motionblur : public GLShader, + public u_ColorMap, + public u_DepthMap, public u_ModelViewProjectionMatrix, public u_blurVec { @@ -2727,6 +4198,7 @@ class GLShader_motionblur : class GLShader_ssao : public GLShader, + public u_DepthMap, public u_ModelViewProjectionMatrix, public u_UnprojectionParams, public u_zFar @@ -2738,6 +4210,7 @@ class GLShader_ssao : class GLShader_depthtile1 : public GLShader, + public u_DepthMap, public u_ModelViewProjectionMatrix, public u_zFar { @@ -2748,6 +4221,7 @@ class GLShader_depthtile1 : class GLShader_depthtile2 : public GLShader, + public u_DepthMap, public u_ModelViewProjectionMatrix { public: @@ -2757,10 +4231,12 @@ class GLShader_depthtile2 : class GLShader_lighttile : public GLShader, - public u_ModelMatrix, + public u_DepthMap, + public u_Lights, + public u_LightsTexture, public u_numLights, public u_lightLayer, - public u_Lights, + public u_ModelMatrix, public u_zFar { public: @@ -2770,6 +4246,7 @@ class GLShader_lighttile : class GLShader_fxaa : public GLShader, + public u_ColorMap, public u_ModelViewProjectionMatrix { public: @@ -2784,17 +4261,24 @@ extern ShaderKind shaderKind; extern GLShader_generic2D *gl_generic2DShader; extern GLShader_generic *gl_genericShader; +extern GLShader_genericMaterial *gl_genericShaderMaterial; extern GLShader_lightMapping *gl_lightMappingShader; +extern GLShader_lightMappingMaterial *gl_lightMappingShaderMaterial; extern GLShader_forwardLighting_omniXYZ *gl_forwardLightingShader_omniXYZ; extern GLShader_forwardLighting_projXYZ *gl_forwardLightingShader_projXYZ; -extern GLShader_forwardLighting_directionalSun *gl_forwardLightingShader_directionalSun; +extern GLShader_forwardLighting_directionalSun *gl_forwardLightingShader_directionalSun; extern GLShader_shadowFill *gl_shadowFillShader; extern GLShader_reflection *gl_reflectionShader; +extern GLShader_reflectionMaterial *gl_reflectionShaderMaterial; extern GLShader_skybox *gl_skyboxShader; +extern GLShader_skyboxMaterial *gl_skyboxShaderMaterial; extern GLShader_fogQuake3 *gl_fogQuake3Shader; +extern GLShader_fogQuake3Material *gl_fogQuake3ShaderMaterial; extern GLShader_fogGlobal *gl_fogGlobalShader; extern GLShader_heatHaze *gl_heatHazeShader; +extern GLShader_heatHazeMaterial *gl_heatHazeShaderMaterial; extern GLShader_screen *gl_screenShader; +extern GLShader_screenMaterial *gl_screenShaderMaterial; extern GLShader_portal *gl_portalShader; extern GLShader_contrast *gl_contrastShader; extern GLShader_cameraEffects *gl_cameraEffectsShader; @@ -2802,6 +4286,7 @@ extern GLShader_blurX *gl_blurXShader; extern GLShader_blurY *gl_blurYShader; extern GLShader_debugShadowMap *gl_debugShadowMapShader; extern GLShader_liquid *gl_liquidShader; +extern GLShader_liquidMaterial *gl_liquidShaderMaterial; extern GLShader_motionblur *gl_motionblurShader; extern GLShader_ssao *gl_ssaoShader; extern GLShader_depthtile1 *gl_depthtile1Shader; diff --git a/src/engine/renderer/glsl_source/cameraEffects_fp.glsl b/src/engine/renderer/glsl_source/cameraEffects_fp.glsl index 1659bc2b1b..74cfa0789c 100644 --- a/src/engine/renderer/glsl_source/cameraEffects_fp.glsl +++ b/src/engine/renderer/glsl_source/cameraEffects_fp.glsl @@ -23,9 +23,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA /* cameraEffects_fp.glsl */ uniform sampler2D u_CurrentMap; -uniform sampler3D u_ColorMap; +uniform sampler3D u_ColorMap3D; uniform float u_LightFactor; + uniform vec4 u_ColorModulate; uniform float u_InverseGamma; @@ -47,10 +48,10 @@ void main() // apply color grading vec3 colCoord = color.rgb * 15.0 / 16.0 + 0.5 / 16.0; colCoord.z *= 0.25; - color.rgb = u_ColorModulate.x * texture3D(u_ColorMap, colCoord).rgb; - color.rgb += u_ColorModulate.y * texture3D(u_ColorMap, colCoord + vec3(0.0, 0.0, 0.25)).rgb; - color.rgb += u_ColorModulate.z * texture3D(u_ColorMap, colCoord + vec3(0.0, 0.0, 0.50)).rgb; - color.rgb += u_ColorModulate.w * texture3D(u_ColorMap, colCoord + vec3(0.0, 0.0, 0.75)).rgb; + color.rgb = u_ColorModulate.x * texture3D(u_ColorMap3D, colCoord).rgb; + color.rgb += u_ColorModulate.y * texture3D(u_ColorMap3D, colCoord + vec3(0.0, 0.0, 0.25)).rgb; + color.rgb += u_ColorModulate.z * texture3D(u_ColorMap3D, colCoord + vec3(0.0, 0.0, 0.50)).rgb; + color.rgb += u_ColorModulate.w * texture3D(u_ColorMap3D, colCoord + vec3(0.0, 0.0, 0.75)).rgb; color.xyz = pow(color.xyz, vec3(u_InverseGamma)); diff --git a/src/engine/renderer/glsl_source/computeLight_fp.glsl b/src/engine/renderer/glsl_source/computeLight_fp.glsl index ce874dd770..2724dd4798 100644 --- a/src/engine/renderer/glsl_source/computeLight_fp.glsl +++ b/src/engine/renderer/glsl_source/computeLight_fp.glsl @@ -21,6 +21,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ // computeLight_fp.glsl - Light computing helper functions +#define COMPUTELIGHT_GLSL + #if !defined(USE_BSP_SURFACE) #define USE_MODEL_SURFACE #endif @@ -47,7 +49,7 @@ layout(std140) uniform u_Lights { }; #define GetLight(idx, component) lights[idx].component #else // !HAVE_ARB_uniform_buffer_object -uniform sampler2D u_Lights; +uniform sampler2D u_LightsTexture; #define idxToTC( idx, w, h ) vec2( floor( ( idx * ( 1.0 / w ) ) + 0.5 ) * ( 1.0 / h ), \ fract( ( idx + 0.5 ) * (1.0 / w ) ) ) const struct GetLightOffsets { @@ -55,7 +57,7 @@ const struct GetLightOffsets { int color_type; int direction_angle; } getLightOffsets = GetLightOffsets(0, 1, 2); -#define GetLight(idx, component) texture2D( u_Lights, idxToTC(3 * idx + getLightOffsets.component, 64.0, float( 3 * MAX_REF_LIGHTS / 64 ) ) ) +#define GetLight(idx, component) texture2D( u_LightsTexture, idxToTC(3 * idx + getLightOffsets.component, 64.0, float( 3 * MAX_REF_LIGHTS / 64 ) ) ) #endif // HAVE_ARB_uniform_buffer_object uniform int u_numLights; @@ -75,9 +77,16 @@ void computeLight(in vec3 lightColor, vec4 diffuseColor, inout vec4 color) { color.rgb += lightColor.rgb * diffuseColor.rgb; } +#if defined(USE_REFLECTIVE_SPECULAR) +void computeDeluxeLight( vec3 lightDir, vec3 normal, vec3 viewDir, vec3 lightColor, + vec4 diffuseColor, vec4 materialColor, + inout vec4 color, in samplerCube u_EnvironmentMap0, in samplerCube u_EnvironmentMap1 ) +#else // !USE_REFLECTIVE_SPECULAR void computeDeluxeLight( vec3 lightDir, vec3 normal, vec3 viewDir, vec3 lightColor, vec4 diffuseColor, vec4 materialColor, - inout vec4 color ) { + inout vec4 color ) +#endif // !USE_REFLECTIVE_SPECULAR +{ vec3 H = normalize( lightDir + viewDir ); #if defined(USE_PHYSICAL_MAPPING) || defined(r_specularMapping) @@ -149,10 +158,10 @@ void computeDeluxeLight( vec3 lightDir, vec3 normal, vec3 viewDir, vec3 lightCol #if defined(HAVE_EXT_texture_integer) && defined(r_highPrecisionRendering) const int lightsPerLayer = 16; -uniform usampler3D u_LightTiles; +uniform usampler3D u_LightTilesInt; #define idxs_t uvec4 -idxs_t fetchIdxs( in vec3 coords ) { - return texture3D( u_LightTiles, coords ); +idxs_t fetchIdxs( in vec3 coords, in usampler3D u_LightTilesInt ) { + return texture3D( u_LightTilesInt, coords ); } int nextIdx( inout idxs_t idxs ) { uvec4 tmp = ( idxs & uvec4( 3 ) ) * uvec4( 0x40, 0x10, 0x04, 0x01 ); @@ -176,10 +185,15 @@ int nextIdx( inout idxs_t idxs ) { const int numLayers = MAX_REF_LIGHTS / 256; -// This code is only used by the tiled dynamic light renderer. #if defined(r_dynamicLight) && r_dynamicLightRenderer == 1 +#if defined(USE_REFLECTIVE_SPECULAR) void computeDynamicLight( int idx, vec3 P, vec3 normal, vec3 viewDir, vec4 diffuse, - vec4 material, inout vec4 color ) { + vec4 material, inout vec4 color, in samplerCube u_EnvironmentMap0, in samplerCube u_EnvironmentMap1 ) +#else // !USE_REFLECTIVE_SPECULAR +void computeDynamicLight( int idx, vec3 P, vec3 normal, vec3 viewDir, vec4 diffuse, + vec4 material, inout vec4 color ) +#endif // !USE_REFLECTIVE_SPECULAR +{ vec4 center_radius = GetLight( idx, center_radius ); vec4 color_type = GetLight( idx, color_type ); vec3 L; @@ -211,13 +225,25 @@ void computeDynamicLight( int idx, vec3 P, vec3 normal, vec3 viewDir, vec4 diffu L = GetLight( idx, direction_angle ).xyz; attenuation = 1.0; } + #if defined(USE_REFLECTIVE_SPECULAR) + computeDeluxeLight( L, normal, viewDir, + attenuation * attenuation * color_type.xyz, + diffuse, material, color, u_EnvironmentMap0, u_EnvironmentMap1 ); + #else // !USE_REFLECTIVE_SPECULAR computeDeluxeLight( L, normal, viewDir, attenuation * attenuation * color_type.xyz, diffuse, material, color ); + #endif // !USE_REFLECTIVE_SPECULAR } +#if defined(USE_REFLECTIVE_SPECULAR) +void computeDynamicLights( vec3 P, vec3 normal, vec3 viewDir, vec4 diffuse, vec4 material, + inout vec4 color, in usampler3D u_LightTilesInt, in samplerCube u_EnvironmentMap0, in samplerCube u_EnvironmentMap1 ) +#else // !USE_REFLECTIVE_SPECULAR void computeDynamicLights( vec3 P, vec3 normal, vec3 viewDir, vec4 diffuse, vec4 material, - inout vec4 color ) { + inout vec4 color, in usampler3D u_LightTilesInt ) +#endif // !USE_REFLECTIVE_SPECULAR +{ vec2 tile = floor( gl_FragCoord.xy * (1.0 / float( TILE_SIZE ) ) ) + 0.5; vec3 tileScale = vec3( r_tileStep, 1.0/numLayers ); @@ -226,7 +252,7 @@ void computeDynamicLights( vec3 P, vec3 normal, vec3 viewDir, vec4 diffuse, vec4 #endif for( int layer = 0; layer < numLayers; layer++ ) { - idxs_t idxs = fetchIdxs( tileScale * vec3( tile, float( layer ) + 0.5 ) ); + idxs_t idxs = fetchIdxs( tileScale * vec3( tile, float( layer ) + 0.5 ), u_LightTilesInt ); for( int i = 0; i < lightsPerLayer; i++ ) { int idx = numLayers * nextIdx( idxs ) + layer; @@ -234,8 +260,12 @@ void computeDynamicLights( vec3 P, vec3 normal, vec3 viewDir, vec4 diffuse, vec4 { break; } - - computeDynamicLight( idx, P, normal, viewDir, diffuse, material, color ); + + #if defined(USE_REFLECTIVE_SPECULAR) + computeDynamicLight( idx, P, normal, viewDir, diffuse, material, color, u_EnvironmentMap0, u_EnvironmentMap1 ); + #else // !USE_REFLECTIVE_SPECULAR + computeDynamicLight( idx, P, normal, viewDir, diffuse, material, color ); + #endif // !USE_REFLECTIVE_SPECULAR #if defined(r_showLightTiles) numLights++; diff --git a/src/engine/renderer/glsl_source/fogQuake3_fp.glsl b/src/engine/renderer/glsl_source/fogQuake3_fp.glsl index 7b8751a645..e14a642870 100644 --- a/src/engine/renderer/glsl_source/fogQuake3_fp.glsl +++ b/src/engine/renderer/glsl_source/fogQuake3_fp.glsl @@ -22,6 +22,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA /* fogQuake3_fp.glsl */ +#define FOGQUAKE3_GLSL + uniform sampler2D u_ColorMap; uniform float u_InverseLightFactor; @@ -33,6 +35,8 @@ DECLARE_OUTPUT(vec4) void main() { + #insert material_fp + vec4 color = texture2D(u_ColorMap, var_TexCoords); color *= var_Color; diff --git a/src/engine/renderer/glsl_source/fogQuake3_vp.glsl b/src/engine/renderer/glsl_source/fogQuake3_vp.glsl index 9eaae25117..8b1099d401 100644 --- a/src/engine/renderer/glsl_source/fogQuake3_vp.glsl +++ b/src/engine/renderer/glsl_source/fogQuake3_vp.glsl @@ -47,6 +47,8 @@ void DeformVertex( inout vec4 pos, void main() { + #insert material_vp + vec4 position; localBasis LB; vec2 texCoord, lmCoord; diff --git a/src/engine/renderer/glsl_source/generic_fp.glsl b/src/engine/renderer/glsl_source/generic_fp.glsl index ac79f5b560..e9f04ef1df 100644 --- a/src/engine/renderer/glsl_source/generic_fp.glsl +++ b/src/engine/renderer/glsl_source/generic_fp.glsl @@ -22,6 +22,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA /* generic_fp.glsl */ +#define GENERIC_GLSL + uniform sampler2D u_ColorMap; uniform float u_AlphaThreshold; @@ -41,6 +43,8 @@ DECLARE_OUTPUT(vec4) void main() { + #insert material_fp + vec4 color = texture2D(u_ColorMap, var_TexCoords); if( abs(color.a + u_AlphaThreshold) <= 1.0 ) diff --git a/src/engine/renderer/glsl_source/generic_vp.glsl b/src/engine/renderer/glsl_source/generic_vp.glsl index adcab067ca..5d82b3a074 100644 --- a/src/engine/renderer/glsl_source/generic_vp.glsl +++ b/src/engine/renderer/glsl_source/generic_vp.glsl @@ -55,6 +55,8 @@ void DeformVertex( inout vec4 pos, void main() { + #insert material_vp + vec4 position; localBasis LB; vec4 color; @@ -92,10 +94,13 @@ void main() var_TexCoords = (u_TextureMatrix * vec4(texCoord, 0.0, 1.0)).xy; #endif -#if defined(USE_DEPTH_FADE) || defined(USE_VERTEX_SPRITE) +#if defined(USE_DEPTH_FADE) // compute z of end of fading effect vec4 fadeDepth = u_ModelViewProjectionMatrix * (position - u_DepthScale * vec4(LB.normal, 0.0)); var_FadeDepth = fadeDepth.zw; +#elif defined(USE_VERTEX_SPRITE) + vec4 fadeDepth = u_ModelViewProjectionMatrix * (position - depthScale * vec4(LB.normal, 0.0)); + var_FadeDepth = fadeDepth.zw; #endif var_Color = color; diff --git a/src/engine/renderer/glsl_source/heatHaze_fp.glsl b/src/engine/renderer/glsl_source/heatHaze_fp.glsl index 99914adb30..d1d2bf9a4b 100644 --- a/src/engine/renderer/glsl_source/heatHaze_fp.glsl +++ b/src/engine/renderer/glsl_source/heatHaze_fp.glsl @@ -22,6 +22,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA /* heatHaze_fp.glsl */ +#define HEATHAZE_GLSL + uniform sampler2D u_CurrentMap; uniform float u_AlphaThreshold; @@ -32,10 +34,16 @@ DECLARE_OUTPUT(vec4) void main() { + #insert material_fp + vec4 color; // compute normal in tangent space from normalmap - vec3 normal = NormalInTangentSpace(var_TexCoords); + #if defined(r_normalMapping) + vec3 normal = NormalInTangentSpace(var_TexCoords, u_NormalMap); + #else // !r_normalMapping + vec3 normal = NormalInTangentSpace(var_TexCoords); + #endif // !r_normalMapping // calculate the screen texcoord in the 0.0 to 1.0 range vec2 st = gl_FragCoord.st / r_FBufSize; diff --git a/src/engine/renderer/glsl_source/heatHaze_vp.glsl b/src/engine/renderer/glsl_source/heatHaze_vp.glsl index a7fe1f3d7f..4c7ceb06bd 100644 --- a/src/engine/renderer/glsl_source/heatHaze_vp.glsl +++ b/src/engine/renderer/glsl_source/heatHaze_vp.glsl @@ -42,6 +42,8 @@ void DeformVertex( inout vec4 pos, void main() { + #insert material_vp + vec4 deformVec; float d1, d2; diff --git a/src/engine/renderer/glsl_source/lightMapping_fp.glsl b/src/engine/renderer/glsl_source/lightMapping_fp.glsl index 1aa67b33c2..a2a858cfec 100644 --- a/src/engine/renderer/glsl_source/lightMapping_fp.glsl +++ b/src/engine/renderer/glsl_source/lightMapping_fp.glsl @@ -22,6 +22,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA /* lightMapping_fp.glsl */ +#define LIGHTMAPPING_GLSL + uniform sampler2D u_DiffuseMap; uniform sampler2D u_MaterialMap; uniform sampler2D u_GlowMap; @@ -37,19 +39,11 @@ IN(smooth) vec3 var_Tangent; IN(smooth) vec3 var_Binormal; IN(smooth) vec3 var_Normal; -#if defined(USE_LIGHT_MAPPING) - uniform sampler2D u_LightMap; -#elif defined(USE_GRID_LIGHTING) - uniform sampler3D u_LightMap; - #define u_LightGrid1 u_LightMap -#endif +uniform sampler2D u_LightMap; +uniform sampler3D u_LightGrid1; -#if defined(USE_DELUXE_MAPPING) - uniform sampler2D u_DeluxeMap; -#elif defined(USE_GRID_DELUXE_MAPPING) - uniform sampler3D u_DeluxeMap; - #define u_LightGrid2 u_DeluxeMap -#endif +uniform sampler2D u_DeluxeMap; +uniform sampler3D u_LightGrid2; #if defined(USE_LIGHT_MAPPING) || defined(USE_DELUXE_MAPPING) IN(smooth) vec2 var_TexLight; @@ -64,6 +58,8 @@ DECLARE_OUTPUT(vec4) void main() { + #insert material_fp + // Compute view direction in world space. vec3 viewDir = normalize(u_ViewOrigin - var_Position); @@ -73,7 +69,7 @@ void main() #if defined(USE_RELIEF_MAPPING) // Compute texcoords offset from heightmap. - vec2 texOffset = ReliefTexOffset(texCoords, viewDir, tangentToWorldMatrix); + vec2 texOffset = ReliefTexOffset(texCoords, viewDir, tangentToWorldMatrix, u_HeightMap); texCoords += texOffset; #endif @@ -91,7 +87,11 @@ void main() } // Compute normal in world space from normalmap. - vec3 normal = NormalInWorldSpace(texCoords, tangentToWorldMatrix); + #if defined(r_normalMapping) + vec3 normal = NormalInWorldSpace(texCoords, tangentToWorldMatrix, u_NormalMap); + #else // !r_normalMapping + vec3 normal = NormalInWorldSpace(texCoords, tangentToWorldMatrix); + #endif // !r_normalMapping // Compute the material term. vec4 material = texture2D(u_MaterialMap, texCoords); @@ -156,14 +156,23 @@ void main() // Blend static light. #if defined(USE_DELUXE_MAPPING) || defined(USE_GRID_DELUXE_MAPPING) - computeDeluxeLight(lightDir, normal, viewDir, lightColor, diffuse, material, color); + #if defined(USE_REFLECTIVE_SPECULAR) + computeDeluxeLight(lightDir, normal, viewDir, lightColor, diffuse, material, color, u_EnvironmentMap0, u_EnvironmentMap1); + #else // !USE_REFLECTIVE_SPECULAR + computeDeluxeLight(lightDir, normal, viewDir, lightColor, diffuse, material, color); + #endif // !USE_REFLECTIVE_SPECULAR #else computeLight(lightColor, diffuse, color); #endif - // Blend dynamic lights, this code is only used by the tiled dynamic light renderer. + // Blend dynamic lights. #if defined(r_dynamicLight) && r_dynamicLightRenderer == 1 - computeDynamicLights(var_Position, normal, viewDir, diffuse, material, color); + #if defined(USE_REFLECTIVE_SPECULAR) + computeDynamicLights(var_Position, normal, viewDir, diffuse, material, color, u_LightTilesInt, + u_EnvironmentMap0, u_EnvironmentMap1); + #else // !USE_REFLECTIVE_SPECULAR + computeDynamicLights(var_Position, normal, viewDir, diffuse, material, color, u_LightTilesInt); + #endif // !USE_REFLECTIVE_SPECULAR #endif // Add Rim Lighting to highlight the edges on model entities. @@ -196,6 +205,7 @@ void main() outputColor = color; + // Debugging. #if defined(r_showNormalMaps) // Convert normal to [0,1] color space. diff --git a/src/engine/renderer/glsl_source/lightMapping_vp.glsl b/src/engine/renderer/glsl_source/lightMapping_vp.glsl index 5e0e1ff2f5..40a88d4f24 100644 --- a/src/engine/renderer/glsl_source/lightMapping_vp.glsl +++ b/src/engine/renderer/glsl_source/lightMapping_vp.glsl @@ -60,6 +60,8 @@ void DeformVertex(inout vec4 pos, inout vec3 normal, inout vec2 st, inout vec4 c void main() { + #insert material_vp + localBasis LB; vec4 position, color; vec2 texCoord, lmCoord; diff --git a/src/engine/renderer/glsl_source/liquid_fp.glsl b/src/engine/renderer/glsl_source/liquid_fp.glsl index ed0b3fa649..85de80601f 100644 --- a/src/engine/renderer/glsl_source/liquid_fp.glsl +++ b/src/engine/renderer/glsl_source/liquid_fp.glsl @@ -22,6 +22,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA /* liquid_fp.glsl */ +#define LIQUID_GLSL + uniform sampler2D u_CurrentMap; uniform sampler2D u_PortalMap; uniform sampler2D u_DepthMap; @@ -50,6 +52,8 @@ DECLARE_OUTPUT(vec4) void main() { + #insert material_fp + // compute incident ray vec3 viewDir = normalize(u_ViewOrigin - var_Position); @@ -64,17 +68,20 @@ void main() vec2 texNormal = var_TexCoords; #if defined(USE_RELIEF_MAPPING) - // ray intersect in view direction // compute texcoords offset from heightmap - vec2 texOffset = ReliefTexOffset(texNormal, viewDir, tangentToWorldMatrix); + vec2 texOffset = ReliefTexOffset(texNormal, viewDir, tangentToWorldMatrix, u_HeightMap); texScreen += texOffset; texNormal += texOffset; #endif // compute normal in world space from normalmap - vec3 normal = NormalInWorldSpace(texNormal, tangentToWorldMatrix); + #if defined(r_normalMapping) + vec3 normal = NormalInWorldSpace(texNormal, tangentToWorldMatrix, u_NormalMap); + #else // !r_normalMapping + vec3 normal = NormalInWorldSpace(texNormal, tangentToWorldMatrix); + #endif // !r_normalMapping // compute fresnel term float fresnel = clamp(u_FresnelBias + pow(1.0 - dot(viewDir, normal), u_FresnelPower) * @@ -129,7 +136,11 @@ void main() vec4 diffuse = vec4(0.0, 0.0, 0.0, 1.0); // compute the specular term - computeDeluxeLight(lightDir, normal, viewDir, lightColor, diffuse, reflectColor, color); + #if defined(USE_REFLECTIVE_SPECULAR) + computeDeluxeLight(lightDir, normal, viewDir, lightColor, diffuse, reflectColor, color, u_EnvironmentMap0, u_EnvironmentMap1); + #else // !USE_REFLECTIVE_SPECULAR + computeDeluxeLight(lightDir, normal, viewDir, lightColor, diffuse, reflectColor, color); + #endif // !USE_REFLECTIVE_SPECULAR outputColor = color; diff --git a/src/engine/renderer/glsl_source/liquid_vp.glsl b/src/engine/renderer/glsl_source/liquid_vp.glsl index 66d6b0de13..b65e2f44e9 100644 --- a/src/engine/renderer/glsl_source/liquid_vp.glsl +++ b/src/engine/renderer/glsl_source/liquid_vp.glsl @@ -40,6 +40,8 @@ OUT(smooth) vec3 var_Normal; void main() { + #insert material_vp + // transform vertex position into homogenous clip-space gl_Position = u_ModelViewProjectionMatrix * vec4(attr_Position, 1.0); diff --git a/src/engine/renderer/glsl_source/material_fp.glsl b/src/engine/renderer/glsl_source/material_fp.glsl new file mode 100644 index 0000000000..bf72a5cf6f --- /dev/null +++ b/src/engine/renderer/glsl_source/material_fp.glsl @@ -0,0 +1,132 @@ +/* +=========================================================================== + +Daemon BSD Source Code +Copyright (c) 2024 Daemon Developers +All rights reserved. + +This file is part of the Daemon BSD Source Code (Daemon Source Code). + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Daemon developers nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL DAEMON DEVELOPERS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=========================================================================== +*/ + +/* material_fp.glsl */ + +/* +* For use with material system +* All changes to uniform samplers in shaders which use this system must be reflected here +* Any shader using this system should add #define SHADERNAME_GLSL in the beginning (including lib shaders) +* It should then be added here in the material system and bindless texture ifdefs: +* #if defined(SHADERNAME_GLSL) +* sampler* samplerName = sampler*( samplerName_initial ); +* #endif // !SHADERNAME_GLSL +* In the main shader add +* #insert material +* in the beginning of main() once +* Any texture samplers should be passed to functions from main() or other functions +*/ + +#if defined(USE_MATERIAL_SYSTEM) + +#ifdef HAVE_ARB_bindless_texture + +#if defined(COMPUTELIGHT_GLSL) +#if defined(USE_REFLECTIVE_SPECULAR) +samplerCube u_EnvironmentMap0 = samplerCube( u_EnvironmentMap0_initial ); +samplerCube u_EnvironmentMap1 = samplerCube( u_EnvironmentMap1_initial ); +#endif // !USE_REFLECTIVE_SPECULAR +usampler3D u_LightTilesInt = usampler3D( u_LightTilesInt_initial ); +#endif // !COMPUTELIGHT_GLSL + +#if defined(FOGQUAKE3_GLSL) +sampler2D u_ColorMap = sampler2D( u_ColorMap_initial ); +#endif // !FOGQUAKE3_GLSL + +#if defined(GENERIC_GLSL) +sampler2D u_ColorMap = sampler2D( u_ColorMap_initial ); +#if defined(USE_DEPTH_FADE) || defined(USE_VERTEX_SPRITE) +sampler2D u_DepthMap = sampler2D( u_DepthMap_initial ); +#endif // !(USE_DEPTH_FADE || USE_VERTEX_SPRITE) +#endif // !GENERIC_GLSL + +#if defined(HEATHAZE_GLSL) +sampler2D u_CurrentMap = sampler2D( u_CurrentMap_initial ); +#endif // !HEATHAZE_GLSL + +#if defined(LIGHTMAPPING_GLSL) +sampler2D u_DiffuseMap = sampler2D( u_DiffuseMap_initial ); +sampler2D u_MaterialMap = sampler2D( u_MaterialMap_initial ); +sampler2D u_GlowMap = sampler2D( u_GlowMap_initial ); +sampler2D u_LightMap = sampler2D( u_LightMap_initial ); +sampler3D u_LightGrid1 = sampler3D( u_LightGrid1_initial ); +sampler2D u_DeluxeMap = sampler2D( u_DeluxeMap_initial ); +sampler3D u_LightGrid2 = sampler3D( u_LightGrid2_initial ); +#endif // !LIGHTMAPPING_GLSL + +#if defined(LIQUID_GLSL) +sampler2D u_CurrentMap = sampler2D( u_CurrentMap_initial ); +sampler2D u_PortalMap = sampler2D( u_PortalMap_initial ); +sampler2D u_DepthMap = sampler2D( u_DepthMap_initial ); +sampler3D u_LightGrid1 = sampler3D( u_LightGrid1_initial ); +sampler3D u_LightGrid2 = sampler3D( u_LightGrid2_initial ); +#endif // !LIQUID_GLSL + +#if defined(REFLECTION_CB_GLSL) +samplerCube u_ColorMap = samplerCube( u_ColorMap_initial ); +#endif // !REFLECTION_CB_GLSL + +#if defined(RELIEFMAPPING_GLSL) +#if defined(r_normalMapping) || defined(USE_HEIGHTMAP_IN_NORMALMAP) +sampler2D u_NormalMap = sampler2D( u_NormalMap_initial ); +#endif // r_normalMapping || USE_HEIGHTMAP_IN_NORMALMAP + +#if defined(USE_RELIEF_MAPPING) +#if !defined(USE_HEIGHTMAP_IN_NORMALMAP) +sampler2D u_HeightMap = sampler2D( u_HeightMap_initial ); +#else +sampler2D u_HeightMap = sampler2D( u_NormalMap_initial ); +#endif // !USE_HEIGHTMAP_IN_NORMALMAP +#endif // USE_RELIEF_MAPPING +#endif // !RELIEFMAPPING_GLSL + +#if defined(SCREEN_GLSL) +sampler2D u_CurrentMap = sampler2D( u_CurrentMap_initial ); +#endif // !SCREEN_GLSL + +#if defined(SKYBOX_GLSL) +samplerCube u_ColorMapCube = samplerCube( u_ColorMapCube_initial ); +sampler2D u_CloudMap = sampler2D( u_CloudMap_initial ); +#endif // !SKYBOX_GLSL + +#else // !HAVE_ARB_bindless_texture +#endif + +#else // !USE_MATERIAL_SYSTEM + +#if defined(USE_HEIGHTMAP_IN_NORMALMAP) +#define u_HeightMap u_NormalMap +#endif // !USE_HEIGHTMAP_IN_NORMALMAP + +#endif // !USE_MATERIAL_SYSTEM diff --git a/src/engine/renderer/glsl_source/material_vp.glsl b/src/engine/renderer/glsl_source/material_vp.glsl new file mode 100644 index 0000000000..c08c75e967 --- /dev/null +++ b/src/engine/renderer/glsl_source/material_vp.glsl @@ -0,0 +1,44 @@ +/* +=========================================================================== + +Daemon BSD Source Code +Copyright (c) 2024 Daemon Developers +All rights reserved. + +This file is part of the Daemon BSD Source Code (Daemon Source Code). + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Daemon developers nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL DAEMON DEVELOPERS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=========================================================================== +*/ + +/* material_vp.glsl */ + +#if defined(USE_MATERIAL_SYSTEM) + +#ifdef HAVE_ARB_shader_draw_parameters + in_drawID = drawID; + in_baseInstance = baseInstance; +#endif // !HAVE_ARB_shader_draw_parameters + +#endif // !USE_MATERIAL_SYSTEM diff --git a/src/engine/renderer/glsl_source/reflection_CB_fp.glsl b/src/engine/renderer/glsl_source/reflection_CB_fp.glsl index 3d73f961d0..d5f49b1161 100644 --- a/src/engine/renderer/glsl_source/reflection_CB_fp.glsl +++ b/src/engine/renderer/glsl_source/reflection_CB_fp.glsl @@ -22,6 +22,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA /* reflection_CB_fp.glsl */ +#define REFLECTION_CB_GLSL + uniform samplerCube u_ColorMap; uniform vec3 u_ViewOrigin; uniform mat4 u_ModelMatrix; @@ -36,6 +38,8 @@ DECLARE_OUTPUT(vec4) void main() { + #insert material_fp + // compute view direction in world space vec3 viewDir = normalize(var_Position - u_ViewOrigin); @@ -45,13 +49,17 @@ void main() #if defined(USE_RELIEF_MAPPING) // compute texcoords offset from heightmap - vec2 texOffset = ReliefTexOffset(texNormal, viewDir, tangentToWorldMatrix); + vec2 texOffset = ReliefTexOffset(texNormal, viewDir, tangentToWorldMatrix, u_HeightMap); texNormal += texOffset; #endif // USE_RELIEF_MAPPING // compute normal in tangent space from normal map - vec3 normal = NormalInWorldSpace(texNormal, tangentToWorldMatrix); + #if defined(r_normalMapping) + vec3 normal = NormalInWorldSpace(texNormal, tangentToWorldMatrix, u_NormalMap); + #else // !r_normalMapping + vec3 normal = NormalInWorldSpace(texNormal, tangentToWorldMatrix); + #endif // !r_normalMapping // compute reflection ray vec3 reflectionRay = reflect(viewDir, normal); diff --git a/src/engine/renderer/glsl_source/reflection_CB_vp.glsl b/src/engine/renderer/glsl_source/reflection_CB_vp.glsl index 6a09fb574b..45df2a0733 100644 --- a/src/engine/renderer/glsl_source/reflection_CB_vp.glsl +++ b/src/engine/renderer/glsl_source/reflection_CB_vp.glsl @@ -42,6 +42,8 @@ void DeformVertex( inout vec4 pos, void main() { + #insert material_vp + vec4 position; localBasis LB; vec2 texCoord, lmCoord; diff --git a/src/engine/renderer/glsl_source/reliefMapping_fp.glsl b/src/engine/renderer/glsl_source/reliefMapping_fp.glsl index de394d756f..02e6e99020 100644 --- a/src/engine/renderer/glsl_source/reliefMapping_fp.glsl +++ b/src/engine/renderer/glsl_source/reliefMapping_fp.glsl @@ -21,6 +21,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ // reliefMapping_fp.glsl - Relief mapping helper functions +#define RELIEFMAPPING_GLSL + #if defined(r_normalMapping) || defined(USE_HEIGHTMAP_IN_NORMALMAP) uniform sampler2D u_NormalMap; #endif // r_normalMapping || USE_HEIGHTMAP_IN_NORMALMAP @@ -38,7 +40,11 @@ uniform float u_ReliefOffsetBias; #endif // USE_RELIEF_MAPPING // compute normal in tangent space +#if defined(r_normalMapping) +vec3 NormalInTangentSpace(vec2 texNormal, in sampler2D u_NormalMap) +#else // !r_normalMapping vec3 NormalInTangentSpace(vec2 texNormal) +#endif // !r_normalMapping { vec3 normal; @@ -102,6 +108,15 @@ vec3 NormalInTangentSpace(vec2 texNormal) } // compute normal in worldspace from normalmap +#if defined(r_normalMapping) +vec3 NormalInWorldSpace(vec2 texNormal, mat3 tangentToWorldMatrix, in sampler2D u_NormalMap) +{ + // compute normal in tangent space from normalmap + vec3 normal = NormalInTangentSpace(texNormal, u_NormalMap); + // transform normal into world space + return normalize(tangentToWorldMatrix * normal); +} +#else // !r_normalMapping vec3 NormalInWorldSpace(vec2 texNormal, mat3 tangentToWorldMatrix) { // compute normal in tangent space from normalmap @@ -109,13 +124,14 @@ vec3 NormalInWorldSpace(vec2 texNormal, mat3 tangentToWorldMatrix) // transform normal into world space return normalize(tangentToWorldMatrix * normal); } +#endif // !r_normalMapping #if defined(USE_RELIEF_MAPPING) // compute texcoords offset from heightmap // most of the code doing somewhat the same is likely to be named // RayIntersectDisplaceMap in other id tech3-based engines // so please keep the comment above to enable cross-tree look-up -vec2 ReliefTexOffset(vec2 rayStartTexCoords, vec3 viewDir, mat3 tangentToWorldMatrix) +vec2 ReliefTexOffset(vec2 rayStartTexCoords, vec3 viewDir, mat3 tangentToWorldMatrix, in sampler2D u_HeightMap) { // compute view direction in tangent space vec3 tangentViewDir = normalize(viewDir * tangentToWorldMatrix); @@ -143,7 +159,7 @@ vec2 ReliefTexOffset(vec2 rayStartTexCoords, vec3 viewDir, mat3 tangentToWorldMa currentDepth += currentSize; #if defined(USE_HEIGHTMAP_IN_NORMALMAP) - float depth = texture2D(u_NormalMap, rayStartTexCoords + displacement * currentDepth).a; + float depth = texture2D(u_HeightMap, rayStartTexCoords + displacement * currentDepth).a; #else // !USE_HEIGHTMAP_IN_NORMALMAP float depth = texture2D(u_HeightMap, rayStartTexCoords + displacement * currentDepth).g; #endif // !USE_HEIGHTMAP_IN_NORMALMAP @@ -167,7 +183,7 @@ vec2 ReliefTexOffset(vec2 rayStartTexCoords, vec3 viewDir, mat3 tangentToWorldMa currentSize *= 0.5; #if defined(USE_HEIGHTMAP_IN_NORMALMAP) - float depth = texture2D(u_NormalMap, rayStartTexCoords + displacement * currentDepth).a; + float depth = texture2D(u_HeightMap, rayStartTexCoords + displacement * currentDepth).a; #else // !USE_HEIGHTMAP_IN_NORMALMAP float depth = texture2D(u_HeightMap, rayStartTexCoords + displacement * currentDepth).g; #endif // !USE_HEIGHTMAP_IN_NORMALMAP diff --git a/src/engine/renderer/glsl_source/screen_fp.glsl b/src/engine/renderer/glsl_source/screen_fp.glsl index 75b6f504cb..8af646bcbd 100644 --- a/src/engine/renderer/glsl_source/screen_fp.glsl +++ b/src/engine/renderer/glsl_source/screen_fp.glsl @@ -22,6 +22,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA /* screen_fp.glsl */ +#define SCREEN_GLSL + uniform sampler2D u_CurrentMap; IN(smooth) vec4 var_Color; @@ -30,6 +32,8 @@ DECLARE_OUTPUT(vec4) void main() { + #insert material_fp + // calculate the screen texcoord in the 0.0 to 1.0 range vec2 st = gl_FragCoord.st / r_FBufSize; diff --git a/src/engine/renderer/glsl_source/screen_vp.glsl b/src/engine/renderer/glsl_source/screen_vp.glsl index 7d0afb53e1..fd35a2885e 100644 --- a/src/engine/renderer/glsl_source/screen_vp.glsl +++ b/src/engine/renderer/glsl_source/screen_vp.glsl @@ -31,6 +31,8 @@ OUT(smooth) vec4 var_Color; void main() { + #insert material_vp + // transform vertex position into homogenous clip-space gl_Position = u_ModelViewProjectionMatrix * vec4(attr_Position, 1.0); diff --git a/src/engine/renderer/glsl_source/skybox_fp.glsl b/src/engine/renderer/glsl_source/skybox_fp.glsl index 59549da0f3..c900e69512 100644 --- a/src/engine/renderer/glsl_source/skybox_fp.glsl +++ b/src/engine/renderer/glsl_source/skybox_fp.glsl @@ -22,9 +22,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA /* skybox_fp.glsl */ +#define SKYBOX_GLSL + const float radiusWorld = 4096.0; // Value used by quake 3 skybox code -uniform samplerCube u_ColorMap; +uniform samplerCube u_ColorMapCube; uniform float u_InverseLightFactor; uniform sampler2D u_CloudMap; @@ -52,12 +54,14 @@ float ComputeCloudParametric( vec3 skyVec, float radiusWorld, float cloudHeight void main() { + #insert material_fp + // compute incident ray vec3 incidentRay = normalize(var_Position); vec4 color; if( !u_UseCloudMap ) { - color = textureCube(u_ColorMap, incidentRay).rgba; + color = textureCube(u_ColorMapCube, incidentRay).rgba; } else { incidentRay *= ComputeCloudParametric( incidentRay, radiusWorld, u_CloudHeight ); incidentRay.z += radiusWorld; diff --git a/src/engine/renderer/glsl_source/skybox_vp.glsl b/src/engine/renderer/glsl_source/skybox_vp.glsl index 382f10a072..e3e236c420 100644 --- a/src/engine/renderer/glsl_source/skybox_vp.glsl +++ b/src/engine/renderer/glsl_source/skybox_vp.glsl @@ -30,6 +30,8 @@ OUT(smooth) vec3 var_Position; void main() { + #insert material_vp + // transform vertex position into homogenous clip-space gl_Position = u_ModelViewProjectionMatrix * vec4(attr_Position, 1.0); diff --git a/src/engine/renderer/glsl_source/vertexSprite_vp.glsl b/src/engine/renderer/glsl_source/vertexSprite_vp.glsl index 1a7537870d..8b914c4307 100644 --- a/src/engine/renderer/glsl_source/vertexSprite_vp.glsl +++ b/src/engine/renderer/glsl_source/vertexSprite_vp.glsl @@ -31,7 +31,7 @@ IN vec4 attr_Orientation; uniform vec3 u_ViewOrigin; uniform vec3 u_ViewUp; -float u_DepthScale; +float depthScale; void VertexFetch(out vec4 position, out localBasis normalBasis, @@ -77,6 +77,6 @@ void VertexFetch(out vec4 position, lmCoord = abs( attr_TexCoord0.zw ); color = attr_Color; - u_DepthScale = 2.0 * radius; + depthScale = 2.0 * radius; } #endif diff --git a/src/engine/renderer/shaders.cpp b/src/engine/renderer/shaders.cpp index 53f89c6636..b9aee09c9e 100644 --- a/src/engine/renderer/shaders.cpp +++ b/src/engine/renderer/shaders.cpp @@ -58,6 +58,8 @@ #include "shadowFill_fp.glsl.h" #include "shadowFill_vp.glsl.h" #include "skybox_fp.glsl.h" +#include "material_vp.glsl.h" +#include "material_fp.glsl.h" std::unordered_map shadermap({ { "glsl/blurX_fp.glsl", std::string(reinterpret_cast(blurX_fp_glsl), sizeof(blurX_fp_glsl)) }, @@ -97,6 +99,8 @@ std::unordered_map shadermap({ { "glsl/lighttile_vp.glsl", std::string(reinterpret_cast(lighttile_vp_glsl), sizeof(lighttile_vp_glsl)) }, { "glsl/liquid_fp.glsl", std::string(reinterpret_cast(liquid_fp_glsl), sizeof(liquid_fp_glsl)) }, { "glsl/liquid_vp.glsl", std::string(reinterpret_cast(liquid_vp_glsl), sizeof(liquid_vp_glsl)) }, + { "glsl/material_vp.glsl", std::string( reinterpret_cast< const char* >( material_vp_glsl ), sizeof( material_vp_glsl ) ) }, + { "glsl/material_fp.glsl", std::string( reinterpret_cast< const char* >( material_fp_glsl ), sizeof( material_fp_glsl ) ) }, { "glsl/motionblur_fp.glsl", std::string(reinterpret_cast(motionblur_fp_glsl), sizeof(motionblur_fp_glsl)) }, { "glsl/motionblur_vp.glsl", std::string(reinterpret_cast(motionblur_vp_glsl), sizeof(motionblur_vp_glsl)) }, { "glsl/portal_fp.glsl", std::string(reinterpret_cast(portal_fp_glsl), sizeof(portal_fp_glsl)) }, diff --git a/src/engine/renderer/tr_backend.cpp b/src/engine/renderer/tr_backend.cpp index c651c51780..39665b4ef4 100644 --- a/src/engine/renderer/tr_backend.cpp +++ b/src/engine/renderer/tr_backend.cpp @@ -24,6 +24,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "tr_local.h" #include "gl_shader.h" +#include "TextureManager.h" +#include "Material.h" #if defined( REFBONE_NAMES ) #include #endif @@ -57,6 +59,11 @@ void GL_Bind( image_t *image ) texnum = tr.blackImage->texnum; } + if ( glConfig2.bindlessTexturesAvailable ) { + tr.textureManager.BindReservedTexture( image->type, texnum ); + return; + } + if ( tr.currenttextures[ glState.currenttmu ] != texnum ) { image->frameUsed = tr.frameCount; @@ -73,7 +80,7 @@ void GL_Unbind( image_t *image ) glBindTexture( image->type, 0 ); } -void BindAnimatedImage( textureBundle_t *bundle ) +GLuint64 BindAnimatedImage( int unit, textureBundle_t *bundle ) { int index; @@ -85,16 +92,15 @@ void BindAnimatedImage( textureBundle_t *bundle ) } else { - GL_Bind( tr.defaultImage ); + return GL_BindToTMU( unit, tr.defaultImage ); } - return; + return tr.cinematicImage[bundle->videoMapHandle]->texture->bindlessTextureHandle; } if ( bundle->numImages <= 1 ) { - GL_Bind( bundle->image[ 0 ] ); - return; + return GL_BindToTMU( unit, bundle->image[ 0 ] ); } // it is necessary to do this messy calc to make sure animations line up @@ -109,7 +115,7 @@ void BindAnimatedImage( textureBundle_t *bundle ) index %= bundle->numImages; - GL_Bind( bundle->image[ index ] ); + return GL_BindToTMU( unit, bundle->image[ index ] ); } void GL_BindProgram( shaderProgram_t *program ) @@ -143,6 +149,7 @@ void GL_BindNullProgram() void GL_SelectTexture( int unit ) { + if ( glState.currenttmu == unit ) { return; @@ -165,7 +172,7 @@ void GL_SelectTexture( int unit ) glState.currenttmu = unit; } -void GL_BindToTMU( int unit, image_t *image ) +GLuint64 GL_BindToTMU( int unit, image_t *image ) { if ( !image ) { @@ -173,6 +180,15 @@ void GL_BindToTMU( int unit, image_t *image ) image = tr.defaultImage; } + if ( glConfig2.bindlessTexturesAvailable ) { + if ( materialSystem.generatingWorldCommandBuffer ) { + materialSystem.AddTexture( image->texture ); + return image->texture->bindlessTextureHandle; + } + + return tr.textureManager.BindTexture( 0, image->texture ); + } + int texnum = image->texnum; if ( unit < 0 || unit >= glConfig2.maxTextureUnits ) @@ -182,11 +198,12 @@ void GL_BindToTMU( int unit, image_t *image ) if ( tr.currenttextures[ unit ] == texnum ) { - return; + return 0; } GL_SelectTexture( unit ); GL_Bind( image ); + return 0; } void GL_BlendFunc( GLenum sfactor, GLenum dfactor ) @@ -872,6 +889,7 @@ static void RB_RenderDrawSurfaces( shaderSort_t fromSort, shaderSort_t toSort, for ( i = backEnd.viewParms.firstDrawSurf[ Util::ordinal(fromSort) ]; i < lastSurf; i++ ) { drawSurf = &backEnd.viewParms.drawSurfs[ i ]; + tess.currentDrawSurf = drawSurf; // FIXME: investigate why this happens. if( drawSurf->surface == nullptr ) @@ -1369,7 +1387,7 @@ static void RB_SetupLightForShadowing( trRefLight_t *light, int index, GL_BindProgram( nullptr ); GL_State( GLS_DEFAULT ); - GL_BindToTMU( 0, tr.whiteImage ); + GL_Bind( tr.whiteImage ); int cubeSide = index; int splitFrustumIndex = index; interaction_t *ia = light->firstInteraction; @@ -1877,7 +1895,9 @@ static void RB_SetupLightForLighting( trRefLight_t *light ) gl_debugShadowMapShader->BindProgram( 0 ); - GL_BindToTMU( 0, tr.sunShadowMapFBOImage[ frustumIndex ] ); + gl_debugShadowMapShader->SetUniform_CurrentMapBindless( + GL_BindToTMU( 0, tr.sunShadowMapFBOImage[frustumIndex] ) + ); w = 200; h = 200; @@ -1914,7 +1934,9 @@ static void RB_SetupLightForLighting( trRefLight_t *light ) GL_Cull( cullType_t::CT_TWO_SIDED ); // bind u_ColorMap - GL_BindToTMU( 0, tr.whiteImage ); + gl_genericShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.whiteImage ) + ); gl_genericShader->SetUniform_TextureMatrix( matrixIdentity ); gl_genericShader->SetUniform_ModelViewProjectionMatrix( light->shadowMatrices[ frustumIndex ] ); @@ -2054,7 +2076,7 @@ static void RB_BlurShadowMap( const trRefLight_t *light, int i ) GL_Cull( cullType_t::CT_TWO_SIDED ); GL_State( GLS_DEPTHTEST_DISABLE ); - GL_BindToTMU( 0, images[ index ] ); + // GL_BindToTMU( 0, images[ index ] ); GL_PushMatrix(); @@ -2065,17 +2087,22 @@ static void RB_BlurShadowMap( const trRefLight_t *light, int i ) gl_blurXShader->SetUniform_DeformMagnitude( 1 ); gl_blurXShader->SetUniform_TexScale( texScale ); + gl_blurXShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, images[index] ) + ); + Tess_InstantQuad( *gl_blurXShader, 0, 0, fbos[ index ]->width, fbos[ index ]->height ); R_AttachFBOTexture2D( images[ index ]->type, images[ index ]->texnum, 0 ); glClear( GL_COLOR_BUFFER_BIT ); - GL_BindToTMU( 0, images[ index + MAX_SHADOWMAPS ] ); - gl_blurYShader->BindProgram( 0 ); gl_blurYShader->SetUniform_DeformMagnitude( 1 ); gl_blurYShader->SetUniform_TexScale( texScale ); + gl_blurYShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, images[index + MAX_SHADOWMAPS] ) + ); Tess_InstantQuad( *gl_blurYShader, 0, 0, fbos[index]->width, fbos[index]->height ); @@ -2780,7 +2807,9 @@ void RB_RunVisTests( ) gl_genericShader->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[ glState.stackIndex ] ); // bind u_ColorMap - GL_BindToTMU( 0, tr.whiteImage ); + gl_genericShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.whiteImage ) + ); gl_genericShader->SetUniform_TextureMatrix( tess.svars.texMatrices[ TB_COLORMAP ] ); GL_State( GLS_DEPTHTEST_DISABLE | GLS_COLORMASK_BITS ); @@ -2857,7 +2886,9 @@ void RB_RenderPostDepthLightTile() zParams[ 2 ] = backEnd.viewParms.zFar; gl_depthtile1Shader->SetUniform_zFar( zParams ); - GL_BindToTMU( 0, tr.currentDepthImage ); + gl_depthtile1Shader->SetUniform_DepthMapBindless( + GL_BindToTMU( 0, tr.currentDepthImage ) + ); matrix_t ortho; GL_PushMatrix(); @@ -2880,7 +2911,9 @@ void RB_RenderPostDepthLightTile() GL_Scissor( 0, 0, w, h ); gl_depthtile2Shader->BindProgram( 0 ); - GL_BindToTMU( 0, tr.depthtile1RenderImage ); + gl_depthtile2Shader->SetUniform_DepthMapBindless( + GL_BindToTMU( 0, tr.depthtile1RenderImage ) + ); Tess_InstantQuad( *gl_depthtile2Shader, backEnd.viewParms.viewportX, backEnd.viewParms.viewportY, @@ -2903,10 +2936,14 @@ void RB_RenderPostDepthLightTile() if( glConfig2.uniformBufferObjectAvailable ) { gl_lighttileShader->SetUniformBlock_Lights( tr.dlightUBO ); } else { - GL_BindToTMU( 1, tr.dlightImage ); + gl_lighttileShader->SetUniform_LightsTextureBindless( + GL_BindToTMU( 1, tr.dlightImage ) + ); } - GL_BindToTMU( 0, tr.depthtile2RenderImage ); + gl_lighttileShader->SetUniform_DepthMapBindless( + GL_BindToTMU( 1, tr.depthtile2RenderImage ) + ); R_BindVBO( tr.lighttileVBO ); @@ -3009,10 +3046,14 @@ void RB_RenderGlobalFog() gl_fogGlobalShader->SetUniform_UnprojectMatrix( backEnd.viewParms.unprojectionMatrix ); // bind u_ColorMap - GL_BindToTMU( 0, tr.fogImage ); + gl_fogGlobalShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.fogImage ) + ); // bind u_DepthMap - GL_BindToTMU( 1, tr.currentDepthImage ); + gl_fogGlobalShader->SetUniform_DepthMapBindless( + GL_BindToTMU( 0, tr.currentDepthImage ) + ); // set 2D virtual screen size GL_PushMatrix(); @@ -3070,7 +3111,9 @@ void RB_RenderBloom() // u_InverseLightFactor gl_contrastShader->SetUniform_InverseLightFactor( tr.mapInverseLightFactor ); - GL_BindToTMU( 0, tr.currentRenderImage[ backEnd.currentMainFBO ] ); + gl_contrastShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.currentRenderImage[backEnd.currentMainFBO] ) + ); GL_PopMatrix(); // special 1/4th of the screen contrastRenderFBO ortho @@ -3084,7 +3127,9 @@ void RB_RenderBloom() backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); // render bloom in multiple passes - GL_BindToTMU( 0, tr.contrastRenderFBOImage ); + gl_contrastShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.contrastRenderFBOImage ) + ); for ( i = 0; i < 2; i++ ) { for ( j = 0; j < r_bloomPasses->integer; j++ ) @@ -3112,6 +3157,9 @@ void RB_RenderBloom() gl_blurXShader->SetUniform_DeformMagnitude( r_bloomBlur->value ); gl_blurXShader->SetUniform_TexScale( texScale ); + gl_blurXShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.bloomRenderFBOImage[flip] ) + ); Tess_InstantQuad( *gl_blurXShader, backEnd.viewParms.viewportX, backEnd.viewParms.viewportY, backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); @@ -3122,6 +3170,9 @@ void RB_RenderBloom() gl_blurYShader->SetUniform_DeformMagnitude( r_bloomBlur->value ); gl_blurYShader->SetUniform_TexScale( texScale ); + gl_blurYShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.bloomRenderFBOImage[flip] ) + ); Tess_InstantQuad( *gl_blurYShader, backEnd.viewParms.viewportX, backEnd.viewParms.viewportY, backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); @@ -3142,6 +3193,7 @@ void RB_RenderBloom() GL_BindToTMU( 0, tr.blackImage ); + gl_screenShader->SetUniform_CurrentMapBindless( GL_BindToTMU( 0, tr.blackImage ) ); Tess_InstantQuad( *gl_screenShader, backEnd.viewParms.viewportX, backEnd.viewParms.viewportY, backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight ); @@ -3167,15 +3219,20 @@ void RB_RenderMotionBlur() GL_State( GLS_DEPTHTEST_DISABLE ); GL_Cull( cullType_t::CT_TWO_SIDED ); + gl_motionblurShader->BindProgram( 0 ); + // Swap main FBOs - GL_BindToTMU( 0, tr.currentRenderImage[ backEnd.currentMainFBO ] ); + gl_motionblurShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.currentRenderImage[backEnd.currentMainFBO] ) + ); backEnd.currentMainFBO = 1 - backEnd.currentMainFBO; R_BindFBO( tr.mainFBO[ backEnd.currentMainFBO ] ); - gl_motionblurShader->BindProgram( 0 ); gl_motionblurShader->SetUniform_blurVec(tr.refdef.blurVec); - GL_BindToTMU( 1, tr.currentDepthImage ); + gl_motionblurShader->SetUniform_DepthMapBindless( + GL_BindToTMU( 1, tr.currentDepthImage ) + ); matrix_t ortho; GL_PushMatrix(); @@ -3234,7 +3291,9 @@ void RB_RenderSSAO() gl_ssaoShader->SetUniform_UnprojectionParams( unprojectionParams ); - GL_BindToTMU( 0, tr.currentDepthImage ); + gl_ssaoShader->SetUniform_DepthMapBindless( + GL_BindToTMU( 0, tr.currentDepthImage ) + ); matrix_t ortho; GL_PushMatrix(); @@ -3273,14 +3332,16 @@ void RB_FXAA() GL_State( GLS_DEPTHTEST_DISABLE ); GL_Cull( cullType_t::CT_TWO_SIDED ); + // set the shader parameters + gl_fxaaShader->BindProgram( 0 ); + // Swap main FBOs - GL_BindToTMU( 0, tr.currentRenderImage[ backEnd.currentMainFBO ] ); + gl_fxaaShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.currentRenderImage[backEnd.currentMainFBO] ) + ); backEnd.currentMainFBO = 1 - backEnd.currentMainFBO; R_BindFBO( tr.mainFBO[ backEnd.currentMainFBO ] ); - // set the shader parameters - gl_fxaaShader->BindProgram( 0 ); - matrix_t ortho; GL_PushMatrix(); MatrixOrthogonalProjection( ortho, backEnd.viewParms.viewportX, @@ -3334,8 +3395,12 @@ void RB_CameraPostFX() // This shader is run last, so let it render to screen instead of // tr.mainFBO R_BindNullFBO(); - GL_BindToTMU( 0, tr.currentRenderImage[ backEnd.currentMainFBO ] ); - GL_BindToTMU( 3, tr.colorGradeImage ); + gl_cameraEffectsShader->SetUniform_CurrentMapBindless( + GL_BindToTMU( 0, tr.currentRenderImage[backEnd.currentMainFBO] ) + ); + gl_cameraEffectsShader->SetUniform_ColorMap3DBindless( + GL_BindToTMU( 3, tr.colorGradeImage ) + ); // draw viewport Tess_InstantQuad( *gl_cameraEffectsShader, @@ -3379,7 +3444,9 @@ static void RB_RenderDebugUtils() gl_genericShader->SetRequiredVertexPointers(); // bind u_ColorMap - GL_BindToTMU( 0, tr.whiteImage ); + gl_genericShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.whiteImage ) + ); gl_genericShader->SetUniform_TextureMatrix( matrixIdentity ); ia = nullptr; @@ -3538,7 +3605,9 @@ static void RB_RenderDebugUtils() gl_genericShader->SetUniform_Color( Color::Black ); // bind u_ColorMap - GL_BindToTMU( 0, tr.whiteImage ); + gl_genericShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.whiteImage ) + ); gl_genericShader->SetUniform_TextureMatrix( matrixIdentity ); for ( iaCount = 0, ia = &backEnd.viewParms.interactions[ 0 ]; iaCount < backEnd.viewParms.numInteractions; ia++, iaCount++ ) @@ -3662,7 +3731,9 @@ static void RB_RenderDebugUtils() gl_genericShader->SetUniform_Color( Color::Black ); // bind u_ColorMap - GL_BindToTMU( 0, tr.whiteImage ); + gl_genericShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.whiteImage ) + ); gl_genericShader->SetUniform_TextureMatrix( matrixIdentity ); ent = backEnd.refdef.entities; @@ -3738,11 +3809,13 @@ static void RB_RenderDebugUtils() // bind u_ColorMap #if defined( REFBONE_NAMES ) - GL_BindToTMU( 0, r_imageHashTable [ tr.charsetImageHash ] ); + GL_BindToTMU( gl_genericShader->GetUniformLocation_ColorMap(), r_imageHashTable [ tr.charsetImageHash ] ); int width = r_imageHashTable [ tr.charsetImageHash ]->width; int height = r_imageHashTable [ tr.charsetImageHash ]->height; #else - GL_BindToTMU( 0, tr.whiteImage ); + gl_genericShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.whiteImage ) + ); #endif gl_genericShader->SetUniform_TextureMatrix( matrixIdentity ); @@ -3964,7 +4037,9 @@ static void RB_RenderDebugUtils() gl_genericShader->SetUniform_ColorModulate( colorGen_t::CGEN_CUSTOM_RGB, alphaGen_t::AGEN_CUSTOM ); // bind u_ColorMap - GL_BindToTMU( 0, tr.whiteImage ); + gl_genericShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.whiteImage ) + ); gl_genericShader->SetUniform_TextureMatrix( matrixIdentity ); // set 2D virtual screen size @@ -4050,7 +4125,9 @@ static void RB_RenderDebugUtils() } // bind u_ColorMap - GL_BindToTMU( 0, cubeProbe->cubemap ); + gl_reflectionShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, cubeProbe->cubemap ) + ); Tess_AddCubeWithNormals( cubeProbe->origin, mins, maxs, Color::White ); } @@ -4087,7 +4164,9 @@ static void RB_RenderDebugUtils() gl_genericShader->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[ glState.stackIndex ] ); // bind u_ColorMap - GL_BindToTMU( 0, tr.whiteImage ); + gl_genericShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.whiteImage ) + ); gl_genericShader->SetUniform_TextureMatrix( matrixIdentity ); GL_CheckErrors(); @@ -4163,7 +4242,9 @@ static void RB_RenderDebugUtils() gl_genericShader->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[ glState.stackIndex ] ); // bind u_ColorMap - GL_BindToTMU( 0, tr.whiteImage ); + gl_genericShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.whiteImage ) + ); gl_genericShader->SetUniform_TextureMatrix( matrixIdentity ); GL_CheckErrors(); @@ -4247,7 +4328,9 @@ static void RB_RenderDebugUtils() gl_genericShader->SetUniform_ColorModulate( colorGen_t::CGEN_CUSTOM_RGB, alphaGen_t::AGEN_CUSTOM ); // bind u_ColorMap - GL_BindToTMU( 0, tr.whiteImage ); + gl_genericShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.whiteImage ) + ); gl_genericShader->SetUniform_TextureMatrix( matrixIdentity ); GL_CheckErrors(); @@ -4339,7 +4422,9 @@ static void RB_RenderDebugUtils() GL_Cull( cullType_t::CT_TWO_SIDED ); // bind u_ColorMap - GL_BindToTMU( 0, tr.whiteImage ); + gl_genericShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.whiteImage ) + ); gl_genericShader->SetUniform_TextureMatrix( matrixIdentity ); gl_genericShader->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[ glState.stackIndex ] ); @@ -4541,7 +4626,9 @@ static void RB_RenderDebugUtils() gl_genericShader->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[ glState.stackIndex ] ); // bind u_ColorMap - GL_BindToTMU( 0, tr.whiteImage ); + gl_genericShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.whiteImage ) + ); gl_genericShader->SetUniform_TextureMatrix( matrixIdentity ); GL_CheckErrors(); @@ -4632,7 +4719,9 @@ void DebugDrawBegin( debugDrawMode_t mode, float size ) { gl_genericShader->SetUniform_Color( colorClear ); // bind u_ColorMap - GL_BindToTMU( 0, tr.whiteImage ); + gl_genericShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.whiteImage ) + ); gl_genericShader->SetUniform_TextureMatrix( matrixIdentity ); // render in world space @@ -4763,7 +4852,12 @@ static void RB_RenderView( bool depthPass ) startTime = ri.Milliseconds(); } + materialSystem.frameStart = true; + if( depthPass ) { + if ( glConfig2.materialSystemAvailable ) { + materialSystem.RenderMaterials( shaderSort_t::SS_DEPTH, shaderSort_t::SS_DEPTH ); + } RB_RenderDrawSurfaces( shaderSort_t::SS_DEPTH, shaderSort_t::SS_DEPTH, DRAWSURFACES_ALL ); RB_RunVisTests(); if ( !backEnd.postDepthLightTileRendered && !backEnd.viewParms.hasNestedViews ) { @@ -4778,6 +4872,9 @@ static void RB_RenderView( bool depthPass ) tr.refdef.blurVec[2] != 0.0f ) { // draw everything that is not the gun + if ( glConfig2.materialSystemAvailable ) { + materialSystem.RenderMaterials( shaderSort_t::SS_ENVIRONMENT_FOG, shaderSort_t::SS_OPAQUE ); + } RB_RenderDrawSurfaces( shaderSort_t::SS_ENVIRONMENT_FOG, shaderSort_t::SS_OPAQUE, DRAWSURFACES_ALL_FAR ); RB_RenderMotionBlur(); @@ -4788,6 +4885,9 @@ static void RB_RenderView( bool depthPass ) else { // draw everything that is opaque + if ( glConfig2.materialSystemAvailable ) { + materialSystem.RenderMaterials( shaderSort_t::SS_ENVIRONMENT_FOG, shaderSort_t::SS_OPAQUE ); + } RB_RenderDrawSurfaces( shaderSort_t::SS_ENVIRONMENT_FOG, shaderSort_t::SS_OPAQUE, DRAWSURFACES_ALL ); } @@ -4817,6 +4917,9 @@ static void RB_RenderView( bool depthPass ) RB_RenderGlobalFog(); // draw everything that is translucent + if ( glConfig2.materialSystemAvailable ) { + materialSystem.RenderMaterials( shaderSort_t::SS_ENVIRONMENT_NOFOG, shaderSort_t::SS_POST_PROCESS ); + } RB_RenderDrawSurfaces( shaderSort_t::SS_ENVIRONMENT_NOFOG, shaderSort_t::SS_POST_PROCESS, DRAWSURFACES_ALL ); GL_CheckErrors(); @@ -4909,6 +5012,11 @@ void RE_UploadCinematic( int cols, int rows, const byte *data, int client, bool glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER ); glTexParameterfv( GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, Color::Black.ToArray() ); + + // Getting bindless handle makes the texture immutable, so generate it again because we used glTexParameter* + if ( glConfig2.bindlessTexturesAvailable ) { + tr.cinematicImage[ client ]->texture->GenBindlessHandle(); + } } else { @@ -5455,7 +5563,9 @@ const RenderCommand *SetupLightsCommand::ExecuteSelf( ) const glUnmapBuffer( bufferTarget ); if( !glConfig2.uniformBufferObjectAvailable ) { - GL_BindToTMU( 0, tr.dlightImage ); + gl_lighttileShader->SetUniform_LightsTextureBindless( + GL_BindToTMU( 1, tr.dlightImage ) + ); glTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, tr.dlightImage->width, tr.dlightImage->height, GL_RGBA, GL_FLOAT, nullptr ); } glBindBuffer( bufferTarget, 0 ); @@ -5795,7 +5905,9 @@ void RB_ShowImages() } // bind u_ColorMap - GL_Bind( image ); + gl_genericShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, image ) + ); Tess_InstantQuad( *gl_genericShader, x, y, w, h ); } @@ -5921,6 +6033,7 @@ void RB_ExecuteRenderCommands( const void *data ) { cmd = cmd->ExecuteSelf(); } + // stop rendering on this thread t2 = ri.Milliseconds(); backEnd.pc.msec = t2 - t1; diff --git a/src/engine/renderer/tr_bsp.cpp b/src/engine/renderer/tr_bsp.cpp index aa0cfd7e18..50f841e1ab 100644 --- a/src/engine/renderer/tr_bsp.cpp +++ b/src/engine/renderer/tr_bsp.cpp @@ -6425,7 +6425,7 @@ vertexHash_t *AddVertexToHashTable( vertexHash_t **hashTable, vec3_t xyz, void * return vertexHash; } -void GL_BindNearestCubeMap( const vec3_t xyz ) +void GL_BindNearestCubeMap( int unit, const vec3_t xyz ) { float distance, maxDistance; cubemapProbe_t *cubeProbe; @@ -6461,7 +6461,7 @@ void GL_BindNearestCubeMap( const vec3_t xyz ) } } - GL_Bind( tr.autoCubeImage ); + GL_BindToTMU( unit, tr.autoCubeImage ); } void R_FindTwoNearestCubeMaps( const vec3_t position, cubemapProbe_t **cubeProbeNearest, cubemapProbe_t **cubeProbeSecondNearest ) diff --git a/src/engine/renderer/tr_image.cpp b/src/engine/renderer/tr_image.cpp index 0934c1cf55..8fe80f51da 100644 --- a/src/engine/renderer/tr_image.cpp +++ b/src/engine/renderer/tr_image.cpp @@ -126,6 +126,11 @@ void GL_TextureMode( const char *string ) { glTexParameterf( image->type, GL_TEXTURE_MAX_ANISOTROPY_EXT, glConfig2.textureAnisotropy ); } + + // Getting bindless handle makes the texture immutable, so generate it again because we used glTexParameter* + if ( glConfig2.bindlessTexturesAvailable ) { + image->texture->GenBindlessHandle(); + } } } } @@ -1344,8 +1349,10 @@ image_t *R_AllocImage( const char *name, bool linkIntoHashTable ) image = (image_t*) ri.Hunk_Alloc( sizeof( image_t ), ha_pref::h_low ); *image = {}; + image->texture = new Texture(); glGenTextures( 1, &image->texnum ); + image->texture->textureHandle = image->texnum; tr.images.push_back( image ); @@ -1399,6 +1406,7 @@ image_t *R_CreateImage( const char *name, const byte **pic, int width, int heigh } image->type = GL_TEXTURE_2D; + image->texture->target = GL_TEXTURE_2D; image->width = width; image->height = height; @@ -1431,6 +1439,7 @@ image_t *R_CreateGlyph( const char *name, const byte *pic, int width, int height } image->type = GL_TEXTURE_2D; + image->texture->target = GL_TEXTURE_2D; image->width = width; image->height = height; image->bits = IF_NOPICMIP; @@ -1477,6 +1486,7 @@ image_t *R_CreateCubeImage( const char *name, const byte *pic[ 6 ], int width, i } image->type = GL_TEXTURE_CUBE_MAP; + image->texture->target = GL_TEXTURE_CUBE_MAP; image->width = width; image->height = height; @@ -1514,6 +1524,7 @@ image_t *R_Create3DImage( const char *name, const byte *pic, int width, int heig } image->type = GL_TEXTURE_3D; + image->texture->target = GL_TEXTURE_3D; image->width = width; image->height = height; @@ -3039,8 +3050,14 @@ void R_ShutdownImages() for ( image_t *image : tr.images ) { + if ( image->texture->IsResident() ) { + image->texture->MakeNonResident(); + } + glDeleteTextures( 1, &image->texnum ); + delete image->texture; } + tr.textureManager.FreeTextures(); tr.currenttextures.clear(); diff --git a/src/engine/renderer/tr_init.cpp b/src/engine/renderer/tr_init.cpp index ebb1288347..b5a733b93f 100644 --- a/src/engine/renderer/tr_init.cpp +++ b/src/engine/renderer/tr_init.cpp @@ -23,6 +23,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // tr_init.c -- functions that are not called every frame #include "tr_local.h" #include "framework/CvarSystem.h" +#include "Material.h" glconfig_t glConfig; glconfig2_t glConfig2; @@ -81,6 +82,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Cvar::Cvar r_mapOverBrightBits("r_mapOverBrightBits", "default map light color shift", Cvar::NONE, 2); Cvar::Cvar r_forceLegacyOverBrightClamping("r_forceLegacyOverBrightClamping", "clamp over bright of legacy maps (enable multiplied color clamping and normalization)", Cvar::NONE, false); Cvar::Range> r_lightMode("r_lightMode", "lighting mode: 0: fullbright (cheat), 1: vertex light, 2: grid light (cheat), 3: light map", Cvar::NONE, Util::ordinal(lightMode_t::MAP), Util::ordinal(lightMode_t::FULLBRIGHT), Util::ordinal(lightMode_t::MAP)); + Cvar::Cvar r_materialSystem( "r_materialSystem", "Use Material System", Cvar::NONE, false ); cvar_t *r_lightStyles; cvar_t *r_exportTextures; cvar_t *r_heatHaze; @@ -1160,6 +1162,7 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p Cvar::Latch( r_dynamicLightRenderer ); Cvar::Latch( r_dynamicLight ); Cvar::Latch( r_staticLight ); + Cvar::Latch( r_materialSystem ); r_drawworld = Cvar_Get( "r_drawworld", "1", CVAR_CHEAT ); r_portalOnly = Cvar_Get( "r_portalOnly", "0", CVAR_CHEAT ); @@ -1488,6 +1491,8 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p R_DoneFreeType(); + materialSystem.Free(); + // shut down platform specific OpenGL stuff if ( destroyWindow ) { diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index 83ec647b54..388f51f3d6 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -31,6 +31,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "botlib/bot_debug.h" #include "tr_public.h" #include "iqm.h" +#include "TextureManager.h" #define GLEW_NO_GLU #include @@ -609,6 +610,7 @@ enum class dynamicLightRenderer_t { LEGACY, TILED }; GLenum type; GLuint texnum; // gl texture binding + Texture *texture; uint16_t width, height, numLayers; // source image uint16_t uploadWidth, uploadHeight; // after power of two and picmip but not including clamp to MAX_TEXTURE_SIZE @@ -1184,6 +1186,14 @@ enum class dynamicLightRenderer_t { LEGACY, TILED }; expression_t deformMagnitudeExp; bool noFog; // used only for shaders that have fog disabled, so we can enable it for individual stages + + bool useMaterialSystem = false; + uint materialPackID = 0; + uint materialID = 0; + bool dynamic = false; + bool colorDynamic = false; + bool texMatricesDynamic = false; + bool texturesDynamic = false; }; enum cullType_t : int @@ -1642,6 +1652,12 @@ enum class dynamicLightRenderer_t { LEGACY, TILED }; uint64_t sort; bool bspSurface; + uint materialsSSBOOffset[ MAX_SHADER_STAGES ]; + bool initialized[ MAX_SHADER_STAGES ]; + uint materialIDs[ MAX_SHADER_STAGES ]; + uint materialPackIDs[ MAX_SHADER_STAGES ]; + bool texturesDynamic[ MAX_SHADER_STAGES ]; + inline int index() const { return int( ( sort & SORT_INDEX_MASK ) ); } @@ -2630,6 +2646,8 @@ enum class dynamicLightRenderer_t { LEGACY, TILED }; world_t *world; + TextureManager textureManager; + const byte *externalVisData; // from RE_SetWorldVisData, shared with CM_Load // Maximum reported is 192, see https://opengl.gpuinfo.org/displaycapability.php?name=GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS @@ -2736,6 +2754,7 @@ enum class dynamicLightRenderer_t { LEGACY, TILED }; drawSurf_t *genericQuad; bool hasSkybox; + bool drawingSky = false; drawSurf_t *skybox; vec3_t sunLight; // from the sky shader for this level @@ -2854,6 +2873,7 @@ enum class dynamicLightRenderer_t { LEGACY, TILED }; extern Cvar::Cvar r_mapOverBrightBits; extern Cvar::Cvar r_forceLegacyOverBrightClamping; extern Cvar::Range> r_lightMode; + extern Cvar::Cvar r_materialSystem; extern cvar_t *r_lightStyles; extern cvar_t *r_exportTextures; extern cvar_t *r_heatHaze; @@ -3032,6 +3052,7 @@ inline bool checkGLErrors() float R_NoiseGet4f( float x, float y, float z, float t ); void R_NoiseInit(); + bool R_MirrorViewBySurface( drawSurf_t* drawSurf ); void R_RenderView( viewParms_t *parms ); void R_RenderPostProcess(); @@ -3125,12 +3146,12 @@ inline bool checkGLErrors() ==================================================================== */ void GL_Bind( image_t *image ); - void GL_BindNearestCubeMap( const vec3_t xyz ); + void GL_BindNearestCubeMap( int unit, const vec3_t xyz ); void GL_Unbind( image_t *image ); - void BindAnimatedImage( textureBundle_t *bundle ); + GLuint64 BindAnimatedImage( int unit, textureBundle_t *bundle ); void GL_TextureFilter( image_t *image, filterType_t filterType ); void GL_BindProgram( shaderProgram_t *program ); - void GL_BindToTMU( int unit, image_t *image ); + GLuint64 GL_BindToTMU( int unit, image_t *image ); void GL_BindNullProgram(); void GL_SetDefaultState(); void GL_SelectTexture( int unit ); @@ -3331,6 +3352,12 @@ inline bool checkGLErrors() uint32_t numIndexes; uint32_t numVertexes; + // Material system stuff for setting up correct SSBO offsets + uint materialPackID = 0; + uint materialID = 0; + uint currentSSBOOffset = 0; + drawSurf_t* currentDrawSurf; + // Must be set by the stage iterator function if needed. These are *not* // automatically cleared by the likes of Tess_End. stageVars_t svars; @@ -3354,6 +3381,7 @@ inline bool checkGLErrors() int multiDrawPrimitives; glIndex_t *multiDrawIndexes[ MAX_MULTIDRAW_PRIMITIVES ]; int multiDrawCounts[ MAX_MULTIDRAW_PRIMITIVES ]; + uint multiDrawOffsets[ MAX_MULTIDRAW_PRIMITIVES ]; // enabled when a skeletal model VBO is used bool vboVertexSkinning; @@ -3410,7 +3438,10 @@ inline bool checkGLErrors() void Tess_DrawArrays( GLenum elementType ); void Tess_CheckOverflow( int verts, int indexes ); + void SetNormalScale( const shaderStage_t* pStage, vec3_t normalScale ); + void SetRgbaGen( const shaderStage_t* pStage, colorGen_t* rgbGen, alphaGen_t* alphaGen ); void Tess_ComputeColor( shaderStage_t *pStage ); + void Tess_ComputeTexMatrices( shaderStage_t* pStage ); void Tess_StageIteratorDebug(); void Tess_StageIteratorColor(); diff --git a/src/engine/renderer/tr_main.cpp b/src/engine/renderer/tr_main.cpp index 061baee517..9494c4035a 100644 --- a/src/engine/renderer/tr_main.cpp +++ b/src/engine/renderer/tr_main.cpp @@ -22,6 +22,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ // tr_main.c -- main control flow for each frame #include "tr_local.h" +#include "Material.h" trGlobals_t tr; @@ -834,6 +835,11 @@ static void SetFarClip() vec3_t v; float distance; + if ( glConfig2.materialSystemAvailable ) { + VectorCopy( materialSystem.worldViewBounds[0], tr.viewParms.visBounds[0] ); + VectorCopy( materialSystem.worldViewBounds[1], tr.viewParms.visBounds[1] ); + } + if ( i & 1 ) { v[ 0 ] = tr.viewParms.visBounds[ 0 ][ 0 ]; @@ -1841,7 +1847,7 @@ R_MirrorViewBySurface Returns true if another view has been rendered ======================== */ -static bool R_MirrorViewBySurface(drawSurf_t *drawSurf) +bool R_MirrorViewBySurface(drawSurf_t *drawSurf) { orientation_t surface, camera; screenRect_t surfRect; @@ -2007,6 +2013,20 @@ void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, int lightmapNum, i tr.refdef.numDrawSurfs++; + // Portal and sky surfaces are not handled by the material system at all + if ( materialSystem.generatingWorldCommandBuffer && ( shader->isPortal || shader->isSky ) ) { + if ( shader->isSky && std::find( materialSystem.skyShaders.begin(), materialSystem.skyShaders.end(), shader ) + == materialSystem.skyShaders.end() ) { + materialSystem.skyShaders.emplace_back( shader ); + } + + if ( shader->isPortal && std::find( materialSystem.portalSurfacesTmp.begin(), materialSystem.portalSurfacesTmp.end(), drawSurf ) + == materialSystem.portalSurfacesTmp.end() ) { + materialSystem.portalSurfacesTmp.emplace_back( drawSurf ); + } + return; + } + if ( shader->depthShader != nullptr ) { R_AddDrawSurf( surface, shader->depthShader, 0, 0, bspSurface ); } @@ -2024,7 +2044,7 @@ static void R_SortDrawSurfs() int i, sort; // it is possible for some views to not have any surfaces - if ( tr.viewParms.numDrawSurfs < 1 ) + if ( !glConfig2.materialSystemAvailable && tr.viewParms.numDrawSurfs < 1 ) { // we still need to add it for hyperspace cases R_AddDrawViewCmd( false ); @@ -2101,6 +2121,10 @@ static void R_SortDrawSurfs() } } + if ( glConfig2.materialSystemAvailable ) { + materialSystem.AddPortalSurfaces(); + } + // tell renderer backend to render this view R_AddDrawViewCmd( false ); } @@ -2802,7 +2826,6 @@ static void R_DebugGraphics() GL_BindProgram( nullptr ); - GL_SelectTexture( 0 ); GL_Bind( tr.whiteImage ); GL_Cull( cullType_t::CT_FRONT_SIDED ); @@ -2860,7 +2883,13 @@ void R_RenderView( viewParms_t *parms ) // because it requires the decalBits R_CullDecalProjectors(); - R_AddWorldSurfaces(); + if ( glConfig2.materialSystemAvailable && !materialSystem.generatedWorldCommandBuffer ) { + materialSystem.GenerateWorldMaterials(); + } + + if ( !glConfig2.materialSystemAvailable ) { + R_AddWorldSurfaces(); + } R_AddPolygonSurfaces(); diff --git a/src/engine/renderer/tr_public.h b/src/engine/renderer/tr_public.h index cfe4af47ad..770658f217 100644 --- a/src/engine/renderer/tr_public.h +++ b/src/engine/renderer/tr_public.h @@ -85,6 +85,11 @@ struct glconfig2_t bool textureIntegerAvailable; bool textureRGAvailable; bool computeShaderAvailable; + bool bindlessTexturesAvailable; + bool shaderDrawParametersAvailable; + bool SSBOAvailable; + bool multiDrawIndirectAvailable; + bool materialSystemAvailable; bool gpuShader4Available; bool gpuShader5Available; bool textureGatherAvailable; diff --git a/src/engine/renderer/tr_scene.cpp b/src/engine/renderer/tr_scene.cpp index f64ec6d748..f793aee0ac 100644 --- a/src/engine/renderer/tr_scene.cpp +++ b/src/engine/renderer/tr_scene.cpp @@ -22,6 +22,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ // tr_scene.c #include "tr_local.h" +#include "Material.h" static int r_firstSceneDrawSurf; static int r_firstSceneInteraction; @@ -625,6 +626,9 @@ void RE_RenderScene( const refdef_t *fd ) VectorCopy( fd->vieworg, parms.pvsOrigin ); Vector4Copy( fd->gradingWeights, parms.gradingWeights ); + // TODO: Add cmds for updating dynamic surfaces and for culling here + materialSystem.frameStart = true; + R_AddClearBufferCmd(); R_AddSetupLightsCmd(); diff --git a/src/engine/renderer/tr_shade.cpp b/src/engine/renderer/tr_shade.cpp index 812d4b645f..11b1fecfe0 100644 --- a/src/engine/renderer/tr_shade.cpp +++ b/src/engine/renderer/tr_shade.cpp @@ -23,6 +23,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // tr_shade.c #include "tr_local.h" #include "gl_shader.h" +#include "Material.h" /* ================================================================================= @@ -78,6 +79,15 @@ static void GLSL_InitGPUShadersOrError() gl_shaderManager.load( gl_generic2DShader ); gl_shaderManager.load( gl_genericShader ); + // Material system shaders that are always loaded if material system is available + if ( glConfig2.materialSystemAvailable ) { + gl_shaderManager.load( gl_genericShaderMaterial ); + gl_shaderManager.load( gl_lightMappingShaderMaterial ); + gl_shaderManager.load( gl_skyboxShaderMaterial ); + gl_shaderManager.load( gl_fogQuake3ShaderMaterial ); + gl_shaderManager.load( gl_heatHazeShaderMaterial ); + } + // standard light mapping gl_shaderManager.load( gl_lightMappingShader ); @@ -127,6 +137,9 @@ static void GLSL_InitGPUShadersOrError() { // bumped cubemap reflection for abitrary polygons ( EMBM ) gl_shaderManager.load( gl_reflectionShader ); + if ( glConfig2.materialSystemAvailable ) { + gl_shaderManager.load( gl_reflectionShaderMaterial ); + } } // skybox drawing for abitrary polygons @@ -146,6 +159,9 @@ static void GLSL_InitGPUShadersOrError() { // screen post process effect gl_shaderManager.load( gl_screenShader ); + if ( glConfig2.materialSystemAvailable ) { + gl_shaderManager.load( gl_screenShaderMaterial ); + } } // portal process effect @@ -168,6 +184,9 @@ static void GLSL_InitGPUShadersOrError() if ( r_liquidMapping->integer != 0 ) { gl_shaderManager.load( gl_liquidShader ); + if ( glConfig2.materialSystemAvailable ) { + gl_shaderManager.load( gl_liquidShaderMaterial ); + } } /* NOTE: motionblur is enabled by cg_motionblur which is a client cvar @@ -271,17 +290,24 @@ void GLSL_ShutdownGPUShaders() gl_shaderManager.freeAll(); gl_genericShader = nullptr; + gl_genericShaderMaterial = nullptr; gl_lightMappingShader = nullptr; + gl_lightMappingShaderMaterial = nullptr; gl_forwardLightingShader_omniXYZ = nullptr; gl_forwardLightingShader_projXYZ = nullptr; gl_forwardLightingShader_directionalSun = nullptr; gl_shadowFillShader = nullptr; gl_reflectionShader = nullptr; + gl_reflectionShaderMaterial = nullptr; gl_skyboxShader = nullptr; + gl_skyboxShaderMaterial = nullptr; gl_fogQuake3Shader = nullptr; + gl_fogQuake3ShaderMaterial = nullptr; gl_fogGlobalShader = nullptr; gl_heatHazeShader = nullptr; + gl_heatHazeShaderMaterial = nullptr; gl_screenShader = nullptr; + gl_screenShaderMaterial = nullptr; gl_portalShader = nullptr; gl_contrastShader = nullptr; gl_cameraEffectsShader = nullptr; @@ -289,6 +315,7 @@ void GLSL_ShutdownGPUShaders() gl_blurYShader = nullptr; gl_debugShadowMapShader = nullptr; gl_liquidShader = nullptr; + gl_liquidShaderMaterial = nullptr; gl_motionblurShader = nullptr; gl_ssaoShader = nullptr; gl_depthtile1Shader = nullptr; @@ -325,7 +352,9 @@ void Tess_DrawElements() { if ( tess.multiDrawPrimitives ) { - glMultiDrawElements( GL_TRIANGLES, tess.multiDrawCounts, GL_INDEX_TYPE, ( const GLvoid ** ) tess.multiDrawIndexes, tess.multiDrawPrimitives ); + if ( !materialSystem.generatingWorldCommandBuffer ) { + glMultiDrawElements( GL_TRIANGLES, tess.multiDrawCounts, GL_INDEX_TYPE, ( const GLvoid** ) tess.multiDrawIndexes, tess.multiDrawPrimitives ); + } backEnd.pc.c_multiDrawElements++; backEnd.pc.c_multiDrawPrimitives += tess.multiDrawPrimitives; @@ -336,6 +365,10 @@ void Tess_DrawElements() { backEnd.pc.c_multiVboIndexes += tess.multiDrawCounts[ i ]; backEnd.pc.c_indexes += tess.multiDrawCounts[ i ]; + if ( materialSystem.generatingWorldCommandBuffer ) { + materialSystem.AddDrawCommand( tess.materialID, tess.materialPackID, tess.currentSSBOOffset, + ( GLuint ) tess.multiDrawCounts[i], tess.multiDrawOffsets[i] ); + } } } else @@ -346,7 +379,11 @@ void Tess_DrawElements() base = tess.indexBase * sizeof( glIndex_t ); } - glDrawRangeElements( GL_TRIANGLES, 0, tess.numVertexes, tess.numIndexes, GL_INDEX_TYPE, BUFFER_OFFSET( base ) ); + if ( materialSystem.generatingWorldCommandBuffer ) { + materialSystem.AddDrawCommand( tess.materialID, tess.materialPackID, tess.currentSSBOOffset, tess.numIndexes, tess.indexBase ); + } else { + glDrawRangeElements( GL_TRIANGLES, 0, tess.numVertexes, tess.numIndexes, GL_INDEX_TYPE, BUFFER_OFFSET( base ) ); + } backEnd.pc.c_drawElements++; @@ -359,7 +396,11 @@ void Tess_DrawElements() } else { - glDrawElements( GL_TRIANGLES, tess.numIndexes, GL_INDEX_TYPE, tess.indexes ); + if ( materialSystem.generatingWorldCommandBuffer ) { + materialSystem.AddDrawCommand( tess.materialID, tess.materialPackID, tess.currentSSBOOffset, tess.numIndexes, tess.indexBase ); + } else { + glDrawElements( GL_TRIANGLES, tess.numIndexes, GL_INDEX_TYPE, tess.indexes ); + } backEnd.pc.c_drawElements++; @@ -481,7 +522,9 @@ static void DrawTris() gl_genericShader->SetUniform_Time( backEnd.refdef.floatTime - backEnd.currentEntity->e.shaderTime ); // bind u_ColorMap - GL_BindToTMU( 0, tr.whiteImage ); + gl_genericShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.whiteImage ) + ); gl_genericShader->SetUniform_TextureMatrix( tess.svars.texMatrices[ TB_COLORMAP ] ); gl_genericShader->SetRequiredVertexPointers( vboVertexSprite ); @@ -561,7 +604,7 @@ void Tess_Begin( void ( *stageIteratorFunc )(), } } -static void SetNormalScale( const shaderStage_t *pStage, vec3_t normalScale ) +void SetNormalScale( const shaderStage_t *pStage, vec3_t normalScale ) { float normalIntensity = RB_EvalExpression( &pStage->normalIntensityExp, 1.0 ); @@ -577,7 +620,7 @@ static void SetNormalScale( const shaderStage_t *pStage, vec3_t normalScale ) normalScale[ 2 ] = pStage->normalScale[ 2 ] * r_normalScale->value; } -static void SetRgbaGen( const shaderStage_t *pStage, colorGen_t *rgbGen, alphaGen_t *alphaGen ) +void SetRgbaGen( const shaderStage_t *pStage, colorGen_t *rgbGen, alphaGen_t *alphaGen ) { switch ( pStage->rgbGen ) { @@ -650,8 +693,7 @@ static void Render_generic2D( shaderStage_t *pStage ) gl_generic2DShader->SetUniform_Time( backEnd.refdef.floatTime - backEnd.currentEntity->e.shaderTime ); // bind u_ColorMap - GL_SelectTexture( 0 ); - BindAnimatedImage( &pStage->bundle[ TB_COLORMAP ] ); + gl_generic2DShader->SetUniform_ColorMapBindless( BindAnimatedImage( 0, &pStage->bundle[TB_COLORMAP] ) ); gl_generic2DShader->SetUniform_TextureMatrix( tess.svars.texMatrices[ TB_COLORMAP ] ); if ( glConfig2.depthClampAvailable ) @@ -666,12 +708,15 @@ static void Render_generic2D( shaderStage_t *pStage ) if ( needDepthMap ) { - GL_BindToTMU( 1, tr.currentDepthImage ); + gl_generic2DShader->SetUniform_DepthMapBindless( + GL_BindToTMU( 1, tr.currentDepthImage ) + ); } gl_generic2DShader->SetRequiredVertexPointers( vboVertexSprite ); Tess_DrawElements(); + GL_CheckErrors(); if ( glConfig2.depthClampAvailable ) { @@ -687,6 +732,11 @@ void Render_generic3D( shaderStage_t *pStage ) { GLimp_LogComment( "--- Render_generic3D ---\n" ); + if ( materialSystem.generatingWorldCommandBuffer ) { + Tess_DrawElements(); + return; + } + GL_State( pStage->stateBits ); bool hasDepthFade = pStage->hasDepthFade && !tess.surfaceShader->autoSpriteMode; @@ -748,16 +798,17 @@ void Render_generic3D( shaderStage_t *pStage ) // u_DeformGen gl_genericShader->SetUniform_Time( backEnd.refdef.floatTime - backEnd.currentEntity->e.shaderTime ); - // bind u_ColorMap - GL_SelectTexture( 0 ); - + // bind u_ColorMap= if ( pStage->type == stageType_t::ST_STYLELIGHTMAP ) { - GL_Bind( GetLightMap() ); + // GL_Bind( GetLightMap() ); + gl_genericShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, GetLightMap() ) + ); } else { - BindAnimatedImage( &pStage->bundle[ TB_COLORMAP ] ); + gl_genericShader->SetUniform_ColorMapBindless( BindAnimatedImage( 0, &pStage->bundle[TB_COLORMAP] ) ); } gl_genericShader->SetUniform_TextureMatrix( tess.svars.texMatrices[ TB_COLORMAP ] ); @@ -769,7 +820,9 @@ void Render_generic3D( shaderStage_t *pStage ) if ( needDepthMap ) { - GL_BindToTMU( 1, tr.currentDepthImage ); + gl_genericShader->SetUniform_DepthMapBindless( + GL_BindToTMU( 1, tr.currentDepthImage ) + ); } gl_genericShader->SetRequiredVertexPointers( vboVertexSprite ); @@ -828,6 +881,11 @@ void Render_lightMapping( shaderStage_t *pStage ) { GLimp_LogComment( "--- Render_lightMapping ---\n" ); + if ( materialSystem.generatingWorldCommandBuffer ) { + Tess_DrawElements(); + return; + } + lightMode_t lightMode = lightMode_t::FULLBRIGHT; deluxeMode_t deluxeMode = deluxeMode_t::NONE; @@ -1011,14 +1069,18 @@ void Render_lightMapping( shaderStage_t *pStage ) gl_lightMappingShader->SetUniformBlock_Lights( tr.dlightUBO ); } else { - GL_BindToTMU( BIND_LIGHTS, tr.dlightImage ); + gl_lightMappingShader->SetUniform_LightsTextureBindless( + GL_BindToTMU( BIND_LIGHTS, tr.dlightImage ) + ); } } // bind u_LightTiles if ( r_dynamicLightRenderer.Get() == Util::ordinal( dynamicLightRenderer_t::TILED ) ) { - GL_BindToTMU( BIND_LIGHTTILES, tr.lighttileRenderImage ); + gl_lightMappingShader->SetUniform_LightTilesIntBindless( + GL_BindToTMU( BIND_LIGHTTILES, tr.lighttileRenderImage ) + ); } } @@ -1054,12 +1116,16 @@ void Render_lightMapping( shaderStage_t *pStage ) // FIXME: if there is both, embedded heightmap in normalmap is used instead of standalone heightmap if ( !pStage->hasHeightMapInNormalMap ) { - GL_BindToTMU( BIND_HEIGHTMAP, pStage->bundle[ TB_HEIGHTMAP ].image[ 0 ] ); + gl_lightMappingShader->SetUniform_HeightMapBindless( + GL_BindToTMU( BIND_HEIGHTMAP, pStage->bundle[TB_HEIGHTMAP].image[0] ) + ); } } // bind u_DiffuseMap - GL_BindToTMU( BIND_DIFFUSEMAP, pStage->bundle[ TB_DIFFUSEMAP ].image[ 0 ] ); + gl_lightMappingShader->SetUniform_DiffuseMapBindless( + GL_BindToTMU( BIND_DIFFUSEMAP, pStage->bundle[TB_DIFFUSEMAP].image[0] ) + ); if ( pStage->type != stageType_t::ST_LIGHTMAP ) { @@ -1069,7 +1135,9 @@ void Render_lightMapping( shaderStage_t *pStage ) // bind u_NormalMap if ( !!r_normalMapping->integer || pStage->hasHeightMapInNormalMap ) { - GL_BindToTMU( BIND_NORMALMAP, pStage->bundle[ TB_NORMALMAP ].image[ 0 ] ); + gl_lightMappingShader->SetUniform_NormalMapBindless( + GL_BindToTMU( BIND_NORMALMAP, pStage->bundle[TB_NORMALMAP].image[0] ) + ); } // bind u_NormalScale @@ -1084,7 +1152,9 @@ void Render_lightMapping( shaderStage_t *pStage ) // bind u_MaterialMap if ( pStage->enableSpecularMapping || pStage->enablePhysicalMapping ) { - GL_BindToTMU( BIND_MATERIALMAP, pStage->bundle[ TB_MATERIALMAP ].image[ 0 ] ); + gl_lightMappingShader->SetUniform_MaterialMapBindless( + GL_BindToTMU( BIND_MATERIALMAP, pStage->bundle[TB_MATERIALMAP].image[0] ) + ); } if ( pStage->enableSpecularMapping ) @@ -1179,10 +1249,14 @@ void Render_lightMapping( shaderStage_t *pStage ) } // bind u_EnvironmentMap0 - GL_BindToTMU( BIND_ENVIRONMENTMAP0, cubeMap0 ); + gl_lightMappingShader->SetUniform_EnvironmentMap0Bindless( + GL_BindToTMU( BIND_ENVIRONMENTMAP0, cubeMap0 ) + ); // bind u_EnvironmentMap1 - GL_BindToTMU( BIND_ENVIRONMENTMAP1, cubeMap1 ); + gl_lightMappingShader->SetUniform_EnvironmentMap1Bindless( + GL_BindToTMU( BIND_ENVIRONMENTMAP1, cubeMap1 ) + ); // bind u_EnvironmentInterpolation gl_lightMappingShader->SetUniform_EnvironmentInterpolation( interpolation ); @@ -1200,15 +1274,29 @@ void Render_lightMapping( shaderStage_t *pStage ) } // bind u_LightMap - GL_BindToTMU( BIND_LIGHTMAP, lightmap ); + if ( !enableGridLighting ) { + gl_lightMappingShader->SetUniform_LightMapBindless( + GL_BindToTMU( BIND_LIGHTMAP, lightmap ) + ); + } else { + gl_lightMappingShader->SetUniform_LightGrid1Bindless( GL_BindToTMU( BIND_LIGHTMAP, lightmap ) ); + } // bind u_DeluxeMap - GL_BindToTMU( BIND_DELUXEMAP, deluxemap ); + if ( !enableGridDeluxeMapping ) { + gl_lightMappingShader->SetUniform_DeluxeMapBindless( + GL_BindToTMU( BIND_DELUXEMAP, deluxemap ) + ); + } else { + gl_lightMappingShader->SetUniform_LightGrid2Bindless( GL_BindToTMU( BIND_DELUXEMAP, deluxemap ) ); + } // bind u_GlowMap if ( !!r_glowMapping->integer ) { - GL_BindToTMU( BIND_GLOWMAP, pStage->bundle[ TB_GLOWMAP ].image[ 0 ] ); + gl_lightMappingShader->SetUniform_GlowMapBindless( + GL_BindToTMU( BIND_GLOWMAP, pStage->bundle[TB_GLOWMAP].image[0] ) + ); } gl_lightMappingShader->SetRequiredVertexPointers(); @@ -1224,6 +1312,10 @@ static void Render_shadowFill( shaderStage_t *pStage ) GLimp_LogComment( "--- Render_shadowFill ---\n" ); + if ( materialSystem.generatingWorldCommandBuffer ) { + return; + } + // remove blend modes stateBits = pStage->stateBits; stateBits &= ~( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ); @@ -1274,12 +1366,16 @@ static void Render_shadowFill( shaderStage_t *pStage ) // bind u_ColorMap if ( ( pStage->stateBits & GLS_ATEST_BITS ) != 0 ) { - GL_BindToTMU( 0, pStage->bundle[ TB_COLORMAP ].image[ 0 ] ); + gl_shadowFillShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, pStage->bundle[TB_COLORMAP].image[0] ) + ); gl_shadowFillShader->SetUniform_TextureMatrix( tess.svars.texMatrices[ TB_COLORMAP ] ); } else { - GL_BindToTMU( 0, tr.whiteImage ); + gl_shadowFillShader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.whiteImage ) + ); } Tess_DrawElements(); @@ -1341,7 +1437,9 @@ static void Render_forwardLighting_DBS_omni( shaderStage_t *pStage, // FIXME: if there is both, embedded heightmap in normalmap is used instead of standalone heightmap if ( !pStage->hasHeightMapInNormalMap ) { - GL_BindToTMU( 15, pStage->bundle[ TB_HEIGHTMAP ].image[ 0 ] ); + gl_forwardLightingShader_omniXYZ->SetUniform_HeightMapBindless( + GL_BindToTMU( 15, pStage->bundle[TB_HEIGHTMAP].image[0] ) + ); } } @@ -1397,7 +1495,9 @@ static void Render_forwardLighting_DBS_omni( shaderStage_t *pStage, GL_CheckErrors(); // bind u_DiffuseMap - GL_BindToTMU( 0, pStage->bundle[ TB_DIFFUSEMAP ].image[ 0 ] ); + gl_forwardLightingShader_omniXYZ->SetUniform_DiffuseMapBindless( + GL_BindToTMU( 0, pStage->bundle[TB_DIFFUSEMAP].image[0] ) + ); if ( pStage->type != stageType_t::ST_LIGHTMAP ) { @@ -1405,7 +1505,9 @@ static void Render_forwardLighting_DBS_omni( shaderStage_t *pStage, } // bind u_NormalMap - GL_BindToTMU( 1, pStage->bundle[ TB_NORMALMAP ].image[ 0 ] ); + gl_forwardLightingShader_omniXYZ->SetUniform_NormalMapBindless( + GL_BindToTMU( 1, pStage->bundle[TB_NORMALMAP].image[0] ) + ); // bind u_NormalScale if ( pStage->enableNormalMapping ) @@ -1417,7 +1519,9 @@ static void Render_forwardLighting_DBS_omni( shaderStage_t *pStage, } // bind u_MaterialMap - GL_BindToTMU( 2, pStage->bundle[ TB_MATERIALMAP ].image[ 0 ] ); + gl_forwardLightingShader_omniXYZ->SetUniform_MaterialMapBindless( + GL_BindToTMU( 2, pStage->bundle[TB_MATERIALMAP].image[0] ) + ); // FIXME: physical mapping is not implemented. if ( pStage->enableSpecularMapping ) @@ -1429,22 +1533,26 @@ static void Render_forwardLighting_DBS_omni( shaderStage_t *pStage, } // bind u_AttenuationMapXY - GL_SelectTexture( 3 ); - BindAnimatedImage( &attenuationXYStage->bundle[ TB_COLORMAP ] ); + gl_forwardLightingShader_omniXYZ->SetUniform_AttenuationMapXYBindless( + BindAnimatedImage( 3, &attenuationXYStage->bundle[TB_COLORMAP]) ); // bind u_AttenuationMapZ - GL_SelectTexture( 4 ); - BindAnimatedImage( &attenuationZStage->bundle[ TB_COLORMAP ] ); + gl_forwardLightingShader_omniXYZ->SetUniform_AttenuationMapZBindless( + BindAnimatedImage( 4, &attenuationZStage->bundle[TB_COLORMAP] ) ); // bind u_ShadowMap if ( shadowCompare ) { - GL_BindToTMU( 5, tr.shadowCubeFBOImage[ light->shadowLOD ] ); - GL_BindToTMU( 7, tr.shadowClipCubeFBOImage[ light->shadowLOD ] ); + gl_forwardLightingShader_omniXYZ->SetUniform_ShadowMapBindless( + GL_BindToTMU( 5, tr.shadowCubeFBOImage[light->shadowLOD] ) ); + gl_forwardLightingShader_omniXYZ->SetUniform_ShadowClipMapBindless( + GL_BindToTMU( 7, tr.shadowClipCubeFBOImage[light->shadowLOD] ) ); } // bind u_RandomMap - GL_BindToTMU( 6, tr.randomNormalsImage ); + gl_forwardLightingShader_omniXYZ->SetUniform_RandomMapBindless( + GL_BindToTMU( 6, tr.randomNormalsImage ) + ); gl_forwardLightingShader_omniXYZ->SetRequiredVertexPointers(); @@ -1507,7 +1615,9 @@ static void Render_forwardLighting_DBS_proj( shaderStage_t *pStage, // FIXME: if there is both, embedded heightmap in normalmap is used instead of standalone heightmap if ( !pStage->hasHeightMapInNormalMap ) { - GL_BindToTMU( 15, pStage->bundle[ TB_HEIGHTMAP ].image[ 0 ] ); + gl_forwardLightingShader_projXYZ->SetUniform_HeightMapBindless( + GL_BindToTMU( 15, pStage->bundle[TB_HEIGHTMAP].image[0] ) + ); } } @@ -1564,7 +1674,9 @@ static void Render_forwardLighting_DBS_proj( shaderStage_t *pStage, GL_CheckErrors(); // bind u_DiffuseMap - GL_BindToTMU( 0, pStage->bundle[ TB_DIFFUSEMAP ].image[ 0 ] ); + gl_forwardLightingShader_projXYZ->SetUniform_DiffuseMapBindless( + GL_BindToTMU( 0, pStage->bundle[TB_DIFFUSEMAP].image[0] ) + ); if ( pStage->type != stageType_t::ST_LIGHTMAP ) { @@ -1572,7 +1684,9 @@ static void Render_forwardLighting_DBS_proj( shaderStage_t *pStage, } // bind u_NormalMap - GL_BindToTMU( 1, pStage->bundle[ TB_NORMALMAP ].image[ 0 ] ); + gl_forwardLightingShader_projXYZ->SetUniform_NormalMapBindless( + GL_BindToTMU( 1, pStage->bundle[TB_NORMALMAP].image[0] ) + ); // bind u_NormalScale if ( pStage->enableNormalMapping ) @@ -1584,7 +1698,9 @@ static void Render_forwardLighting_DBS_proj( shaderStage_t *pStage, } // bind u_MaterialMap - GL_BindToTMU( 2, pStage->bundle[ TB_MATERIALMAP ].image[ 0 ] ); + gl_forwardLightingShader_projXYZ->SetUniform_MaterialMapBindless( + GL_BindToTMU( 2, pStage->bundle[TB_MATERIALMAP].image[0] ) + ); // FIXME: physical mapping is not implemented. if ( pStage->enableSpecularMapping ) @@ -1596,22 +1712,28 @@ static void Render_forwardLighting_DBS_proj( shaderStage_t *pStage, } // bind u_AttenuationMapXY - GL_SelectTexture( 3 ); - BindAnimatedImage( &attenuationXYStage->bundle[ TB_COLORMAP ] ); + gl_forwardLightingShader_projXYZ->SetUniform_AttenuationMapXYBindless( + BindAnimatedImage( 3, &attenuationXYStage->bundle[TB_COLORMAP] ) ); // bind u_AttenuationMapZ - GL_SelectTexture( 4 ); - BindAnimatedImage( &attenuationZStage->bundle[ TB_COLORMAP ] ); + gl_forwardLightingShader_projXYZ->SetUniform_AttenuationMapZBindless( + BindAnimatedImage( 4, &attenuationZStage->bundle[TB_COLORMAP] ) ); // bind u_ShadowMap if ( shadowCompare ) { - GL_BindToTMU( 5, tr.shadowMapFBOImage[ light->shadowLOD ] ); - GL_BindToTMU( 7, tr.shadowClipMapFBOImage[ light->shadowLOD ] ); + gl_forwardLightingShader_projXYZ->SetUniform_ShadowMap0Bindless( + GL_BindToTMU( 5, tr.shadowMapFBOImage[light->shadowLOD] ) + ); + gl_forwardLightingShader_projXYZ->SetUniform_ShadowClipMap0Bindless( + GL_BindToTMU( 7, tr.shadowClipMapFBOImage[light->shadowLOD] ) + ); } // bind u_RandomMap - GL_BindToTMU( 6, tr.randomNormalsImage ); + gl_forwardLightingShader_projXYZ->SetUniform_RandomMapBindless( + GL_BindToTMU( 6, tr.randomNormalsImage ) + ); gl_forwardLightingShader_projXYZ->SetRequiredVertexPointers(); @@ -1672,7 +1794,9 @@ static void Render_forwardLighting_DBS_directional( shaderStage_t *pStage, trRef // FIXME: if there is both, embedded heightmap in normalmap is used instead of standalone heightmap if ( !pStage->hasHeightMapInNormalMap ) { - GL_BindToTMU( 15, pStage->bundle[ TB_HEIGHTMAP ].image[ 0 ] ); + gl_forwardLightingShader_directionalSun->SetUniform_HeightMapBindless( + GL_BindToTMU( 15, pStage->bundle[TB_HEIGHTMAP].image[0] ) + ); } } @@ -1733,7 +1857,9 @@ static void Render_forwardLighting_DBS_directional( shaderStage_t *pStage, trRef GL_CheckErrors(); // bind u_DiffuseMap - GL_BindToTMU( 0, pStage->bundle[ TB_DIFFUSEMAP ].image[ 0 ] ); + gl_forwardLightingShader_directionalSun->SetUniform_DiffuseMapBindless( + GL_BindToTMU( 0, pStage->bundle[TB_DIFFUSEMAP].image[0] ) + ); if ( pStage->type != stageType_t::ST_LIGHTMAP ) { @@ -1741,7 +1867,9 @@ static void Render_forwardLighting_DBS_directional( shaderStage_t *pStage, trRef } // bind u_NormalMap - GL_BindToTMU( 1, pStage->bundle[ TB_NORMALMAP ].image[ 0 ] ); + gl_forwardLightingShader_directionalSun->SetUniform_NormalMapBindless( + GL_BindToTMU( 1, pStage->bundle[TB_NORMALMAP].image[0] ) + ); // bind u_NormalScale if ( pStage->enableNormalMapping ) @@ -1753,7 +1881,9 @@ static void Render_forwardLighting_DBS_directional( shaderStage_t *pStage, trRef } // bind u_MaterialMap - GL_BindToTMU( 2, pStage->bundle[ TB_MATERIALMAP ].image[ 0 ] ); + gl_forwardLightingShader_directionalSun->SetUniform_MaterialMapBindless( + GL_BindToTMU( 2, pStage->bundle[TB_MATERIALMAP].image[0] ) + ); // FIXME: physical mapping is not implemented. if ( pStage->enableSpecularMapping ) @@ -1766,31 +1896,51 @@ static void Render_forwardLighting_DBS_directional( shaderStage_t *pStage, trRef // bind u_ShadowMap if ( shadowCompare ) { - GL_BindToTMU( 5, tr.sunShadowMapFBOImage[ 0 ] ); - GL_BindToTMU( 10, tr.sunShadowClipMapFBOImage[ 0 ] ); + gl_forwardLightingShader_directionalSun->SetUniform_ShadowMap0Bindless( + GL_BindToTMU( 5, tr.sunShadowMapFBOImage[ 0 ] ) + ); + gl_forwardLightingShader_directionalSun->SetUniform_ShadowClipMap0Bindless( + GL_BindToTMU( 10, tr.sunShadowClipMapFBOImage[ 0 ] ) + ); if ( r_parallelShadowSplits->integer >= 1 ) { - GL_BindToTMU( 6, tr.sunShadowMapFBOImage[ 1 ] ); - GL_BindToTMU( 11, tr.sunShadowClipMapFBOImage[ 1 ] ); + gl_forwardLightingShader_directionalSun->SetUniform_ShadowMap1Bindless( + GL_BindToTMU( 6, tr.sunShadowMapFBOImage[ 1 ] ) + ); + gl_forwardLightingShader_directionalSun->SetUniform_ShadowClipMap1Bindless( + GL_BindToTMU( 11, tr.sunShadowClipMapFBOImage[ 1 ] ) + ); } if ( r_parallelShadowSplits->integer >= 2 ) { - GL_BindToTMU( 7, tr.sunShadowMapFBOImage[ 2 ] ); ; - GL_BindToTMU( 12, tr.sunShadowClipMapFBOImage[ 2 ] ); + gl_forwardLightingShader_directionalSun->SetUniform_ShadowMap2Bindless( + GL_BindToTMU( 7, tr.sunShadowMapFBOImage[ 2 ] ) + ); + gl_forwardLightingShader_directionalSun->SetUniform_ShadowClipMap2Bindless( + GL_BindToTMU( 12, tr.sunShadowClipMapFBOImage[ 2 ] ) + ); } if ( r_parallelShadowSplits->integer >= 3 ) { - GL_BindToTMU( 8, tr.sunShadowMapFBOImage[ 3 ] ); - GL_BindToTMU( 13, tr.sunShadowClipMapFBOImage[ 3 ] ); + gl_forwardLightingShader_directionalSun->SetUniform_ShadowMap3Bindless( + GL_BindToTMU( 8, tr.sunShadowMapFBOImage[ 3 ] ) + ); + gl_forwardLightingShader_directionalSun->SetUniform_ShadowClipMap3Bindless( + GL_BindToTMU( 13, tr.sunShadowClipMapFBOImage[ 3 ] ) + ); } if ( r_parallelShadowSplits->integer >= 4 ) { - GL_BindToTMU( 9, tr.sunShadowMapFBOImage[ 4 ] ); - GL_BindToTMU( 14, tr.sunShadowClipMapFBOImage[ 4 ] ); + gl_forwardLightingShader_directionalSun->SetUniform_ShadowMap4Bindless( + GL_BindToTMU( 9, tr.sunShadowMapFBOImage[ 4 ] ) + ); + gl_forwardLightingShader_directionalSun->SetUniform_ShadowClipMap4Bindless( + GL_BindToTMU( 14, tr.sunShadowClipMapFBOImage[ 4 ] ) + ); } } @@ -1805,6 +1955,11 @@ void Render_reflection_CB( shaderStage_t *pStage ) { GLimp_LogComment( "--- Render_reflection_CB ---\n" ); + if ( materialSystem.generatingWorldCommandBuffer ) { + Tess_DrawElements(); + return; + } + GL_State( pStage->stateBits ); // choose right shader program ---------------------------------- @@ -1836,18 +1991,19 @@ void Render_reflection_CB( shaderStage_t *pStage ) } // bind u_ColorMap - GL_SelectTexture( 0 ); if ( backEnd.currentEntity && ( backEnd.currentEntity != &tr.worldEntity ) ) { - GL_BindNearestCubeMap( backEnd.currentEntity->e.origin ); + GL_BindNearestCubeMap( 0, backEnd.currentEntity->e.origin ); } else { - GL_BindNearestCubeMap( backEnd.viewParms.orientation.origin ); + GL_BindNearestCubeMap( 0, backEnd.viewParms.orientation.origin ); } // bind u_NormalMap - GL_BindToTMU( 1, pStage->bundle[ TB_NORMALMAP ].image[ 0 ] ); + gl_reflectionShader->SetUniform_NormalMapBindless( + GL_BindToTMU( 1, pStage->bundle[TB_NORMALMAP].image[0] ) + ); // bind u_NormalScale if ( pStage->enableNormalMapping ) @@ -1872,7 +2028,9 @@ void Render_reflection_CB( shaderStage_t *pStage ) // FIXME: if there is both, embedded heightmap in normalmap is used instead of standalone heightmap if ( !pStage->hasHeightMapInNormalMap ) { - GL_BindToTMU( 15, pStage->bundle[ TB_HEIGHTMAP ].image[ 0 ] ); + gl_reflectionShader->SetUniform_HeightMapBindless( + GL_BindToTMU( 15, pStage->bundle[TB_HEIGHTMAP].image[0] ) + ); } } @@ -1887,6 +2045,11 @@ void Render_skybox( shaderStage_t *pStage ) { GLimp_LogComment( "--- Render_skybox ---\n" ); + if ( materialSystem.generatingWorldCommandBuffer ) { + Tess_DrawElements(); + return; + } + GL_State( pStage->stateBits ); gl_skyboxShader->BindProgram( pStage->deformIndex ); @@ -1897,7 +2060,9 @@ void Render_skybox( shaderStage_t *pStage ) gl_skyboxShader->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[ glState.stackIndex ] ); // bind u_ColorMap - GL_BindToTMU( 0, pStage->bundle[ TB_COLORMAP ].image[ 0 ] ); + gl_skyboxShader->SetUniform_ColorMapCubeBindless( + GL_BindToTMU( 0, pStage->bundle[TB_COLORMAP].image[0] ) + ); // u_AlphaThreshold gl_skyboxShader->SetUniform_AlphaTest( GLS_ATEST_NONE ); @@ -1916,6 +2081,11 @@ void Render_screen( shaderStage_t *pStage ) { GLimp_LogComment( "--- Render_screen ---\n" ); + if ( materialSystem.generatingWorldCommandBuffer ) { + Tess_DrawElements(); + return; + } + GL_State( pStage->stateBits ); gl_screenShader->BindProgram( pStage->deformIndex ); @@ -1928,8 +2098,7 @@ void Render_screen( shaderStage_t *pStage ) gl_screenShader->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[ glState.stackIndex ] ); // bind u_CurrentMap - GL_SelectTexture( 0 ); - BindAnimatedImage( &pStage->bundle[ TB_COLORMAP ] ); + gl_screenShader->SetUniform_CurrentMapBindless( BindAnimatedImage( 0, &pStage->bundle[TB_COLORMAP] ) ); Tess_DrawElements(); @@ -1956,8 +2125,7 @@ void Render_portal( shaderStage_t *pStage ) gl_portalShader->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[ glState.stackIndex ] ); // bind u_CurrentMap - GL_SelectTexture( 0 ); - BindAnimatedImage( &pStage->bundle[ TB_COLORMAP ] ); + gl_portalShader->SetUniform_CurrentMapBindless( BindAnimatedImage( 0, &pStage->bundle[TB_COLORMAP] ) ); Tess_DrawElements(); @@ -1971,6 +2139,11 @@ void Render_heatHaze( shaderStage_t *pStage ) GLimp_LogComment( "--- Render_heatHaze ---\n" ); + // Skip this until heatHaze is working with material system + if ( materialSystem.generatingWorldCommandBuffer ) { + return; + } + // remove alpha test stateBits = pStage->stateBits; stateBits &= ~GLS_ATEST_BITS; @@ -2025,7 +2198,9 @@ void Render_heatHaze( shaderStage_t *pStage ) R_BindFBO( tr.mainFBO[ 1 - backEnd.currentMainFBO ] ); // bind u_NormalMap - GL_BindToTMU( 0, pStage->bundle[ TB_NORMALMAP ].image[ 0 ] ); + gl_heatHazeShader->SetUniform_NormalMapBindless( + GL_BindToTMU( 0, pStage->bundle[TB_NORMALMAP].image[0] ) + ); if ( pStage->enableNormalMapping ) { @@ -2039,7 +2214,9 @@ void Render_heatHaze( shaderStage_t *pStage ) } // bind u_CurrentMap - GL_BindToTMU( 1, tr.currentRenderImage[ backEnd.currentMainFBO ] ); + gl_heatHazeShader->SetUniform_CurrentMapBindless( + GL_BindToTMU( 1, tr.currentRenderImage[backEnd.currentMainFBO] ) + ); gl_heatHazeShader->SetRequiredVertexPointers( vboVertexSprite ); @@ -2047,7 +2224,9 @@ void Render_heatHaze( shaderStage_t *pStage ) // copy to foreground image R_BindFBO( tr.mainFBO[ backEnd.currentMainFBO ] ); - GL_BindToTMU( 1, tr.currentRenderImage[ 1 - backEnd.currentMainFBO ] ); + gl_heatHazeShader->SetUniform_CurrentMapBindless( + GL_BindToTMU( 1, tr.currentRenderImage[1 - backEnd.currentMainFBO] ) + ); gl_heatHazeShader->SetUniform_DeformMagnitude( 0.0f ); Tess_DrawElements(); @@ -2062,6 +2241,11 @@ void Render_liquid( shaderStage_t *pStage ) GLimp_LogComment( "--- Render_liquid ---\n" ); + if ( materialSystem.generatingWorldCommandBuffer ) { + Tess_DrawElements(); + return; + } + // Tr3B: don't allow blend effects GL_State( pStage->stateBits & ~( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS | GLS_DEPTHMASK_TRUE ) ); @@ -2102,13 +2286,13 @@ void Render_liquid( shaderStage_t *pStage ) } // bind u_CurrentMap - GL_BindToTMU( 0, tr.currentRenderImage[ backEnd.currentMainFBO ] ); + gl_liquidShader->SetUniform_CurrentMapBindless( GL_BindToTMU( 0, tr.currentRenderImage[backEnd.currentMainFBO] ) ); // bind u_PortalMap - GL_BindToTMU( 1, tr.portalRenderImage ); + gl_liquidShader->SetUniform_PortalMapBindless( GL_BindToTMU( 1, tr.portalRenderImage ) ); // depth texture - GL_BindToTMU( 2, tr.currentDepthImage ); + gl_liquidShader->SetUniform_DepthMapBindless( GL_BindToTMU( 2, tr.currentDepthImage ) ); // bind u_HeightMap u_depthScale u_reliefOffsetBias if ( pStage->enableReliefMapping ) @@ -2122,12 +2306,12 @@ void Render_liquid( shaderStage_t *pStage ) // FIXME: if there is both, embedded heightmap in normalmap is used instead of standalone heightmap if ( !pStage->hasHeightMapInNormalMap ) { - GL_BindToTMU( 15, pStage->bundle[ TB_HEIGHTMAP ].image[ 0 ] ); + gl_liquidShader->SetUniform_HeightMapBindless( GL_BindToTMU( 15, pStage->bundle[TB_HEIGHTMAP].image[0] ) ); } } // bind u_NormalMap - GL_BindToTMU( 3, pStage->bundle[ TB_NORMALMAP ].image[ 0 ] ); + gl_liquidShader->SetUniform_NormalMapBindless( GL_BindToTMU( 3, pStage->bundle[TB_NORMALMAP].image[0] ) ); // bind u_NormalScale if ( pStage->enableNormalMapping ) @@ -2257,7 +2441,9 @@ static void Render_fog() gl_fogQuake3Shader->SetUniform_Time( backEnd.refdef.floatTime - backEnd.currentEntity->e.shaderTime ); // bind u_ColorMap - GL_BindToTMU( 0, tr.fogImage ); + gl_fogQuake3Shader->SetUniform_ColorMapBindless( + GL_BindToTMU( 0, tr.fogImage ) + ); gl_fogQuake3Shader->SetRequiredVertexPointers(); @@ -2508,7 +2694,7 @@ void Tess_ComputeColor( shaderStage_t *pStage ) Tess_ComputeTexMatrices =============== */ -static void Tess_ComputeTexMatrices( shaderStage_t *pStage ) +void Tess_ComputeTexMatrices( shaderStage_t *pStage ) { GLimp_LogComment( "--- Tess_ComputeTexMatrices ---\n" ); @@ -2577,9 +2763,10 @@ void Tess_StageIteratorColor() } // call shader function + uint stage = 0; for ( shaderStage_t *pStage = tess.surfaceStages; pStage < tess.surfaceLastStage; pStage++ ) { - if ( !RB_EvalExpression( &pStage->ifExp, 1.0 ) ) + if ( !RB_EvalExpression( &pStage->ifExp, 1.0 ) && !( materialSystem.generatingWorldCommandBuffer && pStage->useMaterialSystem ) ) { continue; } @@ -2587,7 +2774,15 @@ void Tess_StageIteratorColor() Tess_ComputeColor( pStage ); Tess_ComputeTexMatrices( pStage ); + if ( materialSystem.generatingWorldCommandBuffer && pStage->useMaterialSystem ) { + tess.currentSSBOOffset = tess.currentDrawSurf->materialsSSBOOffset[stage]; + tess.materialID = tess.currentDrawSurf->materialIDs[stage]; + tess.materialPackID = tess.currentDrawSurf->materialPackIDs[stage]; + } + pStage->colorRenderer( pStage ); + + stage++; } if ( !r_noFog->integer && tess.fogNum >= 1 && tess.surfaceShader->fogPass != fogPass_t::FP_NONE ) @@ -2806,7 +3001,7 @@ Render tesselated data */ void Tess_End() { - if ( ( tess.numIndexes == 0 || tess.numVertexes == 0 ) && tess.multiDrawPrimitives == 0 ) + if ( ( tess.numIndexes == 0 || tess.numVertexes == 0 ) && tess.multiDrawPrimitives == 0 && !tr.drawingSky ) { return; } diff --git a/src/engine/renderer/tr_sky.cpp b/src/engine/renderer/tr_sky.cpp index 01d97d4c9f..b98a05cbfb 100644 --- a/src/engine/renderer/tr_sky.cpp +++ b/src/engine/renderer/tr_sky.cpp @@ -26,19 +26,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA //====================================================================================== -static void Tess_ComputeTexMatrices( shaderStage_t* pStage ) { - int i; - vec_t* matrix; - - GLimp_LogComment( "--- Tess_ComputeTexMatrices ---\n" ); - - for ( i = 0; i < MAX_TEXTURE_BUNDLES; i++ ) { - matrix = tess.svars.texMatrices[i]; - - RB_CalcTexMatrix( &pStage->bundle[i], matrix ); - } -} - /* ================ Tess_StageIteratorSky @@ -60,6 +47,8 @@ void Tess_StageIteratorSky() tess.numVertexes, tess.numIndexes / 3 ) ); } + tr.drawingSky = false; + if ( r_fastsky->integer ) { return; @@ -126,7 +115,9 @@ void Tess_StageIteratorSky() GL_State( GLS_DEFAULT ); // bind u_ColorMap - GL_BindToTMU( 0, tess.surfaceShader->sky.outerbox ); + gl_skyboxShader->SetUniform_ColorMapCubeBindless( + GL_BindToTMU( 0, tess.surfaceShader->sky.outerbox ) + ); // Only render the outer skybox at this stage gl_skyboxShader->SetUniform_UseCloudMap( false ); @@ -151,7 +142,9 @@ void Tess_StageIteratorSky() gl_skyboxShader->SetUniform_TextureMatrix( tess.svars.texMatrices[TB_COLORMAP] ); - GL_BindToTMU( 1, pStage->bundle[TB_COLORMAP].image[0] ); + gl_skyboxShader->SetUniform_CloudMapBindless( + GL_BindToTMU( 1, pStage->bundle[TB_COLORMAP].image[0] ) + ); // u_AlphaThreshold gl_skyboxShader->SetUniform_AlphaTest( pStage->stateBits ); diff --git a/src/engine/renderer/tr_surface.cpp b/src/engine/renderer/tr_surface.cpp index e934de7152..c2af5df58a 100644 --- a/src/engine/renderer/tr_surface.cpp +++ b/src/engine/renderer/tr_surface.cpp @@ -23,6 +23,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // tr_surface.c #include "tr_local.h" #include "gl_shader.h" +#include "Material.h" /* ============================================================================== @@ -207,11 +208,13 @@ static bool Tess_SurfaceVBO( VBO_t *vbo, IBO_t *ibo, int numIndexes, int firstIn else if ( mergeBack ) { tess.multiDrawIndexes[ tess.multiDrawPrimitives - 1 ] = firstIndexOffset; + tess.multiDrawOffsets[ tess.multiDrawPrimitives - 1 ] = (GLuint) firstIndex; tess.multiDrawCounts[ tess.multiDrawPrimitives - 1 ] += numIndexes; } else { tess.multiDrawIndexes[ tess.multiDrawPrimitives ] = firstIndexOffset; + tess.multiDrawOffsets[ tess.multiDrawPrimitives ] = (GLuint) firstIndex; tess.multiDrawCounts[ tess.multiDrawPrimitives ] = numIndexes; tess.multiDrawPrimitives++; diff --git a/src/engine/renderer/tr_vbo.cpp b/src/engine/renderer/tr_vbo.cpp index fec34a85b5..f085f8dc8c 100644 --- a/src/engine/renderer/tr_vbo.cpp +++ b/src/engine/renderer/tr_vbo.cpp @@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ // tr_vbo.c #include "tr_local.h" +#include "Material.h" // "templates" for VBO vertex data layouts @@ -1029,6 +1030,13 @@ static void R_InitLightUBO() } } +static void R_InitMaterialBuffers() { + if( glConfig2.materialSystemAvailable ) { + materialsSSBO.GenBuffer(); + commandBuffer.GenBuffer(); + } +} + /* ============ R_InitVBOs @@ -1076,6 +1084,8 @@ void R_InitVBOs() R_InitLightUBO(); + R_InitMaterialBuffers(); + GL_CheckErrors(); } @@ -1144,6 +1154,11 @@ void R_ShutdownVBOs() tr.dlightUBO = 0; } + if ( glConfig2.materialSystemAvailable ) { + materialsSSBO.DelBuffer(); + commandBuffer.DelBuffer(); + } + tess.verts = tess.vertsBuffer = nullptr; tess.indexes = tess.indexesBuffer = nullptr; } diff --git a/src/engine/renderer/tr_world.cpp b/src/engine/renderer/tr_world.cpp index 2698ef71a7..79860210d7 100644 --- a/src/engine/renderer/tr_world.cpp +++ b/src/engine/renderer/tr_world.cpp @@ -24,6 +24,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "tr_local.h" #include "gl_shader.h" +#include "Material.h" static Cvar::Modified> r_showCluster( "r_showCluster", "print PVS cluster at current location", Cvar::CHEAT, false ); @@ -435,7 +436,7 @@ static void R_RecursiveWorldNode( bspNode_t *node, int planeBits, int decalBits do { // if the node wasn't marked as potentially visible, exit - if ( node->visCounts[ tr.visIndex ] != tr.visCounts[ tr.visIndex ] ) + if ( node->visCounts[ tr.visIndex ] != tr.visCounts[ tr.visIndex ] && !materialSystem.generatingWorldCommandBuffer ) { return; } diff --git a/src/engine/sys/sdl_glimp.cpp b/src/engine/sys/sdl_glimp.cpp index 8a82d24d2d..7203c6b9bb 100644 --- a/src/engine/sys/sdl_glimp.cpp +++ b/src/engine/sys/sdl_glimp.cpp @@ -54,6 +54,12 @@ static Cvar::Cvar r_availableModes( "r_availableModes", "list of available resolutions", Cvar::ROM, ""); // OpenGL extension cvars. +/* Driver bug: Mesa versions > 24.0.9 produce garbage rendering when r_arb_bindless_texture is enabled, +and the shader compiler crashes with material shaders +24.0.9 is the latest known working version, 24.1.1 is the earliest known broken version +So this defaults to disabled */ +static Cvar::Cvar r_arb_bindless_texture( "r_arb_bindless_texture", + "Use GL_ARB_bindless_texture if available", Cvar::NONE, false ); static Cvar::Cvar r_arb_buffer_storage( "r_arb_buffer_storage", "Use GL_ARB_buffer_storage if available", Cvar::NONE, true ); static Cvar::Cvar r_arb_compute_shader( "r_arb_compute_shader", @@ -66,6 +72,12 @@ static Cvar::Cvar r_arb_gpu_shader5( "r_arb_gpu_shader5", "Use GL_ARB_gpu_shader5 if available", Cvar::NONE, true ); static Cvar::Cvar r_arb_map_buffer_range( "r_arb_map_buffer_range", "Use GL_ARB_map_buffer_range if available", Cvar::NONE, true ); +static Cvar::Cvar r_arb_multi_draw_indirect( "r_arb_multi_draw_indirect", + "Use GL_ARB_multi_draw_indirect if available", Cvar::NONE, true ); +static Cvar::Cvar r_arb_shader_draw_parameters( "r_arb_shader_draw_parameters", + "Use GL_ARB_shader_draw_parameters if available", Cvar::NONE, true ); +static Cvar::Cvar r_arb_shader_storage_buffer_object( "r_arb_shader_storage_buffer_object", + "Use GL_ARB_shader_storage_buffer_object if available", Cvar::NONE, true ); static Cvar::Cvar r_arb_sync( "r_arb_sync", "Use GL_ARB_sync if available", Cvar::NONE, true ); static Cvar::Cvar r_arb_texture_gather( "r_arb_texture_gather", @@ -1782,12 +1794,16 @@ static void GLimp_InitExtensions() { logger.Notice("Initializing OpenGL extensions" ); + Cvar::Latch( r_arb_bindless_texture ); Cvar::Latch( r_arb_buffer_storage ); Cvar::Latch( r_arb_compute_shader ); Cvar::Latch( r_arb_debug_output ); Cvar::Latch( r_arb_depth_clamp ); Cvar::Latch( r_arb_gpu_shader5 ); Cvar::Latch( r_arb_map_buffer_range ); + Cvar::Latch( r_arb_multi_draw_indirect ); + Cvar::Latch( r_arb_shader_draw_parameters ); + Cvar::Latch( r_arb_shader_storage_buffer_object ); Cvar::Latch( r_arb_sync ); Cvar::Latch( r_arb_texture_gather ); Cvar::Latch( r_arb_uniform_buffer_object ); @@ -2011,6 +2027,60 @@ static void GLimp_InitExtensions() // made required in OpenGL 4.3 glConfig2.computeShaderAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_NONE, ARB_compute_shader, r_arb_compute_shader.Get() ); + // Some of the mesa 24.x driver versions have a bug in their shader compiler related to bindless textures, + // which results in either glitches or the shader compiler crashing (when material system is enabled) + { + bool foundMesa241 = false; + std::string mesaVersion = ""; + + static const std::vector>> versions = { + { "1.0", { "1.0-devel", "1.0-rc1", "1.0-rc2", "1.0-rc3", "1.0-rc4", "1.0", } }, + { "1.", { "1.1", "1.2", "1.3", "1.4", } }, + { "2.0", { "2.0-devel", "2.0-rc1", } }, + }; + + for ( auto& vp : versions ) { + mesaVersion = Str::Format( "Mesa 24.%s", vp.first ); + + if ( Q_stristr( glConfig.version_string, mesaVersion.c_str() ) ) { + for ( auto& v : vp.second ) { + mesaVersion = Str::Format( "Mesa 24.%s", v ); + + if ( Q_stristr( glConfig.version_string, mesaVersion.c_str() ) ) { + foundMesa241 = true; + break; + } + } + + break; + } + } + + if ( foundMesa241 ) { + logger.Warn( "...found buggy %s driver, ARB_bindless_texture disabled", mesaVersion ); + } + + // not required by any OpenGL version + glConfig2.bindlessTexturesAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_NONE, ARB_bindless_texture, r_arb_bindless_texture.Get() && !foundMesa241 ); + } + + // made required in OpenGL 4.6 + glConfig2.shaderDrawParametersAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_NONE, ARB_shader_draw_parameters, r_arb_shader_draw_parameters.Get() ); + + // made required in OpenGL 4.3 + glConfig2.SSBOAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_NONE, ARB_shader_storage_buffer_object, r_arb_shader_storage_buffer_object.Get() ); + + // made required in OpenGL 4.0 + glConfig2.multiDrawIndirectAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_NONE, ARB_multi_draw_indirect, r_arb_multi_draw_indirect.Get() ); + + glConfig2.materialSystemAvailable = glConfig2.shaderDrawParametersAvailable && glConfig2.SSBOAvailable && + glConfig2.multiDrawIndirectAvailable && glConfig2.bindlessTexturesAvailable + && r_smp->integer == 0 // Currently doesn't work with r_smp 1 + && r_materialSystem.Get(); // Allow disabling it without disabling any extensions + if ( r_materialSystem.Get() && r_smp->integer ) { + Log::Warn( "Material system disabled because r_smp is not 0" ); + } + GL_CheckErrors(); }