movable_text.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2008, Willow Garage, Inc.
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *
00008  *     * Redistributions of source code must retain the above copyright
00009  *       notice, this list of conditions and the following disclaimer.
00010  *     * Redistributions in binary form must reproduce the above copyright
00011  *       notice, this list of conditions and the following disclaimer in the
00012  *       documentation and/or other materials provided with the distribution.
00013  *     * Neither the name of the Willow Garage, Inc. nor the names of its
00014  *       contributors may be used to endorse or promote products derived from
00015  *       this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00027  * POSSIBILITY OF SUCH DAMAGE.
00028  */
00029 
00030 // Adapted from: http://www.ogre3d.org/wiki/index.php/MovableText
00031 //          now: http://www.ogre3d.org/tikiwiki/tiki-index.php?page=MovableText
00032 // Original authors:
00033 /*
00034  * File: MovableText.cpp
00035  *
00036  * description: This create create a billboarding object that display a text.
00037  *
00038  * @author  2003 by cTh see gavocanov@rambler.ru
00039  * @update  2006 by barraq see nospam@barraquand.com
00040  */
00041 
00042 #include "movable_text.h"
00043 
00044 #include <OgreVector3.h>
00045 #include <OgreQuaternion.h>
00046 #include <OgreRoot.h>
00047 #include <OgreCamera.h>
00048 #include <OgreSceneNode.h>
00049 #include <OgreMaterialManager.h>
00050 #include <OgreHardwareBufferManager.h>
00051 #include <OgreFontManager.h>
00052 #include <OgreFont.h>
00053 
00054 #include <sstream>
00055 
00056 using namespace Ogre;
00057 
00058 #define POS_TEX_BINDING    0
00059 #define COLOUR_BINDING     1
00060 
00061 namespace rviz
00062 {
00063 
00064 MovableText::MovableText(const String &caption, const String &fontName, Real charHeight, const ColourValue &color)
00065 : mFontName(fontName)
00066 , mType("MovableText")
00067 , mCaption(caption)
00068 , mHorizontalAlignment(H_LEFT)
00069 , mVerticalAlignment(V_BELOW)
00070 , mColor(color)
00071 , mCharHeight(charHeight)
00072 , mLineSpacing(0.01)
00073 , mSpaceWidth(0)
00074 , mUpdateColors(true)
00075 , mOnTop(false)
00076 , mTimeUntilNextToggle(0)
00077 , mGlobalTranslation(0.0)
00078 , mLocalTranslation(0.0)
00079 , mpCam(NULL)
00080 , mpWin(NULL)
00081 , mpFont(NULL)
00082 {
00083   static int count = 0;
00084   std::stringstream ss;
00085   ss << "MovableText" << count++;
00086   mName = ss.str();
00087 
00088   mRenderOp.vertexData = NULL;
00089   this->setFontName(mFontName);
00090   this->_setupGeometry();
00091 }
00092 
00093 MovableText::~MovableText()
00094 {
00095   if (mRenderOp.vertexData)
00096     delete mRenderOp.vertexData;
00097   // May cause crashing... check this and comment if it does
00098   if (!mpMaterial.isNull())
00099     MaterialManager::getSingletonPtr()->remove(mpMaterial->getName());
00100 }
00101 
00102 void MovableText::setFontName(const String &fontName)
00103 {
00104   if ((Ogre::MaterialManager::getSingletonPtr()->resourceExists(mName + "Material")))
00105   {
00106     Ogre::MaterialManager::getSingleton().remove(mName + "Material");
00107   }
00108 
00109   if (mFontName != fontName || mpMaterial.isNull() || !mpFont)
00110   {
00111     mFontName = fontName;
00112     mpFont
00113         = (Font *) FontManager::getSingleton().getByName(mFontName).getPointer();
00114     if (!mpFont)
00115       throw Exception(Exception::ERR_ITEM_NOT_FOUND, "Could not find font "
00116           + fontName, "MovableText::setFontName");
00117 
00118     mpFont->load();
00119     if (!mpMaterial.isNull())
00120     {
00121       MaterialManager::getSingletonPtr()->remove(mpMaterial->getName());
00122       mpMaterial.setNull();
00123     }
00124 
00125     mpMaterial = mpFont->getMaterial()->clone(mName + "Material");
00126     if (!mpMaterial->isLoaded())
00127       mpMaterial->load();
00128 
00129     mpMaterial->setDepthCheckEnabled(!mOnTop);
00130     mpMaterial->setDepthBias(1.0, 1.0);
00131     mpMaterial->setDepthWriteEnabled(mOnTop);
00132     mpMaterial->setLightingEnabled(false);
00133     mNeedUpdate = true;
00134   }
00135 }
00136 
00137 void MovableText::setCaption(const String &caption)
00138 {
00139   if (caption != mCaption)
00140   {
00141     mCaption = caption;
00142     mNeedUpdate = true;
00143   }
00144 }
00145 
00146 void MovableText::setColor(const ColourValue &color)
00147 {
00148   if (color != mColor)
00149   {
00150     mColor = color;
00151     mUpdateColors = true;
00152   }
00153 }
00154 
00155 void MovableText::setCharacterHeight(Real height)
00156 {
00157   if (height != mCharHeight)
00158   {
00159     mCharHeight = height;
00160     mNeedUpdate = true;
00161   }
00162 }
00163 
00164 void MovableText::setLineSpacing(Real height)
00165 {
00166   if (height != mLineSpacing)
00167   {
00168     mLineSpacing = height;
00169     mNeedUpdate = true;
00170   }
00171 }
00172 
00173 void MovableText::setSpaceWidth(Real width)
00174 {
00175   if (width != mSpaceWidth)
00176   {
00177     mSpaceWidth = width;
00178     mNeedUpdate = true;
00179   }
00180 }
00181 
00182 void MovableText::setTextAlignment(
00183     const HorizontalAlignment& horizontalAlignment,
00184     const VerticalAlignment& verticalAlignment)
00185 {
00186   if (mHorizontalAlignment != horizontalAlignment)
00187   {
00188     mHorizontalAlignment = horizontalAlignment;
00189     mNeedUpdate = true;
00190   }
00191   if (mVerticalAlignment != verticalAlignment)
00192   {
00193     mVerticalAlignment = verticalAlignment;
00194     mNeedUpdate = true;
00195   }
00196 }
00197 
00198 void MovableText::setGlobalTranslation(Vector3 trans)
00199 {
00200   mGlobalTranslation = trans;
00201 }
00202 
00203 void MovableText::setLocalTranslation(Vector3 trans)
00204 {
00205   mLocalTranslation = trans;
00206 }
00207 
00208 void MovableText::showOnTop(bool show)
00209 {
00210   if (mOnTop != show && !mpMaterial.isNull())
00211   {
00212     mOnTop = show;
00213     mpMaterial->setDepthBias(1.0, 1.0);
00214     mpMaterial->setDepthCheckEnabled(!mOnTop);
00215     mpMaterial->setDepthWriteEnabled(mOnTop);
00216   }
00217 }
00218 
00219 void MovableText::_setupGeometry()
00220 {
00221   assert(mpFont);
00222   assert(!mpMaterial.isNull());
00223 
00224   unsigned int vertexCount = 0;
00225 
00226   //count letters to determine how many vertices are needed
00227   std::string::iterator i = mCaption.begin();
00228   std::string::iterator iend = mCaption.end();
00229   for ( ; i != iend; ++i )
00230   {
00231     if ((*i != ' ') && (*i != '\n'))
00232     {
00233       vertexCount += 6;
00234     }
00235   }
00236 
00237   if (mRenderOp.vertexData)
00238   {
00239     delete mRenderOp.vertexData;
00240     mRenderOp.vertexData = NULL;
00241     mUpdateColors = true;
00242   }
00243 
00244   if (mCaption.empty())
00245   {
00246     return;
00247   }
00248 
00249   if (!mRenderOp.vertexData)
00250     mRenderOp.vertexData = new VertexData();
00251 
00252   mRenderOp.indexData = 0;
00253   mRenderOp.vertexData->vertexStart = 0;
00254   mRenderOp.vertexData->vertexCount = vertexCount;
00255   mRenderOp.operationType = RenderOperation::OT_TRIANGLE_LIST;
00256   mRenderOp.useIndexes = false;
00257 
00258   VertexDeclaration *decl = mRenderOp.vertexData->vertexDeclaration;
00259   VertexBufferBinding *bind = mRenderOp.vertexData->vertexBufferBinding;
00260   size_t offset = 0;
00261 
00262   // create/bind positions/tex.ccord. buffer
00263   if (!decl->findElementBySemantic(VES_POSITION))
00264     decl->addElement(POS_TEX_BINDING, offset, VET_FLOAT3, VES_POSITION);
00265 
00266   offset += VertexElement::getTypeSize(VET_FLOAT3);
00267 
00268   if (!decl->findElementBySemantic(VES_TEXTURE_COORDINATES))
00269     decl->addElement(POS_TEX_BINDING, offset, Ogre::VET_FLOAT2,
00270         Ogre::VES_TEXTURE_COORDINATES, 0);
00271 
00272   HardwareVertexBufferSharedPtr ptbuf =
00273       HardwareBufferManager::getSingleton().createVertexBuffer(
00274           decl->getVertexSize(POS_TEX_BINDING),
00275           mRenderOp.vertexData->vertexCount,
00276           HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY);
00277   bind->setBinding(POS_TEX_BINDING, ptbuf);
00278 
00279   // Colours - store these in a separate buffer because they change less often
00280   if (!decl->findElementBySemantic(VES_DIFFUSE))
00281     decl->addElement(COLOUR_BINDING, 0, VET_COLOUR, VES_DIFFUSE);
00282 
00283   HardwareVertexBufferSharedPtr cbuf =
00284       HardwareBufferManager::getSingleton().createVertexBuffer(
00285           decl->getVertexSize(COLOUR_BINDING),
00286           mRenderOp.vertexData->vertexCount,
00287           HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY);
00288   bind->setBinding(COLOUR_BINDING, cbuf);
00289 
00290   float *pPCBuff =
00291       static_cast<float*> (ptbuf->lock(HardwareBuffer::HBL_DISCARD));
00292 
00293   Real spaceWidth = mSpaceWidth;
00294   // Derive space width from a capital A
00295   if (spaceWidth == 0)
00296     spaceWidth = mpFont->getGlyphAspectRatio('A') * mCharHeight * 2.0;
00297 
00298   float total_height = mCharHeight;
00299   float total_width = 0.0f;
00300   float current_width = 0.0f;
00301   i = mCaption.begin();
00302   iend = mCaption.end();
00303   for ( ; i != iend; ++i )
00304   {
00305     if (*i == '\n')
00306     {
00307       total_height += mCharHeight + 0.01;
00308 
00309       if ( current_width > total_width )
00310       {
00311         total_width = current_width;
00312         current_width = 0.0;
00313       }
00314     }
00315     else
00316     {
00317       current_width += mpFont->getGlyphAspectRatio(*i) * mCharHeight * 2.0;
00318     }
00319   }
00320 
00321   if ( current_width > total_width )
00322   {
00323     total_width = current_width;
00324   }
00325 
00326   float top = 0.0f;
00327   switch (mVerticalAlignment)
00328   {
00329   case MovableText::V_ABOVE:
00330     top = total_height * 2;
00331     break;
00332   case MovableText::V_CENTER:
00333     top = 0.5 * total_height * 2;
00334     break;
00335   case MovableText::V_BELOW:
00336     top = 0.0f;
00337     break;
00338   }
00339 
00340   float starting_left = 0.0f;
00341   switch (mHorizontalAlignment)
00342   {
00343   case MovableText::H_LEFT:
00344     starting_left = 0.0f;
00345     break;
00346   case MovableText::H_CENTER:
00347     starting_left = -total_width / 2.0f;
00348     break;
00349   }
00350 
00351   float left = starting_left;
00352 
00353   bool newLine = true;
00354   Real len = 0.0f;
00355   // for calculation of AABB
00356   Ogre::Vector3 min(9999999.0f), max(-9999999.0f), currPos(0.0f);
00357   Ogre::Real maxSquaredRadius = -99999999.0f;
00358   float largestWidth = 0.0f;
00359   for (i = mCaption.begin(); i != iend; ++i)
00360   {
00361     if (newLine)
00362     {
00363       len = 0.0f;
00364       for (String::iterator j = i; j != iend && *j != '\n'; j++)
00365       {
00366         if (*j == ' ')
00367           len += spaceWidth;
00368         else
00369           len += mpFont->getGlyphAspectRatio(*j) * mCharHeight * 2.0;
00370       }
00371       newLine = false;
00372     }
00373 
00374     if (*i == '\n')
00375     {
00376       left = starting_left;
00377       top -= mCharHeight * 2.0;
00378       newLine = true;
00379       continue;
00380     }
00381 
00382     if (*i == ' ')
00383     {
00384       // Just leave a gap, no tris
00385       left += spaceWidth;
00386       continue;
00387     }
00388 
00389     Real horiz_height = mpFont->getGlyphAspectRatio(*i);
00390     Real u1, u2, v1, v2;
00391     Ogre::Font::UVRect utmp;
00392     utmp = mpFont->getGlyphTexCoords(*i);
00393     u1 = utmp.left;
00394     u2 = utmp.right;
00395     v1 = utmp.top;
00396     v2 = utmp.bottom;
00397 
00398     // each vert is (x, y, z, u, v)
00399     //-------------------------------------------------------------------------------------
00400     // First tri
00401     //
00402     // Upper left
00403     currPos = Ogre::Vector3(left, top, 0.0);
00404 
00405     *pPCBuff++ = currPos.x;
00406     *pPCBuff++ = currPos.y;
00407     *pPCBuff++ = currPos.z;
00408     *pPCBuff++ = u1;
00409     *pPCBuff++ = v1;
00410 
00411     // Deal with bounds
00412 
00413 
00414     min.makeFloor(currPos);
00415     max.makeCeil(currPos);
00416     maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength());
00417 
00418     top -= mCharHeight * 2.0;
00419 
00420     // Bottom left
00421     currPos = Ogre::Vector3(left, top, 0.0);
00422     *pPCBuff++ = currPos.x;
00423     *pPCBuff++ = currPos.y;
00424     *pPCBuff++ = currPos.z;
00425     *pPCBuff++ = u1;
00426     *pPCBuff++ = v2;
00427 
00428     // Deal with bounds
00429     min.makeFloor(currPos);
00430     max.makeCeil(currPos);
00431     maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength());
00432 
00433     top += mCharHeight * 2.0;
00434     left += horiz_height * mCharHeight * 2.0;
00435 
00436     // Top right
00437     currPos = Ogre::Vector3(left, top, 0.0);
00438     *pPCBuff++ = currPos.x;
00439     *pPCBuff++ = currPos.y;
00440     *pPCBuff++ = currPos.z;
00441     *pPCBuff++ = u2;
00442     *pPCBuff++ = v1;
00443     //-------------------------------------------------------------------------------------
00444 
00445     // Deal with bounds
00446     min.makeFloor(currPos);
00447     max.makeCeil(currPos);
00448     maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength());
00449 
00450     //-------------------------------------------------------------------------------------
00451     // Second tri
00452     //
00453     // Top right (again)
00454     currPos = Ogre::Vector3(left, top, 0.0);
00455     *pPCBuff++ = currPos.x;
00456     *pPCBuff++ = currPos.y;
00457     *pPCBuff++ = currPos.z;
00458     *pPCBuff++ = u2;
00459     *pPCBuff++ = v1;
00460 
00461     min.makeFloor(currPos);
00462     max.makeCeil(currPos);
00463     maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength());
00464 
00465     top -= mCharHeight * 2.0;
00466     left -= horiz_height * mCharHeight * 2.0;
00467 
00468     // Bottom left (again)
00469     currPos = Ogre::Vector3(left, top, 0.0);
00470     *pPCBuff++ = currPos.x;
00471     *pPCBuff++ = currPos.y;
00472     *pPCBuff++ = currPos.z;
00473     *pPCBuff++ = u1;
00474     *pPCBuff++ = v2;
00475 
00476     min.makeFloor(currPos);
00477     max.makeCeil(currPos);
00478     maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength());
00479 
00480     left += horiz_height * mCharHeight * 2.0;
00481 
00482     // Bottom right
00483     currPos = Ogre::Vector3(left, top, 0.0);
00484     *pPCBuff++ = currPos.x;
00485     *pPCBuff++ = currPos.y;
00486     *pPCBuff++ = currPos.z;
00487     *pPCBuff++ = u2;
00488     *pPCBuff++ = v2;
00489     //-------------------------------------------------------------------------------------
00490     min.makeFloor(currPos);
00491     max.makeCeil(currPos);
00492     maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength());
00493 
00494     // Go back up with top
00495     top += mCharHeight * 2.0;
00496 
00497     float currentWidth = (left + 1) / 2 - 0;
00498     if (currentWidth > largestWidth)
00499       largestWidth = currentWidth;
00500   }
00501 
00502   // Unlock vertex buffer
00503   ptbuf->unlock();
00504 
00505   // update AABB/Sphere radius
00506   mAABB = Ogre::AxisAlignedBox(min, max);
00507   mRadius = Ogre::Math::Sqrt(maxSquaredRadius);
00508 
00509   if (mUpdateColors)
00510     this->_updateColors();
00511 
00512   mNeedUpdate = false;
00513 }
00514 
00515 void MovableText::_updateColors(void)
00516 {
00517   assert(mpFont);
00518   assert(!mpMaterial.isNull());
00519 
00520   // Convert to system-specific
00521   RGBA color;
00522   Root::getSingleton().convertColourValue(mColor, &color);
00523   HardwareVertexBufferSharedPtr vbuf =
00524       mRenderOp.vertexData->vertexBufferBinding->getBuffer(COLOUR_BINDING);
00525   RGBA *pDest = static_cast<RGBA*> (vbuf->lock(HardwareBuffer::HBL_DISCARD));
00526   for (int i = 0; i < (int) mRenderOp.vertexData->vertexCount; ++i)
00527     *pDest++ = color;
00528   vbuf->unlock();
00529   mUpdateColors = false;
00530 }
00531 
00532 const Quaternion& MovableText::getWorldOrientation(void) const
00533 {
00534   assert(mpCam);
00535   return const_cast<Quaternion&> (mpCam->getDerivedOrientation());
00536 }
00537 
00538 #if( (OGRE_VERSION_MAJOR >= 1 && OGRE_VERSION_MINOR >= 6) || OGRE_VERSION_MAJOR >= 2 )
00539 void MovableText::visitRenderables(Ogre::Renderable::Visitor* visitor, bool debugRenderables)
00540 {
00541   visitor->visit( this, 0, false );
00542 }
00543 #endif
00544 
00545 const Vector3& MovableText::getWorldPosition(void) const
00546 {
00547   assert(mParentNode);
00548   return mParentNode->_getDerivedPosition();
00549 }
00550 
00551 void MovableText::getWorldTransforms(Matrix4 *xform) const
00552 {
00553   if (this->isVisible() && mpCam)
00554   {
00555     Matrix3 rot3x3, scale3x3 = Matrix3::IDENTITY;
00556 
00557     // store rotation in a matrix
00558     mpCam->getDerivedOrientation().ToRotationMatrix(rot3x3);
00559 
00560     // parent node position
00561     Vector3 ppos = mParentNode->_getDerivedPosition() + Vector3::UNIT_Y
00562         * mGlobalTranslation;
00563     ppos += rot3x3 * mLocalTranslation;
00564 
00565     // apply scale
00566     scale3x3[0][0] = mParentNode->_getDerivedScale().x / 2;
00567     scale3x3[1][1] = mParentNode->_getDerivedScale().y / 2;
00568     scale3x3[2][2] = mParentNode->_getDerivedScale().z / 2;
00569 
00570     // apply all transforms to xform
00571     *xform = (rot3x3 * scale3x3);
00572     xform->setTrans(ppos);
00573   }
00574 }
00575 
00576 void MovableText::getRenderOperation(RenderOperation &op)
00577 {
00578   if (this->isVisible())
00579   {
00580     if (mNeedUpdate)
00581       this->_setupGeometry();
00582     if (mUpdateColors)
00583       this->_updateColors();
00584     op = mRenderOp;
00585   }
00586 }
00587 
00588 void MovableText::_notifyCurrentCamera(Camera *cam)
00589 {
00590   mpCam = cam;
00591 }
00592 
00593 void MovableText::_updateRenderQueue(RenderQueue* queue)
00594 {
00595   if (this->isVisible())
00596   {
00597     if (mNeedUpdate)
00598       this->_setupGeometry();
00599     if (mUpdateColors)
00600       this->_updateColors();
00601 
00602     queue->addRenderable(this, mRenderQueueID, OGRE_RENDERABLE_DEFAULT_PRIORITY);
00603     //queue->addRenderable(this, mRenderQueueID, RENDER_QUEUE_SKIES_LATE);
00604   }
00605 }
00606 
00607 } // namespace rviz
00608 


rviz
Author(s): Dave Hershberger, David Gossow, Josh Faust
autogenerated on Tue Oct 3 2017 03:19:31