DeveloperConsole.cpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. // Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/Core/DeveloperConsole.h>
  6. namespace anki {
  7. DeveloperConsole::~DeveloperConsole()
  8. {
  9. Logger::getSingleton().removeMessageHandler(this, loggerCallback);
  10. while(!m_logItems.isEmpty())
  11. {
  12. LogItem* item = &m_logItems.getFront();
  13. m_logItems.popFront();
  14. deleteInstance(UiMemoryPool::getSingleton(), item);
  15. }
  16. }
  17. Error DeveloperConsole::init()
  18. {
  19. zeroMemory(m_inputText);
  20. ANKI_CHECK(UiManager::getSingleton().newInstance(m_font, "EngineAssets/UbuntuMonoRegular.ttf", Array<U32, 1>{16}));
  21. // Add a new callback to the logger
  22. Logger::getSingleton().addMessageHandler(this, loggerCallback);
  23. return Error::kNone;
  24. }
  25. void DeveloperConsole::build(CanvasPtr ctx)
  26. {
  27. const Vec4 oldWindowColor = ImGui::GetStyle().Colors[ImGuiCol_WindowBg];
  28. ImGui::GetStyle().Colors[ImGuiCol_WindowBg].w = 0.3f;
  29. ctx->pushFont(m_font, 16);
  30. ImGui::Begin("Console", nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoTitleBar);
  31. ImGui::SetWindowPos(Vec2(0.0f, 0.0f));
  32. ImGui::SetWindowSize(Vec2(F32(ctx->getWidth()), F32(ctx->getHeight()) * (2.0f / 3.0f)));
  33. // Push the items
  34. const F32 footerHeightToPreserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing();
  35. ImGui::BeginChild("ScrollingRegion", Vec2(0, -footerHeightToPreserve), false,
  36. ImGuiWindowFlags_HorizontalScrollbar); // Leave room for 1 separator + 1 InputText
  37. ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, Vec2(4.0f, 1.0f)); // Tighten spacing
  38. for(const LogItem& item : m_logItems)
  39. {
  40. switch(item.m_type)
  41. {
  42. case LoggerMessageType::kNormal:
  43. ImGui::PushStyleColor(ImGuiCol_Text, Vec4(0.0f, 1.0f, 0.0f, 1.0f));
  44. break;
  45. case LoggerMessageType::kError:
  46. case LoggerMessageType::kFatal:
  47. ImGui::PushStyleColor(ImGuiCol_Text, Vec4(1.0f, 0.0f, 0.0f, 1.0f));
  48. break;
  49. case LoggerMessageType::kWarning:
  50. ImGui::PushStyleColor(ImGuiCol_Text, Vec4(0.9f, 0.6f, 0.14f, 1.0f));
  51. break;
  52. default:
  53. ANKI_ASSERT(0);
  54. }
  55. constexpr Array<const Char*, U(LoggerMessageType::kCount)> kMsgText = {"I", "E", "W", "F"};
  56. ImGui::TextWrapped("[%s][%s] %s [%s:%d][%s][%s]", kMsgText[item.m_type],
  57. (item.m_subsystem) ? item.m_subsystem : "N/A ", item.m_msg.cstr(), item.m_file, item.m_line,
  58. item.m_func, item.m_threadName.cstr());
  59. ImGui::PopStyleColor();
  60. }
  61. const U32 timestamp = m_logItemsTimestamp.getNonAtomically();
  62. const Bool scrollToLast = m_logItemsTimestampConsumed < timestamp;
  63. if(scrollToLast)
  64. {
  65. ImGui::SetScrollHereY(1.0f);
  66. ++m_logItemsTimestampConsumed;
  67. }
  68. ImGui::PopStyleVar();
  69. ImGui::EndChild();
  70. // Commands
  71. ImGui::Separator();
  72. ImGui::PushItemWidth(-1.0f); // Use the whole size
  73. if(ImGui::InputText("##noname", &m_inputText[0], m_inputText.getSizeInBytes(), ImGuiInputTextFlags_EnterReturnsTrue,
  74. nullptr, nullptr))
  75. {
  76. const Error err = m_scriptEnv.evalString(&m_inputText[0]);
  77. if(!err)
  78. {
  79. ANKI_CORE_LOGI("Script ran without errors");
  80. }
  81. m_inputText[0] = '\0';
  82. }
  83. ImGui::PopItemWidth();
  84. ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget
  85. ImGui::End();
  86. ImGui::GetStyle().Colors[ImGuiCol_WindowBg] = oldWindowColor;
  87. ctx->popFont();
  88. }
  89. void DeveloperConsole::newLogItem(const LoggerMessageInfo& inf)
  90. {
  91. LogItem* newLogItem;
  92. // Pop first
  93. if(m_logItemCount + 1 > kMaxLogItems)
  94. {
  95. LogItem* first = &m_logItems.getFront();
  96. m_logItems.popFront();
  97. first->m_msg.destroy();
  98. first->m_threadName.destroy();
  99. // Re-use the log item
  100. newLogItem = first;
  101. --m_logItemCount;
  102. }
  103. else
  104. {
  105. newLogItem = newInstance<LogItem>(UiMemoryPool::getSingleton());
  106. }
  107. // Create the new item
  108. newLogItem->m_file = inf.m_file;
  109. newLogItem->m_func = inf.m_func;
  110. newLogItem->m_subsystem = inf.m_subsystem;
  111. newLogItem->m_threadName.create(inf.m_threadName);
  112. newLogItem->m_msg.create(inf.m_msg);
  113. newLogItem->m_line = inf.m_line;
  114. newLogItem->m_type = inf.m_type;
  115. // Push it back
  116. m_logItems.pushBack(newLogItem);
  117. ++m_logItemCount;
  118. m_logItemsTimestamp.fetchAdd(1);
  119. }
  120. } // end namespace anki