💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

311 lines
11 KiB

7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
  1. /*
  2. * Copyright (C) 2021 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper source code.
  5. *
  6. * Antkeeper source code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper source code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "game/states/main-menu.hpp"
  20. #include "game/states/title.hpp"
  21. #include "game/states/options-menu.hpp"
  22. #include "game/states/forage.hpp"
  23. #include "game/states/nuptial-flight.hpp"
  24. #include "game/states/credits.hpp"
  25. #include "render/passes/clear-pass.hpp"
  26. #include "resources/resource-manager.hpp"
  27. #include "render/model.hpp"
  28. #include "animation/animation.hpp"
  29. #include "animation/animator.hpp"
  30. #include "animation/screen-transition.hpp"
  31. #include "animation/ease.hpp"
  32. #include "animation/timeline.hpp"
  33. #include "application.hpp"
  34. #include <limits>
  35. namespace game {
  36. namespace state {
  37. namespace main_menu {
  38. void enter(game::context* ctx, int main_menu_index)
  39. {
  40. ctx->main_menu_index = main_menu_index;
  41. ctx->ui_clear_pass->set_cleared_buffers(true, true, false);
  42. // Construct main menu texts
  43. ctx->main_menu_start_text = new scene::text();
  44. ctx->main_menu_options_text = new scene::text();
  45. ctx->main_menu_credits_text = new scene::text();
  46. ctx->main_menu_quit_text = new scene::text();
  47. // Set content of texts
  48. ctx->main_menu_start_text->set_content((*ctx->strings)["main_menu_start"]);
  49. ctx->main_menu_options_text->set_content((*ctx->strings)["main_menu_options"]);
  50. ctx->main_menu_credits_text->set_content((*ctx->strings)["main_menu_credits"]);
  51. ctx->main_menu_quit_text->set_content((*ctx->strings)["main_menu_quit"]);
  52. std::vector<scene::text*> texts;
  53. texts.push_back(ctx->main_menu_start_text);
  54. texts.push_back(ctx->main_menu_options_text);
  55. texts.push_back(ctx->main_menu_credits_text);
  56. texts.push_back(ctx->main_menu_quit_text);
  57. float offset_y = 0.0f;
  58. float menu_height = texts.size() * ctx->menu_font.get_font_metrics().linespace;
  59. float menu_y = menu_height * 0.5f - ctx->menu_font.get_font_metrics().linespace * 0.5f;
  60. for (std::size_t i = 0; i < texts.size(); ++i)
  61. {
  62. scene::text* text = texts[i];
  63. text->set_material(&ctx->menu_font_material);
  64. text->set_font(&ctx->menu_font);
  65. text->set_color({1.0f, 1.0f, 1.0f, 0.5f});
  66. ctx->ui_scene->add_object(text);
  67. // Align text
  68. const auto& bounds = static_cast<const geom::aabb<float>&>(text->get_local_bounds());
  69. float w = bounds.max_point.x - bounds.min_point.x;
  70. float x = -w * 0.5f;
  71. float y = menu_y - ctx->menu_font.get_font_metrics().linespace * i;
  72. text->set_translation({std::round(x), std::round(y), 0.0f});
  73. }
  74. float advance_x = ctx->menu_font.get_glyph_metrics(U' ').horizontal_advance * 2.0f;
  75. const auto& text_aabb = static_cast<const geom::aabb<float>&>(ctx->main_menu_start_text->get_local_bounds());
  76. const auto& text_translation = ctx->main_menu_start_text->get_translation();
  77. ctx->main_menu_start_text->set_color({1.0f, 1.0f, 1.0f, 1.0f});
  78. ctx->controls["menu_down"]->set_activated_callback
  79. (
  80. [ctx]()
  81. {
  82. ++ctx->main_menu_index;
  83. if (ctx->main_menu_index > 3)
  84. ctx->main_menu_index = 0;
  85. float4 active_color{1.0f, 1.0f, 1.0f, 1.0f};
  86. float4 inactive_color{1.0f, 1.0f, 1.0f, 0.5f};
  87. ctx->main_menu_start_text->set_color((ctx->main_menu_index == 0) ? active_color : inactive_color);
  88. ctx->main_menu_options_text->set_color((ctx->main_menu_index == 1) ? active_color : inactive_color);
  89. ctx->main_menu_credits_text->set_color((ctx->main_menu_index == 2) ? active_color : inactive_color);
  90. ctx->main_menu_quit_text->set_color((ctx->main_menu_index == 3) ? active_color : inactive_color);
  91. }
  92. );
  93. ctx->controls["menu_up"]->set_activated_callback
  94. (
  95. [ctx]()
  96. {
  97. --ctx->main_menu_index;
  98. if (ctx->main_menu_index < 0)
  99. ctx->main_menu_index = 3;
  100. float4 active_color{1.0f, 1.0f, 1.0f, 1.0f};
  101. float4 inactive_color{1.0f, 1.0f, 1.0f, 0.5f};
  102. ctx->main_menu_start_text->set_color((ctx->main_menu_index == 0) ? active_color : inactive_color);
  103. ctx->main_menu_options_text->set_color((ctx->main_menu_index == 1) ? active_color : inactive_color);
  104. ctx->main_menu_credits_text->set_color((ctx->main_menu_index == 2) ? active_color : inactive_color);
  105. ctx->main_menu_quit_text->set_color((ctx->main_menu_index == 3) ? active_color : inactive_color);
  106. }
  107. );
  108. ctx->controls["menu_back"]->set_activated_callback
  109. (
  110. [ctx]()
  111. {
  112. application::state next_state;
  113. next_state.name = "title";
  114. next_state.enter = std::bind(game::state::title::enter, ctx);
  115. next_state.exit = std::bind(game::state::title::exit, ctx);
  116. ctx->app->change_state(next_state);
  117. }
  118. );
  119. ctx->controls["menu_select"]->set_activated_callback
  120. (
  121. [ctx]()
  122. {
  123. if (ctx->main_menu_index == 0)
  124. {
  125. // Disable menu controls
  126. ctx->controls["menu_down"]->set_activated_callback(nullptr);
  127. ctx->controls["menu_up"]->set_activated_callback(nullptr);
  128. ctx->controls["menu_select"]->set_activated_callback(nullptr);
  129. // Create change state function
  130. auto change_state_nuptial_flight = [ctx]()
  131. {
  132. application::state next_state;
  133. next_state.name = "nuptial_flight";
  134. next_state.enter = std::bind(game::state::nuptial_flight::enter, ctx);
  135. next_state.exit = std::bind(game::state::nuptial_flight::exit, ctx);
  136. ctx->app->change_state(next_state);
  137. };
  138. // Set up timing
  139. const float fade_out_duration = 1.0f;
  140. // Schedule state change
  141. timeline* timeline = ctx->timeline;
  142. float t = timeline->get_position();
  143. timeline->add_sequence({{t + fade_out_duration, change_state_nuptial_flight}});
  144. // Start fade out to white
  145. ctx->fade_transition_color->set_value({1, 1, 1});
  146. ctx->fade_transition->transition(fade_out_duration, false, ease<float>::out_quad, false);
  147. }
  148. else if (ctx->main_menu_index == 1)
  149. {
  150. // Disable menu controls
  151. ctx->controls["menu_down"]->set_activated_callback(nullptr);
  152. ctx->controls["menu_up"]->set_activated_callback(nullptr);
  153. ctx->controls["menu_select"]->set_activated_callback(nullptr);
  154. // Create change state function
  155. auto change_state_options = [ctx]()
  156. {
  157. application::state next_state;
  158. next_state.name = "options_menu";
  159. next_state.enter = std::bind(game::state::options_menu::enter, ctx);
  160. next_state.exit = std::bind(game::state::options_menu::exit, ctx);
  161. ctx->app->change_state(next_state);
  162. };
  163. // Set up timing
  164. const float fade_out_duration = 0.25f;
  165. // Schedule state change
  166. timeline* timeline = ctx->timeline;
  167. float t = timeline->get_position();
  168. timeline->add_sequence({{t + fade_out_duration, change_state_options}});
  169. // Start fade out to black
  170. ctx->fade_transition_color->set_value({0, 0, 0});
  171. ctx->fade_transition->transition(fade_out_duration, false, ease<float>::out_quad);
  172. }
  173. else if (ctx->main_menu_index == 2)
  174. {
  175. // Disable menu controls
  176. ctx->controls["menu_down"]->set_activated_callback(nullptr);
  177. ctx->controls["menu_up"]->set_activated_callback(nullptr);
  178. ctx->controls["menu_select"]->set_activated_callback(nullptr);
  179. // Create change state function
  180. auto change_state_credits = [ctx]()
  181. {
  182. application::state next_state;
  183. next_state.name = "credits";
  184. next_state.enter = std::bind(game::state::credits::enter, ctx);
  185. next_state.exit = std::bind(game::state::credits::exit, ctx);
  186. ctx->app->change_state(next_state);
  187. };
  188. // Set up timing
  189. const float fade_out_duration = 0.5f;
  190. // Schedule state change
  191. timeline* timeline = ctx->timeline;
  192. float t = timeline->get_position();
  193. timeline->add_sequence({{t + fade_out_duration, change_state_credits}});
  194. // Start fade out to black
  195. ctx->fade_transition_color->set_value({0, 0, 0});
  196. ctx->fade_transition->transition(fade_out_duration, false, ease<float>::out_quad);
  197. }
  198. else if (ctx->main_menu_index == 3)
  199. {
  200. ctx->app->close(EXIT_SUCCESS);
  201. }
  202. }
  203. );
  204. // Disable control callbacks
  205. ctx->controls["menu_down"]->set_callbacks_enabled(false);
  206. ctx->controls["menu_up"]->set_callbacks_enabled(false);
  207. ctx->controls["menu_select"]->set_callbacks_enabled(false);
  208. // Build main menu fade in animation
  209. ctx->main_menu_fade_animation = new animation<float>();
  210. animation_channel<float>* main_menu_opacity_channel = ctx->main_menu_fade_animation->add_channel(0);
  211. ctx->main_menu_fade_animation->set_interpolator(ease<float>::out_quad);
  212. double main_menu_fade_in_duration = 0.0;
  213. if (ctx->config->contains("main_menu_fade_in_duration"))
  214. main_menu_fade_in_duration = (*ctx->config)["main_menu_fade_in_duration"].get<double>();
  215. main_menu_opacity_channel->insert_keyframe({0.0, 0.0f});
  216. main_menu_opacity_channel->insert_keyframe({main_menu_fade_in_duration, 1.0f});
  217. // Adjust main menu text opacity
  218. ctx->main_menu_fade_animation->set_frame_callback
  219. (
  220. [ctx](int channel, const float& opacity)
  221. {
  222. float4 active_color{1.0f, 1.0f, 1.0f, opacity};
  223. float4 inactive_color{1.0f, 1.0f, 1.0f, 0.5f * opacity};
  224. ctx->main_menu_start_text->set_color((ctx->main_menu_index == 0) ? active_color : inactive_color);
  225. ctx->main_menu_options_text->set_color((ctx->main_menu_index == 1) ? active_color : inactive_color);
  226. ctx->main_menu_credits_text->set_color((ctx->main_menu_index == 2) ? active_color : inactive_color);
  227. ctx->main_menu_quit_text->set_color((ctx->main_menu_index == 3) ? active_color : inactive_color);
  228. // Enable menu controls when visible
  229. if (opacity > 0.0f)
  230. {
  231. ctx->controls["menu_down"]->set_callbacks_enabled(true);
  232. ctx->controls["menu_up"]->set_callbacks_enabled(true);
  233. ctx->controls["menu_select"]->set_callbacks_enabled(true);
  234. }
  235. }
  236. );
  237. ctx->animator->add_animation(ctx->main_menu_fade_animation);
  238. ctx->main_menu_fade_animation->play();
  239. }
  240. void exit(game::context* ctx)
  241. {
  242. // Disable menu control callbacks
  243. ctx->controls["menu_down"]->set_activated_callback(nullptr);
  244. ctx->controls["menu_up"]->set_activated_callback(nullptr);
  245. ctx->controls["menu_back"]->set_activated_callback(nullptr);
  246. ctx->controls["menu_select"]->set_activated_callback(nullptr);
  247. // Destruct main menu animation
  248. ctx->animator->remove_animation(ctx->main_menu_fade_animation);
  249. delete ctx->main_menu_fade_animation;
  250. ctx->main_menu_fade_animation = nullptr;
  251. // Remove text objects from UI
  252. std::vector<scene::text*> texts;
  253. texts.push_back(ctx->main_menu_start_text);
  254. texts.push_back(ctx->main_menu_options_text);
  255. texts.push_back(ctx->main_menu_credits_text);
  256. texts.push_back(ctx->main_menu_quit_text);
  257. for (scene::text* text: texts)
  258. {
  259. ctx->ui_scene->remove_object(text);
  260. delete text;
  261. text = nullptr;
  262. }
  263. ctx->ui_clear_pass->set_cleared_buffers(false, true, false);
  264. }
  265. } // namespace main_menu
  266. } // namespace state
  267. } // namespace game