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 <Overlay/OgreFontManager.h>
52 #include <Overlay/OgreFont.h>
53 #include <OgreUTFString.h>
54 
55 #include <sstream>
56 
57 using namespace Ogre;
58 
59 #define POS_TEX_BINDING 0
60 #define COLOUR_BINDING 1
61 
62 namespace rviz
63 {
64 MovableText::MovableText(const String& caption,
65  const String& fontName,
66  Real charHeight,
67  const ColourValue& color)
68  : mFontName(fontName)
69  , mType("MovableText")
70  , mCaption(caption)
71  , mHorizontalAlignment(H_LEFT)
72  , mVerticalAlignment(V_BELOW)
73  , mColor(color)
74  , mCharHeight(charHeight)
75  , mLineSpacing(0.01)
76  , mSpaceWidth(0)
77  , mUpdateColors(true)
78  , mOnTop(false)
79  , mTimeUntilNextToggle(0)
80  , mGlobalTranslation(0.0)
81  , mLocalTranslation(0.0)
82  , mpCam(nullptr)
83  , mpWin(nullptr)
84  , mpFont(nullptr)
85 {
86  static int count = 0;
87  std::stringstream ss;
88  ss << "MovableText" << count++;
89  mName = ss.str();
90 
91  mRenderOp.vertexData = nullptr;
92  this->setFontName(mFontName);
93  this->_setupGeometry();
94 }
95 
97 {
98  if (mRenderOp.vertexData)
99  delete mRenderOp.vertexData;
100  // May cause crashing... check this and comment if it does
101  if (!mpMaterial.isNull())
102  MaterialManager::getSingletonPtr()->remove(mpMaterial->getName());
103 }
104 
105 void MovableText::setFontName(const String& fontName)
106 {
107  if ((Ogre::MaterialManager::getSingletonPtr()->resourceExists(mName + "Material")))
108  {
109  Ogre::MaterialManager::getSingleton().remove(mName + "Material");
110  }
111 
112  if (mFontName != fontName || mpMaterial.isNull() || !mpFont)
113  {
114  mFontName = fontName;
115  mpFont = (Font*)FontManager::getSingleton().getByName(mFontName).getPointer();
116  if (!mpFont)
117  throw Exception(Exception::ERR_ITEM_NOT_FOUND, "Could not find font " + fontName,
118  "MovableText::setFontName");
119 
120  // to support non-ascii letters, setup the codepoint range before loading
121  mpFont->addCodePointRange(std::make_pair<Ogre::Font::CodePoint>(0, 999));
122  mpFont->load();
123  if (!mpMaterial.isNull())
124  {
125  MaterialManager::getSingletonPtr()->remove(mpMaterial->getName());
126  mpMaterial.setNull();
127  }
128 
129  mpMaterial = mpFont->getMaterial()->clone(mName + "Material");
130  if (!mpMaterial->isLoaded())
131  mpMaterial->load();
132 
133  mpMaterial->setDepthCheckEnabled(!mOnTop);
134  mpMaterial->setDepthBias(1.0, 1.0);
135  mpMaterial->setDepthWriteEnabled(mOnTop);
136  mpMaterial->setLightingEnabled(false);
137  mNeedUpdate = true;
138  }
139 }
140 
141 void MovableText::setCaption(const String& caption)
142 {
143  if (caption != mCaption)
144  {
145  mCaption = caption;
146  mNeedUpdate = true;
147  }
148 }
149 
150 void MovableText::setColor(const ColourValue& color)
151 {
152  if (color != mColor)
153  {
154  mColor = color;
155  mUpdateColors = true;
156  }
157 }
158 
160 {
161  if (height != mCharHeight)
162  {
163  mCharHeight = height;
164  mNeedUpdate = true;
165  }
166 }
167 
169 {
170  if (height != mLineSpacing)
171  {
172  mLineSpacing = height;
173  mNeedUpdate = true;
174  }
175 }
176 
178 {
179  if (width != mSpaceWidth)
180  {
181  mSpaceWidth = width;
182  mNeedUpdate = true;
183  }
184 }
185 
186 void MovableText::setTextAlignment(const HorizontalAlignment& horizontalAlignment,
187  const VerticalAlignment& verticalAlignment)
188 {
189  if (mHorizontalAlignment != horizontalAlignment)
190  {
191  mHorizontalAlignment = horizontalAlignment;
192  mNeedUpdate = true;
193  }
194  if (mVerticalAlignment != verticalAlignment)
195  {
196  mVerticalAlignment = verticalAlignment;
197  mNeedUpdate = true;
198  }
199 }
200 
202 {
203  mGlobalTranslation = trans;
204 }
205 
207 {
208  mLocalTranslation = trans;
209 }
210 
211 void MovableText::showOnTop(bool show)
212 {
213  if (mOnTop != show && !mpMaterial.isNull())
214  {
215  mOnTop = show;
216  mpMaterial->setDepthBias(1.0, 1.0);
217  mpMaterial->setDepthCheckEnabled(!mOnTop);
218  mpMaterial->setDepthWriteEnabled(mOnTop);
219  }
220 }
221 
223 {
224  Ogre::UTFString::utf32string utfCaption(Ogre::UTFString(mCaption).asUTF32());
225 
226  assert(mpFont);
227  assert(!mpMaterial.isNull());
228 
229  unsigned int vertexCount = 0;
230 
231  // count letters to determine how many vertices are needed
232  for (auto ch : utfCaption)
233  {
234  if ((ch != ' ') && (ch != '\n'))
235  {
236  vertexCount += 6;
237  }
238  }
239 
240  if (mRenderOp.vertexData)
241  {
242  delete mRenderOp.vertexData;
243  mRenderOp.vertexData = nullptr;
244  mUpdateColors = true;
245  }
246 
247  if (vertexCount == 0)
248  {
249  return;
250  }
251 
252  if (!mRenderOp.vertexData)
253  mRenderOp.vertexData = new VertexData();
254 
255  mRenderOp.indexData = nullptr;
256  mRenderOp.vertexData->vertexStart = 0;
257  mRenderOp.vertexData->vertexCount = vertexCount;
258  mRenderOp.operationType = RenderOperation::OT_TRIANGLE_LIST;
259  mRenderOp.useIndexes = false;
260 
261  VertexDeclaration* decl = mRenderOp.vertexData->vertexDeclaration;
262  VertexBufferBinding* bind = mRenderOp.vertexData->vertexBufferBinding;
263  size_t offset = 0;
264 
265  // create/bind positions/tex.ccord. buffer
266  if (!decl->findElementBySemantic(VES_POSITION))
267  decl->addElement(POS_TEX_BINDING, offset, VET_FLOAT3, VES_POSITION);
268 
269  offset += VertexElement::getTypeSize(VET_FLOAT3);
270 
271  if (!decl->findElementBySemantic(VES_TEXTURE_COORDINATES))
272  decl->addElement(POS_TEX_BINDING, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, 0);
273 
274  HardwareVertexBufferSharedPtr ptbuf =
275  HardwareBufferManager::getSingleton().createVertexBuffer(decl->getVertexSize(POS_TEX_BINDING),
276  mRenderOp.vertexData->vertexCount,
277  HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY);
278  bind->setBinding(POS_TEX_BINDING, ptbuf);
279 
280  // Colours - store these in a separate buffer because they change less often
281  if (!decl->findElementBySemantic(VES_DIFFUSE))
282  decl->addElement(COLOUR_BINDING, 0, VET_COLOUR, VES_DIFFUSE);
283 
284  HardwareVertexBufferSharedPtr cbuf =
285  HardwareBufferManager::getSingleton().createVertexBuffer(decl->getVertexSize(COLOUR_BINDING),
286  mRenderOp.vertexData->vertexCount,
287  HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY);
288  bind->setBinding(COLOUR_BINDING, cbuf);
289 
290  float* pPCBuff = static_cast<float*>(ptbuf->lock(HardwareBuffer::HBL_DISCARD));
291 
292  Real spaceWidth = mSpaceWidth;
293  // Derive space width from a capital A
294  if (spaceWidth == 0)
295  spaceWidth = mpFont->getGlyphAspectRatio('A') * mCharHeight;
296 
297  float total_height = mCharHeight;
298  float total_width = 0.0f;
299  float current_width = 0.0f;
300  for (auto ch : utfCaption)
301  {
302  if (ch == '\n')
303  {
304  total_height += mCharHeight + mLineSpacing;
305 
306  if (current_width > total_width)
307  {
308  total_width = current_width;
309  }
310  current_width = 0.0;
311  }
312  else if (ch == ' ')
313  {
314  current_width += spaceWidth;
315  }
316  else
317  {
318  current_width += mpFont->getGlyphAspectRatio(ch) * mCharHeight;
319  }
320  }
321 
322  if (current_width > total_width)
323  {
324  total_width = current_width;
325  }
326 
327  float top = 0.0f;
328  switch (mVerticalAlignment)
329  {
331  top = total_height;
332  break;
334  top = 0.5 * total_height;
335  break;
337  top = 0.0f;
338  break;
339  }
340 
341  float starting_left = 0.0f;
342  switch (mHorizontalAlignment)
343  {
344  case MovableText::H_LEFT:
345  starting_left = 0.0f;
346  break;
348  starting_left = -total_width / 2.0f;
349  break;
350  }
351 
352  float left = starting_left;
353 
354  // for calculation of AABB
355  Ogre::Vector3 currPos(0.0f);
356  Ogre::Vector3 min(starting_left, top - total_height, 0.0f);
357  Ogre::Vector3 max(starting_left + total_width, top, 0.0f);
358  auto iend = utfCaption.end();
359  for (auto i = utfCaption.begin(); i != iend; ++i)
360  {
361  if (*i == '\n')
362  {
363  left = starting_left;
364  top -= mCharHeight + mLineSpacing;
365  continue;
366  }
367 
368  if (*i == ' ')
369  {
370  // Just leave a gap, no tris
371  left += spaceWidth;
372  continue;
373  }
374 
375  Real char_width = mpFont->getGlyphAspectRatio(*i) * mCharHeight;
376  Real u1, u2, v1, v2;
377  Ogre::Font::UVRect utmp;
378  utmp = mpFont->getGlyphTexCoords(*i);
379  u1 = utmp.left;
380  u2 = utmp.right;
381  v1 = utmp.top;
382  v2 = utmp.bottom;
383 
384  // each vert is (x, y, z, u, v)
385  //-------------------------------------------------------------------------------------
386  // First tri
387  //
388  // Upper left
389  currPos = Ogre::Vector3(left, top, 0.0);
390 
391  *pPCBuff++ = currPos.x;
392  *pPCBuff++ = currPos.y;
393  *pPCBuff++ = currPos.z;
394  *pPCBuff++ = u1;
395  *pPCBuff++ = v1;
396 
397  top -= mCharHeight;
398 
399  // Bottom left
400  currPos = Ogre::Vector3(left, top, 0.0);
401  *pPCBuff++ = currPos.x;
402  *pPCBuff++ = currPos.y;
403  *pPCBuff++ = currPos.z;
404  *pPCBuff++ = u1;
405  *pPCBuff++ = v2;
406 
407  top += mCharHeight;
408  left += char_width;
409 
410  // Top right
411  currPos = Ogre::Vector3(left, top, 0.0);
412  *pPCBuff++ = currPos.x;
413  *pPCBuff++ = currPos.y;
414  *pPCBuff++ = currPos.z;
415  *pPCBuff++ = u2;
416  *pPCBuff++ = v1;
417 
418  //-------------------------------------------------------------------------------------
419  // Second tri
420  //
421  // Top right (again)
422  currPos = Ogre::Vector3(left, top, 0.0);
423  *pPCBuff++ = currPos.x;
424  *pPCBuff++ = currPos.y;
425  *pPCBuff++ = currPos.z;
426  *pPCBuff++ = u2;
427  *pPCBuff++ = v1;
428 
429  top -= mCharHeight;
430  left -= char_width;
431 
432  // Bottom left (again)
433  currPos = Ogre::Vector3(left, top, 0.0);
434  *pPCBuff++ = currPos.x;
435  *pPCBuff++ = currPos.y;
436  *pPCBuff++ = currPos.z;
437  *pPCBuff++ = u1;
438  *pPCBuff++ = v2;
439 
440  left += char_width;
441 
442  // Bottom right
443  currPos = Ogre::Vector3(left, top, 0.0);
444  *pPCBuff++ = currPos.x;
445  *pPCBuff++ = currPos.y;
446  *pPCBuff++ = currPos.z;
447  *pPCBuff++ = u2;
448  *pPCBuff++ = v2;
449  //-------------------------------------------------------------------------------------
450 
451  // Go back up with top
452  top += mCharHeight;
453  }
454  ptbuf->unlock();
455 
456  // update AABB/Sphere radius
457  mAABB = Ogre::AxisAlignedBox(min, max);
458  mRadius =
459  Ogre::Math::Sqrt(std::max(mAABB.getMinimum().squaredLength(), mAABB.getMaximum().squaredLength()));
460 
461  if (mUpdateColors)
462  this->_updateColors();
463 
464  mNeedUpdate = false;
465 }
466 
468 {
469  assert(mpFont);
470  assert(!mpMaterial.isNull());
471 
472  // Convert to system-specific
473  RGBA color;
474  Root::getSingleton().convertColourValue(mColor, &color);
475  HardwareVertexBufferSharedPtr vbuf =
476  mRenderOp.vertexData->vertexBufferBinding->getBuffer(COLOUR_BINDING);
477  RGBA* pDest = static_cast<RGBA*>(vbuf->lock(HardwareBuffer::HBL_DISCARD));
478  for (int i = 0; i < (int)mRenderOp.vertexData->vertexCount; ++i)
479  *pDest++ = color;
480  vbuf->unlock();
481  mUpdateColors = false;
482 }
483 
484 const Quaternion& MovableText::getWorldOrientation() const
485 {
486  assert(mpCam);
487  return const_cast<Quaternion&>(mpCam->getDerivedOrientation());
488 }
489 
490 #if ((OGRE_VERSION_MAJOR >= 1 && OGRE_VERSION_MINOR >= 6) || OGRE_VERSION_MAJOR >= 2)
491 void MovableText::visitRenderables(Ogre::Renderable::Visitor* visitor, bool /*debugRenderables*/)
492 {
493  visitor->visit(this, 0, false);
494 }
495 #endif
496 
498 {
499  assert(mParentNode);
500  return mParentNode->_getDerivedPosition();
501 }
502 
503 void MovableText::getWorldTransforms(Matrix4* xform) const
504 {
505  if (this->isVisible() && mpCam)
506  {
507  Matrix3 rot3x3, scale3x3 = Matrix3::IDENTITY;
508 
509  // store rotation in a matrix
510  mpCam->getDerivedOrientation().ToRotationMatrix(rot3x3);
511 
512  // parent node position
513  Vector3 ppos = mParentNode->_getDerivedPosition() + mGlobalTranslation;
514  ppos += rot3x3 * mLocalTranslation;
515 
516  // apply scale
517  scale3x3[0][0] = mParentNode->_getDerivedScale().x;
518  scale3x3[1][1] = mParentNode->_getDerivedScale().y;
519  scale3x3[2][2] = mParentNode->_getDerivedScale().z;
520 
521  // apply all transforms to xform
522  *xform = (rot3x3 * scale3x3);
523  xform->setTrans(ppos);
524  }
525 }
526 
527 void MovableText::getRenderOperation(RenderOperation& op)
528 {
529  if (this->isVisible())
530  {
531  if (mNeedUpdate)
532  this->_setupGeometry();
533  if (mUpdateColors)
534  this->_updateColors();
535  op = mRenderOp;
536  }
537 }
538 
540 {
541  mpCam = cam;
542 }
543 
544 void MovableText::_updateRenderQueue(RenderQueue* queue)
545 {
546  if (this->isVisible())
547  {
548  if (mNeedUpdate)
549  this->_setupGeometry();
550  if (mUpdateColors)
551  this->_updateColors();
552 
553  queue->addRenderable(this, mRenderQueueID, OGRE_RENDERABLE_DEFAULT_PRIORITY);
554  // queue->addRenderable(this, mRenderQueueID, RENDER_QUEUE_SKIES_LATE);
555  }
556 }
557 
558 } // namespace rviz
Ogre::Real mSpaceWidth
Definition: movable_text.h:92
Ogre::String mName
Definition: movable_text.h:80
void getWorldTransforms(Ogre::Matrix4 *xform) const override
Ogre::Real mCharHeight
Definition: movable_text.h:90
void showOnTop(bool show=true)
const Ogre::Quaternion & getWorldOrientation() const
f
#define POS_TEX_BINDING
void setGlobalTranslation(Ogre::Vector3 trans)
Ogre::RenderOperation mRenderOp
Definition: movable_text.h:86
Ogre::AxisAlignedBox mAABB
Definition: movable_text.h:87
#define COLOUR_BINDING
void setCharacterHeight(Ogre::Real height)
void setLocalTranslation(Ogre::Vector3 trans)
void getRenderOperation(Ogre::RenderOperation &op) override
Ogre::Real mRadius
Definition: movable_text.h:99
void _notifyCurrentCamera(Ogre::Camera *cam) override
VerticalAlignment mVerticalAlignment
Definition: movable_text.h:83
Ogre::Real mLineSpacing
Definition: movable_text.h:91
Ogre::Vector3 mGlobalTranslation
Definition: movable_text.h:101
HorizontalAlignment mHorizontalAlignment
Definition: movable_text.h:82
void setCaption(const Ogre::String &caption)
Ogre::Camera * mpCam
Definition: movable_text.h:104
void setSpaceWidth(Ogre::Real width)
double min(double a, double b)
void setTextAlignment(const HorizontalAlignment &horizontalAlignment, const VerticalAlignment &verticalAlignment)
Ogre::Font * mpFont
Definition: movable_text.h:106
void setLineSpacing(Ogre::Real height)
void setColor(const Ogre::ColourValue &color)
Ogre::Vector3 mLocalTranslation
Definition: movable_text.h:102
Ogre::String mFontName
Definition: movable_text.h:78
Ogre::MaterialPtr mpMaterial
Definition: movable_text.h:107
bool isVisible(PanelDockWidget *widget)
Definition: display.cpp:297
void setFontName(const Ogre::String &fontName)
void _updateRenderQueue(Ogre::RenderQueue *queue) override
~MovableText() override
double max(double a, double b)
Ogre::ColourValue mColor
Definition: movable_text.h:85
const Ogre::Vector3 & getWorldPosition() const
Ogre::String mCaption
Definition: movable_text.h:81


rviz
Author(s): Dave Hershberger, David Gossow, Josh Faust
autogenerated on Sat May 27 2023 02:06:24