@ -0,0 +1,54 @@ | |||||
/* | |||||
* 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_GAME_STATE_BASE_HPP | |||||
#define ANTKEEPER_GAME_STATE_BASE_HPP | |||||
namespace game { | |||||
struct context; | |||||
namespace state { | |||||
/** | |||||
* Abstract base class for game states. | |||||
*/ | |||||
class base | |||||
{ | |||||
public: | |||||
/** | |||||
* Constructs a game state. | |||||
* | |||||
* @param ctx Reference to the game context on which this state will operate. | |||||
*/ | |||||
base(game::context& ctx); | |||||
/** | |||||
* Destructs a game state. | |||||
*/ | |||||
virtual ~base() = 0; | |||||
protected: | |||||
game::context& ctx; | |||||
}; | |||||
} // namespace state | |||||
} // namespace game | |||||
#endif // ANTKEEPER_GAME_STATE_BASE_HPP |
@ -0,0 +1,68 @@ | |||||
/* | |||||
* 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_GAME_STATE_BOOT_HPP | |||||
#define ANTKEEPER_GAME_STATE_BOOT_HPP | |||||
#include "game/state/base.hpp" | |||||
#include "game/context.hpp" | |||||
#include <optional> | |||||
namespace game { | |||||
namespace state { | |||||
class boot: public game::state::base | |||||
{ | |||||
public: | |||||
boot(game::context& ctx, int argc, char** argv); | |||||
virtual ~boot(); | |||||
private: | |||||
void parse_options(int argc, char** argv); | |||||
void setup_resources(); | |||||
void load_config(); | |||||
void load_strings(); | |||||
void setup_window(); | |||||
void setup_rendering(); | |||||
void setup_sound(); | |||||
void setup_scenes(); | |||||
void setup_animation(); | |||||
void setup_entities(); | |||||
void setup_systems(); | |||||
void setup_controls(); | |||||
void setup_ui(); | |||||
void setup_debugging(); | |||||
void setup_loop(); | |||||
void loop(); | |||||
// 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 | |||||
} // namespace game | |||||
#endif // ANTKEEPER_GAME_STATE_BOOT_HPP |
@ -0,0 +1,143 @@ | |||||
/* | |||||
* 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "game/state/credits.hpp" | |||||
#include "game/state/extras-menu.hpp" | |||||
#include "game/context.hpp" | |||||
#include "animation/ease.hpp" | |||||
#include "animation/animation.hpp" | |||||
#include "animation/animator.hpp" | |||||
#include "application.hpp" | |||||
#include "scene/text.hpp" | |||||
#include "debug/logger.hpp" | |||||
namespace game { | |||||
namespace state { | |||||
credits::credits(game::context& ctx): | |||||
game::state::base(ctx) | |||||
{ | |||||
ctx.logger->push_task("Entering credits state"); | |||||
// Construct credits text | |||||
ctx.credits_text = new scene::text(); | |||||
ctx.credits_text->set_material(&ctx.menu_font_material); | |||||
ctx.credits_text->set_font(&ctx.menu_font); | |||||
ctx.credits_text->set_color({1.0f, 1.0f, 1.0f, 0.0f}); | |||||
ctx.credits_text->set_content((*ctx.strings)["credits"]); | |||||
// Align credits text | |||||
const auto& credits_aabb = static_cast<const geom::aabb<float>&>(ctx.credits_text->get_local_bounds()); | |||||
float credits_w = credits_aabb.max_point.x - credits_aabb.min_point.x; | |||||
float credits_h = credits_aabb.max_point.y - credits_aabb.min_point.y; | |||||
ctx.credits_text->set_translation({std::round(-credits_w * 0.5f), std::round(-credits_h * 0.5f), 0.0f}); | |||||
// Load animation timing configuration | |||||
double credits_fade_in_duration = 0.0; | |||||
double credits_scroll_duration = 0.0; | |||||
if (ctx.config->contains("credits_fade_in_duration")) | |||||
credits_fade_in_duration = (*ctx.config)["credits_fade_in_duration"].get<double>(); | |||||
if (ctx.config->contains("credits_scroll_duration")) | |||||
credits_scroll_duration = (*ctx.config)["credits_scroll_duration"].get<double>(); | |||||
auto set_credits_opacity = [&ctx](int channel, const float& opacity) | |||||
{ | |||||
ctx.credits_text->set_color({1.0f, 1.0f, 1.0f, opacity}); | |||||
}; | |||||
// Build credits fade in animation | |||||
ctx.credits_fade_in_animation = new animation<float>(); | |||||
animation_channel<float>* credits_fade_in_opacity_channel = ctx.credits_fade_in_animation->add_channel(0); | |||||
ctx.credits_fade_in_animation->set_interpolator(ease<float>::in_quad); | |||||
credits_fade_in_opacity_channel->insert_keyframe({0.0, 0.0f}); | |||||
credits_fade_in_opacity_channel->insert_keyframe({credits_fade_in_duration, 1.0f}); | |||||
ctx.credits_fade_in_animation->set_frame_callback(set_credits_opacity); | |||||
// Build credits scroll in animation | |||||
ctx.credits_scroll_animation = new animation<float>(); | |||||
// Trigger credits scroll animation after credits fade in animation ends | |||||
ctx.credits_fade_in_animation->set_end_callback | |||||
( | |||||
[&ctx]() | |||||
{ | |||||
ctx.credits_scroll_animation->play(); | |||||
} | |||||
); | |||||
// Add credits animations to animator | |||||
ctx.animator->add_animation(ctx.credits_fade_in_animation); | |||||
ctx.animator->add_animation(ctx.credits_scroll_animation); | |||||
// Start credits fade in animation | |||||
ctx.credits_fade_in_animation->play(); | |||||
// Set up credits skipper | |||||
ctx.input_listener->set_callback | |||||
( | |||||
[&ctx](const event_base& event) | |||||
{ | |||||
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); | |||||
// Change state | |||||
ctx.state_machine.pop(); | |||||
ctx.state_machine.emplace(new game::state::extras_menu(ctx)); | |||||
} | |||||
} | |||||
} | |||||
); | |||||
ctx.input_listener->set_enabled(true); | |||||
ctx.ui_scene->add_object(ctx.credits_text); | |||||
ctx.credits_text->update_tweens(); | |||||
ctx.logger->pop_task(EXIT_SUCCESS); | |||||
} | |||||
credits::~credits() | |||||
{ | |||||
ctx.logger->push_task("Exiting credits state"); | |||||
// Disable credits skipper | |||||
ctx.input_listener->set_enabled(false); | |||||
ctx.input_listener->set_callback(nullptr); | |||||
// Destruct credits text | |||||
ctx.ui_scene->remove_object(ctx.credits_text); | |||||
delete ctx.credits_text; | |||||
ctx.credits_text = nullptr; | |||||
// Destruct credits animations | |||||
ctx.animator->remove_animation(ctx.credits_fade_in_animation); | |||||
ctx.animator->remove_animation(ctx.credits_scroll_animation); | |||||
delete ctx.credits_fade_in_animation; | |||||
delete ctx.credits_scroll_animation; | |||||
ctx.credits_fade_in_animation = nullptr; | |||||
ctx.credits_scroll_animation = nullptr; | |||||
ctx.logger->pop_task(EXIT_SUCCESS); | |||||
} | |||||
} // namespace state | |||||
} // namespace game |
@ -0,0 +1,357 @@ | |||||
/* | |||||
* 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "game/state/graphics-menu.hpp" | |||||
#include "game/state/options-menu.hpp" | |||||
#include "application.hpp" | |||||
#include "scene/text.hpp" | |||||
#include "debug/logger.hpp" | |||||
#include "game/fonts.hpp" | |||||
#include "game/menu.hpp" | |||||
#include "game/graphics.hpp" | |||||
#include "animation/timeline.hpp" | |||||
namespace game { | |||||
namespace state { | |||||
static void update_value_text_content(game::context* ctx); | |||||
graphics_menu::graphics_menu(game::context& ctx): | |||||
game::state::base(ctx) | |||||
{ | |||||
ctx.logger->push_task("Entering graphics menu state"); | |||||
// Construct menu item texts | |||||
scene::text* fullscreen_name_text = new scene::text(); | |||||
scene::text* fullscreen_value_text = new scene::text(); | |||||
scene::text* resolution_name_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_value_text = new scene::text(); | |||||
scene::text* font_size_name_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_value_text = new scene::text(); | |||||
scene::text* back_text = new scene::text(); | |||||
// Build list of menu item texts | |||||
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({v_sync_name_text, v_sync_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({back_text, nullptr}); | |||||
// Set content of menu item texts | |||||
fullscreen_name_text->set_content((*ctx.strings)["graphics_menu_fullscreen"]); | |||||
resolution_name_text->set_content((*ctx.strings)["graphics_menu_resolution"]); | |||||
v_sync_name_text->set_content((*ctx.strings)["graphics_menu_v_sync"]); | |||||
font_size_name_text->set_content((*ctx.strings)["graphics_menu_font_size"]); | |||||
dyslexia_font_name_text->set_content((*ctx.strings)["graphics_menu_dyslexia_font"]); | |||||
back_text->set_content((*ctx.strings)["back"]); | |||||
update_value_text_content(); | |||||
// Init menu item index | |||||
game::menu::init_menu_item_index(ctx, "graphics"); | |||||
game::menu::update_text_color(ctx); | |||||
game::menu::update_text_font(ctx); | |||||
game::menu::align_text(ctx); | |||||
game::menu::update_text_tweens(ctx); | |||||
game::menu::add_text_to_ui(ctx); | |||||
game::menu::setup_animations(ctx); | |||||
// Construct menu item callbacks | |||||
auto toggle_fullscreen_callback = [this, &ctx]() | |||||
{ | |||||
bool fullscreen = !ctx.app->is_fullscreen(); | |||||
ctx.app->set_fullscreen(fullscreen); | |||||
if (!fullscreen) | |||||
{ | |||||
int2 resolution; | |||||
resolution.x = (*ctx.config)["windowed_resolution"][0].get<int>(); | |||||
resolution.y = (*ctx.config)["windowed_resolution"][1].get<int>(); | |||||
ctx.app->resize_window(resolution.x, resolution.y); | |||||
} | |||||
this->update_value_text_content(); | |||||
game::menu::align_text(ctx); | |||||
game::menu::update_text_tweens(ctx); | |||||
// Save display mode config | |||||
(*ctx.config)["fullscreen"] = fullscreen; | |||||
}; | |||||
auto increase_resolution_callback = [this, &ctx]() | |||||
{ | |||||
// Increase resolution | |||||
if (ctx.controls["menu_modifier"]->is_active()) | |||||
ctx.render_resolution_scale += 0.05f; | |||||
else | |||||
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 | |||||
this->update_value_text_content(); | |||||
game::menu::align_text(ctx); | |||||
game::menu::update_text_tweens(ctx); | |||||
// Update config | |||||
(*ctx.config)["render_resolution"] = ctx.render_resolution_scale; | |||||
}; | |||||
auto decrease_resolution_callback = [this, &ctx]() | |||||
{ | |||||
// Increase resolution | |||||
if (ctx.controls["menu_modifier"]->is_active()) | |||||
ctx.render_resolution_scale -= 0.05f; | |||||
else | |||||
ctx.render_resolution_scale -= 0.25f; | |||||
// Limit resolution | |||||
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 | |||||
this->update_value_text_content(); | |||||
game::menu::align_text(ctx); | |||||
game::menu::update_text_tweens(ctx); | |||||
// Update config | |||||
(*ctx.config)["render_resolution"] = ctx.render_resolution_scale; | |||||
}; | |||||
auto toggle_v_sync_callback = [this, &ctx]() | |||||
{ | |||||
bool v_sync = !ctx.app->get_v_sync(); | |||||
ctx.app->set_v_sync(v_sync); | |||||
this->update_value_text_content(); | |||||
game::menu::align_text(ctx); | |||||
game::menu::update_text_tweens(ctx); | |||||
// Save v-sync config | |||||
(*ctx.config)["v_sync"] = v_sync; | |||||
}; | |||||
auto increase_font_size_callback = [this, &ctx]() | |||||
{ | |||||
// Increase font size | |||||
if (ctx.controls["menu_modifier"]->is_active()) | |||||
ctx.font_size += 0.01f; | |||||
else | |||||
ctx.font_size += 0.1f; | |||||
// Limit font size | |||||
if (ctx.font_size > 2.0f) | |||||
ctx.font_size = 2.0f; | |||||
// Update value text | |||||
this->update_value_text_content(); | |||||
// Update config | |||||
(*ctx.config)["font_size"] = ctx.font_size; | |||||
// Reload fonts | |||||
ctx.logger->push_task("Reloading fonts"); | |||||
try | |||||
{ | |||||
game::load_fonts(ctx); | |||||
} | |||||
catch (...) | |||||
{ | |||||
ctx.logger->pop_task(EXIT_FAILURE); | |||||
} | |||||
ctx.logger->pop_task(EXIT_SUCCESS); | |||||
// Refresh and realign text | |||||
game::menu::refresh_text(ctx); | |||||
game::menu::align_text(ctx); | |||||
game::menu::update_text_tweens(ctx); | |||||
}; | |||||
auto decrease_font_size_callback = [this, &ctx]() | |||||
{ | |||||
// Decrease font size | |||||
if (ctx.controls["menu_modifier"]->is_active()) | |||||
ctx.font_size -= 0.01f; | |||||
else | |||||
ctx.font_size -= 0.1f; | |||||
// Limit font size | |||||
if (ctx.font_size < 0.1f) | |||||
ctx.font_size = 0.1f; | |||||
// Update value text | |||||
this->update_value_text_content(); | |||||
// Update config | |||||
(*ctx.config)["font_size"] = ctx.font_size; | |||||
// Reload fonts | |||||
ctx.logger->push_task("Reloading fonts"); | |||||
try | |||||
{ | |||||
game::load_fonts(ctx); | |||||
} | |||||
catch (...) | |||||
{ | |||||
ctx.logger->pop_task(EXIT_FAILURE); | |||||
} | |||||
ctx.logger->pop_task(EXIT_SUCCESS); | |||||
// Refresh and realign text | |||||
game::menu::refresh_text(ctx); | |||||
game::menu::align_text(ctx); | |||||
game::menu::update_text_tweens(ctx); | |||||
}; | |||||
auto toggle_dyslexia_font_callback = [this, &ctx]() | |||||
{ | |||||
ctx.dyslexia_font = !ctx.dyslexia_font; | |||||
// Update value text | |||||
this->update_value_text_content(); | |||||
// Save dyslexia font config | |||||
(*ctx.config)["dyslexia_font"] = ctx.dyslexia_font; | |||||
// Reload fonts | |||||
ctx.logger->push_task("Reloading fonts"); | |||||
try | |||||
{ | |||||
game::load_fonts(ctx); | |||||
} | |||||
catch (...) | |||||
{ | |||||
ctx.logger->pop_task(EXIT_FAILURE); | |||||
} | |||||
ctx.logger->pop_task(EXIT_SUCCESS); | |||||
// Refresh and realign text | |||||
game::menu::refresh_text(ctx); | |||||
game::menu::align_text(ctx); | |||||
game::menu::update_text_tweens(ctx); | |||||
}; | |||||
auto select_back_callback = [&ctx]() | |||||
{ | |||||
// Disable controls | |||||
game::menu::clear_controls(ctx); | |||||
game::menu::fade_out | |||||
( | |||||
ctx, | |||||
[&ctx]() | |||||
{ | |||||
// Queue change to options menu state | |||||
ctx.function_queue.push | |||||
( | |||||
[&ctx]() | |||||
{ | |||||
ctx.state_machine.pop(); | |||||
ctx.state_machine.emplace(new game::state::options_menu(ctx)); | |||||
} | |||||
); | |||||
} | |||||
); | |||||
}; | |||||
// Build list of menu select callbacks | |||||
ctx.menu_select_callbacks.push_back(toggle_fullscreen_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(increase_font_size_callback); | |||||
ctx.menu_select_callbacks.push_back(toggle_dyslexia_font_callback); | |||||
ctx.menu_select_callbacks.push_back(select_back_callback); | |||||
// Build list of menu left callbacks | |||||
ctx.menu_left_callbacks.push_back(toggle_fullscreen_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(decrease_font_size_callback); | |||||
ctx.menu_left_callbacks.push_back(toggle_dyslexia_font_callback); | |||||
ctx.menu_left_callbacks.push_back(nullptr); | |||||
// Build list of menu right callbacks | |||||
ctx.menu_right_callbacks.push_back(toggle_fullscreen_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(increase_font_size_callback); | |||||
ctx.menu_right_callbacks.push_back(toggle_dyslexia_font_callback); | |||||
ctx.menu_right_callbacks.push_back(nullptr); | |||||
// Set menu back callback | |||||
ctx.menu_back_callback = select_back_callback; | |||||
// Queue menu control setup | |||||
ctx.function_queue.push(std::bind(game::menu::setup_controls, std::ref(ctx))); | |||||
// Fade in menu | |||||
game::menu::fade_in(ctx, nullptr); | |||||
ctx.logger->pop_task(EXIT_SUCCESS); | |||||
} | |||||
graphics_menu::~graphics_menu() | |||||
{ | |||||
ctx.logger->push_task("Exiting graphics menu state"); | |||||
// Destruct menu | |||||
game::menu::clear_controls(ctx); | |||||
game::menu::clear_callbacks(ctx); | |||||
game::menu::delete_animations(ctx); | |||||
game::menu::remove_text_from_ui(ctx); | |||||
game::menu::delete_text(ctx); | |||||
ctx.logger->pop_task(EXIT_SUCCESS); | |||||
} | |||||
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 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<int>(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<int>(std::round(font_size * 100.0f))) + "%"); | |||||
std::get<1>(ctx.menu_item_texts[4])->set_content((dyslexia_font) ? string_on : string_off); | |||||
} | |||||
} // namespace state | |||||
} // namespace game |
@ -0,0 +1,284 @@ | |||||
/* | |||||
* 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "game/state/main-menu.hpp" | |||||
#include "game/state/options-menu.hpp" | |||||
#include "game/state/extras-menu.hpp" | |||||
#include "game/state/forage.hpp" | |||||
#include "game/state/nuptial-flight.hpp" | |||||
#include "game/menu.hpp" | |||||
#include "render/passes/clear-pass.hpp" | |||||
#include "resources/resource-manager.hpp" | |||||
#include "render/model.hpp" | |||||
#include "animation/animation.hpp" | |||||
#include "animation/animator.hpp" | |||||
#include "animation/screen-transition.hpp" | |||||
#include "animation/ease.hpp" | |||||
#include "animation/timeline.hpp" | |||||
#include "application.hpp" | |||||
#include <limits> | |||||
namespace game { | |||||
namespace state { | |||||
main_menu::main_menu(game::context& ctx, bool fade_in): | |||||
game::state::base(ctx) | |||||
{ | |||||
ctx.logger->push_task("Entering main menu state"); | |||||
ctx.ui_clear_pass->set_cleared_buffers(true, true, false); | |||||
// Construct title text | |||||
ctx.title_text = new scene::text(); | |||||
ctx.title_text->set_material(&ctx.title_font_material); | |||||
ctx.title_text->set_font(&ctx.title_font); | |||||
ctx.title_text->set_color({1.0f, 1.0f, 1.0f, 1.0f}); | |||||
ctx.title_text->set_content((*ctx.strings)["title_antkeeper"]); | |||||
// Align title text | |||||
const auto& title_aabb = static_cast<const geom::aabb<float>&>(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 + (ctx.app->get_viewport_dimensions().y / 3.0f) / 2.0f), 0.0f}); | |||||
ctx.title_text->update_tweens(); | |||||
// Add title text to UI | |||||
ctx.ui_scene->add_object(ctx.title_text); | |||||
// Construct title fade animation | |||||
ctx.title_fade_animation = new animation<float>(); | |||||
animation_channel<float>* opacity_channel = ctx.title_fade_animation->add_channel(0); | |||||
ctx.title_fade_animation->set_frame_callback | |||||
( | |||||
[&ctx](int channel, const float& opacity) | |||||
{ | |||||
float4 color = ctx.title_text->get_color(); | |||||
color[3] = opacity; | |||||
ctx.title_text->set_color(color); | |||||
} | |||||
); | |||||
ctx.animator->add_animation(ctx.title_fade_animation); | |||||
// Construct menu item texts | |||||
scene::text* start_text = new scene::text(); | |||||
scene::text* options_text = new scene::text(); | |||||
scene::text* extras_text = new scene::text(); | |||||
scene::text* quit_text = new scene::text(); | |||||
// Build list of menu item texts | |||||
ctx.menu_item_texts.push_back({start_text, nullptr}); | |||||
ctx.menu_item_texts.push_back({options_text, nullptr}); | |||||
ctx.menu_item_texts.push_back({extras_text, nullptr}); | |||||
ctx.menu_item_texts.push_back({quit_text, nullptr}); | |||||
// Set content of menu item texts | |||||
start_text->set_content((*ctx.strings)["main_menu_start"]); | |||||
options_text->set_content((*ctx.strings)["main_menu_options"]); | |||||
extras_text->set_content((*ctx.strings)["main_menu_extras"]); | |||||
quit_text->set_content((*ctx.strings)["main_menu_quit"]); | |||||
// Init menu item index | |||||
game::menu::init_menu_item_index(ctx, "main"); | |||||
game::menu::update_text_color(ctx); | |||||
game::menu::update_text_font(ctx); | |||||
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); | |||||
auto select_start_callback = [&ctx]() | |||||
{ | |||||
// Disable controls and menu callbacks | |||||
game::menu::clear_controls(ctx); | |||||
game::menu::clear_callbacks(ctx); | |||||
// Create change state function | |||||
auto change_state_nuptial_flight = [&ctx]() | |||||
{ | |||||
// Queue change to nuptial state | |||||
ctx.function_queue.push | |||||
( | |||||
[&ctx]() | |||||
{ | |||||
ctx.state_machine.pop(); | |||||
ctx.state_machine.emplace(new game::state::nuptial_flight(ctx)); | |||||
} | |||||
); | |||||
}; | |||||
// Set up timing | |||||
const float fade_out_duration = 1.0f; | |||||
// Schedule state change | |||||
timeline* timeline = ctx.timeline; | |||||
float t = timeline->get_position(); | |||||
timeline->add_sequence({{t + fade_out_duration, change_state_nuptial_flight}}); | |||||
// Start fade out to white | |||||
ctx.fade_transition_color->set_value({1, 1, 1}); | |||||
ctx.fade_transition->transition(fade_out_duration, false, ease<float>::out_cubic, false); | |||||
}; | |||||
auto select_options_callback = [this, &ctx]() | |||||
{ | |||||
game::menu::clear_controls(ctx); | |||||
// Fade out title | |||||
this->fade_out_title(); | |||||
// Fade out menu | |||||
game::menu::fade_out | |||||
( | |||||
ctx, | |||||
[&ctx]() | |||||
{ | |||||
// Queue change to options menu state | |||||
ctx.function_queue.push | |||||
( | |||||
[&ctx]() | |||||
{ | |||||
ctx.state_machine.pop(); | |||||
ctx.state_machine.emplace(new game::state::options_menu(ctx)); | |||||
} | |||||
); | |||||
} | |||||
); | |||||
}; | |||||
auto select_extras_callback = [this, &ctx]() | |||||
{ | |||||
// Disable controls | |||||
game::menu::clear_controls(ctx); | |||||
// Fade out title | |||||
this->fade_out_title(); | |||||
// Fade out menu | |||||
game::menu::fade_out | |||||
( | |||||
ctx, | |||||
[&ctx]() | |||||
{ | |||||
// Queue change to extras menu state | |||||
ctx.function_queue.push | |||||
( | |||||
[&ctx]() | |||||
{ | |||||
ctx.state_machine.pop(); | |||||
ctx.state_machine.emplace(new game::state::extras_menu(ctx)); | |||||
} | |||||
); | |||||
} | |||||
); | |||||
}; | |||||
auto select_quit_callback = [&ctx]() | |||||
{ | |||||
ctx.app->close(); | |||||
}; | |||||
// Build list of menu select callbacks | |||||
ctx.menu_select_callbacks.push_back(select_start_callback); | |||||
ctx.menu_select_callbacks.push_back(select_options_callback); | |||||
ctx.menu_select_callbacks.push_back(select_extras_callback); | |||||
ctx.menu_select_callbacks.push_back(select_quit_callback); | |||||
// Build list of menu left callbacks | |||||
ctx.menu_left_callbacks.push_back(nullptr); | |||||
ctx.menu_left_callbacks.push_back(nullptr); | |||||
ctx.menu_left_callbacks.push_back(nullptr); | |||||
ctx.menu_left_callbacks.push_back(nullptr); | |||||
// Build list of menu right callbacks | |||||
ctx.menu_right_callbacks.push_back(nullptr); | |||||
ctx.menu_right_callbacks.push_back(nullptr); | |||||
ctx.menu_right_callbacks.push_back(nullptr); | |||||
ctx.menu_right_callbacks.push_back(nullptr); | |||||
// Set menu back callback | |||||
ctx.menu_back_callback = select_quit_callback; | |||||
// Queue menu control setup | |||||
ctx.function_queue.push(std::bind(game::menu::setup_controls, std::ref(ctx))); | |||||
if (fade_in) | |||||
{ | |||||
ctx.fade_transition->transition(0.5f, true, ease<float>::out_cubic); | |||||
} | |||||
else | |||||
{ | |||||
// Fade in title | |||||
ctx.title_text->set_color({1.0f, 1.0f, 1.0f, 0.0f}); | |||||
ctx.title_text->update_tweens(); | |||||
fade_in_title(); | |||||
// Fade in menu | |||||
game::menu::fade_in(ctx, nullptr); | |||||
} | |||||
ctx.logger->pop_task(EXIT_SUCCESS); | |||||
} | |||||
main_menu::~main_menu() | |||||
{ | |||||
ctx.logger->push_task("Exiting main menu state"); | |||||
// Destruct menu | |||||
game::menu::clear_controls(ctx); | |||||
game::menu::clear_callbacks(ctx); | |||||
game::menu::delete_animations(ctx); | |||||
game::menu::remove_text_from_ui(ctx); | |||||
game::menu::delete_text(ctx); | |||||
// Destruct title animation | |||||
ctx.animator->remove_animation(ctx.title_fade_animation); | |||||
delete ctx.title_fade_animation; | |||||
ctx.title_fade_animation = nullptr; | |||||
// Destruct title text | |||||
ctx.ui_scene->remove_object(ctx.title_text); | |||||
delete ctx.title_text; | |||||
ctx.title_text = nullptr; | |||||
ctx.logger->pop_task(EXIT_SUCCESS); | |||||
} | |||||
void main_menu::fade_in_title() | |||||
{ | |||||
ctx.title_fade_animation->set_interpolator(ease<float>::out_cubic); | |||||
animation_channel<float>* opacity_channel = ctx.title_fade_animation->get_channel(0); | |||||
opacity_channel->remove_keyframes(); | |||||
opacity_channel->insert_keyframe({0.0, 0.0f}); | |||||
opacity_channel->insert_keyframe({game::menu::fade_in_duration, 1.0f}); | |||||
ctx.title_fade_animation->stop(); | |||||
ctx.title_fade_animation->play(); | |||||
} | |||||
void main_menu::fade_out_title() | |||||
{ | |||||
ctx.title_fade_animation->set_interpolator(ease<float>::out_cubic); | |||||
animation_channel<float>* opacity_channel = ctx.title_fade_animation->get_channel(0); | |||||
opacity_channel->remove_keyframes(); | |||||
opacity_channel->insert_keyframe({0.0, 1.0f}); | |||||
opacity_channel->insert_keyframe({game::menu::fade_out_duration, 0.0f}); | |||||
ctx.title_fade_animation->stop(); | |||||
ctx.title_fade_animation->play(); | |||||
} | |||||
} // namespace state | |||||
} // namespace game |
@ -0,0 +1,544 @@ | |||||
/* | |||||
* 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "game/state/nuptial-flight.hpp" | |||||
#include "game/state/pause-menu.hpp" | |||||
#include "entity/archetype.hpp" | |||||
#include "entity/systems/astronomy.hpp" | |||||
#include "entity/systems/orbit.hpp" | |||||
#include "entity/systems/camera.hpp" | |||||
#include "entity/components/observer.hpp" | |||||
#include "entity/components/transform.hpp" | |||||
#include "entity/components/terrain.hpp" | |||||
#include "entity/components/camera.hpp" | |||||
#include "entity/components/constraints/spring-to.hpp" | |||||
#include "entity/components/constraints/three-dof.hpp" | |||||
#include "entity/components/constraint-stack.hpp" | |||||
#include "entity/commands.hpp" | |||||
#include "animation/screen-transition.hpp" | |||||
#include "animation/ease.hpp" | |||||
#include "resources/resource-manager.hpp" | |||||
#include "game/world.hpp" | |||||
#include "application.hpp" | |||||
#include "render/passes/clear-pass.hpp" | |||||
#include <memory> | |||||
#include <iostream> | |||||
#include "state-machine.hpp" | |||||
namespace game { | |||||
namespace state { | |||||
nuptial_flight::nuptial_flight(game::context& ctx): | |||||
game::state::base(ctx) | |||||
{ | |||||
ctx.logger->push_task("Entering nuptial flight state"); | |||||
// Disable UI color clear | |||||
ctx.ui_clear_pass->set_cleared_buffers(false, true, false); | |||||
// Create world | |||||
game::world::create_stars(ctx); | |||||
game::world::create_sun(ctx); | |||||
game::world::create_planet(ctx); | |||||
game::world::create_moon(ctx); | |||||
// Set time to solar noon | |||||
game::world::set_time(ctx, 0.0); | |||||
// Freeze time | |||||
game::world::set_time_scale(ctx, 0.0); | |||||
// Switch to surface camera | |||||
ctx.underground_camera->set_active(false); | |||||
ctx.surface_camera->set_active(true); | |||||
// Find planet EID by name | |||||
entity::id planet_eid = ctx.entities["planet"]; | |||||
// Remove terrain component from planet (if any) | |||||
//if (ctx.entity_registry->has<entity::component::terrain>(planet_eid)) | |||||
// ctx.entity_registry->remove<entity::component::terrain>(planet_eid); | |||||
// Enable clouds in sky pass | |||||
//ctx.surface_sky_pass->set_clouds_model(ctx.resource_manager->load<render::model>("cloud-plane.mdl")); | |||||
// Create observer | |||||
entity::id observer_eid = ctx.entity_registry->create(); | |||||
{ | |||||
entity::component::observer observer; | |||||
observer.reference_body_eid = planet_eid; | |||||
observer.elevation = 2000.0; | |||||
observer.latitude = 0.0; | |||||
observer.longitude = 0.0; | |||||
observer.camera = ctx.surface_camera; | |||||
ctx.entity_registry->assign<entity::component::observer>(observer_eid, observer); | |||||
// Set reference location of astronomy system | |||||
ctx.astronomy_system->set_reference_body(planet_eid); | |||||
ctx.astronomy_system->set_observer_location(double3{observer.elevation, observer.latitude, observer.longitude}); | |||||
} | |||||
// Setup camera | |||||
setup_camera(); | |||||
/* | |||||
ctx.surface_camera->look_at({0, 0, 1}, {0, 0, 0}, {0, 1, 0}); | |||||
ctx.surface_camera->set_exposure(-14.5f); | |||||
ctx.surface_scene->update_tweens(); | |||||
*/ | |||||
// Queue fade in | |||||
ctx.fade_transition_color->set_value({1, 1, 1}); | |||||
ctx.function_queue.push(std::bind(&screen_transition::transition, ctx.fade_transition, 5.0f, true, math::lerp<float, float>, true)); | |||||
// Queue control setup | |||||
ctx.function_queue.push(std::bind(&nuptial_flight::enable_controls, this)); | |||||
ctx.logger->pop_task(EXIT_SUCCESS); | |||||
} | |||||
nuptial_flight::~nuptial_flight() | |||||
{ | |||||
ctx.logger->push_task("Exiting nuptial flight state"); | |||||
// Resume time | |||||
//const double time_scale = (*ctx.config)["time_scale"].get<double>(); | |||||
//game::world::set_time_scale(ctx, time_scale); | |||||
ctx.logger->pop_task(EXIT_SUCCESS); | |||||
} | |||||
void nuptial_flight::setup_camera() | |||||
{ | |||||
// Switch to surface camera | |||||
ctx.underground_camera->set_active(false); | |||||
ctx.surface_camera->set_active(true); | |||||
// Create surface camera entity | |||||
if (!ctx.entities.count("surface_cam")) | |||||
{ | |||||
// Create camera target entity | |||||
entity::id target_eid = ctx.entity_registry->create(); | |||||
ctx.entities["surface_cam_target"] = target_eid; | |||||
{ | |||||
// Transform | |||||
entity::component::transform target_transform; | |||||
target_transform.local = math::identity_transform<float>; | |||||
target_transform.world = target_transform.local; | |||||
target_transform.warp = true; | |||||
ctx.entity_registry->assign<entity::component::transform>(target_eid, target_transform); | |||||
} | |||||
// Create camera entity | |||||
entity::id camera_eid = ctx.entity_registry->create(); | |||||
ctx.entities["surface_cam"] = camera_eid; | |||||
// Create camera transform component | |||||
entity::component::transform transform; | |||||
transform.local = math::identity_transform<float>; | |||||
transform.world = transform.local; | |||||
transform.warp = true; | |||||
ctx.entity_registry->assign<entity::component::transform>(camera_eid, transform); | |||||
// Create camera camera component | |||||
entity::component::camera camera; | |||||
camera.object = ctx.surface_camera; | |||||
ctx.entity_registry->assign<entity::component::camera>(camera_eid, camera); | |||||
// Create camera 3DOF constraint entity | |||||
entity::id three_dof_constraint_eid = ctx.entity_registry->create(); | |||||
ctx.entities["surface_cam_3dof"] = three_dof_constraint_eid; | |||||
{ | |||||
// Create 3DOF to constraint | |||||
entity::component::constraint::three_dof three_dof; | |||||
three_dof.yaw = 0.0f; | |||||
three_dof.pitch = 0.0f; | |||||
three_dof.roll = 0.0f; | |||||
ctx.entity_registry->assign<entity::component::constraint::three_dof>(three_dof_constraint_eid, three_dof); | |||||
// Create constraint stack node component | |||||
entity::component::constraint_stack_node node; | |||||
node.active = true; | |||||
node.weight = 1.0f; | |||||
node.next = entt::null; | |||||
ctx.entity_registry->assign<entity::component::constraint_stack_node>(three_dof_constraint_eid, node); | |||||
} | |||||
// Create camera spring to constraint entity | |||||
entity::id spring_constraint_eid = ctx.entity_registry->create(); | |||||
{ | |||||
// Create spring to constraint | |||||
entity::component::constraint::spring_to spring; | |||||
spring.target = target_eid; | |||||
spring.translation = {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}, 1.0f, math::two_pi<float>}; | |||||
spring.translation.w = hz_to_rads(8.0f); | |||||
spring.spring_translation = true; | |||||
spring.spring_rotation = false; | |||||
ctx.entity_registry->assign<entity::component::constraint::spring_to>(spring_constraint_eid, spring); | |||||
// Create constraint stack node component | |||||
entity::component::constraint_stack_node node; | |||||
node.active = true; | |||||
node.weight = 1.0f; | |||||
node.next = three_dof_constraint_eid; | |||||
ctx.entity_registry->assign<entity::component::constraint_stack_node>(spring_constraint_eid, node); | |||||
} | |||||
// Create camera constraint stack component | |||||
entity::component::constraint_stack constraint_stack; | |||||
constraint_stack.head = spring_constraint_eid; | |||||
ctx.entity_registry->assign<entity::component::constraint_stack>(camera_eid, constraint_stack); | |||||
} | |||||
ctx.surface_camera->set_exposure(-12.0f); | |||||
} | |||||
void nuptial_flight::enable_controls() | |||||
{ | |||||
// Get camera entities | |||||
entity::id camera_eid = ctx.entities["surface_cam"]; | |||||
entity::id target_eid = ctx.entities["surface_cam_target"]; | |||||
entity::id three_dof_eid = ctx.entities["surface_cam_3dof"]; | |||||
const float slow_modifier = 0.25f; | |||||
const float fast_modifier = 4.0f; | |||||
const float dolly_speed = 20.0f; | |||||
const float truck_speed = dolly_speed; | |||||
const float pedestal_speed = 30.0f; | |||||
float mouse_tilt_sensitivity = 1.0f; | |||||
float mouse_pan_sensitivity = 1.0f; | |||||
bool mouse_invert_tilt = false; | |||||
bool mouse_invert_pan = false; | |||||
float gamepad_tilt_sensitivity = 1.0f; | |||||
float gamepad_pan_sensitivity = 1.0f; | |||||
bool gamepad_invert_tilt = false; | |||||
bool gamepad_invert_pan = false; | |||||
bool mouse_look_toggle = false; | |||||
ctx.mouse_look = false; | |||||
if (ctx.config->contains("mouse_tilt_sensitivity")) | |||||
mouse_tilt_sensitivity = math::radians((*ctx.config)["mouse_tilt_sensitivity"].get<float>()); | |||||
if (ctx.config->contains("mouse_pan_sensitivity")) | |||||
mouse_pan_sensitivity = math::radians((*ctx.config)["mouse_pan_sensitivity"].get<float>()); | |||||
if (ctx.config->contains("mouse_invert_tilt")) | |||||
mouse_invert_tilt = math::radians((*ctx.config)["mouse_invert_tilt"].get<bool>()); | |||||
if (ctx.config->contains("mouse_invert_pan")) | |||||
mouse_invert_pan = math::radians((*ctx.config)["mouse_invert_pan"].get<bool>()); | |||||
if (ctx.config->contains("mouse_look_toggle")) | |||||
mouse_look_toggle = math::radians((*ctx.config)["mouse_look_toggle"].get<bool>()); | |||||
if (ctx.config->contains("gamepad_tilt_sensitivity")) | |||||
gamepad_tilt_sensitivity = math::radians((*ctx.config)["gamepad_tilt_sensitivity"].get<float>()); | |||||
if (ctx.config->contains("gamepad_pan_sensitivity")) | |||||
gamepad_pan_sensitivity = math::radians((*ctx.config)["gamepad_pan_sensitivity"].get<float>()); | |||||
if (ctx.config->contains("gamepad_invert_tilt")) | |||||
gamepad_invert_tilt = math::radians((*ctx.config)["gamepad_invert_tilt"].get<bool>()); | |||||
if (ctx.config->contains("gamepad_invert_pan")) | |||||
gamepad_invert_pan = math::radians((*ctx.config)["gamepad_invert_pan"].get<bool>()); | |||||
const input::control* move_slow = ctx.controls["move_slow"]; | |||||
const input::control* move_fast = ctx.controls["move_fast"]; | |||||
const input::control* mouse_look = ctx.controls["mouse_look"]; | |||||
float mouse_tilt_factor = mouse_tilt_sensitivity * (mouse_invert_tilt ? -1.0f : 1.0f); | |||||
float mouse_pan_factor = mouse_pan_sensitivity * (mouse_invert_pan ? -1.0f : 1.0f); | |||||
float gamepad_tilt_factor = gamepad_tilt_sensitivity * (gamepad_invert_tilt ? -1.0f : 1.0f); | |||||
float gamepad_pan_factor = gamepad_pan_sensitivity * (gamepad_invert_pan ? -1.0f : 1.0f); | |||||
ctx.controls["move_forward"]->set_active_callback | |||||
( | |||||
[&ctx = this->ctx, target_eid, three_dof_eid, truck_speed, move_slow, move_fast, slow_modifier, fast_modifier](float value) | |||||
{ | |||||
if (move_slow->is_active()) | |||||
value *= slow_modifier; | |||||
if (move_fast->is_active()) | |||||
value *= fast_modifier; | |||||
auto& three_dof = ctx.entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid); | |||||
const math::quaternion<float> yaw = math::angle_axis(three_dof.yaw, {0.0f, 1.0f, 0.0f}); | |||||
const float3 movement = {0.0f, 0.0f, -truck_speed * value * (1.0f / 60.0f)}; | |||||
entity::command::translate(*ctx.entity_registry, target_eid, yaw * movement); | |||||
} | |||||
); | |||||
// Dolly backward | |||||
ctx.controls["move_back"]->set_active_callback | |||||
( | |||||
[&ctx = this->ctx, target_eid, three_dof_eid, truck_speed, move_slow, move_fast, slow_modifier, fast_modifier](float value) | |||||
{ | |||||
if (move_slow->is_active()) | |||||
value *= slow_modifier; | |||||
if (move_fast->is_active()) | |||||
value *= fast_modifier; | |||||
auto& three_dof = ctx.entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid); | |||||
const math::quaternion<float> yaw = math::angle_axis(three_dof.yaw, {0.0f, 1.0f, 0.0f}); | |||||
const float3 movement = {0.0f, 0.0f, truck_speed * value * (1.0f / 60.0f)}; | |||||
entity::command::translate(*ctx.entity_registry, target_eid, yaw * movement); | |||||
} | |||||
); | |||||
// Truck right | |||||
ctx.controls["move_right"]->set_active_callback | |||||
( | |||||
[&ctx = this->ctx, target_eid, three_dof_eid, truck_speed, move_slow, move_fast, slow_modifier, fast_modifier](float value) | |||||
{ | |||||
if (move_slow->is_active()) | |||||
value *= slow_modifier; | |||||
if (move_fast->is_active()) | |||||
value *= fast_modifier; | |||||
auto& three_dof = ctx.entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid); | |||||
const math::quaternion<float> yaw = math::angle_axis(three_dof.yaw, {0.0f, 1.0f, 0.0f}); | |||||
const float3 movement = {truck_speed * value * (1.0f / 60.0f), 0.0f, 0.0f}; | |||||
entity::command::translate(*ctx.entity_registry, target_eid, yaw * movement); | |||||
} | |||||
); | |||||
// Truck left | |||||
ctx.controls["move_left"]->set_active_callback | |||||
( | |||||
[&ctx = this->ctx, target_eid, three_dof_eid, truck_speed, move_slow, move_fast, slow_modifier, fast_modifier](float value) | |||||
{ | |||||
if (move_slow->is_active()) | |||||
value *= slow_modifier; | |||||
if (move_fast->is_active()) | |||||
value *= fast_modifier; | |||||
auto& three_dof = ctx.entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid); | |||||
const math::quaternion<float> yaw = math::angle_axis(three_dof.yaw, {0.0f, 1.0f, 0.0f}); | |||||
const float3 movement = {-truck_speed * value * (1.0f / 60.0f), 0.0f, 0.0f}; | |||||
entity::command::translate(*ctx.entity_registry, target_eid, yaw * movement); | |||||
} | |||||
); | |||||
// Pedestal up | |||||
ctx.controls["move_up"]->set_active_callback | |||||
( | |||||
[&ctx = this->ctx, target_eid, pedestal_speed, move_slow, move_fast, slow_modifier, fast_modifier](float value) | |||||
{ | |||||
if (move_slow->is_active()) | |||||
value *= slow_modifier; | |||||
if (move_fast->is_active()) | |||||
value *= fast_modifier; | |||||
const float3 movement = {0.0f, pedestal_speed * value * (1.0f / 60.0f), 0.0f}; | |||||
entity::command::translate(*ctx.entity_registry, target_eid, movement); | |||||
} | |||||
); | |||||
// Pedestal down | |||||
ctx.controls["move_down"]->set_active_callback | |||||
( | |||||
[&ctx = this->ctx, target_eid, pedestal_speed, move_slow, move_fast, slow_modifier, fast_modifier](float value) | |||||
{ | |||||
if (move_slow->is_active()) | |||||
value *= slow_modifier; | |||||
if (move_fast->is_active()) | |||||
value *= fast_modifier; | |||||
const float3 movement = {0.0f, -pedestal_speed * value * (1.0f / 60.0f), 0.0f}; | |||||
entity::command::translate(*ctx.entity_registry, target_eid, movement); | |||||
} | |||||
); | |||||
// Mouse rotate | |||||
ctx.controls["mouse_look"]->set_activated_callback | |||||
( | |||||
[&ctx = this->ctx, mouse_look_toggle]() | |||||
{ | |||||
if (mouse_look_toggle) | |||||
ctx.mouse_look = !ctx.mouse_look; | |||||
else | |||||
ctx.mouse_look = true; | |||||
ctx.app->set_relative_mouse_mode(ctx.mouse_look); | |||||
} | |||||
); | |||||
ctx.controls["mouse_look"]->set_deactivated_callback | |||||
( | |||||
[&ctx = this->ctx, mouse_look_toggle]() | |||||
{ | |||||
if (!mouse_look_toggle) | |||||
{ | |||||
ctx.mouse_look = false; | |||||
ctx.app->set_relative_mouse_mode(false); | |||||
} | |||||
} | |||||
); | |||||
// Pan left | |||||
ctx.controls["look_left_gamepad"]->set_active_callback | |||||
( | |||||
[&ctx = this->ctx, three_dof_eid, gamepad_pan_factor](float value) | |||||
{ | |||||
auto& three_dof = ctx.entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid); | |||||
three_dof.yaw += gamepad_pan_factor * value * (1.0f / 60.0f); | |||||
} | |||||
); | |||||
ctx.controls["look_left_mouse"]->set_active_callback | |||||
( | |||||
[&ctx = this->ctx, three_dof_eid, mouse_pan_factor](float value) | |||||
{ | |||||
if (!ctx.mouse_look) | |||||
return; | |||||
auto& three_dof = ctx.entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid); | |||||
three_dof.yaw += mouse_pan_factor * value * (1.0f / 60.0f); | |||||
} | |||||
); | |||||
// Pan right | |||||
ctx.controls["look_right_gamepad"]->set_active_callback | |||||
( | |||||
[&ctx = this->ctx, three_dof_eid, gamepad_pan_factor](float value) | |||||
{ | |||||
auto& three_dof = ctx.entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid); | |||||
three_dof.yaw -= gamepad_pan_factor * value * (1.0f / 60.0f); | |||||
} | |||||
); | |||||
ctx.controls["look_right_mouse"]->set_active_callback | |||||
( | |||||
[&ctx = this->ctx, three_dof_eid, mouse_pan_factor](float value) | |||||
{ | |||||
if (!ctx.mouse_look) | |||||
return; | |||||
auto& three_dof = ctx.entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid); | |||||
three_dof.yaw -= mouse_pan_factor * value * (1.0f / 60.0f); | |||||
} | |||||
); | |||||
// Tilt up | |||||
ctx.controls["look_up_gamepad"]->set_active_callback | |||||
( | |||||
[&ctx = this->ctx, three_dof_eid, gamepad_tilt_factor](float value) | |||||
{ | |||||
auto& three_dof = ctx.entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid); | |||||
three_dof.pitch -= gamepad_tilt_factor * value * (1.0f / 60.0f); | |||||
three_dof.pitch = std::max<float>(math::radians(-90.0f), three_dof.pitch); | |||||
} | |||||
); | |||||
ctx.controls["look_up_mouse"]->set_active_callback | |||||
( | |||||
[&ctx = this->ctx, three_dof_eid, mouse_tilt_factor](float value) | |||||
{ | |||||
if (!ctx.mouse_look) | |||||
return; | |||||
auto& three_dof = ctx.entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid); | |||||
three_dof.pitch -= mouse_tilt_factor * value * (1.0f / 60.0f); | |||||
three_dof.pitch = std::max<float>(math::radians(-90.0f), three_dof.pitch); | |||||
} | |||||
); | |||||
// Tilt down | |||||
ctx.controls["look_down_gamepad"]->set_active_callback | |||||
( | |||||
[&ctx = this->ctx, three_dof_eid, gamepad_tilt_factor](float value) | |||||
{ | |||||
auto& three_dof = ctx.entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid); | |||||
three_dof.pitch += gamepad_tilt_factor * value * (1.0f / 60.0f); | |||||
three_dof.pitch = std::min<float>(math::radians(90.0f), three_dof.pitch); | |||||
} | |||||
); | |||||
ctx.controls["look_down_mouse"]->set_active_callback | |||||
( | |||||
[&ctx = this->ctx, three_dof_eid, mouse_tilt_factor](float value) | |||||
{ | |||||
if (!ctx.mouse_look) | |||||
return; | |||||
auto& three_dof = ctx.entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid); | |||||
three_dof.pitch += mouse_tilt_factor * value * (1.0f / 60.0f); | |||||
three_dof.pitch = std::min<float>(math::radians(90.0f), three_dof.pitch); | |||||
} | |||||
); | |||||
/* | |||||
// Use tool | |||||
ctx.controls["use_tool"]->set_activated_callback | |||||
( | |||||
[&ctx]() | |||||
{ | |||||
if (ctx.entities.count("active_tool")) | |||||
{ | |||||
entity::id tool_eid = ctx.entities["active_tool"]; | |||||
const auto& tool = ctx.entity_registry->get<entity::component::tool>(tool_eid); | |||||
if (tool.activated) | |||||
tool.activated(); | |||||
} | |||||
} | |||||
); | |||||
ctx.controls["use_tool"]->set_deactivated_callback | |||||
( | |||||
[&ctx]() | |||||
{ | |||||
if (ctx.entities.count("active_tool")) | |||||
{ | |||||
entity::id tool_eid = ctx.entities["active_tool"]; | |||||
const auto& tool = ctx.entity_registry->get<entity::component::tool>(tool_eid); | |||||
if (tool.deactivated) | |||||
tool.deactivated(); | |||||
} | |||||
} | |||||
); | |||||
ctx.controls["use_tool"]->set_active_callback | |||||
( | |||||
[&ctx](float value) | |||||
{ | |||||
if (ctx.entities.count("active_tool")) | |||||
{ | |||||
entity::id tool_eid = ctx.entities["active_tool"]; | |||||
const auto& tool = ctx.entity_registry->get<entity::component::tool>(tool_eid); | |||||
if (tool.active) | |||||
tool.active(); | |||||
} | |||||
} | |||||
); | |||||
*/ | |||||
// Setup pause control | |||||
ctx.controls["pause"]->set_activated_callback | |||||
( | |||||
[this, &ctx = this->ctx]() | |||||
{ | |||||
// Disable controls | |||||
this->disable_controls(); | |||||
// Set resume callback | |||||
ctx.resume_callback = [this, &ctx]() | |||||
{ | |||||
this->enable_controls(); | |||||
ctx.resume_callback = nullptr; | |||||
}; | |||||
// Push pause menu state | |||||
ctx.state_machine.emplace(new game::state::pause_menu(ctx)); | |||||
} | |||||
); | |||||
} | |||||
void nuptial_flight::disable_controls() | |||||
{ | |||||
ctx.controls["pause"]->set_activated_callback(nullptr); | |||||
} | |||||
} // namespace state | |||||
} // namespace game |
@ -0,0 +1,237 @@ | |||||
/* | |||||
* 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "game/state/options-menu.hpp" | |||||
#include "game/state/main-menu.hpp" | |||||
#include "game/state/controls-menu.hpp" | |||||
#include "game/state/graphics-menu.hpp" | |||||
#include "game/state/sound-menu.hpp" | |||||
#include "game/state/language-menu.hpp" | |||||
#include "game/state/pause-menu.hpp" | |||||
#include "game/save.hpp" | |||||
#include "game/menu.hpp" | |||||
#include "animation/ease.hpp" | |||||
#include "animation/animation.hpp" | |||||
#include "animation/animator.hpp" | |||||
#include "application.hpp" | |||||
#include "scene/text.hpp" | |||||
#include "debug/logger.hpp" | |||||
namespace game { | |||||
namespace state { | |||||
options_menu::options_menu(game::context& ctx): | |||||
game::state::base(ctx) | |||||
{ | |||||
ctx.logger->push_task("Entering options menu state"); | |||||
// Construct menu item texts | |||||
scene::text* controls_text = new scene::text(); | |||||
scene::text* graphics_text = new scene::text(); | |||||
scene::text* sound_text = new scene::text(); | |||||
scene::text* language_text = new scene::text(); | |||||
scene::text* back_text = new scene::text(); | |||||
// Set content of menu item texts | |||||
controls_text->set_content((*ctx.strings)["options_menu_controls"]); | |||||
graphics_text->set_content((*ctx.strings)["options_menu_graphics"]); | |||||
sound_text->set_content((*ctx.strings)["options_menu_sound"]); | |||||
language_text->set_content((*ctx.strings)["options_menu_language"]); | |||||
back_text->set_content((*ctx.strings)["back"]); | |||||
// Build list of menu item texts | |||||
ctx.menu_item_texts.push_back({controls_text, nullptr}); | |||||
ctx.menu_item_texts.push_back({graphics_text, nullptr}); | |||||
ctx.menu_item_texts.push_back({sound_text, nullptr}); | |||||
ctx.menu_item_texts.push_back({language_text, nullptr}); | |||||
ctx.menu_item_texts.push_back({back_text, nullptr}); | |||||
// Init menu item index | |||||
game::menu::init_menu_item_index(ctx, "options"); | |||||
game::menu::update_text_color(ctx); | |||||
game::menu::update_text_font(ctx); | |||||
game::menu::align_text(ctx, true); | |||||
game::menu::update_text_tweens(ctx); | |||||
game::menu::add_text_to_ui(ctx); | |||||
game::menu::setup_animations(ctx); | |||||
// Construct menu item callbacks | |||||
auto select_controls_callback = [&ctx]() | |||||
{ | |||||
// Disable controls | |||||
game::menu::clear_controls(ctx); | |||||
// Return to main menu | |||||
game::menu::fade_out | |||||
( | |||||
ctx, | |||||
[&ctx]() | |||||
{ | |||||
// Queue change to controls menu state | |||||
ctx.function_queue.push | |||||
( | |||||
[&ctx]() | |||||
{ | |||||
ctx.state_machine.pop(); | |||||
ctx.state_machine.emplace(new game::state::controls_menu(ctx)); | |||||
} | |||||
); | |||||
} | |||||
); | |||||
}; | |||||
auto select_graphics_callback = [&ctx]() | |||||
{ | |||||
// Disable controls | |||||
game::menu::clear_controls(ctx); | |||||
// Return to main menu | |||||
game::menu::fade_out | |||||
( | |||||
ctx, | |||||
[&ctx]() | |||||
{ | |||||
// Queue change to graphics menu state | |||||
ctx.function_queue.push | |||||
( | |||||
[&ctx]() | |||||
{ | |||||
ctx.state_machine.pop(); | |||||
ctx.state_machine.emplace(new game::state::graphics_menu(ctx)); | |||||
} | |||||
); | |||||
} | |||||
); | |||||
}; | |||||
auto select_sound_callback = [&ctx]() | |||||
{ | |||||
// Disable controls | |||||
game::menu::clear_controls(ctx); | |||||
// Return to main menu | |||||
game::menu::fade_out | |||||
( | |||||
ctx, | |||||
[&ctx]() | |||||
{ | |||||
// Queue change to sound menu state | |||||
ctx.function_queue.push | |||||
( | |||||
[&ctx]() | |||||
{ | |||||
ctx.state_machine.pop(); | |||||
ctx.state_machine.emplace(new game::state::sound_menu(ctx)); | |||||
} | |||||
); | |||||
} | |||||
); | |||||
}; | |||||
auto select_language_callback = [&ctx]() | |||||
{ | |||||
// Disable controls | |||||
game::menu::clear_controls(ctx); | |||||
// Return to main menu | |||||
game::menu::fade_out | |||||
( | |||||
ctx, | |||||
[&ctx]() | |||||
{ | |||||
// Queue change to language menu state | |||||
ctx.function_queue.push | |||||
( | |||||
[&ctx]() | |||||
{ | |||||
ctx.state_machine.pop(); | |||||
ctx.state_machine.emplace(new game::state::language_menu(ctx)); | |||||
} | |||||
); | |||||
} | |||||
); | |||||
}; | |||||
auto select_back_callback = [&ctx]() | |||||
{ | |||||
// Disable controls | |||||
game::menu::clear_controls(ctx); | |||||
// Save config | |||||
game::save_config(ctx); | |||||
game::menu::fade_out | |||||
( | |||||
ctx, | |||||
[&ctx]() | |||||
{ | |||||
// Queue change to main menu state | |||||
ctx.function_queue.push | |||||
( | |||||
[&ctx]() | |||||
{ | |||||
ctx.state_machine.pop(); | |||||
if (ctx.resume_callback) | |||||
ctx.state_machine.emplace(new game::state::pause_menu(ctx)); | |||||
else | |||||
ctx.state_machine.emplace(new game::state::main_menu(ctx, false)); | |||||
} | |||||
); | |||||
} | |||||
); | |||||
}; | |||||
// Build list of menu select callbacks | |||||
ctx.menu_select_callbacks.push_back(select_controls_callback); | |||||
ctx.menu_select_callbacks.push_back(select_graphics_callback); | |||||
ctx.menu_select_callbacks.push_back(select_sound_callback); | |||||
ctx.menu_select_callbacks.push_back(select_language_callback); | |||||
ctx.menu_select_callbacks.push_back(select_back_callback); | |||||
// Build list of menu right callbacks | |||||
ctx.menu_right_callbacks.resize(5, nullptr); | |||||
// Build list of menu left callbacks | |||||
ctx.menu_left_callbacks.resize(5, nullptr); | |||||
// Set menu back callback | |||||
ctx.menu_back_callback = select_back_callback; | |||||
// Queue menu control setup | |||||
ctx.function_queue.push(std::bind(game::menu::setup_controls, std::ref(ctx))); | |||||
// Fade in menu | |||||
game::menu::fade_in(ctx, nullptr); | |||||
ctx.logger->pop_task(EXIT_SUCCESS); | |||||
} | |||||
options_menu::~options_menu() | |||||
{ | |||||
ctx.logger->push_task("Exiting options menu state"); | |||||
// Destruct menu | |||||
game::menu::clear_controls(ctx); | |||||
game::menu::clear_callbacks(ctx); | |||||
game::menu::delete_animations(ctx); | |||||
game::menu::remove_text_from_ui(ctx); | |||||
game::menu::delete_text(ctx); | |||||
ctx.logger->pop_task(EXIT_SUCCESS); | |||||
} | |||||
} // namespace state | |||||
} // namespace game |
@ -0,0 +1,262 @@ | |||||
/* | |||||
* 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "game/state/sound-menu.hpp" | |||||
#include "game/state/options-menu.hpp" | |||||
#include "application.hpp" | |||||
#include "scene/text.hpp" | |||||
#include "debug/logger.hpp" | |||||
#include "game/menu.hpp" | |||||
namespace game { | |||||
namespace state { | |||||
sound_menu::sound_menu(game::context& ctx): | |||||
game::state::base(ctx) | |||||
{ | |||||
ctx.logger->push_task("Entering sound menu state"); | |||||
// Construct menu item texts | |||||
scene::text* master_volume_name_text = new scene::text(); | |||||
scene::text* master_volume_value_text = new scene::text(); | |||||
scene::text* ambience_volume_name_text = new scene::text(); | |||||
scene::text* ambience_volume_value_text = new scene::text(); | |||||
scene::text* effects_volume_name_text = new scene::text(); | |||||
scene::text* effects_volume_value_text = new scene::text(); | |||||
scene::text* mono_audio_name_text = new scene::text(); | |||||
scene::text* mono_audio_value_text = new scene::text(); | |||||
scene::text* captions_name_text = new scene::text(); | |||||
scene::text* captions_value_text = new scene::text(); | |||||
scene::text* captions_size_name_text = new scene::text(); | |||||
scene::text* captions_size_value_text = new scene::text(); | |||||
scene::text* back_text = new scene::text(); | |||||
// Build list of menu item texts | |||||
ctx.menu_item_texts.push_back({master_volume_name_text, master_volume_value_text}); | |||||
ctx.menu_item_texts.push_back({ambience_volume_name_text, ambience_volume_value_text}); | |||||
ctx.menu_item_texts.push_back({effects_volume_name_text, effects_volume_value_text}); | |||||
ctx.menu_item_texts.push_back({mono_audio_name_text, mono_audio_value_text}); | |||||
ctx.menu_item_texts.push_back({captions_name_text, captions_value_text}); | |||||
ctx.menu_item_texts.push_back({captions_size_name_text, captions_size_value_text}); | |||||
ctx.menu_item_texts.push_back({back_text, nullptr}); | |||||
// Set content of menu item texts | |||||
master_volume_name_text->set_content((*ctx.strings)["sound_menu_master_volume"]); | |||||
ambience_volume_name_text->set_content((*ctx.strings)["sound_menu_ambience_volume"]); | |||||
effects_volume_name_text->set_content((*ctx.strings)["sound_menu_effects_volume"]); | |||||
mono_audio_name_text->set_content((*ctx.strings)["sound_menu_mono_audio"]); | |||||
captions_name_text->set_content((*ctx.strings)["sound_menu_captions"]); | |||||
captions_size_name_text->set_content((*ctx.strings)["sound_menu_captions_size"]); | |||||
back_text->set_content((*ctx.strings)["back"]); | |||||
update_value_text_content(); | |||||
// Init menu item index | |||||
game::menu::init_menu_item_index(ctx, "sound"); | |||||
game::menu::update_text_color(ctx); | |||||
game::menu::update_text_font(ctx); | |||||
game::menu::align_text(ctx); | |||||
game::menu::update_text_tweens(ctx); | |||||
game::menu::add_text_to_ui(ctx); | |||||
game::menu::setup_animations(ctx); | |||||
// Construct menu item callbacks | |||||
auto increase_volume_callback = [this, &ctx](float* volume) | |||||
{ | |||||
// Increase volume | |||||
if (ctx.controls["menu_modifier"]->is_active()) | |||||
*volume += 0.01f; | |||||
else | |||||
*volume += 0.1f; | |||||
// Limit volume | |||||
if (*volume > 1.0f) | |||||
*volume = 1.0f; | |||||
this->update_value_text_content(); | |||||
game::menu::align_text(ctx); | |||||
game::menu::update_text_tweens(ctx); | |||||
}; | |||||
auto decrease_volume_callback = [this, &ctx](float* volume) | |||||
{ | |||||
// Decrease volume | |||||
if (ctx.controls["menu_modifier"]->is_active()) | |||||
*volume -= 0.01f; | |||||
else | |||||
*volume -= 0.1f; | |||||
// Limit volume | |||||
if (*volume < 0.0f) | |||||
*volume = 0.0f; | |||||
this->update_value_text_content(); | |||||
game::menu::align_text(ctx); | |||||
game::menu::update_text_tweens(ctx); | |||||
}; | |||||
auto toggle_mono_audio_callback = [this, &ctx]() | |||||
{ | |||||
ctx.mono_audio = !ctx.mono_audio; | |||||
this->update_value_text_content(); | |||||
game::menu::align_text(ctx); | |||||
game::menu::update_text_tweens(ctx); | |||||
}; | |||||
auto toggle_captions_callback = [this, &ctx]() | |||||
{ | |||||
ctx.captions = !ctx.captions; | |||||
this->update_value_text_content(); | |||||
game::menu::align_text(ctx); | |||||
game::menu::update_text_tweens(ctx); | |||||
}; | |||||
auto increase_captions_size_callback = [this, &ctx]() | |||||
{ | |||||
// Increase size | |||||
if (ctx.controls["menu_modifier"]->is_active()) | |||||
ctx.captions_size += 0.01f; | |||||
else | |||||
ctx.captions_size += 0.1f; | |||||
// Limit size | |||||
if (ctx.captions_size > 2.0f) | |||||
ctx.captions_size = 2.0f; | |||||
this->update_value_text_content(); | |||||
game::menu::align_text(ctx); | |||||
game::menu::update_text_tweens(ctx); | |||||
}; | |||||
auto decrease_captions_size_callback = [this, &ctx]() | |||||
{ | |||||
// Decrease size | |||||
if (ctx.controls["menu_modifier"]->is_active()) | |||||
ctx.captions_size -= 0.01f; | |||||
else | |||||
ctx.captions_size -= 0.1f; | |||||
// Limit size | |||||
if (ctx.captions_size < 0.1f) | |||||
ctx.captions_size = 0.1f; | |||||
this->update_value_text_content(); | |||||
game::menu::align_text(ctx); | |||||
game::menu::update_text_tweens(ctx); | |||||
}; | |||||
auto select_back_callback = [&ctx]() | |||||
{ | |||||
// Disable controls | |||||
game::menu::clear_controls(ctx); | |||||
game::menu::fade_out | |||||
( | |||||
ctx, | |||||
[&ctx]() | |||||
{ | |||||
// Queue change to options menu state | |||||
ctx.function_queue.push | |||||
( | |||||
[&ctx]() | |||||
{ | |||||
ctx.state_machine.pop(); | |||||
ctx.state_machine.emplace(new game::state::options_menu(ctx)); | |||||
} | |||||
); | |||||
} | |||||
); | |||||
}; | |||||
// Build list of menu select callbacks | |||||
ctx.menu_select_callbacks.push_back(std::bind(increase_volume_callback, &ctx.master_volume)); | |||||
ctx.menu_select_callbacks.push_back(std::bind(increase_volume_callback, &ctx.ambience_volume)); | |||||
ctx.menu_select_callbacks.push_back(std::bind(increase_volume_callback, &ctx.effects_volume)); | |||||
ctx.menu_select_callbacks.push_back(toggle_mono_audio_callback); | |||||
ctx.menu_select_callbacks.push_back(toggle_captions_callback); | |||||
ctx.menu_select_callbacks.push_back(increase_captions_size_callback); | |||||
ctx.menu_select_callbacks.push_back(select_back_callback); | |||||
// Build list of menu left callbacks | |||||
ctx.menu_left_callbacks.push_back(std::bind(decrease_volume_callback, &ctx.master_volume)); | |||||
ctx.menu_left_callbacks.push_back(std::bind(decrease_volume_callback, &ctx.ambience_volume)); | |||||
ctx.menu_left_callbacks.push_back(std::bind(decrease_volume_callback, &ctx.effects_volume)); | |||||
ctx.menu_left_callbacks.push_back(toggle_mono_audio_callback); | |||||
ctx.menu_left_callbacks.push_back(toggle_captions_callback); | |||||
ctx.menu_left_callbacks.push_back(decrease_captions_size_callback); | |||||
ctx.menu_left_callbacks.push_back(nullptr); | |||||
// Build list of menu right callbacks | |||||
ctx.menu_right_callbacks.push_back(std::bind(increase_volume_callback, &ctx.master_volume)); | |||||
ctx.menu_right_callbacks.push_back(std::bind(increase_volume_callback, &ctx.ambience_volume)); | |||||
ctx.menu_right_callbacks.push_back(std::bind(increase_volume_callback, &ctx.effects_volume)); | |||||
ctx.menu_right_callbacks.push_back(toggle_mono_audio_callback); | |||||
ctx.menu_right_callbacks.push_back(toggle_captions_callback); | |||||
ctx.menu_right_callbacks.push_back(increase_captions_size_callback); | |||||
ctx.menu_right_callbacks.push_back(nullptr); | |||||
// Set menu back callback | |||||
ctx.menu_back_callback = select_back_callback; | |||||
// Queue menu control setup | |||||
ctx.function_queue.push(std::bind(game::menu::setup_controls, std::ref(ctx))); | |||||
// Fade in menu | |||||
game::menu::fade_in(ctx, nullptr); | |||||
ctx.logger->pop_task(EXIT_SUCCESS); | |||||
} | |||||
sound_menu::~sound_menu() | |||||
{ | |||||
ctx.logger->push_task("Exiting sound menu state"); | |||||
// Destruct menu | |||||
game::menu::clear_controls(ctx); | |||||
game::menu::clear_callbacks(ctx); | |||||
game::menu::delete_animations(ctx); | |||||
game::menu::remove_text_from_ui(ctx); | |||||
game::menu::delete_text(ctx); | |||||
// Update config | |||||
(*ctx.config)["master_volume"] = ctx.master_volume; | |||||
(*ctx.config)["ambience_volume"] = ctx.ambience_volume; | |||||
(*ctx.config)["effects_volume"] = ctx.effects_volume; | |||||
(*ctx.config)["mono_audio"] = ctx.mono_audio; | |||||
(*ctx.config)["captions"] = ctx.captions; | |||||
(*ctx.config)["captions_size"] = ctx.captions_size; | |||||
ctx.logger->pop_task(EXIT_SUCCESS); | |||||
} | |||||
void sound_menu::update_value_text_content() | |||||
{ | |||||
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(std::to_string(static_cast<int>(std::round(ctx.master_volume * 100.0f))) + "%"); | |||||
std::get<1>(ctx.menu_item_texts[1])->set_content(std::to_string(static_cast<int>(std::round(ctx.ambience_volume * 100.0f))) + "%"); | |||||
std::get<1>(ctx.menu_item_texts[2])->set_content(std::to_string(static_cast<int>(std::round(ctx.effects_volume * 100.0f))) + "%"); | |||||
std::get<1>(ctx.menu_item_texts[3])->set_content((ctx.mono_audio) ? string_on : string_off); | |||||
std::get<1>(ctx.menu_item_texts[4])->set_content((ctx.captions) ? string_on : string_off); | |||||
std::get<1>(ctx.menu_item_texts[5])->set_content(std::to_string(static_cast<int>(std::round(ctx.captions_size * 100.0f))) + "%"); | |||||
} | |||||
} // namespace state | |||||
} // namespace game |
@ -0,0 +1,170 @@ | |||||
/* | |||||
* 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "game/state/splash.hpp" | |||||
#include "game/state/main-menu.hpp" | |||||
#include "animation/screen-transition.hpp" | |||||
#include "animation/animation.hpp" | |||||
#include "animation/animator.hpp" | |||||
#include "animation/ease.hpp" | |||||
#include "application.hpp" | |||||
#include "render/passes/clear-pass.hpp" | |||||
#include "game/context.hpp" | |||||
#include "debug/logger.hpp" | |||||
namespace game { | |||||
namespace state { | |||||
splash::splash(game::context& ctx): | |||||
game::state::base(ctx) | |||||
{ | |||||
ctx.logger->push_task("Entering splash state"); | |||||
ctx.ui_clear_pass->set_cleared_buffers(true, true, false); | |||||
// Load animation timing configuration | |||||
double splash_fade_in_duration = 0.0; | |||||
double splash_duration = 0.0; | |||||
double splash_fade_out_duration = 0.0; | |||||
if (ctx.config->contains("splash_fade_in_duration")) | |||||
splash_fade_in_duration = (*ctx.config)["splash_fade_in_duration"].get<double>(); | |||||
if (ctx.config->contains("splash_duration")) | |||||
splash_duration = (*ctx.config)["splash_duration"].get<double>(); | |||||
if (ctx.config->contains("splash_fade_out_duration")) | |||||
splash_fade_out_duration = (*ctx.config)["splash_fade_out_duration"].get<double>(); | |||||
// Build splash fade in animation | |||||
ctx.splash_fade_in_animation = new animation<float>(); | |||||
animation_channel<float>* splash_fade_in_opacity_channel = ctx.splash_fade_in_animation->add_channel(0); | |||||
ctx.splash_fade_in_animation->set_interpolator(ease<float>::out_cubic); | |||||
splash_fade_in_opacity_channel->insert_keyframe({0.0, 0.0f}); | |||||
splash_fade_in_opacity_channel->insert_keyframe({splash_fade_in_duration, 1.0f}); | |||||
splash_fade_in_opacity_channel->insert_keyframe({splash_fade_in_duration + splash_duration, 1.0f}); | |||||
// Build splash fade out animation | |||||
ctx.splash_fade_out_animation = new animation<float>(); | |||||
animation_channel<float>* splash_fade_out_opacity_channel = ctx.splash_fade_out_animation->add_channel(0); | |||||
ctx.splash_fade_out_animation->set_interpolator(ease<float>::out_cubic); | |||||
splash_fade_out_opacity_channel->insert_keyframe({0.0, 1.0f}); | |||||
splash_fade_out_opacity_channel->insert_keyframe({splash_fade_out_duration, 0.0f}); | |||||
// Setup animation frame callbacks | |||||
auto set_splash_opacity = [&ctx](int channel, const float& opacity) | |||||
{ | |||||
static_cast<render::material_property<float4>*>(ctx.splash_billboard_material->get_property("tint"))->set_value(float4{1, 1, 1, opacity}); | |||||
}; | |||||
ctx.splash_fade_in_animation->set_frame_callback(set_splash_opacity); | |||||
ctx.splash_fade_out_animation->set_frame_callback(set_splash_opacity); | |||||
// Reset splash color when animation starts | |||||
ctx.splash_fade_in_animation->set_start_callback | |||||
( | |||||
[&ctx]() | |||||
{ | |||||
static_cast<render::material_property<float4>*>(ctx.splash_billboard_material->get_property("tint"))->set_value(float4{1, 1, 1, 0}); | |||||
ctx.splash_billboard_material->update_tweens(); | |||||
} | |||||
); | |||||
// Trigger splash fade out animation when splash fade in animation ends | |||||
ctx.splash_fade_in_animation->set_end_callback | |||||
( | |||||
[&ctx]() | |||||
{ | |||||
ctx.splash_fade_out_animation->play(); | |||||
} | |||||
); | |||||
// Trigger a state change when the splash fade out animation ends | |||||
ctx.splash_fade_out_animation->set_end_callback | |||||
( | |||||
[&ctx]() | |||||
{ | |||||
// Queue change to main menu state | |||||
ctx.function_queue.push | |||||
( | |||||
[&ctx]() | |||||
{ | |||||
ctx.state_machine.pop(); | |||||
ctx.state_machine.emplace(new game::state::main_menu(ctx, true)); | |||||
} | |||||
); | |||||
} | |||||
); | |||||
// Add splash fade animations to animator | |||||
ctx.animator->add_animation(ctx.splash_fade_in_animation); | |||||
ctx.animator->add_animation(ctx.splash_fade_out_animation); | |||||
// Start splash fade in animation | |||||
ctx.splash_fade_in_animation->play(); | |||||
// Set up splash skipper | |||||
ctx.input_listener->set_callback | |||||
( | |||||
[&ctx](const event_base& event) | |||||
{ | |||||
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) | |||||
{ | |||||
// Black out screen | |||||
ctx.rasterizer->set_clear_color(0.0f, 0.0f, 0.0f, 1.0f); | |||||
ctx.rasterizer->clear_framebuffer(true, false, false); | |||||
ctx.app->swap_buffers(); | |||||
// Change to main menu state | |||||
ctx.state_machine.pop(); | |||||
ctx.state_machine.emplace(new game::state::main_menu(ctx, true)); | |||||
} | |||||
} | |||||
); | |||||
ctx.input_listener->set_enabled(true); | |||||
// Add splash billboard to UI scene | |||||
ctx.ui_scene->add_object(ctx.splash_billboard); | |||||
ctx.logger->pop_task(EXIT_SUCCESS); | |||||
} | |||||
splash::~splash() | |||||
{ | |||||
ctx.logger->push_task("Exiting splash state"); | |||||
// Remove splash billboard from UI scene | |||||
ctx.ui_scene->remove_object(ctx.splash_billboard); | |||||
// Disable splash skipper | |||||
ctx.input_listener->set_enabled(false); | |||||
ctx.input_listener->set_callback(nullptr); | |||||
// Destruct splash fade animations | |||||
ctx.animator->remove_animation(ctx.splash_fade_in_animation); | |||||
ctx.animator->remove_animation(ctx.splash_fade_out_animation); | |||||
delete ctx.splash_fade_in_animation; | |||||
delete ctx.splash_fade_out_animation; | |||||
ctx.splash_fade_in_animation = nullptr; | |||||
ctx.splash_fade_out_animation = nullptr; | |||||
ctx.ui_clear_pass->set_cleared_buffers(false, true, false); | |||||
ctx.logger->pop_task(EXIT_SUCCESS); | |||||
} | |||||
} // namespace state | |||||
} // namespace game |
@ -1,137 +0,0 @@ | |||||
/* | |||||
* 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "game/states/credits.hpp" | |||||
#include "game/states/extras-menu.hpp" | |||||
#include "animation/ease.hpp" | |||||
#include "animation/animation.hpp" | |||||
#include "animation/animator.hpp" | |||||
#include "application.hpp" | |||||
#include "scene/text.hpp" | |||||
namespace game { | |||||
namespace state { | |||||
namespace credits { | |||||
void enter(game::context* ctx) | |||||
{ | |||||
// Construct credits text | |||||
ctx->credits_text = new scene::text(); | |||||
ctx->credits_text->set_material(&ctx->menu_font_material); | |||||
ctx->credits_text->set_font(&ctx->menu_font); | |||||
ctx->credits_text->set_color({1.0f, 1.0f, 1.0f, 0.0f}); | |||||
ctx->credits_text->set_content((*ctx->strings)["credits"]); | |||||
// Align credits text | |||||
const auto& credits_aabb = static_cast<const geom::aabb<float>&>(ctx->credits_text->get_local_bounds()); | |||||
float credits_w = credits_aabb.max_point.x - credits_aabb.min_point.x; | |||||
float credits_h = credits_aabb.max_point.y - credits_aabb.min_point.y; | |||||
ctx->credits_text->set_translation({std::round(-credits_w * 0.5f), std::round(-credits_h * 0.5f), 0.0f}); | |||||
// Load animation timing configuration | |||||
double credits_fade_in_duration = 0.0; | |||||
double credits_scroll_duration = 0.0; | |||||
if (ctx->config->contains("credits_fade_in_duration")) | |||||
credits_fade_in_duration = (*ctx->config)["credits_fade_in_duration"].get<double>(); | |||||
if (ctx->config->contains("credits_scroll_duration")) | |||||
credits_scroll_duration = (*ctx->config)["credits_scroll_duration"].get<double>(); | |||||
auto set_credits_opacity = [ctx](int channel, const float& opacity) | |||||
{ | |||||
ctx->credits_text->set_color({1.0f, 1.0f, 1.0f, opacity}); | |||||
}; | |||||
// Build credits fade in animation | |||||
ctx->credits_fade_in_animation = new animation<float>(); | |||||
animation_channel<float>* credits_fade_in_opacity_channel = ctx->credits_fade_in_animation->add_channel(0); | |||||
ctx->credits_fade_in_animation->set_interpolator(ease<float>::in_quad); | |||||
credits_fade_in_opacity_channel->insert_keyframe({0.0, 0.0f}); | |||||
credits_fade_in_opacity_channel->insert_keyframe({credits_fade_in_duration, 1.0f}); | |||||
ctx->credits_fade_in_animation->set_frame_callback(set_credits_opacity); | |||||
// Build credits scroll in animation | |||||
ctx->credits_scroll_animation = new animation<float>(); | |||||
// Trigger credits scroll animation after credits fade in animation ends | |||||
ctx->credits_fade_in_animation->set_end_callback | |||||
( | |||||
[ctx]() | |||||
{ | |||||
ctx->credits_scroll_animation->play(); | |||||
} | |||||
); | |||||
// Add credits animations to animator | |||||
ctx->animator->add_animation(ctx->credits_fade_in_animation); | |||||
ctx->animator->add_animation(ctx->credits_scroll_animation); | |||||
// Start credits fade in animation | |||||
ctx->credits_fade_in_animation->play(); | |||||
// Set up credits skipper | |||||
ctx->input_listener->set_callback | |||||
( | |||||
[ctx](const event_base& event) | |||||
{ | |||||
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); | |||||
// Change state | |||||
application::state next_state; | |||||
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->queue_state(next_state); | |||||
} | |||||
} | |||||
} | |||||
); | |||||
ctx->input_listener->set_enabled(true); | |||||
ctx->ui_scene->add_object(ctx->credits_text); | |||||
ctx->credits_text->update_tweens(); | |||||
} | |||||
void exit(game::context* ctx) | |||||
{ | |||||
// Disable credits skipper | |||||
ctx->input_listener->set_enabled(false); | |||||
ctx->input_listener->set_callback(nullptr); | |||||
// Destruct credits text | |||||
ctx->ui_scene->remove_object(ctx->credits_text); | |||||
delete ctx->credits_text; | |||||
ctx->credits_text = nullptr; | |||||
// Destruct credits animations | |||||
ctx->animator->remove_animation(ctx->credits_fade_in_animation); | |||||
ctx->animator->remove_animation(ctx->credits_scroll_animation); | |||||
delete ctx->credits_fade_in_animation; | |||||
delete ctx->credits_scroll_animation; | |||||
ctx->credits_fade_in_animation = nullptr; | |||||
ctx->credits_scroll_animation = nullptr; | |||||
} | |||||
} // namespace credits | |||||
} // namespace state | |||||
} // namespace game |
@ -1,346 +0,0 @@ | |||||
/* | |||||
* 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "game/states/graphics-menu.hpp" | |||||
#include "game/states/options-menu.hpp" | |||||
#include "application.hpp" | |||||
#include "scene/text.hpp" | |||||
#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); | |||||
void enter(game::context* ctx) | |||||
{ | |||||
// Construct menu item texts | |||||
scene::text* fullscreen_name_text = new scene::text(); | |||||
scene::text* fullscreen_value_text = new scene::text(); | |||||
scene::text* resolution_name_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_value_text = new scene::text(); | |||||
scene::text* font_size_name_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_value_text = new scene::text(); | |||||
scene::text* back_text = new scene::text(); | |||||
// Build list of menu item texts | |||||
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({v_sync_name_text, v_sync_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({back_text, nullptr}); | |||||
// Set content of menu item texts | |||||
fullscreen_name_text->set_content((*ctx->strings)["graphics_menu_fullscreen"]); | |||||
resolution_name_text->set_content((*ctx->strings)["graphics_menu_resolution"]); | |||||
v_sync_name_text->set_content((*ctx->strings)["graphics_menu_v_sync"]); | |||||
font_size_name_text->set_content((*ctx->strings)["graphics_menu_font_size"]); | |||||
dyslexia_font_name_text->set_content((*ctx->strings)["graphics_menu_dyslexia_font"]); | |||||
back_text->set_content((*ctx->strings)["back"]); | |||||
update_value_text_content(ctx); | |||||
// Init menu item index | |||||
game::menu::init_menu_item_index(ctx, "graphics"); | |||||
game::menu::update_text_color(ctx); | |||||
game::menu::update_text_font(ctx); | |||||
game::menu::align_text(ctx); | |||||
game::menu::update_text_tweens(ctx); | |||||
game::menu::add_text_to_ui(ctx); | |||||
game::menu::setup_animations(ctx); | |||||
// Construct menu item callbacks | |||||
auto toggle_fullscreen_callback = [ctx]() | |||||
{ | |||||
bool fullscreen = !ctx->app->is_fullscreen(); | |||||
ctx->app->set_fullscreen(fullscreen); | |||||
if (!fullscreen) | |||||
{ | |||||
int2 resolution; | |||||
resolution.x = (*ctx->config)["windowed_resolution"][0].get<int>(); | |||||
resolution.y = (*ctx->config)["windowed_resolution"][1].get<int>(); | |||||
ctx->app->resize_window(resolution.x, resolution.y); | |||||
} | |||||
update_value_text_content(ctx); | |||||
game::menu::align_text(ctx); | |||||
game::menu::update_text_tweens(ctx); | |||||
// Save display mode config | |||||
(*ctx->config)["fullscreen"] = fullscreen; | |||||
}; | |||||
auto increase_resolution_callback = [ctx]() | |||||
{ | |||||
// Increase resolution | |||||
if (ctx->controls["menu_modifier"]->is_active()) | |||||
ctx->render_resolution_scale += 0.05f; | |||||
else | |||||
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); | |||||
// Update config | |||||
(*ctx->config)["render_resolution"] = ctx->render_resolution_scale; | |||||
}; | |||||
auto decrease_resolution_callback = [ctx]() | |||||
{ | |||||
// Increase resolution | |||||
if (ctx->controls["menu_modifier"]->is_active()) | |||||
ctx->render_resolution_scale -= 0.05f; | |||||
else | |||||
ctx->render_resolution_scale -= 0.25f; | |||||
// Limit resolution | |||||
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); | |||||
// Update config | |||||
(*ctx->config)["render_resolution"] = ctx->render_resolution_scale; | |||||
}; | |||||
auto toggle_v_sync_callback = [ctx]() | |||||
{ | |||||
bool v_sync = !ctx->app->get_v_sync(); | |||||
ctx->app->set_v_sync(v_sync); | |||||
update_value_text_content(ctx); | |||||
game::menu::align_text(ctx); | |||||
game::menu::update_text_tweens(ctx); | |||||
// Save v-sync config | |||||
(*ctx->config)["v_sync"] = v_sync; | |||||
}; | |||||
auto increase_font_size_callback = [ctx]() | |||||
{ | |||||
// Increase font size | |||||
if (ctx->controls["menu_modifier"]->is_active()) | |||||
ctx->font_size += 0.01f; | |||||
else | |||||
ctx->font_size += 0.1f; | |||||
// Limit font size | |||||
if (ctx->font_size > 2.0f) | |||||
ctx->font_size = 2.0f; | |||||
// Update value text | |||||
update_value_text_content(ctx); | |||||
// Update config | |||||
(*ctx->config)["font_size"] = ctx->font_size; | |||||
// Reload fonts | |||||
ctx->logger->push_task("Reloading fonts"); | |||||
try | |||||
{ | |||||
game::load_fonts(ctx); | |||||
} | |||||
catch (...) | |||||
{ | |||||
ctx->logger->pop_task(EXIT_FAILURE); | |||||
} | |||||
ctx->logger->pop_task(EXIT_SUCCESS); | |||||
// Refresh and realign text | |||||
game::menu::refresh_text(ctx); | |||||
game::menu::align_text(ctx); | |||||
game::menu::update_text_tweens(ctx); | |||||
}; | |||||
auto decrease_font_size_callback = [ctx]() | |||||
{ | |||||
// Decrease font size | |||||
if (ctx->controls["menu_modifier"]->is_active()) | |||||
ctx->font_size -= 0.01f; | |||||
else | |||||
ctx->font_size -= 0.1f; | |||||
// Limit font size | |||||
if (ctx->font_size < 0.1f) | |||||
ctx->font_size = 0.1f; | |||||
// Update value text | |||||
update_value_text_content(ctx); | |||||
// Update config | |||||
(*ctx->config)["font_size"] = ctx->font_size; | |||||
// Reload fonts | |||||
ctx->logger->push_task("Reloading fonts"); | |||||
try | |||||
{ | |||||
game::load_fonts(ctx); | |||||
} | |||||
catch (...) | |||||
{ | |||||
ctx->logger->pop_task(EXIT_FAILURE); | |||||
} | |||||
ctx->logger->pop_task(EXIT_SUCCESS); | |||||
// Refresh and realign text | |||||
game::menu::refresh_text(ctx); | |||||
game::menu::align_text(ctx); | |||||
game::menu::update_text_tweens(ctx); | |||||
}; | |||||
auto toggle_dyslexia_font_callback = [ctx]() | |||||
{ | |||||
ctx->dyslexia_font = !ctx->dyslexia_font; | |||||
// Update value text | |||||
update_value_text_content(ctx); | |||||
// Save dyslexia font config | |||||
(*ctx->config)["dyslexia_font"] = ctx->dyslexia_font; | |||||
// Reload fonts | |||||
ctx->logger->push_task("Reloading fonts"); | |||||
try | |||||
{ | |||||
game::load_fonts(ctx); | |||||
} | |||||
catch (...) | |||||
{ | |||||
ctx->logger->pop_task(EXIT_FAILURE); | |||||
} | |||||
ctx->logger->pop_task(EXIT_SUCCESS); | |||||
// Refresh and realign text | |||||
game::menu::refresh_text(ctx); | |||||
game::menu::align_text(ctx); | |||||
game::menu::update_text_tweens(ctx); | |||||
}; | |||||
auto select_back_callback = [ctx]() | |||||
{ | |||||
// Disable controls | |||||
game::menu::clear_controls(ctx); | |||||
game::menu::fade_out | |||||
( | |||||
ctx, | |||||
[ctx]() | |||||
{ | |||||
application::state next_state; | |||||
next_state.name = "options_menu"; | |||||
next_state.enter = std::bind(game::state::options_menu::enter, ctx); | |||||
next_state.exit = std::bind(game::state::options_menu::exit, ctx); | |||||
ctx->app->queue_state(next_state); | |||||
} | |||||
); | |||||
}; | |||||
// Build list of menu select callbacks | |||||
ctx->menu_select_callbacks.push_back(toggle_fullscreen_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(increase_font_size_callback); | |||||
ctx->menu_select_callbacks.push_back(toggle_dyslexia_font_callback); | |||||
ctx->menu_select_callbacks.push_back(select_back_callback); | |||||
// Build list of menu left callbacks | |||||
ctx->menu_left_callbacks.push_back(toggle_fullscreen_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(decrease_font_size_callback); | |||||
ctx->menu_left_callbacks.push_back(toggle_dyslexia_font_callback); | |||||
ctx->menu_left_callbacks.push_back(nullptr); | |||||
// Build list of menu right callbacks | |||||
ctx->menu_right_callbacks.push_back(toggle_fullscreen_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(increase_font_size_callback); | |||||
ctx->menu_right_callbacks.push_back(toggle_dyslexia_font_callback); | |||||
ctx->menu_right_callbacks.push_back(nullptr); | |||||
// Set menu back callback | |||||
ctx->menu_back_callback = select_back_callback; | |||||
// Queue menu control setup | |||||
ctx->function_queue.push(std::bind(game::menu::setup_controls, ctx)); | |||||
// Fade in menu | |||||
game::menu::fade_in(ctx, nullptr); | |||||
} | |||||
void exit(game::context* ctx) | |||||
{ | |||||
// Destruct menu | |||||
game::menu::clear_controls(ctx); | |||||
game::menu::clear_callbacks(ctx); | |||||
game::menu::delete_animations(ctx); | |||||
game::menu::remove_text_from_ui(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<int>(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<int>(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 |
@ -1,265 +0,0 @@ | |||||
/* | |||||
* 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "game/states/main-menu.hpp" | |||||
#include "game/states/options-menu.hpp" | |||||
#include "game/states/extras-menu.hpp" | |||||
#include "game/states/forage.hpp" | |||||
#include "game/states/nuptial-flight.hpp" | |||||
#include "game/menu.hpp" | |||||
#include "render/passes/clear-pass.hpp" | |||||
#include "resources/resource-manager.hpp" | |||||
#include "render/model.hpp" | |||||
#include "animation/animation.hpp" | |||||
#include "animation/animator.hpp" | |||||
#include "animation/screen-transition.hpp" | |||||
#include "animation/ease.hpp" | |||||
#include "animation/timeline.hpp" | |||||
#include "application.hpp" | |||||
#include <limits> | |||||
namespace game { | |||||
namespace state { | |||||
namespace main_menu { | |||||
static void fade_in_title(game::context* ctx) | |||||
{ | |||||
ctx->title_fade_animation->set_interpolator(ease<float>::out_cubic); | |||||
animation_channel<float>* opacity_channel = ctx->title_fade_animation->get_channel(0); | |||||
opacity_channel->remove_keyframes(); | |||||
opacity_channel->insert_keyframe({0.0, 0.0f}); | |||||
opacity_channel->insert_keyframe({game::menu::fade_in_duration, 1.0f}); | |||||
ctx->title_fade_animation->stop(); | |||||
ctx->title_fade_animation->play(); | |||||
} | |||||
static void fade_out_title(game::context* ctx) | |||||
{ | |||||
ctx->title_fade_animation->set_interpolator(ease<float>::out_cubic); | |||||
animation_channel<float>* opacity_channel = ctx->title_fade_animation->get_channel(0); | |||||
opacity_channel->remove_keyframes(); | |||||
opacity_channel->insert_keyframe({0.0, 1.0f}); | |||||
opacity_channel->insert_keyframe({game::menu::fade_out_duration, 0.0f}); | |||||
ctx->title_fade_animation->stop(); | |||||
ctx->title_fade_animation->play(); | |||||
} | |||||
void enter(game::context* ctx, bool fade_in) | |||||
{ | |||||
ctx->ui_clear_pass->set_cleared_buffers(true, true, false); | |||||
// Construct title text | |||||
ctx->title_text = new scene::text(); | |||||
ctx->title_text->set_material(&ctx->title_font_material); | |||||
ctx->title_text->set_font(&ctx->title_font); | |||||
ctx->title_text->set_color({1.0f, 1.0f, 1.0f, 1.0f}); | |||||
ctx->title_text->set_content((*ctx->strings)["title_antkeeper"]); | |||||
// Align title text | |||||
const auto& title_aabb = static_cast<const geom::aabb<float>&>(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 + (ctx->app->get_viewport_dimensions().y / 3.0f) / 2.0f), 0.0f}); | |||||
ctx->title_text->update_tweens(); | |||||
// Add title text to UI | |||||
ctx->ui_scene->add_object(ctx->title_text); | |||||
// Construct title fade animation | |||||
ctx->title_fade_animation = new animation<float>(); | |||||
animation_channel<float>* opacity_channel = ctx->title_fade_animation->add_channel(0); | |||||
ctx->title_fade_animation->set_frame_callback | |||||
( | |||||
[ctx](int channel, const float& opacity) | |||||
{ | |||||
float4 color = ctx->title_text->get_color(); | |||||
color[3] = opacity; | |||||
ctx->title_text->set_color(color); | |||||
} | |||||
); | |||||
ctx->animator->add_animation(ctx->title_fade_animation); | |||||
// Construct menu item texts | |||||
scene::text* start_text = new scene::text(); | |||||
scene::text* options_text = new scene::text(); | |||||
scene::text* extras_text = new scene::text(); | |||||
scene::text* quit_text = new scene::text(); | |||||
// Build list of menu item texts | |||||
ctx->menu_item_texts.push_back({start_text, nullptr}); | |||||
ctx->menu_item_texts.push_back({options_text, nullptr}); | |||||
ctx->menu_item_texts.push_back({extras_text, nullptr}); | |||||
ctx->menu_item_texts.push_back({quit_text, nullptr}); | |||||
// Set content of menu item texts | |||||
start_text->set_content((*ctx->strings)["main_menu_start"]); | |||||
options_text->set_content((*ctx->strings)["main_menu_options"]); | |||||
extras_text->set_content((*ctx->strings)["main_menu_extras"]); | |||||
quit_text->set_content((*ctx->strings)["main_menu_quit"]); | |||||
// Init menu item index | |||||
game::menu::init_menu_item_index(ctx, "main"); | |||||
game::menu::update_text_color(ctx); | |||||
game::menu::update_text_font(ctx); | |||||
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); | |||||
auto select_start_callback = [ctx]() | |||||
{ | |||||
// Disable controls and menu callbacks | |||||
game::menu::clear_controls(ctx); | |||||
game::menu::clear_callbacks(ctx); | |||||
// Create change state function | |||||
auto change_state_nuptial_flight = [ctx]() | |||||
{ | |||||
application::state next_state; | |||||
next_state.name = "nuptial_flight"; | |||||
next_state.enter = std::bind(game::state::nuptial_flight::enter, ctx); | |||||
next_state.exit = std::bind(game::state::nuptial_flight::exit, ctx); | |||||
ctx->app->change_state(next_state); | |||||
}; | |||||
// Set up timing | |||||
const float fade_out_duration = 1.0f; | |||||
// Schedule state change | |||||
timeline* timeline = ctx->timeline; | |||||
float t = timeline->get_position(); | |||||
timeline->add_sequence({{t + fade_out_duration, change_state_nuptial_flight}}); | |||||
// Start fade out to white | |||||
ctx->fade_transition_color->set_value({1, 1, 1}); | |||||
ctx->fade_transition->transition(fade_out_duration, false, ease<float>::out_cubic, false); | |||||
}; | |||||
auto select_options_callback = [ctx]() | |||||
{ | |||||
game::menu::clear_controls(ctx); | |||||
// Fade out title | |||||
fade_out_title(ctx); | |||||
// Fade out menu | |||||
game::menu::fade_out | |||||
( | |||||
ctx, | |||||
[ctx]() | |||||
{ | |||||
application::state next_state; | |||||
next_state.name = "options_menu"; | |||||
next_state.enter = std::bind(game::state::options_menu::enter, ctx); | |||||
next_state.exit = std::bind(game::state::options_menu::exit, ctx); | |||||
ctx->app->queue_state(next_state); | |||||
} | |||||
); | |||||
}; | |||||
auto select_extras_callback = [ctx]() | |||||
{ | |||||
// Disable controls | |||||
game::menu::clear_controls(ctx); | |||||
// Fade out title | |||||
fade_out_title(ctx); | |||||
// Fade out menu | |||||
game::menu::fade_out | |||||
( | |||||
ctx, | |||||
[ctx]() | |||||
{ | |||||
application::state next_state; | |||||
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->queue_state(next_state); | |||||
} | |||||
); | |||||
}; | |||||
auto select_quit_callback = [ctx]() | |||||
{ | |||||
ctx->app->close(EXIT_SUCCESS); | |||||
}; | |||||
// Build list of menu select callbacks | |||||
ctx->menu_select_callbacks.push_back(select_start_callback); | |||||
ctx->menu_select_callbacks.push_back(select_options_callback); | |||||
ctx->menu_select_callbacks.push_back(select_extras_callback); | |||||
ctx->menu_select_callbacks.push_back(select_quit_callback); | |||||
// Build list of menu left callbacks | |||||
ctx->menu_left_callbacks.push_back(nullptr); | |||||
ctx->menu_left_callbacks.push_back(nullptr); | |||||
ctx->menu_left_callbacks.push_back(nullptr); | |||||
ctx->menu_left_callbacks.push_back(nullptr); | |||||
// Build list of menu right callbacks | |||||
ctx->menu_right_callbacks.push_back(nullptr); | |||||
ctx->menu_right_callbacks.push_back(nullptr); | |||||
ctx->menu_right_callbacks.push_back(nullptr); | |||||
ctx->menu_right_callbacks.push_back(nullptr); | |||||
// Set menu back callback | |||||
ctx->menu_back_callback = select_quit_callback; | |||||
// Queue menu control setup | |||||
ctx->function_queue.push(std::bind(game::menu::setup_controls, ctx)); | |||||
if (fade_in) | |||||
{ | |||||
ctx->fade_transition->transition(0.5f, true, ease<float>::out_cubic); | |||||
} | |||||
else | |||||
{ | |||||
// Fade in title | |||||
ctx->title_text->set_color({1.0f, 1.0f, 1.0f, 0.0f}); | |||||
ctx->title_text->update_tweens(); | |||||
fade_in_title(ctx); | |||||
// Fade in menu | |||||
game::menu::fade_in(ctx, nullptr); | |||||
} | |||||
} | |||||
void exit(game::context* ctx) | |||||
{ | |||||
// Destruct menu | |||||
game::menu::clear_controls(ctx); | |||||
game::menu::clear_callbacks(ctx); | |||||
game::menu::delete_animations(ctx); | |||||
game::menu::remove_text_from_ui(ctx); | |||||
game::menu::delete_text(ctx); | |||||
// Destruct title animation | |||||
ctx->animator->remove_animation(ctx->title_fade_animation); | |||||
delete ctx->title_fade_animation; | |||||
ctx->title_fade_animation = nullptr; | |||||
// Destruct title text | |||||
ctx->ui_scene->remove_object(ctx->title_text); | |||||
delete ctx->title_text; | |||||
ctx->title_text = nullptr; | |||||
} | |||||
} // namespace main_menu | |||||
} // namespace state | |||||
} // namespace game |
@ -1,557 +0,0 @@ | |||||
/* | |||||
* 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "game/states/nuptial-flight.hpp" | |||||
#include "game/states/pause-menu.hpp" | |||||
#include "entity/archetype.hpp" | |||||
#include "entity/systems/astronomy.hpp" | |||||
#include "entity/systems/orbit.hpp" | |||||
#include "entity/systems/camera.hpp" | |||||
#include "entity/components/observer.hpp" | |||||
#include "entity/components/transform.hpp" | |||||
#include "entity/components/terrain.hpp" | |||||
#include "entity/components/camera.hpp" | |||||
#include "entity/components/constraints/spring-to.hpp" | |||||
#include "entity/components/constraints/three-dof.hpp" | |||||
#include "entity/components/constraint-stack.hpp" | |||||
#include "entity/commands.hpp" | |||||
#include "animation/screen-transition.hpp" | |||||
#include "animation/ease.hpp" | |||||
#include "resources/resource-manager.hpp" | |||||
#include "game/world.hpp" | |||||
#include "application.hpp" | |||||
#include "render/passes/clear-pass.hpp" | |||||
#include <memory> | |||||
#include <iostream> | |||||
#include "state-machine.hpp" | |||||
namespace game { | |||||
namespace state { | |||||
namespace nuptial_flight { | |||||
static void setup_camera(game::context* ctx); | |||||
static void enable_controls(game::context* ctx); | |||||
static void disable_controls(game::context* ctx); | |||||
void enter(game::context* ctx) | |||||
{ | |||||
// Resume if paused | |||||
if (ctx->paused_state) | |||||
{ | |||||
// Clear paused state | |||||
ctx->paused_state.reset(); | |||||
// Enable controls | |||||
enable_controls(ctx); | |||||
return; | |||||
} | |||||
// Disable UI color clear | |||||
ctx->ui_clear_pass->set_cleared_buffers(false, true, false); | |||||
// Create world | |||||
game::world::create_stars(ctx); | |||||
game::world::create_sun(ctx); | |||||
game::world::create_planet(ctx); | |||||
game::world::create_moon(ctx); | |||||
// Set time to solar noon | |||||
game::world::set_time(ctx, 0.0); | |||||
// Freeze time | |||||
game::world::set_time_scale(ctx, 0.0); | |||||
// Switch to surface camera | |||||
ctx->underground_camera->set_active(false); | |||||
ctx->surface_camera->set_active(true); | |||||
// Find planet EID by name | |||||
entity::id planet_eid = ctx->entities["planet"]; | |||||
// Remove terrain component from planet (if any) | |||||
//if (ctx->entity_registry->has<entity::component::terrain>(planet_eid)) | |||||
// ctx->entity_registry->remove<entity::component::terrain>(planet_eid); | |||||
// Enable clouds in sky pass | |||||
//ctx->surface_sky_pass->set_clouds_model(ctx->resource_manager->load<render::model>("cloud-plane.mdl")); | |||||
// Create observer | |||||
entity::id observer_eid = ctx->entity_registry->create(); | |||||
{ | |||||
entity::component::observer observer; | |||||
observer.reference_body_eid = planet_eid; | |||||
observer.elevation = 2000.0; | |||||
observer.latitude = 0.0; | |||||
observer.longitude = 0.0; | |||||
observer.camera = ctx->surface_camera; | |||||
ctx->entity_registry->assign<entity::component::observer>(observer_eid, observer); | |||||
// Set reference location of astronomy system | |||||
ctx->astronomy_system->set_reference_body(planet_eid); | |||||
ctx->astronomy_system->set_observer_location(double3{observer.elevation, observer.latitude, observer.longitude}); | |||||
} | |||||
// Setup camera | |||||
setup_camera(ctx); | |||||
/* | |||||
ctx->surface_camera->look_at({0, 0, 1}, {0, 0, 0}, {0, 1, 0}); | |||||
ctx->surface_camera->set_exposure(-14.5f); | |||||
ctx->surface_scene->update_tweens(); | |||||
*/ | |||||
// Queue fade in | |||||
ctx->fade_transition_color->set_value({1, 1, 1}); | |||||
ctx->function_queue.push(std::bind(&screen_transition::transition, ctx->fade_transition, 5.0f, true, math::lerp<float, float>, true)); | |||||
// Queue control setup | |||||
ctx->function_queue.push(std::bind(enable_controls, ctx)); | |||||
} | |||||
void exit(game::context* ctx) | |||||
{ | |||||
// Resume time | |||||
//const double time_scale = (*ctx->config)["time_scale"].get<double>(); | |||||
//game::world::set_time_scale(ctx, time_scale); | |||||
} | |||||
void setup_camera(game::context* ctx) | |||||
{ | |||||
// Switch to surface camera | |||||
ctx->underground_camera->set_active(false); | |||||
ctx->surface_camera->set_active(true); | |||||
// Create surface camera entity | |||||
if (!ctx->entities.count("surface_cam")) | |||||
{ | |||||
// Create camera target entity | |||||
entity::id target_eid = ctx->entity_registry->create(); | |||||
ctx->entities["surface_cam_target"] = target_eid; | |||||
{ | |||||
// Transform | |||||
entity::component::transform target_transform; | |||||
target_transform.local = math::identity_transform<float>; | |||||
target_transform.world = target_transform.local; | |||||
target_transform.warp = true; | |||||
ctx->entity_registry->assign<entity::component::transform>(target_eid, target_transform); | |||||
} | |||||
// Create camera entity | |||||
entity::id camera_eid = ctx->entity_registry->create(); | |||||
ctx->entities["surface_cam"] = camera_eid; | |||||
// Create camera transform component | |||||
entity::component::transform transform; | |||||
transform.local = math::identity_transform<float>; | |||||
transform.world = transform.local; | |||||
transform.warp = true; | |||||
ctx->entity_registry->assign<entity::component::transform>(camera_eid, transform); | |||||
// Create camera camera component | |||||
entity::component::camera camera; | |||||
camera.object = ctx->surface_camera; | |||||
ctx->entity_registry->assign<entity::component::camera>(camera_eid, camera); | |||||
// Create camera 3DOF constraint entity | |||||
entity::id three_dof_constraint_eid = ctx->entity_registry->create(); | |||||
ctx->entities["surface_cam_3dof"] = three_dof_constraint_eid; | |||||
{ | |||||
// Create 3DOF to constraint | |||||
entity::component::constraint::three_dof three_dof; | |||||
three_dof.yaw = 0.0f; | |||||
three_dof.pitch = 0.0f; | |||||
three_dof.roll = 0.0f; | |||||
ctx->entity_registry->assign<entity::component::constraint::three_dof>(three_dof_constraint_eid, three_dof); | |||||
// Create constraint stack node component | |||||
entity::component::constraint_stack_node node; | |||||
node.active = true; | |||||
node.weight = 1.0f; | |||||
node.next = entt::null; | |||||
ctx->entity_registry->assign<entity::component::constraint_stack_node>(three_dof_constraint_eid, node); | |||||
} | |||||
// Create camera spring to constraint entity | |||||
entity::id spring_constraint_eid = ctx->entity_registry->create(); | |||||
{ | |||||
// Create spring to constraint | |||||
entity::component::constraint::spring_to spring; | |||||
spring.target = target_eid; | |||||
spring.translation = {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}, 1.0f, math::two_pi<float>}; | |||||
spring.translation.w = hz_to_rads(8.0f); | |||||
spring.spring_translation = true; | |||||
spring.spring_rotation = false; | |||||
ctx->entity_registry->assign<entity::component::constraint::spring_to>(spring_constraint_eid, spring); | |||||
// Create constraint stack node component | |||||
entity::component::constraint_stack_node node; | |||||
node.active = true; | |||||
node.weight = 1.0f; | |||||
node.next = three_dof_constraint_eid; | |||||
ctx->entity_registry->assign<entity::component::constraint_stack_node>(spring_constraint_eid, node); | |||||
} | |||||
// Create camera constraint stack component | |||||
entity::component::constraint_stack constraint_stack; | |||||
constraint_stack.head = spring_constraint_eid; | |||||
ctx->entity_registry->assign<entity::component::constraint_stack>(camera_eid, constraint_stack); | |||||
} | |||||
ctx->surface_camera->set_exposure(-12.0f); | |||||
} | |||||
void enable_controls(game::context* ctx) | |||||
{ | |||||
// Get camera entities | |||||
entity::id camera_eid = ctx->entities["surface_cam"]; | |||||
entity::id target_eid = ctx->entities["surface_cam_target"]; | |||||
entity::id three_dof_eid = ctx->entities["surface_cam_3dof"]; | |||||
const float slow_modifier = 0.25f; | |||||
const float fast_modifier = 4.0f; | |||||
const float dolly_speed = 20.0f; | |||||
const float truck_speed = dolly_speed; | |||||
const float pedestal_speed = 30.0f; | |||||
float mouse_tilt_sensitivity = 1.0f; | |||||
float mouse_pan_sensitivity = 1.0f; | |||||
bool mouse_invert_tilt = false; | |||||
bool mouse_invert_pan = false; | |||||
float gamepad_tilt_sensitivity = 1.0f; | |||||
float gamepad_pan_sensitivity = 1.0f; | |||||
bool gamepad_invert_tilt = false; | |||||
bool gamepad_invert_pan = false; | |||||
bool mouse_look_toggle = false; | |||||
ctx->mouse_look = false; | |||||
if (ctx->config->contains("mouse_tilt_sensitivity")) | |||||
mouse_tilt_sensitivity = math::radians((*ctx->config)["mouse_tilt_sensitivity"].get<float>()); | |||||
if (ctx->config->contains("mouse_pan_sensitivity")) | |||||
mouse_pan_sensitivity = math::radians((*ctx->config)["mouse_pan_sensitivity"].get<float>()); | |||||
if (ctx->config->contains("mouse_invert_tilt")) | |||||
mouse_invert_tilt = math::radians((*ctx->config)["mouse_invert_tilt"].get<bool>()); | |||||
if (ctx->config->contains("mouse_invert_pan")) | |||||
mouse_invert_pan = math::radians((*ctx->config)["mouse_invert_pan"].get<bool>()); | |||||
if (ctx->config->contains("mouse_look_toggle")) | |||||
mouse_look_toggle = math::radians((*ctx->config)["mouse_look_toggle"].get<bool>()); | |||||
if (ctx->config->contains("gamepad_tilt_sensitivity")) | |||||
gamepad_tilt_sensitivity = math::radians((*ctx->config)["gamepad_tilt_sensitivity"].get<float>()); | |||||
if (ctx->config->contains("gamepad_pan_sensitivity")) | |||||
gamepad_pan_sensitivity = math::radians((*ctx->config)["gamepad_pan_sensitivity"].get<float>()); | |||||
if (ctx->config->contains("gamepad_invert_tilt")) | |||||
gamepad_invert_tilt = math::radians((*ctx->config)["gamepad_invert_tilt"].get<bool>()); | |||||
if (ctx->config->contains("gamepad_invert_pan")) | |||||
gamepad_invert_pan = math::radians((*ctx->config)["gamepad_invert_pan"].get<bool>()); | |||||
const input::control* move_slow = ctx->controls["move_slow"]; | |||||
const input::control* move_fast = ctx->controls["move_fast"]; | |||||
const input::control* mouse_look = ctx->controls["mouse_look"]; | |||||
float mouse_tilt_factor = mouse_tilt_sensitivity * (mouse_invert_tilt ? -1.0f : 1.0f); | |||||
float mouse_pan_factor = mouse_pan_sensitivity * (mouse_invert_pan ? -1.0f : 1.0f); | |||||
float gamepad_tilt_factor = gamepad_tilt_sensitivity * (gamepad_invert_tilt ? -1.0f : 1.0f); | |||||
float gamepad_pan_factor = gamepad_pan_sensitivity * (gamepad_invert_pan ? -1.0f : 1.0f); | |||||
ctx->controls["move_forward"]->set_active_callback | |||||
( | |||||
[ctx, target_eid, three_dof_eid, truck_speed, move_slow, move_fast, slow_modifier, fast_modifier](float value) | |||||
{ | |||||
if (move_slow->is_active()) | |||||
value *= slow_modifier; | |||||
if (move_fast->is_active()) | |||||
value *= fast_modifier; | |||||
auto& three_dof = ctx->entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid); | |||||
const math::quaternion<float> yaw = math::angle_axis(three_dof.yaw, {0.0f, 1.0f, 0.0f}); | |||||
const float3 movement = {0.0f, 0.0f, -truck_speed * value * (1.0f / 60.0f)}; | |||||
entity::command::translate(*ctx->entity_registry, target_eid, yaw * movement); | |||||
} | |||||
); | |||||
// Dolly backward | |||||
ctx->controls["move_back"]->set_active_callback | |||||
( | |||||
[ctx, target_eid, three_dof_eid, truck_speed, move_slow, move_fast, slow_modifier, fast_modifier](float value) | |||||
{ | |||||
if (move_slow->is_active()) | |||||
value *= slow_modifier; | |||||
if (move_fast->is_active()) | |||||
value *= fast_modifier; | |||||
auto& three_dof = ctx->entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid); | |||||
const math::quaternion<float> yaw = math::angle_axis(three_dof.yaw, {0.0f, 1.0f, 0.0f}); | |||||
const float3 movement = {0.0f, 0.0f, truck_speed * value * (1.0f / 60.0f)}; | |||||
entity::command::translate(*ctx->entity_registry, target_eid, yaw * movement); | |||||
} | |||||
); | |||||
// Truck right | |||||
ctx->controls["move_right"]->set_active_callback | |||||
( | |||||
[ctx, target_eid, three_dof_eid, truck_speed, move_slow, move_fast, slow_modifier, fast_modifier](float value) | |||||
{ | |||||
if (move_slow->is_active()) | |||||
value *= slow_modifier; | |||||
if (move_fast->is_active()) | |||||
value *= fast_modifier; | |||||
auto& three_dof = ctx->entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid); | |||||
const math::quaternion<float> yaw = math::angle_axis(three_dof.yaw, {0.0f, 1.0f, 0.0f}); | |||||
const float3 movement = {truck_speed * value * (1.0f / 60.0f), 0.0f, 0.0f}; | |||||
entity::command::translate(*ctx->entity_registry, target_eid, yaw * movement); | |||||
} | |||||
); | |||||
// Truck left | |||||
ctx->controls["move_left"]->set_active_callback | |||||
( | |||||
[ctx, target_eid, three_dof_eid, truck_speed, move_slow, move_fast, slow_modifier, fast_modifier](float value) | |||||
{ | |||||
if (move_slow->is_active()) | |||||
value *= slow_modifier; | |||||
if (move_fast->is_active()) | |||||
value *= fast_modifier; | |||||
auto& three_dof = ctx->entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid); | |||||
const math::quaternion<float> yaw = math::angle_axis(three_dof.yaw, {0.0f, 1.0f, 0.0f}); | |||||
const float3 movement = {-truck_speed * value * (1.0f / 60.0f), 0.0f, 0.0f}; | |||||
entity::command::translate(*ctx->entity_registry, target_eid, yaw * movement); | |||||
} | |||||
); | |||||
// Pedestal up | |||||
ctx->controls["move_up"]->set_active_callback | |||||
( | |||||
[ctx, target_eid, pedestal_speed, move_slow, move_fast, slow_modifier, fast_modifier](float value) | |||||
{ | |||||
if (move_slow->is_active()) | |||||
value *= slow_modifier; | |||||
if (move_fast->is_active()) | |||||
value *= fast_modifier; | |||||
const float3 movement = {0.0f, pedestal_speed * value * (1.0f / 60.0f), 0.0f}; | |||||
entity::command::translate(*ctx->entity_registry, target_eid, movement); | |||||
} | |||||
); | |||||
// Pedestal down | |||||
ctx->controls["move_down"]->set_active_callback | |||||
( | |||||
[ctx, target_eid, pedestal_speed, move_slow, move_fast, slow_modifier, fast_modifier](float value) | |||||
{ | |||||
if (move_slow->is_active()) | |||||
value *= slow_modifier; | |||||
if (move_fast->is_active()) | |||||
value *= fast_modifier; | |||||
const float3 movement = {0.0f, -pedestal_speed * value * (1.0f / 60.0f), 0.0f}; | |||||
entity::command::translate(*ctx->entity_registry, target_eid, movement); | |||||
} | |||||
); | |||||
// Mouse rotate | |||||
ctx->controls["mouse_look"]->set_activated_callback | |||||
( | |||||
[ctx, mouse_look_toggle]() | |||||
{ | |||||
if (mouse_look_toggle) | |||||
ctx->mouse_look = !ctx->mouse_look; | |||||
else | |||||
ctx->mouse_look = true; | |||||
ctx->app->set_relative_mouse_mode(ctx->mouse_look); | |||||
} | |||||
); | |||||
ctx->controls["mouse_look"]->set_deactivated_callback | |||||
( | |||||
[ctx, mouse_look_toggle]() | |||||
{ | |||||
if (!mouse_look_toggle) | |||||
{ | |||||
ctx->mouse_look = false; | |||||
ctx->app->set_relative_mouse_mode(false); | |||||
} | |||||
} | |||||
); | |||||
// Pan left | |||||
ctx->controls["look_left_gamepad"]->set_active_callback | |||||
( | |||||
[ctx, three_dof_eid, gamepad_pan_factor](float value) | |||||
{ | |||||
auto& three_dof = ctx->entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid); | |||||
three_dof.yaw += gamepad_pan_factor * value * (1.0f / 60.0f); | |||||
} | |||||
); | |||||
ctx->controls["look_left_mouse"]->set_active_callback | |||||
( | |||||
[ctx, three_dof_eid, mouse_pan_factor](float value) | |||||
{ | |||||
if (!ctx->mouse_look) | |||||
return; | |||||
auto& three_dof = ctx->entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid); | |||||
three_dof.yaw += mouse_pan_factor * value * (1.0f / 60.0f); | |||||
} | |||||
); | |||||
// Pan right | |||||
ctx->controls["look_right_gamepad"]->set_active_callback | |||||
( | |||||
[ctx, three_dof_eid, gamepad_pan_factor](float value) | |||||
{ | |||||
auto& three_dof = ctx->entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid); | |||||
three_dof.yaw -= gamepad_pan_factor * value * (1.0f / 60.0f); | |||||
} | |||||
); | |||||
ctx->controls["look_right_mouse"]->set_active_callback | |||||
( | |||||
[ctx, three_dof_eid, mouse_pan_factor](float value) | |||||
{ | |||||
if (!ctx->mouse_look) | |||||
return; | |||||
auto& three_dof = ctx->entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid); | |||||
three_dof.yaw -= mouse_pan_factor * value * (1.0f / 60.0f); | |||||
} | |||||
); | |||||
// Tilt up | |||||
ctx->controls["look_up_gamepad"]->set_active_callback | |||||
( | |||||
[ctx, three_dof_eid, gamepad_tilt_factor](float value) | |||||
{ | |||||
auto& three_dof = ctx->entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid); | |||||
three_dof.pitch -= gamepad_tilt_factor * value * (1.0f / 60.0f); | |||||
three_dof.pitch = std::max<float>(math::radians(-90.0f), three_dof.pitch); | |||||
} | |||||
); | |||||
ctx->controls["look_up_mouse"]->set_active_callback | |||||
( | |||||
[ctx, three_dof_eid, mouse_tilt_factor](float value) | |||||
{ | |||||
if (!ctx->mouse_look) | |||||
return; | |||||
auto& three_dof = ctx->entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid); | |||||
three_dof.pitch -= mouse_tilt_factor * value * (1.0f / 60.0f); | |||||
three_dof.pitch = std::max<float>(math::radians(-90.0f), three_dof.pitch); | |||||
} | |||||
); | |||||
// Tilt down | |||||
ctx->controls["look_down_gamepad"]->set_active_callback | |||||
( | |||||
[ctx, three_dof_eid, gamepad_tilt_factor](float value) | |||||
{ | |||||
auto& three_dof = ctx->entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid); | |||||
three_dof.pitch += gamepad_tilt_factor * value * (1.0f / 60.0f); | |||||
three_dof.pitch = std::min<float>(math::radians(90.0f), three_dof.pitch); | |||||
} | |||||
); | |||||
ctx->controls["look_down_mouse"]->set_active_callback | |||||
( | |||||
[ctx, three_dof_eid, mouse_tilt_factor](float value) | |||||
{ | |||||
if (!ctx->mouse_look) | |||||
return; | |||||
auto& three_dof = ctx->entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid); | |||||
three_dof.pitch += mouse_tilt_factor * value * (1.0f / 60.0f); | |||||
three_dof.pitch = std::min<float>(math::radians(90.0f), three_dof.pitch); | |||||
} | |||||
); | |||||
/* | |||||
// Use tool | |||||
ctx->controls["use_tool"]->set_activated_callback | |||||
( | |||||
[ctx]() | |||||
{ | |||||
if (ctx->entities.count("active_tool")) | |||||
{ | |||||
entity::id tool_eid = ctx->entities["active_tool"]; | |||||
const auto& tool = ctx->entity_registry->get<entity::component::tool>(tool_eid); | |||||
if (tool.activated) | |||||
tool.activated(); | |||||
} | |||||
} | |||||
); | |||||
ctx->controls["use_tool"]->set_deactivated_callback | |||||
( | |||||
[ctx]() | |||||
{ | |||||
if (ctx->entities.count("active_tool")) | |||||
{ | |||||
entity::id tool_eid = ctx->entities["active_tool"]; | |||||
const auto& tool = ctx->entity_registry->get<entity::component::tool>(tool_eid); | |||||
if (tool.deactivated) | |||||
tool.deactivated(); | |||||
} | |||||
} | |||||
); | |||||
ctx->controls["use_tool"]->set_active_callback | |||||
( | |||||
[ctx](float value) | |||||
{ | |||||
if (ctx->entities.count("active_tool")) | |||||
{ | |||||
entity::id tool_eid = ctx->entities["active_tool"]; | |||||
const auto& tool = ctx->entity_registry->get<entity::component::tool>(tool_eid); | |||||
if (tool.active) | |||||
tool.active(); | |||||
} | |||||
} | |||||
); | |||||
*/ | |||||
// Setup pause control | |||||
ctx->controls["pause"]->set_activated_callback | |||||
( | |||||
[ctx]() | |||||
{ | |||||
// Disable controls | |||||
disable_controls(ctx); | |||||
// Store paused state | |||||
ctx->paused_state = | |||||
{ | |||||
"nuptial_flight", | |||||
std::bind(game::state::nuptial_flight::enter, ctx), | |||||
std::bind(game::state::nuptial_flight::exit, ctx) | |||||
}; | |||||
// Change to pause menu state | |||||
application::state next_state; | |||||
next_state.name = "pause_menu"; | |||||
next_state.enter = std::bind(game::state::pause_menu::enter, ctx); | |||||
next_state.exit = std::bind(game::state::pause_menu::exit, ctx); | |||||
ctx->app->change_state(next_state); | |||||
} | |||||
); | |||||
} | |||||
void disable_controls(game::context* ctx) | |||||
{ | |||||
ctx->controls["pause"]->set_activated_callback(nullptr); | |||||
} | |||||
} // namespace nuptial_flight | |||||
} // namespace state | |||||
} // namespace game |
@ -1,214 +0,0 @@ | |||||
/* | |||||
* 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "game/states/options-menu.hpp" | |||||
#include "game/states/main-menu.hpp" | |||||
#include "game/states/controls-menu.hpp" | |||||
#include "game/states/graphics-menu.hpp" | |||||
#include "game/states/sound-menu.hpp" | |||||
#include "game/states/language-menu.hpp" | |||||
#include "game/states/pause-menu.hpp" | |||||
#include "game/save.hpp" | |||||
#include "game/menu.hpp" | |||||
#include "animation/ease.hpp" | |||||
#include "animation/animation.hpp" | |||||
#include "animation/animator.hpp" | |||||
#include "application.hpp" | |||||
#include "scene/text.hpp" | |||||
namespace game { | |||||
namespace state { | |||||
namespace options_menu { | |||||
void enter(game::context* ctx) | |||||
{ | |||||
// Construct menu item texts | |||||
scene::text* controls_text = new scene::text(); | |||||
scene::text* graphics_text = new scene::text(); | |||||
scene::text* sound_text = new scene::text(); | |||||
scene::text* language_text = new scene::text(); | |||||
scene::text* back_text = new scene::text(); | |||||
// Set content of menu item texts | |||||
controls_text->set_content((*ctx->strings)["options_menu_controls"]); | |||||
graphics_text->set_content((*ctx->strings)["options_menu_graphics"]); | |||||
sound_text->set_content((*ctx->strings)["options_menu_sound"]); | |||||
language_text->set_content((*ctx->strings)["options_menu_language"]); | |||||
back_text->set_content((*ctx->strings)["back"]); | |||||
// Build list of menu item texts | |||||
ctx->menu_item_texts.push_back({controls_text, nullptr}); | |||||
ctx->menu_item_texts.push_back({graphics_text, nullptr}); | |||||
ctx->menu_item_texts.push_back({sound_text, nullptr}); | |||||
ctx->menu_item_texts.push_back({language_text, nullptr}); | |||||
ctx->menu_item_texts.push_back({back_text, nullptr}); | |||||
// Init menu item index | |||||
game::menu::init_menu_item_index(ctx, "options"); | |||||
game::menu::update_text_color(ctx); | |||||
game::menu::update_text_font(ctx); | |||||
game::menu::align_text(ctx, true); | |||||
game::menu::update_text_tweens(ctx); | |||||
game::menu::add_text_to_ui(ctx); | |||||
game::menu::setup_animations(ctx); | |||||
// Construct menu item callbacks | |||||
auto select_controls_callback = [ctx]() | |||||
{ | |||||
// Disable controls | |||||
game::menu::clear_controls(ctx); | |||||
// Return to main menu | |||||
game::menu::fade_out | |||||
( | |||||
ctx, | |||||
[ctx]() | |||||
{ | |||||
application::state next_state; | |||||
next_state.name = "controls_menu"; | |||||
next_state.enter = std::bind(game::state::controls_menu::enter, ctx); | |||||
next_state.exit = std::bind(game::state::controls_menu::exit, ctx); | |||||
ctx->app->queue_state(next_state); | |||||
} | |||||
); | |||||
}; | |||||
auto select_graphics_callback = [ctx]() | |||||
{ | |||||
// Disable controls | |||||
game::menu::clear_controls(ctx); | |||||
// Return to main menu | |||||
game::menu::fade_out | |||||
( | |||||
ctx, | |||||
[ctx]() | |||||
{ | |||||
application::state next_state; | |||||
next_state.name = "graphics_menu"; | |||||
next_state.enter = std::bind(game::state::graphics_menu::enter, ctx); | |||||
next_state.exit = std::bind(game::state::graphics_menu::exit, ctx); | |||||
ctx->app->queue_state(next_state); | |||||
} | |||||
); | |||||
}; | |||||
auto select_sound_callback = [ctx]() | |||||
{ | |||||
// Disable controls | |||||
game::menu::clear_controls(ctx); | |||||
// Return to main menu | |||||
game::menu::fade_out | |||||
( | |||||
ctx, | |||||
[ctx]() | |||||
{ | |||||
application::state next_state; | |||||
next_state.name = "sound_menu"; | |||||
next_state.enter = std::bind(game::state::sound_menu::enter, ctx); | |||||
next_state.exit = std::bind(game::state::sound_menu::exit, ctx); | |||||
ctx->app->queue_state(next_state); | |||||
} | |||||
); | |||||
}; | |||||
auto select_language_callback = [ctx]() | |||||
{ | |||||
// Disable controls | |||||
game::menu::clear_controls(ctx); | |||||
// Return to main menu | |||||
game::menu::fade_out | |||||
( | |||||
ctx, | |||||
[ctx]() | |||||
{ | |||||
application::state next_state; | |||||
next_state.name = "language_menu"; | |||||
next_state.enter = std::bind(game::state::language_menu::enter, ctx); | |||||
next_state.exit = std::bind(game::state::language_menu::exit, ctx); | |||||
ctx->app->queue_state(next_state); | |||||
} | |||||
); | |||||
}; | |||||
auto select_back_callback = [ctx]() | |||||
{ | |||||
// Disable controls | |||||
game::menu::clear_controls(ctx); | |||||
// Save config | |||||
game::save_config(ctx); | |||||
application::state next_state; | |||||
if (ctx->paused_state) | |||||
{ | |||||
// Return to pause menu | |||||
next_state.name = "pause_menu"; | |||||
next_state.enter = std::bind(game::state::pause_menu::enter, ctx); | |||||
next_state.exit = std::bind(game::state::pause_menu::exit, ctx); | |||||
} | |||||
else | |||||
{ | |||||
// Return to main menu | |||||
next_state.name = "main_menu"; | |||||
next_state.enter = std::bind(game::state::main_menu::enter, ctx, false); | |||||
next_state.exit = std::bind(game::state::main_menu::exit, ctx); | |||||
} | |||||
game::menu::fade_out(ctx, std::bind(&application::queue_state, ctx->app, next_state)); | |||||
}; | |||||
// Build list of menu select callbacks | |||||
ctx->menu_select_callbacks.push_back(select_controls_callback); | |||||
ctx->menu_select_callbacks.push_back(select_graphics_callback); | |||||
ctx->menu_select_callbacks.push_back(select_sound_callback); | |||||
ctx->menu_select_callbacks.push_back(select_language_callback); | |||||
ctx->menu_select_callbacks.push_back(select_back_callback); | |||||
// Build list of menu right callbacks | |||||
ctx->menu_right_callbacks.resize(5, nullptr); | |||||
// Build list of menu left callbacks | |||||
ctx->menu_left_callbacks.resize(5, nullptr); | |||||
// Set menu back callback | |||||
ctx->menu_back_callback = select_back_callback; | |||||
// Queue menu control setup | |||||
ctx->function_queue.push(std::bind(game::menu::setup_controls, ctx)); | |||||
// Fade in menu | |||||
game::menu::fade_in(ctx, nullptr); | |||||
} | |||||
void exit(game::context* ctx) | |||||
{ | |||||
// Destruct menu | |||||
game::menu::clear_controls(ctx); | |||||
game::menu::clear_callbacks(ctx); | |||||
game::menu::delete_animations(ctx); | |||||
game::menu::remove_text_from_ui(ctx); | |||||
game::menu::delete_text(ctx); | |||||
// Save config | |||||
game::save_config(ctx); | |||||
} | |||||
} // namespace options_menu | |||||
} // namespace state | |||||
} // namespace game |
@ -1,254 +0,0 @@ | |||||
/* | |||||
* 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "game/states/sound-menu.hpp" | |||||
#include "game/states/options-menu.hpp" | |||||
#include "application.hpp" | |||||
#include "scene/text.hpp" | |||||
#include "debug/logger.hpp" | |||||
#include "game/menu.hpp" | |||||
#include "animation/timeline.hpp" | |||||
namespace game { | |||||
namespace state { | |||||
namespace sound_menu { | |||||
static void update_value_text_content(game::context* ctx) | |||||
{ | |||||
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(std::to_string(static_cast<int>(std::round(ctx->master_volume * 100.0f))) + "%"); | |||||
std::get<1>(ctx->menu_item_texts[1])->set_content(std::to_string(static_cast<int>(std::round(ctx->ambience_volume * 100.0f))) + "%"); | |||||
std::get<1>(ctx->menu_item_texts[2])->set_content(std::to_string(static_cast<int>(std::round(ctx->effects_volume * 100.0f))) + "%"); | |||||
std::get<1>(ctx->menu_item_texts[3])->set_content((ctx->mono_audio) ? string_on : string_off); | |||||
std::get<1>(ctx->menu_item_texts[4])->set_content((ctx->captions) ? string_on : string_off); | |||||
std::get<1>(ctx->menu_item_texts[5])->set_content(std::to_string(static_cast<int>(std::round(ctx->captions_size * 100.0f))) + "%"); | |||||
} | |||||
void enter(game::context* ctx) | |||||
{ | |||||
// Construct menu item texts | |||||
scene::text* master_volume_name_text = new scene::text(); | |||||
scene::text* master_volume_value_text = new scene::text(); | |||||
scene::text* ambience_volume_name_text = new scene::text(); | |||||
scene::text* ambience_volume_value_text = new scene::text(); | |||||
scene::text* effects_volume_name_text = new scene::text(); | |||||
scene::text* effects_volume_value_text = new scene::text(); | |||||
scene::text* mono_audio_name_text = new scene::text(); | |||||
scene::text* mono_audio_value_text = new scene::text(); | |||||
scene::text* captions_name_text = new scene::text(); | |||||
scene::text* captions_value_text = new scene::text(); | |||||
scene::text* captions_size_name_text = new scene::text(); | |||||
scene::text* captions_size_value_text = new scene::text(); | |||||
scene::text* back_text = new scene::text(); | |||||
// Build list of menu item texts | |||||
ctx->menu_item_texts.push_back({master_volume_name_text, master_volume_value_text}); | |||||
ctx->menu_item_texts.push_back({ambience_volume_name_text, ambience_volume_value_text}); | |||||
ctx->menu_item_texts.push_back({effects_volume_name_text, effects_volume_value_text}); | |||||
ctx->menu_item_texts.push_back({mono_audio_name_text, mono_audio_value_text}); | |||||
ctx->menu_item_texts.push_back({captions_name_text, captions_value_text}); | |||||
ctx->menu_item_texts.push_back({captions_size_name_text, captions_size_value_text}); | |||||
ctx->menu_item_texts.push_back({back_text, nullptr}); | |||||
// Set content of menu item texts | |||||
master_volume_name_text->set_content((*ctx->strings)["sound_menu_master_volume"]); | |||||
ambience_volume_name_text->set_content((*ctx->strings)["sound_menu_ambience_volume"]); | |||||
effects_volume_name_text->set_content((*ctx->strings)["sound_menu_effects_volume"]); | |||||
mono_audio_name_text->set_content((*ctx->strings)["sound_menu_mono_audio"]); | |||||
captions_name_text->set_content((*ctx->strings)["sound_menu_captions"]); | |||||
captions_size_name_text->set_content((*ctx->strings)["sound_menu_captions_size"]); | |||||
back_text->set_content((*ctx->strings)["back"]); | |||||
update_value_text_content(ctx); | |||||
// Init menu item index | |||||
game::menu::init_menu_item_index(ctx, "sound"); | |||||
game::menu::update_text_color(ctx); | |||||
game::menu::update_text_font(ctx); | |||||
game::menu::align_text(ctx); | |||||
game::menu::update_text_tweens(ctx); | |||||
game::menu::add_text_to_ui(ctx); | |||||
game::menu::setup_animations(ctx); | |||||
// Construct menu item callbacks | |||||
auto increase_volume_callback = [ctx](float* volume) | |||||
{ | |||||
// Increase volume | |||||
if (ctx->controls["menu_modifier"]->is_active()) | |||||
*volume += 0.01f; | |||||
else | |||||
*volume += 0.1f; | |||||
// Limit volume | |||||
if (*volume > 1.0f) | |||||
*volume = 1.0f; | |||||
update_value_text_content(ctx); | |||||
game::menu::align_text(ctx); | |||||
game::menu::update_text_tweens(ctx); | |||||
}; | |||||
auto decrease_volume_callback = [ctx](float* volume) | |||||
{ | |||||
// Decrease volume | |||||
if (ctx->controls["menu_modifier"]->is_active()) | |||||
*volume -= 0.01f; | |||||
else | |||||
*volume -= 0.1f; | |||||
// Limit volume | |||||
if (*volume < 0.0f) | |||||
*volume = 0.0f; | |||||
update_value_text_content(ctx); | |||||
game::menu::align_text(ctx); | |||||
game::menu::update_text_tweens(ctx); | |||||
}; | |||||
auto toggle_mono_audio_callback = [ctx]() | |||||
{ | |||||
ctx->mono_audio = !ctx->mono_audio; | |||||
update_value_text_content(ctx); | |||||
game::menu::align_text(ctx); | |||||
game::menu::update_text_tweens(ctx); | |||||
}; | |||||
auto toggle_captions_callback = [ctx]() | |||||
{ | |||||
ctx->captions = !ctx->captions; | |||||
update_value_text_content(ctx); | |||||
game::menu::align_text(ctx); | |||||
game::menu::update_text_tweens(ctx); | |||||
}; | |||||
auto increase_captions_size_callback = [ctx]() | |||||
{ | |||||
// Increase size | |||||
if (ctx->controls["menu_modifier"]->is_active()) | |||||
ctx->captions_size += 0.01f; | |||||
else | |||||
ctx->captions_size += 0.1f; | |||||
// Limit size | |||||
if (ctx->captions_size > 2.0f) | |||||
ctx->captions_size = 2.0f; | |||||
update_value_text_content(ctx); | |||||
game::menu::align_text(ctx); | |||||
game::menu::update_text_tweens(ctx); | |||||
}; | |||||
auto decrease_captions_size_callback = [ctx]() | |||||
{ | |||||
// Decrease size | |||||
if (ctx->controls["menu_modifier"]->is_active()) | |||||
ctx->captions_size -= 0.01f; | |||||
else | |||||
ctx->captions_size -= 0.1f; | |||||
// Limit size | |||||
if (ctx->captions_size < 0.1f) | |||||
ctx->captions_size = 0.1f; | |||||
update_value_text_content(ctx); | |||||
game::menu::align_text(ctx); | |||||
game::menu::update_text_tweens(ctx); | |||||
}; | |||||
auto select_back_callback = [ctx]() | |||||
{ | |||||
// Disable controls | |||||
game::menu::clear_controls(ctx); | |||||
game::menu::fade_out | |||||
( | |||||
ctx, | |||||
[ctx]() | |||||
{ | |||||
application::state next_state; | |||||
next_state.name = "options_menu"; | |||||
next_state.enter = std::bind(game::state::options_menu::enter, ctx); | |||||
next_state.exit = std::bind(game::state::options_menu::exit, ctx); | |||||
ctx->app->queue_state(next_state); | |||||
} | |||||
); | |||||
}; | |||||
// Build list of menu select callbacks | |||||
ctx->menu_select_callbacks.push_back(std::bind(increase_volume_callback, &ctx->master_volume)); | |||||
ctx->menu_select_callbacks.push_back(std::bind(increase_volume_callback, &ctx->ambience_volume)); | |||||
ctx->menu_select_callbacks.push_back(std::bind(increase_volume_callback, &ctx->effects_volume)); | |||||
ctx->menu_select_callbacks.push_back(toggle_mono_audio_callback); | |||||
ctx->menu_select_callbacks.push_back(toggle_captions_callback); | |||||
ctx->menu_select_callbacks.push_back(increase_captions_size_callback); | |||||
ctx->menu_select_callbacks.push_back(select_back_callback); | |||||
// Build list of menu left callbacks | |||||
ctx->menu_left_callbacks.push_back(std::bind(decrease_volume_callback, &ctx->master_volume)); | |||||
ctx->menu_left_callbacks.push_back(std::bind(decrease_volume_callback, &ctx->ambience_volume)); | |||||
ctx->menu_left_callbacks.push_back(std::bind(decrease_volume_callback, &ctx->effects_volume)); | |||||
ctx->menu_left_callbacks.push_back(toggle_mono_audio_callback); | |||||
ctx->menu_left_callbacks.push_back(toggle_captions_callback); | |||||
ctx->menu_left_callbacks.push_back(decrease_captions_size_callback); | |||||
ctx->menu_left_callbacks.push_back(nullptr); | |||||
// Build list of menu right callbacks | |||||
ctx->menu_right_callbacks.push_back(std::bind(increase_volume_callback, &ctx->master_volume)); | |||||
ctx->menu_right_callbacks.push_back(std::bind(increase_volume_callback, &ctx->ambience_volume)); | |||||
ctx->menu_right_callbacks.push_back(std::bind(increase_volume_callback, &ctx->effects_volume)); | |||||
ctx->menu_right_callbacks.push_back(toggle_mono_audio_callback); | |||||
ctx->menu_right_callbacks.push_back(toggle_captions_callback); | |||||
ctx->menu_right_callbacks.push_back(increase_captions_size_callback); | |||||
ctx->menu_right_callbacks.push_back(nullptr); | |||||
// 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)}}); | |||||
// Fade in menu | |||||
game::menu::fade_in(ctx, nullptr); | |||||
} | |||||
void exit(game::context* ctx) | |||||
{ | |||||
// Destruct menu | |||||
game::menu::clear_controls(ctx); | |||||
game::menu::clear_callbacks(ctx); | |||||
game::menu::delete_animations(ctx); | |||||
game::menu::remove_text_from_ui(ctx); | |||||
game::menu::delete_text(ctx); | |||||
// Update config | |||||
(*ctx->config)["master_volume"] = ctx->master_volume; | |||||
(*ctx->config)["ambience_volume"] = ctx->ambience_volume; | |||||
(*ctx->config)["effects_volume"] = ctx->effects_volume; | |||||
(*ctx->config)["mono_audio"] = ctx->mono_audio; | |||||
(*ctx->config)["captions"] = ctx->captions; | |||||
(*ctx->config)["captions_size"] = ctx->captions_size; | |||||
} | |||||
} // namespace sound_menu | |||||
} // namespace state | |||||
} // namespace game |
@ -1,160 +0,0 @@ | |||||
/* | |||||
* 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "game/states/splash.hpp" | |||||
#include "game/states/main-menu.hpp" | |||||
#include "animation/screen-transition.hpp" | |||||
#include "animation/animation.hpp" | |||||
#include "animation/animator.hpp" | |||||
#include "animation/ease.hpp" | |||||
#include "application.hpp" | |||||
#include "render/passes/clear-pass.hpp" | |||||
namespace game { | |||||
namespace state { | |||||
namespace splash { | |||||
void enter(game::context* ctx) | |||||
{ | |||||
ctx->ui_clear_pass->set_cleared_buffers(true, true, false); | |||||
// Load animation timing configuration | |||||
double splash_fade_in_duration = 0.0; | |||||
double splash_duration = 0.0; | |||||
double splash_fade_out_duration = 0.0; | |||||
if (ctx->config->contains("splash_fade_in_duration")) | |||||
splash_fade_in_duration = (*ctx->config)["splash_fade_in_duration"].get<double>(); | |||||
if (ctx->config->contains("splash_duration")) | |||||
splash_duration = (*ctx->config)["splash_duration"].get<double>(); | |||||
if (ctx->config->contains("splash_fade_out_duration")) | |||||
splash_fade_out_duration = (*ctx->config)["splash_fade_out_duration"].get<double>(); | |||||
// Build splash fade in animation | |||||
ctx->splash_fade_in_animation = new animation<float>(); | |||||
animation_channel<float>* splash_fade_in_opacity_channel = ctx->splash_fade_in_animation->add_channel(0); | |||||
ctx->splash_fade_in_animation->set_interpolator(ease<float>::out_cubic); | |||||
splash_fade_in_opacity_channel->insert_keyframe({0.0, 0.0f}); | |||||
splash_fade_in_opacity_channel->insert_keyframe({splash_fade_in_duration, 1.0f}); | |||||
splash_fade_in_opacity_channel->insert_keyframe({splash_fade_in_duration + splash_duration, 1.0f}); | |||||
// Build splash fade out animation | |||||
ctx->splash_fade_out_animation = new animation<float>(); | |||||
animation_channel<float>* splash_fade_out_opacity_channel = ctx->splash_fade_out_animation->add_channel(0); | |||||
ctx->splash_fade_out_animation->set_interpolator(ease<float>::out_cubic); | |||||
splash_fade_out_opacity_channel->insert_keyframe({0.0, 1.0f}); | |||||
splash_fade_out_opacity_channel->insert_keyframe({splash_fade_out_duration, 0.0f}); | |||||
// Setup animation frame callbacks | |||||
auto set_splash_opacity = [ctx](int channel, const float& opacity) | |||||
{ | |||||
static_cast<render::material_property<float4>*>(ctx->splash_billboard_material->get_property("tint"))->set_value(float4{1, 1, 1, opacity}); | |||||
}; | |||||
ctx->splash_fade_in_animation->set_frame_callback(set_splash_opacity); | |||||
ctx->splash_fade_out_animation->set_frame_callback(set_splash_opacity); | |||||
// Reset splash color when animation starts | |||||
ctx->splash_fade_in_animation->set_start_callback | |||||
( | |||||
[ctx]() | |||||
{ | |||||
static_cast<render::material_property<float4>*>(ctx->splash_billboard_material->get_property("tint"))->set_value(float4{1, 1, 1, 0}); | |||||
ctx->splash_billboard_material->update_tweens(); | |||||
} | |||||
); | |||||
// Trigger splash fade out animation when splash fade in animation ends | |||||
ctx->splash_fade_in_animation->set_end_callback | |||||
( | |||||
[ctx]() | |||||
{ | |||||
ctx->splash_fade_out_animation->play(); | |||||
} | |||||
); | |||||
// Trigger a state change when the splash fade out animation ends | |||||
ctx->splash_fade_out_animation->set_end_callback | |||||
( | |||||
[ctx]() | |||||
{ | |||||
application::state next_state; | |||||
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->queue_state(next_state); | |||||
} | |||||
); | |||||
// Add splash fade animations to animator | |||||
ctx->animator->add_animation(ctx->splash_fade_in_animation); | |||||
ctx->animator->add_animation(ctx->splash_fade_out_animation); | |||||
// Start splash fade in animation | |||||
ctx->splash_fade_in_animation->play(); | |||||
// Set up splash skipper | |||||
ctx->input_listener->set_callback | |||||
( | |||||
[ctx](const event_base& event) | |||||
{ | |||||
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) | |||||
{ | |||||
// Black out screen | |||||
ctx->rasterizer->set_clear_color(0.0f, 0.0f, 0.0f, 1.0f); | |||||
ctx->rasterizer->clear_framebuffer(true, false, false); | |||||
ctx->app->swap_buffers(); | |||||
// Change state | |||||
application::state next_state; | |||||
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->queue_state(next_state); | |||||
} | |||||
} | |||||
); | |||||
ctx->input_listener->set_enabled(true); | |||||
// Add splash billboard to UI scene | |||||
ctx->ui_scene->add_object(ctx->splash_billboard); | |||||
} | |||||
void exit(game::context* ctx) | |||||
{ | |||||
// Remove splash billboard from UI scene | |||||
ctx->ui_scene->remove_object(ctx->splash_billboard); | |||||
// Disable splash skipper | |||||
ctx->input_listener->set_enabled(false); | |||||
ctx->input_listener->set_callback(nullptr); | |||||
// Destruct splash fade animations | |||||
ctx->animator->remove_animation(ctx->splash_fade_in_animation); | |||||
ctx->animator->remove_animation(ctx->splash_fade_out_animation); | |||||
delete ctx->splash_fade_in_animation; | |||||
delete ctx->splash_fade_out_animation; | |||||
ctx->splash_fade_in_animation = nullptr; | |||||
ctx->splash_fade_out_animation = nullptr; | |||||
ctx->ui_clear_pass->set_cleared_buffers(false, true, false); | |||||
} | |||||
} // namespace splash | |||||
} // namespace state | |||||
} // namespace game |
@ -0,0 +1,39 @@ | |||||
/* | |||||
* 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_HSM_STATE_MACHINE_HPP | |||||
#define ANTKEEPER_HSM_STATE_MACHINE_HPP | |||||
#include <memory> | |||||
#include <stack> | |||||
/// Hierarchical State Machine (HSM) | |||||
namespace hsm { | |||||
/** | |||||
* Stack-based hierarchical state machine. | |||||
* | |||||
* @tparam T State type. | |||||
*/ | |||||
template <typename T> | |||||
using state_machine = std::stack<std::unique_ptr<T>>; | |||||
} // namespace hsm | |||||
#endif // ANTKEEPER_HSM_STATE_MACHINE_HPP |