Browse Source

Make input manager handle quit events. Improve command-line option parsing

master
C. J. Howard 1 year ago
parent
commit
1f7b88f1cf
7 changed files with 139 additions and 150 deletions
  1. +8
    -2
      src/app/sdl/sdl-input-manager.cpp
  2. +2
    -2
      src/app/sdl/sdl-window-manager.cpp
  3. +8
    -6
      src/event/queue.hpp
  4. +32
    -19
      src/game/context.hpp
  5. +85
    -26
      src/game/state/boot.cpp
  6. +2
    -11
      src/game/state/boot.hpp
  7. +2
    -84
      src/input/event.hpp

+ 8
- 2
src/app/sdl/sdl-input-manager.cpp View File

@ -82,9 +82,15 @@ void sdl_input_manager::update()
throw std::runtime_error("Failed to peep SDL events");
}
if (event.type == SDL_QUIT)
switch (event.type)
{
//...
case SDL_QUIT:
debug::log::debug("Application quit requested");
this->event_queue.enqueue<input::event::application_quit>({});
break;
default:
break;
}
}

+ 2
- 2
src/app/sdl/sdl-window-manager.cpp View File

@ -154,7 +154,7 @@ void sdl_window_manager::update()
// Update window state
window->size = {event.window.data1, event.window.data2};
const auto window_flags = SDL_GetWindowFlags(internal_window);
if (!(window_flags & SDL_WINDOW_MAXIMIZED) && !(window_flags & SDL_WINDOW_FULLSCREEN))
if (!(window_flags & SDL_WINDOW_MAXIMIZED) && !(window_flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP)))
{
window->windowed_size = window->size;
}
@ -178,7 +178,7 @@ void sdl_window_manager::update()
// Update window state
window->position = {event.window.data1, event.window.data2};
const auto window_flags = SDL_GetWindowFlags(internal_window);
if (!(window_flags & SDL_WINDOW_MAXIMIZED) && !(window_flags & SDL_WINDOW_FULLSCREEN))
if (!(window_flags & SDL_WINDOW_MAXIMIZED) && !(window_flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP)))
{
window->windowed_position = window->position;
}

+ 8
- 6
src/event/queue.hpp View File

@ -33,7 +33,7 @@
namespace event {
/**
* Collects messages from publishers to be distributed to subscribers when desired.
* Collects messages from publishers to be forwarded to subscribers when desired.
*/
class queue
{
@ -46,6 +46,8 @@ public:
* @param subscriber Function object to subscribe.
*
* @return Shared subscription object which will unsubscribe the subscriber on destruction.
*
* @TODO This function should be available through an interface class which does not expose the queue's message-sending functions, such as event::channel for publishers.
*/
template <class T>
[[nodiscard]] std::shared_ptr<subscription> subscribe(subscriber<T>&& subscriber)
@ -81,13 +83,13 @@ public:
(
[this, message]()
{
this->distribute<T>(message);
this->forward<T>(message);
}
);
}
/**
* Distributes queued messages in FIFO order to subscribers.
* Forwards queued messages, in FIFO order, to subscribers.
*/
void flush()
{
@ -116,14 +118,14 @@ public:
private:
/**
* Distributes a message.
* Forwards a message to subscribers of the message type.
*
* @tparam T Message type.
*
* @param message Message to distribute.
* @param message Message to forward.
*/
template <class T>
void distribute(const T& message) const
void forward(const T& message) const
{
// For each subscriber of the given message type
const auto range = subscribers.equal_range(std::type_index(typeid(T)));

+ 32
- 19
src/game/context.hpp View File

@ -122,17 +122,46 @@ namespace game {
/// Container for data shared between game states.
struct context
{
// Configuration
// Command-line options
std::optional<bool> option_continue;
std::optional<std::string> option_data;
std::optional<bool> option_fullscreen;
std::optional<bool> option_new_game;
std::optional<bool> option_quick_start;
std::optional<bool> option_reset;
std::optional<bool> option_v_sync;
std::optional<bool> option_windowed;
// Resource management and paths
resource_manager* resource_manager;
// Persistent settings
dict<std::uint32_t>* settings;
// Window creation, events, and management
// Window management and event handling
app::window_manager* window_manager;
app::window* window;
bool closed;
std::shared_ptr<::event::subscription> window_closed_subscription;
// Input devices and events
// Input management and event handling
app::input_manager* input_manager;
std::shared_ptr<::event::subscription> application_quit_subscription;
// Localization and internationalization
std::uint16_t language_index;
std::uint16_t language_count;
i18n::string_table* string_table;
std::vector<i18n::string_map> string_maps;
// Fonts
std::unordered_map<std::string, type::typeface*> typefaces;
type::bitmap_font debug_font;
type::bitmap_font menu_font;
type::bitmap_font title_font;
render::material debug_font_material;
render::material menu_font_material;
render::material title_font_material;
// Hierarchichal state machine
hsm::state_machine<game::state::base> state_machine;
@ -180,22 +209,6 @@ struct context
std::filesystem::path controls_path;
std::filesystem::path data_package_path;
// Resources
resource_manager* resource_manager;
// Localization
std::uint16_t language_index;
std::uint16_t language_count;
i18n::string_table* string_table;
std::vector<i18n::string_map> string_maps;
std::unordered_map<std::string, type::typeface*> typefaces;
type::bitmap_font debug_font;
type::bitmap_font menu_font;
type::bitmap_font title_font;
render::material debug_font_material;
render::material menu_font_material;
render::material title_font_material;
// Framebuffers
gl::texture_2d* hdr_color_texture;
gl::texture_2d* hdr_depth_texture;

+ 85
- 26
src/game/state/boot.cpp View File

@ -89,7 +89,6 @@
#include "utility/dict.hpp"
#include "utility/hash/fnv1a.hpp"
#include <algorithm>
#include <cxxopts.hpp>
#include <entt/entt.hpp>
#include <execution>
#include <filesystem>
@ -97,6 +96,10 @@
#include <string>
#include <vector>
// Prevent cxxopts from using RTTI
#define CXXOPTS_NO_RTTI
#include <cxxopts.hpp>
using namespace hash::literals;
namespace game {
@ -108,7 +111,7 @@ boot::boot(game::context& ctx, int argc, char** argv):
// Boot process
debug::log::trace("Booting up...");
parse_arguments(argc, argv);
parse_options(argc, argv);
setup_resources();
load_settings();
setup_window();
@ -153,8 +156,11 @@ boot::~boot()
(*ctx.settings)["maximized"_fnv1a32] = maximized;
(*ctx.settings)["fullscreen"_fnv1a32] = fullscreen;
// Destruct window
delete ctx.window;
// Save settings
ctx.resource_manager->save<dict<std::uint32_t>>(ctx.settings, "settings.cfg");
ctx.resource_manager->save(ctx.settings, "settings.cfg");
// Destruct input and window managers
delete ctx.input_manager;
@ -166,61 +172,78 @@ boot::~boot()
debug::log::trace("Boot down complete");
}
void boot::parse_arguments(int argc, char** argv)
void boot::parse_options(int argc, char** argv)
{
debug::log::trace("Parsing {} command line arguments...", argc);
debug::log::trace("Parsing command-line options...");
// Parse command-line options with cxxopts
try
{
cxxopts::Options options("Antkeeper", "Ant colony simulation game");
cxxopts::Options options(config::application_name, "Ant colony simulation game");
options.add_options()
("c,continue", "Continues from the last save")
("d,data", "Sets the data package path", cxxopts::value<std::string>())
("f,fullscreen", "Starts in fullscreen mode")
("n,new-game", "Starts a new game")
("q,quick-start", "Skips to the main menu")
("r,reset", "Restores all settings to default")
("v,v_sync", "Enables or disables v-sync", cxxopts::value<int>())
("w,window", "Starts in window mode");
("r,reset", "Resets all settings to default")
("v,vsync", "Enables or disables v-sync", cxxopts::value<int>())
("w,windowed", "Starts in windowed mode");
auto result = options.parse(argc, argv);
// --continue
if (result.count("continue"))
option_continue = true;
{
ctx.option_continue = true;
}
// --data
if (result.count("data"))
option_data = result["data"].as<std::string>();
{
ctx.option_data = result["data"].as<std::string>();
}
// --fullscreen
if (result.count("fullscreen"))
option_fullscreen = true;
{
ctx.option_fullscreen = true;
}
// --new-game
if (result.count("new-game"))
option_new_game = true;
{
ctx.option_new_game = true;
}
// --quick-start
if (result.count("quick-start"))
option_quick_start = true;
{
ctx.option_quick_start = true;
}
// --reset
if (result.count("reset"))
option_reset = true;
{
ctx.option_reset = true;
}
// --v_sync
if (result.count("v_sync"))
option_v_sync = (result["v_sync"].as<int>()) ? true : false;
if (result.count("vsync"))
{
ctx.option_v_sync = result["vsync"].as<int>();
}
// --window
if (result.count("window"))
option_windowed = true;
if (result.count("windowed"))
{
ctx.option_windowed = true;
}
debug::log::trace("Parsed {} command line arguments", argc);
debug::log::info("Parsed {} command-line options", argc);
}
catch (const std::exception& e)
{
debug::log::warning("Exception caught while parsing command line arguments: {}", e.what());
debug::log::error("An error occurred while parsing command-line options: {}", e.what());
}
}
@ -287,9 +310,9 @@ void boot::setup_resources()
}
// Determine data package path
if (option_data.has_value())
if (ctx.option_data)
{
ctx.data_package_path = std::filesystem::path(option_data.value());
ctx.data_package_path = std::filesystem::path(ctx.option_data.value());
if (ctx.data_package_path.is_relative())
ctx.data_package_path = ctx.data_path / ctx.data_package_path;
}
@ -318,11 +341,21 @@ void boot::setup_resources()
void boot::load_settings()
{
ctx.settings = ctx.resource_manager->load<dict<std::uint32_t>>("settings.cfg");
if (!ctx.settings)
if (ctx.option_reset)
{
debug::log::info("Settings not found");
// Command-line reset option found, reset settings
ctx.settings = new dict<std::uint32_t>();
ctx.resource_manager->save(ctx.settings, "settings.cfg");
debug::log::info("Settings reset");
}
else
{
ctx.settings = ctx.resource_manager->load<dict<std::uint32_t>>("settings.cfg");
if (!ctx.settings)
{
debug::log::info("Settings not found");
ctx.settings = new dict<std::uint32_t>();
}
}
}
@ -370,6 +403,23 @@ void boot::setup_window()
window_y = usable_bounds_center.y() - window_h / 2;
}
// Handle window-related command-line options
if (ctx.option_windowed)
{
// Start in windowed mode
maximized = false;
fullscreen = false;
}
if (ctx.option_fullscreen)
{
// Start in fullscreen mode
fullscreen = true;
}
if (ctx.option_v_sync)
{
v_sync = ctx.option_v_sync.value();
}
// Construct window
ctx.window = ctx.window_manager->create_window
(
@ -398,6 +448,15 @@ void boot::setup_input()
{
// Construct input manager
ctx.input_manager = app::input_manager::instance();
// Setup application quit callback
ctx.application_quit_subscription = ctx.input_manager->get_event_queue().subscribe<input::event::application_quit>
(
[&](const auto& event)
{
ctx.closed = true;
}
);
}
void boot::load_strings()

+ 2
- 11
src/game/state/boot.hpp View File

@ -48,7 +48,7 @@ public:
virtual ~boot();
private:
void parse_arguments(int argc, char** argv);
void parse_options(int argc, char** argv);
void setup_resources();
void load_settings();
void setup_window();
@ -64,19 +64,10 @@ private:
void setup_ui();
void setup_debugging();
void setup_loop();
void loop();
void shutdown_audio();
// Command line options
std::optional<bool> option_continue;
std::optional<std::string> option_data;
std::optional<bool> option_fullscreen;
std::optional<bool> option_new_game;
std::optional<bool> option_quick_start;
std::optional<bool> option_reset;
std::optional<int> option_v_sync;
std::optional<bool> option_windowed;
};
} // namespace state

+ 2
- 84
src/input/event.hpp View File

@ -237,91 +237,9 @@ struct mouse_scrolled
};
/**
* Event generated when a window has been requested to close.
* Event generated when the application has been requested to quit.
*/
struct window_closed
{
/// Pointer to the window that has been requested to close.
void* window;
};
/**
* Event generated when a window has gained or lost focus.
*/
struct window_focus_changed
{
/// Pointer to the window that has gained or lost focus.
void* window;
/// `true` if the window is in focus, `false` otherwise.
bool in_focus;
};
/**
* Event generated when a window has been moved.
*/
struct window_moved
{
/// Pointer to the window that has been moved.
void* window;
/// Position of the window, in pixels.
math::vector<std::int32_t, 2> position;
/// `true` if the window is maximized, `false` otherwise.
bool maximized;
/// `true` if the window is fullscreen, `false` otherwise.
bool fullscreen;
};
/**
* Event generated when a window has been maximized.
*/
struct window_maximized
{
/// Pointer to the window that has been maximized.
void* window;
};
/**
* Event generated when a window has been minimized.
*/
struct window_minimized
{
/// Pointer to the window that has been minimized.
void* window;
};
/**
* Event generated when a window has been restored.
*/
struct window_restored
{
/// Pointer to the window that has been restored.
void* window;
};
/**
* Event generated when a window has been resized.
*/
struct window_resized
{
/// Pointer to the window that has been resized.
void* window;
/// Window size, in display units.
math::vector<std::int32_t, 2> size;
/// `true` if the window is maximized, `false` otherwise.
bool maximized;
/// `true` if the window is fullscreen, `false` otherwise.
bool fullscreen;
/// Window viewport size, in pixels.
math::vector<std::int32_t, 2> viewport_size;
};
struct application_quit {};
} // namespace event
} // namespace input

Loading…
Cancel
Save