diff --git a/CMakeLists.txt b/CMakeLists.txt index 7f0f857..d3614e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,6 @@ cmake_minimum_required(VERSION 3.7) + option(VERSION_STRING "Project version string" "0.0.0") project(antkeeper VERSION ${VERSION_STRING} LANGUAGES CXX) diff --git a/src/application.cpp b/src/application.cpp index e619d4e..01c0f7a 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -44,7 +44,7 @@ application::application(): update_callback(nullptr), render_callback(nullptr), fullscreen(true), - v_sync(true), + v_sync(false), cursor_visible(true), display_dimensions({0, 0}), display_dpi(0.0f), @@ -187,16 +187,7 @@ application::application(): SDL_GL_GetDrawableSize(sdl_window, &viewport_dimensions[0], &viewport_dimensions[1]); // Set v-sync mode - int swap_interval = (v_sync) ? 1 : 0; - logger->push_task((swap_interval) ? "Enabling v-sync" : "Disabling v-sync"); - if (SDL_GL_SetSwapInterval(swap_interval) != 0) - { - logger->pop_task(EXIT_FAILURE); - } - else - { - logger->pop_task(EXIT_SUCCESS); - } + set_v_sync(true); // Init SDL joystick and gamepad subsystems logger->push_task("Initializing SDL Joystick and Game Controller subsystems"); @@ -496,8 +487,43 @@ void application::set_v_sync(bool v_sync) { if (this->v_sync != v_sync) { - this->v_sync = v_sync; - SDL_GL_SetSwapInterval((v_sync) ? 1 : 0); + if (v_sync) + { + logger->push_task("Enabling adaptive v-sync"); + if (SDL_GL_SetSwapInterval(-1) != 0) + { + logger->pop_task(EXIT_FAILURE); + + logger->push_task("Enabling synchronized v-sync"); + if (SDL_GL_SetSwapInterval(-1) != 0) + { + logger->pop_task(EXIT_FAILURE); + } + else + { + this->v_sync = v_sync; + logger->pop_task(EXIT_SUCCESS); + } + } + else + { + this->v_sync = v_sync; + logger->pop_task(EXIT_SUCCESS); + } + } + else + { + logger->push_task("Disabling v-sync"); + if (SDL_GL_SetSwapInterval(0) != 0) + { + logger->pop_task(EXIT_FAILURE); + } + else + { + this->v_sync = v_sync; + logger->pop_task(EXIT_SUCCESS); + } + } } } diff --git a/src/application.hpp b/src/application.hpp index 4c89e10..8235eef 100644 --- a/src/application.hpp +++ b/src/application.hpp @@ -29,6 +29,7 @@ #include "input/keyboard.hpp" #include "input/mouse.hpp" #include "input/gamepad.hpp" +#include "utility/fundamental-types.hpp" // Forward declarations typedef struct SDL_Window SDL_Window; @@ -192,16 +193,16 @@ public: void add_game_controller_mappings(const void* mappings, std::size_t size); /// Returns the dimensions of the current display. - const std::array& get_display_dimensions() const; + const int2& get_display_dimensions() const; /// Returns the DPI of the display. float get_display_dpi() const; /// Returns the dimensions of the window. - const std::array& get_window_dimensions() const; + const int2& get_window_dimensions() const; /// Returns the dimensions of the window's drawable viewport. - const std::array& get_viewport_dimensions() const; + const int2& get_viewport_dimensions() const; /// Returns `true` if the window is in fullscreen mode, `false` otherwise. bool is_fullscreen() const; @@ -243,11 +244,11 @@ private: bool fullscreen; bool v_sync; bool cursor_visible; - std::array display_dimensions; + int2 display_dimensions; float display_dpi; - std::array window_dimensions; - std::array viewport_dimensions; - std::array mouse_position; + int2 window_dimensions; + int2 viewport_dimensions; + int2 mouse_position; double update_rate; debug::logger* logger; @@ -275,7 +276,7 @@ inline debug::logger* application::get_logger() return logger; } -inline const std::array& application::get_display_dimensions() const +inline const int2& application::get_display_dimensions() const { return display_dimensions; } @@ -285,12 +286,12 @@ inline float application::get_display_dpi() const return display_dpi; } -inline const std::array& application::get_window_dimensions() const +inline const int2& application::get_window_dimensions() const { return window_dimensions; } -inline const std::array& application::get_viewport_dimensions() const +inline const int2& application::get_viewport_dimensions() const { return viewport_dimensions; } diff --git a/src/game/context.hpp b/src/game/context.hpp index d47f49e..919bd34 100644 --- a/src/game/context.hpp +++ b/src/game/context.hpp @@ -44,6 +44,7 @@ #include #include #include +#include #include "resources/json.hpp" #include "type/typeface.hpp" #include "type/bitmap-font.hpp" @@ -110,7 +111,7 @@ namespace render namespace game { -/// Structure containing the state of a game. +/// Container for data that is shared between game states. struct context { application* app; @@ -158,17 +159,18 @@ struct context render::material title_font_material; // Framebuffers - gl::framebuffer* shadow_map_framebuffer; + gl::texture_2d* hdr_color_texture; + gl::texture_2d* hdr_depth_texture; + gl::framebuffer* hdr_framebuffer; + gl::texture_2d* bloom_color_texture; + gl::framebuffer* bloom_framebuffer; gl::texture_2d* shadow_map_depth_texture; - gl::framebuffer* framebuffer_hdr; - gl::texture_2d* framebuffer_hdr_color; - gl::texture_2d* framebuffer_hdr_depth; - gl::framebuffer* framebuffer_bloom; // General purpose framebuffer A - gl::texture_2d* bloom_texture; + gl::framebuffer* shadow_map_framebuffer; // Rendering gl::rasterizer* rasterizer; render::renderer* renderer; + int2 render_resolution; float render_resolution_scale; gl::vertex_buffer* billboard_vbo; gl::vertex_array* billboard_vao; @@ -179,14 +181,11 @@ struct context render::clear_pass* ui_clear_pass; render::material_pass* ui_material_pass; render::compositor* ui_compositor; - render::bloom_pass* common_bloom_pass; render::final_pass* common_final_pass; - render::clear_pass* underground_clear_pass; render::material_pass* underground_material_pass; render::compositor* underground_compositor; - render::clear_pass* surface_shadow_map_clear_pass; render::shadow_map_pass* surface_shadow_map_pass; render::clear_pass* surface_clear_pass; @@ -300,6 +299,9 @@ struct context // State management std::optional paused_state; + // Misc + std::queue> function_queue; + // Debug debug::cli* cli; }; diff --git a/src/game/graphics.cpp b/src/game/graphics.cpp new file mode 100644 index 0000000..21c2af4 --- /dev/null +++ b/src/game/graphics.cpp @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2021 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 "game/graphics.hpp" +#include "gl/framebuffer.hpp" +#include "gl/texture-2d.hpp" +#include "gl/texture-wrapping.hpp" +#include "gl/texture-filter.hpp" +#include "debug/logger.hpp" + +namespace game { +namespace graphics { + +static void resize_framebuffer_attachment(gl::texture_2d& texture, const int2& resolution); + +void create_framebuffers(game::context& ctx) +{ + ctx.logger->push_task("Creating framebuffers"); + + // 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(); + + // Calculate render resolution + const int2& viewport_dimensions = ctx.app->get_viewport_dimensions(); + ctx.render_resolution = {static_cast(viewport_dimensions.x * ctx.render_resolution_scale + 0.5f), static_cast(viewport_dimensions.y * ctx.render_resolution_scale + 0.5f)}; + + // 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->set_wrapping(gl::texture_wrapping::extend, gl::texture_wrapping::extend); + ctx.hdr_color_texture->set_filters(gl::texture_min_filter::linear, gl::texture_mag_filter::linear); + ctx.hdr_color_texture->set_max_anisotropy(0.0f); + ctx.hdr_depth_texture = new gl::texture_2d(ctx.render_resolution.x, ctx.render_resolution.y, gl::pixel_type::float_32, gl::pixel_format::ds); + ctx.hdr_depth_texture->set_wrapping(gl::texture_wrapping::extend, gl::texture_wrapping::extend); + ctx.hdr_depth_texture->set_filters(gl::texture_min_filter::linear, gl::texture_mag_filter::linear); + ctx.hdr_depth_texture->set_max_anisotropy(0.0f); + ctx.hdr_framebuffer = new gl::framebuffer(ctx.render_resolution.x, ctx.render_resolution.y); + ctx.hdr_framebuffer->attach(gl::framebuffer_attachment_type::color, ctx.hdr_color_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); + + // Calculate bloom resolution + int2 bloom_resolution = ctx.render_resolution / 2; + + // Create bloom framebuffer (16F color, no depth) + ctx.bloom_color_texture = new gl::texture_2d(bloom_resolution.x, bloom_resolution.y, gl::pixel_type::float_16, gl::pixel_format::rgb); + ctx.bloom_color_texture->set_wrapping(gl::texture_wrapping::extend, gl::texture_wrapping::extend); + ctx.bloom_color_texture->set_filters(gl::texture_min_filter::linear, gl::texture_mag_filter::linear); + ctx.bloom_color_texture->set_max_anisotropy(0.0f); + ctx.bloom_framebuffer = new gl::framebuffer(bloom_resolution.x, bloom_resolution.y); + ctx.bloom_framebuffer->attach(gl::framebuffer_attachment_type::color, ctx.bloom_color_texture); + + // Load shadow map resolution from config + int shadow_map_resolution = 4096; + if (ctx.config->contains("shadow_map_resolution")) + shadow_map_resolution = (*ctx.config)["shadow_map_resolution"].get(); + + // Create shadow map framebuffer + ctx.shadow_map_depth_texture = new gl::texture_2d(shadow_map_resolution, shadow_map_resolution, gl::pixel_type::float_32, gl::pixel_format::d); + ctx.shadow_map_depth_texture->set_wrapping(gl::texture_wrapping::extend, gl::texture_wrapping::extend); + ctx.shadow_map_depth_texture->set_filters(gl::texture_min_filter::linear, gl::texture_mag_filter::linear); + ctx.shadow_map_depth_texture->set_max_anisotropy(0.0f); + ctx.shadow_map_framebuffer = new gl::framebuffer(shadow_map_resolution, shadow_map_resolution); + ctx.shadow_map_framebuffer->attach(gl::framebuffer_attachment_type::depth, ctx.shadow_map_depth_texture); + + ctx.logger->pop_task(EXIT_SUCCESS); +} + +void destroy_framebuffers(game::context& ctx) +{ + ctx.logger->push_task("Destroying framebuffers"); + + // Delete HDR framebuffer and its attachments + delete ctx.hdr_framebuffer; + ctx.hdr_framebuffer = nullptr; + delete ctx.hdr_color_texture; + ctx.hdr_color_texture = nullptr; + delete ctx.hdr_depth_texture; + ctx.hdr_depth_texture = nullptr; + + // Delete bloom framebuffer and its attachments + delete ctx.bloom_framebuffer; + ctx.bloom_framebuffer = nullptr; + delete ctx.bloom_color_texture; + ctx.bloom_color_texture = nullptr; + + // Delete shadow map framebuffer and its attachments + delete ctx.shadow_map_framebuffer; + ctx.shadow_map_framebuffer = nullptr; + delete ctx.shadow_map_depth_texture; + ctx.shadow_map_depth_texture = nullptr; + + ctx.logger->pop_task(EXIT_SUCCESS); +} + +void change_render_resolution(game::context& ctx, float scale) +{ + ctx.logger->push_task("Changing render resolution"); + + // Update render resolution scale + ctx.render_resolution_scale = scale; + + // Recalculate render resolution + const int2& viewport_dimensions = ctx.app->get_viewport_dimensions(); + ctx.render_resolution = {static_cast(viewport_dimensions.x * ctx.render_resolution_scale + 0.5f), static_cast(viewport_dimensions.y * ctx.render_resolution_scale + 0.5f)}; + + // Resize HDR framebuffer and attachments + 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); + + // Recalculate bloom resolution + int2 bloom_resolution = ctx.render_resolution / 2; + + // Resize bloom framebuffer and attachments + ctx.bloom_framebuffer->resize({bloom_resolution.x, bloom_resolution.y}); + resize_framebuffer_attachment(*ctx.bloom_color_texture, bloom_resolution); + + 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); +} + +} // namespace graphics +} // namespace game diff --git a/src/game/graphics.hpp b/src/game/graphics.hpp new file mode 100644 index 0000000..acce8bb --- /dev/null +++ b/src/game/graphics.hpp @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2021 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_GAME_GRAPHICS_HPP +#define ANTKEEPER_GAME_GRAPHICS_HPP + +#include "game/context.hpp" + +namespace game { +namespace graphics { + +void create_framebuffers(game::context& ctx); +void destroy_framebuffers(game::context& ctx); +void change_render_resolution(game::context& ctx, float scale); + +} // namespace graphics +} // namespace game + +#endif // ANTKEEPER_GAME_GRAPHICS_HPP diff --git a/src/game/menu.hpp b/src/game/menu.hpp index 87c012c..03a5a2b 100644 --- a/src/game/menu.hpp +++ b/src/game/menu.hpp @@ -26,7 +26,7 @@ namespace game { namespace menu { /// Delay, in seconds, to when menu input should be activated. -static constexpr float input_delay = 0.01f; +static constexpr float input_delay = 0.025f; /// RGBA color of active menu items. static constexpr float4 active_color{1.0f, 1.0f, 1.0f, 1.0f}; @@ -35,7 +35,7 @@ static constexpr float4 active_color{1.0f, 1.0f, 1.0f, 1.0f}; static constexpr float4 inactive_color{1.0f, 1.0f, 1.0f, 0.5f}; /// Opacity of the menu background. -static constexpr float bg_opacity = 0.75f; +static constexpr float bg_opacity = 2.0f / 3.0f; /// Padding of the mouseover bounds, as a percentage of the font size. static constexpr float mouseover_padding = 0.1f; diff --git a/src/game/states/boot.cpp b/src/game/states/boot.cpp index 2c88eea..5a7601a 100644 --- a/src/game/states/boot.cpp +++ b/src/game/states/boot.cpp @@ -88,6 +88,7 @@ #include "game/controls.hpp" #include "game/save.hpp" #include "game/menu.hpp" +#include "game/graphics.hpp" #include "utility/timestamp.hpp" #include #include @@ -472,51 +473,8 @@ void setup_rendering(game::context* ctx) // Get rasterizer from application ctx->rasterizer = ctx->app->get_rasterizer(); - // Load render resolution - ctx->render_resolution_scale = 1.0f; - if (ctx->config->contains("render_resolution")) - ctx->render_resolution_scale = (*ctx->config)["render_resolution"].get(); - - // Get default framebuffer - const gl::framebuffer& default_framebuffer = ctx->rasterizer->get_default_framebuffer(); - const auto& viewport_dimensions = default_framebuffer.get_dimensions(); - - // Create HDR framebuffer (32F color, 32F depth) - ctx->framebuffer_hdr_color = new gl::texture_2d(viewport_dimensions[0], viewport_dimensions[1], gl::pixel_type::float_32, gl::pixel_format::rgb); - ctx->framebuffer_hdr_color->set_wrapping(gl::texture_wrapping::extend, gl::texture_wrapping::extend); - ctx->framebuffer_hdr_color->set_filters(gl::texture_min_filter::linear, gl::texture_mag_filter::linear); - ctx->framebuffer_hdr_color->set_max_anisotropy(0.0f); - ctx->framebuffer_hdr_depth = new gl::texture_2d(viewport_dimensions[0], viewport_dimensions[1], gl::pixel_type::float_32, gl::pixel_format::ds); - ctx->framebuffer_hdr_depth->set_wrapping(gl::texture_wrapping::extend, gl::texture_wrapping::extend); - ctx->framebuffer_hdr_depth->set_filters(gl::texture_min_filter::linear, gl::texture_mag_filter::linear); - ctx->framebuffer_hdr_depth->set_max_anisotropy(0.0f); - ctx->framebuffer_hdr = new gl::framebuffer(viewport_dimensions[0], viewport_dimensions[1]); - ctx->framebuffer_hdr->attach(gl::framebuffer_attachment_type::color, ctx->framebuffer_hdr_color); - ctx->framebuffer_hdr->attach(gl::framebuffer_attachment_type::depth, ctx->framebuffer_hdr_depth); - ctx->framebuffer_hdr->attach(gl::framebuffer_attachment_type::stencil, ctx->framebuffer_hdr_depth); - - // Create shadow map framebuffer - int shadow_map_resolution = 4096; - if (ctx->config->contains("shadow_map_resolution")) - { - shadow_map_resolution = (*ctx->config)["shadow_map_resolution"].get(); - } - ctx->shadow_map_depth_texture = new gl::texture_2d(shadow_map_resolution, shadow_map_resolution, gl::pixel_type::float_32, gl::pixel_format::d); - ctx->shadow_map_depth_texture->set_wrapping(gl::texture_wrapping::extend, gl::texture_wrapping::extend); - ctx->shadow_map_depth_texture->set_filters(gl::texture_min_filter::linear, gl::texture_mag_filter::linear); - ctx->shadow_map_depth_texture->set_max_anisotropy(0.0f); - ctx->shadow_map_framebuffer = new gl::framebuffer(shadow_map_resolution, shadow_map_resolution); - ctx->shadow_map_framebuffer->attach(gl::framebuffer_attachment_type::depth, ctx->shadow_map_depth_texture); - - // Create bloom pingpong framebuffers (16F color, no depth) - int bloom_width = viewport_dimensions[0] >> 1; - int bloom_height = viewport_dimensions[1] >> 1; - ctx->bloom_texture = new gl::texture_2d(bloom_width, bloom_height, gl::pixel_type::float_16, gl::pixel_format::rgb); - ctx->bloom_texture->set_wrapping(gl::texture_wrapping::extend, gl::texture_wrapping::extend); - ctx->bloom_texture->set_filters(gl::texture_min_filter::linear, gl::texture_mag_filter::linear); - ctx->bloom_texture->set_max_anisotropy(0.0f); - ctx->framebuffer_bloom = new gl::framebuffer(bloom_width, bloom_height); - ctx->framebuffer_bloom->attach(gl::framebuffer_attachment_type::color, ctx->bloom_texture); + // Create framebuffers + game::graphics::create_framebuffers(*ctx); // Load blue noise texture gl::texture_2d* blue_noise_map = ctx->resource_manager->load("blue-noise.tex"); @@ -526,14 +484,14 @@ void setup_rendering(game::context* ctx) // Setup common render passes { - ctx->common_bloom_pass = new render::bloom_pass(ctx->rasterizer, ctx->framebuffer_bloom, ctx->resource_manager); - ctx->common_bloom_pass->set_source_texture(ctx->framebuffer_hdr_color); + ctx->common_bloom_pass = new render::bloom_pass(ctx->rasterizer, ctx->bloom_framebuffer, ctx->resource_manager); + ctx->common_bloom_pass->set_source_texture(ctx->hdr_color_texture); ctx->common_bloom_pass->set_brightness_threshold(1.0f); ctx->common_bloom_pass->set_blur_iterations(5); ctx->common_final_pass = new render::final_pass(ctx->rasterizer, &ctx->rasterizer->get_default_framebuffer(), ctx->resource_manager); - ctx->common_final_pass->set_color_texture(ctx->framebuffer_hdr_color); - ctx->common_final_pass->set_bloom_texture(ctx->bloom_texture); + ctx->common_final_pass->set_color_texture(ctx->hdr_color_texture); + ctx->common_final_pass->set_bloom_texture(ctx->bloom_color_texture); ctx->common_final_pass->set_blue_noise_texture(blue_noise_map); } @@ -553,12 +511,12 @@ void setup_rendering(game::context* ctx) // Setup underground compositor { - ctx->underground_clear_pass = new render::clear_pass(ctx->rasterizer, ctx->framebuffer_hdr); + ctx->underground_clear_pass = new render::clear_pass(ctx->rasterizer, ctx->hdr_framebuffer); ctx->underground_clear_pass->set_cleared_buffers(true, true, false); ctx->underground_clear_pass->set_clear_color({1, 0, 1, 0}); ctx->underground_clear_pass->set_clear_depth(0.0f); - ctx->underground_material_pass = new render::material_pass(ctx->rasterizer, ctx->framebuffer_hdr, ctx->resource_manager); + ctx->underground_material_pass = new render::material_pass(ctx->rasterizer, ctx->hdr_framebuffer, ctx->resource_manager); ctx->underground_material_pass->set_fallback_material(ctx->fallback_material); ctx->app->get_event_dispatcher()->subscribe(ctx->underground_material_pass); @@ -578,20 +536,20 @@ void setup_rendering(game::context* ctx) ctx->surface_shadow_map_pass = new render::shadow_map_pass(ctx->rasterizer, ctx->shadow_map_framebuffer, ctx->resource_manager); ctx->surface_shadow_map_pass->set_split_scheme_weight(0.75f); - ctx->surface_clear_pass = new render::clear_pass(ctx->rasterizer, ctx->framebuffer_hdr); + ctx->surface_clear_pass = new render::clear_pass(ctx->rasterizer, ctx->hdr_framebuffer); ctx->surface_clear_pass->set_cleared_buffers(true, true, true); ctx->surface_clear_pass->set_clear_depth(0.0f); - ctx->surface_sky_pass = new render::sky_pass(ctx->rasterizer, ctx->framebuffer_hdr, ctx->resource_manager); + ctx->surface_sky_pass = new render::sky_pass(ctx->rasterizer, ctx->hdr_framebuffer, ctx->resource_manager); ctx->app->get_event_dispatcher()->subscribe(ctx->surface_sky_pass); - ctx->surface_material_pass = new render::material_pass(ctx->rasterizer, ctx->framebuffer_hdr, ctx->resource_manager); + ctx->surface_material_pass = new render::material_pass(ctx->rasterizer, ctx->hdr_framebuffer, ctx->resource_manager); ctx->surface_material_pass->set_fallback_material(ctx->fallback_material); ctx->surface_material_pass->shadow_map_pass = ctx->surface_shadow_map_pass; ctx->surface_material_pass->shadow_map = ctx->shadow_map_depth_texture; ctx->app->get_event_dispatcher()->subscribe(ctx->surface_material_pass); - ctx->surface_outline_pass = new render::outline_pass(ctx->rasterizer, ctx->framebuffer_hdr, ctx->resource_manager); + ctx->surface_outline_pass = new render::outline_pass(ctx->rasterizer, ctx->hdr_framebuffer, ctx->resource_manager); ctx->surface_outline_pass->set_outline_width(0.25f); ctx->surface_outline_pass->set_outline_color(float4{1.0f, 1.0f, 1.0f, 1.0f}); @@ -1209,6 +1167,14 @@ void setup_callbacks(game::context* ctx) ctx->underground_scene->update_tweens(); ctx->ui_scene->update_tweens(); + // Process function queue + while (!ctx->function_queue.empty()) + { + ctx->function_queue.front()(); + ctx->function_queue.pop(); + } + + // Advance timeline ctx->timeline->advance(dt); // Update controls @@ -1227,14 +1193,6 @@ void setup_callbacks(game::context* ctx) } ); - - - - - - - - ctx->terrain_system->update(t, dt); //ctx->vegetation_system->update(t, dt); ctx->snapping_system->update(t, dt); @@ -1244,7 +1202,6 @@ void setup_callbacks(game::context* ctx) ctx->behavior_system->update(t, dt); ctx->locomotion_system->update(t, dt); ctx->camera_system->update(t, dt); - ctx->orbit_system->update(t, dt); ctx->blackbody_system->update(t, dt); ctx->atmosphere_system->update(t, dt); @@ -1254,7 +1211,6 @@ void setup_callbacks(game::context* ctx) ctx->painting_system->update(t, dt); ctx->proteome_system->update(t, dt); ctx->animator->animate(dt); - ctx->render_system->update(t, dt); } ); diff --git a/src/game/states/controls-menu.cpp b/src/game/states/controls-menu.cpp index c71b5d9..a18a9b1 100644 --- a/src/game/states/controls-menu.cpp +++ b/src/game/states/controls-menu.cpp @@ -25,7 +25,6 @@ #include "scene/text.hpp" #include "debug/logger.hpp" #include "game/menu.hpp" -#include "animation/timeline.hpp" namespace game { namespace state { @@ -132,10 +131,8 @@ void enter(game::context* ctx) // Set menu back callback ctx->menu_back_callback = select_back_callback; - // Schedule menu control setup - timeline* timeline = ctx->timeline; - float t = timeline->get_position(); - timeline->add_sequence({{t + game::menu::input_delay, std::bind(game::menu::setup_controls, ctx)}}); + // Queue menu control setup + ctx->function_queue.push(std::bind(game::menu::setup_controls, ctx)); // Fade in menu game::menu::fade_in(ctx, nullptr); diff --git a/src/game/states/credits.cpp b/src/game/states/credits.cpp index a017037..bda9bbf 100644 --- a/src/game/states/credits.cpp +++ b/src/game/states/credits.cpp @@ -91,7 +91,7 @@ void enter(game::context* ctx) { auto id = event.get_event_type_id(); if (id != mouse_moved_event::event_type_id && id != mouse_wheel_scrolled_event::event_type_id && id != gamepad_axis_moved_event::event_type_id) - { + { if (ctx->credits_text->get_color()[3] > 0.0f) { ctx->input_listener->set_enabled(false); @@ -101,7 +101,7 @@ void enter(game::context* ctx) next_state.name = "extras_menu"; next_state.enter = std::bind(game::state::extras_menu::enter, ctx); next_state.exit = std::bind(game::state::extras_menu::exit, ctx); - ctx->app->change_state(next_state); + ctx->app->queue_state(next_state); } } } diff --git a/src/game/states/extras-menu.cpp b/src/game/states/extras-menu.cpp index 30f70dd..ef49d48 100644 --- a/src/game/states/extras-menu.cpp +++ b/src/game/states/extras-menu.cpp @@ -25,7 +25,6 @@ #include "debug/logger.hpp" #include "game/fonts.hpp" #include "game/menu.hpp" -#include "animation/timeline.hpp" namespace game { namespace state { @@ -108,10 +107,8 @@ void enter(game::context* ctx) // Set menu back callback ctx->menu_back_callback = select_back_callback; - // Schedule menu control setup - timeline* timeline = ctx->timeline; - float t = timeline->get_position(); - timeline->add_sequence({{t + game::menu::input_delay, std::bind(game::menu::setup_controls, ctx)}}); + // Queue menu control setup + ctx->function_queue.push(std::bind(game::menu::setup_controls, ctx)); // Fade in menu game::menu::fade_in(ctx, nullptr); diff --git a/src/game/states/gamepad-config-menu.cpp b/src/game/states/gamepad-config-menu.cpp index ad46c10..fcf9a3f 100644 --- a/src/game/states/gamepad-config-menu.cpp +++ b/src/game/states/gamepad-config-menu.cpp @@ -25,7 +25,6 @@ #include "resources/resource-manager.hpp" #include "game/menu.hpp" #include "game/controls.hpp" -#include "animation/timeline.hpp" namespace game { namespace state { @@ -261,10 +260,8 @@ static void add_control_item(game::context* ctx, const std::string& control_name ctx->input_listener->set_enabled(false); ctx->input_listener->set_callback(nullptr); - // Schedule re-enabling of menu controls - timeline* timeline = ctx->timeline; - float t = timeline->get_position(); - timeline->add_sequence({{t + game::menu::input_delay, std::bind(game::menu::setup_controls, ctx)}}); + // Queue menu control setup + ctx->function_queue.push(std::bind(game::menu::setup_controls, ctx)); } ); ctx->input_listener->set_enabled(true); @@ -341,10 +338,8 @@ void enter(game::context* ctx) // Set menu back callback ctx->menu_back_callback = select_back_callback; - // Schedule menu control setup - timeline* timeline = ctx->timeline; - float t = timeline->get_position(); - timeline->add_sequence({{t + game::menu::input_delay, std::bind(game::menu::setup_controls, ctx)}}); + // Queue menu control setup + ctx->function_queue.push(std::bind(game::menu::setup_controls, ctx)); // Fade in menu game::menu::fade_in(ctx, nullptr); diff --git a/src/game/states/graphics-menu.cpp b/src/game/states/graphics-menu.cpp index 4982875..626325f 100644 --- a/src/game/states/graphics-menu.cpp +++ b/src/game/states/graphics-menu.cpp @@ -24,29 +24,14 @@ #include "debug/logger.hpp" #include "game/fonts.hpp" #include "game/menu.hpp" +#include "game/graphics.hpp" #include "animation/timeline.hpp" namespace game { namespace state { namespace graphics_menu { -static void update_value_text_content(game::context* ctx) -{ - 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 std::string string_on = (*ctx->strings)["on"]; - const std::string string_off = (*ctx->strings)["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(std::round(resolution * 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[3])->set_content(std::to_string(static_cast(std::round(font_size * 100.0f))) + "%"); - std::get<1>(ctx->menu_item_texts[4])->set_content((dyslexia_font) ? string_on : string_off); -} +static void update_value_text_content(game::context* ctx); void enter(game::context* ctx) { @@ -118,14 +103,18 @@ void enter(game::context* ctx) { // Increase resolution if (ctx->controls["menu_modifier"]->is_active()) - ctx->render_resolution_scale += 0.01f; + ctx->render_resolution_scale += 0.05f; else - ctx->render_resolution_scale += 0.1f; + ctx->render_resolution_scale += 0.25f; // Limit resolution if (ctx->render_resolution_scale > 2.0f) ctx->render_resolution_scale = 2.0f; + // Resize framebuffers + game::graphics::change_render_resolution(*ctx, ctx->render_resolution_scale); + + // Update text update_value_text_content(ctx); game::menu::align_text(ctx); game::menu::update_text_tweens(ctx); @@ -138,14 +127,18 @@ void enter(game::context* ctx) { // Increase resolution if (ctx->controls["menu_modifier"]->is_active()) - ctx->render_resolution_scale -= 0.01f; + ctx->render_resolution_scale -= 0.05f; else - ctx->render_resolution_scale -= 0.1f; + ctx->render_resolution_scale -= 0.25f; // Limit resolution - if (ctx->render_resolution_scale < 0.1f) - ctx->render_resolution_scale = 0.1f; + if (ctx->render_resolution_scale < 0.25f) + ctx->render_resolution_scale = 0.25f; + + // Resize framebuffers + game::graphics::change_render_resolution(*ctx, ctx->render_resolution_scale); + // Update text update_value_text_content(ctx); game::menu::align_text(ctx); game::menu::update_text_tweens(ctx); @@ -313,10 +306,8 @@ void enter(game::context* ctx) // Set menu back callback ctx->menu_back_callback = select_back_callback; - // Schedule menu control setup - timeline* timeline = ctx->timeline; - float t = timeline->get_position(); - timeline->add_sequence({{t + game::menu::input_delay, std::bind(game::menu::setup_controls, ctx)}}); + // Queue menu control setup + ctx->function_queue.push(std::bind(game::menu::setup_controls, ctx)); // Fade in menu game::menu::fade_in(ctx, nullptr); @@ -332,6 +323,24 @@ void exit(game::context* ctx) game::menu::delete_text(ctx); } +static void update_value_text_content(game::context* ctx) +{ + 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 std::string string_on = (*ctx->strings)["on"]; + const std::string string_off = (*ctx->strings)["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(std::round(resolution * 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[3])->set_content(std::to_string(static_cast(std::round(font_size * 100.0f))) + "%"); + std::get<1>(ctx->menu_item_texts[4])->set_content((dyslexia_font) ? string_on : string_off); +} + } // namespace graphics_menu } // namespace state } // namespace game diff --git a/src/game/states/keyboard-config-menu.cpp b/src/game/states/keyboard-config-menu.cpp index f0ec7ff..a496b5b 100644 --- a/src/game/states/keyboard-config-menu.cpp +++ b/src/game/states/keyboard-config-menu.cpp @@ -25,7 +25,6 @@ #include "resources/resource-manager.hpp" #include "game/menu.hpp" #include "game/controls.hpp" -#include "animation/timeline.hpp" namespace game { namespace state { @@ -216,10 +215,8 @@ static void add_control_item(game::context* ctx, const std::string& control_name ctx->input_listener->set_enabled(false); ctx->input_listener->set_callback(nullptr); - // Schedule re-enabling of menu controls - timeline* timeline = ctx->timeline; - float t = timeline->get_position(); - timeline->add_sequence({{t + game::menu::input_delay, std::bind(game::menu::setup_controls, ctx)}}); + // Queue menu control setup + ctx->function_queue.push(std::bind(game::menu::setup_controls, ctx)); } ); ctx->input_listener->set_enabled(true); @@ -296,10 +293,8 @@ void enter(game::context* ctx) // Set menu back callback ctx->menu_back_callback = select_back_callback; - // Schedule menu control setup - timeline* timeline = ctx->timeline; - float t = timeline->get_position(); - timeline->add_sequence({{t + game::menu::input_delay, std::bind(game::menu::setup_controls, ctx)}}); + // Queue menu control setup + ctx->function_queue.push(std::bind(game::menu::setup_controls, ctx)); // Fade in menu game::menu::fade_in(ctx, nullptr); diff --git a/src/game/states/language-menu.cpp b/src/game/states/language-menu.cpp index 31e6c78..75423f6 100644 --- a/src/game/states/language-menu.cpp +++ b/src/game/states/language-menu.cpp @@ -24,7 +24,6 @@ #include "debug/logger.hpp" #include "game/fonts.hpp" #include "game/menu.hpp" -#include "animation/timeline.hpp" namespace game { namespace state { @@ -167,10 +166,8 @@ void enter(game::context* ctx) // Set menu back callback ctx->menu_back_callback = select_back_callback; - // Schedule menu control setup - timeline* timeline = ctx->timeline; - float t = timeline->get_position(); - timeline->add_sequence({{t + game::menu::input_delay, std::bind(game::menu::setup_controls, ctx)}}); + // Queue menu control setup + ctx->function_queue.push(std::bind(game::menu::setup_controls, ctx)); // Fade in menu game::menu::fade_in(ctx, nullptr); diff --git a/src/game/states/main-menu.cpp b/src/game/states/main-menu.cpp index d5ecd05..15b8097 100644 --- a/src/game/states/main-menu.cpp +++ b/src/game/states/main-menu.cpp @@ -75,7 +75,7 @@ void enter(game::context* ctx, bool fade_in) const auto& title_aabb = static_cast&>(ctx->title_text->get_local_bounds()); float title_w = title_aabb.max_point.x - title_aabb.min_point.x; float title_h = title_aabb.max_point.y - title_aabb.min_point.y; - ctx->title_text->set_translation({std::round(-title_w * 0.5f), std::round(-title_h * 0.5f + (std::get<1>(ctx->app->get_viewport_dimensions()) / 3.0f) / 2.0f), 0.0f}); + ctx->title_text->set_translation({std::round(-title_w * 0.5f), std::round(-title_h * 0.5f + (ctx->app->get_viewport_dimensions().y / 3.0f) / 2.0f), 0.0f}); ctx->title_text->update_tweens(); // Add title text to UI @@ -119,7 +119,7 @@ void enter(game::context* ctx, bool fade_in) game::menu::update_text_color(ctx); game::menu::update_text_font(ctx); - game::menu::align_text(ctx, true, false, (-std::get<1>(ctx->app->get_viewport_dimensions()) / 3.0f) / 2.0f); + game::menu::align_text(ctx, true, false, (-ctx->app->get_viewport_dimensions().y / 3.0f) / 2.0f); game::menu::update_text_tweens(ctx); game::menu::add_text_to_ui(ctx); game::menu::setup_animations(ctx); @@ -221,10 +221,8 @@ void enter(game::context* ctx, bool fade_in) // Set menu back callback ctx->menu_back_callback = select_quit_callback; - // Schedule menu control setup - timeline* timeline = ctx->timeline; - float t = timeline->get_position(); - timeline->add_sequence({{t + game::menu::input_delay, std::bind(game::menu::setup_controls, ctx)}}); + // Queue menu control setup + ctx->function_queue.push(std::bind(game::menu::setup_controls, ctx)); if (fade_in) { diff --git a/src/game/states/nuptial-flight.cpp b/src/game/states/nuptial-flight.cpp index 8f1aa8d..4f69728 100644 --- a/src/game/states/nuptial-flight.cpp +++ b/src/game/states/nuptial-flight.cpp @@ -37,7 +37,9 @@ #include "game/world.hpp" #include "application.hpp" #include "render/passes/clear-pass.hpp" -#include "animation/timeline.hpp" +#include +#include +#include "state-machine.hpp" namespace game { namespace state { @@ -113,15 +115,12 @@ void enter(game::context* ctx) ctx->surface_scene->update_tweens(); */ - // Schedule control setup - timeline* timeline = ctx->timeline; - float t = timeline->get_position(); - timeline->add_sequence({{t + 0.01f, std::bind(enable_controls, ctx)}}); - - // Schedule fade in + // Queue fade in ctx->fade_transition_color->set_value({1, 1, 1}); - ctx->fade_transition->transition(5.0f, true, math::lerp); - //timeline->add_sequence({{t + 10.0f, [ctx](){ctx->fade_transition->transition(5.0f, true, math::lerp);}}}); + ctx->function_queue.push(std::bind(&screen_transition::transition, ctx->fade_transition, 5.0f, true, math::lerp, true)); + + // Queue control setup + ctx->function_queue.push(std::bind(enable_controls, ctx)); } void exit(game::context* ctx) @@ -219,9 +218,6 @@ void setup_camera(game::context* ctx) void enable_controls(game::context* ctx) { - /// @WARNING!!! SOMETIMES THIS CALLBACK IS SKIPPED BY THE TIMELINE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - ctx->logger->log("ENABLING CONTROLS"); - // Get camera entities entity::id camera_eid = ctx->entities["surface_cam"]; entity::id target_eid = ctx->entities["surface_cam_target"]; diff --git a/src/game/states/options-menu.cpp b/src/game/states/options-menu.cpp index 3b15bd8..c2ae8f8 100644 --- a/src/game/states/options-menu.cpp +++ b/src/game/states/options-menu.cpp @@ -29,7 +29,6 @@ #include "animation/ease.hpp" #include "animation/animation.hpp" #include "animation/animator.hpp" -#include "animation/timeline.hpp" #include "application.hpp" #include "scene/text.hpp" @@ -190,10 +189,8 @@ void enter(game::context* ctx) // Set menu back callback ctx->menu_back_callback = select_back_callback; - // Schedule menu control setup - timeline* timeline = ctx->timeline; - float t = timeline->get_position(); - timeline->add_sequence({{t + game::menu::input_delay, std::bind(game::menu::setup_controls, ctx)}}); + // Queue menu control setup + ctx->function_queue.push(std::bind(game::menu::setup_controls, ctx)); // Fade in menu game::menu::fade_in(ctx, nullptr); diff --git a/src/game/states/pause-menu.cpp b/src/game/states/pause-menu.cpp index 5430243..98a81c0 100644 --- a/src/game/states/pause-menu.cpp +++ b/src/game/states/pause-menu.cpp @@ -24,7 +24,6 @@ #include "animation/ease.hpp" #include "animation/animation.hpp" #include "animation/animator.hpp" -#include "animation/timeline.hpp" #include "application.hpp" #include "scene/text.hpp" @@ -83,7 +82,7 @@ void enter(game::context* ctx) auto select_options_callback = [ctx]() { // Disable unpause control - //ctx->controls["pause"]->set_activated_callback(nullptr); + ctx->controls["pause"]->set_activated_callback(nullptr); // Disable menu controls game::menu::clear_controls(ctx); @@ -157,12 +156,9 @@ void enter(game::context* ctx) // Set menu back callback ctx->menu_back_callback = select_resume_callback; - // Schedule control setup - timeline* timeline = ctx->timeline; - float t = timeline->get_position(); - timeline->add_sequence - ({{ - t + game::menu::input_delay, + // Queue control setup + ctx->function_queue.push + ( [ctx, select_resume_callback]() { // Enable unpause control @@ -171,7 +167,7 @@ void enter(game::context* ctx) // Enable menu controls game::menu::setup_controls(ctx); } - }}); + ); // Fade in menu and menu BG game::menu::fade_in(ctx, nullptr); diff --git a/src/game/states/splash.cpp b/src/game/states/splash.cpp index 8019c34..afe599a 100644 --- a/src/game/states/splash.cpp +++ b/src/game/states/splash.cpp @@ -23,7 +23,6 @@ #include "animation/animation.hpp" #include "animation/animator.hpp" #include "animation/ease.hpp" -#include "animation/timeline.hpp" #include "application.hpp" #include "render/passes/clear-pass.hpp" @@ -126,7 +125,7 @@ void enter(game::context* ctx) next_state.name = "main_menu"; next_state.enter = std::bind(game::state::main_menu::enter, ctx, true); next_state.exit = std::bind(game::state::main_menu::exit, ctx); - ctx->app->change_state(next_state); + ctx->app->queue_state(next_state); } } );