2016-02-16 17:18:48 +00:00
# include "shadervisitor.hpp"
2020-12-16 23:44:15 +00:00
# include <osg/AlphaFunc>
2016-02-16 17:18:48 +00:00
# include <osg/Geometry>
2021-01-07 18:13:51 +00:00
# include <osg/GLExtensions>
2020-04-10 14:45:37 +00:00
# include <osg/Material>
2020-12-26 22:45:53 +00:00
# include <osg/Multisample>
2020-04-10 14:45:37 +00:00
# include <osg/Texture>
2021-03-24 12:32:15 +00:00
# include <osg/ValueObject>
2016-02-16 17:18:48 +00:00
# include <osgUtil/TangentSpaceGenerator>
2018-08-14 15:42:41 +00:00
# include <components/debug/debuglog.hpp>
2020-01-09 11:57:05 +00:00
# include <components/misc/stringops.hpp>
2016-02-20 16:57:19 +00:00
# include <components/resource/imagemanager.hpp>
# include <components/vfs/manager.hpp>
2016-03-23 15:48:41 +00:00
# include <components/sceneutil/riggeometry.hpp>
2017-09-01 20:56:09 +00:00
# include <components/sceneutil/morphgeometry.hpp>
2016-02-16 17:18:48 +00:00
2020-12-16 23:44:15 +00:00
# include "removedalphafunc.hpp"
2016-02-16 17:18:48 +00:00
# include "shadermanager.hpp"
namespace Shader
{
ShaderVisitor : : ShaderRequirements : : ShaderRequirements ( )
2016-02-20 18:02:11 +00:00
: mShaderRequired ( false )
2018-12-03 18:56:37 +00:00
, mColorMode ( 0 )
2016-02-18 21:48:53 +00:00
, mMaterialOverridden ( false )
2020-12-16 23:44:15 +00:00
, mAlphaTestOverridden ( false )
2021-01-02 19:09:06 +00:00
, mAlphaBlendOverridden ( false )
2020-12-16 23:44:15 +00:00
, mAlphaFunc ( GL_ALWAYS )
, mAlphaRef ( 1.0 )
2021-01-02 19:09:06 +00:00
, mAlphaBlend ( false )
2016-03-22 20:22:59 +00:00
, mNormalHeight ( false )
2016-02-16 17:18:48 +00:00
, mTexStageRequiringTangents ( - 1 )
2018-10-09 06:21:12 +00:00
, mNode ( nullptr )
2016-02-16 17:18:48 +00:00
{
}
2016-02-20 16:57:19 +00:00
ShaderVisitor : : ShaderRequirements : : ~ ShaderRequirements ( )
{
}
2020-12-16 21:46:09 +00:00
ShaderVisitor : : ShaderVisitor ( ShaderManager & shaderManager , Resource : : ImageManager & imageManager , const std : : string & defaultShaderPrefix )
2016-02-16 17:18:48 +00:00
: osg : : NodeVisitor ( TRAVERSE_ALL_CHILDREN )
2016-02-18 16:08:18 +00:00
, mForceShaders ( false )
2016-02-18 21:48:53 +00:00
, mAllowedToModifyStateSets ( true )
2016-02-20 16:57:19 +00:00
, mAutoUseNormalMaps ( false )
2016-02-20 18:02:11 +00:00
, mAutoUseSpecularMaps ( false )
2020-11-09 10:53:58 +00:00
, mApplyLightingToEnvMaps ( false )
2021-04-09 23:08:51 +00:00
, mConvertAlphaTestToAlphaToCoverage ( false )
2021-01-20 23:37:19 +00:00
, mTranslucentFramebuffer ( false )
2016-02-16 17:18:48 +00:00
, mShaderManager ( shaderManager )
2016-02-20 16:57:19 +00:00
, mImageManager ( imageManager )
2020-12-16 21:46:09 +00:00
, mDefaultShaderPrefix ( defaultShaderPrefix )
2016-02-16 17:18:48 +00:00
{
2020-10-17 08:26:35 +00:00
mRequirements . emplace_back ( ) ;
2016-02-16 17:18:48 +00:00
}
2016-02-18 16:08:18 +00:00
void ShaderVisitor : : setForceShaders ( bool force )
{
mForceShaders = force ;
}
2016-02-16 17:18:48 +00:00
void ShaderVisitor : : apply ( osg : : Node & node )
{
if ( node . getStateSet ( ) )
{
2017-08-31 21:39:21 +00:00
pushRequirements ( node ) ;
2016-02-18 21:48:53 +00:00
applyStateSet ( node . getStateSet ( ) , node ) ;
2016-02-16 17:18:48 +00:00
traverse ( node ) ;
popRequirements ( ) ;
}
else
traverse ( node ) ;
}
2016-02-18 21:48:53 +00:00
osg : : StateSet * getWritableStateSet ( osg : : Node & node )
2016-02-16 17:18:48 +00:00
{
2016-02-18 21:48:53 +00:00
if ( ! node . getStateSet ( ) )
return node . getOrCreateStateSet ( ) ;
2017-02-09 03:50:51 +00:00
osg : : ref_ptr < osg : : StateSet > newStateSet = new osg : : StateSet ( * node . getStateSet ( ) , osg : : CopyOp : : SHALLOW_COPY ) ;
2016-02-18 21:48:53 +00:00
node . setStateSet ( newStateSet ) ;
return newStateSet . get ( ) ;
}
2020-12-16 23:44:15 +00:00
osg : : UserDataContainer * getWritableUserDataContainer ( osg : : Object & object )
{
if ( ! object . getUserDataContainer ( ) )
return object . getOrCreateUserDataContainer ( ) ;
osg : : ref_ptr < osg : : UserDataContainer > newUserData = static_cast < osg : : UserDataContainer * > ( object . getUserDataContainer ( ) - > clone ( osg : : CopyOp : : SHALLOW_COPY ) ) ;
object . setUserDataContainer ( newUserData ) ;
return newUserData . get ( ) ;
}
osg : : StateSet * getRemovedState ( osg : : StateSet & stateSet )
{
if ( ! stateSet . getUserDataContainer ( ) )
return nullptr ;
return static_cast < osg : : StateSet * > ( stateSet . getUserDataContainer ( ) - > getUserObject ( " removedState " ) ) ;
}
void updateRemovedState ( osg : : UserDataContainer & userData , osg : : StateSet * stateSet )
{
unsigned int index = userData . getUserObjectIndex ( " removedState " ) ;
if ( index < userData . getNumUserObjects ( ) )
userData . setUserObject ( index , stateSet ) ;
else
userData . addUserObject ( stateSet ) ;
stateSet - > setName ( " removedState " ) ;
}
2020-03-02 01:03:36 +00:00
const char * defaultTextures [ ] = { " diffuseMap " , " normalMap " , " emissiveMap " , " darkMap " , " detailMap " , " envMap " , " specularMap " , " decalMap " , " bumpMap " } ;
2016-02-20 22:43:05 +00:00
bool isTextureNameRecognized ( const std : : string & name )
{
for ( unsigned int i = 0 ; i < sizeof ( defaultTextures ) / sizeof ( defaultTextures [ 0 ] ) ; + + i )
2016-03-01 17:41:36 +00:00
if ( name = = defaultTextures [ i ] )
2016-02-20 22:43:05 +00:00
return true ;
return false ;
}
2016-02-18 21:48:53 +00:00
void ShaderVisitor : : applyStateSet ( osg : : ref_ptr < osg : : StateSet > stateset , osg : : Node & node )
{
2018-10-09 06:21:12 +00:00
osg : : StateSet * writableStateSet = nullptr ;
2016-02-18 21:48:53 +00:00
if ( mAllowedToModifyStateSets )
writableStateSet = node . getStateSet ( ) ;
2016-02-16 17:18:48 +00:00
const osg : : StateSet : : TextureAttributeList & texAttributes = stateset - > getTextureAttributeList ( ) ;
2020-12-16 21:46:09 +00:00
bool shaderRequired = false ;
if ( node . getUserValue ( " shaderRequired " , shaderRequired ) & & shaderRequired )
mRequirements . back ( ) . mShaderRequired = true ;
2016-02-22 18:06:12 +00:00
if ( ! texAttributes . empty ( ) )
2016-02-16 17:18:48 +00:00
{
2018-10-09 06:21:12 +00:00
const osg : : Texture * diffuseMap = nullptr ;
const osg : : Texture * normalMap = nullptr ;
const osg : : Texture * specularMap = nullptr ;
2020-03-05 10:15:18 +00:00
const osg : : Texture * bumpMap = nullptr ;
2016-02-20 16:57:19 +00:00
for ( unsigned int unit = 0 ; unit < texAttributes . size ( ) ; + + unit )
2016-02-16 17:18:48 +00:00
{
2016-02-20 16:57:19 +00:00
const osg : : StateAttribute * attr = stateset - > getTextureAttribute ( unit , osg : : StateAttribute : : TEXTURE ) ;
if ( attr )
2016-02-16 17:18:48 +00:00
{
2016-02-20 16:57:19 +00:00
const osg : : Texture * texture = attr - > asTexture ( ) ;
if ( texture )
2016-02-16 17:18:48 +00:00
{
2016-02-20 22:43:05 +00:00
std : : string texName = texture - > getName ( ) ;
if ( ( texName . empty ( ) | | ! isTextureNameRecognized ( texName ) ) & & unit = = 0 )
texName = " diffuseMap " ;
2016-03-22 20:22:59 +00:00
if ( texName = = " normalHeightMap " )
{
mRequirements . back ( ) . mNormalHeight = true ;
texName = " normalMap " ;
}
2016-02-20 22:43:05 +00:00
if ( ! texName . empty ( ) )
2016-02-16 17:18:48 +00:00
{
2016-02-20 22:43:05 +00:00
mRequirements . back ( ) . mTextures [ unit ] = texName ;
if ( texName = = " normalMap " )
2016-02-20 16:57:19 +00:00
{
mRequirements . back ( ) . mTexStageRequiringTangents = unit ;
2016-02-20 18:02:11 +00:00
mRequirements . back ( ) . mShaderRequired = true ;
2016-02-20 16:57:19 +00:00
if ( ! writableStateSet )
writableStateSet = getWritableStateSet ( node ) ;
// normal maps are by default off since the FFP can't render them, now that we'll use shaders switch to On
writableStateSet - > setTextureMode ( unit , GL_TEXTURE_2D , osg : : StateAttribute : : ON ) ;
normalMap = texture ;
}
2016-03-22 20:22:59 +00:00
else if ( texName = = " diffuseMap " )
2016-02-20 16:57:19 +00:00
diffuseMap = texture ;
2016-03-22 20:22:59 +00:00
else if ( texName = = " specularMap " )
2016-02-20 18:02:11 +00:00
specularMap = texture ;
2020-03-02 01:03:36 +00:00
else if ( texName = = " bumpMap " )
{
2020-03-05 10:15:18 +00:00
bumpMap = texture ;
2020-03-02 01:03:36 +00:00
mRequirements . back ( ) . mShaderRequired = true ;
if ( ! writableStateSet )
writableStateSet = getWritableStateSet ( node ) ;
// Bump maps are off by default as well
writableStateSet - > setTextureMode ( unit , GL_TEXTURE_2D , osg : : StateAttribute : : ON ) ;
}
2020-11-09 10:53:58 +00:00
else if ( texName = = " envMap " & & mApplyLightingToEnvMaps )
2020-03-04 11:06:22 +00:00
{
2020-11-09 10:53:58 +00:00
mRequirements . back ( ) . mShaderRequired = true ;
2020-03-04 11:06:22 +00:00
}
2016-02-16 17:18:48 +00:00
}
2021-01-20 23:37:19 +00:00
else if ( ! mTranslucentFramebuffer )
2018-08-14 15:42:41 +00:00
Log ( Debug : : Error ) < < " ShaderVisitor encountered unknown texture " < < texture ;
2016-02-16 17:18:48 +00:00
}
2016-02-20 16:57:19 +00:00
}
2016-02-16 17:18:48 +00:00
}
2016-02-20 16:57:19 +00:00
2018-10-09 06:21:12 +00:00
if ( mAutoUseNormalMaps & & diffuseMap ! = nullptr & & normalMap = = nullptr & & diffuseMap - > getImage ( 0 ) )
2016-02-18 21:48:53 +00:00
{
2016-08-29 10:20:00 +00:00
std : : string normalMapFileName = diffuseMap - > getImage ( 0 ) - > getFileName ( ) ;
2016-03-22 20:22:59 +00:00
osg : : ref_ptr < osg : : Image > image ;
bool normalHeight = false ;
2016-08-29 10:20:00 +00:00
std : : string normalHeightMap = normalMapFileName ;
2020-01-09 11:57:05 +00:00
Misc : : StringUtils : : replaceLast ( normalHeightMap , " . " , mNormalHeightMapPattern + " . " ) ;
2016-03-22 20:22:59 +00:00
if ( mImageManager . getVFS ( ) - > exists ( normalHeightMap ) )
{
image = mImageManager . getImage ( normalHeightMap ) ;
normalHeight = true ;
}
else
{
2020-01-09 11:57:05 +00:00
Misc : : StringUtils : : replaceLast ( normalMapFileName , " . " , mNormalMapPattern + " . " ) ;
2016-08-29 10:20:00 +00:00
if ( mImageManager . getVFS ( ) - > exists ( normalMapFileName ) )
2016-03-22 20:22:59 +00:00
{
2016-08-29 10:20:00 +00:00
image = mImageManager . getImage ( normalMapFileName ) ;
2016-03-22 20:22:59 +00:00
}
}
2020-03-05 10:15:18 +00:00
// Avoid using the auto-detected normal map if it's already being used as a bump map.
// It's probably not an actual normal map.
bool hasNamesakeBumpMap = image & & bumpMap & & bumpMap - > getImage ( 0 ) & & image - > getFileName ( ) = = bumpMap - > getImage ( 0 ) - > getFileName ( ) ;
2016-03-22 20:22:59 +00:00
2020-03-05 10:15:18 +00:00
if ( ! hasNamesakeBumpMap & & image )
2016-02-20 16:57:19 +00:00
{
2016-03-22 20:22:59 +00:00
osg : : ref_ptr < osg : : Texture2D > normalMapTex ( new osg : : Texture2D ( image ) ) ;
2019-05-29 13:37:00 +00:00
normalMapTex - > setTextureSize ( image - > s ( ) , image - > t ( ) ) ;
2016-02-20 16:57:19 +00:00
normalMapTex - > setWrap ( osg : : Texture : : WRAP_S , diffuseMap - > getWrap ( osg : : Texture : : WRAP_S ) ) ;
normalMapTex - > setWrap ( osg : : Texture : : WRAP_T , diffuseMap - > getWrap ( osg : : Texture : : WRAP_T ) ) ;
normalMapTex - > setFilter ( osg : : Texture : : MIN_FILTER , diffuseMap - > getFilter ( osg : : Texture : : MIN_FILTER ) ) ;
normalMapTex - > setFilter ( osg : : Texture : : MAG_FILTER , diffuseMap - > getFilter ( osg : : Texture : : MAG_FILTER ) ) ;
normalMapTex - > setMaxAnisotropy ( diffuseMap - > getMaxAnisotropy ( ) ) ;
normalMapTex - > setName ( " normalMap " ) ;
int unit = texAttributes . size ( ) ;
if ( ! writableStateSet )
writableStateSet = getWritableStateSet ( node ) ;
writableStateSet - > setTextureAttributeAndModes ( unit , normalMapTex , osg : : StateAttribute : : ON ) ;
mRequirements . back ( ) . mTextures [ unit ] = " normalMap " ;
mRequirements . back ( ) . mTexStageRequiringTangents = unit ;
2016-02-20 18:02:11 +00:00
mRequirements . back ( ) . mShaderRequired = true ;
2016-03-22 20:22:59 +00:00
mRequirements . back ( ) . mNormalHeight = normalHeight ;
2016-02-20 18:02:11 +00:00
}
}
2018-10-09 06:21:12 +00:00
if ( mAutoUseSpecularMaps & & diffuseMap ! = nullptr & & specularMap = = nullptr & & diffuseMap - > getImage ( 0 ) )
2016-02-20 18:02:11 +00:00
{
2016-08-29 10:20:00 +00:00
std : : string specularMapFileName = diffuseMap - > getImage ( 0 ) - > getFileName ( ) ;
2020-01-09 11:57:05 +00:00
Misc : : StringUtils : : replaceLast ( specularMapFileName , " . " , mSpecularMapPattern + " . " ) ;
2016-08-29 10:20:00 +00:00
if ( mImageManager . getVFS ( ) - > exists ( specularMapFileName ) )
2016-02-20 18:02:11 +00:00
{
2019-05-29 13:37:00 +00:00
osg : : ref_ptr < osg : : Image > image ( mImageManager . getImage ( specularMapFileName ) ) ;
osg : : ref_ptr < osg : : Texture2D > specularMapTex ( new osg : : Texture2D ( image ) ) ;
specularMapTex - > setTextureSize ( image - > s ( ) , image - > t ( ) ) ;
2016-02-20 18:02:11 +00:00
specularMapTex - > setWrap ( osg : : Texture : : WRAP_S , diffuseMap - > getWrap ( osg : : Texture : : WRAP_S ) ) ;
specularMapTex - > setWrap ( osg : : Texture : : WRAP_T , diffuseMap - > getWrap ( osg : : Texture : : WRAP_T ) ) ;
specularMapTex - > setFilter ( osg : : Texture : : MIN_FILTER , diffuseMap - > getFilter ( osg : : Texture : : MIN_FILTER ) ) ;
specularMapTex - > setFilter ( osg : : Texture : : MAG_FILTER , diffuseMap - > getFilter ( osg : : Texture : : MAG_FILTER ) ) ;
specularMapTex - > setMaxAnisotropy ( diffuseMap - > getMaxAnisotropy ( ) ) ;
specularMapTex - > setName ( " specularMap " ) ;
int unit = texAttributes . size ( ) ;
if ( ! writableStateSet )
writableStateSet = getWritableStateSet ( node ) ;
writableStateSet - > setTextureAttributeAndModes ( unit , specularMapTex , osg : : StateAttribute : : ON ) ;
mRequirements . back ( ) . mTextures [ unit ] = " specularMap " ;
mRequirements . back ( ) . mShaderRequired = true ;
2016-02-20 16:57:19 +00:00
}
2016-02-18 21:48:53 +00:00
}
2018-10-16 20:23:31 +00:00
if ( diffuseMap )
{
if ( ! writableStateSet )
writableStateSet = getWritableStateSet ( node ) ;
2020-04-27 22:49:48 +00:00
// We probably shouldn't construct a new version of this each time as Uniforms use pointer comparison for early-out.
2020-11-12 00:26:30 +00:00
// Also it should probably belong to the shader manager or be applied by the shadows bin
2018-10-16 20:23:31 +00:00
writableStateSet - > addUniform ( new osg : : Uniform ( " useDiffuseMapForShadowAlpha " , true ) ) ;
}
2016-02-16 17:18:48 +00:00
}
const osg : : StateSet : : AttributeList & attributes = stateset - > getAttributeList ( ) ;
2020-12-16 23:44:15 +00:00
osg : : StateSet : : AttributeList removedAttributes ;
2021-04-14 04:07:56 +00:00
if ( osg : : ref_ptr < osg : : StateSet > removedState = getRemovedState ( * stateset ) )
2020-12-16 23:44:15 +00:00
removedAttributes = removedState - > getAttributeList ( ) ;
2021-06-28 13:54:28 +00:00
for ( const auto * attributeMap : std : : initializer_list < const osg : : StateSet : : AttributeList * > { & attributes , & removedAttributes } )
2016-02-16 17:18:48 +00:00
{
2021-06-28 13:54:28 +00:00
for ( osg : : StateSet : : AttributeList : : const_iterator it = attributeMap - > begin ( ) ; it ! = attributeMap - > end ( ) ; + + it )
2016-02-16 17:18:48 +00:00
{
2021-06-28 13:54:28 +00:00
if ( attributeMap ! = & removedAttributes & & removedAttributes . count ( it - > first ) )
continue ;
2020-12-16 23:44:15 +00:00
if ( it - > first . first = = osg : : StateAttribute : : MATERIAL )
2016-02-18 21:48:53 +00:00
{
2020-12-16 23:44:15 +00:00
// This should probably be moved out of ShaderRequirements and be applied directly now it's a uniform instead of a define
if ( ! mRequirements . back ( ) . mMaterialOverridden | | it - > second . second & osg : : StateAttribute : : PROTECTED )
{
if ( it - > second . second & osg : : StateAttribute : : OVERRIDE )
mRequirements . back ( ) . mMaterialOverridden = true ;
2016-02-18 21:48:53 +00:00
2020-12-16 23:44:15 +00:00
const osg : : Material * mat = static_cast < const osg : : Material * > ( it - > second . first . get ( ) ) ;
2018-10-15 22:12:15 +00:00
2020-12-16 23:44:15 +00:00
if ( ! writableStateSet )
writableStateSet = getWritableStateSet ( node ) ;
2018-10-15 22:12:15 +00:00
2020-12-16 23:44:15 +00:00
int colorMode ;
switch ( mat - > getColorMode ( ) )
{
case osg : : Material : : OFF :
colorMode = 0 ;
break ;
case osg : : Material : : EMISSION :
colorMode = 1 ;
break ;
default :
case osg : : Material : : AMBIENT_AND_DIFFUSE :
colorMode = 2 ;
break ;
case osg : : Material : : AMBIENT :
colorMode = 3 ;
break ;
case osg : : Material : : DIFFUSE :
colorMode = 4 ;
break ;
case osg : : Material : : SPECULAR :
colorMode = 5 ;
break ;
}
mRequirements . back ( ) . mColorMode = colorMode ;
2018-10-15 22:12:15 +00:00
}
2020-12-16 23:44:15 +00:00
}
else if ( it - > first . first = = osg : : StateAttribute : : ALPHAFUNC )
{
if ( ! mRequirements . back ( ) . mAlphaTestOverridden | | it - > second . second & osg : : StateAttribute : : PROTECTED )
{
if ( it - > second . second & osg : : StateAttribute : : OVERRIDE )
mRequirements . back ( ) . mAlphaTestOverridden = true ;
2018-10-15 22:12:15 +00:00
2020-12-16 23:44:15 +00:00
const osg : : AlphaFunc * alpha = static_cast < const osg : : AlphaFunc * > ( it - > second . first . get ( ) ) ;
mRequirements . back ( ) . mAlphaFunc = alpha - > getFunction ( ) ;
mRequirements . back ( ) . mAlphaRef = alpha - > getReferenceValue ( ) ;
}
2016-02-18 21:48:53 +00:00
}
2016-02-16 17:18:48 +00:00
}
2020-04-10 14:45:37 +00:00
}
2021-01-02 19:09:06 +00:00
unsigned int alphaBlend = stateset - > getMode ( GL_BLEND ) ;
if ( alphaBlend ! = osg : : StateAttribute : : INHERIT & & ( ! mRequirements . back ( ) . mAlphaBlendOverridden | | alphaBlend & osg : : StateAttribute : : PROTECTED ) )
{
if ( alphaBlend & osg : : StateAttribute : : OVERRIDE )
mRequirements . back ( ) . mAlphaBlendOverridden = true ;
mRequirements . back ( ) . mAlphaBlend = alphaBlend & osg : : StateAttribute : : ON ;
}
2016-02-16 17:18:48 +00:00
}
2017-08-31 21:39:21 +00:00
void ShaderVisitor : : pushRequirements ( osg : : Node & node )
2016-02-16 17:18:48 +00:00
{
mRequirements . push_back ( mRequirements . back ( ) ) ;
2017-08-31 21:39:21 +00:00
mRequirements . back ( ) . mNode = & node ;
2016-02-16 17:18:48 +00:00
}
void ShaderVisitor : : popRequirements ( )
{
mRequirements . pop_back ( ) ;
}
2017-08-31 21:39:21 +00:00
void ShaderVisitor : : createProgram ( const ShaderRequirements & reqs )
2016-02-16 17:18:48 +00:00
{
2017-09-01 20:01:50 +00:00
if ( ! reqs . mShaderRequired & & ! mForceShaders )
2020-12-03 21:06:02 +00:00
{
ensureFFP ( * reqs . mNode ) ;
2017-09-01 20:01:50 +00:00
return ;
2020-12-03 21:06:02 +00:00
}
2017-09-01 20:01:50 +00:00
2017-08-31 21:39:21 +00:00
osg : : Node & node = * reqs . mNode ;
2018-10-09 06:21:12 +00:00
osg : : StateSet * writableStateSet = nullptr ;
2016-02-18 21:48:53 +00:00
if ( mAllowedToModifyStateSets )
writableStateSet = node . getOrCreateStateSet ( ) ;
else
writableStateSet = getWritableStateSet ( node ) ;
2016-02-16 17:18:48 +00:00
ShaderManager : : DefineMap defineMap ;
for ( unsigned int i = 0 ; i < sizeof ( defaultTextures ) / sizeof ( defaultTextures [ 0 ] ) ; + + i )
{
defineMap [ defaultTextures [ i ] ] = " 0 " ;
defineMap [ std : : string ( defaultTextures [ i ] ) + std : : string ( " UV " ) ] = " 0 " ;
}
for ( std : : map < int , std : : string > : : const_iterator texIt = reqs . mTextures . begin ( ) ; texIt ! = reqs . mTextures . end ( ) ; + + texIt )
{
defineMap [ texIt - > second ] = " 1 " ;
2017-05-06 21:05:13 +00:00
defineMap [ texIt - > second + std : : string ( " UV " ) ] = std : : to_string ( texIt - > first ) ;
2016-02-16 17:18:48 +00:00
}
2016-03-22 20:43:07 +00:00
defineMap [ " parallax " ] = reqs . mNormalHeight ? " 1 " : " 0 " ;
2018-10-18 15:00:51 +00:00
writableStateSet - > addUniform ( new osg : : Uniform ( " colorMode " , reqs . mColorMode ) ) ;
2020-12-16 23:44:15 +00:00
defineMap [ " alphaFunc " ] = std : : to_string ( reqs . mAlphaFunc ) ;
2020-12-24 00:32:15 +00:00
// back up removed state in case recreateShaders gets rid of the shader later
osg : : ref_ptr < osg : : StateSet > removedState ;
if ( ( removedState = getRemovedState ( * writableStateSet ) ) & & ! mAllowedToModifyStateSets )
removedState = new osg : : StateSet ( * removedState , osg : : CopyOp : : SHALLOW_COPY ) ;
if ( ! removedState )
removedState = new osg : : StateSet ( ) ;
2020-12-26 22:45:53 +00:00
defineMap [ " alphaToCoverage " ] = " 0 " ;
2020-12-16 23:44:15 +00:00
if ( reqs . mAlphaFunc ! = osg : : AlphaFunc : : ALWAYS )
{
writableStateSet - > addUniform ( new osg : : Uniform ( " alphaRef " , reqs . mAlphaRef ) ) ;
2021-06-28 13:54:28 +00:00
if ( ! removedState - > getAttributePair ( osg : : StateAttribute : : ALPHAFUNC ) )
{
const auto * alphaFunc = writableStateSet - > getAttributePair ( osg : : StateAttribute : : ALPHAFUNC ) ;
if ( alphaFunc )
removedState - > setAttribute ( alphaFunc - > first , alphaFunc - > second ) ;
}
2020-12-16 23:44:15 +00:00
// This prevents redundant glAlphaFunc calls while letting the shadows bin still see the test
writableStateSet - > setAttribute ( RemovedAlphaFunc : : getInstance ( reqs . mAlphaFunc ) , osg : : StateAttribute : : ON | osg : : StateAttribute : : OVERRIDE ) ;
2020-12-26 22:45:53 +00:00
2021-01-02 19:09:06 +00:00
// Blending won't work with A2C as we use the alpha channel for coverage. gl_SampleCoverage from ARB_sample_shading would save the day, but requires GLSL 130
if ( mConvertAlphaTestToAlphaToCoverage & & ! reqs . mAlphaBlend )
2020-12-26 22:45:53 +00:00
{
writableStateSet - > setMode ( GL_SAMPLE_ALPHA_TO_COVERAGE_ARB , osg : : StateAttribute : : ON ) ;
defineMap [ " alphaToCoverage " ] = " 1 " ;
}
2021-01-07 18:13:51 +00:00
// Preventing alpha tested stuff shrinking as lower mip levels are used requires knowing the texture size
osg : : ref_ptr < osg : : GLExtensions > exts = osg : : GLExtensions : : Get ( 0 , false ) ;
if ( exts & & exts - > isGpuShader4Supported )
defineMap [ " useGPUShader4 " ] = " 1 " ;
// We could fall back to a texture size uniform if EXT_gpu_shader4 is missing
2020-12-24 00:32:15 +00:00
}
2020-12-16 23:44:15 +00:00
2020-12-24 00:32:15 +00:00
if ( writableStateSet - > getMode ( GL_ALPHA_TEST ) ! = osg : : StateAttribute : : INHERIT )
removedState - > setMode ( GL_ALPHA_TEST , writableStateSet - > getMode ( GL_ALPHA_TEST ) ) ;
// This disables the deprecated fixed-function alpha test
writableStateSet - > setMode ( GL_ALPHA_TEST , osg : : StateAttribute : : OFF | osg : : StateAttribute : : PROTECTED ) ;
2020-12-16 23:44:15 +00:00
2020-12-24 00:32:15 +00:00
if ( ! removedState - > getModeList ( ) . empty ( ) | | ! removedState - > getAttributeList ( ) . empty ( ) )
{
// user data is normally shallow copied so shared with the original stateset
osg : : ref_ptr < osg : : UserDataContainer > writableUserData ;
if ( mAllowedToModifyStateSets )
writableUserData = writableStateSet - > getOrCreateUserDataContainer ( ) ;
else
writableUserData = getWritableUserDataContainer ( * writableStateSet ) ;
updateRemovedState ( * writableUserData , removedState ) ;
2020-12-16 23:44:15 +00:00
}
2021-01-20 23:37:19 +00:00
defineMap [ " translucentFramebuffer " ] = mTranslucentFramebuffer ? " 1 " : " 0 " ;
2020-12-16 21:46:09 +00:00
std : : string shaderPrefix ;
if ( ! node . getUserValue ( " shaderPrefix " , shaderPrefix ) )
shaderPrefix = mDefaultShaderPrefix ;
osg : : ref_ptr < osg : : Shader > vertexShader ( mShaderManager . getShader ( shaderPrefix + " _vertex.glsl " , defineMap , osg : : Shader : : VERTEX ) ) ;
osg : : ref_ptr < osg : : Shader > fragmentShader ( mShaderManager . getShader ( shaderPrefix + " _fragment.glsl " , defineMap , osg : : Shader : : FRAGMENT ) ) ;
2016-02-16 17:18:48 +00:00
if ( vertexShader & & fragmentShader )
{
2016-02-18 21:48:53 +00:00
writableStateSet - > setAttributeAndModes ( mShaderManager . getProgram ( vertexShader , fragmentShader ) , osg : : StateAttribute : : ON ) ;
2016-02-16 17:18:48 +00:00
for ( std : : map < int , std : : string > : : const_iterator texIt = reqs . mTextures . begin ( ) ; texIt ! = reqs . mTextures . end ( ) ; + + texIt )
{
2016-02-18 21:48:53 +00:00
writableStateSet - > addUniform ( new osg : : Uniform ( texIt - > second . c_str ( ) , texIt - > first ) , osg : : StateAttribute : : ON ) ;
2016-02-16 17:18:48 +00:00
}
}
}
2020-12-03 21:06:02 +00:00
void ShaderVisitor : : ensureFFP ( osg : : Node & node )
{
if ( ! node . getStateSet ( ) | | ! node . getStateSet ( ) - > getAttribute ( osg : : StateAttribute : : PROGRAM ) )
return ;
osg : : StateSet * writableStateSet = nullptr ;
if ( mAllowedToModifyStateSets )
writableStateSet = node . getStateSet ( ) ;
else
writableStateSet = getWritableStateSet ( node ) ;
writableStateSet - > removeAttribute ( osg : : StateAttribute : : PROGRAM ) ;
2020-12-16 23:44:15 +00:00
2021-04-14 04:07:56 +00:00
if ( osg : : ref_ptr < osg : : StateSet > removedState = getRemovedState ( * writableStateSet ) )
2020-12-16 23:44:15 +00:00
{
// user data is normally shallow copied so shared with the original stateset
osg : : ref_ptr < osg : : UserDataContainer > writableUserData ;
if ( mAllowedToModifyStateSets )
writableUserData = writableStateSet - > getUserDataContainer ( ) ;
else
writableUserData = getWritableUserDataContainer ( * writableStateSet ) ;
unsigned int index = writableUserData - > getUserObjectIndex ( " removedState " ) ;
writableUserData - > removeUserObject ( index ) ;
for ( const auto & [ mode , value ] : removedState - > getModeList ( ) )
writableStateSet - > setMode ( mode , value ) ;
for ( const auto & attribute : removedState - > getAttributeList ( ) )
writableStateSet - > setAttribute ( attribute . second . first , attribute . second . second ) ;
}
2020-12-03 21:06:02 +00:00
}
2017-09-01 20:01:50 +00:00
bool ShaderVisitor : : adjustGeometry ( osg : : Geometry & sourceGeometry , const ShaderRequirements & reqs )
{
bool useShader = reqs . mShaderRequired | | mForceShaders ;
bool generateTangents = reqs . mTexStageRequiringTangents ! = - 1 ;
bool changed = false ;
if ( mAllowedToModifyStateSets & & ( useShader | | generateTangents ) )
{
// make sure that all UV sets are there
for ( std : : map < int , std : : string > : : const_iterator it = reqs . mTextures . begin ( ) ; it ! = reqs . mTextures . end ( ) ; + + it )
{
2018-10-09 06:21:12 +00:00
if ( sourceGeometry . getTexCoordArray ( it - > first ) = = nullptr )
2017-09-01 20:01:50 +00:00
{
sourceGeometry . setTexCoordArray ( it - > first , sourceGeometry . getTexCoordArray ( 0 ) ) ;
changed = true ;
}
}
if ( generateTangents )
{
osg : : ref_ptr < osgUtil : : TangentSpaceGenerator > generator ( new osgUtil : : TangentSpaceGenerator ) ;
generator - > generate ( & sourceGeometry , reqs . mTexStageRequiringTangents ) ;
sourceGeometry . setTexCoordArray ( 7 , generator - > getTangentArray ( ) , osg : : Array : : BIND_PER_VERTEX ) ;
changed = true ;
}
}
return changed ;
}
2016-02-16 17:18:48 +00:00
void ShaderVisitor : : apply ( osg : : Geometry & geometry )
{
2018-10-09 06:21:12 +00:00
bool needPop = ( geometry . getStateSet ( ) ! = nullptr ) ;
2017-08-31 21:39:21 +00:00
if ( geometry . getStateSet ( ) ) // TODO: check if stateset affects shader permutation before pushing it
2016-02-16 17:18:48 +00:00
{
2017-08-31 21:39:21 +00:00
pushRequirements ( geometry ) ;
2016-02-18 21:48:53 +00:00
applyStateSet ( geometry . getStateSet ( ) , geometry ) ;
2016-02-16 17:18:48 +00:00
}
if ( ! mRequirements . empty ( ) )
{
const ShaderRequirements & reqs = mRequirements . back ( ) ;
2016-02-20 18:02:11 +00:00
2017-09-01 20:01:50 +00:00
adjustGeometry ( geometry , reqs ) ;
2017-03-01 02:00:08 +00:00
2017-09-01 20:01:50 +00:00
createProgram ( reqs ) ;
2016-02-16 17:18:48 +00:00
}
2020-12-03 21:06:02 +00:00
else
ensureFFP ( geometry ) ;
2016-02-16 17:18:48 +00:00
if ( needPop )
popRequirements ( ) ;
}
void ShaderVisitor : : apply ( osg : : Drawable & drawable )
{
// non-Geometry drawable (e.g. particle system)
2018-10-09 06:21:12 +00:00
bool needPop = ( drawable . getStateSet ( ) ! = nullptr ) ;
2016-02-16 17:18:48 +00:00
if ( drawable . getStateSet ( ) )
{
2017-08-31 21:39:21 +00:00
pushRequirements ( drawable ) ;
2016-02-18 21:48:53 +00:00
applyStateSet ( drawable . getStateSet ( ) , drawable ) ;
2016-02-16 17:18:48 +00:00
}
if ( ! mRequirements . empty ( ) )
{
2016-02-18 16:08:18 +00:00
const ShaderRequirements & reqs = mRequirements . back ( ) ;
2017-09-01 20:01:50 +00:00
createProgram ( reqs ) ;
2017-09-01 20:56:09 +00:00
if ( auto rig = dynamic_cast < SceneUtil : : RigGeometry * > ( & drawable ) )
2017-09-01 20:01:50 +00:00
{
osg : : ref_ptr < osg : : Geometry > sourceGeometry = rig - > getSourceGeometry ( ) ;
if ( sourceGeometry & & adjustGeometry ( * sourceGeometry , reqs ) )
rig - > setSourceGeometry ( sourceGeometry ) ;
}
2017-09-01 20:56:09 +00:00
else if ( auto morph = dynamic_cast < SceneUtil : : MorphGeometry * > ( & drawable ) )
{
osg : : ref_ptr < osg : : Geometry > sourceGeometry = morph - > getSourceGeometry ( ) ;
if ( sourceGeometry & & adjustGeometry ( * sourceGeometry , reqs ) )
morph - > setSourceGeometry ( sourceGeometry ) ;
}
2016-02-16 17:18:48 +00:00
}
2020-12-03 21:06:02 +00:00
else
ensureFFP ( drawable ) ;
2016-02-16 17:18:48 +00:00
if ( needPop )
popRequirements ( ) ;
}
2016-02-18 21:48:53 +00:00
void ShaderVisitor : : setAllowedToModifyStateSets ( bool allowed )
{
mAllowedToModifyStateSets = allowed ;
}
2016-02-20 16:57:19 +00:00
void ShaderVisitor : : setAutoUseNormalMaps ( bool use )
{
mAutoUseNormalMaps = use ;
}
void ShaderVisitor : : setNormalMapPattern ( const std : : string & pattern )
{
mNormalMapPattern = pattern ;
}
2016-03-22 20:43:07 +00:00
void ShaderVisitor : : setNormalHeightMapPattern ( const std : : string & pattern )
{
mNormalHeightMapPattern = pattern ;
}
2016-02-20 18:02:11 +00:00
void ShaderVisitor : : setAutoUseSpecularMaps ( bool use )
{
mAutoUseSpecularMaps = use ;
}
void ShaderVisitor : : setSpecularMapPattern ( const std : : string & pattern )
{
mSpecularMapPattern = pattern ;
}
2020-11-09 10:53:58 +00:00
void ShaderVisitor : : setApplyLightingToEnvMaps ( bool apply )
{
mApplyLightingToEnvMaps = apply ;
}
2020-12-26 22:45:53 +00:00
void ShaderVisitor : : setConvertAlphaTestToAlphaToCoverage ( bool convert )
{
mConvertAlphaTestToAlphaToCoverage = convert ;
}
2021-01-20 23:37:19 +00:00
void ShaderVisitor : : setTranslucentFramebuffer ( bool translucent )
{
mTranslucentFramebuffer = translucent ;
}
2021-02-19 19:59:48 +00:00
ReinstateRemovedStateVisitor : : ReinstateRemovedStateVisitor ( bool allowedToModifyStateSets )
: osg : : NodeVisitor ( TRAVERSE_ALL_CHILDREN )
, mAllowedToModifyStateSets ( allowedToModifyStateSets )
{
}
void ReinstateRemovedStateVisitor : : apply ( osg : : Node & node )
{
if ( node . getStateSet ( ) )
{
osg : : ref_ptr < osg : : StateSet > removedState = getRemovedState ( * node . getStateSet ( ) ) ;
if ( removedState )
{
osg : : ref_ptr < osg : : StateSet > writableStateSet ;
if ( mAllowedToModifyStateSets )
writableStateSet = node . getStateSet ( ) ;
else
writableStateSet = getWritableStateSet ( node ) ;
// user data is normally shallow copied so shared with the original stateset
osg : : ref_ptr < osg : : UserDataContainer > writableUserData ;
if ( mAllowedToModifyStateSets )
writableUserData = writableStateSet - > getUserDataContainer ( ) ;
else
writableUserData = getWritableUserDataContainer ( * writableStateSet ) ;
unsigned int index = writableUserData - > getUserObjectIndex ( " removedState " ) ;
writableUserData - > removeUserObject ( index ) ;
for ( const auto & [ mode , value ] : removedState - > getModeList ( ) )
writableStateSet - > setMode ( mode , value ) ;
for ( const auto & attribute : removedState - > getAttributeList ( ) )
writableStateSet - > setAttribute ( attribute . second . first , attribute . second . second ) ;
}
}
traverse ( node ) ;
}
2016-02-16 17:18:48 +00:00
}