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 #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
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
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
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
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
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
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
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
00398
00399
00400
00401
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
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
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
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
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
00445 min.makeFloor(currPos);
00446 max.makeCeil(currPos);
00447 maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength());
00448
00449
00450
00451
00452
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
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
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
00494 top += mCharHeight * 2.0;
00495
00496 float currentWidth = (left + 1) / 2 - 0;
00497 if (currentWidth > largestWidth)
00498 largestWidth = currentWidth;
00499 }
00500
00501
00502 ptbuf->unlock();
00503
00504
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
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
00557 mpCam->getDerivedOrientation().ToRotationMatrix(rot3x3);
00558
00559
00560 Vector3 ppos = mParentNode->_getDerivedPosition() + Vector3::UNIT_Y
00561 * mGlobalTranslation;
00562 ppos += rot3x3 * mLocalTranslation;
00563
00564
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
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
00603 }
00604 }
00605
00606 }
00607