font renderer: exposed cursor offset; backlog: colored loglevel;

This commit is contained in:
Turánszki János
2022-06-01 12:24:30 +02:00
parent 1dd03455af
commit 2104d41b94
5 changed files with 108 additions and 58 deletions
+60 -21
View File
@@ -22,15 +22,20 @@ using namespace wi::graphics;
namespace wi::backlog
{
bool enabled = false;
std::deque<std::string> stream;
std::deque<std::string> history;
struct LogEntry
{
std::string text;
LogLevel level = LogLevel::Default;
};
std::deque<LogEntry> entries;
std::deque<LogEntry> 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::font::Params font_params;
wi::SpinLock logLock;
Texture backgroundTex;
bool refitscroll = false;
@@ -123,32 +128,60 @@ namespace wi::backlog
fx.opacity = wi::math::Lerp(1, 0, -pos / canvas.GetLogicalHeight());
wi::image::Draw(&backgroundTex, fx, cmd);
fx.pos = XMFLOAT3(5, canvas.GetLogicalHeight() - 30, 0);
fx.siz = XMFLOAT2(canvas.GetLogicalWidth() - 10, 25);
fx.color = XMFLOAT4(1, 1, 1, 0.2f);
wi::image::Draw(wi::texturehelper::getWhite(), 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;
params.shadowColor = 0x10000000u;
params.shadow_offset_x = 2;
params.shadow_offset_y = 2;
params.shadow_softness = 1;
wi::font::Draw(inputArea, params, cmd);
font.SetText(getText());
font_params.cursor = XMFLOAT2(0, 0);
params.shadowColor = 0x10000000u;
params.shadow_offset_x = 2;
params.shadow_offset_y = 2;
params.shadow_softness = 1;
if (refitscroll)
{
refitscroll = false;
float textheight = font.TextHeight();
float textheight = wi::font::TextHeight(getText(), font_params);
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;
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);
rect.bottom = int32_t(canvas.LogicalToPhysical(canvas.GetLogicalHeight() - 35));
wi::graphics::GetDevice()->BindScissorRects(1, &rect, cmd);
font.Draw(cmd);
for (auto& x : entries)
{
switch (x.level)
{
case LogLevel::Warning:
font_params.color = 0xFF66FFFF; // light yellow
break;
case LogLevel::Error:
font_params.color = 0xFF6666FF; // light red
break;
default:
font_params.color = wi::Color::White();
break;
}
font_params.cursor = wi::font::Draw(x.text, font_params, cmd);
}
rect.left = -std::numeric_limits<int>::max();
rect.right = std::numeric_limits<int>::max();
rect.top = -std::numeric_limits<int>::max();
@@ -162,16 +195,16 @@ namespace wi::backlog
{
std::scoped_lock lock(logLock);
std::string retval;
for (auto& x : stream)
for (auto& x : entries)
{
retval += x;
retval += x.text;
}
return retval;
}
void clear()
{
std::scoped_lock lock(logLock);
stream.clear();
entries.clear();
scroll = 0;
}
void post(const std::string& input, LogLevel level)
@@ -201,10 +234,13 @@ namespace wi::backlog
}
str += input;
str += '\n';
stream.push_back(str);
if (stream.size() > deletefromline)
LogEntry entry;
entry.text = str;
entry.level = level;
entries.push_back(entry);
if (entries.size() > deletefromline)
{
stream.pop_front();
entries.pop_front();
}
refitscroll = true;
@@ -243,7 +279,10 @@ namespace wi::backlog
{
historyPos = 0;
post(inputArea.c_str());
history.push_back(inputArea);
LogEntry entry;
entry.text = inputArea;
entry.level = LogLevel::Default;
history.push_back(entry);
if (history.size() > deletefromline)
{
history.pop_front();
@@ -272,7 +311,7 @@ namespace wi::backlog
std::scoped_lock lock(logLock);
if (!history.empty())
{
inputArea = history[history.size() - 1 - historyPos];
inputArea = history[history.size() - 1 - historyPos].text;
if ((size_t)historyPos < history.size() - 1)
{
historyPos++;
@@ -288,7 +327,7 @@ namespace wi::backlog
{
historyPos--;
}
inputArea = history[history.size() - 1 - historyPos];
inputArea = history[history.size() - 1 - historyPos].text;
}
}
@@ -298,11 +337,11 @@ namespace wi::backlog
}
void setFontSize(int value)
{
font.params.size = value;
font_params.size = value;
}
void setFontRowspacing(float value)
{
font.params.spacingY = value;
font_params.spacingY = value;
}
bool isActive() { return enabled; }
+6 -2
View File
@@ -37,6 +37,10 @@ namespace wi
inline float GetDPI() const { return dpi * scaling; }
// The scaling factor between logical and physical coordinates
inline float GetDPIScaling() const { return GetDPI() / 96.f; }
// Convert from logical to physical coordinates
inline uint32_t LogicalToPhysical(float logical) const { return uint32_t(logical * GetDPIScaling()); }
// Convert from physical to logical coordinates
inline float PhysicalToLogical(uint32_t physical) const { return float(physical) / GetDPIScaling(); }
// Returns native resolution width in pixels:
// Use this for texture allocations
// Use this for scissor, viewport
@@ -47,10 +51,10 @@ namespace wi
inline uint32_t GetPhysicalHeight() const { return height; }
// Returns the width with DPI scaling applied (subpixel size):
// Use this for logic and positioning drawable elements
inline float GetLogicalWidth() const { return GetPhysicalWidth() / GetDPIScaling(); }
inline float GetLogicalWidth() const { return PhysicalToLogical(GetPhysicalWidth()); }
// Returns the height with DPI scaling applied (subpixel size):
// Use this for logic and positioning drawable elements
inline float GetLogicalHeight() const { return GetPhysicalHeight() / GetDPIScaling(); }
inline float GetLogicalHeight() const { return PhysicalToLogical(GetPhysicalHeight()); }
// Returns projection matrix that maps logical to physical space
// Use this to render to a graphics viewport
inline XMMATRIX GetProjection() const
+34 -30
View File
@@ -126,6 +126,8 @@ namespace wi::font
Cursor ParseText(const T* text, size_t text_length, Params params)
{
Cursor cursor;
cursor.pos = params.cursor;
const FontStyle& fontStyle = fontStyles[params.style];
const float fontScale = stbtt_ScaleForPixelHeight(&fontStyle.fontInfo, (float)params.size);
vertexList.clear();
@@ -135,7 +137,7 @@ namespace wi::font
if (cursor.last_word_begin > 0 && params.h_wrap >= 0 && cursor.pos.x >= params.h_wrap - 1)
{
// Word ended and wrap detected, push down last word by one line:
float word_offset = vertexList[cursor.last_word_begin].pos.x;
float word_offset = vertexList[cursor.last_word_begin].pos.x + WHITESPACE_SIZE;
for (size_t i = cursor.last_word_begin; i < cursor.quadCount * 4; ++i)
{
vertexList[i].pos.x -= word_offset;
@@ -146,7 +148,7 @@ namespace wi::font
}
};
cursor.size.y = LINEBREAK_SIZE;
cursor.size.y = cursor.pos.y + LINEBREAK_SIZE;
for (size_t i = 0; i < text_length; ++i)
{
T character = text[i];
@@ -431,23 +433,23 @@ namespace wi::font
}
template<typename T>
void Draw_internal(const T* text, size_t text_length, const Params& params, CommandList cmd)
XMFLOAT2 Draw_internal(const T* text, size_t text_length, const Params& params_in, CommandList cmd)
{
if (text_length <= 0)
{
return;
return XMFLOAT2(0, 0);
}
Cursor cursor = ParseText(text, text_length, params);
Cursor cursor = ParseText(text, text_length, params_in);
Params newProps = params;
Params params = params_in;
if (params.h_align == WIFALIGN_CENTER)
newProps.posX -= cursor.size.x / 2;
params.posX -= cursor.size.x / 2;
else if (params.h_align == WIFALIGN_RIGHT)
newProps.posX -= cursor.size.x;
params.posX -= cursor.size.x;
if (params.v_align == WIFALIGN_CENTER)
newProps.posY -= cursor.size.y / 2;
params.posY -= cursor.size.y / 2;
else if (params.v_align == WIFALIGN_BOTTOM)
newProps.posY -= cursor.size.y;
params.posY -= cursor.size.y;
if (cursor.quadCount > 0)
@@ -456,7 +458,7 @@ namespace wi::font
GraphicsDevice::GPUAllocation mem = device->AllocateGPU(sizeof(FontVertex) * cursor.quadCount * 4, cmd);
if (!mem.IsValid())
{
return;
return cursor.pos;
}
CommitText(mem.data);
@@ -476,16 +478,16 @@ namespace wi::font
assert(canvas.dpi > 0);
const XMMATRIX Projection = canvas.GetProjection();
if (newProps.shadowColor.getA() > 0)
if (params.shadowColor.getA() > 0)
{
// font shadow render:
XMStoreFloat4x4(&font.transform,
XMMatrixTranslation((float)newProps.posX + newProps.shadow_offset_x, (float)newProps.posY + newProps.shadow_offset_y, 0)
XMMatrixTranslation((float)params.posX + params.shadow_offset_x, (float)params.posY + params.shadow_offset_y, 0)
* Projection
);
font.color = newProps.shadowColor.rgba;
font.sdf_threshold_top = wi::math::Lerp(float(SDF::onedge_value) / 255.0f, 0, std::max(0.0f, newProps.shadow_bolden));
font.sdf_threshold_bottom = wi::math::Lerp(font.sdf_threshold_top, 0, std::max(0.0f, newProps.shadow_softness));
font.color = params.shadowColor.rgba;
font.sdf_threshold_top = wi::math::Lerp(float(SDF::onedge_value) / 255.0f, 0, std::max(0.0f, params.shadow_bolden));
font.sdf_threshold_bottom = wi::math::Lerp(font.sdf_threshold_top, 0, std::max(0.0f, params.shadow_softness));
device->BindDynamicConstantBuffer(font, CBSLOT_FONT, cmd);
device->DrawInstanced(4, cursor.quadCount, 0, 0, cmd);
@@ -493,18 +495,20 @@ namespace wi::font
// font base render:
XMStoreFloat4x4(&font.transform,
XMMatrixTranslation((float)newProps.posX, (float)newProps.posY, 0)
XMMatrixTranslation((float)params.posX, (float)params.posY, 0)
* Projection
);
font.color = newProps.color.rgba;
font.sdf_threshold_top = wi::math::Lerp(float(SDF::onedge_value) / 255.0f, 0, std::max(0.0f, newProps.bolden));
font.sdf_threshold_bottom = wi::math::Lerp(font.sdf_threshold_top, 0, std::max(0.0f, newProps.softness));
font.color = params.color.rgba;
font.sdf_threshold_top = wi::math::Lerp(float(SDF::onedge_value) / 255.0f, 0, std::max(0.0f, params.bolden));
font.sdf_threshold_bottom = wi::math::Lerp(font.sdf_threshold_top, 0, std::max(0.0f, params.softness));
device->BindDynamicConstantBuffer(font, CBSLOT_FONT, cmd);
device->DrawInstanced(4, cursor.quadCount, 0, 0, cmd);
device->EventEnd(cmd);
}
return cursor.pos;
}
void SetCanvas(const wi::Canvas& current_canvas)
@@ -512,31 +516,31 @@ namespace wi::font
canvas = current_canvas;
}
void Draw(const char* text, const Params& params, CommandList cmd)
XMFLOAT2 Draw(const char* text, const Params& params, CommandList cmd)
{
size_t text_length = strlen(text);
if (text_length == 0)
{
return;
return XMFLOAT2(0, 0);
}
Draw_internal(text, text_length, params, cmd);
return Draw_internal(text, text_length, params, cmd);
}
void Draw(const wchar_t* text, const Params& params, CommandList cmd)
XMFLOAT2 Draw(const wchar_t* text, const Params& params, CommandList cmd)
{
size_t text_length = wcslen(text);
if (text_length == 0)
{
return;
return XMFLOAT2(0, 0);
}
Draw_internal(text, text_length, params, cmd);
return Draw_internal(text, text_length, params, cmd);
}
void Draw(const std::string& text, const Params& params, CommandList cmd)
XMFLOAT2 Draw(const std::string& text, const Params& params, CommandList cmd)
{
Draw_internal(text.c_str(), text.length(), params, cmd);
return Draw_internal(text.c_str(), text.length(), params, cmd);
}
void Draw(const std::wstring& text, const Params& params, CommandList cmd)
XMFLOAT2 Draw(const std::wstring& text, const Params& params, CommandList cmd)
{
Draw_internal(text.c_str(), text.length(), params, cmd);
return Draw_internal(text.c_str(), text.length(), params, cmd);
}
XMFLOAT2 TextSize(const char* text, const Params& params)
+7 -4
View File
@@ -3,6 +3,7 @@
#include "wiGraphicsDevice.h"
#include "wiColor.h"
#include "wiCanvas.h"
#include "wiMath.h"
#include <string>
@@ -38,6 +39,7 @@ namespace wi::font
float shadow_bolden = 0.1f; // value in [0,1] range
float shadow_offset_x = 0; // offset for shadow under the text in logical canvas coordinates
float shadow_offset_y = 0; // offset for shadow under the text in logical canvas coordinates
XMFLOAT2 cursor = XMFLOAT2(0, 0); // cursor offset, it can be used to continue text drawing by taking the Draw's return value (optional)
Params(
float posX = 0,
@@ -83,10 +85,11 @@ namespace wi::font
// Call once per frame to update font atlas texture
void UpdateAtlas();
void Draw(const char* text, const Params& params, wi::graphics::CommandList cmd);
void Draw(const wchar_t* text, const Params& params, wi::graphics::CommandList cmd);
void Draw(const std::string& text, const Params& params, wi::graphics::CommandList cmd);
void Draw(const std::wstring& text, const Params& params, wi::graphics::CommandList cmd);
// Draw text with specified parameters and return cursor for last word
XMFLOAT2 Draw(const char* text, const Params& params, wi::graphics::CommandList cmd);
XMFLOAT2 Draw(const wchar_t* text, const Params& params, wi::graphics::CommandList cmd);
XMFLOAT2 Draw(const std::string& text, const Params& params, wi::graphics::CommandList cmd);
XMFLOAT2 Draw(const std::wstring& text, const Params& params, wi::graphics::CommandList cmd);
XMFLOAT2 TextSize(const char* text, const Params& params);
XMFLOAT2 TextSize(const wchar_t* text, const Params& params);
+1 -1
View File
@@ -9,7 +9,7 @@ namespace wi::version
// minor features, major updates, breaking compatibility changes
const int minor = 60;
// minor bug fixes, alterations, refactors, updates
const int revision = 77;
const int revision = 78;
const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);