font renderer cursor refactor; initialization screen and backlog update;

This commit is contained in:
Turánszki János
2022-06-01 21:09:12 +02:00
parent c9e4c34e31
commit 347c2ee0e4
6 changed files with 138 additions and 129 deletions
+1 -13
View File
@@ -86,25 +86,13 @@ namespace wi
// Until engine is not loaded, present initialization screen...
CommandList cmd = graphicsDevice->BeginCommandList();
graphicsDevice->RenderPassBegin(&swapChain, cmd);
wi::image::SetCanvas(canvas);
Viewport viewport;
viewport.width = (float)swapChain.desc.width;
viewport.height = (float)swapChain.desc.height;
graphicsDevice->BindViewports(1, &viewport, cmd);
if (wi::initializer::IsInitializeFinished(wi::initializer::INITIALIZED_SYSTEM_FONT))
{
wi::font::SetCanvas(canvas);
wi::font::Params params;
params.posX = 5.f;
params.posY = 5.f;
std::string text = wi::backlog::getText();
float textheight = wi::font::TextHeight(text, params);
float screenheight = canvas.GetLogicalHeight();
if (textheight > screenheight)
{
params.posY = screenheight - textheight;
}
wi::font::Draw(text, params, cmd);
wi::backlog::DrawOutputText(canvas, cmd);
}
graphicsDevice->RenderPassEnd(cmd);
graphicsDevice->SubmitCommandLists();
+49 -41
View File
@@ -31,7 +31,7 @@ namespace wi::backlog
std::deque<LogEntry> history;
const float speed = 4000.0f;
const size_t deletefromline = 500;
float pos = std::numeric_limits<float>::lowest();
float pos = 5;
float scroll = 0;
std::string inputArea;
int historyPos = 0;
@@ -44,6 +44,15 @@ namespace wi::backlog
bool blockLuaExec = false;
LogLevel logLevel = LogLevel::Default;
std::string getTextWithoutLock()
{
std::string retval;
for (auto& x : entries)
{
retval += x.text;
}
return retval;
}
void write_logfile()
{
std::string filename = wi::helper::GetTempDirectoryPath() + "wiBacklog.txt";
@@ -142,46 +151,15 @@ namespace wi::backlog
params.shadow_softness = 1;
wi::font::Draw(inputArea, params, cmd);
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 = 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;
Rect rect;
rect.left = 0;
rect.right = (int32_t)canvas.GetPhysicalWidth();
rect.top = 0;
rect.bottom = int32_t(canvas.LogicalToPhysical(canvas.GetLogicalHeight() - 35));
wi::graphics::GetDevice()->BindScissorRects(1, &rect, 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);
}
DrawOutputText(canvas, cmd);
rect.left = -std::numeric_limits<int>::max();
rect.right = std::numeric_limits<int>::max();
rect.top = -std::numeric_limits<int>::max();
@@ -190,16 +168,46 @@ namespace wi::backlog
}
}
void DrawOutputText(const wi::Canvas& canvas, wi::graphics::CommandList cmd)
{
std::scoped_lock lock(logLock);
wi::font::SetCanvas(canvas); // always set here as it can be called from outside...
font_params.cursor = {};
if (refitscroll)
{
float textheight = wi::font::TextHeight(getTextWithoutLock(), font_params);
float limit = canvas.GetLogicalHeight() - 35;
if (scroll + textheight > limit)
{
scroll = limit - textheight;
}
refitscroll = false;
}
font_params.posX = 5;
font_params.posY = pos + scroll;
font_params.h_wrap = canvas.GetLogicalWidth() - font_params.posX;
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);
}
}
std::string getText()
{
std::scoped_lock lock(logLock);
std::string retval;
for (auto& x : entries)
{
retval += x.text;
}
return retval;
return getTextWithoutLock();
}
void clear()
{
+1
View File
@@ -20,6 +20,7 @@ namespace wi::backlog
void Scroll(int direction);
void Update(const wi::Canvas& canvas, float dt = 1.0f / 60.0f);
void Draw(const wi::Canvas& canvas, wi::graphics::CommandList cmd);
void DrawOutputText(const wi::Canvas& canvas, wi::graphics::CommandList cmd);
std::string getText();
void clear();
+52 -54
View File
@@ -111,10 +111,9 @@ namespace wi::font
};
static wi::vector<FontStyle> fontStyles;
struct Cursor
struct ParseStatus
{
XMFLOAT2 pos = {};
XMFLOAT2 size = {};
Cursor cursor;
uint32_t quadCount = 0;
size_t last_word_begin = 0;
bool start_new_word = false;
@@ -123,32 +122,32 @@ namespace wi::font
static thread_local wi::vector<FontVertex> vertexList;
template<typename T>
Cursor ParseText(const T* text, size_t text_length, Params params)
ParseStatus ParseText(const T* text, size_t text_length, Params params)
{
Cursor cursor;
cursor.pos = params.cursor;
ParseStatus status;
status.cursor = params.cursor;
const FontStyle& fontStyle = fontStyles[params.style];
const float fontScale = stbtt_ScaleForPixelHeight(&fontStyle.fontInfo, (float)params.size);
vertexList.clear();
auto word_wrap = [&] {
cursor.start_new_word = true;
if (cursor.last_word_begin > 0 && params.h_wrap >= 0 && cursor.pos.x >= params.h_wrap - 1)
status.start_new_word = true;
if (status.last_word_begin > 0 && params.h_wrap >= 0 && status.cursor.position.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 + WHITESPACE_SIZE;
for (size_t i = cursor.last_word_begin; i < cursor.quadCount * 4; ++i)
float word_offset = vertexList[status.last_word_begin].pos.x + WHITESPACE_SIZE;
for (size_t i = status.last_word_begin; i < status.quadCount * 4; ++i)
{
vertexList[i].pos.x -= word_offset;
vertexList[i].pos.y += LINEBREAK_SIZE;
}
cursor.pos.x -= word_offset;
cursor.pos.y += LINEBREAK_SIZE;
status.cursor.position.x -= word_offset;
status.cursor.position.y += LINEBREAK_SIZE;
}
};
cursor.size.y = cursor.pos.y + LINEBREAK_SIZE;
status.cursor.size.y = status.cursor.position.y + LINEBREAK_SIZE;
for (size_t i = 0; i < text_length; ++i)
{
T character = text[i];
@@ -166,18 +165,18 @@ namespace wi::font
if (code == '\n')
{
word_wrap();
cursor.pos.x = 0;
cursor.pos.y += LINEBREAK_SIZE;
status.cursor.position.x = 0;
status.cursor.position.y += LINEBREAK_SIZE;
}
else if (code == ' ')
{
word_wrap();
cursor.pos.x += WHITESPACE_SIZE;
status.cursor.position.x += WHITESPACE_SIZE;
}
else if (code == '\t')
{
word_wrap();
cursor.pos.x += TAB_SIZE;
status.cursor.position.x += TAB_SIZE;
}
else
{
@@ -187,19 +186,19 @@ namespace wi::font
const float glyphOffsetX = glyph.x * params.scaling;
const float glyphOffsetY = glyph.y * params.scaling;
const size_t vertexID = size_t(cursor.quadCount) * 4;
const size_t vertexID = size_t(status.quadCount) * 4;
vertexList.resize(vertexID + 4);
cursor.quadCount++;
status.quadCount++;
if (cursor.start_new_word)
if (status.start_new_word)
{
cursor.last_word_begin = vertexID;
status.last_word_begin = vertexID;
}
cursor.start_new_word = false;
status.start_new_word = false;
const float left = cursor.pos.x + glyphOffsetX;
const float left = status.cursor.position.x + glyphOffsetX;
const float right = left + glyphWidth;
const float top = cursor.pos.y + glyphOffsetY;
const float top = status.cursor.position.y + glyphOffsetY;
const float bottom = top + glyphHeight;
vertexList[vertexID + 0].pos = float2(left, top);
@@ -214,25 +213,25 @@ namespace wi::font
int advance, lsb;
stbtt_GetCodepointHMetrics(&fontStyle.fontInfo, code, &advance, &lsb);
cursor.pos.x += advance * fontScale * params.scaling;
status.cursor.position.x += advance * fontScale * params.scaling;
cursor.pos.x += params.spacingX;
status.cursor.position.x += params.spacingX;
if (text_length > 1 && i < text_length - 1 && text[i + 1])
{
int code_next = (int)text[i + 1];
int kern = stbtt_GetCodepointKernAdvance(&fontStyle.fontInfo, code, code_next);
cursor.pos.x += kern * fontScale;
status.cursor.position.x += kern * fontScale;
}
}
cursor.size.x = std::max(cursor.size.x, cursor.pos.x);
cursor.size.y = std::max(cursor.size.y, cursor.pos.y + LINEBREAK_SIZE);
status.cursor.size.x = std::max(status.cursor.size.x, status.cursor.position.x);
status.cursor.size.y = std::max(status.cursor.size.y, status.cursor.position.y + LINEBREAK_SIZE);
}
word_wrap();
return cursor;
return status;
}
void CommitText(void* vertexList_GPU)
{
@@ -433,32 +432,31 @@ namespace wi::font
}
template<typename T>
XMFLOAT2 Draw_internal(const T* text, size_t text_length, const Params& params_in, CommandList cmd)
Cursor Draw_internal(const T* text, size_t text_length, const Params& params_in, CommandList cmd)
{
if (text_length <= 0)
{
return XMFLOAT2(0, 0);
return Cursor();
}
Cursor cursor = ParseText(text, text_length, params_in);
ParseStatus status = ParseText(text, text_length, params_in);
Params params = params_in;
if (params.h_align == WIFALIGN_CENTER)
params.posX -= cursor.size.x / 2;
params.posX -= status.cursor.size.x / 2;
else if (params.h_align == WIFALIGN_RIGHT)
params.posX -= cursor.size.x;
params.posX -= status.cursor.size.x;
if (params.v_align == WIFALIGN_CENTER)
params.posY -= cursor.size.y / 2;
params.posY -= status.cursor.size.y / 2;
else if (params.v_align == WIFALIGN_BOTTOM)
params.posY -= cursor.size.y;
params.posY -= status.cursor.size.y;
if (cursor.quadCount > 0)
if (status.quadCount > 0)
{
GraphicsDevice* device = wi::graphics::GetDevice();
GraphicsDevice::GPUAllocation mem = device->AllocateGPU(sizeof(FontVertex) * cursor.quadCount * 4, cmd);
GraphicsDevice::GPUAllocation mem = device->AllocateGPU(sizeof(FontVertex) * status.quadCount * 4, cmd);
if (!mem.IsValid())
{
return cursor.pos;
return status.cursor;
}
CommitText(mem.data);
@@ -490,7 +488,7 @@ namespace wi::font
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);
device->DrawInstanced(4, status.quadCount, 0, 0, cmd);
}
// font base render:
@@ -503,12 +501,12 @@ namespace wi::font
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->DrawInstanced(4, status.quadCount, 0, 0, cmd);
device->EventEnd(cmd);
}
return cursor.pos;
return status.cursor;
}
void SetCanvas(const wi::Canvas& current_canvas)
@@ -516,29 +514,29 @@ namespace wi::font
canvas = current_canvas;
}
XMFLOAT2 Draw(const char* text, const Params& params, CommandList cmd)
Cursor Draw(const char* text, const Params& params, CommandList cmd)
{
size_t text_length = strlen(text);
if (text_length == 0)
{
return XMFLOAT2(0, 0);
return Cursor();
}
return Draw_internal(text, text_length, params, cmd);
}
XMFLOAT2 Draw(const wchar_t* text, const Params& params, CommandList cmd)
Cursor Draw(const wchar_t* text, const Params& params, CommandList cmd)
{
size_t text_length = wcslen(text);
if (text_length == 0)
{
return XMFLOAT2(0, 0);
return Cursor();
}
return Draw_internal(text, text_length, params, cmd);
}
XMFLOAT2 Draw(const std::string& text, const Params& params, CommandList cmd)
Cursor Draw(const std::string& text, const Params& params, CommandList cmd)
{
return Draw_internal(text.c_str(), text.length(), params, cmd);
}
XMFLOAT2 Draw(const std::wstring& text, const Params& params, CommandList cmd)
Cursor Draw(const std::wstring& text, const Params& params, CommandList cmd)
{
return Draw_internal(text.c_str(), text.length(), params, cmd);
}
@@ -550,7 +548,7 @@ namespace wi::font
{
return XMFLOAT2(0, 0);
}
return ParseText(text, text_length, params).size;
return ParseText(text, text_length, params).cursor.size;
}
XMFLOAT2 TextSize(const wchar_t* text, const Params& params)
{
@@ -559,7 +557,7 @@ namespace wi::font
{
return XMFLOAT2(0, 0);
}
return ParseText(text, text_length, params).size;
return ParseText(text, text_length, params).cursor.size;
}
XMFLOAT2 TextSize(const std::string& text, const Params& params)
{
@@ -567,7 +565,7 @@ namespace wi::font
{
return XMFLOAT2(0, 0);
}
return ParseText(text.c_str(), text.length(), params).size;
return ParseText(text.c_str(), text.length(), params).cursor.size;
}
XMFLOAT2 TextSize(const std::wstring& text, const Params& params)
{
@@ -575,7 +573,7 @@ namespace wi::font
{
return XMFLOAT2(0, 0);
}
return ParseText(text.c_str(), text.length(), params).size;
return ParseText(text.c_str(), text.length(), params).cursor.size;
}
float TextWidth(const char* text, const Params& params)
+34 -20
View File
@@ -12,34 +12,41 @@ namespace wi::font
// Do not alter order because it is bound to lua manually
enum Alignment
{
WIFALIGN_LEFT,
WIFALIGN_CENTER,
WIFALIGN_RIGHT,
WIFALIGN_TOP,
WIFALIGN_BOTTOM
WIFALIGN_LEFT, // left alignment (horizontal)
WIFALIGN_CENTER, // center alignment (horizontal or vertical)
WIFALIGN_RIGHT, // right alignment (horizontal)
WIFALIGN_TOP, // top alignment (vertical)
WIFALIGN_BOTTOM // bottom alignment (vertical)
};
static constexpr int WIFONTSIZE_DEFAULT = 16;
struct Cursor
{
XMFLOAT2 position = {}; // the next character's position offset from the first character (logical canvas units)
XMFLOAT2 size = {}; // the written text's measurements from the first character (logical canvas units)
};
struct Params
{
float posX = 0;
float posY = 0;
int size = WIFONTSIZE_DEFAULT; // line height in DPI scaled units
float scaling = 1;
float spacingX = 0, spacingY = 0; // minimum spacing between characters
Alignment h_align, v_align;
wi::Color color;
wi::Color shadowColor;
float h_wrap = -1; // wrap start width (-1 default for no wrap)
int style = 0;
float posX = 0; // position in horizontal direction (logical canvas units)
float posY = 0; // position in vertical direction (logical canvas units)
int size = WIFONTSIZE_DEFAULT; // line height (logical canvas units)
float scaling = 1; // this will apply upscaling to the text while keeping the same resolution (size) of the font
float spacingX = 0, spacingY = 0; // minimum spacing between characters (logical canvas units)
Alignment h_align = WIFALIGN_LEFT; // horizontal alignment
Alignment v_align = WIFALIGN_TOP; // vertical alignment
wi::Color color; // base color of the text characters
wi::Color shadowColor; // transparent disables, any other color enables shadow under text
float h_wrap = -1; // wrap start width (-1 default for no wrap) (logical canvas units)
int style = 0; // 0: use default font style, other values can be taken from the wi::font::AddFontStyle() funtion's return value
float softness = 0.1f; // value in [0,1] range
float bolden = 0; // value in [0,1] range
float shadow_softness = 0.5f; // value in [0,1] range
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)
Cursor cursor; // cursor can be used to continue text drawing by taking the Draw's return value (optional)
Params(
float posX = 0,
@@ -86,21 +93,28 @@ namespace wi::font
void UpdateAtlas();
// 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);
// The next Draw() can continue from where this left off by using the return value of this function
// in wi::font::Params::cursor
Cursor Draw(const char* text, const Params& params, wi::graphics::CommandList cmd);
Cursor Draw(const wchar_t* text, const Params& params, wi::graphics::CommandList cmd);
Cursor Draw(const std::string& text, const Params& params, wi::graphics::CommandList cmd);
Cursor Draw(const std::wstring& text, const Params& params, wi::graphics::CommandList cmd);
// Computes the text's size measurements in logical canvas coordinates
XMFLOAT2 TextSize(const char* text, const Params& params);
XMFLOAT2 TextSize(const wchar_t* text, const Params& params);
XMFLOAT2 TextSize(const std::string& text, const Params& params);
XMFLOAT2 TextSize(const std::wstring& text, const Params& params);
// Computes the text's width in logical canvas coordinates
// Avoid calling TextWidth() and TextHeight() both, instead use TextSize() if you need both measurements!
float TextWidth(const char* text, const Params& params);
float TextWidth(const wchar_t* text, const Params& params);
float TextWidth(const std::string& text, const Params& params);
float TextWidth(const std::wstring& text, const Params& params);
// Computes the text's height in logical canvas coordinates
// Avoid calling TextWidth() and TextHeight() both, instead use TextSize() if you need both measurements!
float TextHeight(const char* text, const Params& params);
float TextHeight(const wchar_t* text, const Params& params);
float TextHeight(const std::string& 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 = 78;
const int revision = 79;
const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);