@@ -17,6 +17,7 @@ Low-level renderer for communicating with the OpenGL and Vulkan APIs.
1717 3 . [ Defining Layers in a Render Pass] ( #defining-layers-in-a-render-pass )
1818 4 . [ Complex Geometry] ( #complex-geometry )
1919 5 . [ Uniform Buffers] ( #uniform-buffers )
20+ 6 . [ Shader Templates] ( #shader-templates )
20215 . [ Thread-safety] ( #thread-safety )
2122
2223
@@ -542,5 +543,80 @@ resources::UniformBufferInfo ubo_info{
542543std::shared_ptr<UniformBuffer> buffer = renderer->add_uniform_buffer(ubo_info);
543544```
544545
546+ ### Shader Templates
547+
548+ Shader templates allow the definition of a shader source code with placeholders that can be replaced at
549+ load- or run-time. Templates are help if only specific parts of the shader code are supposed to
550+ be configurable. This may be used, for example, to alter certain code path of the built-in shaders
551+ without recompiling the engine.
552+
553+ An example shader template looks like this:
554+
555+ ``` glsl
556+ #version 330
557+
558+ in vec2 tex_coord;
559+ out vec4 frag_color;
560+
561+ // PLACEHOLDER: uniform_color
562+
563+ void main() {
564+ // PLACEHOLDER: alpha
565+ frag_color = vec4(col.xyz, alpha);
566+ }
567+ ```
568+
569+ Placeholders are inserted as comments into the GLSL source. Every placeholder has an ID for
570+ referencing. For these IDs, * snippets* can be defined to insert code in place of the placeholder
571+ comment. Placeholders can be placed at any position in the template, so they can be used to insert
572+ other statements than the control code, including unforms, input/output variables, functions and more.
573+
574+ The snippets for the above example may look like this:
575+
576+ ` uniform_color.snippet `
577+
578+ ``` glsl
579+ uniform vec4 col;
580+ ```
581+
582+ ` alpha.snippet `
583+
584+ ``` glsl
585+ float alpha = 0.5;
586+ ```
587+
588+ In the renderer, shader templates can be created using the ` renderer::resources::ShaderTemplate ` class.
589+
590+ ``` cpp
591+ util::Path template_path = shaderdir / " example_template.frag.glsl" ;
592+ resources::ShaderTemplate template (template_path);
593+ ```
594+
595+ After loading the template, snippets for the placeholders can be added. These are either loaded
596+ as single files or from a directory.
597+
598+ ```cpp
599+ util::Path snippets_path = shaderdir / "example_snippets";
600+ template.load_snippets(snippets_path);
601+ ```
602+
603+ or
604+
605+ ``` cpp
606+ util::Path snippets_path = shaderdir / " example_snippets" ;
607+ template .add_snippet(snippets_path / " uniform_color.snippet" );
608+ template .add_snippet(snippets_path / " alpha.snippet" );
609+ ```
610+
611+ If snippets have been loaded for all placeholder IDs, the shader template can generate the final
612+ shader source code as ` renderer::resources::ShaderSource ` . This can then be used to create the actual
613+ ` renderer::ShaderProgram ` uploaded to the GPU.
614+
615+ ``` cpp
616+ resources::ShaderSource source = template .generate_source();
617+ ShaderProgram prog = = renderer->add_shader ({source});
618+ ```
619+
620+
545621## Thread-safety
546622This level might or might not be threadsafe depending on the concrete backend. The OpenGL version is, in typical GL fashion, so not-threadsafe it's almost anti-threadsafe. All code must be executed sequentially on a dedicated window thread, the same one on which the window and renderer were initially created. The plan for the Vulkan version is to make it at least independent of thread-local storage and hopefully completely threadsafe.
0 commit comments