diff --git a/WickedEngine/wiBacklog.cpp b/WickedEngine/wiBacklog.cpp index f85d6b852..82e851235 100644 --- a/WickedEngine/wiBacklog.cpp +++ b/WickedEngine/wiBacklog.cpp @@ -22,15 +22,20 @@ using namespace wi::graphics; namespace wi::backlog { bool enabled = false; - std::deque stream; - std::deque history; + struct LogEntry + { + std::string text; + LogLevel level = LogLevel::Default; + }; + std::deque entries; + std::deque history; const float speed = 4000.0f; const size_t deletefromline = 500; float pos = std::numeric_limits::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::max(); rect.right = std::numeric_limits::max(); rect.top = -std::numeric_limits::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; } diff --git a/WickedEngine/wiCanvas.h b/WickedEngine/wiCanvas.h index d9f8e9b27..4c56e3764 100644 --- a/WickedEngine/wiCanvas.h +++ b/WickedEngine/wiCanvas.h @@ -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 diff --git a/WickedEngine/wiFont.cpp b/WickedEngine/wiFont.cpp index e75b219d1..d2721da06 100644 --- a/WickedEngine/wiFont.cpp +++ b/WickedEngine/wiFont.cpp @@ -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 - 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) diff --git a/WickedEngine/wiFont.h b/WickedEngine/wiFont.h index bd61ae87e..cd8b0407c 100644 --- a/WickedEngine/wiFont.h +++ b/WickedEngine/wiFont.h @@ -3,6 +3,7 @@ #include "wiGraphicsDevice.h" #include "wiColor.h" #include "wiCanvas.h" +#include "wiMath.h" #include @@ -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); diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 65f79a2db..5f293f06a 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -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);