Files
WickedEngine/WickedEngine/wiBacklog.cpp
T
Turánszki János c4c582d739 general improvements (#368)
* custom implementation for wi::vector

* fix

* sdl vulkan fix

* linux fix

* fix

* vector fix

* shader compiler and job system will be initialized automatically on first use

* vector improvements

* updates

* update

* network and audio will be auto initializing on first use only

* fix

* for now, use std::vector

* vector refactor minor

* backlog: access safety

* shader clearcoat fix

* gui initialization on demand

* initializer updates

* job system will be explicitly initialized
2021-12-09 18:58:27 +01:00

334 lines
6.6 KiB
C++

#include "wiBacklog.h"
#include "wiMath.h"
#include "wiResourceManager.h"
#include "wiTextureHelper.h"
#include "wiSpinLock.h"
#include "wiFont.h"
#include "wiSpriteFont.h"
#include "wiImage.h"
#include "wiLua.h"
#include "wiInput.h"
#include "wiPlatform.h"
#include "wiHelper.h"
#include <mutex>
#include <deque>
#include <limits>
#include <thread>
#include <iostream>
using namespace wi::graphics;
namespace wi::backlog
{
bool enabled = false;
std::deque<std::string> stream;
std::deque<std::string> history;
const float speed = 4000.0f;
const size_t deletefromline = 500;
float pos = std::numeric_limits<float>::lowest();
float scroll = 0;
std::string inputArea;
int historyPos = 0;
wi::SpriteFont font;
wi::SpinLock logLock;
Texture backgroundTex;
bool refitscroll = false;
bool locked = false;
bool blockLuaExec = false;
LogLevel logLevel = LogLevel::Default;
void write_logfile()
{
std::string filename = wi::helper::GetTempDirectoryPath() + "wiBacklog.txt";
std::string text = getText(); // will lock mutex
wi::helper::FileWrite(filename, (const uint8_t*)text.c_str(), text.length());
}
// The logwriter object will automatically write out the backlog to the temp folder when it's destroyed
// Should happen on application exit
struct LogWriter
{
~LogWriter()
{
write_logfile();
}
} logwriter;
void Toggle()
{
enabled = !enabled;
}
void Scroll(float dir)
{
scroll += dir;
}
void Update(const wi::Canvas& canvas, float dt)
{
if (!locked)
{
if (wi::input::Press(wi::input::KEYBOARD_BUTTON_HOME))
{
Toggle();
}
if (isActive())
{
if (wi::input::Press(wi::input::KEYBOARD_BUTTON_UP))
{
historyPrev();
}
if (wi::input::Press(wi::input::KEYBOARD_BUTTON_DOWN))
{
historyNext();
}
if (wi::input::Press(wi::input::KEYBOARD_BUTTON_ENTER))
{
acceptInput();
}
if (wi::input::Down(wi::input::KEYBOARD_BUTTON_PAGEUP))
{
Scroll(1000.0f * dt);
}
if (wi::input::Down(wi::input::KEYBOARD_BUTTON_PAGEDOWN))
{
Scroll(-1000.0f * dt);
}
}
}
if (enabled)
{
pos += speed * dt;
}
else
{
pos -= speed * dt;
}
pos = wi::math::Clamp(pos, -canvas.GetLogicalHeight(), 0);
}
void Draw(const wi::Canvas& canvas, CommandList cmd)
{
if (pos > -canvas.GetLogicalHeight())
{
if (!backgroundTex.IsValid())
{
const uint8_t colorData[] = { 0, 0, 43, 200, 43, 31, 141, 223 };
wi::texturehelper::CreateTexture(backgroundTex, colorData, 1, 2);
}
wi::image::Params fx = wi::image::Params((float)canvas.GetLogicalWidth(), (float)canvas.GetLogicalHeight());
fx.pos = XMFLOAT3(0, pos, 0);
fx.opacity = wi::math::Lerp(1, 0, -pos / canvas.GetLogicalHeight());
wi::image::Draw(&backgroundTex, fx, cmd);
wi::font::Params params = wi::font::Params(10, canvas.GetLogicalHeight() - 10, wi::font::WIFONTSIZE_DEFAULT, wi::font::WIFALIGN_LEFT, wi::font::WIFALIGN_BOTTOM);
params.h_wrap = canvas.GetLogicalWidth() - params.posX;
params.v_align = wi::font::WIFALIGN_BOTTOM;
wi::font::Draw(inputArea, params, cmd);
font.SetText(getText());
if (refitscroll)
{
refitscroll = false;
float textheight = font.TextHeight();
float limit = canvas.GetLogicalHeight() * 0.9f;
if (scroll + textheight > limit)
{
scroll = limit - textheight;
}
}
font.params.posX = 50;
font.params.posY = pos + scroll;
font.params.h_wrap = canvas.GetLogicalWidth() - font.params.posX;
Rect rect;
rect.left = 0;
rect.right = (int32_t)canvas.GetPhysicalWidth();
rect.top = 0;
rect.bottom = int32_t(canvas.GetPhysicalHeight() * 0.9f);
wi::graphics::GetDevice()->BindScissorRects(1, &rect, cmd);
font.Draw(cmd);
rect.left = -std::numeric_limits<int>::max();
rect.right = std::numeric_limits<int>::max();
rect.top = -std::numeric_limits<int>::max();
rect.bottom = std::numeric_limits<int>::max();
wi::graphics::GetDevice()->BindScissorRects(1, &rect, cmd);
}
}
std::string getText()
{
std::scoped_lock lock(logLock);
std::string retval;
for (auto& x : stream)
{
retval += x;
}
return retval;
}
void clear()
{
std::scoped_lock lock(logLock);
stream.clear();
scroll = 0;
}
void post(const std::string& input, LogLevel level)
{
if (logLevel > level)
{
return;
}
// This is explicitly scoped for scoped_lock!
{
std::scoped_lock lock(logLock);
std::string str;
switch (level)
{
default:
case LogLevel::Default:
str = "";
break;
case LogLevel::Warning:
str = "[Warning] ";
break;
case LogLevel::Error:
str = "[Error] ";
break;
}
str += input;
str += '\n';
stream.push_back(str);
if (stream.size() > deletefromline)
{
stream.pop_front();
}
refitscroll = true;
#ifdef _WIN32
OutputDebugStringA(str.c_str());
#endif // _WIN32
switch (level)
{
default:
case LogLevel::Default:
std::cout << str;
break;
case LogLevel::Warning:
std::clog << str;
break;
case LogLevel::Error:
std::cerr << str;
break;
}
// lock released on block end
}
if (level >= LogLevel::Error)
{
write_logfile(); // will lock mutex
}
}
void input(const char input)
{
std::scoped_lock lock(logLock);
inputArea += input;
}
void acceptInput()
{
historyPos = 0;
post(inputArea.c_str());
history.push_back(inputArea);
if (history.size() > deletefromline)
{
history.pop_front();
}
if (!blockLuaExec)
{
wi::lua::RunText(inputArea);
}
else
{
post("Lua execution is disabled", LogLevel::Error);
}
inputArea.clear();
}
void deletefromInput()
{
std::scoped_lock lock(logLock);
if (!inputArea.empty())
{
inputArea.pop_back();
}
}
void historyPrev()
{
std::scoped_lock lock(logLock);
if (!history.empty())
{
inputArea = history[history.size() - 1 - historyPos];
if ((size_t)historyPos < history.size() - 1)
{
historyPos++;
}
}
}
void historyNext()
{
std::scoped_lock lock(logLock);
if (!history.empty())
{
if (historyPos > 0)
{
historyPos--;
}
inputArea = history[history.size() - 1 - historyPos];
}
}
void setBackground(Texture* texture)
{
backgroundTex = *texture;
}
void setFontSize(int value)
{
font.params.size = value;
}
void setFontRowspacing(float value)
{
font.params.spacingY = value;
}
bool isActive() { return enabled; }
void Lock()
{
locked = true;
enabled = false;
}
void Unlock()
{
locked = false;
}
void BlockLuaExecution()
{
blockLuaExec = true;
}
void UnblockLuaExecution()
{
blockLuaExec = false;
}
void SetLogLevel(LogLevel newLevel)
{
logLevel = newLevel;
}
}