diff --git a/CMakeLists.txt b/CMakeLists.txt index 72688ab..3859b97 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -96,7 +96,7 @@ add_library(Lina::VG ALIAS ${PROJECT_NAME}) target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR}/include) target_compile_definitions(${PROJECT_NAME} PUBLIC LINAVG_VERSION_MAJOR=1) target_compile_definitions(${PROJECT_NAME} PUBLIC LINAVG_VERSION_MINOR=4) -target_compile_definitions(${PROJECT_NAME} PUBLIC LINAVG_VERSION_PATCH=3) +target_compile_definitions(${PROJECT_NAME} PUBLIC LINAVG_VERSION_PATCH=4) #-------------------------------------------------------------------- # Subdirectories & linking diff --git a/include/Core/Common.hpp b/include/Core/Common.hpp index aa01070..b50f927 100644 --- a/include/Core/Common.hpp +++ b/include/Core/Common.hpp @@ -393,6 +393,23 @@ namespace LinaVG Center, Right }; + + struct CharacterInfo + { + float x = 0.0f; + float y = 0.0f; + float sizeX = 0.0f; + float sizeY = 0.0f; + }; + + LINAVG_API struct TextOutData + { + /// + /// Upon drawing a text, this vector contains position and size information for each character. + /// + LINAVG_VEC characterInfo; + }; + /// /// Text styling, DrawText will render the given text as normal or via signed-distance-field (SDF) methods. /// This depends on the font handle given with options (or default font if not-provided). diff --git a/include/Core/Drawer.hpp b/include/Core/Drawer.hpp index 3f8b62c..54f9ceb 100644 --- a/include/Core/Drawer.hpp +++ b/include/Core/Drawer.hpp @@ -246,9 +246,10 @@ namespace LinaVG /// Rotates the whole shape by the given angle (degrees). /// Shapes with lower draw order is drawn first, resulting at the very bottom Z layer. /// Even if text caching is enabled globally, setting this to true will skip it for this call. Best used for dynamically changing text such as number counters. + /// Fill character related information if not nullptr. /// - LINAVG_API void DrawTextNormal(int thread, const char* text, const Vec2& position, const TextOptions& opts, float rotateAngle = 0.0f, int drawOrder = 0, bool skipCache = false); - LINAVG_API void DrawTextNormal(const char* text, const Vec2& position, const TextOptions& opts, float rotateAngle = 0.0f, int drawOrder = 0, bool skipCache = false); + LINAVG_API void DrawTextNormal(int thread, const char* text, const Vec2& position, const TextOptions& opts, float rotateAngle = 0.0f, int drawOrder = 0, bool skipCache = false, TextOutData* outData = nullptr); + LINAVG_API void DrawTextNormal(const char* text, const Vec2& position, const TextOptions& opts, float rotateAngle = 0.0f, int drawOrder = 0, bool skipCache = false, TextOutData* outData = nullptr); /// /// Draws the given text at position as an SDF text, which produces a lot more high-quality results than normal text, regardless @@ -262,9 +263,10 @@ namespace LinaVG /// Rotates the whole shape by the given angle (degrees). /// Shapes with lower draw order is drawn first, resulting at the very bottom Z layer. /// Even if text caching is enabled globally, setting this to true will skip it for this call. Best used for dynamically changing text such as number counters. + /// Fill character related information if not nullptr. /// - LINAVG_API void DrawTextSDF(int thread, const char* text, const Vec2& position, const SDFTextOptions& opts, float rotateAngle = 0.0f, int drawOrder = 0, bool skipCache = false); - LINAVG_API void DrawTextSDF(const char* text, const Vec2& position, const SDFTextOptions& opts, float rotateAngle = 0.0f, int drawOrder = 0, bool skipCache = false); + LINAVG_API void DrawTextSDF(int thread, const char* text, const Vec2& position, const SDFTextOptions& opts, float rotateAngle = 0.0f, int drawOrder = 0, bool skipCache = false, TextOutData* outData = nullptr); + LINAVG_API void DrawTextSDF(const char* text, const Vec2& position, const SDFTextOptions& opts, float rotateAngle = 0.0f, int drawOrder = 0, bool skipCache = false, TextOutData* outData = nullptr); /// /// Returns a Vec2 containing max width and height this text will occupy. @@ -442,12 +444,12 @@ namespace LinaVG /// /// Process, parse & draw text according to options. /// - void ProcessText(DrawBuffer* buf, LinaVGFont* font, const char* text, const Vec2& pos, const Vec2& offset, const Vec4Grad& color, float spacing, bool isGradient, float scale, float wrapWidth, float rotateAngle, TextAlignment alignment, float newLineSpacing, float sdfThickness); + void ProcessText(DrawBuffer* buf, LinaVGFont* font, const char* text, const Vec2& pos, const Vec2& offset, const Vec4Grad& color, float spacing, bool isGradient, float scale, float wrapWidth, float rotateAngle, TextAlignment alignment, float newLineSpacing, float sdfThickness, TextOutData* outData); /// /// DrawText implementation. /// - void DrawText(DrawBuffer* buf, LinaVGFont* font, const char* text, const Vec2& pos, const Vec2& offset, const Vec4Grad& color, float spacing, bool isGradient, float scale); + void DrawText(DrawBuffer* buf, LinaVGFont* font, const char* text, const Vec2& pos, const Vec2& offset, const Vec4Grad& color, float spacing, bool isGradient, float scale, TextOutData* outData); /// /// Returns the total text size for non-wrapped text. diff --git a/src/Core/Drawer.cpp b/src/Core/Drawer.cpp index 7bdab62..1cf3cdd 100644 --- a/src/Core/Drawer.cpp +++ b/src/Core/Drawer.cpp @@ -717,7 +717,7 @@ namespace LinaVG #ifdef LINAVG_TEXT_SUPPORT - LINAVG_API void DrawTextSDF(int thread, const char* text, const Vec2& position, const SDFTextOptions& opts, float rotateAngle, int drawOrder, bool skipCache) + LINAVG_API void DrawTextSDF(int thread, const char* text, const Vec2& position, const SDFTextOptions& opts, float rotateAngle, int drawOrder, bool skipCache, TextOutData* outData) { if (text == NULL || text[0] == '\0') return; @@ -738,13 +738,13 @@ namespace LinaVG const int indexStart = buf->m_indexBuffer.m_size; if (!Config.textCachingSDFEnabled || skipCache) - Internal::ProcessText(buf, font, text, position, Vec2(0.0f, 0.0f), opts.color, opts.spacing, isGradient, scale, opts.wrapWidth, rotateAngle, opts.alignment, opts.newLineSpacing, opts.sdfThickness); + Internal::ProcessText(buf, font, text, position, Vec2(0.0f, 0.0f), opts.color, opts.spacing, isGradient, scale, opts.wrapWidth, rotateAngle, opts.alignment, opts.newLineSpacing, opts.sdfThickness, outData); else { uint32_t sid = Utility::FnvHash(text); if (Internal::g_rendererData[thread].CheckSDFTextCache(sid, opts, buf) == nullptr) { - Internal::ProcessText(buf, font, text, Vec2(0.0f, 0.0f), Vec2(0.0f, 0.0f), opts.color, opts.spacing, isGradient, scale, opts.wrapWidth, rotateAngle, opts.alignment, opts.newLineSpacing, opts.sdfThickness); + Internal::ProcessText(buf, font, text, Vec2(0.0f, 0.0f), Vec2(0.0f, 0.0f), opts.color, opts.spacing, isGradient, scale, opts.wrapWidth, rotateAngle, opts.alignment, opts.newLineSpacing, opts.sdfThickness, outData); Internal::g_rendererData[thread].AddSDFTextCache(sid, opts, buf, vtxStart, indexStart); } @@ -764,16 +764,16 @@ namespace LinaVG usedOpts.sdfSoftness = opts.sdfDropShadowSoftness; DrawBuffer* dsBuf = &Internal::g_rendererData[thread].GetSDFTextBuffer(font->m_texture, drawOrder, usedOpts, true); const int dsStart = buf->m_vertexBuffer.m_size; - Internal::ProcessText(dsBuf, font, text, position, Vec2(opts.dropShadowOffset.x * opts.framebufferScale, opts.dropShadowOffset.y * opts.framebufferScale), opts.dropShadowColor, opts.spacing, false, scale, opts.wrapWidth, rotateAngle, opts.alignment, opts.newLineSpacing, opts.sdfThickness); + Internal::ProcessText(dsBuf, font, text, position, Vec2(opts.dropShadowOffset.x * opts.framebufferScale, opts.dropShadowOffset.y * opts.framebufferScale), opts.dropShadowColor, opts.spacing, false, scale, opts.wrapWidth, rotateAngle, opts.alignment, opts.newLineSpacing, opts.sdfThickness, outData); } } - LINAVG_API void DrawTextSDF(const char* text, const Vec2& position, const SDFTextOptions& opts, float rotateAngle, int drawOrder, bool skipCache) + LINAVG_API void DrawTextSDF(const char* text, const Vec2& position, const SDFTextOptions& opts, float rotateAngle, int drawOrder, bool skipCache, TextOutData* outData) { - return DrawTextSDF(0, text, position, opts, rotateAngle, drawOrder, skipCache); + return DrawTextSDF(0, text, position, opts, rotateAngle, drawOrder, skipCache, outData); } - LINAVG_API void DrawTextNormal(int thread, const char* text, const Vec2& position, const TextOptions& opts, float rotateAngle, int drawOrder, bool skipCache) + LINAVG_API void DrawTextNormal(int thread, const char* text, const Vec2& position, const TextOptions& opts, float rotateAngle, int drawOrder, bool skipCache, TextOutData* outData) { if (text == NULL || text[0] == '\0') return; @@ -794,13 +794,13 @@ namespace LinaVG const int indexStart = buf->m_indexBuffer.m_size; if (!Config.textCachingEnabled || skipCache) - Internal::ProcessText(buf, font, text, position, Vec2(0.0f, 0.0f), opts.color, opts.spacing, isGradient, scale, opts.wrapWidth, rotateAngle, opts.alignment, opts.newLineSpacing, 0.0f); + Internal::ProcessText(buf, font, text, position, Vec2(0.0f, 0.0f), opts.color, opts.spacing, isGradient, scale, opts.wrapWidth, rotateAngle, opts.alignment, opts.newLineSpacing, 0.0f, outData); else { uint32_t sid = Utility::FnvHash(text); if (Internal::g_rendererData[thread].CheckTextCache(sid, opts, buf) == nullptr) { - Internal::ProcessText(buf, font, text, Vec2(0, 0), Vec2(0.0f, 0.0f), opts.color, opts.spacing, isGradient, scale, opts.wrapWidth, rotateAngle, opts.alignment, opts.newLineSpacing, 0.0f); + Internal::ProcessText(buf, font, text, Vec2(0, 0), Vec2(0.0f, 0.0f), opts.color, opts.spacing, isGradient, scale, opts.wrapWidth, rotateAngle, opts.alignment, opts.newLineSpacing, 0.0f, outData); Internal::g_rendererData[thread].AddTextCache(sid, opts, buf, vtxStart, indexStart); } @@ -817,13 +817,13 @@ namespace LinaVG if (opts.dropShadowOffset.x != 0.0f || opts.dropShadowOffset.y != 0.0f) { DrawBuffer* dsBuf = &Internal::g_rendererData[thread].GetSimpleTextBuffer(font->m_texture, drawOrder, true); - Internal::ProcessText(dsBuf, font, text, position, Vec2(opts.dropShadowOffset.x * opts.framebufferScale, opts.dropShadowOffset.y * opts.framebufferScale), opts.dropShadowColor, opts.spacing, false, scale, opts.wrapWidth, rotateAngle, opts.alignment, opts.newLineSpacing, 0.0f); + Internal::ProcessText(dsBuf, font, text, position, Vec2(opts.dropShadowOffset.x * opts.framebufferScale, opts.dropShadowOffset.y * opts.framebufferScale), opts.dropShadowColor, opts.spacing, false, scale, opts.wrapWidth, rotateAngle, opts.alignment, opts.newLineSpacing, 0.0f, outData); } } - LINAVG_API void DrawTextNormal(const char* text, const Vec2& position, const TextOptions& opts, float rotateAngle, int drawOrder, bool skipCache) + LINAVG_API void DrawTextNormal(const char* text, const Vec2& position, const TextOptions& opts, float rotateAngle, int drawOrder, bool skipCache, TextOutData* outData) { - return DrawTextNormal(0, text, position, opts, rotateAngle, drawOrder, skipCache); + return DrawTextNormal(0, text, position, opts, rotateAngle, drawOrder, skipCache, outData); } LINAVG_API Vec2 CalculateTextSize(int thread, const char* text, TextOptions& opts) @@ -3090,7 +3090,7 @@ namespace LinaVG lines.push_back(newLine); } - void ProcessText(DrawBuffer* buf, LinaVGFont* font, const char* text, const Vec2& pos, const Vec2& offset, const Vec4Grad& color, float spacing, bool isGradient, float scale, float wrapWidth, float rotateAngle, TextAlignment alignment, float newLineSpacing, float sdfThickness) + void ProcessText(DrawBuffer* buf, LinaVGFont* font, const char* text, const Vec2& pos, const Vec2& offset, const Vec4Grad& color, float spacing, bool isGradient, float scale, float wrapWidth, float rotateAngle, TextAlignment alignment, float newLineSpacing, float sdfThickness, TextOutData* outData) { const int bufStart = buf->m_vertexBuffer.m_size; const Vec2 size = CalcTextSize(text, font, scale, spacing, sdfThickness); @@ -3112,7 +3112,7 @@ namespace LinaVG else if (alignment == TextAlignment::Right) usedPos.x -= size.x; - DrawText(buf, font, text, usedPos, offset, color, spacing, isGradient, scale); + DrawText(buf, font, text, usedPos, offset, color, spacing, isGradient, scale, outData); } else { @@ -3133,7 +3133,7 @@ namespace LinaVG else if (alignment == TextAlignment::Right) usedPos.x = pos.x - lines[i]->m_size.x; - DrawText(buf, font, lines[i]->m_str.c_str(), usedPos, offset, color, spacing, isGradient, scale); + DrawText(buf, font, lines[i]->m_str.c_str(), usedPos, offset, color, spacing, isGradient, scale, outData); usedPos.y += font->m_newLineHeight * scale + newLineSpacing; delete lines[i]; } @@ -3175,7 +3175,7 @@ namespace LinaVG return offset; } - void DrawText(DrawBuffer* buf, LinaVGFont* font, const char* text, const Vec2& position, const Vec2& offset, const Vec4Grad& color, float spacing, bool isGradient, float scale) + void DrawText(DrawBuffer* buf, LinaVGFont* font, const char* text, const Vec2& position, const Vec2& offset, const Vec4Grad& color, float spacing, bool isGradient, float scale, TextOutData* outData) { const uint8_t* c; const int totalCharacterCount = Utility::GetTextCharacterSize(text); @@ -3253,6 +3253,16 @@ namespace LinaVG v2.uv = Vec2(ch.m_uv34.x, ch.m_uv34.y); v3.uv = Vec2(ch.m_uv34.z, ch.m_uv34.w); + if (outData != nullptr) + { + CharacterInfo ci; + ci.x = v0.pos.x; + ci.y = v3.pos.y; + ci.sizeX = w; + ci.sizeY = ybot - ytop; + outData->characterInfo.push_back(ci); + } + buf->PushVertex(v0); buf->PushVertex(v1); buf->PushVertex(v2);