Show logs in the debug window

Some part of UI code is written by @andrew-app
openmw-fix_osx_build_maybe
Petr Mikheev 2 years ago
parent 5110c4a50e
commit cf49b46d64

@ -143,6 +143,7 @@
Feature #6128: Soft Particles
Feature #6161: Refactor Sky to use shaders and GLES/GL3 friendly
Feature #6162: Refactor GUI to use shaders and to be GLES and GL3+ friendly
Feature #6171: In-game log viewer
Feature #6189: Navigation mesh disk cache
Feature #6199: Support FBO Rendering
Feature #6248: Embedded error marker mesh

@ -5,6 +5,8 @@
#include <MyGUI_EditBox.h>
#include <LinearMath/btQuickprof.h>
#include <components/debug/debugging.hpp>
#include <components/settings/settings.hpp>
#ifndef BT_NO_PROFILE
@ -84,28 +86,105 @@ namespace MWGui
// Ideas for other tabs:
// - Texture / compositor texture viewer
// - Log viewer
// - Material editor
// - Shader editor
initLogView();
#ifndef BT_NO_PROFILE
MyGUI::TabItem* item = mTabControl->addItem("Physics Profiler");
mBulletProfilerEdit = item->createWidgetReal<MyGUI::EditBox>
("LogEdit", MyGUI::FloatCoord(0,0,1,1), MyGUI::Align::Stretch);
#else
mBulletProfilerEdit = nullptr;
#endif
}
void DebugWindow::onFrame(float dt)
void DebugWindow::initLogView()
{
#ifndef BT_NO_PROFILE
if (!isVisible())
return;
MyGUI::TabItem* itemLV = mTabControl->addItem("Log Viewer");
mLogView = itemLV->createWidgetReal<MyGUI::EditBox>
("LogEdit", MyGUI::FloatCoord(0,0,1,1), MyGUI::Align::Stretch);
mLogView->setEditReadOnly(true);
static float timer = 0;
timer -= dt;
mLogCircularBuffer.resize(std::max<int64_t>(0, Settings::Manager::getInt64("log buffer size", "General")));
Debug::setLogListener([this](Debug::Level level, std::string_view prefix, std::string_view msg)
{
if (mLogCircularBuffer.empty())
return; // Log viewer is disabled.
std::string_view color;
switch (level)
{
case Debug::Error: color = "#FF0000"; break;
case Debug::Warning: color = "#FFFF00"; break;
case Debug::Info: color = "#FFFFFF"; break;
case Debug::Verbose:
case Debug::Debug: color = "#666666"; break;
default: color = "#FFFFFF";
}
bool bufferOverflow = false;
const int64_t bufSize = mLogCircularBuffer.size();
auto addChar = [&](char c)
{
mLogCircularBuffer[mLogEndIndex++] = c;
if (mLogEndIndex == bufSize)
mLogEndIndex = 0;
bufferOverflow = bufferOverflow || mLogEndIndex == mLogStartIndex;
};
auto addShieldedStr = [&](std::string_view s)
{
for (char c : s)
{
addChar(c);
if (c == '#')
addChar(c);
}
};
for (char c : color)
addChar(c);
addShieldedStr(prefix);
addShieldedStr(msg);
if (bufferOverflow)
mLogStartIndex = (mLogEndIndex + 1) % bufSize;
});
}
if (timer > 0)
void DebugWindow::updateLogView()
{
if (!mLogView || mLogCircularBuffer.empty() || mLogStartIndex == mLogEndIndex)
return;
timer = 1;
if (mLogView->isTextSelection())
return; // Don't change text while player is trying to copy something
std::string addition;
const int64_t bufSize = mLogCircularBuffer.size();
{
std::unique_lock<std::mutex> lock = Log::lock();
if (mLogStartIndex < mLogEndIndex)
addition = std::string(mLogCircularBuffer.data() + mLogStartIndex, mLogEndIndex - mLogStartIndex);
else
{
addition = std::string(mLogCircularBuffer.data() + mLogStartIndex, bufSize - mLogStartIndex);
addition.append(mLogCircularBuffer.data(), mLogEndIndex);
}
mLogStartIndex = mLogEndIndex;
}
size_t scrollPos = mLogView->getVScrollPosition();
bool scrolledToTheEnd = scrollPos+1 >= mLogView->getVScrollRange();
int64_t newSizeEstimation = mLogView->getTextLength() + addition.size();
if (newSizeEstimation > bufSize)
mLogView->eraseText(0, newSizeEstimation - bufSize);
mLogView->addText(addition);
if (scrolledToTheEnd && mLogView->getVScrollRange() > 0)
mLogView->setVScrollPosition(mLogView->getVScrollRange() - 1);
else
mLogView->setVScrollPosition(scrollPos);
}
void DebugWindow::updateBulletProfile()
{
#ifndef BT_NO_PROFILE
std::stringstream stream;
bulletDumpAll(stream);
@ -118,4 +197,17 @@ namespace MWGui
#endif
}
}
void DebugWindow::onFrame(float dt)
{
static float timer = 0;
timer -= dt;
if (timer > 0 || !isVisible())
return;
timer = 0.25;
if (mTabControl->getIndexSelected() == 0)
updateLogView();
else
updateBulletProfile();
}
}

@ -14,8 +14,17 @@ namespace MWGui
void onFrame(float dt) override;
private:
void initLogView();
void updateLogView();
void updateBulletProfile();
MyGUI::TabControl* mTabControl;
MyGUI::EditBox* mLogView;
std::vector<char> mLogCircularBuffer;
int64_t mLogStartIndex = 0;
int64_t mLogEndIndex = 0;
MyGUI::EditBox* mBulletProfilerEdit;
};

@ -884,6 +884,8 @@ namespace MWGui
if (mLocalMapRender)
mLocalMapRender->cleanupCameras();
mDebugWindow->onFrame(frameDuration);
if (!gameRunning)
return;
@ -903,8 +905,6 @@ namespace MWGui
mHud->onFrame(frameDuration);
mDebugWindow->onFrame(frameDuration);
mPostProcessorHud->onFrame(frameDuration);
if (mCharGen)
@ -2061,9 +2061,7 @@ namespace MWGui
void WindowManager::toggleDebugWindow()
{
#ifndef BT_NO_PROFILE
mDebugWindow->setVisible(!mDebugWindow->isVisible());
#endif
}
void WindowManager::togglePostProcessorHud()

@ -61,6 +61,9 @@ namespace Debug
}
#endif
static LogListener logListener;
void setLogListener(LogListener listener) { logListener = std::move(listener); }
std::streamsize DebugOutputBase::write(const char *str, std::streamsize size)
{
if (size <= 0)
@ -94,6 +97,8 @@ namespace Debug
lineSize++;
writeImpl(prefix, prefixSize, level);
writeImpl(msg.data(), lineSize, level);
if (logListener)
logListener(level, std::string_view(prefix, prefixSize), std::string_view(msg.data(), lineSize));
msg = msg.substr(lineSize);
}

@ -133,6 +133,8 @@ namespace Debug
};
#endif
using LogListener = std::function<void(Debug::Level, std::string_view prefix, std::string_view msg)>;
void setLogListener(LogListener);
}

@ -35,7 +35,7 @@ public:
return;
// Locks a global lock while the object is alive
mLock = std::unique_lock<std::mutex>(sLock);
mLock = lock();
// If the app has no logging system enabled, log level is not specified.
// Show all messages without marker - we just use the plain cout in this case.
@ -61,6 +61,8 @@ public:
std::cout << std::endl;
}
static std::unique_lock<std::mutex> lock() { return std::unique_lock<std::mutex>(sLock); }
private:
const bool mShouldLog;
};

@ -86,3 +86,17 @@ since if the country code isn't specified the generic language-code only locale
refer to any of the country-specific variants.
This setting can only be configured by editing the settings configuration file.
log buffer size
---------------
:Type: integer
:Range: >= 0
:Default: 65536
Buffer size for the in-game log viewer (press F10 to toggle the log viewer).
When the log doesn't fit into the buffer, only the end of the log is visible in the log viewer.
Zero disables the log viewer.
This setting can only be configured by editing the settings configuration file.

@ -8,14 +8,14 @@
<Property key="Size" value="600 520"/>
</Layer>
<Layer name="Windows" overlapped="true" pick="true"/>
<Layer name="Debug" overlapped="true" pick="true"/>
<Layer name="DragAndDrop" overlapped="false" pick="false"/>
<Layer name="DrowningBar" overlapped="false" pick="false"/>
<Layer name="MainMenuBackground" overlapped="true" pick="true"/>
<Layer name="MainMenu" overlapped="true" pick="true"/>
<Layer name="Console" overlapped="true" pick="true"/>
<Layer name="LoadingScreenBackground" overlapped="false" pick="true"/>
<Layer name="LoadingScreen" overlapped="false" pick="true"/>
<Layer name="Debug" overlapped="true" pick="true"/>
<Layer name="Console" overlapped="true" pick="true"/>
<Layer name="Modal" overlapped="true" pick="true"/>
<Layer name="Popup" overlapped="true" pick="true"/>
<Layer name="Notification" overlapped="false" pick="false"/>

@ -400,6 +400,9 @@ notify on saved screenshot = false
# For example "de,en" means German as the first prority and English as a fallback.
preferred locales = en
# Buffer size for the in-game log viewer (press F10 to toggle). Zero disables the log viewer.
log buffer size = 65536
[Shaders]
# Force rendering with shaders. By default, only bump-mapped objects will use shaders.

Loading…
Cancel
Save