movable_text.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2008, Willow Garage, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Willow Garage, Inc. nor the names of its
14  * contributors may be used to endorse or promote products derived from
15  * this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 // Adapted from: http://www.ogre3d.org/wiki/index.php/MovableText
31 // now: http://www.ogre3d.org/tikiwiki/tiki-index.php?page=MovableText
32 // Original authors:
33 /*
34  * File: MovableText.cpp
35  *
36  * description: This create create a billboarding object that display a text.
37  *
38  * @author 2003 by cTh see gavocanov@rambler.ru
39  * @update 2006 by barraq see nospam@barraquand.com
40  */
41 
42 #include "movable_text.h"
43 
44 #include <OgreVector3.h>
45 #include <OgreQuaternion.h>
46 #include <OgreRoot.h>
47 #include <OgreCamera.h>
48 #include <OgreSceneNode.h>
49 #include <OgreMaterialManager.h>
50 #include <OgreHardwareBufferManager.h>
51 #include <OgreFontManager.h>
52 #include <OgreFont.h>
53 
54 #include <sstream>
55 
56 using namespace Ogre;
57 
58 #define POS_TEX_BINDING 0
59 #define COLOUR_BINDING 1
60 
61 namespace rviz
62 {
63 
64 MovableText::MovableText(const String &caption, const String &fontName, Real charHeight, const ColourValue &color)
65 : mFontName(fontName)
66 , mType("MovableText")
67 , mCaption(caption)
68 , mHorizontalAlignment(H_LEFT)
69 , mVerticalAlignment(V_BELOW)
70 , mColor(color)
71 , mCharHeight(charHeight)
72 , mLineSpacing(0.01)
73 , mSpaceWidth(0)
74 , mUpdateColors(true)
75 , mOnTop(false)
76 , mTimeUntilNextToggle(0)
77 , mGlobalTranslation(0.0)
78 , mLocalTranslation(0.0)
79 , mpCam(NULL)
80 , mpWin(NULL)
81 , mpFont(NULL)
82 {
83  static int count = 0;
84  std::stringstream ss;
85  ss << "MovableText" << count++;
86  mName = ss.str();
87 
88  mRenderOp.vertexData = NULL;
89  this->setFontName(mFontName);
90  this->_setupGeometry();
91 }
92 
94 {
95  if (mRenderOp.vertexData)
96  delete mRenderOp.vertexData;
97  // May cause crashing... check this and comment if it does
98  if (!mpMaterial.isNull())
99  MaterialManager::getSingletonPtr()->remove(mpMaterial->getName());
100 }
101 
102 void MovableText::setFontName(const String &fontName)
103 {
104  if ((Ogre::MaterialManager::getSingletonPtr()->resourceExists(mName + "Material")))
105  {
106  Ogre::MaterialManager::getSingleton().remove(mName + "Material");
107  }
108 
109  if (mFontName != fontName || mpMaterial.isNull() || !mpFont)
110  {
111  mFontName = fontName;
112  mpFont
113  = (Font *) FontManager::getSingleton().getByName(mFontName).getPointer();
114  if (!mpFont)
115  throw Exception(Exception::ERR_ITEM_NOT_FOUND, "Could not find font "
116  + fontName, "MovableText::setFontName");
117 
118  mpFont->load();
119  if (!mpMaterial.isNull())
120  {
121  MaterialManager::getSingletonPtr()->remove(mpMaterial->getName());
122  mpMaterial.setNull();
123  }
124 
125  mpMaterial = mpFont->getMaterial()->clone(mName + "Material");
126  if (!mpMaterial->isLoaded())
127  mpMaterial->load();
128 
129  mpMaterial->setDepthCheckEnabled(!mOnTop);
130  mpMaterial->setDepthBias(1.0, 1.0);
131  mpMaterial->setDepthWriteEnabled(mOnTop);
132  mpMaterial->setLightingEnabled(false);
133  mNeedUpdate = true;
134  }
135 }
136 
137 void MovableText::setCaption(const String &caption)
138 {
139  if (caption != mCaption)
140  {
141  mCaption = caption;
142  mNeedUpdate = true;
143  }
144 }
145 
146 void MovableText::setColor(const ColourValue &color)
147 {
148  if (color != mColor)
149  {
150  mColor = color;
151  mUpdateColors = true;
152  }
153 }
154 
156 {
157  if (height != mCharHeight)
158  {
159  mCharHeight = height;
160  mNeedUpdate = true;
161  }
162 }
163 
165 {
166  if (height != mLineSpacing)
167  {
168  mLineSpacing = height;
169  mNeedUpdate = true;
170  }
171 }
172 
174 {
175  if (width != mSpaceWidth)
176  {
177  mSpaceWidth = width;
178  mNeedUpdate = true;
179  }
180 }
181 
183  const HorizontalAlignment& horizontalAlignment,
184  const VerticalAlignment& verticalAlignment)
185 {
186  if (mHorizontalAlignment != horizontalAlignment)
187  {
188  mHorizontalAlignment = horizontalAlignment;
189  mNeedUpdate = true;
190  }
191  if (mVerticalAlignment != verticalAlignment)
192  {
193  mVerticalAlignment = verticalAlignment;
194  mNeedUpdate = true;
195  }
196 }
197 
199 {
200  mGlobalTranslation = trans;
201 }
202 
204 {
205  mLocalTranslation = trans;
206 }
207 
208 void MovableText::showOnTop(bool show)
209 {
210  if (mOnTop != show && !mpMaterial.isNull())
211  {
212  mOnTop = show;
213  mpMaterial->setDepthBias(1.0, 1.0);
214  mpMaterial->setDepthCheckEnabled(!mOnTop);
215  mpMaterial->setDepthWriteEnabled(mOnTop);
216  }
217 }
218 
220 {
221  assert(mpFont);
222  assert(!mpMaterial.isNull());
223 
224  unsigned int vertexCount = 0;
225 
226  //count letters to determine how many vertices are needed
227  std::string::iterator i = mCaption.begin();
228  std::string::iterator iend = mCaption.end();
229  for ( ; i != iend; ++i )
230  {
231  if ((*i != ' ') && (*i != '\n'))
232  {
233  vertexCount += 6;
234  }
235  }
236 
237  if (mRenderOp.vertexData)
238  {
239  delete mRenderOp.vertexData;
240  mRenderOp.vertexData = NULL;
241  mUpdateColors = true;
242  }
243 
244  if (mCaption.empty())
245  {
246  return;
247  }
248 
249  if (!mRenderOp.vertexData)
250  mRenderOp.vertexData = new VertexData();
251 
252  mRenderOp.indexData = 0;
253  mRenderOp.vertexData->vertexStart = 0;
254  mRenderOp.vertexData->vertexCount = vertexCount;
255  mRenderOp.operationType = RenderOperation::OT_TRIANGLE_LIST;
256  mRenderOp.useIndexes = false;
257 
258  VertexDeclaration *decl = mRenderOp.vertexData->vertexDeclaration;
259  VertexBufferBinding *bind = mRenderOp.vertexData->vertexBufferBinding;
260  size_t offset = 0;
261 
262  // create/bind positions/tex.ccord. buffer
263  if (!decl->findElementBySemantic(VES_POSITION))
264  decl->addElement(POS_TEX_BINDING, offset, VET_FLOAT3, VES_POSITION);
265 
266  offset += VertexElement::getTypeSize(VET_FLOAT3);
267 
268  if (!decl->findElementBySemantic(VES_TEXTURE_COORDINATES))
269  decl->addElement(POS_TEX_BINDING, offset, Ogre::VET_FLOAT2,
270  Ogre::VES_TEXTURE_COORDINATES, 0);
271 
272  HardwareVertexBufferSharedPtr ptbuf =
273  HardwareBufferManager::getSingleton().createVertexBuffer(
274  decl->getVertexSize(POS_TEX_BINDING),
275  mRenderOp.vertexData->vertexCount,
276  HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY);
277  bind->setBinding(POS_TEX_BINDING, ptbuf);
278 
279  // Colours - store these in a separate buffer because they change less often
280  if (!decl->findElementBySemantic(VES_DIFFUSE))
281  decl->addElement(COLOUR_BINDING, 0, VET_COLOUR, VES_DIFFUSE);
282 
283  HardwareVertexBufferSharedPtr cbuf =
284  HardwareBufferManager::getSingleton().createVertexBuffer(
285  decl->getVertexSize(COLOUR_BINDING),
286  mRenderOp.vertexData->vertexCount,
287  HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY);
288  bind->setBinding(COLOUR_BINDING, cbuf);
289 
290  float *pPCBuff =
291  static_cast<float*> (ptbuf->lock(HardwareBuffer::HBL_DISCARD));
292 
293  Real spaceWidth = mSpaceWidth;
294  // Derive space width from a capital A
295  if (spaceWidth == 0)
296  spaceWidth = mpFont->getGlyphAspectRatio('A') * mCharHeight * 2.0;
297 
298  float total_height = mCharHeight;
299  float total_width = 0.0f;
300  float current_width = 0.0f;
301  i = mCaption.begin();
302  iend = mCaption.end();
303  for ( ; i != iend; ++i )
304  {
305  if (*i == '\n')
306  {
307  total_height += mCharHeight + mLineSpacing;
308 
309  if ( current_width > total_width )
310  {
311  total_width = current_width;
312  }
313  current_width = 0.0;
314  }
315  else if (*i == ' ')
316  {
317  current_width += spaceWidth;
318  }
319  else
320  {
321  current_width += mpFont->getGlyphAspectRatio(*i) * mCharHeight * 2.0;
322  }
323  }
324 
325  if ( current_width > total_width )
326  {
327  total_width = current_width;
328  }
329 
330  float top = 0.0f;
331  switch (mVerticalAlignment)
332  {
334  top = total_height * 2;
335  break;
337  top = 0.5 * total_height * 2;
338  break;
340  top = 0.0f;
341  break;
342  }
343 
344  float starting_left = 0.0f;
345  switch (mHorizontalAlignment)
346  {
347  case MovableText::H_LEFT:
348  starting_left = 0.0f;
349  break;
351  starting_left = -total_width / 2.0f;
352  break;
353  }
354 
355  float left = starting_left;
356 
357  bool newLine = true;
358  Real len = 0.0f;
359  // for calculation of AABB
360  Ogre::Vector3 min(9999999.0f), max(-9999999.0f), currPos(0.0f);
361  Ogre::Real maxSquaredRadius = -99999999.0f;
362  float largestWidth = 0.0f;
363  for (i = mCaption.begin(); i != iend; ++i)
364  {
365  if (newLine)
366  {
367  len = 0.0f;
368  for (String::iterator j = i; j != iend && *j != '\n'; j++)
369  {
370  if (*j == ' ')
371  len += spaceWidth;
372  else
373  len += mpFont->getGlyphAspectRatio(*j) * mCharHeight * 2.0;
374  }
375  newLine = false;
376  }
377 
378  if (*i == '\n')
379  {
380  left = starting_left;
381  top -= (mCharHeight + mLineSpacing) * 2.0;
382  newLine = true;
383  continue;
384  }
385 
386  if (*i == ' ')
387  {
388  // Just leave a gap, no tris
389  left += spaceWidth;
390  currPos = Ogre::Vector3(left, top, 0.0);
391  min.makeFloor(currPos);
392  max.makeCeil(currPos);
393  maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength());
394  continue;
395  }
396 
397  Real horiz_height = mpFont->getGlyphAspectRatio(*i);
398  Real u1, u2, v1, v2;
399  Ogre::Font::UVRect utmp;
400  utmp = mpFont->getGlyphTexCoords(*i);
401  u1 = utmp.left;
402  u2 = utmp.right;
403  v1 = utmp.top;
404  v2 = utmp.bottom;
405 
406  // each vert is (x, y, z, u, v)
407  //-------------------------------------------------------------------------------------
408  // First tri
409  //
410  // Upper left
411  currPos = Ogre::Vector3(left, top, 0.0);
412 
413  *pPCBuff++ = currPos.x;
414  *pPCBuff++ = currPos.y;
415  *pPCBuff++ = currPos.z;
416  *pPCBuff++ = u1;
417  *pPCBuff++ = v1;
418 
419  // Deal with bounds
420 
421 
422  min.makeFloor(currPos);
423  max.makeCeil(currPos);
424  maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength());
425 
426  top -= mCharHeight * 2.0;
427 
428  // Bottom left
429  currPos = Ogre::Vector3(left, top, 0.0);
430  *pPCBuff++ = currPos.x;
431  *pPCBuff++ = currPos.y;
432  *pPCBuff++ = currPos.z;
433  *pPCBuff++ = u1;
434  *pPCBuff++ = v2;
435 
436  // Deal with bounds
437  min.makeFloor(currPos);
438  max.makeCeil(currPos);
439  maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength());
440 
441  top += mCharHeight * 2.0;
442  left += horiz_height * mCharHeight * 2.0;
443 
444  // Top right
445  currPos = Ogre::Vector3(left, top, 0.0);
446  *pPCBuff++ = currPos.x;
447  *pPCBuff++ = currPos.y;
448  *pPCBuff++ = currPos.z;
449  *pPCBuff++ = u2;
450  *pPCBuff++ = v1;
451  //-------------------------------------------------------------------------------------
452 
453  // Deal with bounds
454  min.makeFloor(currPos);
455  max.makeCeil(currPos);
456  maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength());
457 
458  //-------------------------------------------------------------------------------------
459  // Second tri
460  //
461  // Top right (again)
462  currPos = Ogre::Vector3(left, top, 0.0);
463  *pPCBuff++ = currPos.x;
464  *pPCBuff++ = currPos.y;
465  *pPCBuff++ = currPos.z;
466  *pPCBuff++ = u2;
467  *pPCBuff++ = v1;
468 
469  min.makeFloor(currPos);
470  max.makeCeil(currPos);
471  maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength());
472 
473  top -= mCharHeight * 2.0;
474  left -= horiz_height * mCharHeight * 2.0;
475 
476  // Bottom left (again)
477  currPos = Ogre::Vector3(left, top, 0.0);
478  *pPCBuff++ = currPos.x;
479  *pPCBuff++ = currPos.y;
480  *pPCBuff++ = currPos.z;
481  *pPCBuff++ = u1;
482  *pPCBuff++ = v2;
483 
484  min.makeFloor(currPos);
485  max.makeCeil(currPos);
486  maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength());
487 
488  left += horiz_height * mCharHeight * 2.0;
489 
490  // Bottom right
491  currPos = Ogre::Vector3(left, top, 0.0);
492  *pPCBuff++ = currPos.x;
493  *pPCBuff++ = currPos.y;
494  *pPCBuff++ = currPos.z;
495  *pPCBuff++ = u2;
496  *pPCBuff++ = v2;
497  //-------------------------------------------------------------------------------------
498  min.makeFloor(currPos);
499  max.makeCeil(currPos);
500  maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength());
501 
502  // Go back up with top
503  top += mCharHeight * 2.0;
504 
505  float currentWidth = (left + 1) / 2 - 0;
506  if (currentWidth > largestWidth)
507  largestWidth = currentWidth;
508  }
509  // Taking empty last line into account for the AABB
510  if(newLine)
511  {
512  top -= mCharHeight * 2.0;
513  currPos = Ogre::Vector3(left, top, 0.0);
514  min.makeFloor(currPos);
515  max.makeCeil(currPos);
516  maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength());
517  }
518  // Unlock vertex buffer
519  ptbuf->unlock();
520 
521  // update AABB/Sphere radius
522  mAABB = Ogre::AxisAlignedBox(min, max);
523  mRadius = Ogre::Math::Sqrt(maxSquaredRadius);
524 
525  if (mUpdateColors)
526  this->_updateColors();
527 
528  mNeedUpdate = false;
529 }
530 
532 {
533  assert(mpFont);
534  assert(!mpMaterial.isNull());
535 
536  // Convert to system-specific
537  RGBA color;
538  Root::getSingleton().convertColourValue(mColor, &color);
539  HardwareVertexBufferSharedPtr vbuf =
540  mRenderOp.vertexData->vertexBufferBinding->getBuffer(COLOUR_BINDING);
541  RGBA *pDest = static_cast<RGBA*> (vbuf->lock(HardwareBuffer::HBL_DISCARD));
542  for (int i = 0; i < (int) mRenderOp.vertexData->vertexCount; ++i)
543  *pDest++ = color;
544  vbuf->unlock();
545  mUpdateColors = false;
546 }
547 
548 const Quaternion& MovableText::getWorldOrientation(void) const
549 {
550  assert(mpCam);
551  return const_cast<Quaternion&> (mpCam->getDerivedOrientation());
552 }
553 
554 #if( (OGRE_VERSION_MAJOR >= 1 && OGRE_VERSION_MINOR >= 6) || OGRE_VERSION_MAJOR >= 2 )
555 void MovableText::visitRenderables(Ogre::Renderable::Visitor* visitor, bool debugRenderables)
556 {
557  visitor->visit( this, 0, false );
558 }
559 #endif
560 
562 {
563  assert(mParentNode);
564  return mParentNode->_getDerivedPosition();
565 }
566 
567 void MovableText::getWorldTransforms(Matrix4 *xform) const
568 {
569  if (this->isVisible() && mpCam)
570  {
571  Matrix3 rot3x3, scale3x3 = Matrix3::IDENTITY;
572 
573  // store rotation in a matrix
574  mpCam->getDerivedOrientation().ToRotationMatrix(rot3x3);
575 
576  // parent node position
577  Vector3 ppos = mParentNode->_getDerivedPosition() + Vector3::UNIT_Y
579  ppos += rot3x3 * mLocalTranslation;
580 
581  // apply scale
582  scale3x3[0][0] = mParentNode->_getDerivedScale().x / 2;
583  scale3x3[1][1] = mParentNode->_getDerivedScale().y / 2;
584  scale3x3[2][2] = mParentNode->_getDerivedScale().z / 2;
585 
586  // apply all transforms to xform
587  *xform = (rot3x3 * scale3x3);
588  xform->setTrans(ppos);
589  }
590 }
591 
592 void MovableText::getRenderOperation(RenderOperation &op)
593 {
594  if (this->isVisible())
595  {
596  if (mNeedUpdate)
597  this->_setupGeometry();
598  if (mUpdateColors)
599  this->_updateColors();
600  op = mRenderOp;
601  }
602 }
603 
605 {
606  mpCam = cam;
607 }
608 
609 void MovableText::_updateRenderQueue(RenderQueue* queue)
610 {
611  if (this->isVisible())
612  {
613  if (mNeedUpdate)
614  this->_setupGeometry();
615  if (mUpdateColors)
616  this->_updateColors();
617 
618  queue->addRenderable(this, mRenderQueueID, OGRE_RENDERABLE_DEFAULT_PRIORITY);
619  //queue->addRenderable(this, mRenderQueueID, RENDER_QUEUE_SKIES_LATE);
620  }
621 }
622 
623 } // namespace rviz
624 
Ogre::Real mSpaceWidth
Definition: movable_text.h:90
#define NULL
Definition: global.h:37
Ogre::String mName
Definition: movable_text.h:78
Ogre::Real mCharHeight
Definition: movable_text.h:88
void showOnTop(bool show=true)
virtual ~MovableText()
f
#define POS_TEX_BINDING
void setGlobalTranslation(Ogre::Vector3 trans)
void getRenderOperation(Ogre::RenderOperation &op)
Ogre::RenderOperation mRenderOp
Definition: movable_text.h:84
Ogre::AxisAlignedBox mAABB
Definition: movable_text.h:85
#define COLOUR_BINDING
void setCharacterHeight(Ogre::Real height)
void setLocalTranslation(Ogre::Vector3 trans)
const Ogre::Quaternion & getWorldOrientation(void) const
Ogre::Real mRadius
Definition: movable_text.h:97
VerticalAlignment mVerticalAlignment
Definition: movable_text.h:81
void getWorldTransforms(Ogre::Matrix4 *xform) const
Ogre::Real mLineSpacing
Definition: movable_text.h:89
Ogre::Vector3 mGlobalTranslation
Definition: movable_text.h:99
HorizontalAlignment mHorizontalAlignment
Definition: movable_text.h:80
void _notifyCurrentCamera(Ogre::Camera *cam)
void _updateRenderQueue(Ogre::RenderQueue *queue)
TFSIMD_FORCE_INLINE Vector3()
void setCaption(const Ogre::String &caption)
Ogre::Camera * mpCam
Definition: movable_text.h:102
void setSpaceWidth(Ogre::Real width)
void setTextAlignment(const HorizontalAlignment &horizontalAlignment, const VerticalAlignment &verticalAlignment)
Ogre::Font * mpFont
Definition: movable_text.h:104
void setLineSpacing(Ogre::Real height)
const Ogre::Vector3 & getWorldPosition(void) const
void setColor(const Ogre::ColourValue &color)
Ogre::Vector3 mLocalTranslation
Definition: movable_text.h:100
Ogre::String mFontName
Definition: movable_text.h:76
int min(int a, int b)
Ogre::MaterialPtr mpMaterial
Definition: movable_text.h:105
void setFontName(const Ogre::String &fontName)
Ogre::ColourValue mColor
Definition: movable_text.h:83
Ogre::String mCaption
Definition: movable_text.h:79


rviz
Author(s): Dave Hershberger, David Gossow, Josh Faust
autogenerated on Wed Aug 28 2019 04:01:51