Rigs of Rods 2023.09
Soft-body Physics Simulation
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Loading...
Searching...
No Matches
MovableText.cpp
Go to the documentation of this file.
1/*
2 This source file is part of Rigs of Rods
3 Copyright 2005-2012 Pierre-Michel Ricordel
4 Copyright 2007-2012 Thomas Fischer
5
6 For more information, see http://www.rigsofrods.org/
7
8 Rigs of Rods is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License version 3, as
10 published by the Free Software Foundation.
11
12 Rigs of Rods is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Rigs of Rods. If not, see <http://www.gnu.org/licenses/>.
19*/
20
25
26#include "MovableText.h"
27
28#include <Ogre.h>
29#include <Overlay/OgreFontManager.h>
30
31using namespace Ogre;
32using namespace RoR;
33
34#define POS_TEX_BINDING 0
35#define COLOUR_BINDING 1
36
37MovableText::MovableText(const std::string& name, const std::string& caption, const std::string& fontName, Real charHeight, const ColourValue& color)
38 : mpCam(NULL)
39 , mpWin(NULL)
40 , mpFont(NULL)
41 , mName(name)
42 , mCaption(caption)
43 , mFontName(fontName)
44 , mCharHeight(charHeight)
45 , mColor(color)
46 , mType("MovableText")
47 , mTimeUntilNextToggle(0)
48 , mSpaceWidth(0.2f)
49 , mUpdateColors(true)
50 , mOnTop(false)
51 , mHorizontalAlignment(H_LEFT)
52 , mVerticalAlignment(V_BELOW)
53 , mAdditionalHeight(0.0)
54{
55 if (name == "")
56 throw Exception(Exception::ERR_INVALIDPARAMS, "Trying to create MovableText without name", "MovableText::MovableText");
57
58 if (caption == "")
59 // throw Exception(Exception::ERR_INVALIDPARAMS, "Trying to create MovableText without caption", "MovableText::MovableText");
60 mCaption = ".";
61
62 mRenderOp.vertexData = NULL;
64 this->_setupGeometry();
65}
66
68{
69 if (mRenderOp.vertexData)
70 delete mRenderOp.vertexData;
71}
72
73void MovableText::setFontName(const std::string& fontName)
74{
75 if ((Ogre::MaterialManager::getSingletonPtr()->resourceExists(mName + "Material")))
76 {
77 Ogre::MaterialManager::getSingleton().remove(mName + "Material");
78 }
79
80 if (mFontName != fontName || !mpMaterial || !mpFont)
81 {
82 mFontName = fontName;
83 mpFont = (Ogre::Font *)FontManager::getSingleton().getResourceByName(mFontName).get();
84
85 if (!mpFont)
86 throw Exception(Exception::ERR_ITEM_NOT_FOUND, "Could not find font " + fontName, "MovableText::setFontName");
87
88 mpFont->load();
89 if (mpMaterial)
90 {
91 MaterialManager::getSingletonPtr()->remove(mpMaterial->getName());
92 mpMaterial.reset();
93 }
94
95 mpMaterial = mpFont->getMaterial()->clone(mName + "Material");
96 if (!mpMaterial->isLoaded())
97 mpMaterial->load();
98
99 mpMaterial->setDepthCheckEnabled(!mOnTop);
100 mpMaterial->setDepthBias(1.0, 1.0);
101 mpMaterial->setFog(true);
102 mpMaterial->setDepthWriteEnabled(mOnTop);
103 mpMaterial->setLightingEnabled(false);
104 mNeedUpdate = true;
105 }
106}
107
108void MovableText::setCaption(const std::string& caption)
109{
110 if (caption != mCaption)
111 {
112 mCaption = caption;
113 mNeedUpdate = true;
114 }
115}
116
117void MovableText::setColor(const ColourValue& color)
118{
119 if (color != mColor)
120 {
121 mColor = color;
122 mUpdateColors = true;
123 }
124}
125
127{
128 if (fabs(height - mCharHeight) > 0.00001f)
129 {
130 mCharHeight = height;
131 mNeedUpdate = true;
132 }
133}
134
136{
137 if (fabs(width - mSpaceWidth) > 0.00001f)
138 {
139 mSpaceWidth = width;
140 mNeedUpdate = true;
141 }
142}
143
144void MovableText::setTextAlignment(const HorizontalAlignment& horizontalAlignment, const VerticalAlignment& verticalAlignment)
145{
146 if (mHorizontalAlignment != horizontalAlignment)
147 {
148 mHorizontalAlignment = horizontalAlignment;
149 mNeedUpdate = true;
150 }
151 if (mVerticalAlignment != verticalAlignment)
152 {
153 mVerticalAlignment = verticalAlignment;
154 mNeedUpdate = true;
155 }
156}
157
159{
160 if (fabs(mAdditionalHeight - height) > 0.00001f)
161 {
162 mAdditionalHeight = height;
163 mNeedUpdate = true;
164 }
165}
166
168{
169 if (mOnTop != show && mpMaterial)
170 {
171 mOnTop = show;
172 mpMaterial->setDepthBias(1.0, 1.0);
173 mpMaterial->setDepthCheckEnabled(!mOnTop);
174 mpMaterial->setDepthWriteEnabled(mOnTop);
175 }
176}
177
179{
182
183 uint vertexCount = static_cast<uint>(mCaption.size() * 6);
184
185 if (mRenderOp.vertexData)
186 {
187 // Removed this test as it causes problems when replacing a caption
188 // of the same size: replacing "Hello" with "hello"
189 // as well as when changing the text alignment
190 //if (mRenderOp.vertexData->vertexCount != vertexCount)
191 {
192 delete mRenderOp.vertexData;
193 mRenderOp.vertexData = NULL;
194 mUpdateColors = true;
195 }
196 }
197
198 if (!mRenderOp.vertexData)
199 mRenderOp.vertexData = new VertexData();
200
201 mRenderOp.indexData = 0;
202 mRenderOp.vertexData->vertexStart = 0;
203 mRenderOp.vertexData->vertexCount = vertexCount;
204 mRenderOp.operationType = RenderOperation::OT_TRIANGLE_LIST;
205 mRenderOp.useIndexes = false;
206
207 VertexDeclaration* decl = mRenderOp.vertexData->vertexDeclaration;
208 VertexBufferBinding* bind = mRenderOp.vertexData->vertexBufferBinding;
209 size_t offset = 0;
210
211 // create/bind positions/tex.ccord. buffer
212 if (!decl->findElementBySemantic(VES_POSITION))
213 decl->addElement(POS_TEX_BINDING, offset, VET_FLOAT3, VES_POSITION);
214
215 offset += VertexElement::getTypeSize(VET_FLOAT3);
216
217 if (!decl->findElementBySemantic(VES_TEXTURE_COORDINATES))
218 decl->addElement(POS_TEX_BINDING, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, 0);
219
220 HardwareVertexBufferSharedPtr ptbuf = HardwareBufferManager::getSingleton().createVertexBuffer(decl->getVertexSize(POS_TEX_BINDING),
221 mRenderOp.vertexData->vertexCount,
222 HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY);
223 bind->setBinding(POS_TEX_BINDING, ptbuf);
224
225 // Colours - store these in a separate buffer because they change less often
226 if (!decl->findElementBySemantic(VES_DIFFUSE))
227 decl->addElement(COLOUR_BINDING, 0, VET_COLOUR, VES_DIFFUSE);
228
229 HardwareVertexBufferSharedPtr cbuf = HardwareBufferManager::getSingleton().createVertexBuffer(decl->getVertexSize(COLOUR_BINDING),
230 mRenderOp.vertexData->vertexCount,
231 HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY);
232 bind->setBinding(COLOUR_BINDING, cbuf);
233
234 //Real *pPCBuff = static_cast<Real*>(ptbuf->lock(HardwareBuffer::HBL_NORMAL));
235 Real* pPCBuff = (Real*)malloc(ptbuf->getSizeInBytes());
236 Real* oPCBuff = pPCBuff;
237
238 float largestWidth = 0;
239 float left = 0 * 2.0 - 1.0;
240 float top = -((0 * 2.0) - 1.0);
241
242 // Derive space width from a capital A
243 if (fabs(mSpaceWidth) < 0.00001f)
244 mSpaceWidth = mpFont->getGlyphAspectRatio('A') * mCharHeight * 2.0;
245
246 // for calculation of AABB
247 Ogre::Vector3 min = Ogre::Vector3::ZERO, max = Ogre::Vector3::ZERO, currPos = Ogre::Vector3::ZERO;
248 Ogre::Real maxSquaredRadius = 0.0f;
249 bool first = true;
250
251 // Use iterator
252 std::string::iterator i, iend;
253 iend = mCaption.end();
254 bool newLine = true;
255 Real len = 0.0f;
256
258 {
259 // Raise the first line of the caption
260 top += mCharHeight;
261 for (i = mCaption.begin(); i != iend; ++i)
262 {
263 if (*i == '\n')
264 top += mCharHeight * 2.0;
265 }
266 }
267
268 for (i = mCaption.begin(); i != iend; ++i)
269 {
270 if (newLine)
271 {
272 len = 0.0f;
273 for (std::string::iterator j = i; j != iend && *j != '\n'; j++)
274 {
275 if (*j == ' ')
276 len += mSpaceWidth;
277 else
278 len += mpFont->getGlyphAspectRatio(*j) * mCharHeight * 2.0;
279 }
280 newLine = false;
281 }
282
283 if (*i == '\n')
284 {
285 left = 0 * 2.0 - 1.0;
286 top -= mCharHeight * 2.0;
287 newLine = true;
288 continue;
289 }
290
291 if (*i == ' ')
292 {
293 // Just leave a gap, no tris
294 left += mSpaceWidth;
295 // Also reduce tri count
296 mRenderOp.vertexData->vertexCount -= 6;
297 continue;
298 }
299
300 Real horiz_height = mpFont->getGlyphAspectRatio(*i);
301 Real u1, u2, v1, v2;
302 Ogre::Font::UVRect utmp;
303 utmp = mpFont->getGlyphTexCoords(*i);
304 u1 = utmp.left;
305 u2 = utmp.right;
306 v1 = utmp.top;
307 v2 = utmp.bottom;
308
309 // each vert is (x, y, z, u, v)
310 //-------------------------------------------------------------------------------------
311 // First tri
312 //
313 // Upper left
315 *pPCBuff++ = left;
316 else
317 *pPCBuff++ = left - (len / 2);
318 *pPCBuff++ = top;
319 *pPCBuff++ = -1.0;
320 *pPCBuff++ = u1;
321 *pPCBuff++ = v1;
322
323 // Deal with bounds
325 currPos = Ogre::Vector3(left, top, -1.0);
326 else
327 currPos = Ogre::Vector3(left - (len / 2), top, -1.0);
328 if (first)
329 {
330 min = max = currPos;
331 maxSquaredRadius = currPos.squaredLength();
332 first = false;
333 }
334 else
335 {
336 min.makeFloor(currPos);
337 max.makeCeil(currPos);
338 maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength());
339 }
340
341 top -= mCharHeight * 2.0;
342
343 // Bottom left
345 *pPCBuff++ = left;
346 else
347 *pPCBuff++ = left - (len / 2);
348 *pPCBuff++ = top;
349 *pPCBuff++ = -1.0;
350 *pPCBuff++ = u1;
351 *pPCBuff++ = v2;
352
353 // Deal with bounds
355 currPos = Ogre::Vector3(left, top, -1.0);
356 else
357 currPos = Ogre::Vector3(left - (len / 2), top, -1.0);
358 min.makeFloor(currPos);
359 max.makeCeil(currPos);
360 maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength());
361
362 top += mCharHeight * 2.0;
363 left += horiz_height * mCharHeight * 2.0;
364
365 // Top right
367 *pPCBuff++ = left;
368 else
369 *pPCBuff++ = left - (len / 2);
370 *pPCBuff++ = top;
371 *pPCBuff++ = -1.0;
372 *pPCBuff++ = u2;
373 *pPCBuff++ = v1;
374 //-------------------------------------------------------------------------------------
375
376 // Deal with bounds
378 currPos = Ogre::Vector3(left, top, -1.0);
379 else
380 currPos = Ogre::Vector3(left - (len / 2), top, -1.0);
381 min.makeFloor(currPos);
382 max.makeCeil(currPos);
383 maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength());
384
385 //-------------------------------------------------------------------------------------
386 // Second tri
387 //
388 // Top right (again)
390 *pPCBuff++ = left;
391 else
392 *pPCBuff++ = left - (len / 2);
393 *pPCBuff++ = top;
394 *pPCBuff++ = -1.0;
395 *pPCBuff++ = u2;
396 *pPCBuff++ = v1;
397
398 currPos = Ogre::Vector3(left, top, -1.0);
399 min.makeFloor(currPos);
400 max.makeCeil(currPos);
401 maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength());
402
403 top -= mCharHeight * 2.0;
404 left -= horiz_height * mCharHeight * 2.0;
405
406 // Bottom left (again)
408 *pPCBuff++ = left;
409 else
410 *pPCBuff++ = left - (len / 2);
411 *pPCBuff++ = top;
412 *pPCBuff++ = -1.0;
413 *pPCBuff++ = u1;
414 *pPCBuff++ = v2;
415
416 currPos = Ogre::Vector3(left, top, -1.0);
417 min.makeFloor(currPos);
418 max.makeCeil(currPos);
419 maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength());
420
421 left += horiz_height * mCharHeight * 2.0;
422
423 // Bottom right
425 *pPCBuff++ = left;
426 else
427 *pPCBuff++ = left - (len / 2);
428 *pPCBuff++ = top;
429 *pPCBuff++ = -1.0;
430 *pPCBuff++ = u2;
431 *pPCBuff++ = v2;
432 //-------------------------------------------------------------------------------------
433
434 currPos = Ogre::Vector3(left, top, -1.0);
435 min.makeFloor(currPos);
436 max.makeCeil(currPos);
437 maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength());
438
439 // Go back up with top
440 top += mCharHeight * 2.0;
441
442 float currentWidth = (left + 1) / 2 - 0;
443 if (currentWidth > largestWidth)
444 largestWidth = currentWidth;
445 }
446
447 // Unlock vertex buffer
448 //ptbuf->unlock();
449 ptbuf->writeData(0, ptbuf->getSizeInBytes(), oPCBuff, true);
450 free(oPCBuff);
451
452 // update AABB/Sphere radius
453 mAABB = Ogre::AxisAlignedBox(min, max);
454 mRadius = Ogre::Math::Sqrt(maxSquaredRadius);
455
456 if (mUpdateColors)
457 this->_updateColors();
458
459 mNeedUpdate = false;
460}
461
463{
466
467 // Convert to system-specific
468 RGBA color;
469 Root::getSingleton().convertColourValue(mColor, &color);
470 HardwareVertexBufferSharedPtr vbuf = mRenderOp.vertexData->vertexBufferBinding->getBuffer(COLOUR_BINDING);
471 //RGBA *pDest = static_cast<RGBA*>(vbuf->lock(HardwareBuffer::HBL_NORMAL));
472 RGBA* pDest = (RGBA*)malloc(vbuf->getSizeInBytes());
473 ROR_ASSERT(pDest);
474 if (!pDest)
475 {
476 return;
477 }
478 RGBA* oDest = pDest;
479 for (uint i = 0; i < mRenderOp.vertexData->vertexCount; ++i)
480 {
481 *pDest++ = color;
482 }
483 //vbuf->unlock();
484 vbuf->writeData(0, vbuf->getSizeInBytes(), oDest, true);
485 free(oDest);
486 mUpdateColors = false;
487}
488
489const Quaternion& MovableText::getWorldOrientation(void) const
490{
492 return const_cast<Quaternion&>(mpCam->getDerivedOrientation());
493}
494
495const Vector3& MovableText::getWorldPosition(void) const
496{
497 ROR_ASSERT(mParentNode);
498 return mParentNode->_getDerivedPosition();
499}
500
501void MovableText::getWorldTransforms(Matrix4* xform) const
502{
503 if (this->isVisible() && mpCam)
504 {
505 Matrix3 rot3x3, scale3x3 = Matrix3::IDENTITY;
506
507 // store rotation in a matrix
508 mpCam->getDerivedOrientation().ToRotationMatrix(rot3x3);
509
510 // parent node position
511 Vector3 ppos = mParentNode->_getDerivedPosition() + Vector3::UNIT_Y * mAdditionalHeight;
512
513 // apply scale
514 scale3x3[0][0] = mParentNode->_getDerivedScale().x / 2;
515 scale3x3[1][1] = mParentNode->_getDerivedScale().y / 2;
516 scale3x3[2][2] = mParentNode->_getDerivedScale().z / 2;
517
518 // apply all transforms to xform
519 *xform = (rot3x3 * scale3x3);
520 xform->setTrans(ppos);
521 }
522}
523
524void MovableText::getRenderOperation(RenderOperation& op)
525{
526 if (this->isVisible())
527 {
528 if (mNeedUpdate)
529 this->_setupGeometry();
530 if (mUpdateColors)
531 this->_updateColors();
532 op = mRenderOp;
533 }
534}
535
537{
538 mpCam = cam;
539}
540
541void MovableText::_updateRenderQueue(RenderQueue* queue)
542{
543 if (this->isVisible())
544 {
545 if (mNeedUpdate)
546 this->_setupGeometry();
547 if (mUpdateColors)
548 this->_updateColors();
549
550 queue->addRenderable(this, mRenderQueueID, OGRE_RENDERABLE_DEFAULT_PRIORITY);
551 // queue->addRenderable(this, mRenderQueueID, RENDER_QUEUE_SKIES_LATE);
552 }
553}
#define ROR_ASSERT(_EXPR)
Definition Application.h:40
#define POS_TEX_BINDING
This creates a billboarding object that displays a text.
virtual ~MovableText()
void _notifyCurrentCamera(Ogre::Camera *cam)
Ogre::MaterialPtr mpMaterial
Definition MovableText.h:72
void setColor(const Ogre::ColourValue &color)
std::string mCaption
Definition MovableText.h:49
void getRenderOperation(Ogre::RenderOperation &op)
MovableText(const std::string &name, const std::string &caption, const std::string &fontName="highcontrast_black", Ogre::Real charHeight=1.0, const Ogre::ColourValue &color=Ogre::ColourValue::Black)
Ogre::Real mAdditionalHeight
Definition MovableText.h:67
Ogre::Font * mpFont
Definition MovableText.h:71
const Ogre::Quaternion & getWorldOrientation(void) const
Ogre::Real mSpaceWidth
Definition MovableText.h:59
Ogre::Real mRadius
Definition MovableText.h:66
void setCharacterHeight(Ogre::Real height)
Ogre::RenderOperation mRenderOp
Definition MovableText.h:54
void showOnTop(bool show=true)
void setTextAlignment(const HorizontalAlignment &horizontalAlignment, const VerticalAlignment &verticalAlignment)
VerticalAlignment mVerticalAlignment
Definition MovableText.h:51
void getWorldTransforms(Ogre::Matrix4 *xform) const
void setAdditionalHeight(Ogre::Real height)
void _updateRenderQueue(Ogre::RenderQueue *queue)
void setFontName(const std::string &fontName)
Ogre::Camera * mpCam
Definition MovableText.h:69
std::string mFontName
Definition MovableText.h:46
Ogre::String mName
Definition MovableText.h:48
Ogre::ColourValue mColor
Definition MovableText.h:53
Ogre::AxisAlignedBox mAABB
Definition MovableText.h:55
HorizontalAlignment mHorizontalAlignment
Definition MovableText.h:50
Ogre::Real mCharHeight
Definition MovableText.h:58
void setCaption(const std::string &caption)
void setSpaceWidth(Ogre::Real width)
const Ogre::Vector3 & getWorldPosition(void) const