Commit 358baf67 authored by Isaak Lim's avatar Isaak Lim
Browse files

- cleaned up and added some documentation to TextNode

- adjusted the code in RulerPlugin and SkeletonObject accordingly

refs #269

git-svn-id: http://www.openflipper.org/svnrepo/OpenFlipper/branches/Free@14695 383ad7c9-94d9-4d36-a494-682f7c89f535
parent fd859ed6
...@@ -74,12 +74,45 @@ bool TextNode::initialised_ = false; ...@@ -74,12 +74,45 @@ bool TextNode::initialised_ = false;
std::map<char, unsigned int> TextNode::charToIndex_ = TextNode::createMap(); std::map<char, unsigned int> TextNode::charToIndex_ = TextNode::createMap();
QColor TextNode::color_ = QColor(255, 0, 0); QColor TextNode::color_ = QColor(255, 0, 0);
//----------------------------------------------------------------------------
TextNode::
TextNode( BaseNode* _parent,
std::string _name,
TextMode _textMode)
: BaseNode(_parent, _name),
size_(1),
textMode_(_textMode),
vbo_(0),
vertexBuffer_(0),
blendEnabled_(false),
texture2dEnabled_(false),
cullFaceEnabled_(false),
blendSrc_(0),
blendDest_(0)
{
updateFont();
updateVBO();
}
//----------------------------------------------------------------------------
TextNode:: TextNode::
~TextNode() ~TextNode()
{ {
glDeleteBuffers(1, &vbo_); glDeleteBuffers(1, &vbo_);
} }
//----------------------------------------------------------------------------
void void
TextNode:: TextNode::
boundingBox(Vec3d& /*_bbMin*/, Vec3d& /*_bbMax*/) boundingBox(Vec3d& /*_bbMin*/, Vec3d& /*_bbMax*/)
...@@ -103,6 +136,49 @@ availableDrawModes() const ...@@ -103,6 +136,49 @@ availableDrawModes() const
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void
TextNode::
setRenderingMode(TextMode _textMode) {
textMode_ = _textMode;
}
//----------------------------------------------------------------------------
TextNode::TextMode
TextNode::
renderingMode() {
return textMode_;
}
//----------------------------------------------------------------------------
void
TextNode::
setText(std::string _text) {
text_ = _text; updateVBO();
}
//----------------------------------------------------------------------------
void
TextNode::
setSize(unsigned int _size) {
size_ = _size; updateVBO();
}
//----------------------------------------------------------------------------
std::map<char, unsigned int> std::map<char, unsigned int>
TextNode:: TextNode::
createMap() { createMap() {
...@@ -144,6 +220,7 @@ enter(GLState& /*_state*/, const DrawModes::DrawMode& /*_drawmode*/) { ...@@ -144,6 +220,7 @@ enter(GLState& /*_state*/, const DrawModes::DrawMode& /*_drawmode*/) {
void void
TextNode:: TextNode::
leave(GLState& /*_state*/, const DrawModes::DrawMode& /*_drawmode*/) { leave(GLState& /*_state*/, const DrawModes::DrawMode& /*_drawmode*/) {
// restore the GLState as it was when entering TextNode
if (cullFaceEnabled_) if (cullFaceEnabled_)
ACG::GLState::enable(GL_CULL_FACE); ACG::GLState::enable(GL_CULL_FACE);
if (!texture2dEnabled_) if (!texture2dEnabled_)
...@@ -165,6 +242,8 @@ draw(GLState& _state, const DrawModes::DrawMode& /*_drawMode*/) ...@@ -165,6 +242,8 @@ draw(GLState& _state, const DrawModes::DrawMode& /*_drawMode*/)
{ {
if (!text_.empty()) { if (!text_.empty()) {
bindVBO(); bindVBO();
// do not rotate the quads in this case
if (textMode_ == SCREEN_ALIGNED) { if (textMode_ == SCREEN_ALIGNED) {
_state.push_modelview_matrix(); _state.push_modelview_matrix();
Vec3d projected = _state.project(Vec3d(0.0, 0.0, 0.0)); Vec3d projected = _state.project(Vec3d(0.0, 0.0, 0.0));
...@@ -211,7 +290,7 @@ void ...@@ -211,7 +290,7 @@ void
TextNode::setFont(const QFont& _font) { TextNode::setFont(const QFont& _font) {
qfont_ = QFont(_font); qfont_ = QFont(_font);
initialised_ = false; initialised_ = false;
UpdateFont(); updateFont();
updateVBO(); updateVBO();
} }
...@@ -220,16 +299,19 @@ TextNode::setFont(const QFont& _font) { ...@@ -220,16 +299,19 @@ TextNode::setFont(const QFont& _font) {
void void
TextNode:: TextNode::
UpdateFont() { updateFont() {
// do not generate a new texture for every TextNode unless necessary
if (initialised_) if (initialised_)
return; return;
QFontMetrics metric(qfont_); QFontMetrics metric(qfont_);
int height = metric.height(); int height = metric.height();
// ensure that the height of the texture is a power of 2
int heightPow2 = nearestPowerOfTwo(height); int heightPow2 = nearestPowerOfTwo(height);
int width = metric.maxWidth(); int width = metric.maxWidth();
// ensure that the width of the texture is a power of 2
int widthPow2 = nearestPowerOfTwo(width); int widthPow2 = nearestPowerOfTwo(width);
imageWidth_ = widthPow2 * numberOfChars_; imageWidth_ = widthPow2 * numberOfChars_;
...@@ -241,14 +323,19 @@ UpdateFont() { ...@@ -241,14 +323,19 @@ UpdateFont() {
| QPainter::TextAntialiasing); | QPainter::TextAntialiasing);
painter.setFont(qfont_); painter.setFont(qfont_);
painter.setPen(color_); painter.setPen(color_);
// characters are drawn aligned to the left into the QImage finalImage next to each other
unsigned int i = 0; unsigned int i = 0;
for (char c = ' '; c < '~'; ++c, ++i) { for (char c = ' '; c < '~'; ++c, ++i) {
painter.drawText(i*widthPow2, 0, widthPow2, heightPow2, Qt::AlignLeft | Qt::AlignBottom, QString(c)); painter.drawText(i*widthPow2, 0, widthPow2, heightPow2, Qt::AlignLeft | Qt::AlignBottom, QString(c));
} }
painter.end(); painter.end();
// convert finalImage to an OpenGL friendly format
finalImage = QGLWidget::convertToGLFormat(finalImage); finalImage = QGLWidget::convertToGLFormat(finalImage);
// delete the old texture if it exists
// and generate a new texture from finalImage
glDeleteTextures(1, &texture_); glDeleteTextures(1, &texture_);
glGenTextures(1, &texture_); glGenTextures(1, &texture_);
ACG::GLState::bindTexture(GL_TEXTURE_2D, texture_); ACG::GLState::bindTexture(GL_TEXTURE_2D, texture_);
...@@ -274,7 +361,11 @@ updateVBO() { ...@@ -274,7 +361,11 @@ updateVBO() {
vertexBuffer_.clear(); vertexBuffer_.clear();
// generate a quad for each character // generate a quad for each character next to each other
// *--*--*----*-*
// | | | | |
// | | | | |
// *--*--*----*-*
QFontMetrics metric(qfont_); QFontMetrics metric(qfont_);
int maxWidth = metric.maxWidth(); int maxWidth = metric.maxWidth();
int avgWidth = metric.averageCharWidth(); int avgWidth = metric.averageCharWidth();
...@@ -300,7 +391,6 @@ updateVBO() { ...@@ -300,7 +391,6 @@ updateVBO() {
// QFontMetrics does not seem to always give the correct width // QFontMetrics does not seem to always give the correct width
// therefore we add a margin so that characters are not cut off // therefore we add a margin so that characters are not cut off
//if ( (leftBearing == 0) && (rightBearing == 0) ) {
if (leftBearing + rightBearing < 0.1*maxWidth) { if (leftBearing + rightBearing < 0.1*maxWidth) {
if (metricWidth + 0.25*maxWidth < maxWidth) if (metricWidth + 0.25*maxWidth < maxWidth)
metricWidth += 0.25*maxWidth; metricWidth += 0.25*maxWidth;
...@@ -311,6 +401,8 @@ updateVBO() { ...@@ -311,6 +401,8 @@ updateVBO() {
} }
float widthTx = (float) metricWidth / (float) imageWidth_; float widthTx = (float) metricWidth / (float) imageWidth_;
// 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
float leftTx = ((float) charToIndex_[text_[i]] ) / (float) numberOfChars_; float leftTx = ((float) charToIndex_[text_[i]] ) / (float) numberOfChars_;
float rightTx = leftTx + widthTx; float rightTx = leftTx + widthTx;
......
...@@ -75,9 +75,13 @@ namespace SceneGraph { ...@@ -75,9 +75,13 @@ namespace SceneGraph {
/** \class TextNode TextNode.hh <ACG/Scenegraph/TextNode.hh> /** \class TextNode TextNode.hh <ACG/Scenegraph/TextNode.hh>
* TextNode can be used to display a string on quads in OpenGL. This string can be set with
TextNode renders Text. * setText(std::string _text). A TextNode can be attached to a parent node by using the function
* BaseObjectData::addAdditionalNode. The quads can then be set to align to the parent by setting #textMode_
* to OBJECT_ALIGNED via the setRenderingMode(TextMode _textMode) function. Alternatively the quads can be aligned
* to the screen by setting #textMode_ to SCREEN_ALIGNED. The font that is used to display #text_ on the screen is stored
* in #qfont_, which can be set with the setFont(const QFont& _font) function. Finally the quads can be scaled by setting #size_
* via the setSize(unsigned int _size) function.
**/ **/
class ACGDLLEXPORT TextNode : public BaseNode class ACGDLLEXPORT TextNode : public BaseNode
...@@ -91,29 +95,12 @@ public: ...@@ -91,29 +95,12 @@ public:
/** default constructor /** default constructor
* @param _parent Define the parent Node this node gets attached to * @param _parent Define the parent Node this node gets attached to
* @param _fontfile Font File ( should include full path )
* @param _name Name of this Node * @param _name Name of this Node
* @param _textMode Define the text rendering style ( see TextNode::TextMode ) * @param _textMode Define the text rendering style ( see TextNode::TextMode )
*/ */
TextNode( std::string _fontFile, TextNode( BaseNode* _parent=0,
BaseNode* _parent=0,
std::string _name="<TextNode>", std::string _name="<TextNode>",
TextMode _textMode = SCREEN_ALIGNED) TextMode _textMode = SCREEN_ALIGNED);
: BaseNode(_parent, _name),
size_(1),
fontFile_(_fontFile),
textMode_(_textMode),
vbo_(0),
vertexBuffer_(0),
blendEnabled_(false),
texture2dEnabled_(false),
cullFaceEnabled_(false),
blendSrc_(0),
blendDest_(0)
{
UpdateFont();
updateVBO();
}
/// destructor /// destructor
~TextNode(); ~TextNode();
...@@ -138,65 +125,103 @@ public: ...@@ -138,65 +125,103 @@ public:
/** Set the rendering mode ( see TextNode::TextMode ) /** Set the rendering mode ( see TextNode::TextMode )
*/ */
void setRenderingMode(TextMode _textMode);
void setRenderingMode(TextMode _textMode) { textMode_ = _textMode; }; /// returns the rendering mode (SCREEN_ALIGNED or OBJECT_ALIGNED)
TextMode renderingMode();
TextMode renderingMode() { return textMode_; }; /// sets the string that will be rendered
void setText(std::string _text);
/// sets the text that will be rendered /// sets the size by which the quads displaying the text will be scaled
void setText(std::string _text) {text_ = _text; updateVBO();}; void setSize(unsigned int _size);
/// sets the scaling size of the TextNode /// sets the font to be used for generating a texture with most characters of the chosen font
void setSize(unsigned int _size) {size_ = _size; updateVBO();};
/// sets the font to be used
void setFont(const QFont& _font); void setFont(const QFont& _font);
protected: protected:
static void UpdateFont(); /**
* Generates a texture by drawing most characters into one texture.
* This texture is then used to draw single characters onto quads
*/
static void updateFont();
private: private:
/// returns the nearest greater power of 2 to num
static quint32 nearestPowerOfTwo(quint32 num); static quint32 nearestPowerOfTwo(quint32 num);
/**
* generates a quad for each character in #text_ and also
* calculates the texture coordinates for each quad's character
*/
void updateVBO(); void updateVBO();
/// binds #vbo_ and sets the necessary OpenGL states
void bindVBO(); void bindVBO();
/// unbinds #vbo_
void unbindVBO(); void unbindVBO();
/**
* Creates a map #charToIndex_ from most characters to an incrementing set of indices.
* These indices are used to create the texture coordinates in updateVBO().
*/
static std::map<char, unsigned int> createMap(); static std::map<char, unsigned int> createMap();
private: private:
/// scaling factor by which the quads in #vbo_ are scaled
unsigned int size_; unsigned int size_;
/// text to be displayed on quads in #vbo_
std::string text_; std::string text_;
std::string fontFile_; /// current display mode of #text_ (SCREEN_ALIGNED or OBJECT_ALIGNED)
TextMode textMode_; TextMode textMode_;
/**
* handle to the vertex buffer object, containing the quads on which the characters in
* #text_ are rendered
*/
GLuint vbo_; GLuint vbo_;
/// buffer of vertex coordinates and texture coordinates of the quads
std::vector<GLfloat> vertexBuffer_; std::vector<GLfloat> vertexBuffer_;
/// stores if GL_BLEND was enabled on entering TextNode
bool blendEnabled_; bool blendEnabled_;
/// stores if GL_TEXTURE_2D was enabled on entering TextNode
bool texture2dEnabled_; bool texture2dEnabled_;
/// stores if GL_CULL_FACE was enabled on entering TextNode
bool cullFaceEnabled_; bool cullFaceEnabled_;
/// stores the sfactor parameter of glBlendFunc on entering TextNode
GLint blendSrc_; GLint blendSrc_;
/// stores the dfactor parameter of glBlendFunc on entering TextNode
GLint blendDest_; GLint blendDest_;
/// maps most readable characters to indices for texture coordinate calculation in updateVBO()
static std::map<char, unsigned int> charToIndex_; static std::map<char, unsigned int> charToIndex_;
/// font that is used to generate the texture in updateFont()
static QFont qfont_; static QFont qfont_;
/// handle for the texture into which characters from #qfont_ are painted in updateFont()
static GLuint texture_; static GLuint texture_;
/// width of the generated texture
static int imageWidth_; static int imageWidth_;
/// number of characters that are drawn into the texture
static const int numberOfChars_ = 94; static const int numberOfChars_ = 94;
/// this is used to ensure that the texture is only generated once when necessary
static bool initialised_; static bool initialised_;
/// color that is used to draw the characters into the texture in updateFont()
static QColor color_; static QColor color_;
}; };
......
...@@ -432,21 +432,19 @@ void SkeletonObject::showIndices(bool _bVisible) ...@@ -432,21 +432,19 @@ void SkeletonObject::showIndices(bool _bVisible)
pSubMatNode = new ACG::SceneGraph::MaterialNode(pTransNode, nameSubMatNode.c_str()); pSubMatNode = new ACG::SceneGraph::MaterialNode(pTransNode, nameSubMatNode.c_str());
addAdditionalNode(pSubMatNode, "SkeletonPlugin", nameSubMatNode.c_str()); addAdditionalNode(pSubMatNode, "SkeletonPlugin", nameSubMatNode.c_str());
} }
// pSubMatNode->set_color(skeleton_->joint(i)->color()); // pSubMatNode->set_color(skeleton_->joint(i)->color());
#ifdef USE_FTGL
ACG::SceneGraph::TextNode *pTextNode = NULL; ACG::SceneGraph::TextNode *pTextNode = NULL;
if(!getAdditionalNode(pTextNode, "SkeletonPlugin", nameTextNode.c_str())) if(!getAdditionalNode(pTextNode, "SkeletonPlugin", nameTextNode.c_str()))
{ {
pTextNode = new ACG::SceneGraph::TextNode( pTextNode = new ACG::SceneGraph::TextNode(pSubMatNode,
(OpenFlipper::Options::fontsDirStr() + OpenFlipper::Options::dirSeparator() + "freefont" + OpenFlipper::Options:: dirSeparator() + "FreeSans.ttf").toStdString(), nameTextNode.c_str(),
pSubMatNode, nameTextNode.c_str(), ACG::SceneGraph::TextNode::SCREEN_ALIGNED); ACG::SceneGraph::TextNode::SCREEN_ALIGNED);
addAdditionalNode(pTextNode, "SkeletonPlugin", nameTextNode.c_str()); addAdditionalNode(pTextNode, "SkeletonPlugin", nameTextNode.c_str());
} }
pTextNode->setText(" " + nameJoint); pTextNode->setText(" " + nameJoint);
pTextNode->setSize(50); pTextNode->setSize(50);
pTextNode->multipassNodeSetActive(8, true); pTextNode->multipassNodeSetActive(8, true);
#endif
} }
//update the indices with the current animationhandle //update the indices with the current animationhandle
......
...@@ -158,8 +158,7 @@ void RulerPlugin::slotMouseEvent(QMouseEvent* _event) ...@@ -158,8 +158,7 @@ void RulerPlugin::slotMouseEvent(QMouseEvent* _event)
if (!object->getAdditionalNode(textNode_,name(),textNodeName_.c_str())) if (!object->getAdditionalNode(textNode_,name(),textNodeName_.c_str()))
{ {
textNode_ = new ACG::SceneGraph::TextNode((OpenFlipper::Options::fontsDirStr() + OpenFlipper::Options::dirSeparator() + "freefont" + OpenFlipper::Options::dirSeparator() + "FreeSans.ttf").toStdString(), textNode_ = new ACG::SceneGraph::TextNode(textTransformNode_,textNodeName_,ACG::SceneGraph::TextNode::OBJECT_ALIGNED);
textTransformNode_,textNodeName_,ACG::SceneGraph::TextNode::OBJECT_ALIGNED);
object->addAdditionalNode(textNode_,name(),textNodeName_.c_str()); object->addAdditionalNode(textNode_,name(),textNodeName_.c_str());
} }
......
Supports Markdown
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