mirror of
https://github.com/overte-org/overte.git
synced 2025-04-25 22:36:39 +02:00
merge
This commit is contained in:
commit
1ac8b5737c
3 changed files with 338 additions and 14 deletions
190
SvoViewer/src/TextRenderer.cpp
Normal file
190
SvoViewer/src/TextRenderer.cpp
Normal file
|
@ -0,0 +1,190 @@
|
||||||
|
//
|
||||||
|
// TextRenderer.cpp
|
||||||
|
// interface
|
||||||
|
//
|
||||||
|
// Created by Andrzej Kapolka on 4/24/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
|
||||||
|
#include <QFont>
|
||||||
|
#include <QPaintEngine>
|
||||||
|
#include <QtDebug>
|
||||||
|
#include <QString>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
#include "SvoViewerConfig.h"
|
||||||
|
#include "TextRenderer.h"
|
||||||
|
|
||||||
|
// the width/height of the cached glyph textures
|
||||||
|
const int IMAGE_SIZE = 256;
|
||||||
|
|
||||||
|
Glyph::Glyph(int textureID, const QPoint& location, const QRect& bounds, int width) :
|
||||||
|
_textureID(textureID), _location(location), _bounds(bounds), _width(width) {
|
||||||
|
}
|
||||||
|
|
||||||
|
TextRenderer::TextRenderer(const char* family, int pointSize, int weight,
|
||||||
|
bool italic, EffectType effectType, int effectThickness)
|
||||||
|
: _font(family, pointSize, weight, italic), _metrics(_font), _effectType(effectType),
|
||||||
|
_effectThickness(effectThickness), _x(IMAGE_SIZE), _y(IMAGE_SIZE), _rowHeight(0) {
|
||||||
|
_font.setKerning(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextRenderer::~TextRenderer() {
|
||||||
|
glDeleteTextures(_allTextureIDs.size(), _allTextureIDs.constData());
|
||||||
|
}
|
||||||
|
|
||||||
|
int TextRenderer::calculateHeight(const char* str) {
|
||||||
|
int maxHeight = 0;
|
||||||
|
for (const char* ch = str; *ch != 0; ch++) {
|
||||||
|
const Glyph& glyph = getGlyph(*ch);
|
||||||
|
if (glyph.textureID() == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (glyph.bounds().height() > maxHeight) {
|
||||||
|
maxHeight = glyph.bounds().height();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return maxHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
int TextRenderer::draw(int x, int y, const char* str) {
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
|
||||||
|
int maxHeight = 0;
|
||||||
|
for (const char* ch = str; *ch != 0; ch++) {
|
||||||
|
const Glyph& glyph = getGlyph(*ch);
|
||||||
|
if (glyph.textureID() == 0) {
|
||||||
|
x += glyph.width();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (glyph.bounds().height() > maxHeight) {
|
||||||
|
maxHeight = glyph.bounds().height();
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, glyph.textureID());
|
||||||
|
|
||||||
|
int left = x + glyph.bounds().x();
|
||||||
|
int right = x + glyph.bounds().x() + glyph.bounds().width();
|
||||||
|
int bottom = y + glyph.bounds().y();
|
||||||
|
int top = y + glyph.bounds().y() + glyph.bounds().height();
|
||||||
|
|
||||||
|
float scale = 1.0 / IMAGE_SIZE;
|
||||||
|
float ls = glyph.location().x() * scale;
|
||||||
|
float rs = (glyph.location().x() + glyph.bounds().width()) * scale;
|
||||||
|
float bt = glyph.location().y() * scale;
|
||||||
|
float tt = (glyph.location().y() + glyph.bounds().height()) * scale;
|
||||||
|
|
||||||
|
glBegin(GL_QUADS);
|
||||||
|
glTexCoord2f(ls, bt);
|
||||||
|
glVertex2f(left, bottom);
|
||||||
|
glTexCoord2f(rs, bt);
|
||||||
|
glVertex2f(right, bottom);
|
||||||
|
glTexCoord2f(rs, tt);
|
||||||
|
glVertex2f(right, top);
|
||||||
|
glTexCoord2f(ls, tt);
|
||||||
|
glVertex2f(left, top);
|
||||||
|
glEnd();
|
||||||
|
|
||||||
|
x += glyph.width();
|
||||||
|
}
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
glDisable(GL_TEXTURE_2D);
|
||||||
|
|
||||||
|
return maxHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
int TextRenderer::computeWidth(char ch)
|
||||||
|
{
|
||||||
|
return getGlyph(ch).width();
|
||||||
|
}
|
||||||
|
|
||||||
|
int TextRenderer::computeWidth(const char* str)
|
||||||
|
{
|
||||||
|
int width = 0;
|
||||||
|
for (const char* ch = str; *ch != 0; ch++) {
|
||||||
|
width += computeWidth(*ch);
|
||||||
|
}
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Glyph& TextRenderer::getGlyph(char c) {
|
||||||
|
Glyph& glyph = _glyphs[c];
|
||||||
|
if (glyph.isValid()) {
|
||||||
|
return glyph;
|
||||||
|
}
|
||||||
|
// we use 'J' as a representative size for the solid block character
|
||||||
|
QChar ch = (c == SOLID_BLOCK_CHAR) ? QChar('J') : QChar(c);
|
||||||
|
QRect bounds = _metrics.boundingRect(ch);
|
||||||
|
if (bounds.isEmpty()) {
|
||||||
|
glyph = Glyph(0, QPoint(), QRect(), _metrics.width(ch));
|
||||||
|
return glyph;
|
||||||
|
}
|
||||||
|
// grow the bounds to account for effect, if any
|
||||||
|
if (_effectType == SHADOW_EFFECT) {
|
||||||
|
bounds.adjust(-_effectThickness, 0, 0, _effectThickness);
|
||||||
|
|
||||||
|
} else if (_effectType == OUTLINE_EFFECT) {
|
||||||
|
bounds.adjust(-_effectThickness, -_effectThickness, _effectThickness, _effectThickness);
|
||||||
|
}
|
||||||
|
|
||||||
|
// grow the bounds to account for antialiasing
|
||||||
|
bounds.adjust(-1, -1, 1, 1);
|
||||||
|
|
||||||
|
if (_x + bounds.width() > IMAGE_SIZE) {
|
||||||
|
// we can't fit it on the current row; move to next
|
||||||
|
_y += _rowHeight;
|
||||||
|
_x = _rowHeight = 0;
|
||||||
|
}
|
||||||
|
if (_y + bounds.height() > IMAGE_SIZE) {
|
||||||
|
// can't fit it on current texture; make a new one
|
||||||
|
glGenTextures(1, &_currentTextureID);
|
||||||
|
_x = _y = _rowHeight = 0;
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, _currentTextureID);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, IMAGE_SIZE, IMAGE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
||||||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
_allTextureIDs.append(_currentTextureID);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
glBindTexture(GL_TEXTURE_2D, _currentTextureID);
|
||||||
|
}
|
||||||
|
// render the glyph into an image and copy it into the texture
|
||||||
|
QImage image(bounds.width(), bounds.height(), QImage::Format_ARGB32);
|
||||||
|
if (c == SOLID_BLOCK_CHAR) {
|
||||||
|
image.fill(QColor(255, 255, 255));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
image.fill(0);
|
||||||
|
QPainter painter(&image);
|
||||||
|
painter.setFont(_font);
|
||||||
|
if (_effectType == SHADOW_EFFECT) {
|
||||||
|
for (int i = 0; i < _effectThickness; i++) {
|
||||||
|
painter.drawText(-bounds.x() - 1 - i, -bounds.y() + 1 + i, ch);
|
||||||
|
}
|
||||||
|
} else if (_effectType == OUTLINE_EFFECT) {
|
||||||
|
QPainterPath path;
|
||||||
|
QFont font = _font;
|
||||||
|
font.setStyleStrategy(QFont::ForceOutline);
|
||||||
|
path.addText(-bounds.x() - 0.5, -bounds.y() + 0.5, font, ch);
|
||||||
|
QPen pen;
|
||||||
|
pen.setWidth(_effectThickness);
|
||||||
|
pen.setJoinStyle(Qt::RoundJoin);
|
||||||
|
pen.setCapStyle(Qt::RoundCap);
|
||||||
|
painter.setPen(pen);
|
||||||
|
painter.setRenderHint(QPainter::Antialiasing);
|
||||||
|
painter.drawPath(path);
|
||||||
|
}
|
||||||
|
painter.setPen(QColor(255, 255, 255));
|
||||||
|
painter.drawText(-bounds.x(), -bounds.y(), ch);
|
||||||
|
}
|
||||||
|
glTexSubImage2D(GL_TEXTURE_2D, 0, _x, _y, bounds.width(), bounds.height(), GL_RGBA, GL_UNSIGNED_BYTE, image.constBits());
|
||||||
|
|
||||||
|
glyph = Glyph(_currentTextureID, QPoint(_x, _y), bounds, _metrics.width(ch));
|
||||||
|
_x += bounds.width();
|
||||||
|
_rowHeight = qMax(_rowHeight, bounds.height());
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
return glyph;
|
||||||
|
}
|
114
SvoViewer/src/TextRenderer.h
Normal file
114
SvoViewer/src/TextRenderer.h
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
//
|
||||||
|
// TextRenderer.h
|
||||||
|
// interface
|
||||||
|
//
|
||||||
|
// Created by Andrzej Kapolka on 4/26/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef __interface__TextRenderer__
|
||||||
|
#define __interface__TextRenderer__
|
||||||
|
|
||||||
|
#include <QFont>
|
||||||
|
#include <QFontMetrics>
|
||||||
|
#include <QHash>
|
||||||
|
#include <QImage>
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
|
#include "SvoViewerConfig.h"
|
||||||
|
|
||||||
|
// a special "character" that renders as a solid block
|
||||||
|
const char SOLID_BLOCK_CHAR = 127;
|
||||||
|
|
||||||
|
// the standard sans serif font family
|
||||||
|
#define SANS_FONT_FAMILY "Helvetica"
|
||||||
|
|
||||||
|
// the standard mono font family
|
||||||
|
#define MONO_FONT_FAMILY "Courier"
|
||||||
|
|
||||||
|
// the Inconsolata font family
|
||||||
|
#define INCONSOLATA_FONT_FAMILY "Inconsolata"
|
||||||
|
|
||||||
|
|
||||||
|
class Glyph;
|
||||||
|
|
||||||
|
class TextRenderer {
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum EffectType { NO_EFFECT, SHADOW_EFFECT, OUTLINE_EFFECT };
|
||||||
|
|
||||||
|
TextRenderer(const char* family, int pointSize = -1, int weight = -1, bool italic = false,
|
||||||
|
EffectType effect = NO_EFFECT, int effectThickness = 1);
|
||||||
|
~TextRenderer();
|
||||||
|
|
||||||
|
const QFontMetrics& metrics() const { return _metrics; }
|
||||||
|
|
||||||
|
// returns the height of the tallest character
|
||||||
|
int calculateHeight(const char* str);
|
||||||
|
|
||||||
|
// also returns the height of the tallest character
|
||||||
|
int draw(int x, int y, const char* str);
|
||||||
|
|
||||||
|
int computeWidth(char ch);
|
||||||
|
int computeWidth(const char* str);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
const Glyph& getGlyph (char c);
|
||||||
|
|
||||||
|
// the font to render
|
||||||
|
QFont _font;
|
||||||
|
|
||||||
|
// the font metrics
|
||||||
|
QFontMetrics _metrics;
|
||||||
|
|
||||||
|
// the type of effect to apply
|
||||||
|
EffectType _effectType;
|
||||||
|
|
||||||
|
// the thickness of the effect
|
||||||
|
int _effectThickness;
|
||||||
|
|
||||||
|
// maps characters to cached glyph info
|
||||||
|
QHash<char, Glyph> _glyphs;
|
||||||
|
|
||||||
|
// the id of the glyph texture to which we're currently writing
|
||||||
|
GLuint _currentTextureID;
|
||||||
|
|
||||||
|
// the position within the current glyph texture
|
||||||
|
int _x, _y;
|
||||||
|
|
||||||
|
// the height of the current row of characters
|
||||||
|
int _rowHeight;
|
||||||
|
|
||||||
|
// the list of all texture ids for which we're responsible
|
||||||
|
QVector<GLuint> _allTextureIDs;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Glyph {
|
||||||
|
public:
|
||||||
|
|
||||||
|
Glyph(int textureID = 0, const QPoint& location = QPoint(), const QRect& bounds = QRect(), int width = 0);
|
||||||
|
|
||||||
|
GLuint textureID() const { return _textureID; }
|
||||||
|
const QPoint& location () const { return _location; }
|
||||||
|
const QRect& bounds() const { return _bounds; }
|
||||||
|
int width () const { return _width; }
|
||||||
|
|
||||||
|
bool isValid() { return _width != 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// the id of the OpenGL texture containing the glyph
|
||||||
|
GLuint _textureID;
|
||||||
|
|
||||||
|
// the location of the character within the texture
|
||||||
|
QPoint _location;
|
||||||
|
|
||||||
|
// the bounds of the character
|
||||||
|
QRect _bounds;
|
||||||
|
|
||||||
|
// the width of the character (distance to next, as opposed to bounds width)
|
||||||
|
int _width;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* defined(__interface__TextRenderer__) */
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include "svoviewer.h"
|
#include "svoviewer.h"
|
||||||
#include "GLCanvas.h"
|
#include "GLCanvas.h"
|
||||||
|
#include "TextRenderer.h"
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <QDesktopWidget>
|
#include <QDesktopWidget>
|
||||||
|
@ -211,7 +212,9 @@ void SvoViewer::init() {
|
||||||
void SvoViewer::initializeGL()
|
void SvoViewer::initializeGL()
|
||||||
{
|
{
|
||||||
int argc = 0;
|
int argc = 0;
|
||||||
|
#ifdef WIN32
|
||||||
glutInit(&argc, 0);
|
glutInit(&argc, 0);
|
||||||
|
#endif
|
||||||
init();
|
init();
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
GLenum err = glewInit();
|
GLenum err = glewInit();
|
||||||
|
@ -324,11 +327,12 @@ void SvoViewer::paintGL()
|
||||||
// Update every x seconds for more stability
|
// Update every x seconds for more stability
|
||||||
quint64 tc = usecTimestampNow();
|
quint64 tc = usecTimestampNow();
|
||||||
quint64 interval = tc - _lastTimeFpsUpdated;
|
quint64 interval = tc - _lastTimeFpsUpdated;
|
||||||
#define FPS_UPDATE_TIME_INTERVAL 2
|
const quint64 USECS_PER_SECOND = 1000 * 1000;
|
||||||
if (interval > 1000 * FPS_UPDATE_TIME_INTERVAL)
|
const int FPS_UPDATE_TIME_INTERVAL = 2;
|
||||||
{
|
if (interval > (USECS_PER_SECOND * FPS_UPDATE_TIME_INTERVAL)) {
|
||||||
int numFrames = _frameCount - _lastTrackedFrameCount;
|
int numFrames = _frameCount - _lastTrackedFrameCount;
|
||||||
_fps = (float)numFrames / (float)(FPS_UPDATE_TIME_INTERVAL);
|
float intervalSeconds = (float)((float)interval/(float)USECS_PER_SECOND);
|
||||||
|
_fps = (float)numFrames / intervalSeconds;
|
||||||
_lastTrackedFrameCount = _frameCount;
|
_lastTrackedFrameCount = _frameCount;
|
||||||
_lastTimeFpsUpdated = tc;
|
_lastTimeFpsUpdated = tc;
|
||||||
}
|
}
|
||||||
|
@ -337,6 +341,27 @@ void SvoViewer::paintGL()
|
||||||
PrintToScreen(10, 30, "Drawing %d of %d (%% %f) total elements", _numElemsDrawn, _totalPossibleElems, ((float)_numElemsDrawn / (float)_totalPossibleElems) * 100.0);
|
PrintToScreen(10, 30, "Drawing %d of %d (%% %f) total elements", _numElemsDrawn, _totalPossibleElems, ((float)_numElemsDrawn / (float)_totalPossibleElems) * 100.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void drawtext(int x, int y, float scale, float rotate, float thick, int mono,
|
||||||
|
char const* string, float r, float g, float b) {
|
||||||
|
//
|
||||||
|
// Draws text on screen as stroked so it can be resized
|
||||||
|
//
|
||||||
|
glPushMatrix();
|
||||||
|
glTranslatef(static_cast<float>(x), static_cast<float>(y), 0.0f);
|
||||||
|
glColor3f(r,g,b);
|
||||||
|
glRotated(rotate,0,0,1);
|
||||||
|
// glLineWidth(thick);
|
||||||
|
glScalef(scale / 0.10, scale / 0.10, 1.0);
|
||||||
|
|
||||||
|
TextRenderer textRenderer(SANS_FONT_FAMILY, 11, 50);
|
||||||
|
textRenderer.draw(0, 0, string);
|
||||||
|
|
||||||
|
//textRenderer(mono)->draw(0, 0, string);
|
||||||
|
|
||||||
|
glPopMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#define TEMP_STRING_BUFFER_MAX 1024
|
#define TEMP_STRING_BUFFER_MAX 1024
|
||||||
#define SHADOW_OFFSET 2
|
#define SHADOW_OFFSET 2
|
||||||
void SvoViewer::PrintToScreen(const int width, const int height, const char* szFormat, ...)
|
void SvoViewer::PrintToScreen(const int width, const int height, const char* szFormat, ...)
|
||||||
|
@ -352,28 +377,23 @@ void SvoViewer::PrintToScreen(const int width, const int height, const char* szF
|
||||||
memset(szUBuff, 0, sizeof(szUBuff));
|
memset(szUBuff, 0, sizeof(szUBuff));
|
||||||
int len = strlen(szBuff);
|
int len = strlen(szBuff);
|
||||||
for (int i = 0; i < len; i++) szUBuff[i] = (unsigned char)szBuff[i];
|
for (int i = 0; i < len; i++) szUBuff[i] = (unsigned char)szBuff[i];
|
||||||
|
qDebug() << szBuff;
|
||||||
|
|
||||||
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
glMatrixMode( GL_PROJECTION );
|
glMatrixMode( GL_PROJECTION );
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
glOrtho(0, _width, 0, _height, 0, 1);
|
gluOrtho2D(0, _width, _height, 0);
|
||||||
|
|
||||||
glDisable(GL_LIGHTING);
|
glDisable(GL_LIGHTING);
|
||||||
glMatrixMode( GL_MODELVIEW );
|
glMatrixMode( GL_MODELVIEW );
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
|
|
||||||
glColor3f(.8f, .8f, .8f); // Matt:: reverse ordering once depth enabled.
|
drawtext(width, height, 0.10f, 0, 1, 2, szBuff, 1,1,1);
|
||||||
glRasterPos2i(width, height);
|
|
||||||
//glutBitmapString(GLUT_BITMAP_HELVETICA_18, szUBuff);
|
|
||||||
|
|
||||||
glColor3f(0.0f, 0.0f, 0.0f);
|
|
||||||
glRasterPos2i(width - SHADOW_OFFSET, height - SHADOW_OFFSET );
|
|
||||||
//glutBitmapString(GLUT_BITMAP_HELVETICA_18, szUBuff);
|
|
||||||
|
|
||||||
//glEnable(GL_LIGHTING);
|
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
glMatrixMode( GL_PROJECTION );
|
glMatrixMode( GL_PROJECTION );
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
|
|
Loading…
Reference in a new issue