gameui.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. /*
  2. Minetest
  3. Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
  4. Copyright (C) 2018 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU Lesser General Public License as published by
  7. the Free Software Foundation; either version 2.1 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public License along
  14. with this program; if not, write to the Free Software Foundation, Inc.,
  15. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  16. */
  17. #include "gameui.h"
  18. #include <irrlicht_changes/static_text.h>
  19. #include <gettext.h>
  20. #include "gui/mainmenumanager.h"
  21. #include "util/pointedthing.h"
  22. #include "client.h"
  23. #include "clientmap.h"
  24. #include "fontengine.h"
  25. #include "nodedef.h"
  26. #include "profiler.h"
  27. #include "renderingengine.h"
  28. #include "version.h"
  29. inline static const char *yawToDirectionString(int yaw)
  30. {
  31. static const char *direction[4] = {"N +Z", "W -X", "S -Z", "E +X"};
  32. yaw = wrapDegrees_0_360(yaw);
  33. yaw = (yaw + 45) % 360 / 90;
  34. return direction[yaw];
  35. }
  36. GameUI::GameUI()
  37. {
  38. if (guienv && guienv->getSkin())
  39. m_statustext_initial_color = guienv->getSkin()->getColor(gui::EGDC_BUTTON_TEXT);
  40. else
  41. m_statustext_initial_color = video::SColor(255, 0, 0, 0);
  42. }
  43. void GameUI::init()
  44. {
  45. // First line of debug text
  46. m_guitext = gui::StaticText::add(guienv, utf8_to_wide(PROJECT_NAME_C).c_str(),
  47. core::rect<s32>(0, 0, 0, 0), false, false, guiroot);
  48. // Second line of debug text
  49. m_guitext2 = gui::StaticText::add(guienv, L"", core::rect<s32>(0, 0, 0, 0), false,
  50. false, guiroot);
  51. // At the middle of the screen
  52. // Object infos are shown in this
  53. m_guitext_info = gui::StaticText::add(guienv, L"",
  54. core::rect<s32>(0, 0, 400, g_fontengine->getTextHeight() * 5 + 5)
  55. + v2s32(100, 200), false, true, guiroot);
  56. // Status text (displays info when showing and hiding GUI stuff, etc.)
  57. m_guitext_status = gui::StaticText::add(guienv, L"<Status>",
  58. core::rect<s32>(0, 0, 0, 0), false, false, guiroot);
  59. m_guitext_status->setVisible(false);
  60. // Chat text
  61. m_guitext_chat = gui::StaticText::add(guienv, L"", core::rect<s32>(0, 0, 0, 0),
  62. //false, false); // Disable word wrap as of now
  63. false, true, guiroot);
  64. // Profiler text (size is updated when text is updated)
  65. m_guitext_profiler = gui::StaticText::add(guienv, L"<Profiler>",
  66. core::rect<s32>(0, 0, 0, 0), false, false, guiroot);
  67. m_guitext_profiler->setBackgroundColor(video::SColor(120, 0, 0, 0));
  68. m_guitext_profiler->setVisible(false);
  69. m_guitext_profiler->setWordWrap(true);
  70. }
  71. void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_control,
  72. const CameraOrientation &cam, const PointedThing &pointed_old, float dtime)
  73. {
  74. v2u32 screensize = RenderingEngine::get_instance()->getWindowSize();
  75. if (m_flags.show_debug) {
  76. static float drawtime_avg = 0;
  77. drawtime_avg = drawtime_avg * 0.95 + stats.drawtime * 0.05;
  78. u16 fps = 1.0 / stats.dtime_jitter.avg;
  79. std::ostringstream os(std::ios_base::binary);
  80. os << std::fixed
  81. << PROJECT_NAME_C " " << g_version_hash
  82. << ", FPS: " << fps
  83. << std::setprecision(0)
  84. << ", drawtime: " << drawtime_avg << "ms"
  85. << std::setprecision(1)
  86. << ", dtime jitter: "
  87. << (stats.dtime_jitter.max_fraction * 100.0) << "%"
  88. << std::setprecision(1)
  89. << ", view range: "
  90. << (draw_control->range_all ? "All" : itos(draw_control->wanted_range))
  91. << std::setprecision(3)
  92. << ", RTT: " << client->getRTT() << "s";
  93. setStaticText(m_guitext, utf8_to_wide(os.str()).c_str());
  94. m_guitext->setRelativePosition(core::rect<s32>(5, 5, screensize.X,
  95. 5 + g_fontengine->getTextHeight()));
  96. }
  97. // Finally set the guitext visible depending on the flag
  98. m_guitext->setVisible(m_flags.show_debug);
  99. if (m_flags.show_debug) {
  100. LocalPlayer *player = client->getEnv().getLocalPlayer();
  101. v3f player_position = player->getPosition();
  102. std::ostringstream os(std::ios_base::binary);
  103. os << std::setprecision(1) << std::fixed
  104. << "pos: (" << (player_position.X / BS)
  105. << ", " << (player_position.Y / BS)
  106. << ", " << (player_position.Z / BS)
  107. << "), yaw: " << (wrapDegrees_0_360(cam.camera_yaw)) << "° "
  108. << yawToDirectionString(cam.camera_yaw)
  109. << ", seed: " << ((u64)client->getMapSeed());
  110. if (pointed_old.type == POINTEDTHING_NODE) {
  111. ClientMap &map = client->getEnv().getClientMap();
  112. const NodeDefManager *nodedef = client->getNodeDefManager();
  113. MapNode n = map.getNodeNoEx(pointed_old.node_undersurface);
  114. if (n.getContent() != CONTENT_IGNORE && nodedef->get(n).name != "unknown") {
  115. os << ", pointed: " << nodedef->get(n).name
  116. << ", param2: " << (u64) n.getParam2();
  117. }
  118. }
  119. setStaticText(m_guitext2, utf8_to_wide(os.str()).c_str());
  120. m_guitext2->setRelativePosition(core::rect<s32>(5,
  121. 5 + g_fontengine->getTextHeight(), screensize.X,
  122. 5 + g_fontengine->getTextHeight() * 2
  123. ));
  124. }
  125. m_guitext2->setVisible(m_flags.show_debug);
  126. setStaticText(m_guitext_info, translate_string(m_infotext).c_str());
  127. m_guitext_info->setVisible(m_flags.show_hud && g_menumgr.menuCount() == 0);
  128. static const float statustext_time_max = 1.5f;
  129. if (!m_statustext.empty()) {
  130. m_statustext_time += dtime;
  131. if (m_statustext_time >= statustext_time_max) {
  132. clearStatusText();
  133. m_statustext_time = 0.0f;
  134. }
  135. }
  136. setStaticText(m_guitext_status, translate_string(m_statustext).c_str());
  137. m_guitext_status->setVisible(!m_statustext.empty());
  138. if (!m_statustext.empty()) {
  139. s32 status_width = m_guitext_status->getTextWidth();
  140. s32 status_height = m_guitext_status->getTextHeight();
  141. s32 status_y = screensize.Y - 150;
  142. s32 status_x = (screensize.X - status_width) / 2;
  143. m_guitext_status->setRelativePosition(core::rect<s32>(status_x ,
  144. status_y - status_height, status_x + status_width, status_y));
  145. // Fade out
  146. video::SColor final_color = m_statustext_initial_color;
  147. final_color.setAlpha(0);
  148. video::SColor fade_color = m_statustext_initial_color.getInterpolated_quadratic(
  149. m_statustext_initial_color, final_color, m_statustext_time / statustext_time_max);
  150. m_guitext_status->setOverrideColor(fade_color);
  151. m_guitext_status->enableOverrideColor(true);
  152. }
  153. }
  154. void GameUI::initFlags()
  155. {
  156. m_flags = GameUI::Flags();
  157. m_flags.show_chat = true;
  158. m_flags.show_hud = true;
  159. m_flags.show_debug = g_settings->getBool("show_debug");
  160. }
  161. void GameUI::showMinimap(bool show)
  162. {
  163. m_flags.show_minimap = show;
  164. }
  165. void GameUI::showTranslatedStatusText(const char *str)
  166. {
  167. const wchar_t *wmsg = wgettext(str);
  168. showStatusText(wmsg);
  169. delete[] wmsg;
  170. }
  171. void GameUI::setChatText(const EnrichedString &chat_text, u32 recent_chat_count)
  172. {
  173. setStaticText(m_guitext_chat, chat_text);
  174. // Update gui element size and position
  175. s32 chat_y = 5;
  176. if (m_flags.show_debug)
  177. chat_y += 2 * g_fontengine->getLineHeight();
  178. // first pass to calculate height of text to be set
  179. const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize();
  180. s32 width = std::min(g_fontengine->getTextWidth(chat_text.c_str()) + 10,
  181. window_size.X - 20);
  182. m_guitext_chat->setRelativePosition(core::rect<s32>(10, chat_y, width,
  183. chat_y + window_size.Y));
  184. // now use real height of text and adjust rect according to this size
  185. m_guitext_chat->setRelativePosition(core::rect<s32>(10, chat_y, width,
  186. chat_y + m_guitext_chat->getTextHeight()));
  187. // Don't show chat if disabled or empty or profiler is enabled
  188. m_guitext_chat->setVisible(m_flags.show_chat &&
  189. recent_chat_count != 0 && m_profiler_current_page == 0);
  190. }
  191. void GameUI::updateProfiler()
  192. {
  193. if (m_profiler_current_page != 0) {
  194. std::ostringstream os(std::ios_base::binary);
  195. g_profiler->printPage(os, m_profiler_current_page, m_profiler_max_page);
  196. std::wstring text = translate_string(utf8_to_wide(os.str()));
  197. setStaticText(m_guitext_profiler, text.c_str());
  198. s32 w = g_fontengine->getTextWidth(text);
  199. if (w < 400)
  200. w = 400;
  201. u32 text_height = g_fontengine->getTextHeight();
  202. core::position2di upper_left, lower_right;
  203. upper_left.X = 6;
  204. upper_left.Y = (text_height + 5) * 2;
  205. lower_right.X = 12 + w;
  206. lower_right.Y = upper_left.Y + (text_height + 1) * MAX_PROFILER_TEXT_ROWS;
  207. s32 screen_height = RenderingEngine::get_video_driver()->getScreenSize().Height;
  208. if (lower_right.Y > screen_height * 2 / 3)
  209. lower_right.Y = screen_height * 2 / 3;
  210. m_guitext_profiler->setRelativePosition(core::rect<s32>(upper_left, lower_right));
  211. }
  212. m_guitext_profiler->setVisible(m_profiler_current_page != 0);
  213. }
  214. void GameUI::toggleChat()
  215. {
  216. m_flags.show_chat = !m_flags.show_chat;
  217. if (m_flags.show_chat)
  218. showTranslatedStatusText("Chat shown");
  219. else
  220. showTranslatedStatusText("Chat hidden");
  221. }
  222. void GameUI::toggleHud()
  223. {
  224. m_flags.show_hud = !m_flags.show_hud;
  225. if (m_flags.show_hud)
  226. showTranslatedStatusText("HUD shown");
  227. else
  228. showTranslatedStatusText("HUD hidden");
  229. }
  230. void GameUI::toggleProfiler()
  231. {
  232. m_profiler_current_page = (m_profiler_current_page + 1) % (m_profiler_max_page + 1);
  233. // FIXME: This updates the profiler with incomplete values
  234. updateProfiler();
  235. if (m_profiler_current_page != 0) {
  236. wchar_t buf[255];
  237. const wchar_t* str = wgettext("Profiler shown (page %d of %d)");
  238. swprintf(buf, sizeof(buf) / sizeof(wchar_t), str,
  239. m_profiler_current_page, m_profiler_max_page);
  240. delete[] str;
  241. showStatusText(buf);
  242. } else {
  243. showTranslatedStatusText("Profiler hidden");
  244. }
  245. }