gameui.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  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. void GameUI::init()
  37. {
  38. // First line of debug text
  39. m_guitext = gui::StaticText::add(guienv, utf8_to_wide(PROJECT_NAME_C).c_str(),
  40. core::rect<s32>(0, 0, 0, 0), false, false, guiroot);
  41. // Second line of debug text
  42. m_guitext2 = gui::StaticText::add(guienv, L"", core::rect<s32>(0, 0, 0, 0), false,
  43. false, guiroot);
  44. // At the middle of the screen
  45. // Object infos are shown in this
  46. m_guitext_info = gui::StaticText::add(guienv, L"",
  47. core::rect<s32>(0, 0, 400, g_fontengine->getTextHeight() * 5 + 5)
  48. + v2s32(100, 200), false, true, guiroot);
  49. // Status text (displays info when showing and hiding GUI stuff, etc.)
  50. m_guitext_status = gui::StaticText::add(guienv, L"<Status>",
  51. core::rect<s32>(0, 0, 0, 0), false, false, guiroot);
  52. m_guitext_status->setVisible(false);
  53. // Chat text
  54. m_guitext_chat = gui::StaticText::add(guienv, L"", core::rect<s32>(0, 0, 0, 0),
  55. //false, false); // Disable word wrap as of now
  56. false, true, guiroot);
  57. // Profiler text (size is updated when text is updated)
  58. m_guitext_profiler = gui::StaticText::add(guienv, L"<Profiler>",
  59. core::rect<s32>(0, 0, 0, 0), false, false, guiroot);
  60. m_guitext_profiler->setBackgroundColor(video::SColor(120, 0, 0, 0));
  61. m_guitext_profiler->setVisible(false);
  62. m_guitext_profiler->setWordWrap(true);
  63. }
  64. void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_control,
  65. const CameraOrientation &cam, const PointedThing &pointed_old, float dtime)
  66. {
  67. v2u32 screensize = RenderingEngine::get_instance()->getWindowSize();
  68. if (m_flags.show_debug) {
  69. static float drawtime_avg = 0;
  70. drawtime_avg = drawtime_avg * 0.95 + stats.drawtime * 0.05;
  71. u16 fps = 1.0 / stats.dtime_jitter.avg;
  72. std::ostringstream os(std::ios_base::binary);
  73. os << std::fixed
  74. << PROJECT_NAME_C " " << g_version_hash
  75. << ", FPS: " << fps
  76. << std::setprecision(0)
  77. << ", drawtime: " << drawtime_avg << "ms"
  78. << std::setprecision(1)
  79. << ", dtime jitter: "
  80. << (stats.dtime_jitter.max_fraction * 100.0) << "%"
  81. << std::setprecision(1)
  82. << ", view range: "
  83. << (draw_control->range_all ? "All" : itos(draw_control->wanted_range))
  84. << std::setprecision(3)
  85. << ", RTT: " << client->getRTT() << "s";
  86. setStaticText(m_guitext, utf8_to_wide(os.str()).c_str());
  87. m_guitext->setRelativePosition(core::rect<s32>(5, 5, screensize.X,
  88. 5 + g_fontengine->getTextHeight()));
  89. }
  90. // Finally set the guitext visible depending on the flag
  91. m_guitext->setVisible(m_flags.show_debug);
  92. if (m_flags.show_debug) {
  93. LocalPlayer *player = client->getEnv().getLocalPlayer();
  94. v3f player_position = player->getPosition();
  95. std::ostringstream os(std::ios_base::binary);
  96. os << std::setprecision(1) << std::fixed
  97. << "pos: (" << (player_position.X / BS)
  98. << ", " << (player_position.Y / BS)
  99. << ", " << (player_position.Z / BS)
  100. << "), yaw: " << (wrapDegrees_0_360(cam.camera_yaw)) << "° "
  101. << yawToDirectionString(cam.camera_yaw)
  102. << ", seed: " << ((u64)client->getMapSeed());
  103. if (pointed_old.type == POINTEDTHING_NODE) {
  104. ClientMap &map = client->getEnv().getClientMap();
  105. const INodeDefManager *nodedef = client->getNodeDefManager();
  106. MapNode n = map.getNodeNoEx(pointed_old.node_undersurface);
  107. if (n.getContent() != CONTENT_IGNORE && nodedef->get(n).name != "unknown") {
  108. os << ", pointed: " << nodedef->get(n).name
  109. << ", param2: " << (u64) n.getParam2();
  110. }
  111. }
  112. setStaticText(m_guitext2, utf8_to_wide(os.str()).c_str());
  113. m_guitext2->setRelativePosition(core::rect<s32>(5,
  114. 5 + g_fontengine->getTextHeight(), screensize.X,
  115. 5 + g_fontengine->getTextHeight() * 2
  116. ));
  117. }
  118. m_guitext2->setVisible(m_flags.show_debug);
  119. setStaticText(m_guitext_info, translate_string(m_infotext).c_str());
  120. m_guitext_info->setVisible(m_flags.show_hud && g_menumgr.menuCount() == 0);
  121. static const float statustext_time_max = 1.5f;
  122. if (!m_statustext.empty()) {
  123. m_statustext_time += dtime;
  124. if (m_statustext_time >= statustext_time_max) {
  125. clearStatusText();
  126. m_statustext_time = 0.0f;
  127. }
  128. }
  129. setStaticText(m_guitext_status, translate_string(m_statustext).c_str());
  130. m_guitext_status->setVisible(!m_statustext.empty());
  131. if (!m_statustext.empty()) {
  132. s32 status_width = m_guitext_status->getTextWidth();
  133. s32 status_height = m_guitext_status->getTextHeight();
  134. s32 status_y = screensize.Y - 150;
  135. s32 status_x = (screensize.X - status_width) / 2;
  136. m_guitext_status->setRelativePosition(core::rect<s32>(status_x ,
  137. status_y - status_height, status_x + status_width, status_y));
  138. // Fade out
  139. video::SColor initial_color(255, 0, 0, 0);
  140. if (guienv->getSkin())
  141. initial_color = guienv->getSkin()->getColor(gui::EGDC_BUTTON_TEXT);
  142. video::SColor final_color = initial_color;
  143. final_color.setAlpha(0);
  144. video::SColor fade_color = initial_color.getInterpolated_quadratic(
  145. initial_color, final_color,
  146. pow(m_statustext_time / statustext_time_max, 2.0f));
  147. m_guitext_status->setOverrideColor(fade_color);
  148. m_guitext_status->enableOverrideColor(true);
  149. }
  150. }
  151. void GameUI::initFlags()
  152. {
  153. memset(&m_flags, 0, sizeof(GameUI::Flags));
  154. m_flags.show_chat = true;
  155. m_flags.show_hud = true;
  156. m_flags.show_debug = g_settings->getBool("show_debug");
  157. }
  158. void GameUI::showMinimap(bool show)
  159. {
  160. m_flags.show_minimap = show;
  161. }
  162. void GameUI::showTranslatedStatusText(const char *str)
  163. {
  164. const wchar_t *wmsg = wgettext(str);
  165. showStatusText(wmsg);
  166. delete[] wmsg;
  167. }
  168. void GameUI::setChatText(const EnrichedString &chat_text, u32 recent_chat_count)
  169. {
  170. setStaticText(m_guitext_chat, chat_text);
  171. // Update gui element size and position
  172. s32 chat_y = 5;
  173. if (m_flags.show_debug)
  174. chat_y += 2 * g_fontengine->getLineHeight();
  175. // first pass to calculate height of text to be set
  176. const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize();
  177. s32 width = std::min(g_fontengine->getTextWidth(chat_text.c_str()) + 10,
  178. window_size.X - 20);
  179. m_guitext_chat->setRelativePosition(core::rect<s32>(10, chat_y, width,
  180. chat_y + window_size.Y));
  181. // now use real height of text and adjust rect according to this size
  182. m_guitext_chat->setRelativePosition(core::rect<s32>(10, chat_y, width,
  183. chat_y + m_guitext_chat->getTextHeight()));
  184. // Don't show chat if disabled or empty or profiler is enabled
  185. m_guitext_chat->setVisible(m_flags.show_chat &&
  186. recent_chat_count != 0 && m_profiler_current_page == 0);
  187. }
  188. void GameUI::updateProfiler()
  189. {
  190. if (m_profiler_current_page != 0) {
  191. std::ostringstream os(std::ios_base::binary);
  192. g_profiler->printPage(os, m_profiler_current_page, m_profiler_max_page);
  193. std::wstring text = translate_string(utf8_to_wide(os.str()));
  194. setStaticText(m_guitext_profiler, text.c_str());
  195. s32 w = g_fontengine->getTextWidth(text);
  196. if (w < 400)
  197. w = 400;
  198. unsigned text_height = g_fontengine->getTextHeight();
  199. core::position2di upper_left, lower_right;
  200. upper_left.X = 6;
  201. upper_left.Y = (text_height + 5) * 2;
  202. lower_right.X = 12 + w;
  203. lower_right.Y = upper_left.Y + (text_height + 1) * MAX_PROFILER_TEXT_ROWS;
  204. s32 screen_height = RenderingEngine::get_video_driver()->getScreenSize().Height;
  205. if (lower_right.Y > screen_height * 2 / 3)
  206. lower_right.Y = screen_height * 2 / 3;
  207. m_guitext_profiler->setRelativePosition(core::rect<s32>(upper_left, lower_right));
  208. }
  209. m_guitext_profiler->setVisible(m_profiler_current_page != 0);
  210. }
  211. void GameUI::toggleChat()
  212. {
  213. m_flags.show_chat = !m_flags.show_chat;
  214. if (m_flags.show_chat)
  215. showTranslatedStatusText("Chat shown");
  216. else
  217. showTranslatedStatusText("Chat hidden");
  218. }
  219. void GameUI::toggleHud()
  220. {
  221. m_flags.show_hud = !m_flags.show_hud;
  222. if (m_flags.show_hud)
  223. showTranslatedStatusText("HUD shown");
  224. else
  225. showTranslatedStatusText("HUD hidden");
  226. }
  227. void GameUI::toggleProfiler()
  228. {
  229. m_profiler_current_page = (m_profiler_current_page + 1) % (m_profiler_max_page + 1);
  230. // FIXME: This updates the profiler with incomplete values
  231. updateProfiler();
  232. if (m_profiler_current_page != 0) {
  233. wchar_t buf[255];
  234. const wchar_t* str = wgettext("Profiler shown (page %d of %d)");
  235. swprintf(buf, sizeof(buf) / sizeof(wchar_t), str,
  236. m_profiler_current_page, m_profiler_max_page);
  237. delete[] str;
  238. showStatusText(buf);
  239. } else {
  240. showTranslatedStatusText("Profiler hidden");
  241. }
  242. }