fixed: auto_ptr -> unique_ptr
[opensg.git] / Source / System / Window / Foreground / OSGSimpleTextForeground.cpp
blob83a010b64143b5f04a3c5da06760484d561fb720
1 /*---------------------------------------------------------------------------*\
2 * OpenSG *
3 * *
4 * *
5 * Copyright (C) 2000-2006 by the OpenSG Forum *
6 * *
7 * www.opensg.org *
8 * *
9 * contact: David Kabala (djkabala@gmail.com) *
10 * *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
13 * License *
14 * *
15 * This library is free software; you can redistribute it and/or modify it *
16 * under the terms of the GNU Library General Public License as published *
17 * by the Free Software Foundation, version 2. *
18 * *
19 * This library is distributed in the hope that it will be useful, but *
20 * WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
22 * Library General Public License for more details. *
23 * *
24 * You should have received a copy of the GNU Library General Public *
25 * License along with this library; if not, write to the Free Software *
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
27 * *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
30 * Changes *
31 * *
32 * *
33 * *
34 * *
35 * *
36 * *
37 \*---------------------------------------------------------------------------*/
39 //---------------------------------------------------------------------------
40 // Includes
41 //---------------------------------------------------------------------------
43 #include <cstdlib>
44 #include <cstdio>
46 #include "OSGConfig.h"
48 #include "OSGSimpleTextForeground.h"
50 #include "OSGImage.h"
52 #include "OSGViewport.h"
54 #include "OSGDefaultFont.h"
56 #include "OSGTextLayoutParam.h"
57 #include "OSGTextLayoutResult.h"
58 #include "OSGTextTXFGlyph.h"
59 #include "OSGTextureObjChunk.h"
60 #include "OSGTextureEnvChunk.h"
62 #include <boost/xpressive/xpressive.hpp>
63 #include <boost/xpressive/regex_actions.hpp>
65 using namespace boost::xpressive;
67 OSG_BEGIN_NAMESPACE
69 // Documentation for this class is emitted in the
70 // OSGSimpleTextForegroundBase.cpp file.
71 // To modify it, please change the .fcd file (OSGSimpleTextForeground.fcd) and
72 // regenerate the base file.
74 /***************************************************************************\
75 * Class variables *
76 \***************************************************************************/
78 /***************************************************************************\
79 * Class methods *
80 \***************************************************************************/
82 void SimpleTextForeground::initMethod(InitPhase ePhase)
84 Inherited::initMethod(ePhase);
86 if(ePhase == TypeObject::SystemPost)
92 /***************************************************************************\
93 * Instance methods *
94 \***************************************************************************/
96 void SimpleTextForeground::initText(const std::string &szFamily, Real32 fSize)
98 // Cleanup
99 _pFace = NULL;
100 _pTexChunk = NULL;
102 // Create the font
103 if(szFamily.empty() == false)
105 TextTXFParam param;
107 param.size = static_cast<UInt32>(fSize);
109 _pFace = TextTXFFace::create(szFamily, TextFace::STYLE_PLAIN, param);
111 if(_pFace != NULL)
113 _pTexChunk = TextureObjChunk::createLocal();
115 ImageUnrecPtr pTexture = _pFace->getTexture();
117 _pTexChunk->setImage (pTexture );
118 _pTexChunk->setWrapS (GL_CLAMP_TO_EDGE);
119 _pTexChunk->setWrapT (GL_CLAMP_TO_EDGE);
120 _pTexChunk->setMinFilter(GL_NEAREST );
121 _pTexChunk->setMagFilter(GL_NEAREST );
125 // We failed to create the font - fallback to the default font
126 if(_pFace == NULL)
128 _pFace = DefaultFont::the()->getFace ();
129 _pTexChunk = DefaultFont::the()->getTexture();
133 void SimpleTextForeground::draw(DrawEnv *pEnv)
135 #if !defined(OSG_OGL_COREONLY) || defined(OSG_CHECK_COREONLY)
136 if(!getActive())
138 return;
141 if(_pFace == NULL)
143 initText(getFamily(), getSize());
146 //Setup the orthographic projection
147 UInt32 fullWidth;
148 UInt32 fullHeight;
150 beginOrthoRender(pEnv, fullWidth, fullHeight);
152 glPushAttrib(GL_LIGHTING_BIT | GL_POLYGON_BIT |
153 GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
155 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
157 glDisable(GL_DEPTH_TEST );
158 glDisable(GL_COLOR_MATERIAL);
160 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
162 glEnable(GL_BLEND);
164 //Layout the text
165 TextLayoutParam layoutParam;
167 layoutParam.spacing = 1.1f;
168 layoutParam.majorAlignment = TextLayoutParam::ALIGN_BEGIN;
169 layoutParam.minorAlignment = TextLayoutParam::ALIGN_BEGIN;
171 TextLayoutResult layoutResult;
173 _pFace->layout(_vPlainTextLines, layoutParam, layoutResult);
175 Real32 scale = 1.f / _pFace->getScale();
176 Real32 size = _pFace->getParam().size;
177 Real32 textWidth =
178 layoutResult.textBounds.x() * scale + size + getTextMargin().x() * 2.0f;
179 Real32 textHeight =
180 layoutResult.textBounds.y() * scale + size + getTextMargin().y() * 2.0f;
182 // Let's do some simple form of layout management
183 Real32 pw = Real32(pEnv->getPixelWidth ());
184 Real32 ph = Real32(pEnv->getPixelHeight());
186 if(pw < 1.f || ph < 1.f)
188 return;
191 Real32 orthoX = 0.f, orthoY = ph;
193 switch(getHorizontalAlign())
195 case Right:
196 orthoX = pw - textWidth;
197 break;
198 case Middle:
199 orthoX = (pw - textWidth) * 0.5;
200 break;
201 case Left:
202 default:
203 break;
206 switch(getVerticalAlign())
208 case Bottom:
209 orthoY = textHeight;
210 break;
211 case Center:
212 orthoY = (ph - textHeight) * 0.5 + textHeight;
213 break;
214 case Top:
215 default:
216 break;
219 glTranslatef(orthoX, orthoY, 0.0);
221 // draw background
222 glColor4fv(static_cast<const GLfloat *>(getBgColor().getValuesRGBA()));
224 glBegin(GL_QUADS);
225 glVertex2f(0.f, -textHeight);
226 glVertex2f(textWidth, -textHeight);
227 glVertex2f(textWidth, 0.f );
228 glVertex2f(0.f, 0.f );
229 glEnd();
231 // draw border
232 if(getBorderColor().alpha() >= 0.0f)
234 glColor4fv(
235 static_cast<const GLfloat *>(getBorderColor().getValuesRGBA()));
237 glBegin(GL_LINE_LOOP);
238 glVertex2f( getBorderOffset().x(),
239 -textHeight + 1 + getBorderOffset().y());
241 glVertex2f( textWidth - 1 - getBorderOffset().x(),
242 -textHeight + 1 + getBorderOffset().y());
244 glVertex2f( textWidth - 1 - getBorderOffset().x(),
245 - 1 - getBorderOffset().y());
247 glVertex2f( getBorderOffset().x(),
248 - 1 - getBorderOffset().y());
249 glEnd();
252 glTranslatef( 0.5f * size + getTextMargin().x(),
253 -0.5f * size - getTextMargin().y(),
254 0.0f);
256 _pTexChunk ->activate(pEnv);
257 _pTexEnvChunk->activate(pEnv);
259 // draw text shadow
260 glColor4fv(static_cast<const GLfloat *>(getShadowColor().getValuesRGBA()));
262 glPushMatrix();
263 glTranslatef(getShadowOffset().x(), getShadowOffset().y(), 0);
264 glScalef(scale, scale, 1);
266 drawCharacters(_pFace, layoutResult, false);
268 // draw text
269 glPopMatrix();
270 glScalef(scale, scale, 1);
272 drawCharacters(_pFace, layoutResult, true);
274 _pTexChunk ->deactivate(pEnv);
275 _pTexEnvChunk->deactivate(pEnv);
277 glPopAttrib();
279 //reset the matrices
280 endOrthoRender(pEnv);
281 #endif
284 /*-------------------------------------------------------------------------*\
285 - private -
286 \*-------------------------------------------------------------------------*/
287 /*! Sets up an ortho projection for rendering. It handles tiling
288 when a TileCameraDecorator is in use. When done you need to call
289 endOrthoRender to clean up changes to the OpenGL matrix stacks.
291 \param pEnv DrawEnv being used for rendering
292 \param normX Wether x coordinates are going to be normalized.
293 \param normY Wether y coordinates are going to be normalized.
294 \param[out] fullWidth width of the viewport
295 \param[out] fullHeight height of the viewport
297 \note When the TileCameraDecorator is in use, the width and height of the
298 viewport (fullWidth, fullHeight) are defined by the
299 TileCameraDecorator.
301 void SimpleTextForeground::beginOrthoRender(DrawEnv *pEnv,
302 UInt32 &fullWidth,
303 UInt32 &fullHeight)
305 #if !defined(OSG_OGL_COREONLY) || defined(OSG_CHECK_COREONLY)
306 glMatrixMode(GL_MODELVIEW);
307 glPushMatrix();
308 glLoadIdentity();
310 glMatrixMode(GL_PROJECTION);
311 glPushMatrix();
312 glLoadIdentity();
314 UInt32 width = pEnv->getPixelWidth ();
315 UInt32 height = pEnv->getPixelHeight();
317 fullWidth = pEnv->getTileFullSize()[0];
318 fullHeight = pEnv->getTileFullSize()[1];
320 if(fullWidth == 0 || getTile())
322 fullWidth = width;
323 fullHeight = height;
325 else if(!getTile())
327 /*! \warning: Hack! */
328 glMatrixMode(GL_MODELVIEW);
329 glTranslatef(0.0f, fullHeight - height,0.0f);
330 //End Hack
332 glMatrixMode(GL_PROJECTION);
333 Matrix sm = pEnv->calcTileDecorationMatrix();
335 glLoadMatrixf(sm.getValues());
339 glOrtho(- 0.375f,
340 static_cast<Real32>(fullWidth) - 0.375f,
341 - 0.375f,
342 static_cast<Real32>(fullHeight) - 0.375f,
343 -1.0f,
344 1.0f);
346 glMatrixMode(GL_MODELVIEW);
347 #endif
350 /*! Clean up changes to the OpenGL matrix stacks done by beginOrthoRender
352 void SimpleTextForeground::endOrthoRender(DrawEnv *pEnv)
354 #if !defined(OSG_OGL_COREONLY) || defined(OSG_CHECK_COREONLY)
355 glMatrixMode(GL_PROJECTION);
356 glPopMatrix();
358 glMatrixMode(GL_MODELVIEW);
359 glPopMatrix();
360 #endif
363 void SimpleTextForeground::resolveLinks(void)
365 Inherited::resolveLinks();
367 _pTexChunk = NULL;
368 _pTexEnvChunk = NULL;
369 _pFace = NULL;
372 template <typename ElemT>
373 struct HexTo
375 ElemT value;
376 operator ElemT() const { return value; }
378 friend std::istream& operator>>(std::istream& in, HexTo& out)
380 in >> std::hex >> out.value;
381 return in;
385 bool SimpleTextForeground::isColoredRange(UInt32 uiPosition) const
387 for(UInt32 i = 0; i < _vColorRanges.size(); ++i)
389 if(_vColorRanges[i].isBounded(uiPosition))
391 return true;
395 return false;
398 Color4f SimpleTextForeground::getColorRange(UInt32 uiPosition) const
400 for(UInt32 i = 0; i < _vColorRanges.size(); ++i)
402 if(_vColorRanges[i].isBounded(uiPosition))
404 return _vColorRanges[i].getColor();
408 return Color4f();
411 void SimpleTextForeground::updateFormatting(void)
413 //Clear the formatted lines
414 _vPlainTextLines.clear();
415 _vColorRanges .clear();
417 UInt32 uiIndexOffset = 0;
419 for(UInt32 i = 0; i < getMFLines()->size() ; ++i)
421 std::string szResult = getLines(i);
423 //Remove all newlines that do not have another newline directly
424 //afterward
426 mark_tag redTag (1),
427 greenTag(2),
428 blueTag (3),
429 alphaTag(4),
430 textTag (5);
432 //Matches a string similar to \color=AA00FF11
433 //sregex ColorRegex =
434 //"\\color"
435 //>> *space
436 //>> '='
437 //>> *space
438 //>> (redTag = repeat<2>(alnum))
439 //>> (greenTag = repeat<2>(alnum))
440 //>> (blueTag = repeat<2>(alnum))
441 //>> !(alphaTag = repeat<2>(alnum));
443 //Matches a string similar to \{\color=AA00FF11 Some text}
444 sregex srTaggedColorRegex =
445 as_xpr('\\') >> '{'
446 >> *space
447 >> "\\color"
448 >> *space
449 >> '='
450 >> *space
451 >> (redTag = repeat<2>(alnum))
452 >> (greenTag = repeat<2>(alnum))
453 >> (blueTag = repeat<2>(alnum))
454 >> !(alphaTag = repeat<2>(alnum))
455 >> *space
456 >> (textTag = -*_) >> '}';
458 //Get the color
459 smatch what;
461 while(regex_search(szResult, what, srTaggedColorRegex))
463 Real32 Red(0.0f), Green(0.0f), Blue(0.0f), Alpha(1.0f);
467 Red = static_cast<Real32>(
468 boost::lexical_cast< HexTo<UInt16> >(
469 std::string("0x") + what[redTag])) /
470 TypeTraits<UInt8>::getMax();
472 catch(boost::bad_lexical_cast &)
474 SWARNING << "Could not convert hex value "
475 << what[redTag]
476 << " into a 8-bit unsigned integer for the red "
477 << "color component."
478 << std::endl;
483 Green = static_cast<Real32>(
484 boost::lexical_cast< HexTo<UInt16> >(
485 std::string("0x") + what[greenTag])) /
486 TypeTraits<UInt8>::getMax();
489 catch(boost::bad_lexical_cast &)
491 SWARNING << "Could not convert hex value "
492 << what[greenTag]
493 << " into a 8-bit unsigned integer for the "
494 << "green color component."
495 << std::endl;
500 Blue = static_cast<Real32>(
501 boost::lexical_cast< HexTo<UInt16> >(
502 std::string("0x") + what[blueTag])) /
503 TypeTraits<UInt8>::getMax();
506 catch(boost::bad_lexical_cast &)
508 SWARNING << "Could not convert hex value "
509 << what[blueTag]
510 << " into a 8-bit unsigned integer for the "
511 << "blue color component."
512 << std::endl;
517 Alpha = static_cast<Real32>(
518 boost::lexical_cast<HexTo <UInt16> >(
519 std::string("0x") + what[alphaTag])) /
520 TypeTraits<UInt8>::getMax();
523 catch(boost::bad_lexical_cast &)
525 SWARNING << "Could not convert hex value "
526 << what[alphaTag]
527 << " into a 8-bit unsigned integer for the "
528 << "alpha color component."
529 << std::endl;
532 TextColoredRange oColorRange(
533 uiIndexOffset + what.position(),
534 uiIndexOffset + what.position() + what[textTag].length() - 1,
535 Color4f(Red, Green, Blue, Alpha));
537 _vColorRanges.push_back(oColorRange);
539 //Remove the tag from the plain text
540 szResult = regex_replace(szResult,
541 srTaggedColorRegex,
542 "" + textTag,
543 regex_constants::match_default |
544 regex_constants::format_first_only);
547 //Push the plain text line to the lines vector
548 _vPlainTextLines.push_back(szResult);
550 uiIndexOffset += UInt32(szResult.size());
554 // Render the text using the layout
555 void SimpleTextForeground::drawCharacters(
556 TextTXFFace * const pTextFace,
557 const TextLayoutResult & oLayoutResult,
558 bool bWithColoring)
560 #if !defined(OSG_OGL_COREONLY) || defined(OSG_CHECK_COREONLY)
561 Color4f cCurrentColor = getColor();
562 Color4f cNewColor;
564 glBegin(GL_QUADS);
566 if(bWithColoring)
568 glColor4fv(cCurrentColor.getValues());
571 UInt32 i, numGlyphs = oLayoutResult.getNumGlyphs();
573 for(i = 0; i < numGlyphs; ++i)
575 //Does the text color need to change
576 if(bWithColoring)
578 if(isColoredRange(i))
580 cNewColor = getColorRange(i);
582 else
584 cNewColor = getColor();
587 if(cCurrentColor != cNewColor)
589 cCurrentColor = cNewColor;
590 glColor4fv(cCurrentColor.getValues());
594 const TextTXFGlyph &glyph =
595 pTextFace->getTXFGlyph(oLayoutResult.indices[i]);
597 Real32 width = glyph.getWidth ();
598 Real32 height = glyph.getHeight();
600 // No need to draw invisible glyphs
601 if((width <= 0.f) || (height <= 0.f))
602 continue;
604 // Calculate coordinates
605 Vec2f const &pos = oLayoutResult.positions[i];
606 Real32 posLeft = pos.x();
607 Real32 posTop = pos.y();
608 Real32 posRight = pos.x() + width;
609 Real32 posBottom = pos.y() - height;
611 Real32 texCoordLeft = glyph.getTexCoord(TextTXFGlyph::COORD_LEFT );
612 Real32 texCoordTop = glyph.getTexCoord(TextTXFGlyph::COORD_TOP );
613 Real32 texCoordRight = glyph.getTexCoord(TextTXFGlyph::COORD_RIGHT );
614 Real32 texCoordBottom = glyph.getTexCoord(TextTXFGlyph::COORD_BOTTOM);
616 // lower left corner
617 glTexCoord2f(texCoordLeft, texCoordBottom);
618 glVertex2f (posLeft, posBottom );
620 // lower right corner
621 glTexCoord2f(texCoordRight, texCoordBottom);
622 glVertex2f (posRight, posBottom );
624 // upper right corner
625 glTexCoord2f(texCoordRight, texCoordTop);
626 glVertex2f (posRight, posTop );
628 // upper left corner
629 glTexCoord2f(texCoordLeft, texCoordTop);
630 glVertex2f (posLeft, posTop );
633 glEnd();
634 #endif
637 /*----------------------- constructors & destructors ----------------------*/
639 SimpleTextForeground::SimpleTextForeground(void) :
640 Inherited ( ),
641 _pFace (NULL),
642 _pTexChunk (NULL),
643 _pTexEnvChunk (NULL),
644 _vPlainTextLines( ),
645 _vColorRanges ( )
648 _pTexEnvChunk = TextureEnvChunk::createLocal();
649 _pTexEnvChunk->setEnvMode(GL_MODULATE);
652 SimpleTextForeground::SimpleTextForeground(const SimpleTextForeground &source) :
653 Inherited (source ),
654 _pFace (source._pFace ),
655 _pTexChunk (source._pTexChunk ),
656 _pTexEnvChunk (source._pTexEnvChunk ),
657 _vPlainTextLines(source._vPlainTextLines),
658 _vColorRanges (source._vColorRanges )
662 SimpleTextForeground::~SimpleTextForeground(void)
666 /*----------------------------- class specific ----------------------------*/
668 void SimpleTextForeground::changed(ConstFieldMaskArg whichField,
669 UInt32 origin,
670 BitVector details)
672 Inherited::changed(whichField, origin, details);
674 if(whichField & LinesFieldMask)
676 updateFormatting();
679 if((whichField & SizeFieldMask) ||
680 (whichField & FamilyFieldMask))
682 _pFace = NULL;
686 void SimpleTextForeground::dump( UInt32 ,
687 const BitVector ) const
689 SLOG << "Dump SimpleTextForeground NI" << std::endl;
692 /*---------------------------- internal classes ---------------------------*/
693 //SimpleTextForeground::TextElement::TextElement(const std::string& Text,
694 //bool IsColored,
695 //const Color4f& Color) :
696 //_Text(Text),
697 //_IsColored(IsColored),
698 //_Color(Color)
702 OSG_END_NAMESPACE