Browse Source

Add support for FXAA

master
C. J. Howard 1 year ago
parent
commit
f4d46b0ca7
14 changed files with 760 additions and 56 deletions
  1. +14
    -2
      src/game/context.hpp
  2. +124
    -15
      src/game/graphics.cpp
  3. +3
    -0
      src/game/graphics.hpp
  4. +55
    -8
      src/game/state/boot.cpp
  5. +122
    -20
      src/game/state/graphics-menu.cpp
  6. +39
    -0
      src/render/anti-aliasing-method.hpp
  7. +5
    -0
      src/render/pass.cpp
  8. +2
    -0
      src/render/pass.hpp
  9. +4
    -2
      src/render/passes/bloom-pass.cpp
  10. +9
    -9
      src/render/passes/final-pass.cpp
  11. +113
    -0
      src/render/passes/fxaa-pass.cpp
  12. +84
    -0
      src/render/passes/fxaa-pass.hpp
  13. +105
    -0
      src/render/passes/resample-pass.cpp
  14. +81
    -0
      src/render/passes/resample-pass.hpp

+ 14
- 2
src/game/context.hpp View File

@ -50,6 +50,7 @@
#include "type/bitmap-font.hpp" #include "type/bitmap-font.hpp"
#include "render/material.hpp" #include "render/material.hpp"
#include "render/material-property.hpp" #include "render/material-property.hpp"
#include "render/anti-aliasing-method.hpp"
#include "ui/mouse-tracker.hpp" #include "ui/mouse-tracker.hpp"
#include "application.hpp" #include "application.hpp"
#include "game/state/base.hpp" #include "game/state/base.hpp"
@ -108,6 +109,8 @@ namespace render
class clear_pass; class clear_pass;
class compositor; class compositor;
class final_pass; class final_pass;
class fxaa_pass;
class resample_pass;
class material_pass; class material_pass;
class renderer; class renderer;
class outline_pass; class outline_pass;
@ -185,6 +188,10 @@ struct context
gl::texture_2d* hdr_color_texture; gl::texture_2d* hdr_color_texture;
gl::texture_2d* hdr_depth_texture; gl::texture_2d* hdr_depth_texture;
gl::framebuffer* hdr_framebuffer; gl::framebuffer* hdr_framebuffer;
gl::texture_2d* ldr_color_texture_a;
gl::framebuffer* ldr_framebuffer_a;
gl::texture_2d* ldr_color_texture_b;
gl::framebuffer* ldr_framebuffer_b;
gl::texture_2d* shadow_map_depth_texture; gl::texture_2d* shadow_map_depth_texture;
gl::framebuffer* shadow_map_framebuffer; gl::framebuffer* shadow_map_framebuffer;
@ -192,7 +199,7 @@ struct context
gl::rasterizer* rasterizer; gl::rasterizer* rasterizer;
render::renderer* renderer; render::renderer* renderer;
int2 render_resolution; int2 render_resolution;
float render_resolution_scale;
float render_scale;
gl::vertex_buffer* billboard_vbo; gl::vertex_buffer* billboard_vbo;
gl::vertex_array* billboard_vao; gl::vertex_array* billboard_vao;
render::material* fallback_material; render::material* fallback_material;
@ -201,8 +208,10 @@ struct context
render::clear_pass* ui_clear_pass; render::clear_pass* ui_clear_pass;
render::material_pass* ui_material_pass; render::material_pass* ui_material_pass;
render::compositor* ui_compositor; render::compositor* ui_compositor;
render::bloom_pass* common_bloom_pass;
render::bloom_pass* bloom_pass;
render::final_pass* common_final_pass; render::final_pass* common_final_pass;
render::fxaa_pass* fxaa_pass;
render::resample_pass* resample_pass;
render::clear_pass* underground_clear_pass; render::clear_pass* underground_clear_pass;
render::material_pass* underground_material_pass; render::material_pass* underground_material_pass;
render::compositor* underground_compositor; render::compositor* underground_compositor;
@ -296,6 +305,9 @@ struct context
double3 rgb_wavelengths; double3 rgb_wavelengths;
const ecoregion* active_ecoregion; const ecoregion* active_ecoregion;
bool bloom_enabled;
render::anti_aliasing_method anti_aliasing_method;
}; };
} // namespace game } // namespace game

+ 124
- 15
src/game/graphics.cpp View File

@ -19,6 +19,9 @@
#include "game/graphics.hpp" #include "game/graphics.hpp"
#include "render/passes/bloom-pass.hpp" #include "render/passes/bloom-pass.hpp"
#include "render/passes/fxaa-pass.hpp"
#include "render/passes/final-pass.hpp"
#include "render/passes/resample-pass.hpp"
#include "gl/framebuffer.hpp" #include "gl/framebuffer.hpp"
#include "gl/texture-2d.hpp" #include "gl/texture-2d.hpp"
#include "gl/texture-wrapping.hpp" #include "gl/texture-wrapping.hpp"
@ -33,20 +36,20 @@
namespace game { namespace game {
namespace graphics { namespace graphics {
static void resize_framebuffer_attachment(gl::texture_2d& texture, const int2& resolution);
static void reroute_framebuffers(game::context& ctx);
void create_framebuffers(game::context& ctx) void create_framebuffers(game::context& ctx)
{ {
ctx.logger->push_task("Creating framebuffers"); ctx.logger->push_task("Creating framebuffers");
// Load render resolution scale from config // Load render resolution scale from config
ctx.render_resolution_scale = 1.0f;
if (ctx.config->contains("render_resolution"))
ctx.render_resolution_scale = (*ctx.config)["render_resolution"].get<float>();
ctx.render_scale = 1.0f;
if (ctx.config->contains("render_scale"))
ctx.render_scale = (*ctx.config)["render_scale"].get<float>();
// Calculate render resolution // Calculate render resolution
const int2& viewport_dimensions = ctx.app->get_viewport_dimensions(); const int2& viewport_dimensions = ctx.app->get_viewport_dimensions();
ctx.render_resolution = {static_cast<int>(viewport_dimensions.x() * ctx.render_resolution_scale + 0.5f), static_cast<int>(viewport_dimensions.y() * ctx.render_resolution_scale + 0.5f)};
ctx.render_resolution = {static_cast<int>(viewport_dimensions.x() * ctx.render_scale + 0.5f), static_cast<int>(viewport_dimensions.y() * ctx.render_scale + 0.5f)};
// Create HDR framebuffer (32F color, 32F depth) // Create HDR framebuffer (32F color, 32F depth)
ctx.hdr_color_texture = new gl::texture_2d(ctx.render_resolution.x(), ctx.render_resolution.y(), gl::pixel_type::float_32, gl::pixel_format::rgb); ctx.hdr_color_texture = new gl::texture_2d(ctx.render_resolution.x(), ctx.render_resolution.y(), gl::pixel_type::float_32, gl::pixel_format::rgb);
@ -62,6 +65,21 @@ void create_framebuffers(game::context& ctx)
ctx.hdr_framebuffer->attach(gl::framebuffer_attachment_type::depth, ctx.hdr_depth_texture); ctx.hdr_framebuffer->attach(gl::framebuffer_attachment_type::depth, ctx.hdr_depth_texture);
ctx.hdr_framebuffer->attach(gl::framebuffer_attachment_type::stencil, ctx.hdr_depth_texture); ctx.hdr_framebuffer->attach(gl::framebuffer_attachment_type::stencil, ctx.hdr_depth_texture);
// Create LDR framebuffers (8-bit color, no depth)
ctx.ldr_color_texture_a = new gl::texture_2d(ctx.render_resolution.x(), ctx.render_resolution.y(), gl::pixel_type::uint_8, gl::pixel_format::rgb);
ctx.ldr_color_texture_a->set_wrapping(gl::texture_wrapping::extend, gl::texture_wrapping::extend);
ctx.ldr_color_texture_a->set_filters(gl::texture_min_filter::linear, gl::texture_mag_filter::linear);
ctx.ldr_color_texture_a->set_max_anisotropy(0.0f);
ctx.ldr_framebuffer_a = new gl::framebuffer(ctx.render_resolution.x(), ctx.render_resolution.y());
ctx.ldr_framebuffer_a->attach(gl::framebuffer_attachment_type::color, ctx.ldr_color_texture_a);
ctx.ldr_color_texture_b = new gl::texture_2d(ctx.render_resolution.x(), ctx.render_resolution.y(), gl::pixel_type::uint_8, gl::pixel_format::rgb);
ctx.ldr_color_texture_b->set_wrapping(gl::texture_wrapping::extend, gl::texture_wrapping::extend);
ctx.ldr_color_texture_b->set_filters(gl::texture_min_filter::linear, gl::texture_mag_filter::linear);
ctx.ldr_color_texture_b->set_max_anisotropy(0.0f);
ctx.ldr_framebuffer_b = new gl::framebuffer(ctx.render_resolution.x(), ctx.render_resolution.y());
ctx.ldr_framebuffer_b->attach(gl::framebuffer_attachment_type::color, ctx.ldr_color_texture_b);
// Load shadow map resolution from config // Load shadow map resolution from config
int shadow_map_resolution = 4096; int shadow_map_resolution = 4096;
if (ctx.config->contains("shadow_map_resolution")) if (ctx.config->contains("shadow_map_resolution"))
@ -90,6 +108,17 @@ void destroy_framebuffers(game::context& ctx)
delete ctx.hdr_depth_texture; delete ctx.hdr_depth_texture;
ctx.hdr_depth_texture = nullptr; ctx.hdr_depth_texture = nullptr;
// Delete LDR framebuffers and attachments
delete ctx.ldr_framebuffer_a;
ctx.ldr_framebuffer_a = nullptr;
delete ctx.ldr_color_texture_a;
ctx.ldr_color_texture_a = nullptr;
delete ctx.ldr_framebuffer_b;
ctx.ldr_framebuffer_b = nullptr;
delete ctx.ldr_color_texture_b;
ctx.ldr_color_texture_b = nullptr;
// Delete shadow map framebuffer and its attachments // Delete shadow map framebuffer and its attachments
delete ctx.shadow_map_framebuffer; delete ctx.shadow_map_framebuffer;
ctx.shadow_map_framebuffer = nullptr; ctx.shadow_map_framebuffer = nullptr;
@ -104,28 +133,40 @@ void change_render_resolution(game::context& ctx, float scale)
ctx.logger->push_task("Changing render resolution"); ctx.logger->push_task("Changing render resolution");
// Update render resolution scale // Update render resolution scale
ctx.render_resolution_scale = scale;
ctx.render_scale = scale;
// Recalculate render resolution // Recalculate render resolution
const int2& viewport_dimensions = ctx.app->get_viewport_dimensions(); const int2& viewport_dimensions = ctx.app->get_viewport_dimensions();
ctx.render_resolution = {static_cast<int>(viewport_dimensions.x() * ctx.render_resolution_scale + 0.5f), static_cast<int>(viewport_dimensions.y() * ctx.render_resolution_scale + 0.5f)};
ctx.render_resolution = {static_cast<int>(viewport_dimensions.x() * ctx.render_scale + 0.5f), static_cast<int>(viewport_dimensions.y() * ctx.render_scale + 0.5f)};
// Resize HDR framebuffer and attachments // Resize HDR framebuffer and attachments
ctx.hdr_framebuffer->resize({ctx.render_resolution.x(), ctx.render_resolution.y()}); ctx.hdr_framebuffer->resize({ctx.render_resolution.x(), ctx.render_resolution.y()});
resize_framebuffer_attachment(*ctx.hdr_color_texture, ctx.render_resolution);
resize_framebuffer_attachment(*ctx.hdr_depth_texture, ctx.render_resolution);
ctx.hdr_color_texture->resize(ctx.render_resolution.x(), ctx.render_resolution.y(), nullptr);
ctx.hdr_depth_texture->resize(ctx.render_resolution.x(), ctx.render_resolution.y(), nullptr);
// Resize LDR framebuffers and attachments
ctx.ldr_framebuffer_a->resize({ctx.render_resolution.x(), ctx.render_resolution.y()});
ctx.ldr_color_texture_a->resize(ctx.render_resolution.x(), ctx.render_resolution.y(), nullptr);
ctx.ldr_framebuffer_b->resize({ctx.render_resolution.x(), ctx.render_resolution.y()});
ctx.ldr_color_texture_b->resize(ctx.render_resolution.x(), ctx.render_resolution.y(), nullptr);
// Resize bloom render pass // Resize bloom render pass
ctx.common_bloom_pass->resize();
ctx.bloom_pass->resize();
// Enable or disable resample pass
if (viewport_dimensions.x() != ctx.render_resolution.x() || viewport_dimensions.y() != ctx.render_resolution.y())
{
ctx.resample_pass->set_enabled(true);
}
else
{
ctx.resample_pass->set_enabled(false);
}
reroute_framebuffers(ctx);
ctx.logger->pop_task(EXIT_SUCCESS); ctx.logger->pop_task(EXIT_SUCCESS);
} }
void resize_framebuffer_attachment(gl::texture_2d& texture, const int2& resolution)
{
texture.resize(resolution.x(), resolution.y(), texture.get_pixel_type(), texture.get_pixel_format(), texture.get_color_space(), nullptr);
}
void save_screenshot(game::context& ctx) void save_screenshot(game::context& ctx)
{ {
// Determine screenshot path // Determine screenshot path
@ -158,5 +199,73 @@ void save_screenshot(game::context& ctx)
ctx.logger->pop_task(EXIT_SUCCESS); ctx.logger->pop_task(EXIT_SUCCESS);
} }
void toggle_bloom(game::context& ctx, bool enabled)
{
if (enabled)
{
ctx.bloom_pass->set_mip_chain_length(6);
ctx.bloom_pass->set_enabled(true);
ctx.common_final_pass->set_bloom_weight(0.04f);
}
else
{
ctx.bloom_pass->set_mip_chain_length(0);
ctx.bloom_pass->set_enabled(false);
ctx.common_final_pass->set_bloom_weight(0.0f);
}
ctx.bloom_enabled = enabled;
}
void select_anti_aliasing_method(game::context& ctx, render::anti_aliasing_method method)
{
// Switch AA method
switch (method)
{
// Off
case render::anti_aliasing_method::none:
ctx.fxaa_pass->set_enabled(false);
reroute_framebuffers(ctx);
break;
// FXAA
case render::anti_aliasing_method::fxaa:
ctx.fxaa_pass->set_enabled(true);
reroute_framebuffers(ctx);
break;
}
// Update AA method setting
ctx.anti_aliasing_method = method;
}
void reroute_framebuffers(game::context& ctx)
{
if (ctx.fxaa_pass->is_enabled())
{
if (ctx.resample_pass->is_enabled())
{
ctx.common_final_pass->set_framebuffer(ctx.ldr_framebuffer_a);
ctx.fxaa_pass->set_framebuffer(ctx.ldr_framebuffer_b);
}
else
{
ctx.common_final_pass->set_framebuffer(ctx.ldr_framebuffer_a);
ctx.fxaa_pass->set_framebuffer(&ctx.rasterizer->get_default_framebuffer());
}
}
else
{
if (ctx.resample_pass->is_enabled())
{
ctx.common_final_pass->set_framebuffer(ctx.ldr_framebuffer_b);
}
else
{
ctx.common_final_pass->set_framebuffer(&ctx.rasterizer->get_default_framebuffer());
}
}
}
} // namespace graphics } // namespace graphics
} // namespace game } // namespace game

+ 3
- 0
src/game/graphics.hpp View File

@ -21,6 +21,7 @@
#define ANTKEEPER_GAME_GRAPHICS_HPP #define ANTKEEPER_GAME_GRAPHICS_HPP
#include "game/context.hpp" #include "game/context.hpp"
#include "render/anti-aliasing-method.hpp"
namespace game { namespace game {
namespace graphics { namespace graphics {
@ -29,6 +30,8 @@ void create_framebuffers(game::context& ctx);
void destroy_framebuffers(game::context& ctx); void destroy_framebuffers(game::context& ctx);
void change_render_resolution(game::context& ctx, float scale); void change_render_resolution(game::context& ctx, float scale);
void save_screenshot(game::context& ctx); void save_screenshot(game::context& ctx);
void toggle_bloom(game::context& ctx, bool enabled);
void select_anti_aliasing_method(game::context& ctx, render::anti_aliasing_method method);
} // namespace graphics } // namespace graphics
} // namespace game } // namespace game

+ 55
- 8
src/game/state/boot.cpp View File

@ -43,6 +43,8 @@
#include "render/passes/bloom-pass.hpp" #include "render/passes/bloom-pass.hpp"
#include "render/passes/clear-pass.hpp" #include "render/passes/clear-pass.hpp"
#include "render/passes/final-pass.hpp" #include "render/passes/final-pass.hpp"
#include "render/passes/fxaa-pass.hpp"
#include "render/passes/resample-pass.hpp"
#include "render/passes/material-pass.hpp" #include "render/passes/material-pass.hpp"
#include "render/passes/outline-pass.hpp" #include "render/passes/outline-pass.hpp"
#include "render/passes/shadow-map-pass.hpp" #include "render/passes/shadow-map-pass.hpp"
@ -447,16 +449,57 @@ void boot::setup_rendering()
// Setup common render passes // Setup common render passes
{ {
ctx.common_bloom_pass = new render::bloom_pass(ctx.rasterizer, ctx.resource_manager);
ctx.common_bloom_pass->set_source_texture(ctx.hdr_color_texture);
ctx.common_bloom_pass->set_mip_chain_length(6);
ctx.common_bloom_pass->set_filter_radius(0.005f);
// Construct bloom pass
ctx.bloom_pass = new render::bloom_pass(ctx.rasterizer, ctx.resource_manager);
ctx.bloom_pass->set_source_texture(ctx.hdr_color_texture);
ctx.bloom_pass->set_mip_chain_length(0);
ctx.bloom_pass->set_filter_radius(0.005f);
ctx.common_final_pass = new render::final_pass(ctx.rasterizer, &ctx.rasterizer->get_default_framebuffer(), ctx.resource_manager);
ctx.common_final_pass = new render::final_pass(ctx.rasterizer, ctx.ldr_framebuffer_a, ctx.resource_manager);
ctx.common_final_pass->set_color_texture(ctx.hdr_color_texture); ctx.common_final_pass->set_color_texture(ctx.hdr_color_texture);
ctx.common_final_pass->set_bloom_texture(ctx.common_bloom_pass->get_bloom_texture());
ctx.common_final_pass->set_bloom_texture(ctx.bloom_pass->get_bloom_texture());
ctx.common_final_pass->set_bloom_weight(0.04f); ctx.common_final_pass->set_bloom_weight(0.04f);
ctx.common_final_pass->set_blue_noise_texture(blue_noise_map); ctx.common_final_pass->set_blue_noise_texture(blue_noise_map);
ctx.fxaa_pass = new render::fxaa_pass(ctx.rasterizer, &ctx.rasterizer->get_default_framebuffer(), ctx.resource_manager);
ctx.fxaa_pass->set_source_texture(ctx.ldr_color_texture_a);
ctx.resample_pass = new render::resample_pass(ctx.rasterizer, &ctx.rasterizer->get_default_framebuffer(), ctx.resource_manager);
ctx.resample_pass->set_source_texture(ctx.ldr_color_texture_b);
ctx.resample_pass->set_enabled(false);
// Toggle bloom according to settings
ctx.bloom_enabled = true;
if (ctx.config->contains("bloom_enabled"))
ctx.bloom_enabled = (*ctx.config)["bloom_enabled"].get<bool>();
graphics::toggle_bloom(ctx, ctx.bloom_enabled);
// Configure anti-aliasing according to settings
ctx.anti_aliasing_method = render::anti_aliasing_method::fxaa;
if (ctx.config->contains("anti_aliasing_method"))
{
const std::string aa_method = (*ctx.config)["anti_aliasing_method"].get<std::string>();
if (aa_method == "fxaa")
{
ctx.anti_aliasing_method = render::anti_aliasing_method::fxaa;
}
else
{
ctx.anti_aliasing_method = render::anti_aliasing_method::none;
}
}
graphics::select_anti_aliasing_method(ctx, ctx.anti_aliasing_method);
// Configure render scaling according to settings
ctx.render_scale = 1.0f;
if (ctx.config->contains("render_scale"))
{
ctx.render_scale = (*ctx.config)["render_scale"].get<float>();
if (ctx.render_scale != 1.0f)
{
graphics::change_render_resolution(ctx, ctx.render_scale);
}
}
} }
// Setup UI compositor // Setup UI compositor
@ -487,8 +530,10 @@ void boot::setup_rendering()
ctx.underground_compositor = new render::compositor(); ctx.underground_compositor = new render::compositor();
ctx.underground_compositor->add_pass(ctx.underground_clear_pass); ctx.underground_compositor->add_pass(ctx.underground_clear_pass);
ctx.underground_compositor->add_pass(ctx.underground_material_pass); ctx.underground_compositor->add_pass(ctx.underground_material_pass);
ctx.underground_compositor->add_pass(ctx.common_bloom_pass);
ctx.underground_compositor->add_pass(ctx.bloom_pass);
ctx.underground_compositor->add_pass(ctx.common_final_pass); ctx.underground_compositor->add_pass(ctx.common_final_pass);
ctx.underground_compositor->add_pass(ctx.fxaa_pass);
ctx.underground_compositor->add_pass(ctx.resample_pass);
} }
// Setup surface compositor // Setup surface compositor
@ -527,8 +572,10 @@ void boot::setup_rendering()
ctx.surface_compositor->add_pass(ctx.ground_pass); ctx.surface_compositor->add_pass(ctx.ground_pass);
ctx.surface_compositor->add_pass(ctx.surface_material_pass); ctx.surface_compositor->add_pass(ctx.surface_material_pass);
//ctx.surface_compositor->add_pass(ctx.surface_outline_pass); //ctx.surface_compositor->add_pass(ctx.surface_outline_pass);
ctx.surface_compositor->add_pass(ctx.common_bloom_pass);
ctx.surface_compositor->add_pass(ctx.bloom_pass);
ctx.surface_compositor->add_pass(ctx.common_final_pass); ctx.surface_compositor->add_pass(ctx.common_final_pass);
ctx.surface_compositor->add_pass(ctx.fxaa_pass);
ctx.surface_compositor->add_pass(ctx.resample_pass);
} }
// Create billboard VAO // Create billboard VAO

+ 122
- 20
src/game/state/graphics-menu.cpp View File

@ -44,6 +44,10 @@ graphics_menu::graphics_menu(game::context& ctx):
scene::text* resolution_value_text = new scene::text(); scene::text* resolution_value_text = new scene::text();
scene::text* v_sync_name_text = new scene::text(); scene::text* v_sync_name_text = new scene::text();
scene::text* v_sync_value_text = new scene::text(); scene::text* v_sync_value_text = new scene::text();
scene::text* aa_method_name_text = new scene::text();
scene::text* aa_method_value_text = new scene::text();
scene::text* bloom_name_text = new scene::text();
scene::text* bloom_value_text = new scene::text();
scene::text* font_size_name_text = new scene::text(); scene::text* font_size_name_text = new scene::text();
scene::text* font_size_value_text = new scene::text(); scene::text* font_size_value_text = new scene::text();
scene::text* dyslexia_font_name_text = new scene::text(); scene::text* dyslexia_font_name_text = new scene::text();
@ -54,6 +58,8 @@ graphics_menu::graphics_menu(game::context& ctx):
ctx.menu_item_texts.push_back({fullscreen_name_text, fullscreen_value_text}); ctx.menu_item_texts.push_back({fullscreen_name_text, fullscreen_value_text});
ctx.menu_item_texts.push_back({resolution_name_text, resolution_value_text}); ctx.menu_item_texts.push_back({resolution_name_text, resolution_value_text});
ctx.menu_item_texts.push_back({v_sync_name_text, v_sync_value_text}); ctx.menu_item_texts.push_back({v_sync_name_text, v_sync_value_text});
ctx.menu_item_texts.push_back({aa_method_name_text, aa_method_value_text});
ctx.menu_item_texts.push_back({bloom_name_text, bloom_value_text});
ctx.menu_item_texts.push_back({font_size_name_text, font_size_value_text}); ctx.menu_item_texts.push_back({font_size_name_text, font_size_value_text});
ctx.menu_item_texts.push_back({dyslexia_font_name_text, dyslexia_font_value_text}); ctx.menu_item_texts.push_back({dyslexia_font_name_text, dyslexia_font_value_text});
ctx.menu_item_texts.push_back({back_text, nullptr}); ctx.menu_item_texts.push_back({back_text, nullptr});
@ -62,6 +68,8 @@ graphics_menu::graphics_menu(game::context& ctx):
fullscreen_name_text->set_content((*ctx.strings)["graphics_menu_fullscreen"]); fullscreen_name_text->set_content((*ctx.strings)["graphics_menu_fullscreen"]);
resolution_name_text->set_content((*ctx.strings)["graphics_menu_resolution"]); resolution_name_text->set_content((*ctx.strings)["graphics_menu_resolution"]);
v_sync_name_text->set_content((*ctx.strings)["graphics_menu_v_sync"]); v_sync_name_text->set_content((*ctx.strings)["graphics_menu_v_sync"]);
aa_method_name_text->set_content((*ctx.strings)["graphics_menu_aa_method"]);
bloom_name_text->set_content((*ctx.strings)["graphics_menu_bloom"]);
font_size_name_text->set_content((*ctx.strings)["graphics_menu_font_size"]); font_size_name_text->set_content((*ctx.strings)["graphics_menu_font_size"]);
dyslexia_font_name_text->set_content((*ctx.strings)["graphics_menu_dyslexia_font"]); dyslexia_font_name_text->set_content((*ctx.strings)["graphics_menu_dyslexia_font"]);
back_text->set_content((*ctx.strings)["back"]); back_text->set_content((*ctx.strings)["back"]);
@ -105,16 +113,16 @@ graphics_menu::graphics_menu(game::context& ctx):
{ {
// Increase resolution // Increase resolution
if (ctx.controls["menu_modifier"]->is_active()) if (ctx.controls["menu_modifier"]->is_active())
ctx.render_resolution_scale += 0.05f;
ctx.render_scale += 0.05f;
else else
ctx.render_resolution_scale += 0.25f;
ctx.render_scale += 0.25f;
// Limit resolution // Limit resolution
if (ctx.render_resolution_scale > 2.0f)
ctx.render_resolution_scale = 2.0f;
if (ctx.render_scale > 2.0f)
ctx.render_scale = 2.0f;
// Resize framebuffers // Resize framebuffers
game::graphics::change_render_resolution(ctx, ctx.render_resolution_scale);
game::graphics::change_render_resolution(ctx, ctx.render_scale);
// Update text // Update text
this->update_value_text_content(); this->update_value_text_content();
@ -122,23 +130,23 @@ graphics_menu::graphics_menu(game::context& ctx):
game::menu::update_text_tweens(ctx); game::menu::update_text_tweens(ctx);
// Update config // Update config
(*ctx.config)["render_resolution"] = ctx.render_resolution_scale;
(*ctx.config)["render_scale"] = ctx.render_scale;
}; };
auto decrease_resolution_callback = [this, &ctx]() auto decrease_resolution_callback = [this, &ctx]()
{ {
// Increase resolution // Increase resolution
if (ctx.controls["menu_modifier"]->is_active()) if (ctx.controls["menu_modifier"]->is_active())
ctx.render_resolution_scale -= 0.05f;
ctx.render_scale -= 0.05f;
else else
ctx.render_resolution_scale -= 0.25f;
ctx.render_scale -= 0.25f;
// Limit resolution // Limit resolution
if (ctx.render_resolution_scale < 0.25f)
ctx.render_resolution_scale = 0.25f;
if (ctx.render_scale < 0.25f)
ctx.render_scale = 0.25f;
// Resize framebuffers // Resize framebuffers
game::graphics::change_render_resolution(ctx, ctx.render_resolution_scale);
game::graphics::change_render_resolution(ctx, ctx.render_scale);
// Update text // Update text
this->update_value_text_content(); this->update_value_text_content();
@ -146,7 +154,7 @@ graphics_menu::graphics_menu(game::context& ctx):
game::menu::update_text_tweens(ctx); game::menu::update_text_tweens(ctx);
// Update config // Update config
(*ctx.config)["render_resolution"] = ctx.render_resolution_scale;
(*ctx.config)["render_scale"] = ctx.render_scale;
}; };
auto toggle_v_sync_callback = [this, &ctx]() auto toggle_v_sync_callback = [this, &ctx]()
@ -163,6 +171,74 @@ graphics_menu::graphics_menu(game::context& ctx):
(*ctx.config)["v_sync"] = v_sync; (*ctx.config)["v_sync"] = v_sync;
}; };
auto next_aa_method_callback = [this, &ctx]()
{
switch (ctx.anti_aliasing_method)
{
case render::anti_aliasing_method::none:
ctx.anti_aliasing_method = render::anti_aliasing_method::fxaa;
(*ctx.config)["anti_aliasing_method"] = "fxaa";
break;
case render::anti_aliasing_method::fxaa:
ctx.anti_aliasing_method = render::anti_aliasing_method::none;
(*ctx.config)["anti_aliasing_method"] = "none";
break;
}
game::graphics::select_anti_aliasing_method(ctx, ctx.anti_aliasing_method);
// Update value text
this->update_value_text_content();
// Refresh and realign text
game::menu::refresh_text(ctx);
game::menu::align_text(ctx);
game::menu::update_text_tweens(ctx);
};
auto previous_aa_method_callback = [this, &ctx]()
{
switch (ctx.anti_aliasing_method)
{
case render::anti_aliasing_method::none:
ctx.anti_aliasing_method = render::anti_aliasing_method::fxaa;
(*ctx.config)["anti_aliasing_method"] = "fxaa";
break;
case render::anti_aliasing_method::fxaa:
ctx.anti_aliasing_method = render::anti_aliasing_method::none;
(*ctx.config)["anti_aliasing_method"] = "none";
break;
}
game::graphics::select_anti_aliasing_method(ctx, ctx.anti_aliasing_method);
// Update value text
this->update_value_text_content();
// Refresh and realign text
game::menu::refresh_text(ctx);
game::menu::align_text(ctx);
game::menu::update_text_tweens(ctx);
};
auto toggle_bloom_callback = [this, &ctx]()
{
game::graphics::toggle_bloom(ctx, !ctx.bloom_enabled);
// Update value text
this->update_value_text_content();
// Update config
(*ctx.config)["bloom_enabled"] = ctx.bloom_enabled;
// Refresh and realign text
game::menu::refresh_text(ctx);
game::menu::align_text(ctx);
game::menu::update_text_tweens(ctx);
};
auto increase_font_size_callback = [this, &ctx]() auto increase_font_size_callback = [this, &ctx]()
{ {
// Increase font size // Increase font size
@ -289,6 +365,8 @@ graphics_menu::graphics_menu(game::context& ctx):
ctx.menu_select_callbacks.push_back(toggle_fullscreen_callback); ctx.menu_select_callbacks.push_back(toggle_fullscreen_callback);
ctx.menu_select_callbacks.push_back(increase_resolution_callback); ctx.menu_select_callbacks.push_back(increase_resolution_callback);
ctx.menu_select_callbacks.push_back(toggle_v_sync_callback); ctx.menu_select_callbacks.push_back(toggle_v_sync_callback);
ctx.menu_select_callbacks.push_back(next_aa_method_callback);
ctx.menu_select_callbacks.push_back(toggle_bloom_callback);
ctx.menu_select_callbacks.push_back(increase_font_size_callback); ctx.menu_select_callbacks.push_back(increase_font_size_callback);
ctx.menu_select_callbacks.push_back(toggle_dyslexia_font_callback); ctx.menu_select_callbacks.push_back(toggle_dyslexia_font_callback);
ctx.menu_select_callbacks.push_back(select_back_callback); ctx.menu_select_callbacks.push_back(select_back_callback);
@ -297,6 +375,8 @@ graphics_menu::graphics_menu(game::context& ctx):
ctx.menu_left_callbacks.push_back(toggle_fullscreen_callback); ctx.menu_left_callbacks.push_back(toggle_fullscreen_callback);
ctx.menu_left_callbacks.push_back(decrease_resolution_callback); ctx.menu_left_callbacks.push_back(decrease_resolution_callback);
ctx.menu_left_callbacks.push_back(toggle_v_sync_callback); ctx.menu_left_callbacks.push_back(toggle_v_sync_callback);
ctx.menu_left_callbacks.push_back(previous_aa_method_callback);
ctx.menu_left_callbacks.push_back(toggle_bloom_callback);
ctx.menu_left_callbacks.push_back(decrease_font_size_callback); ctx.menu_left_callbacks.push_back(decrease_font_size_callback);
ctx.menu_left_callbacks.push_back(toggle_dyslexia_font_callback); ctx.menu_left_callbacks.push_back(toggle_dyslexia_font_callback);
ctx.menu_left_callbacks.push_back(nullptr); ctx.menu_left_callbacks.push_back(nullptr);
@ -305,6 +385,8 @@ graphics_menu::graphics_menu(game::context& ctx):
ctx.menu_right_callbacks.push_back(toggle_fullscreen_callback); ctx.menu_right_callbacks.push_back(toggle_fullscreen_callback);
ctx.menu_right_callbacks.push_back(increase_resolution_callback); ctx.menu_right_callbacks.push_back(increase_resolution_callback);
ctx.menu_right_callbacks.push_back(toggle_v_sync_callback); ctx.menu_right_callbacks.push_back(toggle_v_sync_callback);
ctx.menu_right_callbacks.push_back(next_aa_method_callback);
ctx.menu_right_callbacks.push_back(toggle_bloom_callback);
ctx.menu_right_callbacks.push_back(increase_font_size_callback); ctx.menu_right_callbacks.push_back(increase_font_size_callback);
ctx.menu_right_callbacks.push_back(toggle_dyslexia_font_callback); ctx.menu_right_callbacks.push_back(toggle_dyslexia_font_callback);
ctx.menu_right_callbacks.push_back(nullptr); ctx.menu_right_callbacks.push_back(nullptr);
@ -337,20 +419,40 @@ graphics_menu::~graphics_menu()
void graphics_menu::update_value_text_content() void graphics_menu::update_value_text_content()
{ {
bool fullscreen = ctx.app->is_fullscreen();
float resolution = ctx.render_resolution_scale;
bool v_sync = ctx.app->get_v_sync();
float font_size = ctx.font_size;
bool dyslexia_font = ctx.dyslexia_font;
const bool fullscreen = ctx.app->is_fullscreen();
const float render_scale = ctx.render_scale;
const bool v_sync = ctx.app->get_v_sync();
const int aa_method_index = static_cast<int>(ctx.anti_aliasing_method);
const bool bloom_enabled = ctx.bloom_enabled;
const float font_size = ctx.font_size;
const bool dyslexia_font = ctx.dyslexia_font;
const std::string string_on = (*ctx.strings)["on"]; const std::string string_on = (*ctx.strings)["on"];
const std::string string_off = (*ctx.strings)["off"]; const std::string string_off = (*ctx.strings)["off"];
/*
const std::string string_quality[4] =
{
(*ctx.strings)["off"],
(*ctx.strings)["quality_low"],
(*ctx.strings)["quality_medium"],
(*ctx.strings)["quality_high"]
};
*/
const std::string string_aa_methods[2] =
{
(*ctx.strings)["graphics_menu_aa_method_none"],
(*ctx.strings)["graphics_menu_aa_method_fxaa"]
};
std::get<1>(ctx.menu_item_texts[0])->set_content((fullscreen) ? string_on : string_off); std::get<1>(ctx.menu_item_texts[0])->set_content((fullscreen) ? string_on : string_off);
std::get<1>(ctx.menu_item_texts[1])->set_content(std::to_string(static_cast<int>(std::round(resolution * 100.0f))) + "%");
std::get<1>(ctx.menu_item_texts[1])->set_content(std::to_string(static_cast<int>(std::round(render_scale * 100.0f))) + "%");
std::get<1>(ctx.menu_item_texts[2])->set_content((v_sync) ? string_on : string_off); std::get<1>(ctx.menu_item_texts[2])->set_content((v_sync) ? string_on : string_off);
std::get<1>(ctx.menu_item_texts[3])->set_content(std::to_string(static_cast<int>(std::round(font_size * 100.0f))) + "%");
std::get<1>(ctx.menu_item_texts[4])->set_content((dyslexia_font) ? string_on : string_off);
std::get<1>(ctx.menu_item_texts[3])->set_content(string_aa_methods[aa_method_index]);
std::get<1>(ctx.menu_item_texts[4])->set_content((bloom_enabled) ? string_on : string_off);
std::get<1>(ctx.menu_item_texts[5])->set_content(std::to_string(static_cast<int>(std::round(font_size * 100.0f))) + "%");
std::get<1>(ctx.menu_item_texts[6])->set_content((dyslexia_font) ? string_on : string_off);
} }
} // namespace state } // namespace state

+ 39
- 0
src/render/anti-aliasing-method.hpp View File

@ -0,0 +1,39 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_RENDER_ANTI_ALIASING_METHOD_HPP
#define ANTKEEPER_RENDER_ANTI_ALIASING_METHOD_HPP
namespace render {
/**
* Anti-aliasing methods.
*/
enum class anti_aliasing_method
{
/// No anti-aliasing.
none,
/// Fast approximate anti-aliasing (FXAA).
fxaa
};
} // namespace render
#endif // ANTKEEPER_RENDER_ANTI_ALIASING_METHOD_HPP

+ 5
- 0
src/render/pass.cpp View File

@ -35,4 +35,9 @@ void pass::set_enabled(bool enabled)
this->enabled = enabled; this->enabled = enabled;
} }
void pass::set_framebuffer(const gl::framebuffer* framebuffer)
{
this->framebuffer = framebuffer;
}
} // namespace render } // namespace render

+ 2
- 0
src/render/pass.hpp View File

@ -40,6 +40,8 @@ public:
void set_enabled(bool enabled); void set_enabled(bool enabled);
bool is_enabled() const; bool is_enabled() const;
void set_framebuffer(const gl::framebuffer* framebuffer);
protected: protected:
gl::rasterizer* rasterizer; gl::rasterizer* rasterizer;

+ 4
- 2
src/render/passes/bloom-pass.cpp View File

@ -35,7 +35,6 @@
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>
#include <glad/glad.h> #include <glad/glad.h>
#include <iostream>
namespace render { namespace render {
@ -46,7 +45,7 @@ bloom_pass::bloom_pass(gl::rasterizer* rasterizer, resource_manager* resource_ma
filter_radius(0.005f), filter_radius(0.005f),
corrected_filter_radius{filter_radius, filter_radius} corrected_filter_radius{filter_radius, filter_radius}
{ {
// Load downsample with Karis average shader
// Load downsample shader with Karis average
downsample_karis_shader = resource_manager->load<gl::shader_program>("bloom-downsample-karis.glsl"); downsample_karis_shader = resource_manager->load<gl::shader_program>("bloom-downsample-karis.glsl");
downsample_karis_source_texture_input = downsample_karis_shader->get_input("source_texture"); downsample_karis_source_texture_input = downsample_karis_shader->get_input("source_texture");
@ -91,6 +90,9 @@ bloom_pass::bloom_pass(gl::rasterizer* rasterizer, resource_manager* resource_ma
bloom_pass::~bloom_pass() bloom_pass::~bloom_pass()
{ {
set_mip_chain_length(0); set_mip_chain_length(0);
delete quad_vao;
delete quad_vbo;
} }
void bloom_pass::render(const render::context& ctx, render::queue& queue) const void bloom_pass::render(const render::context& ctx, render::queue& queue) const

+ 9
- 9
src/render/passes/final-pass.cpp View File

@ -56,15 +56,15 @@ final_pass::final_pass(gl::rasterizer* rasterizer, const gl::framebuffer* frameb
const float vertex_data[] = 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
-1.0f, 1.0f,
-1.0f, -1.0f,
1.0f, 1.0f,
1.0f, 1.0f,
-1.0f, -1.0f,
1.0f, -1.0f
}; };
std::size_t vertex_size = 3;
std::size_t vertex_size = 2;
std::size_t vertex_stride = sizeof(float) * vertex_size; std::size_t vertex_stride = sizeof(float) * vertex_size;
std::size_t vertex_count = 6; std::size_t vertex_count = 6;
@ -77,7 +77,7 @@ final_pass::final_pass(gl::rasterizer* rasterizer, const gl::framebuffer* frameb
position_attribute.offset = 0; position_attribute.offset = 0;
position_attribute.stride = vertex_stride; position_attribute.stride = vertex_stride;
position_attribute.type = gl::vertex_attribute_type::float_32; position_attribute.type = gl::vertex_attribute_type::float_32;
position_attribute.components = 3;
position_attribute.components = 2;
// Bind vertex attributes to VAO // Bind vertex attributes to VAO
quad_vao->bind(render::vertex_attribute::position, position_attribute); quad_vao->bind(render::vertex_attribute::position, position_attribute);

+ 113
- 0
src/render/passes/fxaa-pass.cpp View File

@ -0,0 +1,113 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "render/passes/fxaa-pass.hpp"
#include "resources/resource-manager.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 "render/vertex-attribute.hpp"
#include "render/context.hpp"
#include <glad/glad.h>
namespace render {
fxaa_pass::fxaa_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuffer, resource_manager* resource_manager):
pass(rasterizer, framebuffer),
source_texture(nullptr)
{
// Load FXAA shader
shader = resource_manager->load<gl::shader_program>("fxaa.glsl");
source_texture_input = shader->get_input("source_texture");
texel_size_input = shader->get_input("texel_size");
const float vertex_data[] =
{
-1.0f, 1.0f,
-1.0f, -1.0f,
1.0f, 1.0f,
1.0f, 1.0f,
-1.0f, -1.0f,
1.0f, -1.0f
};
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();
// 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 = 2;
// Bind vertex attributes to VAO
quad_vao->bind(render::vertex_attribute::position, position_attribute);
}
fxaa_pass::~fxaa_pass()
{
delete quad_vao;
delete quad_vbo;
}
void fxaa_pass::render(const render::context& ctx, render::queue& queue) const
{
if (!source_texture)
return;
// Set rasterizer state
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glDisable(GL_BLEND);
// Render FXAA
rasterizer->use_framebuffer(*framebuffer);
rasterizer->set_viewport(0, 0, framebuffer->get_dimensions()[0], framebuffer->get_dimensions()[1]);
rasterizer->use_program(*shader);
source_texture_input->upload(source_texture);
if (texel_size_input)
{
const float2 texel_size = 1.0f / float2{static_cast<float>(source_texture->get_width()), static_cast<float>(source_texture->get_height())};
texel_size_input->upload(texel_size);
}
rasterizer->draw_arrays(*quad_vao, gl::drawing_mode::triangles, 0, 6);
}
void fxaa_pass::set_source_texture(const gl::texture_2d* texture)
{
source_texture = texture;
}
} // namespace render

+ 84
- 0
src/render/passes/fxaa-pass.hpp View File

@ -0,0 +1,84 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_RENDER_FXAA_PASS_HPP
#define ANTKEEPER_RENDER_FXAA_PASS_HPP
#include "render/pass.hpp"
#include "gl/shader-program.hpp"
#include "gl/shader-input.hpp"
#include "gl/vertex-buffer.hpp"
#include "gl/vertex-array.hpp"
#include "gl/texture-2d.hpp"
class resource_manager;
namespace render {
/**
* FXAA render pass.
*
* @see Lottes, T. (2009). Fxaa. White paper, Nvidia, Febuary, 2.
*/
class fxaa_pass: public pass
{
public:
/**
* Constructs an FXAA pass.
*
* @param rasterizer Rasterizer.
* @param framebuffer Target framebuffer.
* @param resource_manager Resource manager.
*/
fxaa_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuffer, resource_manager* resource_manager);
/**
* Destructs an FXAA pass.
*/
virtual ~fxaa_pass();
/**
* Renders FXAA.
*
* @param ctx Render context.
* @param queue Render queue.
*/
virtual void render(const render::context& ctx, render::queue& queue) const final;
/**
* Sets the FXAA source texture.
*
* @param texture FXAA source texture.
*/
void set_source_texture(const gl::texture_2d* texture);
private:
const gl::texture_2d* source_texture;
gl::shader_program* shader;
const gl::shader_input* source_texture_input;
const gl::shader_input* texel_size_input;
gl::vertex_buffer* quad_vbo;
gl::vertex_array* quad_vao;
};
} // namespace render
#endif // ANTKEEPER_RENDER_FXAA_PASS_HPP

+ 105
- 0
src/render/passes/resample-pass.cpp View File

@ -0,0 +1,105 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "render/passes/resample-pass.hpp"
#include "resources/resource-manager.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 "render/vertex-attribute.hpp"
#include "render/context.hpp"
#include <glad/glad.h>
namespace render {
resample_pass::resample_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuffer, resource_manager* resource_manager):
pass(rasterizer, framebuffer),
source_texture(nullptr)
{
// Load resample shader
shader = resource_manager->load<gl::shader_program>("resample.glsl");
source_texture_input = shader->get_input("source_texture");
const float vertex_data[] =
{
-1.0f, 1.0f,
-1.0f, -1.0f,
1.0f, 1.0f,
1.0f, 1.0f,
-1.0f, -1.0f,
1.0f, -1.0f
};
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();
// 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 = 2;
// Bind vertex attributes to VAO
quad_vao->bind(render::vertex_attribute::position, position_attribute);
}
resample_pass::~resample_pass()
{
delete quad_vao;
delete quad_vbo;
}
void resample_pass::render(const render::context& ctx, render::queue& queue) const
{
if (!source_texture)
return;
// Set rasterizer state
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glDisable(GL_BLEND);
// Render FXAA
rasterizer->use_framebuffer(*framebuffer);
rasterizer->set_viewport(0, 0, framebuffer->get_dimensions()[0], framebuffer->get_dimensions()[1]);
rasterizer->use_program(*shader);
source_texture_input->upload(source_texture);
rasterizer->draw_arrays(*quad_vao, gl::drawing_mode::triangles, 0, 6);
}
void resample_pass::set_source_texture(const gl::texture_2d* texture)
{
source_texture = texture;
}
} // namespace render

+ 81
- 0
src/render/passes/resample-pass.hpp View File

@ -0,0 +1,81 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_RENDER_RESAMPLE_PASS_HPP
#define ANTKEEPER_RENDER_RESAMPLE_PASS_HPP
#include "render/pass.hpp"
#include "gl/shader-program.hpp"
#include "gl/shader-input.hpp"
#include "gl/vertex-buffer.hpp"
#include "gl/vertex-array.hpp"
#include "gl/texture-2d.hpp"
class resource_manager;
namespace render {
/**
* Resamples a texture.
*/
class resample_pass: public pass
{
public:
/**
* Constructs a resample pass.
*
* @param rasterizer Rasterizer.
* @param framebuffer Target framebuffer.
* @param resource_manager Resource manager.
*/
resample_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuffer, resource_manager* resource_manager);
/**
* Destructs a resample pass.
*/
virtual ~resample_pass();
/**
* Resamples a texture.
*
* @param ctx Render context.
* @param queue Render queue.
*/
virtual void render(const render::context& ctx, render::queue& queue) const final;
/**
* Sets the resample source texture.
*
* @param texture Texture to resample.
*/
void set_source_texture(const gl::texture_2d* texture);
private:
const gl::texture_2d* source_texture;
gl::shader_program* shader;
const gl::shader_input* source_texture_input;
gl::vertex_buffer* quad_vbo;
gl::vertex_array* quad_vao;
};
} // namespace render
#endif // ANTKEEPER_RENDER_RESAMPLE_PASS_HPP

Loading…
Cancel
Save