$search
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