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_PLANE2, 0.0f, -1.0f, 0.0f, clipMinimum.y + clipDimensions.y);
enableClipPlane(GL_CLIP_PLANE3, 0.0f, 1.0f, 0.0f, -clipMinimum.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() }; glm::vec4 textColor = { _color.red / MAX_COLOR, _color.green / MAX_COLOR, _color.blue / MAX_COLOR, getAlpha() };
QStringList lines = _text.split("\n"); textRenderer->drawString(0, 0, _text, textColor);
int lineOffset = maxHeight;
foreach(QString thisLine, lines) {
textRenderer->draw(0, lineOffset, qPrintable(thisLine), textColor);
lineOffset += maxHeight;
}
glDisable(GL_CLIP_PLANE0); glDisable(GL_CLIP_PLANE0);
glDisable(GL_CLIP_PLANE1); glDisable(GL_CLIP_PLANE1);

View file

@ -92,17 +92,7 @@ void TextOverlay::render(RenderArgs* args) {
float alpha = getAlpha(); float alpha = getAlpha();
glm::vec4 textColor = {_color.red / MAX_COLOR, _color.green / MAX_COLOR, _color.blue / MAX_COLOR, alpha }; glm::vec4 textColor = {_color.red / MAX_COLOR, _color.green / MAX_COLOR, _color.blue / MAX_COLOR, alpha };
QStringList lines = _text.split("\n"); textRenderer->draw(x, y, _text, textColor);
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;
}
} }
void TextOverlay::setProperties(const QScriptValue& properties) { 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 #ifndef ROBOTO_REGULAR_SDFF_H
#define ROBOTO_REGULAR_SDFF_H #define ROBOTO_REGULAR_SDFF_H
// http://www.dafont.com/roboto.font
static const unsigned char SDFF_ROBOTO[] = { static const unsigned char SDFF_ROBOTO[] = {
0x53, 0x44, 0x46, 0x46, 0x02, 0x00, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x6f, 0x53, 0x44, 0x46, 0x46, 0x02, 0x00, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x6f,
0x20, 0x52, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x00, 0x00, 0x80, 0x5d, 0x20, 0x52, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x00, 0x00, 0x80, 0x5d,

View file

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

View file

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

View file

@ -139,8 +139,8 @@ void QTestWindow::makeCurrent() {
m_context->makeCurrent(this); m_context->makeCurrent(this);
} }
static const wchar_t * EXAMPLE_TEXT = L"Hello 1.0\nline 2\ndescent ggg\nascent ÁÁÁ"; static const wchar_t * EXAMPLE_TEXT = L"Áy Hello 1.0\nline 2\nÁy";
static const glm::uvec2 QUAD_OFFSET(10, 20); static const glm::uvec2 QUAD_OFFSET(10, 10);
static const glm::vec3 COLORS[4] = { static const glm::vec3 COLORS[4] = {
{ 1, 1, 1 }, { 1, 1, 1 },
{ 0.5, 1.0, 0.5 }, { 0.5, 1.0, 0.5 },
@ -183,7 +183,18 @@ void QTestWindow::draw() {
} }
QString str = QString::fromWCharArray(EXAMPLE_TEXT); QString str = QString::fromWCharArray(EXAMPLE_TEXT);
for (int i = 0; i < 4; ++i) { 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); m_context->swapBuffers(this);
} }