mirror of
https://github.com/scratchfoundation/bgfx.git
synced 2025-02-17 20:31:57 -05:00
add Text metrics helper
This commit is contained in:
parent
60e51ea707
commit
f1042b3f6f
2 changed files with 370 additions and 0 deletions
303
examples/common/font/text_metrics.cpp
Normal file
303
examples/common/font/text_metrics.cpp
Normal file
|
@ -0,0 +1,303 @@
|
|||
/*
|
||||
* Copyright 2013 Jeremie Roy. All rights reserved.
|
||||
* License: http://www.opensource.org/licenses/BSD-2-Clause
|
||||
*/
|
||||
#include "text_metrics.h"
|
||||
#include <wchar.h> // wcslen
|
||||
#include "utf8.h"
|
||||
|
||||
TextMetrics::TextMetrics(FontManager* _fontManager): m_fontManager(_fontManager), m_width(0), m_height(0), m_x(0), m_lineHeight(0), m_lineGap(0)
|
||||
{
|
||||
}
|
||||
|
||||
void TextMetrics::appendText(FontHandle _fontHandle, const char* _string)
|
||||
{
|
||||
GlyphInfo glyph;
|
||||
const FontInfo& font = m_fontManager->getFontInfo(_fontHandle);
|
||||
|
||||
if(font.lineGap > m_lineGap)
|
||||
{
|
||||
m_lineGap = font.lineGap;
|
||||
}
|
||||
|
||||
if( (font.ascender - font.descender) > m_lineHeight)
|
||||
{
|
||||
m_height -= m_lineHeight;
|
||||
m_lineHeight = font.ascender - font.descender;
|
||||
m_height += m_lineHeight;
|
||||
}
|
||||
|
||||
CodePoint codepoint = 0;
|
||||
uint32_t state = 0;
|
||||
|
||||
for (; *_string; ++_string)
|
||||
{
|
||||
if (!utf8_decode(&state, (uint32_t*)&codepoint, *_string) )
|
||||
{
|
||||
if (m_fontManager->getGlyphInfo(_fontHandle, codepoint, glyph) )
|
||||
{
|
||||
if (codepoint == L'\n')
|
||||
{
|
||||
m_height += m_lineGap + font.ascender - font.descender;
|
||||
m_lineGap = font.lineGap;
|
||||
m_lineHeight = font.ascender - font.descender;
|
||||
m_x = 0;
|
||||
break;
|
||||
}
|
||||
//TODO handle kerning
|
||||
m_x += glyph.advance_x;
|
||||
if(m_x > m_width)
|
||||
{
|
||||
m_width = m_x;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BX_CHECK(false, "Glyph not found");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BX_CHECK(state == UTF8_ACCEPT, "The string is not well-formed");
|
||||
}
|
||||
|
||||
void TextMetrics::appendText(FontHandle _fontHandle, const wchar_t* _string)
|
||||
{
|
||||
GlyphInfo glyph;
|
||||
const FontInfo& font = m_fontManager->getFontInfo(_fontHandle);
|
||||
|
||||
if(font.lineGap > m_lineGap)
|
||||
{
|
||||
m_lineGap = font.lineGap;
|
||||
}
|
||||
|
||||
if( (font.ascender - font.descender) > m_lineHeight)
|
||||
{
|
||||
m_height -= m_lineHeight;
|
||||
m_lineHeight = font.ascender - font.descender;
|
||||
m_height += m_lineHeight;
|
||||
}
|
||||
|
||||
for (uint32_t ii = 0, end = wcslen(_string); ii < end; ++ii)
|
||||
{
|
||||
uint32_t codepoint = _string[ii];
|
||||
if (m_fontManager->getGlyphInfo(_fontHandle, codepoint, glyph) )
|
||||
{
|
||||
if (codepoint == L'\n')
|
||||
{
|
||||
m_height += m_lineGap + font.ascender - font.descender;
|
||||
m_lineGap = font.lineGap;
|
||||
m_lineHeight = font.ascender - font.descender;
|
||||
m_x = 0;
|
||||
break;
|
||||
}
|
||||
//TODO handle kerning
|
||||
m_x += glyph.advance_x;
|
||||
if(m_x > m_width)
|
||||
{
|
||||
m_width = m_x;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BX_CHECK(false, "Glyph not found");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextLineMetrics::TextLineMetrics(FontManager* _fontManager, FontHandle _fontHandle )
|
||||
{
|
||||
const FontInfo& font = _fontManager->getFontInfo(_fontHandle);
|
||||
m_lineHeight = font.ascender - font.descender + font.lineGap;
|
||||
}
|
||||
|
||||
uint32_t TextLineMetrics::getLineCount(const char* _string) const
|
||||
{
|
||||
CodePoint codepoint = 0;
|
||||
uint32_t state = 0;
|
||||
uint32_t lineCount = 1;
|
||||
for (; *_string; ++_string)
|
||||
{
|
||||
if(utf8_decode(&state, (uint32_t*)&codepoint, *_string) == UTF8_ACCEPT)
|
||||
{
|
||||
if(codepoint == L'\n')
|
||||
{
|
||||
++lineCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
BX_CHECK(state == UTF8_ACCEPT, "The string is not well-formed");
|
||||
return lineCount;
|
||||
}
|
||||
|
||||
uint32_t TextLineMetrics::getLineCount(const wchar_t* _string) const
|
||||
{
|
||||
uint32_t lineCount = 1;
|
||||
for ( ;*_string != L'\0'; ++_string)
|
||||
{
|
||||
if(*_string == L'\n')
|
||||
{
|
||||
++lineCount;
|
||||
}
|
||||
}
|
||||
return lineCount;
|
||||
}
|
||||
|
||||
|
||||
void TextLineMetrics::getSubText(const char* _string, uint32_t _firstLine, uint32_t _lastLine, const char*& _begin, const char*& _end)
|
||||
{
|
||||
CodePoint codepoint = 0;
|
||||
uint32_t state = 0;
|
||||
// y is bottom of a text line
|
||||
uint32_t currentLine = 0;
|
||||
while(*_string && (currentLine < _firstLine))
|
||||
{
|
||||
for (; *_string; ++_string)
|
||||
{
|
||||
if(utf8_decode(&state, (uint32_t*)&codepoint, *_string) == UTF8_ACCEPT)
|
||||
{
|
||||
if(codepoint == L'\n')
|
||||
{
|
||||
++currentLine;
|
||||
++_string;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BX_CHECK(state == UTF8_ACCEPT, "The string is not well-formed");
|
||||
_begin = _string;
|
||||
|
||||
while((*_string) && (currentLine < _lastLine) )
|
||||
{
|
||||
for (; *_string; ++_string)
|
||||
{
|
||||
if(utf8_decode(&state, (uint32_t*)&codepoint, *_string) == UTF8_ACCEPT)
|
||||
{
|
||||
if(codepoint == L'\n')
|
||||
{
|
||||
++currentLine;
|
||||
++_string;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BX_CHECK(state == UTF8_ACCEPT, "The string is not well-formed");
|
||||
_end = _string;
|
||||
}
|
||||
|
||||
void TextLineMetrics::getSubText(const wchar_t* _string, uint32_t _firstLine, uint32_t _lastLine, const wchar_t*& _begin, const wchar_t*& _end)
|
||||
{
|
||||
uint32_t currentLine = 0;
|
||||
while((*_string != L'\0') && (currentLine < _firstLine))
|
||||
{
|
||||
for ( ;*_string != L'\0'; ++_string)
|
||||
{
|
||||
if(*_string == L'\n')
|
||||
{
|
||||
++currentLine;
|
||||
++_string;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_begin = _string;
|
||||
|
||||
while((*_string != L'\0') && (currentLine < _lastLine) )
|
||||
{
|
||||
for ( ;*_string != L'\0'; ++_string)
|
||||
{
|
||||
if(*_string == L'\n')
|
||||
{
|
||||
++currentLine;
|
||||
++_string;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_end = _string;
|
||||
}
|
||||
|
||||
void TextLineMetrics::getVisibleText(const char* _string, float _top, float _bottom, const char*& _begin, const char*& _end)
|
||||
{
|
||||
CodePoint codepoint = 0;
|
||||
uint32_t state = 0;
|
||||
// y is bottom of a text line
|
||||
float y = m_lineHeight;
|
||||
while(*_string && (y < _top))
|
||||
{
|
||||
for (; *_string; ++_string)
|
||||
{
|
||||
if(utf8_decode(&state, (uint32_t*)&codepoint, *_string) == UTF8_ACCEPT)
|
||||
{
|
||||
if(codepoint == L'\n')
|
||||
{
|
||||
y += m_lineHeight;
|
||||
++_string;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BX_CHECK(state == UTF8_ACCEPT, "The string is not well-formed");
|
||||
_begin = _string;
|
||||
|
||||
// y is now top of a text line
|
||||
y -= m_lineHeight;
|
||||
while((*_string) && (y < _bottom) )
|
||||
{
|
||||
for (; *_string; ++_string)
|
||||
{
|
||||
if(utf8_decode(&state, (uint32_t*)&codepoint, *_string) == UTF8_ACCEPT)
|
||||
{
|
||||
if(codepoint == L'\n')
|
||||
{
|
||||
y += m_lineHeight;
|
||||
++_string;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BX_CHECK(state == UTF8_ACCEPT, "The string is not well-formed");
|
||||
_end = _string;
|
||||
}
|
||||
|
||||
void TextLineMetrics::getVisibleText(const wchar_t* _string, float _top, float _bottom, const wchar_t*& _begin, const wchar_t*& _end)
|
||||
{
|
||||
// y is bottom of a text line
|
||||
float y = m_lineHeight;
|
||||
|
||||
const wchar_t* _textEnd = _string + wcslen(_string);
|
||||
|
||||
while(y < _top)
|
||||
{
|
||||
for (const wchar_t* _current = _string; _current < _textEnd; ++_current)
|
||||
{
|
||||
if(*_current == L'\n')
|
||||
{
|
||||
y += m_lineHeight;
|
||||
++_string;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_begin = _string;
|
||||
|
||||
// y is now top of a text line
|
||||
y -= m_lineHeight;
|
||||
while(y < _bottom )
|
||||
{
|
||||
for (const wchar_t* _current = _string; _current < _textEnd; ++_current)
|
||||
{
|
||||
if(*_current == L'\n')
|
||||
{
|
||||
y += m_lineHeight;
|
||||
++_string;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_end = _string;
|
||||
}
|
67
examples/common/font/text_metrics.h
Normal file
67
examples/common/font/text_metrics.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright 2013 Jeremie Roy. All rights reserved.
|
||||
* License: http://www.opensource.org/licenses/BSD-2-Clause
|
||||
*/
|
||||
|
||||
#ifndef __TEXT_METRICS_H__
|
||||
#define __TEXT_METRICS_H__
|
||||
|
||||
#include "font_manager.h"
|
||||
|
||||
class TextMetrics
|
||||
{
|
||||
public:
|
||||
TextMetrics(FontManager* _fontManager);
|
||||
|
||||
/// Append an ASCII/utf-8 string to the metrics helper
|
||||
void appendText(FontHandle _fontHandle, const char* _string);
|
||||
|
||||
/// Append a wide char string to the metrics helper
|
||||
void appendText(FontHandle _fontHandle, const wchar_t* _string);
|
||||
|
||||
/// return the width of the measured text
|
||||
float getWidth() const { return m_width; }
|
||||
|
||||
/// return the height of the measured text
|
||||
float getHeight() const { return m_height; }
|
||||
|
||||
private:
|
||||
FontManager* m_fontManager;
|
||||
float m_width;
|
||||
float m_height;
|
||||
float m_x;
|
||||
float m_lineHeight;
|
||||
float m_lineGap;
|
||||
};
|
||||
|
||||
/// Compute text crop area for text using a single font
|
||||
class TextLineMetrics
|
||||
{
|
||||
public:
|
||||
TextLineMetrics(FontManager* _fontManager, FontHandle _fontHandle);
|
||||
|
||||
/// Return the height of a line of text using the given font
|
||||
float getLineHeight() const { return m_lineHeight; }
|
||||
|
||||
/// Return the number of text line in the given text
|
||||
uint32_t getLineCount(const char* _string) const;
|
||||
/// Return the number of text line in the given text
|
||||
uint32_t getLineCount(const wchar_t* _string) const;
|
||||
|
||||
/// Return the first and last character visible in the [_firstLine, _lastLine[ range
|
||||
void getSubText(const char* _string, uint32_t _firstLine, uint32_t _lastLine, const char*& _begin, const char*& _end);
|
||||
/// Return the first and last character visible in the [_firstLine, _lastLine[ range
|
||||
void getSubText(const wchar_t* _string, uint32_t _firstLine, uint32_t _lastLine, const wchar_t*& _begin, const wchar_t*& _end);
|
||||
|
||||
/// Return the first and last character visible in the [_top, _bottom] range,
|
||||
void getVisibleText(const char* _string, float _top, float _bottom, const char*& _begin, const char*& _end);
|
||||
/// Return the first and last character visible in the [_top, _bottom] range,
|
||||
void getVisibleText(const wchar_t* _string, float _top, float _bottom, const wchar_t*& _begin, const wchar_t*& _end);
|
||||
|
||||
private:
|
||||
FontManager* m_fontManager;
|
||||
float m_lineHeight;
|
||||
};
|
||||
|
||||
|
||||
#endif // __TEXT_METRICS_H__
|
Loading…
Reference in a new issue