397 lines
11 KiB
C++
397 lines
11 KiB
C++
/* -*-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 <osgText/TextBase>
|
|
|
|
#include <osg/Math>
|
|
#include <osg/GL>
|
|
#include <osg/Notify>
|
|
#include <osg/PolygonOffset>
|
|
#include <osg/TexEnv>
|
|
|
|
#include <osgUtil/CullVisitor>
|
|
|
|
#include <osgDB/ReadFile>
|
|
|
|
#include "DefaultFont.h"
|
|
|
|
using namespace osg;
|
|
using namespace osgText;
|
|
|
|
//#define TREES_CODE_FOR_MAKING_SPACES_EDITABLE
|
|
|
|
TextBase::TextBase():
|
|
_fontSize(32,32),
|
|
_characterHeight(32),
|
|
_characterAspectRatio(1.0f),
|
|
_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),
|
|
_kerningType(KERNING_DEFAULT),
|
|
_lineCount(0)
|
|
{
|
|
setStateSet(DefaultFont::instance()->getStateSet());
|
|
setUseDisplayList(false);
|
|
setSupportsDisplayList(false);
|
|
}
|
|
|
|
TextBase::TextBase(const TextBase& textBase,const osg::CopyOp& copyop):
|
|
osg::Drawable(textBase,copyop),
|
|
_fontSize(textBase._fontSize),
|
|
_characterHeight(textBase._characterHeight),
|
|
_characterAspectRatio(textBase._characterAspectRatio),
|
|
_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),
|
|
_kerningType(textBase._kerningType),
|
|
_lineCount(textBase._lineCount)
|
|
{
|
|
}
|
|
|
|
TextBase::~TextBase()
|
|
{
|
|
}
|
|
|
|
void TextBase::setFontResolution(unsigned int width, unsigned int height)
|
|
{
|
|
_fontSize = FontResolution(width,height);
|
|
computeGlyphRepresentation();
|
|
}
|
|
|
|
void TextBase::setCharacterSize(float height,float aspectRatio)
|
|
{
|
|
_characterHeight = height;
|
|
_characterAspectRatio = aspectRatio;
|
|
computeGlyphRepresentation();
|
|
}
|
|
|
|
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;
|
|
computePositions();
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
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 && (_characterSizeMode!=OBJECT_COORDS || _autoRotateToScreen))
|
|
{
|
|
// _autoTransformCache is not valid so don't take it into accoumt when compute bounding volume.
|
|
#if 0
|
|
// so fallback to estimating the bounding box size by assuming a scale of 1
|
|
// but might cause problems due to small feature culling...
|
|
osg::Matrix matrix;
|
|
matrix.makeTranslate(_position);
|
|
bbox.expandBy(osg::Vec3(_textBB.xMin(),_textBB.yMin(),_textBB.zMin())*matrix);
|
|
bbox.expandBy(osg::Vec3(_textBB.xMax(),_textBB.yMax(),_textBB.zMax())*matrix);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
osg::Matrix& matrix = _autoTransformCache[i]._matrix;
|
|
bbox.expandBy(osg::Vec3(_textBB.xMin(),_textBB.yMin(),_textBB.zMin())*matrix);
|
|
bbox.expandBy(osg::Vec3(_textBB.xMax(),_textBB.yMax(),_textBB.zMax())*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<size;++i)
|
|
{
|
|
computePositions(i);
|
|
}
|
|
}
|
|
|
|
void TextBase::setThreadSafeRefUnref(bool threadSafe)
|
|
{
|
|
Drawable::setThreadSafeRefUnref(threadSafe);
|
|
}
|
|
|
|
void TextBase::resizeGLObjectBuffers(unsigned int maxSize)
|
|
{
|
|
Drawable::resizeGLObjectBuffers(maxSize);
|
|
|
|
_autoTransformCache.resize(maxSize);
|
|
}
|
|
|
|
|
|
void TextBase::releaseGLObjects(osg::State* state) const
|
|
{
|
|
Drawable::releaseGLObjects(state);
|
|
}
|
|
|
|
void TextBase::positionCursor(const osg::Vec2 & endOfLine_coords, osg::Vec2 & cursor, unsigned int linelength)
|
|
{
|
|
switch(_layout)
|
|
{
|
|
case LEFT_TO_RIGHT:
|
|
{
|
|
switch (_alignment)
|
|
{
|
|
// nothing to be done for these
|
|
//case LEFT_TOP:
|
|
//case LEFT_CENTER:
|
|
//case LEFT_BOTTOM:
|
|
//case LEFT_BASE_LINE:
|
|
//case LEFT_BOTTOM_BASE_LINE:
|
|
// break;
|
|
case CENTER_TOP:
|
|
case CENTER_CENTER:
|
|
case CENTER_BOTTOM:
|
|
case CENTER_BASE_LINE:
|
|
case CENTER_BOTTOM_BASE_LINE:
|
|
cursor.x() = (cursor.x() - endOfLine_coords.x()) * 0.5f;
|
|
break;
|
|
case RIGHT_TOP:
|
|
case RIGHT_CENTER:
|
|
case RIGHT_BOTTOM:
|
|
case RIGHT_BASE_LINE:
|
|
case RIGHT_BOTTOM_BASE_LINE:
|
|
cursor.x() = cursor.x() - endOfLine_coords.x();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case RIGHT_TO_LEFT:
|
|
{
|
|
switch (_alignment)
|
|
{
|
|
case LEFT_TOP:
|
|
case LEFT_CENTER:
|
|
case LEFT_BOTTOM:
|
|
case LEFT_BASE_LINE:
|
|
case LEFT_BOTTOM_BASE_LINE:
|
|
cursor.x() = 2*cursor.x() - endOfLine_coords.x();
|
|
break;
|
|
case CENTER_TOP:
|
|
case CENTER_CENTER:
|
|
case CENTER_BOTTOM:
|
|
case CENTER_BASE_LINE:
|
|
case CENTER_BOTTOM_BASE_LINE:
|
|
cursor.x() = cursor.x() + (cursor.x() - endOfLine_coords.x()) * 0.5f;
|
|
break;
|
|
// nothing to be done for these
|
|
//case RIGHT_TOP:
|
|
//case RIGHT_CENTER:
|
|
//case RIGHT_BOTTOM:
|
|
//case RIGHT_BASE_LINE:
|
|
//case RIGHT_BOTTOM_BASE_LINE:
|
|
// break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case VERTICAL:
|
|
{
|
|
switch (_alignment)
|
|
{
|
|
// TODO: current behaviour top baselines lined up in both cases - need to implement
|
|
// top of characters aligment - Question is this neccesary?
|
|
// ... otherwise, nothing to be done for these 6 cases
|
|
//case LEFT_TOP:
|
|
//case CENTER_TOP:
|
|
//case RIGHT_TOP:
|
|
// break;
|
|
//case LEFT_BASE_LINE:
|
|
//case CENTER_BASE_LINE:
|
|
//case RIGHT_BASE_LINE:
|
|
// break;
|
|
case LEFT_CENTER:
|
|
case CENTER_CENTER:
|
|
case RIGHT_CENTER:
|
|
cursor.y() = cursor.y() + (cursor.y() - endOfLine_coords.y()) * 0.5f;
|
|
break;
|
|
case LEFT_BOTTOM_BASE_LINE:
|
|
case CENTER_BOTTOM_BASE_LINE:
|
|
case RIGHT_BOTTOM_BASE_LINE:
|
|
cursor.y() = cursor.y() - (linelength * _characterHeight);
|
|
break;
|
|
case LEFT_BOTTOM:
|
|
case CENTER_BOTTOM:
|
|
case RIGHT_BOTTOM:
|
|
cursor.y() = 2*cursor.y() - endOfLine_coords.y();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|