Commit 97cef418 authored by Isaak Lim's avatar Isaak Lim
Browse files

- got rid of FTGL dependencies in TextNode

- now TextNode uses textures and QFont to render text
- adjusted scaling in RulerPlugin and SkeletonObject

refs #269

git-svn-id: http://www.openflipper.org/svnrepo/OpenFlipper/branches/Free@14682 383ad7c9-94d9-4d36-a494-682f7c89f535
parent 292957fb
......@@ -49,16 +49,13 @@
//
//=============================================================================
#ifdef USE_FTGL
//== INCLUDES =================================================================
#include "TextNode.hh"
#include "../GL/gl.hh"
#include <stdlib.h>
#include <FTGL/ftgl.h> //<-- if these are moved to the .hh every plugin that includes the .hh has to link with FTGL
#include <FTGL/FTGLPixmapFont.h>
#include <FTGL/FTGLPolygonFont.h>
//== NAMESPACES ===============================================================
......@@ -69,20 +66,18 @@ namespace SceneGraph {
//== IMPLEMENTATION ==========================================================
// static members
QFont TextNode::qfont_ = QFont("Helvetica", 20);
GLuint TextNode::texture_ = 0;
int TextNode::imageWidth_ = 0;
bool TextNode::initialised_ = false;
std::map<char, unsigned int> TextNode::charToIndex_ = TextNode::createMap();
QColor TextNode::color_ = QColor(255, 0, 0);
TextNode::
~TextNode()
{
if ( textMode_ == SCREEN_ALIGNED ) {
if(font_ != 0)
delete reinterpret_cast<FTGLPixmapFont*>(font_);
} else if ( textMode_ == OBJECT_ALIGNED ) {
if(font_ != 0)
delete reinterpret_cast<FTGLPolygonFont*>(font_);
}
glDeleteBuffers(1, &vbo_);
}
void
......@@ -105,75 +100,296 @@ availableDrawModes() const
}
//----------------------------------------------------------------------------
std::map<char, unsigned int>
TextNode::
createMap() {
std::map<char, unsigned int> m;
unsigned int i = 0;
for (char c = ' '; c < '~'; ++c, ++i) {
m[c] = i;
}
return m;
}
//----------------------------------------------------------------------------
void
TextNode::
enter(GLState& /*_state*/, const DrawModes::DrawMode& /*_drawmode*/) {
// store current gl state
cullFaceEnabled_ = glIsEnabled(GL_CULL_FACE);
texture2dEnabled_ = glIsEnabled(GL_TEXTURE_2D);
blendEnabled_ = glIsEnabled(GL_BLEND);
glGetIntegerv(GL_BLEND_SRC, &blendSrc_);
glGetIntegerv(GL_BLEND_DST, &blendDest_);
// set texture and drawing states
ACG::GLState::disable(GL_CULL_FACE);
ACG::GLState::enable(GL_TEXTURE_2D);
ACG::GLState::enable(GL_BLEND);
ACG::GLState::blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
//----------------------------------------------------------------------------
void
TextNode::
leave(GLState& /*_state*/, const DrawModes::DrawMode& /*_drawmode*/) {
if (cullFaceEnabled_)
ACG::GLState::enable(GL_CULL_FACE);
if (!texture2dEnabled_)
ACG::GLState::disable(GL_TEXTURE_2D);
if (!blendEnabled_)
ACG::GLState::disable(GL_BLEND);
ACG::GLState::blendFunc(blendSrc_, blendDest_);
}
//----------------------------------------------------------------------------
void
TextNode::
draw(GLState& /* _state */ , const DrawModes::DrawMode& /*_drawMode*/)
draw(GLState& _state, const DrawModes::DrawMode& /*_drawMode*/)
{
glRasterPos3f(0.0f, 0.0f, 0.0f);
if (!text_.empty()) {
bindVBO();
if (textMode_ == SCREEN_ALIGNED) {
_state.push_modelview_matrix();
Vec3d projected = _state.project(Vec3d(0.0, 0.0, 0.0));
_state.reset_modelview();
Vec3d unprojected = _state.unproject(projected);
_state.translate(unprojected);
}
_state.push_modelview_matrix();
_state.scale(size_);
glDrawArrays(GL_QUADS, 0, text_.size() * 4);
_state.pop_modelview_matrix();
if ( textMode_ == SCREEN_ALIGNED ) {
if(font_ == 0)
return;
reinterpret_cast<FTGLPixmapFont*>(font_)->Render(text_.c_str());
if (textMode_ == SCREEN_ALIGNED) {
_state.pop_modelview_matrix();
}
unbindVBO();
}
}
if ( textMode_ == OBJECT_ALIGNED ) {
glScalef(0.1,0.1,0.1);
//----------------------------------------------------------------------------
if(font_ == 0)
return;
reinterpret_cast<FTGLPolygonFont*>(font_)->Render(text_.c_str());
glScalef(10.0,10.0,10.0);
}
uint32_t
TextNode::nearestPowerOfTwo(uint32_t num) {
uint32_t n = num > 0 ? num - 1 : 0;
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
n++;
return n;
}
//----------------------------------------------------------------------------
void
TextNode::setFont(const QFont& _font) {
qfont_ = QFont(_font);
initialised_ = false;
UpdateFont();
updateVBO();
}
//----------------------------------------------------------------------------
void
TextNode::
UpdateFont() {
if ( textMode_ == SCREEN_ALIGNED ) {
if(font_ != 0)
delete reinterpret_cast<FTGLPixmapFont*>(font_);
font_ = reinterpret_cast<void*>(new FTGLPixmapFont(fontFile_.c_str()));
reinterpret_cast<FTGLPixmapFont*>(font_)->FaceSize(size_);
if(reinterpret_cast<FTGLPixmapFont*>(font_)->Error()) {
std::cerr << "Unable to find font: " << fontFile_.c_str() << std::endl;
delete reinterpret_cast<FTGLPixmapFont*>(font_);
font_ = 0;
}
} else if ( textMode_ == OBJECT_ALIGNED ) {
if(font_ != 0)
delete reinterpret_cast<FTGLPolygonFont*>(font_);
font_ = reinterpret_cast<void*>(new FTGLPolygonFont(fontFile_.c_str()));
reinterpret_cast<FTGLPolygonFont*>(font_)->FaceSize(size_);
if(reinterpret_cast<FTGLPolygonFont*>(font_)->Error()) {
std::cerr << "Unable to find font: " << fontFile_.c_str() << std::endl;
delete reinterpret_cast<FTGLPolygonFont*>(font_);
font_ = 0;
if (initialised_)
return;
QFontMetrics metric(qfont_);
int height = metric.height();
int heightPow2 = nearestPowerOfTwo(height);
int width = metric.maxWidth();
int widthPow2 = nearestPowerOfTwo(width);
imageWidth_ = widthPow2 * numberOfChars_;
QImage finalImage(imageWidth_, heightPow2, QImage::Format_ARGB32);
finalImage.fill(Qt::transparent);
QPainter painter;
painter.begin(&finalImage);
painter.setRenderHints(QPainter::HighQualityAntialiasing
| QPainter::TextAntialiasing);
painter.setFont(qfont_);
painter.setPen(color_);
unsigned int i = 0;
for (char c = ' '; c < '~'; ++c, ++i) {
painter.drawText(i*widthPow2, 0, widthPow2, heightPow2, Qt::AlignLeft | Qt::AlignBottom, QString(c));
}
painter.end();
finalImage = QGLWidget::convertToGLFormat(finalImage);
glDeleteTextures(1, &texture_);
glGenTextures(1, &texture_);
ACG::GLState::bindTexture(GL_TEXTURE_2D, texture_);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, finalImage.width(), finalImage.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, finalImage.bits());
ACG::GLState::bindTexture(GL_TEXTURE_2D, 0);
initialised_ = true;
}
//----------------------------------------------------------------------------
void
TextNode::
updateVBO() {
if (text_.size() == 0)
return;
vertexBuffer_.clear();
// generate a quad for each character
QFontMetrics metric(qfont_);
int maxWidth = metric.maxWidth();
int avgWidth = metric.averageCharWidth();
float lastCharRight = 0.0f;
for (unsigned int i = 0; i < text_.size(); ++i) {
// left and right vertex coordinates
float width = (float) metric.width(text_[i]) / (float) maxWidth;
float left, right;
if (i == 0)
left = 0.0f;
else
left = lastCharRight;
right = (left + width);
lastCharRight = right;
// left and right texture coordinates
int leftBearing = abs(metric.leftBearing(text_[i]));
int rightBearing = abs(metric.rightBearing(text_[i]));
int metricWidth = metric.width(text_[i]);
// QFontMetrics does not seem to always give the correct width
// therefore we add a margin so that characters are not cut off
//if ( (leftBearing == 0) && (rightBearing == 0) ) {
if (leftBearing + rightBearing < 0.1*maxWidth) {
if (metricWidth + 0.25*maxWidth < maxWidth)
metricWidth += 0.25*maxWidth;
else
metricWidth = maxWidth;
} else {
metricWidth += leftBearing + rightBearing;
}
float widthTx = (float) metricWidth / (float) imageWidth_;
float leftTx = ((float) charToIndex_[text_[i]] ) / (float) numberOfChars_;
float rightTx = leftTx + widthTx;
// bottom left
vertexBuffer_.push_back(left);
vertexBuffer_.push_back(0.0f);
vertexBuffer_.push_back(0.0f);
// texture coordinates
vertexBuffer_.push_back(leftTx);
vertexBuffer_.push_back(0.0f);
// top left
vertexBuffer_.push_back(left);
vertexBuffer_.push_back(avgWidth*0.15);
vertexBuffer_.push_back(0.0f);
// texture coordinates
vertexBuffer_.push_back(leftTx);
vertexBuffer_.push_back(1.0f);
// top right
vertexBuffer_.push_back(right);
vertexBuffer_.push_back(avgWidth*0.15);
vertexBuffer_.push_back(0.0f);
// texture coordinates
vertexBuffer_.push_back(rightTx);
vertexBuffer_.push_back(1.0f);
// bottom right
vertexBuffer_.push_back(right);
vertexBuffer_.push_back(0.0f);
vertexBuffer_.push_back(0.0f);
// texture coordinates
vertexBuffer_.push_back(rightTx);
vertexBuffer_.push_back(0.0f);
}
glDeleteBuffers(1, &vbo_);
glGenBuffers(1, &vbo_);
ACG::GLState::bindBuffer(GL_ARRAY_BUFFER, vbo_);
glBufferData(GL_ARRAY_BUFFER, vertexBuffer_.size() * sizeof(GLfloat), &vertexBuffer_[0], GL_DYNAMIC_DRAW);
}
//----------------------------------------------------------------------------
void
TextNode::
bindVBO() {
ACG::GLState::bindBuffer(GL_ARRAY_BUFFER, vbo_);
ACG::GLState::vertexPointer(3, GL_FLOAT, 5*sizeof(GLfloat), 0);
ACG::GLState::enableClientState(GL_VERTEX_ARRAY);
ACG::GLState::activeTexture(GL_TEXTURE0);
ACG::GLState::texcoordPointer(2, GL_FLOAT, 5*sizeof(GLfloat), reinterpret_cast<void*>(3*sizeof(GLfloat)));
ACG::GLState::enableClientState(GL_TEXTURE_COORD_ARRAY);
ACG::GLState::bindTexture(GL_TEXTURE_2D, texture_);
}
//----------------------------------------------------------------------------
void
TextNode::
unbindVBO() {
ACG::GLState::bindTexture(GL_TEXTURE_2D, 0);
ACG::GLState::bindBuffer(GL_ARRAY_BUFFER, 0);
ACG::GLState::disableClientState(GL_VERTEX_ARRAY);
ACG::GLState::disableClientState(GL_TEXTURE_COORD_ARRAY);
}
//=============================================================================
} // namespace SceneGraph
} // namespace ACG
//=============================================================================
#endif // USE_FTGL
......@@ -49,8 +49,6 @@
//
//=============================================================================
#ifdef USE_FTGL
#ifndef ACG_TEXTNODE_HH
#define ACG_TEXTNODE_HH
......@@ -58,8 +56,14 @@
//== INCLUDES =================================================================
#include "BaseNode.hh"
#include "TransformNode.hh"
#include "DrawModes.hh"
#include <vector>
#include <QFont>
#include <QFontMetrics>
#include <QImage>
#include <QPainter>
#include <QGLWidget>
//== NAMESPACES ===============================================================
......@@ -96,12 +100,19 @@ public:
std::string _name="<TextNode>",
TextMode _textMode = SCREEN_ALIGNED)
: BaseNode(_parent, _name),
font_(0),
size_(_textMode == SCREEN_ALIGNED ? 15 : 1),
size_(1),
fontFile_(_fontFile),
textMode_(_textMode)
textMode_(_textMode),
vbo_(0),
vertexBuffer_(0),
blendEnabled_(false),
texture2dEnabled_(false),
cullFaceEnabled_(false),
blendSrc_(0),
blendDest_(0)
{
UpdateFont();
UpdateFont();
updateVBO();
}
/// destructor
......@@ -119,6 +130,12 @@ public:
/// draw Text
void draw(GLState& _state, const DrawModes::DrawMode& _drawMode);
/// set texture and drawing states
void enter(GLState& _state, const DrawModes::DrawMode& _drawmode);
/// restore texture and drawing states
void leave(GLState& _state, const DrawModes::DrawMode& _drawmode);
/** Set the rendering mode ( see TextNode::TextMode )
*/
......@@ -126,16 +143,26 @@ public:
TextMode renderingMode() { return textMode_; };
void setText(std::string _text) {text_ = _text;};
/// sets the text that will be rendered
void setText(std::string _text) {text_ = _text; updateVBO();};
void setSize(unsigned int _size) {size_ = _size; UpdateFont();};
/// sets the scaling size of the TextNode
void setSize(unsigned int _size) {size_ = _size; updateVBO();};
/// sets the font to be used
void setFont(const QFont& _font);
protected:
void UpdateFont();
static void UpdateFont();
private:
void *font_;
static uint32_t nearestPowerOfTwo(uint32_t num);
void updateVBO();
void bindVBO();
void unbindVBO();
static std::map<char, unsigned int> createMap();
private:
unsigned int size_;
std::string text_;
......@@ -143,8 +170,35 @@ private:
std::string fontFile_;
TextMode textMode_;
};
GLuint vbo_;
std::vector<GLfloat> vertexBuffer_;
bool blendEnabled_;
bool texture2dEnabled_;
bool cullFaceEnabled_;
GLint blendSrc_;
GLint blendDest_;
static std::map<char, unsigned int> charToIndex_;
static QFont qfont_;
static GLuint texture_;
static int imageWidth_;
static const int numberOfChars_ = 94;
static bool initialised_;
static QColor color_;
};
//=============================================================================
} // namespace SceneGraph
......@@ -152,13 +206,3 @@ private:
//=============================================================================
#endif // ACG_TEXTNODE_HH defined
//=============================================================================
#else // NO USE_FTGL but header included
#ifdef WIN32
#pragma message ( "TextNode requires ftgl but ftgl was not found" )
#else
#warning TextNode requires ftgl but ftgl was not found
#endif
#endif // USE_FTGL defined
//=============================================================================
......@@ -444,7 +444,7 @@ void SkeletonObject::showIndices(bool _bVisible)
addAdditionalNode(pTextNode, "SkeletonPlugin", nameTextNode.c_str());
}
pTextNode->setText(" " + nameJoint);
pTextNode->setSize(16);
pTextNode->setSize(50);
pTextNode->multipassNodeSetActive(8, true);
#endif
}
......
......@@ -86,7 +86,7 @@ void RulerPlugin::showDistance()
QString distanceStr = QString().number((distVec).length());
textNode_->setText(distanceStr.toStdString());
textNode_->multipassNodeSetActive(8, true);
textNode_->setSize(5);
textNode_->setSize(1);
textTransformNode_->loadIdentity();
textTransformNode_->translate(ACG::Vec3d(Point2.data()[0],Point2.data()[1],bbmax_.data()[2]));
......
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