DeveloperConsole.cpp 4.1 KB

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