Working on the text renderer

This commit is contained in:
Brad Davis 2015-02-03 01:49:06 -08:00
parent 5d9aee16cb
commit 6cfb51283e
9 changed files with 31893 additions and 11040 deletions

View file

@ -124,13 +124,8 @@ void Text3DOverlay::render(RenderArgs* args) {
enableClipPlane(GL_CLIP_PLANE2, 0.0f, -1.0f, 0.0f, clipMinimum.y + clipDimensions.y);
enableClipPlane(GL_CLIP_PLANE3, 0.0f, 1.0f, 0.0f, -clipMinimum.y);
glm::vec4 textColor = {_color.red / MAX_COLOR, _color.green / MAX_COLOR, _color.blue / MAX_COLOR, getAlpha() };
QStringList lines = _text.split("\n");
int lineOffset = maxHeight;
foreach(QString thisLine, lines) {
textRenderer->draw(0, lineOffset, qPrintable(thisLine), textColor);
lineOffset += maxHeight;
}
glm::vec4 textColor = { _color.red / MAX_COLOR, _color.green / MAX_COLOR, _color.blue / MAX_COLOR, getAlpha() };
textRenderer->drawString(0, 0, _text, textColor);
glDisable(GL_CLIP_PLANE0);
glDisable(GL_CLIP_PLANE1);

View file

@ -92,17 +92,7 @@ void TextOverlay::render(RenderArgs* args) {
float alpha = getAlpha();
glm::vec4 textColor = {_color.red / MAX_COLOR, _color.green / MAX_COLOR, _color.blue / MAX_COLOR, alpha };
QStringList lines = _text.split("\n");
int lineOffset = 0;
foreach(QString thisLine, lines) {
if (lineOffset == 0) {
lineOffset = textRenderer->calculateHeight(qPrintable(thisLine));
}
lineOffset += textRenderer->draw(x, y + lineOffset, qPrintable(thisLine), textColor);
const int lineGap = 2;
lineOffset += lineGap;
}
textRenderer->draw(x, y, _text, textColor);
}
void TextOverlay::setProperties(const QScriptValue& properties) {

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,9 @@
#ifndef ROBOTO_REGULAR_SDFF_H
#define ROBOTO_REGULAR_SDFF_H
// http://www.dafont.com/roboto.font
static const unsigned char SDFF_ROBOTO[] = {
0x53, 0x44, 0x46, 0x46, 0x02, 0x00, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x6f,
0x20, 0x52, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x00, 0x00, 0x80, 0x5d,

View file

@ -1,6 +1,8 @@
#ifndef TIMELESS_REGULAR_SDFF_H
#define TIMELESS_REGULAR_SDFF_H
// http://www.dafont.com/timeless.font
static const unsigned char SDFF_TIMELESS[] = {
0x53, 0x44, 0x46, 0x46, 0x02, 0x00, 0x54, 0x69, 0x6d, 0x65, 0x6c, 0x65,
0x73, 0x73, 0x20, 0x52, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x00, 0x7d,

View file

@ -33,8 +33,9 @@
#include "gpu/Stream.h"
#include "FontInconsolataMedium.h"
#include "FontRoboto.h"
#include "FontJackInput.h"
#include "FontTimeless.h"
#include "FontCourierPrime.h"
namespace Shaders {
@ -95,8 +96,12 @@ void main() {
// retrieve signed distance
float sdf = texture(Font, vTexCoord).r;
if (Outline && (sdf > 0.6)) {
sdf = 1.0 - sdf;
if (Outline) {
if (sdf > 0.8) {
sdf = 1.0 - sdf;
} else {
sdf += 0.2;
}
}
// perform adaptive anti-aliasing of the edges
// The larger we're rendering, the less anti-aliasing we need
@ -187,13 +192,15 @@ public:
// Initialize the OpenGL structures
void setupGL();
glm::vec2 computeExtent(const QString & str) const;
glm::vec2 drawString(
float x, float y,
const QString & str,
const glm::vec4& color,
float scale,
TextRenderer::EffectType effectType,
float maxWidth);
float maxWidth) const;
};
@ -231,7 +238,7 @@ void Font::read(QIODevice & in) {
readStream(in, _descent);
readStream(in, _spaceWidth);
_fontSize = _ascent + _descent;
_rowHeight = _fontSize + _descent / 2;
_rowHeight = _fontSize + _descent;
// Read character count
uint16_t count;
@ -360,88 +367,93 @@ void Font::setupGL() {
_vao->release();
}
glm::vec2 Font::computeExtent(const QString & str) const {
glm::vec2 advance(0, _rowHeight - _descent);
float maxX = 0;
foreach(QString token, str.split(" ")) {
foreach(QChar c, token) {
if (QChar('\n') == c) {
maxX = std::max(advance.x, maxX);
advance.x = 0;
advance.y += _rowHeight;
continue;
}
if (!_glyphs.contains(c)) {
c = QChar('?');
}
const Glyph & m = _glyphs[c];
advance.x += m.d;
}
advance.x += _spaceWidth;
}
return glm::vec2(maxX, advance.y);
}
glm::vec2 Font::drawString(
float x, float y,
const QString & str,
const glm::vec4& color,
float scale,
TextRenderer::EffectType effectType,
float maxWidth) {
// This is a hand made scale intended to match the previous scale of text in the application
//float scale = 0.25f; // DTP_TO_METERS;
//if (fontSize > 0.0) {
// scale *= fontSize / _fontSize;
//}
//bool wrap = false; // (maxWidth == maxWidth);
//if (wrap) {
// maxWidth /= scale;
//}
float maxWidth) const {
// Stores how far we've moved from the start of the string, in DTP units
static const float SPACE_ADVANCE = getGlyph('J').d;
glm::vec2 advance(0, -_ascent);
MatrixStack::withGlMatrices([&] {
// Fetch the matrices out of GL
_program->bind();
_program->setUniformValue("Color", color.r, color.g, color.b, color.a);
_program->setUniformValue("Projection", fromGlm(MatrixStack::projection().top()));
if (effectType == TextRenderer::OUTLINE_EFFECT) {
_program->setUniformValue("Outline", true);
}
_texture->bind();
_vao->bind();
glm::vec2 advance(0, -_rowHeight - _descent);
MatrixStack & mv = MatrixStack::modelview();
MatrixStack & pr = MatrixStack::projection();
// scale the modelview into font units
mv.translate(glm::vec2(x, y)).scale(glm::vec3(scale, -scale, scale));
mv.translate(glm::vec3(0, _ascent, 0));
foreach(QString token, str.split(" ")) {
// float tokenWidth = measureWidth(token, fontSize);
// if (wrap && 0 != advance.x && (advance.x + tokenWidth) > maxWidth) {
_program->bind();
_program->setUniformValue("Color", color.r, color.g, color.b, color.a);
_program->setUniformValue("Projection", fromGlm(MatrixStack::projection().top()));
if (effectType == TextRenderer::OUTLINE_EFFECT) {
_program->setUniformValue("Outline", true);
}
_texture->bind();
_vao->bind();
MatrixStack & mv = MatrixStack::modelview();
// scale the modelview into font units
mv.translate(glm::vec3(0, _ascent, 0));
foreach(QString token, str.split(" ")) {
// float tokenWidth = measureWidth(token, fontSize);
// if (wrap && 0 != advance.x && (advance.x + tokenWidth) > maxWidth) {
// advance.x = 0;
// advance.y -= _rowHeight;
// }
foreach(QChar c, token) {
if (QChar('\n') == c) {
advance.x = 0;
advance.y -= _rowHeight;
continue;
}
if (!_glyphs.contains(c)) {
c = QChar('?');
}
// get metrics for this character to speed up measurements
const Glyph & m = _glyphs[c];
//if (wrap && ((advance.x + m.d) > maxWidth)) {
// advance.x = 0;
// advance.y -= _rowHeight;
// }
//}
foreach(QChar c, token) {
if (QChar('\n') == c) {
advance.x = 0;
advance.y -= _rowHeight;
continue;
}
if (!_glyphs.contains(c)) {
c = QChar('?');
}
// get metrics for this character to speed up measurements
const Glyph & m = _glyphs[c];
//if (wrap && ((advance.x + m.d) > maxWidth)) {
// advance.x = 0;
// advance.y -= _rowHeight;
//}
// We create an offset vec2 to hold the local offset of this character
// This includes compensating for the inverted Y axis of the font
// coordinates
glm::vec2 offset(advance);
offset.y -= m.size.y;
// Bind the new position
mv.withPush([&] {
mv.translate(offset);
_program->setUniformValue("ModelView", fromGlm(mv.top()));
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, (void*)(m.indexOffset));
});
advance.x += m.d;//+ m.offset.x;// font->getAdvance(m, mFontSize);
}
advance.x += SPACE_ADVANCE;
// We create an offset vec2 to hold the local offset of this character
// This includes compensating for the inverted Y axis of the font
// coordinates
glm::vec2 offset(advance);
offset.y -= m.size.y;
// Bind the new position
mv.withPush([&] {
mv.translate(offset);
_program->setUniformValue("ModelView", fromGlm(mv.top()));
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, (void*)(m.indexOffset));
});
advance.x += m.d;//+ m.offset.x;// font->getAdvance(m, mFontSize);
}
advance.x += _spaceWidth;
}
_vao->release();
_program->release();
});
_vao->release();
_program->release();
return advance;
}
@ -469,7 +481,7 @@ static QHash<QString, Font*> LOADED_FONTS;
Font * loadFont(const QString & family) {
if (!LOADED_FONTS.contains(family)) {
if (family == MONO_FONT_FAMILY) {
LOADED_FONTS[family] = loadFont(SDFF_JACKINPUT);
LOADED_FONTS[family] = loadFont(SDFF_COURIER_PRIME);
} else if (family == INCONSOLATA_FONT_FAMILY) {
LOADED_FONTS[family] = loadFont(SDFF_INCONSOLATA_MEDIUM);
} else if (family == SANS_FONT_FAMILY) {
@ -497,44 +509,12 @@ TextRenderer::TextRenderer(const Properties& properties) :
TextRenderer::~TextRenderer() {
}
int TextRenderer::computeWidth(const QChar & ch) const {
//return getGlyph(ch).width();
return 0;
glm::vec2 TextRenderer::computeExtent(const QString & str) const {
float scale = (_pointSize / DEFAULT_POINT_SIZE) * 0.25f;
return _font->computeExtent(str) * scale;
}
int TextRenderer::computeWidth(const QString & str) const {
int width = 0;
foreach(QChar c, str) {
width += computeWidth(c);
}
return width;
}
int TextRenderer::computeWidth(const char * str) const {
int width = 0;
while (*str) {
width += computeWidth(*str++);
}
return width;
}
int TextRenderer::computeWidth(char ch) const {
return computeWidth(QChar(ch));
}
int TextRenderer::calculateHeight(const char* str) const {
int maxHeight = 0;
//for (const char* ch = str; *ch != 0; ch++) {
// const Glyph& glyph = getGlyph(*ch);
// if (glyph.bounds().height() > maxHeight) {
// maxHeight = glyph.bounds().height();
// }
//}
return maxHeight;
}
float TextRenderer::drawString(
float TextRenderer::draw(
float x, float y,
const QString & str,
const glm::vec4& color,
@ -543,6 +523,15 @@ float TextRenderer::drawString(
if (actualColor.r < 0) {
actualColor = glm::vec4(_color.redF(), _color.greenF(), _color.blueF(), 1.0);
}
return _font->drawString(x, y, str, actualColor, (_pointSize / DEFAULT_POINT_SIZE) * 0.25f, _effectType, maxWidth).x;
float scale = (_pointSize / DEFAULT_POINT_SIZE) * 0.25f;
glm::vec2 result;
MatrixStack::withGlMatrices([&] {
MatrixStack & mv = MatrixStack::modelview();
// scale the modelview into font units
mv.translate(glm::vec2(x, y)).scale(glm::vec3(scale, -scale, scale));
result = _font->drawString(x, y, str, actualColor, _effectType, maxWidth);
});
return result.x;
}

View file

@ -65,25 +65,20 @@ public:
~TextRenderer();
glm::vec2 computeExtent(const QString & str) const;
// returns the height of the tallest character
int calculateHeight(const char * str) const;
int calculateHeight(const QString & str) const;
//int calculateHeight(const char * str) const;
//int calculateHeight(const QString & str) const;
int computeWidth(char ch) const;
int computeWidth(const QChar & ch) const;
//int computeWidth(char ch) const;
//int computeWidth(const QChar & ch) const;
int computeWidth(const QString & str) const;
int computeWidth(const char * str) const;
//int computeWidth(const QString & str) const;
//int computeWidth(const char * str) const;
// also returns the height of the tallest character
inline int draw(int x, int y, const char* str,
const glm::vec4& color = glm::vec4(-1),
float maxWidth = -1
) {
return drawString(x, y, QString(str), color, maxWidth);
}
float drawString(
float draw(
float x, float y,
const QString & str,
const glm::vec4& color = glm::vec4(-1),

View file

@ -139,8 +139,8 @@ void QTestWindow::makeCurrent() {
m_context->makeCurrent(this);
}
static const wchar_t * EXAMPLE_TEXT = L"Hello 1.0\nline 2\ndescent ggg\nascent ÁÁÁ";
static const glm::uvec2 QUAD_OFFSET(10, 20);
static const wchar_t * EXAMPLE_TEXT = L"Áy Hello 1.0\nline 2\nÁy";
static const glm::uvec2 QUAD_OFFSET(10, 10);
static const glm::vec3 COLORS[4] = {
{ 1, 1, 1 },
{ 0.5, 1.0, 0.5 },
@ -183,7 +183,18 @@ void QTestWindow::draw() {
}
QString str = QString::fromWCharArray(EXAMPLE_TEXT);
for (int i = 0; i < 4; ++i) {
_textRenderer[i]->drawString(offsets[i].x, offsets[i].y, str, glm::vec4(COLORS[i], 1.0f));
glm::vec2 bounds = _textRenderer[i]->computeExtent(str);
glPushMatrix(); {
glTranslatef(offsets[i].x, offsets[i].y, 0);
glColor3f(0, 0, 0);
glBegin(GL_QUADS); {
glVertex2f(0, 0);
glVertex2f(0, bounds.y);
glVertex2f(bounds.x, bounds.y);
glVertex2f(bounds.x, 0);
} glEnd();
} glPopMatrix();
_textRenderer[i]->draw(offsets[i].x, offsets[i].y, str, glm::vec4(COLORS[i], 1.0f));
}
m_context->swapBuffers(this);
}