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);