DeveloperConsole.cpp 4.2 KB

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