Page 1 of 1
hlms template conditions
Posted: Fri Feb 07, 2025 3:15 pm
by bishopnator
Hi, I am trying to write a template shader for my custom hlms which will have multiple "sections". Basically I want to write couple of pieces and based on the Renderable's properties, only once piece will be inserted to the shader:
Code: Select all
@piece(PropertyA) @insertpiece(ShaderA) @end
@piece(PropertyB) @insertpiece(ShaderB) @end
@piece(PropertyC) @insertpiece(ShaderC) @end
@piece(!PropertyA && !PropertyB && !PropertyC) @insertpiece(DefaultShader) @end
This of course work, but I would like to write last part in more general way that if I insert new PropertyD, that I don't have to update the condition there. Something like this (but it doesn't work):
Code: Select all
@piece(PropertyA) @insertpiece(ShaderA) @set(ShaderSet, 1) @end
@piece(PropertyB) @insertpiece(ShaderB) @set(ShaderSet, 1) @end
@piece(PropertyC) @insertpiece(ShaderC) @set(ShaderSet, 1) @end
@piece(!ShaderSet) @insertpiece(DefaultShader) @end
From what I read in the documentation for HLMS I think I understand why it is not working - the @set is evaluated after the pieces are inserted, which is just too late. I tried it also with @pset, but this one is evaluated before any piece is inserted. Is there something more dynamic? There was description of something similar and recommended that it is possible to use HLSL/GLSL preprocessor macros with their own cons and pros. I would like to stick purely to HLMS preprocessing so if there is nothing else what I can do, I will stick to my original template code (with last part naming all properties).
Re: hlms template conditions
Posted: Fri Feb 07, 2025 6:18 pm
by dark_sylinc
Since the Hlms parses files as individual units and in alphabetical order, you can workaround this by using two files:
Code: Select all
// 01.Script_piece_all.any
@property(PropertyA) @insertpiece(ShaderA) @set(ShaderSet, 1) @end
@property(PropertyB) @insertpiece(ShaderB) @set(ShaderSet, 1) @end
@property(PropertyC) @insertpiece(ShaderC) @set(ShaderSet, 1) @end
Code: Select all
// 02.Script_piece_all.any
@property(!ShaderSet) @insertpiece(DefaultShader) @end
This way 01.Script_piece_all.any will be parsed, the piece inserted and the property set.
Then 02.Script_piece_all.any gets parsed with ShaderSet already set.
Alternatively in C++, Hlms::notifyPropertiesMergedPreGenerationStep (or HlmsListener::propertiesMergedPreGenerationStep) can do the same evaluation, where you can check if Prop A, B or C have been set, then set/unset ShaderSet:
Code: Select all
void MyListener::propertiesMergedPreGenerationStep(
Hlms *hlms, const HlmsCache &passCache, const HlmsPropertyVec &renderableCacheProperties,
const PiecesMap renderableCachePieces[NumShaderTypes], const HlmsPropertyVec &properties,
const QueuedRenderable &queuedRenderable, const size_t tid )
{
if( hlms->_getProperty( tid, "A" ) != 0 ||
hlms->_getProperty( tid, "B" ) != 0 ||
hlms->_getProperty( tid, "C" ) != 0 )
{
hlms->_setProperty( tid, "ShaderSet", 1 );
}
}
Re: hlms template conditions
Posted: Fri Feb 07, 2025 9:10 pm
by bishopnator
The approach with 2 files sounds better for me. However I need to wrap the "implementation" in a piece. So something like this:
Code: Select all
// 01.Script_piece_all.any
@piece(mainShaderBody)
@property(PropertyA) @insertpiece(ShaderA) @set(ShaderSet, 1) @end
@property(PropertyB) @insertpiece(ShaderB) @set(ShaderSet, 1) @end
@property(PropertyC) @insertpiece(ShaderC) @set(ShaderSet, 1) @end
@end
And in the second file:
Code: Select all
// 02.Script_piece_all.any
@insertpiece(mainShaderBody)
@property(!ShaderSet) @insertpiece(DefaultShader) @end
Without trying it, do you think it could work? I will experiment with it later as I am in the middle of shader implementation and I went for now with the solution of using all the conditions as mentioned in my first post.