bgfx/examples/common/font/text_buffer_manager.cpp

898 lines
24 KiB
C++
Raw Normal View History

2013-05-15 17:07:04 +04:00
/*
* Copyright 2013 Jeremie Roy. All rights reserved.
2016-01-01 11:11:04 +03:00
* License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
2013-05-15 17:07:04 +04:00
*/
2013-05-19 09:12:40 +04:00
#include "../common.h"
2013-05-17 09:03:57 +04:00
#include <bgfx/bgfx.h>
2016-12-06 07:12:31 +03:00
#include <bgfx/embedded_shader.h>
2013-05-16 06:42:39 +04:00
#include <stddef.h> // offsetof
#include <wchar.h> // wcslen
2013-04-23 00:42:11 +04:00
#include "text_buffer_manager.h"
2013-05-17 09:03:57 +04:00
#include "utf8.h"
2013-04-23 00:42:11 +04:00
#include "../cube_atlas.h"
2013-05-08 21:53:47 +04:00
#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"
2016-12-06 07:12:31 +03:00
static const bgfx::EmbeddedShader s_embeddedShaders[] =
{
BGFX_EMBEDDED_SHADER(vs_font_basic),
BGFX_EMBEDDED_SHADER(fs_font_basic),
BGFX_EMBEDDED_SHADER(vs_font_distance_field),
BGFX_EMBEDDED_SHADER(fs_font_distance_field),
BGFX_EMBEDDED_SHADER(vs_font_distance_field_subpixel),
BGFX_EMBEDDED_SHADER(fs_font_distance_field_subpixel),
BGFX_EMBEDDED_SHADER_END()
};
#define MAX_BUFFERED_CHARACTERS (8192 - 5)
2013-04-23 00:42:11 +04:00
class TextBuffer
{
2013-05-15 17:21:23 +04:00
public:
2013-05-16 06:42:39 +04:00
/// TextBuffer is bound to a fontManager for glyph retrieval
/// @remark the ownership of the manager is not taken
TextBuffer(FontManager* _fontManager);
~TextBuffer();
2013-05-15 17:21:23 +04:00
2013-05-16 06:42:39 +04:00
void setStyle(uint32_t _flags = STYLE_NORMAL)
{
m_styleFlags = _flags;
}
2013-05-23 08:34:21 +04:00
2013-05-16 06:42:39 +04:00
void setTextColor(uint32_t _rgba = 0x000000FF)
{
m_textColor = toABGR(_rgba);
}
2013-05-23 08:34:21 +04:00
2013-05-16 06:42:39 +04:00
void setBackgroundColor(uint32_t _rgba = 0x000000FF)
{
m_backgroundColor = toABGR(_rgba);
}
2013-05-15 17:21:23 +04:00
2013-05-16 06:42:39 +04:00
void setOverlineColor(uint32_t _rgba = 0x000000FF)
{
m_overlineColor = toABGR(_rgba);
}
2013-05-23 08:34:21 +04:00
2013-05-16 06:42:39 +04:00
void setUnderlineColor(uint32_t _rgba = 0x000000FF)
{
m_underlineColor = toABGR(_rgba);
}
2013-05-23 08:34:21 +04:00
2013-05-16 06:42:39 +04:00
void setStrikeThroughColor(uint32_t _rgba = 0x000000FF)
{
m_strikeThroughColor = toABGR(_rgba);
}
2013-05-15 17:21:23 +04:00
2013-05-16 06:42:39 +04:00
void setPenPosition(float _x, float _y)
{
m_penX = _x; m_penY = _y;
}
2013-05-15 17:21:23 +04:00
2013-05-23 08:34:21 +04:00
/// 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);
2013-05-15 17:21:23 +04:00
2013-05-23 08:34:21 +04:00
/// 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);
2015-02-17 08:58:13 +03:00
2013-05-23 08:34:21 +04:00
/// Append a whole face of the atlas cube, mostly used for debugging
/// and visualizing atlas.
void appendAtlasFace(uint16_t _faceIndex);
2013-05-15 17:21:23 +04:00
2013-05-16 06:42:39 +04:00
/// Clear the text buffer and reset its state (pen/color)
void clearTextBuffer();
2013-05-15 17:21:23 +04:00
2013-05-23 08:34:21 +04:00
/// Get pointer to the vertex buffer to submit it to the graphic card.
2013-05-16 06:42:39 +04:00
const uint8_t* getVertexBuffer()
{
return (uint8_t*) m_vertexBuffer;
}
2013-05-23 08:34:21 +04:00
/// Number of vertex in the vertex buffer.
uint32_t getVertexCount() const
2013-05-16 06:42:39 +04:00
{
return m_vertexCount;
}
2013-05-23 08:34:21 +04:00
/// Size in bytes of a vertex.
uint32_t getVertexSize() const
2013-05-16 06:42:39 +04:00
{
return sizeof(TextVertex);
}
2013-05-15 17:21:23 +04:00
2013-05-16 06:42:39 +04:00
/// get a pointer to the index buffer to submit it to the graphic
2013-05-23 08:34:21 +04:00
const uint16_t* getIndexBuffer() const
2013-05-16 06:42:39 +04:00
{
return m_indexBuffer;
}
2013-05-23 08:34:21 +04:00
2013-05-16 06:42:39 +04:00
/// number of index in the index buffer
2013-05-23 08:34:21 +04:00
uint32_t getIndexCount() const
2013-05-16 06:42:39 +04:00
{
return m_indexCount;
}
2013-05-23 08:34:21 +04:00
/// Size in bytes of an index.
uint32_t getIndexSize() const
2013-05-16 06:42:39 +04:00
{
return sizeof(uint16_t);
}
2013-05-15 17:21:23 +04:00
2013-05-23 08:34:21 +04:00
uint32_t getTextColor() const
2013-05-16 06:42:39 +04:00
{
return toABGR(m_textColor);
}
2013-05-15 17:21:23 +04:00
2013-05-16 06:42:39 +04:00
TextRectangle getRectangle() const
{
return m_rectangle;
}
2013-05-09 01:55:54 +04:00
2013-04-23 00:42:11 +04:00
private:
2013-05-30 08:53:19 +04:00
void appendGlyph(FontHandle _handle, CodePoint _codePoint);
2013-05-16 06:42:39 +04:00
void verticalCenterLastLine(float _txtDecalY, float _top, float _bottom);
2013-05-23 08:34:21 +04:00
static uint32_t toABGR(uint32_t _rgba)
2013-05-16 06:42:39 +04:00
{
2013-05-23 08:34:21 +04:00
return ( ( (_rgba >> 0) & 0xff) << 24)
| ( ( (_rgba >> 8) & 0xff) << 16)
| ( ( (_rgba >> 16) & 0xff) << 8)
| ( ( (_rgba >> 24) & 0xff) << 0)
;
2013-05-16 06:42:39 +04:00
}
2013-04-23 00:42:11 +04:00
2013-05-16 06:42:39 +04:00
uint32_t m_styleFlags;
2013-04-23 00:42:11 +04:00
2013-05-16 06:42:39 +04:00
// color states
uint32_t m_textColor;
2013-04-23 00:42:11 +04:00
2013-05-16 06:42:39 +04:00
uint32_t m_backgroundColor;
uint32_t m_overlineColor;
uint32_t m_underlineColor;
uint32_t m_strikeThroughColor;
2013-05-15 17:21:23 +04:00
2013-05-16 06:42:39 +04:00
//position states
float m_penX;
float m_penY;
2013-05-15 17:21:23 +04:00
2013-05-16 06:42:39 +04:00
float m_originX;
float m_originY;
2013-05-15 17:21:23 +04:00
2013-05-16 06:42:39 +04:00
float m_lineAscender;
float m_lineDescender;
float m_lineGap;
2013-05-15 17:21:23 +04:00
2013-05-16 06:42:39 +04:00
TextRectangle m_rectangle;
FontManager* m_fontManager;
2013-05-15 17:21:23 +04:00
2013-05-16 06:42:39 +04:00
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;
}
2013-05-15 17:21:23 +04:00
2013-05-16 06:42:39 +04:00
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;
2014-01-21 10:07:08 +04:00
uint16_t m_vertexCount;
2013-05-15 17:21:23 +04:00
};
2013-04-23 00:42:11 +04:00
TextBuffer::TextBuffer(FontManager* _fontManager)
2013-05-17 09:03:57 +04:00
: 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)
2014-01-21 11:43:09 +04:00
, m_vertexCount(0)
2013-05-15 17:21:23 +04:00
{
2013-05-09 01:55:54 +04:00
m_rectangle.width = 0;
m_rectangle.height = 0;
2013-04-23 00:42:11 +04:00
}
TextBuffer::~TextBuffer()
{
2013-06-25 10:38:14 +04:00
delete [] m_vertexBuffer;
delete [] m_indexBuffer;
2013-12-22 11:37:35 +04:00
delete [] m_styleBuffer;
2013-04-23 00:42:11 +04:00
}
void TextBuffer::appendText(FontHandle _fontHandle, const char* _string, const char* _end)
2013-05-15 17:21:23 +04:00
{
if (m_vertexCount == 0)
2013-04-23 00:42:11 +04:00
{
m_originX = m_penX;
m_originY = m_penY;
m_lineDescender = 0;
m_lineAscender = 0;
m_lineGap = 0;
2013-04-23 00:42:11 +04:00
}
2013-05-15 17:21:23 +04:00
2013-05-17 09:03:57 +04:00
CodePoint codepoint = 0;
2013-04-23 00:42:11 +04:00
uint32_t state = 0;
if (_end == NULL)
{
2017-04-17 07:56:17 +03:00
_end = _string + bx::strLen(_string);
}
BX_CHECK(_end >= _string);
for (; *_string && _string < _end ; ++_string)
2013-05-15 17:21:23 +04:00
{
if (utf8_decode(&state, (uint32_t*)&codepoint, *_string) == UTF8_ACCEPT )
2013-04-23 00:42:11 +04:00
{
2013-05-30 08:53:19 +04:00
appendGlyph(_fontHandle, codepoint);
2013-04-23 00:42:11 +04:00
}
2013-05-15 17:21:23 +04:00
}
2015-02-17 08:58:13 +03:00
BX_CHECK(state == UTF8_ACCEPT, "The string is not well-formed");
2013-04-23 00:42:11 +04:00
}
void TextBuffer::appendText(FontHandle _fontHandle, const wchar_t* _string, const wchar_t* _end)
2013-05-15 17:21:23 +04:00
{
if (m_vertexCount == 0)
2013-04-23 00:42:11 +04:00
{
m_originX = m_penX;
m_originY = m_penY;
m_lineDescender = 0;
m_lineAscender = 0;
2013-04-23 00:42:11 +04:00
m_lineGap = 0;
}
2013-05-23 08:34:21 +04:00
if (_end == NULL)
{
_end = _string + wcslen(_string);
}
BX_CHECK(_end >= _string);
2013-04-23 00:42:11 +04:00
for (const wchar_t* _current = _string; _current < _end; ++_current)
2013-04-23 00:42:11 +04:00
{
uint32_t _codePoint = *_current;
2013-05-30 08:53:19 +04:00
appendGlyph(_fontHandle, _codePoint);
2013-04-23 00:42:11 +04:00
}
}
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();
2013-05-23 08:34:21 +04:00
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;
}
2013-04-23 00:42:11 +04:00
void TextBuffer::clearTextBuffer()
{
m_penX = 0;
m_penY = 0;
m_originX = 0;
m_originY = 0;
2013-04-23 00:42:11 +04:00
m_vertexCount = 0;
m_indexCount = 0;
m_lineStartIndex = 0;
m_lineAscender = 0;
m_lineDescender = 0;
m_lineGap = 0;
2013-05-09 01:55:54 +04:00
m_rectangle.width = 0;
m_rectangle.height = 0;
2013-04-23 00:42:11 +04:00
}
2013-05-30 08:53:19 +04:00
void TextBuffer::appendGlyph(FontHandle _handle, CodePoint _codePoint)
{
2015-10-08 06:44:40 +03:00
if (_codePoint == L'\t')
{
for (uint32_t ii = 0; ii < 4; ++ii)
{
appendGlyph(_handle, L' ');
}
return;
}
2013-05-30 08:53:19 +04:00
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;
}
if( m_vertexCount/4 >= MAX_BUFFERED_CHARACTERS)
{
return;
}
2015-10-08 06:44:40 +03:00
const FontInfo& font = m_fontManager->getFontInfo(_handle);
2013-05-15 17:21:23 +04:00
if (_codePoint == L'\n')
{
m_penX = m_originX;
m_penY += m_lineGap + m_lineAscender -m_lineDescender;
2013-05-30 08:53:19 +04:00
m_lineGap = font.lineGap;
2015-10-08 06:44:40 +03:00
m_lineDescender = font.descender;
m_lineAscender = font.ascender;
2013-05-15 17:21:23 +04:00
m_lineStartIndex = m_vertexCount;
2013-04-23 00:42:11 +04:00
return;
2013-05-15 17:21:23 +04:00
}
//is there a change of font size that require the text on the left to be centered again ?
2013-05-30 08:53:19 +04:00
if (font.ascender > m_lineAscender
2015-10-08 06:44:40 +03:00
|| (font.descender < m_lineDescender) )
2013-05-15 17:21:23 +04:00
{
2013-05-30 08:53:19 +04:00
if (font.descender < m_lineDescender)
2013-04-23 00:42:11 +04:00
{
2013-05-30 08:53:19 +04:00
m_lineDescender = font.descender;
m_lineGap = font.lineGap;
2013-04-23 00:42:11 +04:00
}
2013-05-15 17:21:23 +04:00
2013-05-30 08:53:19 +04:00
float txtDecals = (font.ascender - m_lineAscender);
m_lineAscender = font.ascender;
2015-02-17 08:58:13 +03:00
m_lineGap = font.lineGap;
verticalCenterLastLine( (txtDecals), (m_penY - m_lineAscender), (m_penY + m_lineAscender - m_lineDescender + m_lineGap) );
2013-05-15 17:21:23 +04:00
}
2013-05-30 08:53:19 +04:00
float kerning = 0 * font.scale;
m_penX += kerning;
2013-04-23 00:42:11 +04:00
2013-05-30 08:53:19 +04:00
const GlyphInfo& blackGlyph = m_fontManager->getBlackGlyph();
2013-05-30 09:47:19 +04:00
const Atlas* atlas = m_fontManager->getAtlas();
2013-05-15 17:21:23 +04:00
if (m_styleFlags & STYLE_BACKGROUND
2015-10-08 06:44:40 +03:00
&& m_backgroundColor & 0xff000000)
2013-04-23 00:42:11 +04:00
{
2013-05-15 17:21:23 +04:00
float x0 = (m_penX - kerning);
float y0 = (m_penY);
2013-05-30 08:53:19 +04:00
float x1 = ( (float)x0 + (glyph->advance_x) );
float y1 = (m_penY + m_lineAscender - m_lineDescender + m_lineGap);
2013-05-15 17:21:23 +04:00
2013-05-30 09:47:19 +04:00
atlas->packUV(blackGlyph.regionIndex
2013-05-23 08:34:21 +04:00
, (uint8_t*)m_vertexBuffer
, sizeof(TextVertex) * m_vertexCount + offsetof(TextVertex, u)
, sizeof(TextVertex)
);
2013-05-15 17:21:23 +04:00
2014-01-21 10:07:08 +04:00
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;
2013-04-23 00:42:11 +04:00
m_vertexCount += 4;
m_indexCount += 6;
}
2013-05-15 17:21:23 +04:00
if (m_styleFlags & STYLE_UNDERLINE
2013-05-17 09:03:57 +04:00
&& m_underlineColor & 0xFF000000)
2013-04-23 00:42:11 +04:00
{
2013-05-15 17:21:23 +04:00
float x0 = (m_penX - kerning);
float y0 = (m_penY + m_lineAscender - m_lineDescender * 0.5f);
2013-05-30 08:53:19 +04:00
float x1 = ( (float)x0 + (glyph->advance_x) );
float y1 = y0 + font.underlineThickness;
2013-05-15 17:21:23 +04:00
2013-05-30 09:47:19 +04:00
atlas->packUV(blackGlyph.regionIndex
2013-05-23 08:34:21 +04:00
, (uint8_t*)m_vertexBuffer
, sizeof(TextVertex) * m_vertexCount + offsetof(TextVertex, u)
, sizeof(TextVertex)
);
2013-05-15 17:21:23 +04:00
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;
2013-04-23 00:42:11 +04:00
m_vertexCount += 4;
m_indexCount += 6;
}
2013-05-15 17:21:23 +04:00
if (m_styleFlags & STYLE_OVERLINE
2013-05-17 09:03:57 +04:00
&& m_overlineColor & 0xFF000000)
2013-04-23 00:42:11 +04:00
{
2013-05-15 17:21:23 +04:00
float x0 = (m_penX - kerning);
float y0 = (m_penY);
2013-05-30 08:53:19 +04:00
float x1 = ( (float)x0 + (glyph->advance_x) );
float y1 = y0 + font.underlineThickness;
2013-05-15 17:21:23 +04:00
2013-05-23 08:34:21 +04:00
m_fontManager->getAtlas()->packUV(blackGlyph.regionIndex
, (uint8_t*)m_vertexBuffer
, sizeof(TextVertex) * m_vertexCount + offsetof(TextVertex, u)
, sizeof(TextVertex)
);
2013-05-15 17:21:23 +04:00
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;
2013-04-23 00:42:11 +04:00
m_vertexCount += 4;
m_indexCount += 6;
}
2013-05-15 17:21:23 +04:00
if (m_styleFlags & STYLE_STRIKE_THROUGH
2013-05-17 09:03:57 +04:00
&& m_strikeThroughColor & 0xFF000000)
2013-04-23 00:42:11 +04:00
{
2013-05-15 17:21:23 +04:00
float x0 = (m_penX - kerning);
2013-05-30 08:53:19 +04:00
float y0 = (m_penY + 0.666667f * font.ascender);
float x1 = ( (float)x0 + (glyph->advance_x) );
float y1 = y0 + font.underlineThickness;
2013-05-15 17:21:23 +04:00
2013-05-30 09:47:19 +04:00
atlas->packUV(blackGlyph.regionIndex
2013-05-23 08:34:21 +04:00
, (uint8_t*)m_vertexBuffer
, sizeof(TextVertex) * m_vertexCount + offsetof(TextVertex, u)
, sizeof(TextVertex)
);
2013-05-15 17:21:23 +04:00
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;
2013-04-23 00:42:11 +04:00
m_vertexCount += 4;
m_indexCount += 6;
}
2013-05-30 08:53:19 +04:00
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);
2013-05-15 17:21:23 +04:00
2013-05-30 09:47:19 +04:00
atlas->packUV(glyph->regionIndex
2013-05-23 08:34:21 +04:00
, (uint8_t*)m_vertexBuffer
, sizeof(TextVertex) * m_vertexCount + offsetof(TextVertex, u)
, sizeof(TextVertex)
);
2013-05-15 17:21:23 +04:00
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;
2013-04-23 00:42:11 +04:00
m_vertexCount += 4;
m_indexCount += 6;
2013-05-15 17:21:23 +04:00
2013-05-30 08:53:19 +04:00
m_penX += glyph->advance_x;
2013-05-15 17:21:23 +04:00
if (m_penX > m_rectangle.width)
{
m_rectangle.width = m_penX;
}
if ( (m_penY +m_lineAscender - m_lineDescender+m_lineGap) > m_rectangle.height)
2013-05-15 17:21:23 +04:00
{
m_rectangle.height = (m_penY +m_lineAscender - m_lineDescender+m_lineGap);
2013-05-15 17:21:23 +04:00
}
2013-04-23 00:42:11 +04:00
}
void TextBuffer::verticalCenterLastLine(float _dy, float _top, float _bottom)
2013-05-15 17:21:23 +04:00
{
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
2013-04-23 00:42:11 +04:00
{
2013-05-15 17:21:23 +04:00
m_vertexBuffer[ii + 0].y += _dy;
m_vertexBuffer[ii + 1].y += _dy;
m_vertexBuffer[ii + 2].y += _dy;
m_vertexBuffer[ii + 3].y += _dy;
2013-04-23 00:42:11 +04:00
}
2013-05-15 17:21:23 +04:00
}
2013-04-23 00:42:11 +04:00
}
2013-05-16 08:35:26 +04:00
TextBufferManager::TextBufferManager(FontManager* _fontManager)
2013-09-21 09:13:58 +04:00
: m_fontManager(_fontManager)
2013-04-23 00:42:11 +04:00
{
m_textBuffers = new BufferCache[MAX_TEXT_BUFFER_COUNT];
2016-12-06 07:12:31 +03:00
bgfx::RendererType::Enum type = bgfx::getRendererType();
2013-04-23 00:42:11 +04:00
2014-04-17 09:11:14 +04:00
m_basicProgram = bgfx::createProgram(
2016-12-06 07:12:31 +03:00
bgfx::createEmbeddedShader(s_embeddedShaders, type, "vs_font_basic")
, bgfx::createEmbeddedShader(s_embeddedShaders, type, "fs_font_basic")
, true
);
2014-04-17 09:11:14 +04:00
m_distanceProgram = bgfx::createProgram(
2016-12-06 07:12:31 +03:00
bgfx::createEmbeddedShader(s_embeddedShaders, type, "vs_font_distance_field")
, bgfx::createEmbeddedShader(s_embeddedShaders, type, "fs_font_distance_field")
, true
);
2014-04-17 09:11:14 +04:00
m_distanceSubpixelProgram = bgfx::createProgram(
2016-12-06 07:12:31 +03:00
bgfx::createEmbeddedShader(s_embeddedShaders, type, "vs_font_distance_field_subpixel")
, bgfx::createEmbeddedShader(s_embeddedShaders, type, "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();
2015-07-29 09:16:23 +03:00
s_texColor = bgfx::createUniform("s_texColor", bgfx::UniformType::Int1);
}
2013-04-23 00:42:11 +04:00
2013-05-08 21:53:47 +04:00
TextBufferManager::~TextBufferManager()
{
BX_CHECK(m_textBufferHandles.getNumHandles() == 0, "All the text buffers must be destroyed before destroying the manager");
2013-06-25 10:38:14 +04:00
delete [] m_textBuffers;
2013-04-23 00:42:11 +04:00
bgfx::destroy(s_texColor);
2013-04-23 00:42:11 +04:00
bgfx::destroy(m_basicProgram);
bgfx::destroy(m_distanceProgram);
bgfx::destroy(m_distanceSubpixelProgram);
2013-05-08 21:53:47 +04:00
}
2013-04-23 00:42:11 +04:00
2013-06-04 10:16:02 +04:00
TextBufferHandle TextBufferManager::createTextBuffer(uint32_t _type, BufferType::Enum _bufferType)
2013-05-15 17:21:23 +04:00
{
2013-04-23 00:42:11 +04:00
uint16_t textIdx = m_textBufferHandles.alloc();
BufferCache& bc = m_textBuffers[textIdx];
2013-05-15 17:21:23 +04:00
bc.textBuffer = new TextBuffer(m_fontManager);
bc.fontType = _type;
2013-05-15 17:21:23 +04:00
bc.bufferType = _bufferType;
2017-06-10 07:57:08 +03:00
bc.indexBufferHandleIdx = bgfx::kInvalidHandle;
bc.vertexBufferHandleIdx = bgfx::kInvalidHandle;
2013-04-23 00:42:11 +04:00
TextBufferHandle ret = {textIdx};
2013-05-15 17:21:23 +04:00
return ret;
2013-04-23 00:42:11 +04:00
}
void TextBufferManager::destroyTextBuffer(TextBufferHandle _handle)
2013-05-15 17:21:23 +04:00
{
BX_CHECK(bgfx::isValid(_handle), "Invalid handle used");
2013-05-15 17:21:23 +04:00
BufferCache& bc = m_textBuffers[_handle.idx];
m_textBufferHandles.free(_handle.idx);
delete bc.textBuffer;
bc.textBuffer = NULL;
2013-04-23 00:42:11 +04:00
2017-06-10 07:57:08 +03:00
if (bc.vertexBufferHandleIdx == bgfx::kInvalidHandle)
2013-05-15 17:21:23 +04:00
{
return;
}
switch (bc.bufferType)
2013-04-23 00:42:11 +04:00
{
2013-06-04 10:16:02 +04:00
case BufferType::Static:
2013-05-16 06:42:39 +04:00
{
bgfx::IndexBufferHandle ibh;
bgfx::VertexBufferHandle vbh;
ibh.idx = bc.indexBufferHandleIdx;
vbh.idx = bc.vertexBufferHandleIdx;
bgfx::destroy(ibh);
bgfx::destroy(vbh);
2013-05-16 06:42:39 +04:00
}
2013-05-15 17:21:23 +04:00
2013-05-16 06:42:39 +04:00
break;
2013-04-23 00:42:11 +04:00
2013-06-04 10:16:02 +04:00
case BufferType::Dynamic:
2013-04-23 00:42:11 +04:00
bgfx::DynamicIndexBufferHandle ibh;
bgfx::DynamicVertexBufferHandle vbh;
ibh.idx = bc.indexBufferHandleIdx;
vbh.idx = bc.vertexBufferHandleIdx;
bgfx::destroy(ibh);
bgfx::destroy(vbh);
2013-05-15 17:21:23 +04:00
2013-04-23 00:42:11 +04:00
break;
2013-05-15 17:21:23 +04:00
2013-06-04 10:16:02 +04:00
case BufferType::Transient: // destroyed every frame
2013-05-15 17:21:23 +04:00
break;
}
2013-04-23 00:42:11 +04:00
}
void TextBufferManager::submitTextBuffer(TextBufferHandle _handle, bgfx::ViewId _id, int32_t _depth)
2013-04-23 00:42:11 +04:00
{
BX_CHECK(bgfx::isValid(_handle), "Invalid handle used");
2013-06-04 10:16:02 +04:00
2013-04-23 00:42:11 +04:00
BufferCache& bc = m_textBuffers[_handle.idx];
2013-05-15 17:21:23 +04:00
2014-04-17 09:11:14 +04:00
uint32_t indexSize = bc.textBuffer->getIndexCount() * bc.textBuffer->getIndexSize();
uint32_t vertexSize = bc.textBuffer->getVertexCount() * bc.textBuffer->getVertexSize();
2013-08-09 09:18:19 +04:00
if (0 == indexSize || 0 == vertexSize)
{
return;
}
2015-07-29 09:16:23 +03:00
bgfx::setTexture(0, s_texColor, m_fontManager->getAtlas()->getTextureHandle() );
2013-05-15 17:21:23 +04:00
bgfx::ProgramHandle program = BGFX_INVALID_HANDLE;
switch (bc.fontType)
2013-04-23 00:42:11 +04:00
{
case FONT_TYPE_ALPHA:
program = m_basicProgram;
2013-05-23 08:34:21 +04:00
bgfx::setState(0
| BGFX_STATE_RGB_WRITE
| BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA)
);
2013-04-23 00:42:11 +04:00
break;
2013-05-15 17:21:23 +04:00
2013-04-23 00:42:11 +04:00
case FONT_TYPE_DISTANCE:
program = m_distanceProgram;
2013-05-23 08:34:21 +04:00
bgfx::setState(0
| BGFX_STATE_RGB_WRITE
| BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA)
);
2013-04-23 00:42:11 +04:00
break;
2013-05-15 17:21:23 +04:00
2013-04-23 00:42:11 +04:00
case FONT_TYPE_DISTANCE_SUBPIXEL:
program = m_distanceSubpixelProgram;
2013-05-23 08:34:21 +04:00
bgfx::setState(0
| BGFX_STATE_RGB_WRITE
| BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_FACTOR, BGFX_STATE_BLEND_INV_SRC_COLOR)
, bc.textBuffer->getTextColor()
);
2013-05-15 17:21:23 +04:00
break;
}
2013-04-23 00:42:11 +04:00
2013-05-15 17:21:23 +04:00
switch (bc.bufferType)
2013-04-23 00:42:11 +04:00
{
2013-06-04 10:16:02 +04:00
case BufferType::Static:
2013-05-15 17:21:23 +04:00
{
2013-05-16 06:42:39 +04:00
bgfx::IndexBufferHandle ibh;
bgfx::VertexBufferHandle vbh;
2013-04-23 00:42:11 +04:00
2017-06-10 07:57:08 +03:00
if (bgfx::kInvalidHandle == bc.vertexBufferHandleIdx)
2013-05-16 06:42:39 +04:00
{
2014-04-17 09:24:31 +04:00
ibh = bgfx::createIndexBuffer(
bgfx::copy(bc.textBuffer->getIndexBuffer(), indexSize)
);
2013-04-23 00:42:11 +04:00
2014-04-17 09:24:31 +04:00
vbh = bgfx::createVertexBuffer(
bgfx::copy(bc.textBuffer->getVertexBuffer(), vertexSize)
, m_vertexDecl
);
2013-04-23 00:42:11 +04:00
bc.vertexBufferHandleIdx = vbh.idx;
2014-04-17 09:24:31 +04:00
bc.indexBufferHandleIdx = ibh.idx;
2013-05-16 06:42:39 +04:00
}
else
{
vbh.idx = bc.vertexBufferHandleIdx;
2014-04-17 09:24:31 +04:00
ibh.idx = bc.indexBufferHandleIdx;
2013-05-16 06:42:39 +04:00
}
2013-04-23 00:42:11 +04:00
2017-05-14 21:48:59 +03:00
bgfx::setVertexBuffer(0, vbh, 0, bc.textBuffer->getVertexCount() );
2015-07-23 06:55:59 +03:00
bgfx::setIndexBuffer(ibh, 0, bc.textBuffer->getIndexCount() );
2013-05-30 09:47:19 +04:00
}
break;
2013-04-23 00:42:11 +04:00
2013-06-04 10:16:02 +04:00
case BufferType::Dynamic:
2013-05-15 17:21:23 +04:00
{
2013-05-16 06:42:39 +04:00
bgfx::DynamicIndexBufferHandle ibh;
bgfx::DynamicVertexBufferHandle vbh;
2013-05-15 17:21:23 +04:00
2017-06-10 07:57:08 +03:00
if (bgfx::kInvalidHandle == bc.vertexBufferHandleIdx )
2013-05-16 06:42:39 +04:00
{
2014-04-17 09:24:31 +04:00
ibh = bgfx::createDynamicIndexBuffer(
bgfx::copy(bc.textBuffer->getIndexBuffer(), indexSize)
);
2013-05-15 17:21:23 +04:00
2014-04-17 09:24:31 +04:00
vbh = bgfx::createDynamicVertexBuffer(
bgfx::copy(bc.textBuffer->getVertexBuffer(), vertexSize)
, m_vertexDecl
);
2013-05-16 06:42:39 +04:00
bc.indexBufferHandleIdx = ibh.idx;
bc.vertexBufferHandleIdx = vbh.idx;
2013-05-16 06:42:39 +04:00
}
else
{
ibh.idx = bc.indexBufferHandleIdx;
vbh.idx = bc.vertexBufferHandleIdx;
2013-05-15 17:21:23 +04:00
2014-04-17 09:24:31 +04:00
bgfx::updateDynamicIndexBuffer(ibh
, 0
2014-04-17 09:24:31 +04:00
, bgfx::copy(bc.textBuffer->getIndexBuffer(), indexSize)
);
2013-05-15 17:21:23 +04:00
2014-04-17 09:24:31 +04:00
bgfx::updateDynamicVertexBuffer(vbh
, 0
2014-04-17 09:24:31 +04:00
, bgfx::copy(bc.textBuffer->getVertexBuffer(), vertexSize)
);
2013-05-16 06:42:39 +04:00
}
2013-05-15 17:21:23 +04:00
2017-05-14 21:48:59 +03:00
bgfx::setVertexBuffer(0, vbh, 0, bc.textBuffer->getVertexCount() );
2016-02-24 02:30:25 +03:00
bgfx::setIndexBuffer(ibh, 0, bc.textBuffer->getIndexCount() );
2013-05-30 09:47:19 +04:00
}
break;
2013-05-15 17:21:23 +04:00
2013-06-04 10:16:02 +04:00
case BufferType::Transient:
2013-05-16 06:42:39 +04:00
{
bgfx::TransientIndexBuffer tib;
bgfx::TransientVertexBuffer tvb;
bgfx::allocTransientIndexBuffer(&tib, bc.textBuffer->getIndexCount() );
bgfx::allocTransientVertexBuffer(&tvb, bc.textBuffer->getVertexCount(), m_vertexDecl);
2017-02-09 06:55:31 +03:00
bx::memCopy(tib.data, bc.textBuffer->getIndexBuffer(), indexSize);
bx::memCopy(tvb.data, bc.textBuffer->getVertexBuffer(), vertexSize);
2017-05-14 21:48:59 +03:00
bgfx::setVertexBuffer(0, &tvb, 0, bc.textBuffer->getVertexCount() );
2014-04-27 10:49:06 +04:00
bgfx::setIndexBuffer(&tib, 0, bc.textBuffer->getIndexCount() );
2013-05-30 09:47:19 +04:00
}
break;
2013-04-23 00:42:11 +04:00
}
bgfx::submit(_id, program, _depth);
2013-04-23 00:42:11 +04:00
}
2013-05-15 17:21:23 +04:00
void TextBufferManager::setStyle(TextBufferHandle _handle, uint32_t _flags)
{
BX_CHECK(bgfx::isValid(_handle), "Invalid handle used");
2013-04-23 00:42:11 +04:00
BufferCache& bc = m_textBuffers[_handle.idx];
2013-05-15 17:21:23 +04:00
bc.textBuffer->setStyle(_flags);
2013-04-23 00:42:11 +04:00
}
2013-05-15 17:21:23 +04:00
void TextBufferManager::setTextColor(TextBufferHandle _handle, uint32_t _rgba)
{
BX_CHECK(bgfx::isValid(_handle), "Invalid handle used");
2013-04-23 00:42:11 +04:00
BufferCache& bc = m_textBuffers[_handle.idx];
2013-05-15 17:21:23 +04:00
bc.textBuffer->setTextColor(_rgba);
2013-04-23 00:42:11 +04:00
}
2013-05-15 17:21:23 +04:00
void TextBufferManager::setBackgroundColor(TextBufferHandle _handle, uint32_t _rgba)
{
BX_CHECK(bgfx::isValid(_handle), "Invalid handle used");
2013-04-23 00:42:11 +04:00
BufferCache& bc = m_textBuffers[_handle.idx];
2013-05-15 17:21:23 +04:00
bc.textBuffer->setBackgroundColor(_rgba);
2013-04-23 00:42:11 +04:00
}
2013-05-15 17:21:23 +04:00
void TextBufferManager::setOverlineColor(TextBufferHandle _handle, uint32_t _rgba)
{
BX_CHECK(bgfx::isValid(_handle), "Invalid handle used");
2013-04-23 00:42:11 +04:00
BufferCache& bc = m_textBuffers[_handle.idx];
2013-05-15 17:21:23 +04:00
bc.textBuffer->setOverlineColor(_rgba);
2013-04-23 00:42:11 +04:00
}
2013-05-15 17:21:23 +04:00
void TextBufferManager::setUnderlineColor(TextBufferHandle _handle, uint32_t _rgba)
2013-04-23 00:42:11 +04:00
{
BX_CHECK(bgfx::isValid(_handle), "Invalid handle used");
2013-04-23 00:42:11 +04:00
BufferCache& bc = m_textBuffers[_handle.idx];
2013-05-15 17:21:23 +04:00
bc.textBuffer->setUnderlineColor(_rgba);
2013-04-23 00:42:11 +04:00
}
2013-05-15 17:21:23 +04:00
void TextBufferManager::setStrikeThroughColor(TextBufferHandle _handle, uint32_t _rgba)
{
BX_CHECK(bgfx::isValid(_handle), "Invalid handle used");
2013-04-23 00:42:11 +04:00
BufferCache& bc = m_textBuffers[_handle.idx];
2013-05-15 17:21:23 +04:00
bc.textBuffer->setStrikeThroughColor(_rgba);
2013-04-23 00:42:11 +04:00
}
2013-05-15 17:21:23 +04:00
void TextBufferManager::setPenPosition(TextBufferHandle _handle, float _x, float _y)
2013-04-23 00:42:11 +04:00
{
BX_CHECK(bgfx::isValid(_handle), "Invalid handle used");
2013-04-23 00:42:11 +04:00
BufferCache& bc = m_textBuffers[_handle.idx];
2013-05-15 17:21:23 +04:00
bc.textBuffer->setPenPosition(_x, _y);
2013-04-23 00:42:11 +04:00
}
void TextBufferManager::appendText(TextBufferHandle _handle, FontHandle _fontHandle, const char* _string, const char* _end)
2013-04-23 00:42:11 +04:00
{
BX_CHECK(bgfx::isValid(_handle), "Invalid handle used");
2013-04-23 00:42:11 +04:00
BufferCache& bc = m_textBuffers[_handle.idx];
bc.textBuffer->appendText(_fontHandle, _string, _end);
2013-04-23 00:42:11 +04:00
}
void TextBufferManager::appendText(TextBufferHandle _handle, FontHandle _fontHandle, const wchar_t* _string, const wchar_t* _end)
2013-04-23 00:42:11 +04:00
{
BX_CHECK(bgfx::isValid(_handle), "Invalid handle used");
2013-04-23 00:42:11 +04:00
BufferCache& bc = m_textBuffers[_handle.idx];
bc.textBuffer->appendText(_fontHandle, _string, _end);
2013-04-23 00:42:11 +04:00
}
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);
}
2013-04-23 00:42:11 +04:00
void TextBufferManager::clearTextBuffer(TextBufferHandle _handle)
{
BX_CHECK(bgfx::isValid(_handle), "Invalid handle used");
2013-04-23 00:42:11 +04:00
BufferCache& bc = m_textBuffers[_handle.idx];
bc.textBuffer->clearTextBuffer();
2013-04-23 00:42:11 +04:00
}
2013-05-09 01:55:54 +04:00
TextRectangle TextBufferManager::getRectangle(TextBufferHandle _handle) const
{
BX_CHECK(bgfx::isValid(_handle), "Invalid handle used");
2013-05-09 01:55:54 +04:00
BufferCache& bc = m_textBuffers[_handle.idx];
return bc.textBuffer->getRectangle();
2013-05-09 01:55:54 +04:00
}