diff --git a/src/game/state/boot.cpp b/src/game/state/boot.cpp index c05007f..2bb7df8 100644 --- a/src/game/state/boot.cpp +++ b/src/game/state/boot.cpp @@ -50,7 +50,6 @@ #include "render/passes/shadow-map-pass.hpp" #include "render/passes/sky-pass.hpp" #include "render/passes/ground-pass.hpp" -#include "render/passes/simple-pass.hpp" #include "render/vertex-attribute.hpp" #include "render/compositor.hpp" #include "render/renderer.hpp" diff --git a/src/render/passes/bloom-pass.cpp b/src/render/passes/bloom-pass.cpp index 73b55f7..2e99880 100644 --- a/src/render/passes/bloom-pass.cpp +++ b/src/render/passes/bloom-pass.cpp @@ -45,19 +45,30 @@ bloom_pass::bloom_pass(gl::rasterizer* rasterizer, resource_manager* resource_ma filter_radius(0.005f), corrected_filter_radius{filter_radius, filter_radius} { - // Load downsample shader with Karis average - downsample_karis_shader = resource_manager->load("bloom-downsample-karis.glsl"); + // Load downsample shader template + downsample_shader_template = resource_manager->load("bloom-downsample.glsl"); + + // Build downsample shader program with Karis averaging + downsample_karis_shader = downsample_shader_template->build + ( + { + {"KARIS_AVERAGE", std::string()} + } + ); downsample_karis_source_texture_input = downsample_karis_shader->get_input("source_texture"); - // Load downsample shader - downsample_shader = resource_manager->load("bloom-downsample.glsl"); + // Build downsample shader program without Karis averaging + downsample_shader = downsample_shader_template->build(); downsample_source_texture_input = downsample_shader->get_input("source_texture"); - // Load upsample shader - upsample_shader = resource_manager->load("bloom-upsample.glsl"); + // Load upsample shader template + upsample_shader_template = resource_manager->load("bloom-upsample.glsl"); + + // Build upsample shader program + upsample_shader = upsample_shader_template->build(); upsample_source_texture_input = upsample_shader->get_input("source_texture"); upsample_filter_radius_input = upsample_shader->get_input("filter_radius"); - + const float vertex_data[] = { -1.0f, 1.0f, @@ -71,7 +82,7 @@ bloom_pass::bloom_pass(gl::rasterizer* rasterizer, resource_manager* resource_ma std::size_t vertex_size = 2; std::size_t vertex_stride = sizeof(float) * vertex_size; std::size_t vertex_count = 6; - + quad_vbo = new gl::vertex_buffer(sizeof(float) * vertex_size * vertex_count, vertex_data); quad_vao = new gl::vertex_array(); @@ -89,10 +100,18 @@ bloom_pass::bloom_pass(gl::rasterizer* rasterizer, resource_manager* resource_ma bloom_pass::~bloom_pass() { - set_mip_chain_length(0); - delete quad_vao; delete quad_vbo; + + set_mip_chain_length(0); + + delete downsample_karis_shader; + delete downsample_shader; + delete upsample_shader; + + /// @TODO + //resource_manager->unload("bloom-downsample.glsl"); + //resource_manager->unload("bloom-upsample.glsl"); } void bloom_pass::render(const render::context& ctx, render::queue& queue) const diff --git a/src/render/passes/bloom-pass.hpp b/src/render/passes/bloom-pass.hpp index ea83364..49644e5 100644 --- a/src/render/passes/bloom-pass.hpp +++ b/src/render/passes/bloom-pass.hpp @@ -21,6 +21,7 @@ #define ANTKEEPER_RENDER_BLOOM_PASS_HPP #include "render/pass.hpp" +#include "render/shader-template.hpp" #include "gl/shader-program.hpp" #include "gl/shader-input.hpp" #include "gl/vertex-buffer.hpp" @@ -95,6 +96,9 @@ public: private: const gl::texture_2d* source_texture; + shader_template* downsample_shader_template; + shader_template* upsample_shader_template; + gl::shader_program* downsample_karis_shader; const gl::shader_input* downsample_karis_source_texture_input; diff --git a/src/render/passes/final-pass.cpp b/src/render/passes/final-pass.cpp index 21821bd..435fc68 100644 --- a/src/render/passes/final-pass.cpp +++ b/src/render/passes/final-pass.cpp @@ -45,7 +45,11 @@ final_pass::final_pass(gl::rasterizer* rasterizer, const gl::framebuffer* frameb blue_noise_texture(nullptr), blue_noise_scale(1.0f) { - shader_program = resource_manager->load("final.glsl"); + // Load shader template + shader_template = resource_manager->load("final.glsl"); + + // Build shader program + shader_program = shader_template->build(); color_texture_input = shader_program->get_input("color_texture"); bloom_texture_input = shader_program->get_input("bloom_texture"); bloom_weight_input = shader_program->get_input("bloom_weight"); @@ -87,6 +91,11 @@ final_pass::~final_pass() { delete quad_vao; delete quad_vbo; + + delete shader_program; + + /// @TODO + // resource_manager->unload("final.glsl"); } void final_pass::render(const render::context& ctx, render::queue& queue) const diff --git a/src/render/passes/final-pass.hpp b/src/render/passes/final-pass.hpp index b5dc2f4..04d284e 100644 --- a/src/render/passes/final-pass.hpp +++ b/src/render/passes/final-pass.hpp @@ -21,6 +21,7 @@ #define ANTKEEPER_RENDER_FINAL_PASS_HPP #include "render/pass.hpp" +#include "render/shader-template.hpp" #include "gl/shader-program.hpp" #include "gl/shader-input.hpp" #include "gl/vertex-buffer.hpp" @@ -47,6 +48,8 @@ public: void set_blue_noise_texture(const gl::texture_2d* texture); private: + render::shader_template* shader_template; + gl::shader_program* shader_program; const gl::shader_input* color_texture_input; const gl::shader_input* bloom_texture_input; diff --git a/src/render/passes/fxaa-pass.cpp b/src/render/passes/fxaa-pass.cpp index 3adc5cf..e69d075 100644 --- a/src/render/passes/fxaa-pass.cpp +++ b/src/render/passes/fxaa-pass.cpp @@ -38,8 +38,11 @@ fxaa_pass::fxaa_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuf pass(rasterizer, framebuffer), source_texture(nullptr) { - // Load FXAA shader - shader = resource_manager->load("fxaa.glsl"); + // Load FXAA shader template + shader_template = resource_manager->load("fxaa.glsl"); + + // Build FXAA shader program + shader = shader_template->build(); source_texture_input = shader->get_input("source_texture"); texel_size_input = shader->get_input("texel_size"); @@ -76,6 +79,11 @@ fxaa_pass::~fxaa_pass() { delete quad_vao; delete quad_vbo; + + delete shader; + + /// @TODO + // resource_manager->unload("fxaa.glsl"); } void fxaa_pass::render(const render::context& ctx, render::queue& queue) const diff --git a/src/render/passes/fxaa-pass.hpp b/src/render/passes/fxaa-pass.hpp index 432f5e7..96f0982 100644 --- a/src/render/passes/fxaa-pass.hpp +++ b/src/render/passes/fxaa-pass.hpp @@ -21,6 +21,7 @@ #define ANTKEEPER_RENDER_FXAA_PASS_HPP #include "render/pass.hpp" +#include "render/shader-template.hpp" #include "gl/shader-program.hpp" #include "gl/shader-input.hpp" #include "gl/vertex-buffer.hpp" @@ -71,6 +72,7 @@ public: private: const gl::texture_2d* source_texture; + render::shader_template* shader_template; gl::shader_program* shader; const gl::shader_input* source_texture_input; const gl::shader_input* texel_size_input; diff --git a/src/render/passes/resample-pass.cpp b/src/render/passes/resample-pass.cpp index 44ae8bd..f90c566 100644 --- a/src/render/passes/resample-pass.cpp +++ b/src/render/passes/resample-pass.cpp @@ -38,8 +38,11 @@ resample_pass::resample_pass(gl::rasterizer* rasterizer, const gl::framebuffer* pass(rasterizer, framebuffer), source_texture(nullptr) { - // Load resample shader - shader = resource_manager->load("resample.glsl"); + // Load resample shader template + shader_template = resource_manager->load("resample.glsl"); + + // Build resample shader program + shader = shader_template->build(); source_texture_input = shader->get_input("source_texture"); const float vertex_data[] = @@ -75,6 +78,11 @@ resample_pass::~resample_pass() { delete quad_vao; delete quad_vbo; + + delete shader; + + /// @TODO + // resource_manager->unload("resample.glsl"); } void resample_pass::render(const render::context& ctx, render::queue& queue) const diff --git a/src/render/passes/resample-pass.hpp b/src/render/passes/resample-pass.hpp index 861c2bf..653e421 100644 --- a/src/render/passes/resample-pass.hpp +++ b/src/render/passes/resample-pass.hpp @@ -21,6 +21,7 @@ #define ANTKEEPER_RENDER_RESAMPLE_PASS_HPP #include "render/pass.hpp" +#include "render/shader-template.hpp" #include "gl/shader-program.hpp" #include "gl/shader-input.hpp" #include "gl/vertex-buffer.hpp" @@ -69,6 +70,7 @@ public: private: const gl::texture_2d* source_texture; + render::shader_template* shader_template; gl::shader_program* shader; const gl::shader_input* source_texture_input; diff --git a/src/render/passes/simple-pass.cpp b/src/render/passes/simple-pass.cpp deleted file mode 100644 index bef8e03..0000000 --- a/src/render/passes/simple-pass.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2023 Christopher J. Howard - * - * This file is part of Antkeeper source code. - * - * Antkeeper source code is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Antkeeper source code is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Antkeeper source code. If not, see . - */ - -#include "render/passes/simple-pass.hpp" -#include "gl/rasterizer.hpp" -#include "gl/framebuffer.hpp" -#include "gl/shader-program.hpp" -#include "gl/shader-input.hpp" -#include "gl/vertex-buffer.hpp" -#include "gl/vertex-array.hpp" -#include "gl/vertex-attribute.hpp" -#include "gl/drawing-mode.hpp" -#include "gl/texture-2d.hpp" -#include "gl/texture-wrapping.hpp" -#include "gl/texture-filter.hpp" -#include "render/vertex-attribute.hpp" -#include "render/context.hpp" -#include "render/material.hpp" -#include "render/material-property.hpp" -#include - -namespace render { - -simple_pass::simple_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuffer, gl::shader_program* shader_program): - pass(rasterizer, framebuffer), - shader_program(shader_program) -{ - // Create material - material = new render::material(shader_program); - - // Add standard properties to material - time_property = material->add_property("time"); - resolution_property = material->add_property("resolution"); - - const float vertex_data[] = - { - -1.0f, 1.0f, 0.0f, - -1.0f, -1.0f, 0.0f, - 1.0f, 1.0f, 0.0f, - 1.0f, 1.0f, 0.0f, - -1.0f, -1.0f, 0.0f, - 1.0f, -1.0f, 0.0f - }; - - std::size_t vertex_size = 3; - std::size_t vertex_stride = sizeof(float) * vertex_size; - std::size_t vertex_count = 6; - - quad_vbo = new gl::vertex_buffer(sizeof(float) * vertex_size * vertex_count, vertex_data); - quad_vao = new gl::vertex_array(); - - // Define position vertex attribute - gl::vertex_attribute position_attribute; - position_attribute.buffer = quad_vbo; - position_attribute.offset = 0; - position_attribute.stride = vertex_stride; - position_attribute.type = gl::vertex_attribute_type::float_32; - position_attribute.components = 3; - - // Bind vertex attributes to VAO - quad_vao->bind(render::vertex_attribute::position, position_attribute); -} - -simple_pass::~simple_pass() -{ - delete material; - delete quad_vao; - delete quad_vbo; -} - -void simple_pass::render(const render::context& ctx, render::queue& queue) const -{ - // Bind framebuffer - rasterizer->use_framebuffer(*framebuffer); - - // Setup graphics context - glDisable(GL_BLEND); - glDisable(GL_DEPTH_TEST); - glDepthMask(GL_FALSE); - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); - - // Setup viewport - auto viewport = framebuffer->get_dimensions(); - rasterizer->set_viewport(0, 0, std::get<0>(viewport), std::get<1>(viewport)); - - // Change shader program - rasterizer->use_program(*shader_program); - - // Update material properties - time_property->set_value(ctx.t); - resolution_property->set_value({static_cast(std::get<0>(viewport)), static_cast(std::get<1>(viewport))}); - - // Upload material properties - material->upload(ctx.alpha); - - // Draw quad - rasterizer->draw_arrays(*quad_vao, gl::drawing_mode::triangles, 0, 6); -} - -} // namespace render diff --git a/src/render/passes/simple-pass.hpp b/src/render/passes/simple-pass.hpp deleted file mode 100644 index 33e026c..0000000 --- a/src/render/passes/simple-pass.hpp +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2023 Christopher J. Howard - * - * This file is part of Antkeeper source code. - * - * Antkeeper source code is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Antkeeper source code is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Antkeeper source code. If not, see . - */ - -#ifndef ANTKEEPER_RENDER_SIMPLE_PASS_HPP -#define ANTKEEPER_RENDER_SIMPLE_PASS_HPP - -#include "render/pass.hpp" -#include "utility/fundamental-types.hpp" -#include "gl/shader-program.hpp" -#include "gl/shader-input.hpp" -#include "gl/vertex-buffer.hpp" -#include "gl/vertex-array.hpp" - -namespace render { - -class material; -template -class material_property; - -/** - * Simple render passes are associated with a single shader and a single material. - */ -class simple_pass: public pass -{ -public: - simple_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuffer, gl::shader_program* shader_program); - virtual ~simple_pass(); - virtual void render(const render::context& ctx, render::queue& queue) const final; - - const render::material* get_material() const; - render::material* get_material(); - -private: - gl::shader_program* shader_program; - material* material; - material_property* time_property; - material_property* resolution_property; - - gl::vertex_buffer* quad_vbo; - gl::vertex_array* quad_vao; -}; - -inline const render::material* simple_pass::get_material() const -{ - return material; -} - -inline render::material* simple_pass::get_material() -{ - return material; -} - -} // namespace render - -#endif // ANTKEEPER_RENDER_SIMPLE_PASS_HPP diff --git a/src/render/passes/sky-pass.cpp b/src/render/passes/sky-pass.cpp index 6ba5119..5a0f5b9 100644 --- a/src/render/passes/sky-pass.cpp +++ b/src/render/passes/sky-pass.cpp @@ -114,8 +114,11 @@ sky_pass::sky_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuffe transmittance_lut_framebuffer->attach(gl::framebuffer_attachment_type::color, transmittance_lut_texture); transmittance_lut_resolution = {static_cast(transmittance_lut_texture->get_width()), static_cast(transmittance_lut_texture->get_height())}; - // Load transmittance LUT shader - transmittance_shader_program = resource_manager->load("transmittance-lut.glsl"); + // Load transmittance LUT shader template + transmittance_shader_template = resource_manager->load("transmittance-lut.glsl"); + + // Build transmittance LUT shader program + transmittance_shader_program = transmittance_shader_template->build(); transmittance_atmosphere_radii_input = transmittance_shader_program->get_input("atmosphere_radii"); transmittance_rayleigh_parameters_input = transmittance_shader_program->get_input("rayleigh_parameters"); transmittance_mie_parameters_input = transmittance_shader_program->get_input("mie_parameters"); @@ -134,8 +137,11 @@ sky_pass::sky_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuffe sky_lut_framebuffer = new gl::framebuffer(sky_lut_width, sky_lut_height); sky_lut_framebuffer->attach(gl::framebuffer_attachment_type::color, sky_lut_texture); - // Load sky LUT shader - sky_lut_shader_program = resource_manager->load("sky-illuminance-lut.glsl"); + // Load sky LUT shader template + sky_lut_shader_template = resource_manager->load("sky-illuminance-lut.glsl"); + + // Build sky LUT shader program + sky_lut_shader_program = sky_lut_shader_template->build(); sky_lut_light_direction_input = sky_lut_shader_program->get_input("light_direction"); sky_lut_light_illuminance_input = sky_lut_shader_program->get_input("light_illuminance"); sky_lut_atmosphere_radii_input = sky_lut_shader_program->get_input("atmosphere_radii"); @@ -158,6 +164,13 @@ sky_pass::~sky_pass() delete transmittance_lut_texture; delete quad_vao; delete quad_vbo; + + delete transmittance_shader_program; + delete sky_lut_shader_program; + + /// @TODO + // resource_maanger->unload("transmittance-lut.glsl"); + // resource_maanger->unload("sky-illuminance-lut.glsl"); } void sky_pass::render(const render::context& ctx, render::queue& queue) const diff --git a/src/render/passes/sky-pass.hpp b/src/render/passes/sky-pass.hpp index d91ac3a..674f867 100644 --- a/src/render/passes/sky-pass.hpp +++ b/src/render/passes/sky-pass.hpp @@ -21,6 +21,7 @@ #define ANTKEEPER_RENDER_SKY_PASS_HPP #include "render/pass.hpp" +#include "render/shader-template.hpp" #include "utility/fundamental-types.hpp" #include "event/event-handler.hpp" #include "event/input-events.hpp" @@ -101,6 +102,7 @@ private: gl::texture_2d* transmittance_lut_texture; gl::framebuffer* transmittance_lut_framebuffer; float2 transmittance_lut_resolution; + render::shader_template* transmittance_shader_template; gl::shader_program* transmittance_shader_program; const gl::shader_input* transmittance_atmosphere_radii_input; const gl::shader_input* transmittance_rayleigh_parameters_input; @@ -112,6 +114,7 @@ private: gl::texture_2d* sky_lut_texture; gl::framebuffer* sky_lut_framebuffer; + render::shader_template* sky_lut_shader_template; gl::shader_program* sky_lut_shader_program; float2 sky_lut_resolution; const gl::shader_input* sky_lut_light_direction_input; @@ -174,13 +177,6 @@ private: const gl::shader_input* star_projection_input; const gl::shader_input* star_exposure_input; const gl::shader_input* star_distance_input; - - gl::shader_program* cloud_shader_program; - const gl::shader_input* cloud_model_view_projection_input; - const gl::shader_input* cloud_sun_direction_input; - const gl::shader_input* cloud_sun_illuminance_input; - const gl::shader_input* cloud_camera_position_input; - const gl::shader_input* cloud_camera_exposure_input; float2 mouse_position; @@ -200,7 +196,6 @@ private: tween moon_planetlight_illuminance_tween; tween moon_illuminance_tween; float3 moon_transmitted_illuminance; - float sun_angular_radius; float atmosphere_upper_limit; diff --git a/src/render/shader-template.cpp b/src/render/shader-template.cpp index bb6eed0..23254cf 100644 --- a/src/render/shader-template.cpp +++ b/src/render/shader-template.cpp @@ -28,7 +28,8 @@ shader_template::shader_template(const std::string& source_code) source(source_code); } -shader_template::shader_template() +shader_template::shader_template(): + hash(std::hash{}(std::string())) {} void shader_template::source(const std::string& source) @@ -71,6 +72,9 @@ void shader_template::source(const std::string& source) // Append line to template source template_source.push_back(line); } + + // Calculate hash of source + hash = std::hash{}(source); } std::string shader_template::configure(gl::shader_stage stage, const dictionary_type& definitions) const @@ -186,7 +190,7 @@ void shader_template::replace_define_directives(const dictionary_type& definitio auto definitions_it = definitions.find(define_directive.first); if (definitions_it != definitions.end()) { - // Definition found, Replace `#pragma define ` with `#define ` or `#define ` + // Definition found, replace `#pragma define ` with `#define ` or `#define ` line = "#define " + define_directive.first; if (!definitions_it->second.empty()) line += " " + definitions_it->second; diff --git a/src/render/shader-template.hpp b/src/render/shader-template.hpp index bec0f84..ded26bc 100644 --- a/src/render/shader-template.hpp +++ b/src/render/shader-template.hpp @@ -30,7 +30,7 @@ namespace render { /** - * Shader templates can be used to generate multiple shader variants from a single source. + * Template used to for generating one or more shader variants from a single source. * * Shader templates support the following preprocessor directives: * @@ -46,11 +46,11 @@ namespace render { class shader_template { public: - /// Container of definitions used to replace `#pragma define ` directives. + /// Container of definitions used to generate `#pragma define ` directives. typedef std::unordered_map dictionary_type; /** - * Creates a shader template and sets its source code. + * Constructs a shader template and sets its source code. * * @param source_code String containing the shader template source code. * @@ -59,7 +59,7 @@ public: shader_template(const std::string& source_code); /** - * Creates a shader template. + * Constructs an empty shader template. */ shader_template(); @@ -77,7 +77,7 @@ public: * @param definitions Container of definitions used to replace `#pragma define ` directives. * @return Configured shader object source code. */ - std::string configure(gl::shader_stage stage, const dictionary_type& definitions) const; + std::string configure(gl::shader_stage stage, const dictionary_type& definitions = {}) const; /** * Configures and compiles a shader object. @@ -88,7 +88,7 @@ public: * * @exception std::runtime_error Any exceptions thrown by gl::shader_object. */ - gl::shader_object* compile(gl::shader_stage stage, const dictionary_type& definitions) const; + gl::shader_object* compile(gl::shader_stage stage, const dictionary_type& definitions = {}) const; /** * Configures and compiles shader objects, then links them into a shader program. Shader object stages are determined according to the presence of `#pragma ` directives. @@ -102,7 +102,7 @@ public: * @see has_fragment_directive() const * @see has_geometry_directive() const */ - gl::shader_program* build(const dictionary_type& definitions) const; + gl::shader_program* build(const dictionary_type& definitions = {}) const; /// Returns `true` if the template source contains one or more `#pragma vertex` directive. bool has_vertex_directive() const; @@ -120,6 +120,9 @@ public: */ bool has_define_directive(const std::string& key) const; + /// Returns a hash of the template source. + std::size_t get_hash() const; + private: void replace_stage_directives(gl::shader_stage stage) const; void replace_define_directives(const dictionary_type& definitions) const; @@ -129,8 +132,14 @@ private: std::unordered_set fragment_directives; std::unordered_set geometry_directives; std::multimap define_directives; + std::size_t hash; }; +inline std::size_t shader_template::get_hash() const +{ + return hash; +} + } // namespace render #endif // ANTKEEPER_RENDER_SHADER_TEMPLATE_HPP diff --git a/src/resources/shader-program-loader.cpp b/src/resources/shader-loader.cpp similarity index 83% rename from src/resources/shader-program-loader.cpp rename to src/resources/shader-loader.cpp index d471ca4..f3f0729 100644 --- a/src/resources/shader-program-loader.cpp +++ b/src/resources/shader-loader.cpp @@ -102,6 +102,25 @@ gl::shader_program* resource_loader::load(resource_manager* // Destroy shader template delete shader; - + return program; } + +template <> +render::shader_template* resource_loader::load(resource_manager* resource_manager, PHYSFS_File* file, const std::filesystem::path& path) +{ + // Load shader template source + text_file source_lines = *resource_loader::load(resource_manager, file, path); + + // Handle `#pragma include` directives + handle_includes(&source_lines, resource_manager); + + // Join vector of source lines into single string + std::ostringstream stream; + std::copy(source_lines.begin(), source_lines.end(), std::ostream_iterator(stream, "\n")); + + // Create shader template + render::shader_template* shader = new render::shader_template(stream.str()); + + return shader; +}