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


ogre_tools_qt
Author(s): Josh Faust
autogenerated on Fri Dec 6 2013 20:56:42