summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/bgfx/examples/common/font/text_buffer_manager.cpp
diff options
context:
space:
mode:
author Miodrag Milanovic <mmicko@gmail.com>2015-02-01 10:14:17 +0100
committer Miodrag Milanovic <mmicko@gmail.com>2015-02-01 10:14:17 +0100
commitb3303c3a32b94b61f82e739d8d494752047f11c1 (patch)
tree1383c753eaebdfa039f1768f55c96fe800ce020f /3rdparty/bgfx/examples/common/font/text_buffer_manager.cpp
parent09b6ec9869349cf9befd8c3589f1dccb32bacd1a (diff)
Added BGFX latest code to 3rdparty (nw)
Diffstat (limited to '3rdparty/bgfx/examples/common/font/text_buffer_manager.cpp')
-rw-r--r--3rdparty/bgfx/examples/common/font/text_buffer_manager.cpp907
1 files changed, 907 insertions, 0 deletions
diff --git a/3rdparty/bgfx/examples/common/font/text_buffer_manager.cpp b/3rdparty/bgfx/examples/common/font/text_buffer_manager.cpp
new file mode 100644
index 00000000000..654d1cabec1
--- /dev/null
+++ b/3rdparty/bgfx/examples/common/font/text_buffer_manager.cpp
@@ -0,0 +1,907 @@
+/*
+ * Copyright 2013 Jeremie Roy. All rights reserved.
+ * License: http://www.opensource.org/licenses/BSD-2-Clause
+ */
+
+#include "../common.h"
+
+#include <bgfx.h>
+#include <stddef.h> // offsetof
+#include <memory.h> // memcpy
+#include <wchar.h> // wcslen
+
+#include "text_buffer_manager.h"
+#include "utf8.h"
+#include "../cube_atlas.h"
+
+#include "vs_font_basic.bin.h"
+#include "fs_font_basic.bin.h"
+#include "vs_font_distance_field.bin.h"
+#include "fs_font_distance_field.bin.h"
+#include "vs_font_distance_field_subpixel.bin.h"
+#include "fs_font_distance_field_subpixel.bin.h"
+
+#define MAX_BUFFERED_CHARACTERS (8192 - 5)
+
+class TextBuffer
+{
+public:
+
+ /// TextBuffer is bound to a fontManager for glyph retrieval
+ /// @remark the ownership of the manager is not taken
+ TextBuffer(FontManager* _fontManager);
+ ~TextBuffer();
+
+ void setStyle(uint32_t _flags = STYLE_NORMAL)
+ {
+ m_styleFlags = _flags;
+ }
+
+ void setTextColor(uint32_t _rgba = 0x000000FF)
+ {
+ m_textColor = toABGR(_rgba);
+ }
+
+ void setBackgroundColor(uint32_t _rgba = 0x000000FF)
+ {
+ m_backgroundColor = toABGR(_rgba);
+ }
+
+ void setOverlineColor(uint32_t _rgba = 0x000000FF)
+ {
+ m_overlineColor = toABGR(_rgba);
+ }
+
+ void setUnderlineColor(uint32_t _rgba = 0x000000FF)
+ {
+ m_underlineColor = toABGR(_rgba);
+ }
+
+ void setStrikeThroughColor(uint32_t _rgba = 0x000000FF)
+ {
+ m_strikeThroughColor = toABGR(_rgba);
+ }
+
+ void setPenPosition(float _x, float _y)
+ {
+ m_penX = _x; m_penY = _y;
+ }
+
+ /// Append an ASCII/utf-8 string to the buffer using current pen
+ /// position and color.
+ void appendText(FontHandle _fontHandle, const char* _string, const char* _end = NULL);
+
+ /// Append a wide char unicode string to the buffer using current pen
+ /// position and color.
+ void appendText(FontHandle _fontHandle, const wchar_t* _string, const wchar_t* _end = NULL);
+
+ /// Append a whole face of the atlas cube, mostly used for debugging
+ /// and visualizing atlas.
+ void appendAtlasFace(uint16_t _faceIndex);
+
+ /// Clear the text buffer and reset its state (pen/color)
+ void clearTextBuffer();
+
+ /// Get pointer to the vertex buffer to submit it to the graphic card.
+ const uint8_t* getVertexBuffer()
+ {
+ return (uint8_t*) m_vertexBuffer;
+ }
+
+ /// Number of vertex in the vertex buffer.
+ uint32_t getVertexCount() const
+ {
+ return m_vertexCount;
+ }
+
+ /// Size in bytes of a vertex.
+ uint32_t getVertexSize() const
+ {
+ return sizeof(TextVertex);
+ }
+
+ /// get a pointer to the index buffer to submit it to the graphic
+ const uint16_t* getIndexBuffer() const
+ {
+ return m_indexBuffer;
+ }
+
+ /// number of index in the index buffer
+ uint32_t getIndexCount() const
+ {
+ return m_indexCount;
+ }
+
+ /// Size in bytes of an index.
+ uint32_t getIndexSize() const
+ {
+ return sizeof(uint16_t);
+ }
+
+ uint32_t getTextColor() const
+ {
+ return toABGR(m_textColor);
+ }
+
+ TextRectangle getRectangle() const
+ {
+ return m_rectangle;
+ }
+
+private:
+ void appendGlyph(FontHandle _handle, CodePoint _codePoint);
+ void verticalCenterLastLine(float _txtDecalY, float _top, float _bottom);
+
+ static uint32_t toABGR(uint32_t _rgba)
+ {
+ return ( ( (_rgba >> 0) & 0xff) << 24)
+ | ( ( (_rgba >> 8) & 0xff) << 16)
+ | ( ( (_rgba >> 16) & 0xff) << 8)
+ | ( ( (_rgba >> 24) & 0xff) << 0)
+ ;
+ }
+
+ uint32_t m_styleFlags;
+
+ // color states
+ uint32_t m_textColor;
+
+ uint32_t m_backgroundColor;
+ uint32_t m_overlineColor;
+ uint32_t m_underlineColor;
+ uint32_t m_strikeThroughColor;
+
+ //position states
+ float m_penX;
+ float m_penY;
+
+ float m_originX;
+ float m_originY;
+
+ float m_lineAscender;
+ float m_lineDescender;
+ float m_lineGap;
+
+ TextRectangle m_rectangle;
+ FontManager* m_fontManager;
+
+ void setVertex(uint32_t _i, float _x, float _y, uint32_t _rgba, uint8_t _style = STYLE_NORMAL)
+ {
+ m_vertexBuffer[_i].x = _x;
+ m_vertexBuffer[_i].y = _y;
+ m_vertexBuffer[_i].rgba = _rgba;
+ m_styleBuffer[_i] = _style;
+ }
+
+ struct TextVertex
+ {
+ float x, y;
+ int16_t u, v, w, t;
+ uint32_t rgba;
+ };
+
+ TextVertex* m_vertexBuffer;
+ uint16_t* m_indexBuffer;
+ uint8_t* m_styleBuffer;
+
+ uint32_t m_indexCount;
+ uint32_t m_lineStartIndex;
+ uint16_t m_vertexCount;
+};
+
+TextBuffer::TextBuffer(FontManager* _fontManager)
+ : m_styleFlags(STYLE_NORMAL)
+ , m_textColor(0xffffffff)
+ , m_backgroundColor(0xffffffff)
+ , m_overlineColor(0xffffffff)
+ , m_underlineColor(0xffffffff)
+ , m_strikeThroughColor(0xffffffff)
+ , m_penX(0)
+ , m_penY(0)
+ , m_originX(0)
+ , m_originY(0)
+ , m_lineAscender(0)
+ , m_lineDescender(0)
+ , m_lineGap(0)
+ , m_fontManager(_fontManager)
+ , m_vertexBuffer(new TextVertex[MAX_BUFFERED_CHARACTERS * 4])
+ , m_indexBuffer(new uint16_t[MAX_BUFFERED_CHARACTERS * 6])
+ , m_styleBuffer(new uint8_t[MAX_BUFFERED_CHARACTERS * 4])
+ , m_indexCount(0)
+ , m_lineStartIndex(0)
+ , m_vertexCount(0)
+{
+ m_rectangle.width = 0;
+ m_rectangle.height = 0;
+}
+
+TextBuffer::~TextBuffer()
+{
+ delete [] m_vertexBuffer;
+ delete [] m_indexBuffer;
+ delete [] m_styleBuffer;
+}
+
+void TextBuffer::appendText(FontHandle _fontHandle, const char* _string, const char* _end)
+{
+ if (m_vertexCount == 0)
+ {
+ m_originX = m_penX;
+ m_originY = m_penY;
+ m_lineDescender = 0;
+ m_lineAscender = 0;
+ m_lineGap = 0;
+ }
+
+ CodePoint codepoint = 0;
+ uint32_t state = 0;
+
+ if (_end == NULL)
+ {
+ _end = _string + strlen(_string);
+ }
+ BX_CHECK(_end >= _string);
+
+ for (; *_string && _string < _end ; ++_string)
+ {
+ if (utf8_decode(&state, (uint32_t*)&codepoint, *_string) == UTF8_ACCEPT )
+ {
+ appendGlyph(_fontHandle, codepoint);
+ }
+ }
+
+ BX_CHECK(state == UTF8_ACCEPT, "The string is not well-formed");
+}
+
+void TextBuffer::appendText(FontHandle _fontHandle, const wchar_t* _string, const wchar_t* _end)
+{
+ if (m_vertexCount == 0)
+ {
+ m_originX = m_penX;
+ m_originY = m_penY;
+ m_lineDescender = 0;
+ m_lineAscender = 0;
+ m_lineGap = 0;
+ }
+
+ if (_end == NULL)
+ {
+ _end = _string + wcslen(_string);
+ }
+ BX_CHECK(_end >= _string);
+
+ for (const wchar_t* _current = _string; _current < _end; ++_current)
+ {
+ uint32_t _codePoint = *_current;
+ appendGlyph(_fontHandle, _codePoint);
+ }
+}
+
+void TextBuffer::appendAtlasFace(uint16_t _faceIndex)
+{
+ if( m_vertexCount/4 >= MAX_BUFFERED_CHARACTERS)
+ {
+ return;
+ }
+
+ float x0 = m_penX;
+ float y0 = m_penY;
+ float x1 = x0 + (float)m_fontManager->getAtlas()->getTextureSize();
+ float y1 = y0 + (float)m_fontManager->getAtlas()->getTextureSize();
+
+ m_fontManager->getAtlas()->packFaceLayerUV(_faceIndex
+ , (uint8_t*)m_vertexBuffer
+ , sizeof(TextVertex) * m_vertexCount + offsetof(TextVertex, u)
+ , sizeof(TextVertex)
+ );
+
+ setVertex(m_vertexCount + 0, x0, y0, m_backgroundColor);
+ setVertex(m_vertexCount + 1, x0, y1, m_backgroundColor);
+ setVertex(m_vertexCount + 2, x1, y1, m_backgroundColor);
+ setVertex(m_vertexCount + 3, x1, y0, m_backgroundColor);
+
+ m_indexBuffer[m_indexCount + 0] = m_vertexCount + 0;
+ m_indexBuffer[m_indexCount + 1] = m_vertexCount + 1;
+ m_indexBuffer[m_indexCount + 2] = m_vertexCount + 2;
+ m_indexBuffer[m_indexCount + 3] = m_vertexCount + 0;
+ m_indexBuffer[m_indexCount + 4] = m_vertexCount + 2;
+ m_indexBuffer[m_indexCount + 5] = m_vertexCount + 3;
+ m_vertexCount += 4;
+ m_indexCount += 6;
+}
+
+void TextBuffer::clearTextBuffer()
+{
+ m_penX = 0;
+ m_penY = 0;
+ m_originX = 0;
+ m_originY = 0;
+
+ m_vertexCount = 0;
+ m_indexCount = 0;
+ m_lineStartIndex = 0;
+ m_lineAscender = 0;
+ m_lineDescender = 0;
+ m_lineGap = 0;
+ m_rectangle.width = 0;
+ m_rectangle.height = 0;
+}
+
+void TextBuffer::appendGlyph(FontHandle _handle, CodePoint _codePoint)
+{
+ const GlyphInfo* glyph = m_fontManager->getGlyphInfo(_handle, _codePoint);
+ BX_WARN(NULL != glyph, "Glyph not found (font handle %d, code point %d)", _handle.idx, _codePoint);
+ if (NULL == glyph)
+ {
+ return;
+ }
+
+ const FontInfo& font = m_fontManager->getFontInfo(_handle);
+
+ if( m_vertexCount/4 >= MAX_BUFFERED_CHARACTERS)
+ {
+ return;
+ }
+
+ if (_codePoint == L'\n')
+ {
+ m_penX = m_originX;
+ m_penY += m_lineGap + m_lineAscender -m_lineDescender;
+ m_lineGap = font.lineGap;
+ m_lineDescender = font.descender;
+ m_lineAscender = font.ascender;
+ m_lineStartIndex = m_vertexCount;
+ return;
+ }
+
+ //is there a change of font size that require the text on the left to be centered again ?
+ if (font.ascender > m_lineAscender
+ || (font.descender < m_lineDescender) )
+ {
+ if (font.descender < m_lineDescender)
+ {
+ m_lineDescender = font.descender;
+ m_lineGap = font.lineGap;
+ }
+
+ float txtDecals = (font.ascender - m_lineAscender);
+ m_lineAscender = font.ascender;
+ m_lineGap = font.lineGap;
+ verticalCenterLastLine( (txtDecals), (m_penY - m_lineAscender), (m_penY + m_lineAscender - m_lineDescender + m_lineGap) );
+ }
+
+ float kerning = 0 * font.scale;
+ m_penX += kerning;
+
+ const GlyphInfo& blackGlyph = m_fontManager->getBlackGlyph();
+ const Atlas* atlas = m_fontManager->getAtlas();
+
+ if (m_styleFlags & STYLE_BACKGROUND
+ && m_backgroundColor & 0xFF000000)
+ {
+ float x0 = (m_penX - kerning);
+ float y0 = (m_penY);
+ float x1 = ( (float)x0 + (glyph->advance_x) );
+ float y1 = (m_penY + m_lineAscender - m_lineDescender + m_lineGap);
+
+ atlas->packUV(blackGlyph.regionIndex
+ , (uint8_t*)m_vertexBuffer
+ , sizeof(TextVertex) * m_vertexCount + offsetof(TextVertex, u)
+ , sizeof(TextVertex)
+ );
+
+ const uint16_t vertexCount = m_vertexCount;
+ setVertex(vertexCount + 0, x0, y0, m_backgroundColor, STYLE_BACKGROUND);
+ setVertex(vertexCount + 1, x0, y1, m_backgroundColor, STYLE_BACKGROUND);
+ setVertex(vertexCount + 2, x1, y1, m_backgroundColor, STYLE_BACKGROUND);
+ setVertex(vertexCount + 3, x1, y0, m_backgroundColor, STYLE_BACKGROUND);
+
+ m_indexBuffer[m_indexCount + 0] = vertexCount + 0;
+ m_indexBuffer[m_indexCount + 1] = vertexCount + 1;
+ m_indexBuffer[m_indexCount + 2] = vertexCount + 2;
+ m_indexBuffer[m_indexCount + 3] = vertexCount + 0;
+ m_indexBuffer[m_indexCount + 4] = vertexCount + 2;
+ m_indexBuffer[m_indexCount + 5] = vertexCount + 3;
+ m_vertexCount += 4;
+ m_indexCount += 6;
+ }
+
+ if (m_styleFlags & STYLE_UNDERLINE
+ && m_underlineColor & 0xFF000000)
+ {
+ float x0 = (m_penX - kerning);
+ float y0 = (m_penY + m_lineAscender - m_lineDescender * 0.5f);
+ float x1 = ( (float)x0 + (glyph->advance_x) );
+ float y1 = y0 + font.underlineThickness;
+
+ atlas->packUV(blackGlyph.regionIndex
+ , (uint8_t*)m_vertexBuffer
+ , sizeof(TextVertex) * m_vertexCount + offsetof(TextVertex, u)
+ , sizeof(TextVertex)
+ );
+
+ setVertex(m_vertexCount + 0, x0, y0, m_underlineColor, STYLE_UNDERLINE);
+ setVertex(m_vertexCount + 1, x0, y1, m_underlineColor, STYLE_UNDERLINE);
+ setVertex(m_vertexCount + 2, x1, y1, m_underlineColor, STYLE_UNDERLINE);
+ setVertex(m_vertexCount + 3, x1, y0, m_underlineColor, STYLE_UNDERLINE);
+
+ m_indexBuffer[m_indexCount + 0] = m_vertexCount + 0;
+ m_indexBuffer[m_indexCount + 1] = m_vertexCount + 1;
+ m_indexBuffer[m_indexCount + 2] = m_vertexCount + 2;
+ m_indexBuffer[m_indexCount + 3] = m_vertexCount + 0;
+ m_indexBuffer[m_indexCount + 4] = m_vertexCount + 2;
+ m_indexBuffer[m_indexCount + 5] = m_vertexCount + 3;
+ m_vertexCount += 4;
+ m_indexCount += 6;
+ }
+
+ if (m_styleFlags & STYLE_OVERLINE
+ && m_overlineColor & 0xFF000000)
+ {
+ float x0 = (m_penX - kerning);
+ float y0 = (m_penY);
+ float x1 = ( (float)x0 + (glyph->advance_x) );
+ float y1 = y0 + font.underlineThickness;
+
+ m_fontManager->getAtlas()->packUV(blackGlyph.regionIndex
+ , (uint8_t*)m_vertexBuffer
+ , sizeof(TextVertex) * m_vertexCount + offsetof(TextVertex, u)
+ , sizeof(TextVertex)
+ );
+
+ setVertex(m_vertexCount + 0, x0, y0, m_overlineColor, STYLE_OVERLINE);
+ setVertex(m_vertexCount + 1, x0, y1, m_overlineColor, STYLE_OVERLINE);
+ setVertex(m_vertexCount + 2, x1, y1, m_overlineColor, STYLE_OVERLINE);
+ setVertex(m_vertexCount + 3, x1, y0, m_overlineColor, STYLE_OVERLINE);
+
+ m_indexBuffer[m_indexCount + 0] = m_vertexCount + 0;
+ m_indexBuffer[m_indexCount + 1] = m_vertexCount + 1;
+ m_indexBuffer[m_indexCount + 2] = m_vertexCount + 2;
+ m_indexBuffer[m_indexCount + 3] = m_vertexCount + 0;
+ m_indexBuffer[m_indexCount + 4] = m_vertexCount + 2;
+ m_indexBuffer[m_indexCount + 5] = m_vertexCount + 3;
+ m_vertexCount += 4;
+ m_indexCount += 6;
+ }
+
+ if (m_styleFlags & STYLE_STRIKE_THROUGH
+ && m_strikeThroughColor & 0xFF000000)
+ {
+ float x0 = (m_penX - kerning);
+ float y0 = (m_penY + 0.666667f * font.ascender);
+ float x1 = ( (float)x0 + (glyph->advance_x) );
+ float y1 = y0 + font.underlineThickness;
+
+ atlas->packUV(blackGlyph.regionIndex
+ , (uint8_t*)m_vertexBuffer
+ , sizeof(TextVertex) * m_vertexCount + offsetof(TextVertex, u)
+ , sizeof(TextVertex)
+ );
+
+ setVertex(m_vertexCount + 0, x0, y0, m_strikeThroughColor, STYLE_STRIKE_THROUGH);
+ setVertex(m_vertexCount + 1, x0, y1, m_strikeThroughColor, STYLE_STRIKE_THROUGH);
+ setVertex(m_vertexCount + 2, x1, y1, m_strikeThroughColor, STYLE_STRIKE_THROUGH);
+ setVertex(m_vertexCount + 3, x1, y0, m_strikeThroughColor, STYLE_STRIKE_THROUGH);
+
+ m_indexBuffer[m_indexCount + 0] = m_vertexCount + 0;
+ m_indexBuffer[m_indexCount + 1] = m_vertexCount + 1;
+ m_indexBuffer[m_indexCount + 2] = m_vertexCount + 2;
+ m_indexBuffer[m_indexCount + 3] = m_vertexCount + 0;
+ m_indexBuffer[m_indexCount + 4] = m_vertexCount + 2;
+ m_indexBuffer[m_indexCount + 5] = m_vertexCount + 3;
+ m_vertexCount += 4;
+ m_indexCount += 6;
+ }
+
+ float x0 = m_penX + (glyph->offset_x);
+ float y0 = (m_penY + m_lineAscender + (glyph->offset_y) );
+ float x1 = (x0 + glyph->width);
+ float y1 = (y0 + glyph->height);
+
+ atlas->packUV(glyph->regionIndex
+ , (uint8_t*)m_vertexBuffer
+ , sizeof(TextVertex) * m_vertexCount + offsetof(TextVertex, u)
+ , sizeof(TextVertex)
+ );
+
+ setVertex(m_vertexCount + 0, x0, y0, m_textColor);
+ setVertex(m_vertexCount + 1, x0, y1, m_textColor);
+ setVertex(m_vertexCount + 2, x1, y1, m_textColor);
+ setVertex(m_vertexCount + 3, x1, y0, m_textColor);
+
+ m_indexBuffer[m_indexCount + 0] = m_vertexCount + 0;
+ m_indexBuffer[m_indexCount + 1] = m_vertexCount + 1;
+ m_indexBuffer[m_indexCount + 2] = m_vertexCount + 2;
+ m_indexBuffer[m_indexCount + 3] = m_vertexCount + 0;
+ m_indexBuffer[m_indexCount + 4] = m_vertexCount + 2;
+ m_indexBuffer[m_indexCount + 5] = m_vertexCount + 3;
+ m_vertexCount += 4;
+ m_indexCount += 6;
+
+ m_penX += glyph->advance_x;
+ if (m_penX > m_rectangle.width)
+ {
+ m_rectangle.width = m_penX;
+ }
+
+ if ( (m_penY +m_lineAscender - m_lineDescender+m_lineGap) > m_rectangle.height)
+ {
+ m_rectangle.height = (m_penY +m_lineAscender - m_lineDescender+m_lineGap);
+ }
+}
+
+void TextBuffer::verticalCenterLastLine(float _dy, float _top, float _bottom)
+{
+ for (uint32_t ii = m_lineStartIndex; ii < m_vertexCount; ii += 4)
+ {
+ if (m_styleBuffer[ii] == STYLE_BACKGROUND)
+ {
+ m_vertexBuffer[ii + 0].y = _top;
+ m_vertexBuffer[ii + 1].y = _bottom;
+ m_vertexBuffer[ii + 2].y = _bottom;
+ m_vertexBuffer[ii + 3].y = _top;
+ }
+ else
+ {
+ m_vertexBuffer[ii + 0].y += _dy;
+ m_vertexBuffer[ii + 1].y += _dy;
+ m_vertexBuffer[ii + 2].y += _dy;
+ m_vertexBuffer[ii + 3].y += _dy;
+ }
+ }
+}
+
+TextBufferManager::TextBufferManager(FontManager* _fontManager)
+ : m_fontManager(_fontManager)
+{
+ m_textBuffers = new BufferCache[MAX_TEXT_BUFFER_COUNT];
+
+ const bgfx::Memory* vs_font_basic;
+ const bgfx::Memory* fs_font_basic;
+ const bgfx::Memory* vs_font_distance_field;
+ const bgfx::Memory* fs_font_distance_field;
+ const bgfx::Memory* vs_font_distance_field_subpixel;
+ const bgfx::Memory* fs_font_distance_field_subpixel;
+
+ switch (bgfx::getRendererType() )
+ {
+ case bgfx::RendererType::Direct3D9:
+ vs_font_basic = bgfx::makeRef(vs_font_basic_dx9, sizeof(vs_font_basic_dx9) );
+ fs_font_basic = bgfx::makeRef(fs_font_basic_dx9, sizeof(fs_font_basic_dx9) );
+ vs_font_distance_field = bgfx::makeRef(vs_font_distance_field_dx9, sizeof(vs_font_distance_field_dx9) );
+ fs_font_distance_field = bgfx::makeRef(fs_font_distance_field_dx9, sizeof(fs_font_distance_field_dx9) );
+ vs_font_distance_field_subpixel = bgfx::makeRef(vs_font_distance_field_subpixel_dx9, sizeof(vs_font_distance_field_subpixel_dx9) );
+ fs_font_distance_field_subpixel = bgfx::makeRef(fs_font_distance_field_subpixel_dx9, sizeof(fs_font_distance_field_subpixel_dx9) );
+ break;
+
+ case bgfx::RendererType::Direct3D11:
+ vs_font_basic = bgfx::makeRef(vs_font_basic_dx11, sizeof(vs_font_basic_dx11) );
+ fs_font_basic = bgfx::makeRef(fs_font_basic_dx11, sizeof(fs_font_basic_dx11) );
+ vs_font_distance_field = bgfx::makeRef(vs_font_distance_field_dx11, sizeof(vs_font_distance_field_dx11) );
+ fs_font_distance_field = bgfx::makeRef(fs_font_distance_field_dx11, sizeof(fs_font_distance_field_dx11) );
+ vs_font_distance_field_subpixel = bgfx::makeRef(vs_font_distance_field_subpixel_dx11, sizeof(vs_font_distance_field_subpixel_dx11) );
+ fs_font_distance_field_subpixel = bgfx::makeRef(fs_font_distance_field_subpixel_dx11, sizeof(fs_font_distance_field_subpixel_dx11) );
+ break;
+
+ default:
+ vs_font_basic = bgfx::makeRef(vs_font_basic_glsl, sizeof(vs_font_basic_glsl) );
+ fs_font_basic = bgfx::makeRef(fs_font_basic_glsl, sizeof(fs_font_basic_glsl) );
+ vs_font_distance_field = bgfx::makeRef(vs_font_distance_field_glsl, sizeof(vs_font_distance_field_glsl) );
+ fs_font_distance_field = bgfx::makeRef(fs_font_distance_field_glsl, sizeof(fs_font_distance_field_glsl) );
+ vs_font_distance_field_subpixel = bgfx::makeRef(vs_font_distance_field_subpixel_glsl, sizeof(vs_font_distance_field_subpixel_glsl) );
+ fs_font_distance_field_subpixel = bgfx::makeRef(fs_font_distance_field_subpixel_glsl, sizeof(fs_font_distance_field_subpixel_glsl) );
+ break;
+ }
+
+ m_basicProgram = bgfx::createProgram(
+ bgfx::createShader(vs_font_basic)
+ , bgfx::createShader(fs_font_basic)
+ , true
+ );
+
+ m_distanceProgram = bgfx::createProgram(
+ bgfx::createShader(vs_font_distance_field)
+ , bgfx::createShader(fs_font_distance_field)
+ , true
+ );
+
+ m_distanceSubpixelProgram = bgfx::createProgram(
+ bgfx::createShader(vs_font_distance_field_subpixel)
+ , bgfx::createShader(fs_font_distance_field_subpixel)
+ , true
+ );
+
+ m_vertexDecl
+ .begin()
+ .add(bgfx::Attrib::Position, 2, bgfx::AttribType::Float)
+ .add(bgfx::Attrib::TexCoord0, 4, bgfx::AttribType::Int16, true)
+ .add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true)
+ .end();
+
+ u_texColor = bgfx::createUniform("u_texColor", bgfx::UniformType::Uniform1iv);
+}
+
+TextBufferManager::~TextBufferManager()
+{
+ BX_CHECK(m_textBufferHandles.getNumHandles() == 0, "All the text buffers must be destroyed before destroying the manager");
+ delete [] m_textBuffers;
+
+ bgfx::destroyUniform(u_texColor);
+
+ bgfx::destroyProgram(m_basicProgram);
+ bgfx::destroyProgram(m_distanceProgram);
+ bgfx::destroyProgram(m_distanceSubpixelProgram);
+}
+
+TextBufferHandle TextBufferManager::createTextBuffer(uint32_t _type, BufferType::Enum _bufferType)
+{
+ uint16_t textIdx = m_textBufferHandles.alloc();
+ BufferCache& bc = m_textBuffers[textIdx];
+
+ bc.textBuffer = new TextBuffer(m_fontManager);
+ bc.fontType = _type;
+ bc.bufferType = _bufferType;
+ bc.indexBufferHandleIdx = bgfx::invalidHandle;
+ bc.vertexBufferHandleIdx = bgfx::invalidHandle;
+
+ TextBufferHandle ret = {textIdx};
+ return ret;
+}
+
+void TextBufferManager::destroyTextBuffer(TextBufferHandle _handle)
+{
+ BX_CHECK(bgfx::isValid(_handle), "Invalid handle used");
+
+ BufferCache& bc = m_textBuffers[_handle.idx];
+ m_textBufferHandles.free(_handle.idx);
+ delete bc.textBuffer;
+ bc.textBuffer = NULL;
+
+ if (bc.vertexBufferHandleIdx == bgfx::invalidHandle)
+ {
+ return;
+ }
+
+ switch (bc.bufferType)
+ {
+ case BufferType::Static:
+ {
+ bgfx::IndexBufferHandle ibh;
+ bgfx::VertexBufferHandle vbh;
+ ibh.idx = bc.indexBufferHandleIdx;
+ vbh.idx = bc.vertexBufferHandleIdx;
+ bgfx::destroyIndexBuffer(ibh);
+ bgfx::destroyVertexBuffer(vbh);
+ }
+
+ break;
+
+ case BufferType::Dynamic:
+ bgfx::DynamicIndexBufferHandle ibh;
+ bgfx::DynamicVertexBufferHandle vbh;
+ ibh.idx = bc.indexBufferHandleIdx;
+ vbh.idx = bc.vertexBufferHandleIdx;
+ bgfx::destroyDynamicIndexBuffer(ibh);
+ bgfx::destroyDynamicVertexBuffer(vbh);
+
+ break;
+
+ case BufferType::Transient: // destroyed every frame
+ break;
+ }
+}
+
+void TextBufferManager::submitTextBuffer(TextBufferHandle _handle, uint8_t _id, int32_t _depth)
+{
+ BX_CHECK(bgfx::isValid(_handle), "Invalid handle used");
+
+ BufferCache& bc = m_textBuffers[_handle.idx];
+
+ uint32_t indexSize = bc.textBuffer->getIndexCount() * bc.textBuffer->getIndexSize();
+ uint32_t vertexSize = bc.textBuffer->getVertexCount() * bc.textBuffer->getVertexSize();
+
+ if (0 == indexSize || 0 == vertexSize)
+ {
+ return;
+ }
+
+ bgfx::setTexture(0, u_texColor, m_fontManager->getAtlas()->getTextureHandle() );
+
+ switch (bc.fontType)
+ {
+ case FONT_TYPE_ALPHA:
+ bgfx::setProgram(m_basicProgram);
+ bgfx::setState(0
+ | BGFX_STATE_RGB_WRITE
+ | BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA)
+ );
+ break;
+
+ case FONT_TYPE_DISTANCE:
+ bgfx::setProgram(m_distanceProgram);
+ bgfx::setState(0
+ | BGFX_STATE_RGB_WRITE
+ | BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA)
+ );
+ break;
+
+ case FONT_TYPE_DISTANCE_SUBPIXEL:
+ bgfx::setProgram(m_distanceSubpixelProgram);
+ bgfx::setState(0
+ | BGFX_STATE_RGB_WRITE
+ | BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_FACTOR, BGFX_STATE_BLEND_INV_SRC_COLOR)
+ , bc.textBuffer->getTextColor()
+ );
+ break;
+ }
+
+ switch (bc.bufferType)
+ {
+ case BufferType::Static:
+ {
+ bgfx::IndexBufferHandle ibh;
+ bgfx::VertexBufferHandle vbh;
+
+ if (bgfx::invalidHandle == bc.vertexBufferHandleIdx)
+ {
+ ibh = bgfx::createIndexBuffer(
+ bgfx::copy(bc.textBuffer->getIndexBuffer(), indexSize)
+ );
+
+ vbh = bgfx::createVertexBuffer(
+ bgfx::copy(bc.textBuffer->getVertexBuffer(), vertexSize)
+ , m_vertexDecl
+ );
+
+ bc.vertexBufferHandleIdx = vbh.idx;
+ bc.indexBufferHandleIdx = ibh.idx;
+ }
+ else
+ {
+ vbh.idx = bc.vertexBufferHandleIdx;
+ ibh.idx = bc.indexBufferHandleIdx;
+ }
+
+ bgfx::setVertexBuffer(vbh, 0, bc.textBuffer->getVertexCount() );
+ bgfx::setIndexBuffer(ibh, bc.textBuffer->getIndexCount() );
+ }
+ break;
+
+ case BufferType::Dynamic:
+ {
+ bgfx::DynamicIndexBufferHandle ibh;
+ bgfx::DynamicVertexBufferHandle vbh;
+
+ if (bgfx::invalidHandle == bc.vertexBufferHandleIdx )
+ {
+ ibh = bgfx::createDynamicIndexBuffer(
+ bgfx::copy(bc.textBuffer->getIndexBuffer(), indexSize)
+ );
+
+ vbh = bgfx::createDynamicVertexBuffer(
+ bgfx::copy(bc.textBuffer->getVertexBuffer(), vertexSize)
+ , m_vertexDecl
+ );
+
+ bc.indexBufferHandleIdx = ibh.idx;
+ bc.vertexBufferHandleIdx = vbh.idx;
+ }
+ else
+ {
+ ibh.idx = bc.indexBufferHandleIdx;
+ vbh.idx = bc.vertexBufferHandleIdx;
+
+ bgfx::updateDynamicIndexBuffer(ibh
+ , bgfx::copy(bc.textBuffer->getIndexBuffer(), indexSize)
+ );
+
+ bgfx::updateDynamicVertexBuffer(vbh
+ , bgfx::copy(bc.textBuffer->getVertexBuffer(), vertexSize)
+ );
+ }
+
+ bgfx::setVertexBuffer(vbh, bc.textBuffer->getVertexCount() );
+ bgfx::setIndexBuffer(ibh, bc.textBuffer->getIndexCount() );
+ }
+ break;
+
+ case BufferType::Transient:
+ {
+ bgfx::TransientIndexBuffer tib;
+ bgfx::TransientVertexBuffer tvb;
+ bgfx::allocTransientIndexBuffer(&tib, bc.textBuffer->getIndexCount() );
+ bgfx::allocTransientVertexBuffer(&tvb, bc.textBuffer->getVertexCount(), m_vertexDecl);
+ memcpy(tib.data, bc.textBuffer->getIndexBuffer(), indexSize);
+ memcpy(tvb.data, bc.textBuffer->getVertexBuffer(), vertexSize);
+ bgfx::setVertexBuffer(&tvb, 0, bc.textBuffer->getVertexCount() );
+ bgfx::setIndexBuffer(&tib, 0, bc.textBuffer->getIndexCount() );
+ }
+ break;
+ }
+
+ bgfx::submit(_id, _depth);
+}
+
+void TextBufferManager::setStyle(TextBufferHandle _handle, uint32_t _flags)
+{
+ BX_CHECK(bgfx::isValid(_handle), "Invalid handle used");
+ BufferCache& bc = m_textBuffers[_handle.idx];
+ bc.textBuffer->setStyle(_flags);
+}
+
+void TextBufferManager::setTextColor(TextBufferHandle _handle, uint32_t _rgba)
+{
+ BX_CHECK(bgfx::isValid(_handle), "Invalid handle used");
+ BufferCache& bc = m_textBuffers[_handle.idx];
+ bc.textBuffer->setTextColor(_rgba);
+}
+
+void TextBufferManager::setBackgroundColor(TextBufferHandle _handle, uint32_t _rgba)
+{
+ BX_CHECK(bgfx::isValid(_handle), "Invalid handle used");
+ BufferCache& bc = m_textBuffers[_handle.idx];
+ bc.textBuffer->setBackgroundColor(_rgba);
+}
+
+void TextBufferManager::setOverlineColor(TextBufferHandle _handle, uint32_t _rgba)
+{
+ BX_CHECK(bgfx::isValid(_handle), "Invalid handle used");
+ BufferCache& bc = m_textBuffers[_handle.idx];
+ bc.textBuffer->setOverlineColor(_rgba);
+}
+
+void TextBufferManager::setUnderlineColor(TextBufferHandle _handle, uint32_t _rgba)
+{
+ BX_CHECK(bgfx::isValid(_handle), "Invalid handle used");
+ BufferCache& bc = m_textBuffers[_handle.idx];
+ bc.textBuffer->setUnderlineColor(_rgba);
+}
+
+void TextBufferManager::setStrikeThroughColor(TextBufferHandle _handle, uint32_t _rgba)
+{
+ BX_CHECK(bgfx::isValid(_handle), "Invalid handle used");
+ BufferCache& bc = m_textBuffers[_handle.idx];
+ bc.textBuffer->setStrikeThroughColor(_rgba);
+}
+
+void TextBufferManager::setPenPosition(TextBufferHandle _handle, float _x, float _y)
+{
+ BX_CHECK(bgfx::isValid(_handle), "Invalid handle used");
+ BufferCache& bc = m_textBuffers[_handle.idx];
+ bc.textBuffer->setPenPosition(_x, _y);
+}
+
+void TextBufferManager::appendText(TextBufferHandle _handle, FontHandle _fontHandle, const char* _string, const char* _end)
+{
+ BX_CHECK(bgfx::isValid(_handle), "Invalid handle used");
+ BufferCache& bc = m_textBuffers[_handle.idx];
+ bc.textBuffer->appendText(_fontHandle, _string, _end);
+}
+
+void TextBufferManager::appendText(TextBufferHandle _handle, FontHandle _fontHandle, const wchar_t* _string, const wchar_t* _end)
+{
+ BX_CHECK(bgfx::isValid(_handle), "Invalid handle used");
+ BufferCache& bc = m_textBuffers[_handle.idx];
+ bc.textBuffer->appendText(_fontHandle, _string, _end);
+}
+
+void TextBufferManager::appendAtlasFace(TextBufferHandle _handle, uint16_t _faceIndex)
+{
+ BX_CHECK(bgfx::isValid(_handle), "Invalid handle used");
+ BufferCache& bc = m_textBuffers[_handle.idx];
+ bc.textBuffer->appendAtlasFace(_faceIndex);
+}
+
+void TextBufferManager::clearTextBuffer(TextBufferHandle _handle)
+{
+ BX_CHECK(bgfx::isValid(_handle), "Invalid handle used");
+ BufferCache& bc = m_textBuffers[_handle.idx];
+ bc.textBuffer->clearTextBuffer();
+}
+
+TextRectangle TextBufferManager::getRectangle(TextBufferHandle _handle) const
+{
+ BX_CHECK(bgfx::isValid(_handle), "Invalid handle used");
+ BufferCache& bc = m_textBuffers[_handle.idx];
+ return bc.textBuffer->getRectangle();
+}