/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include #include #include using namespace osg; using namespace osgText; //#define TREES_CODE_FOR_MAKING_SPACES_EDITABLE TextBase::TextBase(): _color(1.0f,1.0f,1.0f,1.0f), _fontSize(32,32), _characterHeight(32), _characterSizeMode(OBJECT_COORDS), _maximumWidth(0.0f), _maximumHeight(0.0f), _lineSpacing(0.0f), _alignment(BASE_LINE), _axisAlignment(XY_PLANE), _autoRotateToScreen(false), _layout(LEFT_TO_RIGHT), _drawMode(TEXT), _textBBMargin(0.0f), _textBBColor(0.0, 0.0, 0.0, 0.5), _kerningType(KERNING_DEFAULT), _lineCount(0) { setStateSet(Font::getDefaultFont()->getStateSet()); setUseDisplayList(false); setSupportsDisplayList(false); } TextBase::TextBase(const TextBase& textBase,const osg::CopyOp& copyop): osg::Drawable(textBase,copyop), _color(textBase._color), _font(textBase._font), _style(textBase._style), _fontSize(textBase._fontSize), _characterHeight(textBase._characterHeight), _characterSizeMode(textBase._characterSizeMode), _maximumWidth(textBase._maximumWidth), _maximumHeight(textBase._maximumHeight), _lineSpacing(textBase._lineSpacing), _text(textBase._text), _position(textBase._position), _alignment(textBase._alignment), _axisAlignment(textBase._axisAlignment), _rotation(textBase._rotation), _autoRotateToScreen(textBase._autoRotateToScreen), _layout(textBase._layout), _drawMode(textBase._drawMode), _textBBMargin(textBase._textBBMargin), _textBBColor(textBase._textBBColor), _kerningType(textBase._kerningType), _lineCount(textBase._lineCount) { } TextBase::~TextBase() { } void TextBase::setColor(const osg::Vec4& color) { _color = color; } void TextBase::setFont(osg::ref_ptr font) { if (_font==font) return; _font = font; computeGlyphRepresentation(); } void TextBase::setFont(const std::string& fontfile) { setFont(readRefFontFile(fontfile)); } void TextBase::setFontResolution(unsigned int width, unsigned int height) { _fontSize = FontResolution(width,height); computeGlyphRepresentation(); } void TextBase::setCharacterSize(float height) { _characterHeight = height; computeGlyphRepresentation(); } void TextBase::setCharacterSize(float height, float aspectRatio) { if (getCharacterAspectRatio()!=aspectRatio) { getOrCreateStyle()->setWidthRatio(aspectRatio); } setCharacterSize(height); } void TextBase::setMaximumWidth(float maximumWidth) { _maximumWidth = maximumWidth; computeGlyphRepresentation(); } void TextBase::setMaximumHeight(float maximumHeight) { _maximumHeight = maximumHeight; computeGlyphRepresentation(); } void TextBase::setLineSpacing(float lineSpacing) { _lineSpacing = lineSpacing; computeGlyphRepresentation(); } void TextBase::setText(const String& text) { if (_text==text) return; _text = text; computeGlyphRepresentation(); } void TextBase::setText(const std::string& text) { setText(String(text)); } void TextBase::setText(const std::string& text,String::Encoding encoding) { setText(String(text,encoding)); } void TextBase::setText(const wchar_t* text) { setText(String(text)); } void TextBase::setPosition(const osg::Vec3& pos) { if (_position==pos) return; _position = pos; computePositions(); } void TextBase::setAlignment(AlignmentType alignment) { if (_alignment==alignment) return; _alignment = alignment; computeGlyphRepresentation(); } void TextBase::setAxisAlignment(AxisAlignment axis) { _axisAlignment = axis; switch(axis) { case XZ_PLANE: setAutoRotateToScreen(false); setRotation(osg::Quat(osg::inDegrees(90.0f),osg::Vec3(1.0f,0.0f,0.0f))); break; case REVERSED_XZ_PLANE: setAutoRotateToScreen(false); setRotation(osg::Quat(osg::inDegrees(180.0f),osg::Vec3(0.0f,1.0f,0.0f))* osg::Quat(osg::inDegrees(90.0f),osg::Vec3(1.0f,0.0f,0.0f))); break; case YZ_PLANE: setAutoRotateToScreen(false); setRotation(osg::Quat(osg::inDegrees(90.0f),osg::Vec3(1.0f,0.0f,0.0f))* osg::Quat(osg::inDegrees(90.0f),osg::Vec3(0.0f,0.0f,1.0f))); break; case REVERSED_YZ_PLANE: setAutoRotateToScreen(false); setRotation(osg::Quat(osg::inDegrees(180.0f),osg::Vec3(0.0f,1.0f,0.0f))* osg::Quat(osg::inDegrees(90.0f),osg::Vec3(1.0f,0.0f,0.0f))* osg::Quat(osg::inDegrees(90.0f),osg::Vec3(0.0f,0.0f,1.0f))); break; case XY_PLANE: setAutoRotateToScreen(false); setRotation(osg::Quat()); // nop - already on XY plane. break; case REVERSED_XY_PLANE: setAutoRotateToScreen(false); setRotation(osg::Quat(osg::inDegrees(180.0f),osg::Vec3(0.0f,1.0f,0.0f))); break; case SCREEN: setAutoRotateToScreen(true); setRotation(osg::Quat()); // nop - already on XY plane. break; default: break; } } void TextBase::setRotation(const osg::Quat& quat) { _rotation = quat; computePositions(); } void TextBase::setAutoRotateToScreen(bool autoRotateToScreen) { if (_autoRotateToScreen==autoRotateToScreen) return; _autoRotateToScreen = autoRotateToScreen; computePositions(); } void TextBase::setLayout(Layout layout) { if (_layout==layout) return; _layout = layout; computeGlyphRepresentation(); } void TextBase::setDrawMode(unsigned int mode) { if (_drawMode==mode) return; _drawMode=mode; } void TextBase::setBoundingBoxMargin(float margin) { if (_textBBMargin == margin) return; _textBBMargin = margin; computeGlyphRepresentation(); } osg::BoundingBox TextBase::computeBound() const { osg::BoundingBox bbox; if (_textBB.valid()) { for(unsigned int i=0;i<_autoTransformCache.size();++i) { if (_autoTransformCache[i]._traversalNumber>=0) { osg::Matrix& matrix = _autoTransformCache[i]._matrix; bbox.expandBy(_textBB.corner(0)*matrix); bbox.expandBy(_textBB.corner(1)*matrix); bbox.expandBy(_textBB.corner(2)*matrix); bbox.expandBy(_textBB.corner(3)*matrix); bbox.expandBy(_textBB.corner(4)*matrix); bbox.expandBy(_textBB.corner(5)*matrix); bbox.expandBy(_textBB.corner(6)*matrix); bbox.expandBy(_textBB.corner(7)*matrix); } } if (!bbox.valid()) { // Provide a fallback in cases where no bounding box has been been setup so far. // Note, assume a scaling of 1.0 for _characterSizeMode!=OBJECT_COORDS as the // for screen space coordinates size modes we don't know what scale will be used until // the text is actually rendered, but we haven't to assume something otherwise the // text label will be culled by view or small feature culling on first frame. if (_autoRotateToScreen) { // use bounding sphere encompassing the maximum size of the text centered on the _position double radius = _textBB.radius(); osg::Vec3 diagonal(radius, radius, radius); bbox.set(_position-diagonal, _position+diagonal); } else { osg::Matrix matrix; matrix.makeTranslate(-_offset); matrix.postMultRotate(_rotation); matrix.postMultTranslate(_position); bbox.expandBy(_textBB.corner(0)*matrix); bbox.expandBy(_textBB.corner(1)*matrix); bbox.expandBy(_textBB.corner(2)*matrix); bbox.expandBy(_textBB.corner(3)*matrix); bbox.expandBy(_textBB.corner(4)*matrix); bbox.expandBy(_textBB.corner(5)*matrix); bbox.expandBy(_textBB.corner(6)*matrix); bbox.expandBy(_textBB.corner(7)*matrix); } } } return bbox; } void TextBase::computePositions() { unsigned int size = osg::maximum(osg::DisplaySettings::instance()->getMaxNumberOfGraphicsContexts(),_autoTransformCache.size()); // FIXME: OPTIMIZE: This would be one of the ideal locations to // call computeAverageGlyphWidthAndHeight(). It is out of the contextID loop // so the value would be computed fewer times. But the code will need changes // to get the value down to the locations it is needed. (Either pass through parameters // or member variables, but we would need a system to know if the values are stale.) for(unsigned int i=0;i