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


rviz
Author(s): Dave Hershberger, David Gossow, Josh Faust
autogenerated on Thu Aug 27 2015 15:02:27