💿🐜 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.

324 lines
11 KiB

1 year 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/sound-menu.hpp"
  20. #include "game/states/options-menu.hpp"
  21. #include "application.hpp"
  22. #include "scene/text.hpp"
  23. #include "render/passes/clear-pass.hpp"
  24. #include "debug/logger.hpp"
  25. namespace game {
  26. namespace state {
  27. namespace sound_menu {
  28. static void update_text_color(game::context* ctx)
  29. {
  30. float4 inactive_color = {1.0f, 1.0f, 1.0f, 0.5f};
  31. float4 active_color = {1.0f, 1.0f, 1.0f, 1.0f};
  32. for (std::size_t i = 0; i < ctx->sound_menu_label_texts.size(); ++i)
  33. {
  34. scene::text* label_text = ctx->sound_menu_label_texts[i];
  35. scene::text* value_text = ctx->sound_menu_value_texts[i];
  36. if (i == ctx->sound_menu_index)
  37. {
  38. label_text->set_color(active_color);
  39. if (value_text)
  40. value_text->set_color(active_color);
  41. }
  42. else
  43. {
  44. label_text->set_color(inactive_color);
  45. if (value_text)
  46. value_text->set_color(inactive_color);
  47. }
  48. }
  49. }
  50. static void update_text_tweens(game::context* ctx)
  51. {
  52. for (std::size_t i = 0; i < ctx->sound_menu_label_texts.size(); ++i)
  53. {
  54. scene::text* label_text = ctx->sound_menu_label_texts[i];
  55. scene::text* value_text = ctx->sound_menu_value_texts[i];
  56. label_text->update_tweens();
  57. if (value_text)
  58. value_text->update_tweens();
  59. }
  60. }
  61. void enter(game::context* ctx)
  62. {
  63. ctx->ui_clear_pass->set_cleared_buffers(true, true, false);
  64. ctx->sound_menu_index = 0;
  65. // Construct sound menu texts
  66. ctx->sound_menu_master_volume_label_text = new scene::text();
  67. ctx->sound_menu_master_volume_value_text = new scene::text();
  68. ctx->sound_menu_ambience_volume_label_text = new scene::text();
  69. ctx->sound_menu_ambience_volume_value_text = new scene::text();
  70. ctx->sound_menu_effects_volume_label_text = new scene::text();
  71. ctx->sound_menu_effects_volume_value_text = new scene::text();
  72. ctx->sound_menu_back_label_text = new scene::text();
  73. // Set text content
  74. ctx->sound_menu_master_volume_label_text->set_content((*ctx->strings)["sound_menu_master_volume"]);
  75. ctx->sound_menu_master_volume_value_text->set_content(std::to_string(static_cast<int>(ctx->master_volume * 100.0f + 0.5f)));
  76. ctx->sound_menu_ambience_volume_label_text->set_content((*ctx->strings)["sound_menu_ambience_volume"]);
  77. ctx->sound_menu_ambience_volume_value_text->set_content(std::to_string(static_cast<int>(ctx->ambience_volume * 100.0f + 0.5f)));
  78. ctx->sound_menu_effects_volume_label_text->set_content((*ctx->strings)["sound_menu_effects_volume"]);
  79. ctx->sound_menu_effects_volume_value_text->set_content(std::to_string(static_cast<int>(ctx->effects_volume * 100.0f + 0.5f)));
  80. ctx->sound_menu_back_label_text->set_content((*ctx->strings)["back"]);
  81. // Build lists of sound menu texts
  82. ctx->sound_menu_label_texts.push_back(ctx->sound_menu_master_volume_label_text);
  83. ctx->sound_menu_label_texts.push_back(ctx->sound_menu_ambience_volume_label_text);
  84. ctx->sound_menu_label_texts.push_back(ctx->sound_menu_effects_volume_label_text);
  85. ctx->sound_menu_label_texts.push_back(ctx->sound_menu_back_label_text);
  86. ctx->sound_menu_value_texts.push_back(ctx->sound_menu_master_volume_value_text);
  87. ctx->sound_menu_value_texts.push_back(ctx->sound_menu_ambience_volume_value_text);
  88. ctx->sound_menu_value_texts.push_back(ctx->sound_menu_effects_volume_value_text);
  89. ctx->sound_menu_value_texts.push_back(nullptr);
  90. // Set text fonts
  91. for (std::size_t i = 0; i < ctx->sound_menu_label_texts.size(); ++i)
  92. {
  93. scene::text* label_text = ctx->sound_menu_label_texts[i];
  94. label_text->set_material(&ctx->menu_font_material);
  95. label_text->set_font(&ctx->menu_font);
  96. scene::text* value_text = ctx->sound_menu_value_texts[i];
  97. if (value_text)
  98. {
  99. value_text->set_material(&ctx->menu_font_material);
  100. value_text->set_font(&ctx->menu_font);
  101. }
  102. }
  103. // Calculate menu width
  104. float menu_width = 0.0f;
  105. float menu_spacing = ctx->menu_font.get_glyph_metrics(U'M').width;
  106. for (std::size_t i = 0; i < ctx->sound_menu_label_texts.size(); ++i)
  107. {
  108. scene::text* label_text = ctx->sound_menu_label_texts[i];
  109. scene::text* value_text = ctx->sound_menu_value_texts[i];
  110. float row_width = 0.0f;
  111. // Add label width to width
  112. const auto& label_bounds = static_cast<const geom::aabb<float>&>(label_text->get_local_bounds());
  113. row_width += label_bounds.max_point.x - label_bounds.min_point.x;
  114. if (value_text != nullptr)
  115. {
  116. // Add value width to width
  117. //const auto& value_bounds = static_cast<const geom::aabb<float>&>(value_text->get_local_bounds());
  118. //row_width += value_bounds.max_point.x - value_bounds.min_point.x;
  119. // Add spacing to row width
  120. row_width += menu_spacing * 4.0f;
  121. }
  122. menu_width = std::max<float>(menu_width, row_width);
  123. }
  124. // Align texts
  125. float menu_height = ctx->sound_menu_label_texts.size() * ctx->menu_font.get_font_metrics().linespace;
  126. float menu_x = -menu_width * 0.5f;
  127. float menu_y = menu_height * 0.5f - ctx->menu_font.get_font_metrics().linespace;
  128. for (std::size_t i = 0; i < ctx->sound_menu_label_texts.size(); ++i)
  129. {
  130. scene::text* label_text = ctx->sound_menu_label_texts[i];
  131. float x = menu_x;
  132. float y = menu_y - ctx->menu_font.get_font_metrics().linespace * i;
  133. label_text->set_translation({std::round(x), std::round(y), 0.0f});
  134. scene::text* value_text = ctx->sound_menu_value_texts[i];
  135. if (value_text)
  136. {
  137. const auto& value_bounds = static_cast<const geom::aabb<float>&>(value_text->get_local_bounds());
  138. const float value_width = value_bounds.max_point.x - value_bounds.min_point.x;
  139. x = menu_x + menu_width - value_width;
  140. value_text->set_translation({std::round(x), std::round(y), 0.0f});
  141. }
  142. }
  143. // Construct sound menu callbacks
  144. auto menu_back_callback = [ctx]()
  145. {
  146. application::state next_state;
  147. next_state.name = "options_menu";
  148. next_state.enter = std::bind(game::state::options_menu::enter, ctx);
  149. next_state.exit = std::bind(game::state::options_menu::exit, ctx);
  150. ctx->app->change_state(next_state);
  151. };
  152. auto increase_volume_callback = [ctx, menu_x, menu_width]()
  153. {
  154. if (ctx->sound_menu_index > 2)
  155. return;
  156. // Find volume variable
  157. float* volumes[] =
  158. {
  159. &ctx->master_volume,
  160. &ctx->ambience_volume,
  161. &ctx->effects_volume
  162. };
  163. float* volume = volumes[ctx->sound_menu_index];
  164. // Increase volume
  165. *volume += 0.1f;
  166. if (*volume > 1.0f)
  167. *volume = 1.0f;
  168. // Update volume value text
  169. scene::text* value_text = ctx->sound_menu_value_texts[ctx->sound_menu_index];
  170. value_text->set_content(std::to_string(static_cast<int>((*volume) * 100.0f + 0.5f)));
  171. // Realign value text
  172. const auto& value_bounds = static_cast<const geom::aabb<float>&>(value_text->get_local_bounds());
  173. const float value_width = value_bounds.max_point.x - value_bounds.min_point.x;
  174. const float3& translation = value_text->get_translation();
  175. value_text->set_translation(float3{std::round(menu_x + menu_width - value_width), translation.y, translation.z});
  176. value_text->update_tweens();
  177. };
  178. auto decrease_volume_callback = [ctx, menu_x, menu_width]()
  179. {
  180. if (ctx->sound_menu_index > 2)
  181. return;
  182. // Find volume variable
  183. float* volumes[] =
  184. {
  185. &ctx->master_volume,
  186. &ctx->ambience_volume,
  187. &ctx->effects_volume
  188. };
  189. float* volume = volumes[ctx->sound_menu_index];
  190. // Decrease volume
  191. *volume -= 0.1f;
  192. if (*volume < 0.0f)
  193. *volume = 0.0f;
  194. // Update volume value text
  195. scene::text* value_text = ctx->sound_menu_value_texts[ctx->sound_menu_index];
  196. value_text->set_content(std::to_string(static_cast<int>((*volume) * 100.0f + 0.5f)));
  197. // Realign value text
  198. const auto& value_bounds = static_cast<const geom::aabb<float>&>(value_text->get_local_bounds());
  199. const float value_width = value_bounds.max_point.x - value_bounds.min_point.x;
  200. const float3& translation = value_text->get_translation();
  201. value_text->set_translation(float3{std::round(menu_x + menu_width - value_width), translation.y, translation.z});
  202. value_text->update_tweens();
  203. };
  204. ctx->controls["menu_down"]->set_activated_callback
  205. (
  206. [ctx]()
  207. {
  208. ++ctx->sound_menu_index;
  209. if (ctx->sound_menu_index >= ctx->sound_menu_label_texts.size())
  210. ctx->sound_menu_index = 0;
  211. update_text_color(ctx);
  212. }
  213. );
  214. ctx->controls["menu_up"]->set_activated_callback
  215. (
  216. [ctx]()
  217. {
  218. --ctx->sound_menu_index;
  219. if (ctx->sound_menu_index < 0)
  220. ctx->sound_menu_index = ctx->sound_menu_label_texts.size() - 1;
  221. update_text_color(ctx);
  222. }
  223. );
  224. ctx->controls["menu_left"]->set_activated_callback(decrease_volume_callback);
  225. ctx->controls["menu_right"]->set_activated_callback(increase_volume_callback);
  226. ctx->controls["menu_select"]->set_activated_callback
  227. (
  228. [ctx, menu_back_callback]()
  229. {
  230. if (ctx->sound_menu_index == 3)
  231. menu_back_callback();
  232. }
  233. );
  234. ctx->controls["menu_back"]->set_activated_callback(menu_back_callback);
  235. // Add text objects to UI
  236. for (std::size_t i = 0; i < ctx->sound_menu_label_texts.size(); ++i)
  237. {
  238. scene::text* label_text = ctx->sound_menu_label_texts[i];
  239. scene::text* value_text = ctx->sound_menu_value_texts[i];
  240. ctx->ui_scene->add_object(label_text);
  241. if (value_text)
  242. ctx->ui_scene->add_object(value_text);
  243. }
  244. update_text_color(ctx);
  245. update_text_tweens(ctx);
  246. }
  247. void exit(game::context* ctx)
  248. {
  249. // Clear control callbacks
  250. ctx->controls["menu_down"]->set_activated_callback(nullptr);
  251. ctx->controls["menu_up"]->set_activated_callback(nullptr);
  252. ctx->controls["menu_left"]->set_activated_callback(nullptr);
  253. ctx->controls["menu_right"]->set_activated_callback(nullptr);
  254. ctx->controls["menu_select"]->set_activated_callback(nullptr);
  255. ctx->controls["menu_back"]->set_activated_callback(nullptr);
  256. // Destruct sound menu texts
  257. for (std::size_t i = 0; i < ctx->sound_menu_label_texts.size(); ++i)
  258. {
  259. scene::text* label_text = ctx->sound_menu_label_texts[i];
  260. ctx->ui_scene->remove_object(label_text);
  261. delete label_text;
  262. scene::text* value_text = ctx->sound_menu_value_texts[i];
  263. if (value_text)
  264. {
  265. ctx->ui_scene->remove_object(value_text);
  266. delete value_text;
  267. }
  268. }
  269. ctx->sound_menu_label_texts.clear();
  270. ctx->sound_menu_value_texts.clear();
  271. // Update volumes in config
  272. (*ctx->config)["master_volume"] = ctx->master_volume;
  273. (*ctx->config)["ambience_volume"] = ctx->ambience_volume;
  274. (*ctx->config)["effects_volume"] = ctx->effects_volume;
  275. ctx->ui_clear_pass->set_cleared_buffers(false, true, false);
  276. }
  277. } // namespace sound_menu
  278. } // namespace state
  279. } // namespace game