1 /*---------------------------------------------------------------------------*\
5 * Copyright (C) 2000-2006 by the OpenSG Forum *
9 * contact: David Kabala (djkabala@gmail.com) *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
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. *
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. *
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. *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
37 \*---------------------------------------------------------------------------*/
39 //---------------------------------------------------------------------------
41 //---------------------------------------------------------------------------
46 #include "OSGConfig.h"
48 #include "OSGSimpleTextForeground.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
;
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 /***************************************************************************\
76 \***************************************************************************/
78 /***************************************************************************\
80 \***************************************************************************/
82 void SimpleTextForeground::initMethod(InitPhase ePhase
)
84 Inherited::initMethod(ePhase
);
86 if(ePhase
== TypeObject::SystemPost
)
92 /***************************************************************************\
94 \***************************************************************************/
96 void SimpleTextForeground::initText(const std::string
&szFamily
, Real32 fSize
)
103 if(szFamily
.empty() == false)
107 param
.size
= static_cast<UInt32
>(fSize
);
109 _pFace
= TextTXFFace::create(szFamily
, TextFace::STYLE_PLAIN
, param
);
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
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)
143 initText(getFamily(), getSize());
146 //Setup the orthographic projection
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
);
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
;
178 layoutResult
.textBounds
.x() * scale
+ size
+ getTextMargin().x() * 2.0f
;
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
)
191 Real32 orthoX
= 0.f
, orthoY
= ph
;
193 switch(getHorizontalAlign())
196 orthoX
= pw
- textWidth
;
199 orthoX
= (pw
- textWidth
) * 0.5;
206 switch(getVerticalAlign())
212 orthoY
= (ph
- textHeight
) * 0.5 + textHeight
;
219 glTranslatef(orthoX
, orthoY
, 0.0);
222 glColor4fv(static_cast<const GLfloat
*>(getBgColor().getValuesRGBA()));
225 glVertex2f(0.f
, -textHeight
);
226 glVertex2f(textWidth
, -textHeight
);
227 glVertex2f(textWidth
, 0.f
);
228 glVertex2f(0.f
, 0.f
);
232 if(getBorderColor().alpha() >= 0.0f
)
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());
252 glTranslatef( 0.5f
* size
+ getTextMargin().x(),
253 -0.5f
* size
- getTextMargin().y(),
256 _pTexChunk
->activate(pEnv
);
257 _pTexEnvChunk
->activate(pEnv
);
260 glColor4fv(static_cast<const GLfloat
*>(getShadowColor().getValuesRGBA()));
263 glTranslatef(getShadowOffset().x(), getShadowOffset().y(), 0);
264 glScalef(scale
, scale
, 1);
266 drawCharacters(_pFace
, layoutResult
, false);
270 glScalef(scale
, scale
, 1);
272 drawCharacters(_pFace
, layoutResult
, true);
274 _pTexChunk
->deactivate(pEnv
);
275 _pTexEnvChunk
->deactivate(pEnv
);
280 endOrthoRender(pEnv
);
284 /*-------------------------------------------------------------------------*\
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
301 void SimpleTextForeground::beginOrthoRender(DrawEnv
*pEnv
,
305 #if !defined(OSG_OGL_COREONLY) || defined(OSG_CHECK_COREONLY)
306 glMatrixMode(GL_MODELVIEW
);
310 glMatrixMode(GL_PROJECTION
);
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())
327 /*! \warning: Hack! */
328 glMatrixMode(GL_MODELVIEW
);
329 glTranslatef(0.0f
, fullHeight
- height
,0.0f
);
332 glMatrixMode(GL_PROJECTION
);
333 Matrix sm
= pEnv
->calcTileDecorationMatrix();
335 glLoadMatrixf(sm
.getValues());
340 static_cast<Real32
>(fullWidth
) - 0.375f
,
342 static_cast<Real32
>(fullHeight
) - 0.375f
,
346 glMatrixMode(GL_MODELVIEW
);
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
);
358 glMatrixMode(GL_MODELVIEW
);
363 void SimpleTextForeground::resolveLinks(void)
365 Inherited::resolveLinks();
368 _pTexEnvChunk
= NULL
;
372 template <typename ElemT
>
376 operator ElemT() const { return value
; }
378 friend std::istream
& operator>>(std::istream
& in
, HexTo
& out
)
380 in
>> std::hex
>> out
.value
;
385 bool SimpleTextForeground::isColoredRange(UInt32 uiPosition
) const
387 for(UInt32 i
= 0; i
< _vColorRanges
.size(); ++i
)
389 if(_vColorRanges
[i
].isBounded(uiPosition
))
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();
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
432 //Matches a string similar to \color=AA00FF11
433 //sregex ColorRegex =
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
=
451 >> (redTag
= repeat
<2>(alnum
))
452 >> (greenTag
= repeat
<2>(alnum
))
453 >> (blueTag
= repeat
<2>(alnum
))
454 >> !(alphaTag
= repeat
<2>(alnum
))
456 >> (textTag
= -*_
) >> '}';
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 "
476 << " into a 8-bit unsigned integer for the red "
477 << "color component."
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 "
493 << " into a 8-bit unsigned integer for the "
494 << "green color component."
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 "
510 << " into a 8-bit unsigned integer for the "
511 << "blue color component."
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 "
527 << " into a 8-bit unsigned integer for the "
528 << "alpha color component."
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
,
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
,
560 #if !defined(OSG_OGL_COREONLY) || defined(OSG_CHECK_COREONLY)
561 Color4f cCurrentColor
= getColor();
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
578 if(isColoredRange(i
))
580 cNewColor
= getColorRange(i
);
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
))
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
);
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
);
629 glTexCoord2f(texCoordLeft
, texCoordTop
);
630 glVertex2f (posLeft
, posTop
);
637 /*----------------------- constructors & destructors ----------------------*/
639 SimpleTextForeground::SimpleTextForeground(void) :
643 _pTexEnvChunk (NULL
),
648 _pTexEnvChunk
= TextureEnvChunk::createLocal();
649 _pTexEnvChunk
->setEnvMode(GL_MODULATE
);
652 SimpleTextForeground::SimpleTextForeground(const SimpleTextForeground
&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
,
672 Inherited::changed(whichField
, origin
, details
);
674 if(whichField
& LinesFieldMask
)
679 if((whichField
& SizeFieldMask
) ||
680 (whichField
& FamilyFieldMask
))
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,
695 //const Color4f& Color) :
697 //_IsColored(IsColored),