Commit f3a079a2 authored by Jan Möbius's avatar Jan Möbius

Try to fix text node rendering

parent 794a65fb
......@@ -78,7 +78,7 @@ QFont TextNode::qfont_ = QFont("Helvetica", 30);
GLuint TextNode::texture_ = 0;
int TextNode::imageWidth_ = 0;
int TextNode::imageHeight_ = 0;
qreal TextNode::maxFontWidth_ = 0.0;
QFontMetrics TextNode::fontMetric_ = (QFontMetrics(TextNode::qfont_));
bool TextNode::initialised_ = false;
std::map< char, std::pair<unsigned int, unsigned int> > TextNode::charToIndex_ = TextNode::createMap();
QColor TextNode::color_ = QColor(255, 0, 0);
......@@ -110,7 +110,6 @@ TextNode( BaseNode* _parent,
blendSrc_(0),
blendDest_(0),
lastScale_(0.f)
{
updateFont();
vertexDecl_.addElement(GL_FLOAT, 3, ACG::VERTEX_USAGE_POSITION);
......@@ -364,41 +363,70 @@ updateFont() {
if (initialised_)
return;
QFontMetricsF metric(qfont_);
maxFontWidth_ = metric.maxWidth();
if ( maxFontWidth_ == 0 ) {
// since metric.maxWidth() returns 0 for Mac we calculate it here
for (char c = ' '; c < '~'; ++c) {
qreal width = metric.width(c) + std::abs(metric.leftBearing(c)) + std::abs(metric.rightBearing(c));
if (width > maxFontWidth_)
maxFontWidth_ = width;
}
std::cerr << "Warning! Max font width returned 0! manual computation returned " << maxFontWidth_ << std::endl;
}
qreal height = metric.height();
// ensure that the height of the texture is a power of 2
int heightPow2 = nearestPowerOfTwo(height);
// ensure that the width of the texture is a power of 2
int widthPow2 = nearestPowerOfTwo(maxFontWidth_);
// =================================================
// Ugly workaround to get correct font metrics:
// 1. Setup painter with an qimage
// 2. Get metrics from painter
// 3. Destroy everything
// 4. Use the metrics to setup the correct values
// =================================================
// The image we work on. We actually don'T use the size here.
// It's just to get the correct metris.
QImage tmp(128, 128, QImage::Format_ARGB32);
// Setup our painter
QPainter tempPainter;
tempPainter.begin(&tmp);
tempPainter.setRenderHints(QPainter::HighQualityAntialiasing
| QPainter::TextAntialiasing);
tempPainter.setFont(qfont_);
tempPainter.setPen(color_);
// Now get the correct metrics and store them for now and for rendering
fontMetric_ = tempPainter.fontMetrics();
// Stop painting and setup the image correctly from the metrics
tempPainter.end();
/// @TODO Remove, if it works correctly on mac
// if ( maxFontWidth_ == 0 ) {
// // since metric.maxWidth() returns 0 for Mac we calculate it here
// for (char c = ' '; c < '~'; ++c) {
// qreal width = metric.width(c) + std::abs(metric.leftBearing(c)) + std::abs(metric.rightBearing(c));
// if (width > maxFontWidth_)
// maxFontWidth_ = width;
// }
// std::cerr << "Warning! Max font width returned 0! manual computation returned " << maxFontWidth_ << std::endl;
// }
// Maximal height of a character this is used to set the spacing in the texture containing the characters
qreal height = fontMetric_.height();
// ensure that the height and width of the texture is a power of 2 for easier rendering
int heightPow2 = nearestPowerOfTwo(fontMetric_.height());
int widthPow2 = nearestPowerOfTwo(fontMetric_.maxWidth());
// Calculate the final image size used as a texture containing all characters
imageWidth_ = widthPow2 * columns_;
imageHeight_ = heightPow2 * rows_;
// Create an empty image
QImage finalImage(imageWidth_, imageHeight_, QImage::Format_ARGB32);
finalImage.fill(Qt::transparent);
// Setup our painter on the image
QPainter painter;
painter.begin(&finalImage);
painter.setRenderHints(QPainter::HighQualityAntialiasing
| QPainter::TextAntialiasing);
| QPainter::TextAntialiasing);
painter.setFont(qfont_);
painter.setPen(color_);
// characters are drawn aligned to the left into the QImage finalImage
// coords contains a map from a character to its coordinates in the texture.
for (char c = ' '; c < '~'; ++c) {
std::pair<unsigned int, unsigned int> coords = charToIndex_[c];
painter.drawText(coords.first*widthPow2, imageHeight_ - (coords.second+1)*heightPow2, widthPow2, heightPow2, Qt::AlignLeft | Qt::AlignBottom, QString(c));
......@@ -436,44 +464,58 @@ updateVBO() {
vertexBuffer_.clear();
// Fixed values for now. The projection changes the sizes anyway.
qreal pixelHeight = 3.0;
qreal pixelWidth = 3.0;
// generate a quad for each character next to each other
// *--*--*----*-*
// | | | | |
// | | | | |
// *--*--*----*-*
QFontMetricsF metric(qfont_);
qreal avgWidth = metric.averageCharWidth();
const int height = nearestPowerOfTwo(metric.height());
float lastCharRight = 0.0f;
// The height of the rows in the font texture
const int height = nearestPowerOfTwo(fontMetric_.height());
// Left coordinate of current Character
float left = 0.0f;
for (unsigned int i = 0; i < text_.size(); ++i) {
// left and right vertex coordinates
float width = metric.width(text_[i]) / maxFontWidth_;
float left, right;
// ====================================================================
// Calculate the vertex coordinates of the character
// ====================================================================
if (i == 0)
left = 0.0f;
else
left = lastCharRight;
// Compute the width we will cover with this letter. As each letter has a different size in the texture,
// we need to modulate the width of the quad we draw to match the texture aspect ratio.
// Otherwise we get distortion.
right = (left + width);
lastCharRight = right;
// The change is the fraction between the width of the current character to the maximal charater width in the fontset.
float width = pixelWidth * fontMetric_.horizontalAdvance(text_[i]) / fontMetric_.maxWidth();
// left and right texture coordinates
qreal leftBearing = std::abs(metric.leftBearing(text_[i]));
qreal rightBearing = std::abs(metric.rightBearing(text_[i]));
qreal metricWidth = metric.width(text_[i]);
// If we have a space character, we move the the maximal font width
if ( text_[i] == ' ')
width = pixelWidth;
#ifdef WIN32
metricWidth += leftBearing + rightBearing;
#endif
// Compute the current left and right vertex coordinates.
float right = left + width;
const float widthTx = (float) metricWidth / (float) imageWidth_;
// ====================================================================
// Calculate the texture coordinates of the current character
// ====================================================================
// Width and height of one character in texture space (Remember that we calculate texture coordinates here between 0 and 1)
// We don't take the full width of the texture block, as it might contain mostly black.
const float widthTx = (float) fontMetric_.horizontalAdvance(text_[i]) / (float) imageWidth_;
const float heightTx = (float) height/ (float) imageHeight_;
// get the starting position of the character in the texture
// Get the starting position of the character in the texture
// note that the characters are drawn aligned to the bottom left in in the texture
// X Coordinate
const float leftTx = ((float) charToIndex_[text_[i]].first ) / (float) columns_;
const float rightTx = leftTx + widthTx;
// YCoordinate
const float bottomTx = charToIndex_[text_[i]].second / (float) rows_;
const float topTx = bottomTx + heightTx;
......@@ -488,7 +530,7 @@ updateVBO() {
// top left
vertexBuffer_.push_back(left);
vertexBuffer_.push_back(avgWidth*0.15);
vertexBuffer_.push_back(pixelHeight);
vertexBuffer_.push_back(0.0f);
// texture coordinates
......@@ -497,7 +539,7 @@ updateVBO() {
// top right
vertexBuffer_.push_back(right);
vertexBuffer_.push_back(avgWidth*0.15);
vertexBuffer_.push_back(pixelHeight);
vertexBuffer_.push_back(0.0f);
// texture coordinates
......@@ -515,7 +557,7 @@ updateVBO() {
// top right
vertexBuffer_.push_back(right);
vertexBuffer_.push_back(avgWidth*0.15);
vertexBuffer_.push_back(pixelHeight);
vertexBuffer_.push_back(0.0f);
// texture coordinates
......@@ -530,6 +572,9 @@ updateVBO() {
// texture coordinates
vertexBuffer_.push_back(rightTx);
vertexBuffer_.push_back(bottomTx);
// The current right is the new left coordinate (Coordinates not texture space!)
left = right;
}
if (!vbo_)
......
......@@ -65,6 +65,7 @@
#include <QPainter>
#include <QGLWidget>
//== NAMESPACES ===============================================================
namespace ACG {
......@@ -271,8 +272,9 @@ private:
/// height of the generated texture
static int imageHeight_;
/// max width of qfont
static qreal maxFontWidth_;
/// We need to store the font metric to make sure texture font metrics and rendering
/// metrics match.
static QFontMetrics fontMetric_;
/// number of characters that are drawn into the texture
static const int numberOfChars_ = 94;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment