00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
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
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
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
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
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
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
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
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
00399
00400
00401
00402
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
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
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
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
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
00446 min.makeFloor(currPos);
00447 max.makeCeil(currPos);
00448 maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength());
00449
00450
00451
00452
00453
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
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
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
00495 top += mCharHeight * 2.0;
00496
00497 float currentWidth = (left + 1) / 2 - 0;
00498 if (currentWidth > largestWidth)
00499 largestWidth = currentWidth;
00500 }
00501
00502
00503 ptbuf->unlock();
00504
00505
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
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
00558 mpCam->getDerivedOrientation().ToRotationMatrix(rot3x3);
00559
00560
00561 Vector3 ppos = mParentNode->_getDerivedPosition() + Vector3::UNIT_Y
00562 * mGlobalTranslation;
00563 ppos += rot3x3 * mLocalTranslation;
00564
00565
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
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
00604 }
00605 }
00606
00607 }
00608