DeveloperConsole.cpp 4.1 KB

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