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