@ -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 |