root/OpenSceneGraph/trunk/src/osgText/TextBase.cpp @ 13041

Revision 13041, 12.8 kB (checked in by robert, 3 years ago)

Ran script to remove trailing spaces and tabs

  • Property svn:eol-style set to native
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13
14
15#include <osgText/TextBase>
16#include <osgText/Font>
17
18#include <osg/Math>
19#include <osg/GL>
20#include <osg/Notify>
21#include <osg/PolygonOffset>
22#include <osg/TexEnv>
23
24#include <osgUtil/CullVisitor>
25
26#include <osgDB/ReadFile>
27
28using namespace osg;
29using namespace osgText;
30
31//#define TREES_CODE_FOR_MAKING_SPACES_EDITABLE
32
33TextBase::TextBase():
34    _color(1.0f,1.0f,1.0f,1.0f),
35    _fontSize(32,32),
36    _characterHeight(32),
37    _characterSizeMode(OBJECT_COORDS),
38    _maximumWidth(0.0f),
39    _maximumHeight(0.0f),
40    _lineSpacing(0.0f),
41    _alignment(BASE_LINE),
42    _axisAlignment(XY_PLANE),
43    _autoRotateToScreen(false),
44    _layout(LEFT_TO_RIGHT),
45    _drawMode(TEXT),
46    _textBBMargin(0.0f),
47    _textBBColor(0.0, 0.0, 0.0, 0.5),
48    _kerningType(KERNING_DEFAULT),
49    _lineCount(0)
50{
51    setStateSet(Font::getDefaultFont()->getStateSet());
52    setUseDisplayList(false);
53    setSupportsDisplayList(false);
54}
55
56TextBase::TextBase(const TextBase& textBase,const osg::CopyOp& copyop):
57    osg::Drawable(textBase,copyop),
58    _color(textBase._color),
59    _font(textBase._font),
60    _style(textBase._style),
61    _fontSize(textBase._fontSize),
62    _characterHeight(textBase._characterHeight),
63    _characterSizeMode(textBase._characterSizeMode),
64    _maximumWidth(textBase._maximumWidth),
65    _maximumHeight(textBase._maximumHeight),
66    _lineSpacing(textBase._lineSpacing),
67    _text(textBase._text),
68    _position(textBase._position),
69    _alignment(textBase._alignment),
70    _axisAlignment(textBase._axisAlignment),
71    _rotation(textBase._rotation),
72    _autoRotateToScreen(textBase._autoRotateToScreen),
73    _layout(textBase._layout),
74    _drawMode(textBase._drawMode),
75    _textBBMargin(textBase._textBBMargin),
76    _textBBColor(textBase._textBBColor),
77    _kerningType(textBase._kerningType),
78    _lineCount(textBase._lineCount)
79{
80}
81
82TextBase::~TextBase()
83{
84}
85
86void TextBase::setColor(const osg::Vec4& color)
87{
88    _color = color;
89}
90
91
92void TextBase::setFont(osg::ref_ptr<Font> font)
93{
94    if (_font==font) return;
95
96    _font = font;
97
98    computeGlyphRepresentation();
99}
100
101void TextBase::setFont(const std::string& fontfile)
102{
103    setFont(readRefFontFile(fontfile));
104}
105
106void TextBase::setFontResolution(unsigned int width, unsigned int height)
107{
108    _fontSize = FontResolution(width,height);
109    computeGlyphRepresentation();
110}
111
112void TextBase::setCharacterSize(float height)
113{
114    _characterHeight = height;
115    computeGlyphRepresentation();
116}
117
118void TextBase::setCharacterSize(float height, float aspectRatio)
119{
120    if (getCharacterAspectRatio()!=aspectRatio)
121    {
122        getOrCreateStyle()->setWidthRatio(aspectRatio);
123    }
124    setCharacterSize(height);
125}
126
127void TextBase::setMaximumWidth(float maximumWidth)
128{
129    _maximumWidth = maximumWidth;
130    computeGlyphRepresentation();
131}
132
133void  TextBase::setMaximumHeight(float maximumHeight)
134{
135    _maximumHeight = maximumHeight;
136    computeGlyphRepresentation();
137}
138
139void TextBase::setLineSpacing(float lineSpacing)
140{
141    _lineSpacing = lineSpacing;
142    computeGlyphRepresentation();
143}
144
145
146void TextBase::setText(const String& text)
147{
148    if (_text==text) return;
149
150    _text = text;
151    computeGlyphRepresentation();
152}
153
154void TextBase::setText(const std::string& text)
155{
156    setText(String(text));
157}
158
159void TextBase::setText(const std::string& text,String::Encoding encoding)
160{
161    setText(String(text,encoding));
162}
163
164
165void TextBase::setText(const wchar_t* text)
166{
167    setText(String(text));
168}
169
170void TextBase::setPosition(const osg::Vec3& pos)
171{
172    if (_position==pos) return;
173
174    _position = pos;
175    computePositions();
176}
177
178void TextBase::setAlignment(AlignmentType alignment)
179{
180    if (_alignment==alignment) return;
181
182    _alignment = alignment;
183    computeGlyphRepresentation();
184}
185
186void TextBase::setAxisAlignment(AxisAlignment axis)
187{
188    _axisAlignment = axis;
189
190    switch(axis)
191    {
192    case XZ_PLANE:
193        setAutoRotateToScreen(false);
194        setRotation(osg::Quat(osg::inDegrees(90.0f),osg::Vec3(1.0f,0.0f,0.0f)));
195        break;
196    case REVERSED_XZ_PLANE:
197        setAutoRotateToScreen(false);
198        setRotation(osg::Quat(osg::inDegrees(180.0f),osg::Vec3(0.0f,1.0f,0.0f))*
199                    osg::Quat(osg::inDegrees(90.0f),osg::Vec3(1.0f,0.0f,0.0f)));
200        break;
201    case YZ_PLANE:
202        setAutoRotateToScreen(false);
203        setRotation(osg::Quat(osg::inDegrees(90.0f),osg::Vec3(1.0f,0.0f,0.0f))*
204                    osg::Quat(osg::inDegrees(90.0f),osg::Vec3(0.0f,0.0f,1.0f)));
205        break;
206    case REVERSED_YZ_PLANE:
207        setAutoRotateToScreen(false);
208        setRotation(osg::Quat(osg::inDegrees(180.0f),osg::Vec3(0.0f,1.0f,0.0f))*
209                    osg::Quat(osg::inDegrees(90.0f),osg::Vec3(1.0f,0.0f,0.0f))*
210                    osg::Quat(osg::inDegrees(90.0f),osg::Vec3(0.0f,0.0f,1.0f)));
211        break;
212    case XY_PLANE:
213        setAutoRotateToScreen(false);
214        setRotation(osg::Quat());  // nop - already on XY plane.
215        break;
216    case REVERSED_XY_PLANE:
217        setAutoRotateToScreen(false);
218        setRotation(osg::Quat(osg::inDegrees(180.0f),osg::Vec3(0.0f,1.0f,0.0f)));
219        break;
220    case SCREEN:
221        setAutoRotateToScreen(true);
222        setRotation(osg::Quat());  // nop - already on XY plane.
223        break;
224    default: break;
225    }
226}
227
228void TextBase::setRotation(const osg::Quat& quat)
229{
230    _rotation = quat;
231    computePositions();
232}
233
234
235void TextBase::setAutoRotateToScreen(bool autoRotateToScreen)
236{
237    if (_autoRotateToScreen==autoRotateToScreen) return;
238
239    _autoRotateToScreen = autoRotateToScreen;
240    computePositions();
241}
242
243
244void TextBase::setLayout(Layout layout)
245{
246    if (_layout==layout) return;
247
248    _layout = layout;
249    computeGlyphRepresentation();
250}
251
252
253void TextBase::setDrawMode(unsigned int mode)
254{
255    if (_drawMode==mode) return;
256
257    _drawMode=mode;
258}
259
260
261void TextBase::setBoundingBoxMargin(float margin)
262{
263    if (_textBBMargin == margin)
264        return;
265
266    _textBBMargin = margin;
267    computeGlyphRepresentation();
268}
269
270
271osg::BoundingBox TextBase::computeBound() const
272{
273    osg::BoundingBox  bbox;
274
275    if (_textBB.valid())
276    {
277        for(unsigned int i=0;i<_autoTransformCache.size();++i)
278        {
279            if (_autoTransformCache[i]._traversalNumber>=0)
280            {
281                osg::Matrix& matrix = _autoTransformCache[i]._matrix;
282                bbox.expandBy(osg::Vec3(_textBB.xMin(),_textBB.yMin(),_textBB.zMin())*matrix);
283                bbox.expandBy(osg::Vec3(_textBB.xMax(),_textBB.yMax(),_textBB.zMax())*matrix);
284            }
285        }
286
287
288        if (!bbox.valid())
289        {
290            // Provide a fallback in cases where no bounding box has been been setup so far.
291            // Note, assume a scaling of 1.0 for _characterSizeMode!=OBJECT_COORDS as the
292            // for screen space coordinates size modes we don't know what scale will be used until
293            // the text is actually rendered, but we haven't to assume something otherwise the
294            // text label will be culled by view or small feature culling on first frame.
295            if (_autoRotateToScreen)
296            {
297                // use bounding sphere encompassing the maximum size of the text centered on the _position
298                double radius = _textBB.radius();
299                osg::Vec3 diagonal(radius, radius, radius);
300                bbox.set(_position-diagonal, _position+diagonal);
301            }
302            else
303            {
304                osg::Matrix matrix;
305                matrix.makeTranslate(-_offset);
306                matrix.postMultRotate(_rotation);
307                matrix.postMultTranslate(_position);
308                bbox.expandBy(osg::Vec3(_textBB.xMin(),_textBB.yMin(),_textBB.zMin())*matrix);
309                bbox.expandBy(osg::Vec3(_textBB.xMax(),_textBB.yMax(),_textBB.zMax())*matrix);
310            }
311        }
312    }
313
314    return bbox;
315}
316
317void TextBase::computePositions()
318{
319    unsigned int size = osg::maximum(osg::DisplaySettings::instance()->getMaxNumberOfGraphicsContexts(),_autoTransformCache.size());
320
321    // FIXME: OPTIMIZE: This would be one of the ideal locations to
322    // call computeAverageGlyphWidthAndHeight(). It is out of the contextID loop
323    // so the value would be computed fewer times. But the code will need changes
324    // to get the value down to the locations it is needed. (Either pass through parameters
325    // or member variables, but we would need a system to know if the values are stale.)
326
327
328    for(unsigned int i=0;i<size;++i)
329    {
330        computePositions(i);
331    }
332}
333
334void TextBase::setThreadSafeRefUnref(bool threadSafe)
335{
336    Drawable::setThreadSafeRefUnref(threadSafe);
337}
338
339void TextBase::resizeGLObjectBuffers(unsigned int maxSize)
340{
341    Drawable::resizeGLObjectBuffers(maxSize);
342
343    _autoTransformCache.resize(maxSize);
344}
345
346
347void TextBase::releaseGLObjects(osg::State* state) const
348{
349    Drawable::releaseGLObjects(state);
350}
351
352void TextBase::positionCursor(const osg::Vec2 & endOfLine_coords, osg::Vec2 & cursor, unsigned int linelength)
353{
354    switch(_layout)
355    {
356        case LEFT_TO_RIGHT:
357        {
358            switch (_alignment)
359            {
360                // nothing to be done for these
361                //case LEFT_TOP:
362                //case LEFT_CENTER:
363                //case LEFT_BOTTOM:
364                //case LEFT_BASE_LINE:
365                //case LEFT_BOTTOM_BASE_LINE:
366                //  break;
367                case CENTER_TOP:
368                case CENTER_CENTER:
369                case CENTER_BOTTOM:
370                case CENTER_BASE_LINE:
371                case CENTER_BOTTOM_BASE_LINE:
372                    cursor.x() = (cursor.x() - endOfLine_coords.x()) * 0.5f;
373                    break;
374                case RIGHT_TOP:
375                case RIGHT_CENTER:
376                case RIGHT_BOTTOM:
377                case RIGHT_BASE_LINE:
378                case RIGHT_BOTTOM_BASE_LINE:
379                    cursor.x() = cursor.x() - endOfLine_coords.x();
380                    break;
381                default:
382                    break;
383            }
384            break;
385        }
386        case RIGHT_TO_LEFT:
387        {
388            switch (_alignment)
389            {
390                case LEFT_TOP:
391                case LEFT_CENTER:
392                case LEFT_BOTTOM:
393                case LEFT_BASE_LINE:
394                case LEFT_BOTTOM_BASE_LINE:
395                    cursor.x() = 2*cursor.x() - endOfLine_coords.x();
396                    break;
397                case CENTER_TOP:
398                case CENTER_CENTER:
399                case CENTER_BOTTOM:
400                case CENTER_BASE_LINE:
401                case CENTER_BOTTOM_BASE_LINE:
402                    cursor.x() = cursor.x() + (cursor.x() - endOfLine_coords.x()) * 0.5f;
403                    break;
404                    // nothing to be done for these
405                    //case RIGHT_TOP:
406                    //case RIGHT_CENTER:
407                    //case RIGHT_BOTTOM:
408                    //case RIGHT_BASE_LINE:
409                    //case RIGHT_BOTTOM_BASE_LINE:
410                    //  break;
411                default:
412                    break;
413            }
414            break;
415        }
416        case VERTICAL:
417        {
418            switch (_alignment)
419            {
420                // TODO: current behaviour top baselines lined up in both cases - need to implement
421                //       top of characters aligment - Question is this neccesary?
422                // ... otherwise, nothing to be done for these 6 cases
423                //case LEFT_TOP:
424                //case CENTER_TOP:
425                //case RIGHT_TOP:
426                //  break;
427                //case LEFT_BASE_LINE:
428                //case CENTER_BASE_LINE:
429                //case RIGHT_BASE_LINE:
430                //  break;
431                case LEFT_CENTER:
432                case CENTER_CENTER:
433                case RIGHT_CENTER:
434                    cursor.y() = cursor.y() + (cursor.y() - endOfLine_coords.y()) * 0.5f;
435                    break;
436                case LEFT_BOTTOM_BASE_LINE:
437                case CENTER_BOTTOM_BASE_LINE:
438                case RIGHT_BOTTOM_BASE_LINE:
439                    cursor.y() = cursor.y() - (linelength * _characterHeight);
440                    break;
441                case LEFT_BOTTOM:
442                case CENTER_BOTTOM:
443                case RIGHT_BOTTOM:
444                    cursor.y() = 2*cursor.y() - endOfLine_coords.y();
445                    break;
446                default:
447                    break;
448            }
449            break;
450        }
451    }
452}
Note: See TracBrowser for help on using the browser.