From David Callu, added support of 3D text to osgText and associated plugins.

This commit is contained in:
Robert Osfield 2007-12-10 15:15:56 +00:00
parent 9b56dbe83a
commit f69a48e552
27 changed files with 3427 additions and 798 deletions

View File

@ -83,6 +83,7 @@ IF(DYNAMIC_OPENSCENEGRAPH)
ADD_SUBDIRECTORY(osgteapot)
ADD_SUBDIRECTORY(osgtessellate)#)
ADD_SUBDIRECTORY(osgtext)
ADD_SUBDIRECTORY(osgtext3D)
ADD_SUBDIRECTORY(osgtexture1D)
ADD_SUBDIRECTORY(osgtexture2D)
ADD_SUBDIRECTORY(osgtexture3D)

View File

@ -0,0 +1,7 @@
#this file is automatically generated
SET(TARGET_SRC osgtext3D.cpp )
SET(TARGET_ADDED_LIBRARIES osgText )
#### end var setup ###
SETUP_EXAMPLE(osgtext3D)

View File

@ -0,0 +1,137 @@
/* OpenSceneGraph example, osgtext.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgDB/ReadFile>
#include <osgGA/TrackballManipulator>
#include <osgGA/StateSetManipulator>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/Material>
#include <osg/Shape>
#include <osg/ShapeDrawable>
#include <osgText/Text3D>
#include <iostream>
#include <sstream>
// create text which sits in 3D space such as would be inserted into a normal model
osg::Group* create3DText(const osg::Vec3& center,float radius)
{
osg::Geode* geode = new osg::Geode;
////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Examples of how to set up axis/orientation alignments
//
float characterSize=radius*0.2f;
float characterDepth=characterSize*0.2f;
osg::Vec3 pos(center.x()-radius*.5f,center.y()-radius*.5f,center.z()-radius*.5f);
osgText::Text3D* text1 = new osgText::Text3D;
text1->setFont("fonts/arial.ttf");
text1->setCharacterSize(characterSize);
text1->setCharacterDepth(characterDepth);
text1->setPosition(pos);
text1->setDrawMode(osgText::Text3D::TEXT | osgText::Text3D::BOUNDINGBOX);
text1->setAxisAlignment(osgText::Text3D::XY_PLANE);
text1->setText("XY_PLANE");
geode->addDrawable(text1);
osgText::Text3D* text2 = new osgText::Text3D;
text2->setFont("fonts/times.ttf");
text2->setCharacterSize(characterSize);
text2->setCharacterDepth(characterDepth);
text2->setPosition(pos);
text2->setDrawMode(osgText::Text3D::TEXT | osgText::Text3D::BOUNDINGBOX);
text2->setAxisAlignment(osgText::Text3D::YZ_PLANE);
text2->setText("YZ_PLANE");
geode->addDrawable(text2);
osgText::Text3D* text3 = new osgText::Text3D;
text3->setFont("fonts/dirtydoz.ttf");
text3->setCharacterSize(characterSize);
text3->setCharacterDepth(characterDepth);
text3->setPosition(pos);
text3->setDrawMode(osgText::Text3D::TEXT | osgText::Text3D::BOUNDINGBOX);
text3->setAxisAlignment(osgText::Text3D::XZ_PLANE);
text3->setText("XZ_PLANE");
geode->addDrawable(text3);
osgText::Text3D* text7 = new osgText::Text3D;
text7->setFont("fonts/times.ttf");
text7->setCharacterSize(characterSize);
text7->setCharacterDepth(characterSize*0.2f);
text7->setPosition(center - osg::Vec3(0.0, 0.0, 0.6));
text7->setDrawMode(osgText::Text3D::TEXT | osgText::Text3D::BOUNDINGBOX);
text7->setAxisAlignment(osgText::Text3D::SCREEN);
text7->setCharacterSizeMode(osgText::Text3D::OBJECT_COORDS);
text7->setText("CharacterSizeMode OBJECT_COORDS (default)");
geode->addDrawable(text7);
osg::ShapeDrawable* shape = new osg::ShapeDrawable(new osg::Sphere(center,characterSize*0.2f));
shape->getOrCreateStateSet()->setMode(GL_LIGHTING,osg::StateAttribute::ON);
geode->addDrawable(shape);
osg::Group* rootNode = new osg::Group;
rootNode->addChild(geode);
osg::Material* front = new osg::Material;
front->setAlpha(osg::Material::FRONT_AND_BACK,1);
front->setAmbient(osg::Material::FRONT_AND_BACK,osg::Vec4(0.2,0.2,0.2,1.0));
front->setDiffuse(osg::Material::FRONT_AND_BACK,osg::Vec4(.0,.0,1.0,1.0));
rootNode->getOrCreateStateSet()->setAttributeAndModes(front);
return rootNode;
}
int main(int, char**)
{
osgViewer::Viewer viewer;
osg::Vec3 center(0.0f,0.0f,0.0f);
float radius = 1.0f;
osg::Group* root = new osg::Group;
root->addChild(create3DText(center, radius));
viewer.setSceneData(root);
viewer.setCameraManipulator(new osgGA::TrackballManipulator());
viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
viewer.addEventHandler(new osgViewer::ThreadingHandler);
viewer.addEventHandler(new osgViewer::WindowSizeHandler);
viewer.addEventHandler(new osgViewer::StatsHandler);
viewer.run();
return 0;
}

View File

@ -25,6 +25,7 @@
#include <osg/TexEnv>
#include <osgDB/ReaderWriter>
#include <osgText/Export>
#include <osgText/KerningType>
#include <OpenThreads/Mutex>
@ -32,12 +33,7 @@ namespace osgText {
class Font;
class Text;
enum KerningType
{
KERNING_DEFAULT, //default locked to integer kerning values
KERNING_UNFITTED, //use floating point value for kerning
KERNING_NONE //no kerning
};
/** Read a font from specified file. The filename may contain a path.
* It will search for the font file in the following places in this order:
@ -179,8 +175,6 @@ protected:
typedef std::pair< unsigned int, unsigned int > SizePair;
typedef std::map< SizePair, GlyphMap > SizeGlyphMap;
mutable FontMutex _serializeFontCallsMutex;
osg::ref_ptr<osg::TexEnv> _texenv;
osg::ref_ptr<osg::StateSet> _stateset;
SizeGlyphMap _sizeGlyphMap;

284
include/osgText/Font3D Normal file
View File

@ -0,0 +1,284 @@
/* -*-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.
*/
#ifndef OSGTEXT_FONT3D
#define OSGTEXT_FONT3D 1
#include <string>
#include <istream>
#include <osg/Vec2>
#include <osg/Geometry>
#include <osgDB/ReaderWriter>
#include <osgText/Export>
#include <osgText/KerningType>
#include <OpenThreads/Mutex>
namespace osgText {
class Font3D;
class Text3D;
/** Read a font from specified file. The filename may contain a path.
* It will search for the font file in the following places in this order:
* - In the current directory
* - All paths defined in OSG_FILE_PATH or OSGFILEPATH environment variable
* - Filename with path stripped: In the current directory
* - Filename with path stripped: All paths defined in OSG_FILE_PATH or OSGFILEPATH
*
* Then the file will be searched in OS specific directories in the following order:
* - Again in the current directory
* - Windows: In C:/winnt/fonts
* - Windows: In C:/windows/fonts
* - Windows: In the fonts directory of the windows install directory
* - Other OS: In /usr/share/fonts/ttf
* - Other OS: In /usr/share/fonts/ttf/western
* - Other OS: In /usr/share/fonts/ttf/decoratives
*
* If the given file could not be found, the path part will be stripped and
* the file will be searched again in the OS specific directories.
*/
extern OSGTEXT_EXPORT Font3D* readFont3DFile(const std::string& filename, const osgDB::ReaderWriter::Options* userOptions = 0);
/** read a font from specified stream.*/
extern OSGTEXT_EXPORT Font3D* readFont3DStream(std::istream& stream, const osgDB::ReaderWriter::Options* userOptions = 0);
extern OSGTEXT_EXPORT std::string findFont3DFile(const std::string& str);
/** Pure virtual base class for fonts.
* Concrete implementation are the DefaultFont found in src/osgText/DefaultFont.cpp
* and FreeTypeFont found in src/osgPlugins/freetype/FreeTypeFont.cpp*/
class OSGTEXT_EXPORT Font3D : public osg::Object
{
// declare the interface to a font.
public:
// forward declare nested classes.
class Glyph3D;
class Font3DImplementation;
public:
Font3D(Font3DImplementation* implementation=0);
virtual osg::Object* cloneType() const { return 0; } // cloneType() not appropriate
virtual osg::Object* clone(const osg::CopyOp&) const { return 0; } // clone() not appropriate
virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast<const Font3D*>(obj)!=NULL; }
virtual const char* className() const { return "Font3D"; }
virtual const char* libraryName() const { return "osgText"; }
virtual std::string getFileName() const;
/** Set the pixel width and height hint.*/
// virtual void setFontResolution(unsigned int width, unsigned int height, unsigned int depth);
unsigned int getFontWidth() const { return _width; }
unsigned int getFontHeight() const { return _height; }
unsigned int getFontDepth() const { return _depth; }
/** Get a kerning (adjustment of spacing of two adjacent character) for specified charcodes, w.r.t the current font size hint.*/
virtual osg::Vec2 getKerning(unsigned int leftcharcode,unsigned int rightcharcode, KerningType kerningType);
/** Get a Glyph for specified charcode, and the font size nearest to the current font size hint.*/
virtual Glyph3D* getGlyph(unsigned int charcode);
/** Return true if this font provides vertical alignments and spacing or glyphs.*/
virtual bool hasVertical() const;
/** Return the scale to apply on the glyph to have a charactere size equal to 1 */
virtual float getScale() const { return _implementation->getScale(); };
// make Text a friend to allow it add and remove its entry in the Font's _textList.
friend class Font3DImplementation;
void setImplementation(Font3DImplementation* implementation);
Font3DImplementation* getImplementation();
const Font3DImplementation* getImplementation() const;
/** Set whether to use a mutex to ensure ref() and unref() */
virtual void setThreadSafeRefUnref(bool threadSafe);
typedef OpenThreads::Mutex Font3DMutex;
/** Get the mutex that enables the serialization of calls to this font.*/
static Font3DMutex* getSerializeFontCallsMutex();
protected:
virtual ~Font3D();
// void addGlyph(unsigned int width, unsigned int height, unsigned int charcode, Glyph* glyph);
void addGlyph(unsigned int charcode, Glyph3D* glyph);
// current active size of font
unsigned int _depth;
unsigned int _width;
unsigned int _height;
// unsigned int _margin;
// float _marginRatio;
typedef std::map<char, osg::ref_ptr<Glyph3D> > Glyph3DMap;
Glyph3DMap _glyph3DMap;
osg::ref_ptr<Font3DImplementation> _implementation;
// declare the nested classes.
public:
class Font3DImplementation : public osg::Referenced
{
public:
Font3DImplementation():
osg::Referenced(true) {}
virtual std::string getFileName() const = 0;
/** Set the pixel width and height hint.*/
// virtual void setFontResolution(unsigned int width, unsigned int height, unsigned int depth) = 0;
/** Get a Glyph for specified charcode, and the font size nearest to the current font size hint.*/
virtual Glyph3D* getGlyph(unsigned int charcode) = 0;
/** Get a kerning (adjustment of spacing of two adjacent character) for specified charcodes, w.r.t the current font size hint.*/
virtual osg::Vec2 getKerning(unsigned int leftcharcode,unsigned int rightcharcode, KerningType kerningType) = 0;
/** Return true if this font provides vertical alignments and spacing or glyphs.*/
virtual bool hasVertical() const = 0;
virtual float getScale() const = 0;
void setFontWidth(unsigned int width) { _facade->_width = width; }
void setFontHeight(unsigned int height) { _facade->_height = height; }
void setFontDepth(unsigned int depth) { _facade->_depth = depth; }
// void addGlyph(unsigned int width, unsigned int height, unsigned int charcode, Glyph3D* glyph)
// {
// _facade->addGlyph(width, height, charcode, glyph);
// }
//
// void addGlyph(unsigned int charcode, Glyph3D* glyph)
// {
// _facade->addGlyph(charcode, glyph);
// }
Font3D* _facade;
};
class OSGTEXT_EXPORT Glyph3D : public osg::Referenced
{
public:
Glyph3D(unsigned int glyphCode):
_glyphCode(glyphCode),
_horizontalBearing(0,0),
_horizontalAdvance(0),
_verticalBearing(0,0),
_verticalAdvance(0)
{}
/** return -1 if *this < *rhs, 0 if *this==*rhs, 1 if *this>*rhs.*/
// virtual int compare(const osg::StateAttribute& rhs) const;
//
// virtual void apply(osg::State& state) const;
unsigned int getGlyphCode() const { return _glyphCode; }
void setHorizontalBearing(const osg::Vec2& bearing) { _horizontalBearing=bearing; }
const osg::Vec2 & getHorizontalBearing() const { return _horizontalBearing; }
void setHorizontalAdvance(float advance) { _horizontalAdvance=advance; }
float getHorizontalAdvance() const { return _horizontalAdvance; }
void setVerticalBearing(const osg::Vec2& bearing) { _verticalBearing=bearing; }
const osg::Vec2& getVerticalBearing() const { return _verticalBearing; }
void setVerticalAdvance(float advance) { _verticalAdvance=advance; }
float getVerticalAdvance() const { return _verticalAdvance; }
void setBoundingBox(osg::BoundingBox & bb) { _bb=bb; }
const osg::BoundingBox & getBoundingBox() const { return _bb; }
/** Set whether to use a mutex to ensure ref() and unref() are thread safe.*/
virtual void setThreadSafeRefUnref(bool threadSafe);
/** Get the PrimitiveSetList for the front face. */
osg::Geometry::PrimitiveSetList & getFrontPrimitiveSetList() { return _frontPrimitiveSetList; }
/** Get the PrimitiveSetList for the wall face. */
osg::Geometry::PrimitiveSetList & getWallPrimitiveSetList() { return _wallPrimitiveSetList; }
/** Get et the PrimitiveSetList for the back face. */
osg::Geometry::PrimitiveSetList & getBackPrimitiveSetList() { return _backPrimitiveSetList; }
/** Set the VertexArray of the glyph. */
void setVertexArray(osg::Vec3Array * va) { _vertexArray = va; }
/** Get the VertexArray of the glyph. */
osg::Vec3Array * getVertexArray() { return _vertexArray.get(); }
/** Get the NormalArray for the wall face. */
osg::Vec3Array * getNormalArray() { return _normalArray.get(); }
float getHorizontalWidth() { return (-_horizontalBearing.x() + _horizontalAdvance); }
float getHorizontalHeight() { return (-_horizontalBearing.y() + _bb.yMax()); }
float getVerticalWidth() { return (-_verticalBearing.x() + _bb.xMax()); }
float getVerticalHeight() { return (-_verticalBearing.y() + _verticalAdvance); }
void setWidth(float width) { _width = width; }
float getWidth() { return _width; }
void setHeight(float height) { _height = height; }
float getHeight() { return _height; }
protected:
virtual ~Glyph3D() {}
unsigned int _glyphCode;
osg::Vec2 _horizontalBearing;
float _horizontalAdvance;
osg::Vec2 _verticalBearing;
float _verticalAdvance;
osg::BoundingBox _bb;
// osg::Vec2 _advance;
float _width;
float _height;
osg::ref_ptr<osg::Vec3Array> _vertexArray;
osg::ref_ptr<osg::Vec3Array> _normalArray;
osg::Geometry::PrimitiveSetList _frontPrimitiveSetList;
osg::Geometry::PrimitiveSetList _wallPrimitiveSetList;
osg::Geometry::PrimitiveSetList _backPrimitiveSetList;
};
};
}
#endif

View File

@ -0,0 +1,26 @@
/* -*-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.
*/
#ifndef OSGTEXT_KERNINGTYPE
#define OSGTEXT_KERNINGTYPE
namespace osgText
{
enum KerningType
{
KERNING_DEFAULT, //default locked to integer kerning values
KERNING_UNFITTED, //use floating point value for kerning
KERNING_NONE //no kerning
};
}
#endif /*OSGTEXT_KERNINGTYPE*/

View File

@ -14,16 +14,17 @@
#ifndef OSGTEXT_TEXT
#define OSGTEXT_TEXT 1
#include <osg/Drawable>
#include <osg/Quat>
#include <osgText/TextBase>
#include <osgText/Font>
#include <osgText/String>
namespace osgText {
class OSGTEXT_EXPORT Text : public osg::Drawable
class OSGTEXT_EXPORT Text : public osgText::TextBase
{
public:
@ -50,179 +51,14 @@ public:
const Font* getFont() const { return _font.get(); }
/** Set the Font reference width and height resolution in texels.
* Note, the size may not be supported by current font,
* the closest supported font size will be selected.*/
void setFontResolution(unsigned int width, unsigned int height);
unsigned int getFontWidth() const { return _fontWidth; }
unsigned int getFontHeight() const { return _fontHeight; }
/** Set the text using a osgText::String.*/
void setText(const String& text);
/** Set the text using a std::string,
* which is converted to an internal TextString.*/
void setText(const std::string& text);
/** Set the text using a Unicode encoded std::string, which is converted to an internal TextString.
* The encoding parameter specificies which Unicode encodeding is used in the std::string. */
void setText(const std::string& text,String::Encoding encoding);
/** Set the text using a wchar_t string,
* which is converted to an internal TextString.*/
void setText(const wchar_t* text);
/** Get the text string.
* Note, if you modify the string you must call Text::update() for
* the internal glyph reprentation to be updated.*/
String& getText() { return _text; }
/** Get the const text string.*/
const String& getText() const { return _text; }
/** update internal glyph respresnetation used for rendering,
* and bounding volume.*/
void update() { computeGlyphRepresentation(); }
/** Set the rendered character size in object coordinates.*/
void setCharacterSize(float height,float aspectRatio=1.0f);
float getCharacterHeight() const { return _characterHeight; }
float getCharacterAspectRatio() const { return _characterAspectRatio; }
enum CharacterSizeMode
{
OBJECT_COORDS, /// default
SCREEN_COORDS, /// internally scale the characters to be constant screen size.
OBJECT_COORDS_WITH_MAXIMUM_SCREEN_SIZE_CAPPED_BY_FONT_HEIGHT /// text that behavaves like OBJECT_COORDS sized text when a long distance way, but has its screen sized capped automatically when the viewer gets near.
};
/** Set how the CharacterSize value relates to the final rendered character.*/
void setCharacterSizeMode(CharacterSizeMode mode) { _characterSizeMode = mode; }
/** Get the CharacterSizeMode.*/
CharacterSizeMode getCharacterSizeMode() const { return _characterSizeMode; }
/** Set the maximum width of the text box.
* With horizontal layouts any characters which do not fit are wrapped around.
* 0 or negative values indicate that no maximum width is set, lines can be as long as
* they need be to fit thre required text*/
void setMaximumWidth(float maximumWidth);
/** Get the maximim width of the text box.*/
float getMaximumWidth() const { return _maximumWidth; }
/** Set the maximum height of the text box.
* With horizontal layouts any characters which do not fit are wrapped around.
* 0 or negative values indicate that no maximum height is set, lines can be as long as
* they need be to fit the required text*/
void setMaximumHeight(float maximumHeight);
/** Get the maximum height of the text box.*/
float getMaximumHeight() const { return _maximumHeight; }
/** Set the line spacing of the text box, given as a percentage of
* the character height. The default value is 0 for backward
* compatibility. For longer paragraphs of text, a value of at
* least 25% (i.e. set line spacing to 0.25) is recommended. */
void setLineSpacing(float lineSpacing);
/** Get the line spacing of the text box. */
float getLineSpacing() const { return _lineSpacing; }
/** Set the position of text.*/
void setPosition(const osg::Vec3& pos);
/** Get the position of text.*/
const osg::Vec3& getPosition() const { return _position; }
enum AlignmentType
{
LEFT_TOP,
LEFT_CENTER,
LEFT_BOTTOM,
CENTER_TOP,
CENTER_CENTER,
CENTER_BOTTOM,
RIGHT_TOP,
RIGHT_CENTER,
RIGHT_BOTTOM,
LEFT_BASE_LINE,
CENTER_BASE_LINE,
RIGHT_BASE_LINE,
LEFT_BOTTOM_BASE_LINE,
CENTER_BOTTOM_BASE_LINE,
RIGHT_BOTTOM_BASE_LINE,
BASE_LINE = LEFT_BASE_LINE /// default.
};
void setAlignment(AlignmentType alignment);
AlignmentType getAlignment() const { return _alignment; }
enum AxisAlignment
{
XY_PLANE,
REVERSED_XY_PLANE,
XZ_PLANE,
REVERSED_XZ_PLANE,
YZ_PLANE,
REVERSED_YZ_PLANE,
SCREEN,
USER_DEFINED_ROTATION
};
void setAxisAlignment(AxisAlignment axis);
AxisAlignment getAxisAlignment() const { return _axisAlignment; }
void setRotation(const osg::Quat& quat);
const osg::Quat& getRotation() const { return _rotation; }
void setAutoRotateToScreen(bool autoRotateToScreen);
bool getAutoRotateToScreen() const { return _autoRotateToScreen; }
enum Layout
{
LEFT_TO_RIGHT, /// default
RIGHT_TO_LEFT,
VERTICAL
};
void setLayout(Layout layout);
Layout getLayout() const { return _layout; }
void setColor(const osg::Vec4& color);
const osg::Vec4& getColor() const { return _color; }
enum DrawModeMask
{
TEXT = 1, /// default
BOUNDINGBOX = 2,
ALIGNMENT = 4
};
void setDrawMode(unsigned int mode);
unsigned int getDrawMode() const { return _drawMode; }
enum BackdropType
{
DROP_SHADOW_BOTTOM_RIGHT = 0, // usually the type of shadow you see
@ -417,13 +253,7 @@ public:
const osg::Vec4& getColorGradientTopRight() const { return _colorGradientTopRight; }
void setKerningType(KerningType kerningType) { _kerningType = kerningType; }
KerningType getKerningType() const { return _kerningType; }
/** Get the number of wrapped lines - only valid after computeGlyphRepresentation() has been called, returns 0 otherwise */
unsigned int getLineCount() const { return _lineCount; }
/** Draw the text.*/
virtual void drawImplementation(osg::RenderInfo& renderInfo) const;
@ -454,9 +284,9 @@ public:
* for all graphics contexts. */
virtual void releaseGLObjects(osg::State* state=0) const;
// make Font a friend to allow it set the _font to 0 if the font is
// forcefully unloaded.
friend class Font;
// // make Font a friend to allow it set the _font to 0 if the font is
// // forcefully unloaded.
// friend class Font;
public:
// internal structures, variable and methods used for rendering of characters.
@ -510,7 +340,6 @@ public:
return _textureGlyphQuadMap;
}
virtual osg::BoundingBox computeBound() const;
protected:
@ -523,26 +352,7 @@ protected:
// members which have public access.
osg::ref_ptr<Font> _font;
unsigned int _fontWidth;
unsigned int _fontHeight;
float _characterHeight;
float _characterAspectRatio;
CharacterSizeMode _characterSizeMode;
float _maximumWidth;
float _maximumHeight;
float _lineSpacing;
String _text;
osg::Vec3 _position;
AlignmentType _alignment;
AxisAlignment _axisAlignment;
osg::Quat _rotation;
bool _autoRotateToScreen;
Layout _layout;
osg::Vec4 _color;
unsigned int _drawMode;
KerningType _kerningType;
unsigned int _lineCount;
// iternal map used for rendering. Set up by the computeGlyphRepresentation() method.
mutable TextureGlyphQuadMap _textureGlyphQuadMap;
@ -551,31 +361,9 @@ protected:
// internal caches of the positioning of the text.
struct AutoTransformCache
{
AutoTransformCache():
_traversalNumber(-1),
_width(0),
_height(0) {}
int _traversalNumber;
int _width;
int _height;
osg::Vec3 _transformedPosition;
osg::Matrix _modelview;
osg::Matrix _projection;
osg::Matrix _matrix;
};
mutable osg::buffered_object<AutoTransformCache> _autoTransformCache;
mutable osg::Vec3 _offset;
mutable osg::Vec3 _normal;
mutable osg::BoundingBox _textBB;
bool computeAverageGlyphWidthAndHeight(float& avg_width, float& avg_height) const;
void computePositions();
void computePositions(unsigned int contextID) const;
virtual void computePositions(unsigned int contextID) const;
void computeBackdropPositions(unsigned int contextID) const;
void computeBackdropBoundingBox() const;

292
include/osgText/TextBase Normal file
View File

@ -0,0 +1,292 @@
/* -*-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.
*/
#ifndef OSGTEXT_TEXTBASE
#define OSGTEXT_TEXTBASE 1
#include <osg/Drawable>
#include <osgText/String>
#include <osgText/KerningType>
namespace osgText {
class OSGTEXT_EXPORT TextBase : public osg::Drawable
{
public:
TextBase();
TextBase(const TextBase& text,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY);
//virtual osg::Object* cloneType() const { return new Text(); }
//virtual osg::Object* clone(const osg::CopyOp& copyop) const { return new Text(*this,copyop); }
virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast<const TextBase*>(obj)!=NULL; }
virtual const char* className() const { return "TextBase"; }
virtual const char* libraryName() const { return "osgText"; }
/** Set the Font reference width and height resolution in texels.
* Note, the size may not be supported by current font,
* the closest supported font size will be selected.*/
void setFontResolution(unsigned int width, unsigned int height);
unsigned int getFontWidth() const { return _fontWidth; }
unsigned int getFontHeight() const { return _fontHeight; }
/** Set the text using a osgText::String.*/
void setText(const String& text);
/** Set the text using a std::string,
* which is converted to an internal TextString.*/
void setText(const std::string& text);
/** Set the text using a Unicode encoded std::string, which is converted to an internal TextString.
* The encoding parameter specificies which Unicode encodeding is used in the std::string. */
void setText(const std::string& text,String::Encoding encoding);
/** Set the text using a wchar_t string,
* which is converted to an internal TextString.*/
void setText(const wchar_t* text);
/** Get the text string.
* Note, if you modify the string you must call Text::update() for
* the internal glyph reprentation to be updated.*/
String& getText() { return _text; }
/** Get the const text string.*/
const String& getText() const { return _text; }
/** update internal glyph respresentation used for rendering,
* and bounding volume.*/
void update() { computeGlyphRepresentation(); }
/** Set the rendered character size in object coordinates.*/
void setCharacterSize(float height,float aspectRatio=1.0f);
float getCharacterHeight() const { return _characterHeight; }
float getCharacterAspectRatio() const { return _characterAspectRatio; }
enum CharacterSizeMode
{
OBJECT_COORDS, /// default
SCREEN_COORDS, /// internally scale the characters to be constant screen size.
OBJECT_COORDS_WITH_MAXIMUM_SCREEN_SIZE_CAPPED_BY_FONT_HEIGHT /// text that behavaves like OBJECT_COORDS sized text when a long distance way, but has its screen sized capped automatically when the viewer gets near.
};
/** Set how the CharacterSize value relates to the final rendered character.*/
void setCharacterSizeMode(CharacterSizeMode mode) { _characterSizeMode = mode; }
/** Get the CharacterSizeMode.*/
CharacterSizeMode getCharacterSizeMode() const { return _characterSizeMode; }
/** Set the maximum width of the text box.
* With horizontal layouts any characters which do not fit are wrapped around.
* 0 or negative values indicate that no maximum width is set, lines can be as long as
* they need be to fit thre required text*/
void setMaximumWidth(float maximumWidth);
/** Get the maximim width of the text box.*/
float getMaximumWidth() const { return _maximumWidth; }
/** Set the maximum height of the text box.
* With horizontal layouts any characters which do not fit are wrapped around.
* 0 or negative values indicate that no maximum height is set, lines can be as long as
* they need be to fit the required text*/
void setMaximumHeight(float maximumHeight);
/** Get the maximum height of the text box.*/
float getMaximumHeight() const { return _maximumHeight; }
/** Set the line spacing of the text box, given as a percentage of
* the character height. The default value is 0 for backward
* compatibility. For longer paragraphs of text, a value of at
* least 25% (i.e. set line spacing to 0.25) is recommended. */
void setLineSpacing(float lineSpacing);
/** Get the line spacing of the text box. */
float getLineSpacing() const { return _lineSpacing; }
/** Set the position of text.*/
void setPosition(const osg::Vec3& pos);
/** Get the position of text.*/
const osg::Vec3& getPosition() const { return _position; }
enum AlignmentType
{
LEFT_TOP,
LEFT_CENTER,
LEFT_BOTTOM,
CENTER_TOP,
CENTER_CENTER,
CENTER_BOTTOM,
RIGHT_TOP,
RIGHT_CENTER,
RIGHT_BOTTOM,
LEFT_BASE_LINE,
CENTER_BASE_LINE,
RIGHT_BASE_LINE,
LEFT_BOTTOM_BASE_LINE,
CENTER_BOTTOM_BASE_LINE,
RIGHT_BOTTOM_BASE_LINE,
BASE_LINE = LEFT_BASE_LINE /// default.
};
void setAlignment(AlignmentType alignment);
AlignmentType getAlignment() const { return _alignment; }
enum AxisAlignment
{
XY_PLANE,
REVERSED_XY_PLANE,
XZ_PLANE,
REVERSED_XZ_PLANE,
YZ_PLANE,
REVERSED_YZ_PLANE,
SCREEN,
USER_DEFINED_ROTATION
};
void setAxisAlignment(AxisAlignment axis);
AxisAlignment getAxisAlignment() const { return _axisAlignment; }
void setRotation(const osg::Quat& quat);
const osg::Quat& getRotation() const { return _rotation; }
void setAutoRotateToScreen(bool autoRotateToScreen);
bool getAutoRotateToScreen() const { return _autoRotateToScreen; }
enum Layout
{
LEFT_TO_RIGHT, /// default
RIGHT_TO_LEFT,
VERTICAL
};
void setLayout(Layout layout);
Layout getLayout() const { return _layout; }
enum DrawModeMask
{
TEXT = 1, /// default
BOUNDINGBOX = 2,
ALIGNMENT = 4
};
void setDrawMode(unsigned int mode);
unsigned int getDrawMode() const { return _drawMode; }
void setKerningType(KerningType kerningType) { _kerningType = kerningType; }
KerningType getKerningType() const { return _kerningType; }
/** Get the number of wrapped lines - only valid after computeGlyphRepresentation() has been called, returns 0 otherwise */
unsigned int getLineCount() const { return _lineCount; }
/** Set whether to use a mutex to ensure ref() and unref() are thread safe.*/
virtual void setThreadSafeRefUnref(bool threadSafe);
/** Resize any per context GLObject buffers to specified size. */
virtual void resizeGLObjectBuffers(unsigned int maxSize);
/** If State is non-zero, this function releases OpenGL objects for
* the specified graphics context. Otherwise, releases OpenGL objexts
* for all graphics contexts. */
virtual void releaseGLObjects(osg::State* state=0) const;
virtual osg::BoundingBox computeBound() const;
protected:
virtual ~TextBase();
void positionCursor(const osg::Vec2 & endOfLine_coords, osg::Vec2 & cursor, unsigned int linelength);
void computePositions();
String::iterator computeLastCharacterOnLine(osg::Vec2& cursor, String::iterator first,String::iterator last);
virtual void computePositions(unsigned int contextID) const = 0;
virtual void computeGlyphRepresentation() = 0;
// members which have public access.
unsigned int _fontWidth;
unsigned int _fontHeight;
float _characterHeight;
float _characterAspectRatio;
CharacterSizeMode _characterSizeMode;
float _maximumWidth;
float _maximumHeight;
float _lineSpacing;
String _text;
osg::Vec3 _position;
AlignmentType _alignment;
AxisAlignment _axisAlignment;
osg::Quat _rotation;
bool _autoRotateToScreen;
Layout _layout;
unsigned int _drawMode;
KerningType _kerningType;
unsigned int _lineCount;
// internal caches of the positioning of the text.
struct AutoTransformCache
{
AutoTransformCache():
_traversalNumber(-1),
_width(0),
_height(0) {}
int _traversalNumber;
int _width;
int _height;
osg::Vec3 _transformedPosition;
osg::Matrix _modelview;
osg::Matrix _projection;
osg::Matrix _matrix;
};
mutable osg::buffered_object<AutoTransformCache> _autoTransformCache;
mutable osg::Vec3 _offset;
mutable osg::Vec3 _normal;
mutable osg::BoundingBox _textBB;
};
}
#endif

View File

@ -7,8 +7,8 @@
INCLUDE_DIRECTORIES(${FREETYPE_INCLUDE_DIRS} )
SET(TARGET_SRC FreeTypeFont.cpp FreeTypeLibrary.cpp ReaderWriterFreeType.cpp )
SET(TARGET_H FreeTypeFont.h FreeTypeLibrary.h )
SET(TARGET_SRC FreeTypeFont.cpp FreeTypeFont3D.cpp FreeTypeLibrary.cpp ReaderWriterFreeType.cpp )
SET(TARGET_H FreeTypeFont.h FreeTypeFont3D.h FreeTypeLibrary.h )
SET(TARGET_ADDED_LIBRARIES osgText )
SET(TARGET_LIBRARIES_VARS FREETYPE_LIBRARY )
#### end var setup ###

View File

@ -34,7 +34,7 @@ public:
virtual void setFontResolution(unsigned int width, unsigned int height);
virtual osgText::Font::Glyph* getGlyph(unsigned int charcode);
virtual osg::Vec2 getKerning(unsigned int leftcharcode,unsigned int rightcharcode, osgText::KerningType _kerningType);
virtual bool hasVertical() const;

View File

@ -0,0 +1,521 @@
/* -*-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 "FreeTypeFont3D.h"
#include "FreeTypeLibrary.h"
#include <limits.h>
#include <fstream>
#include <osg/Geometry>
#include <osg/Notify>
#include <osgDB/WriteFile>
#include <osgUtil/SmoothingVisitor>
#include <osgUtil/Tessellator>
#include <ft2build.h>
#include FT_FREETYPE_H
#include <freetype/ftoutln.h>
#include <freetype/ftbbox.h>
namespace
{
struct Char3DInfo
{
Char3DInfo(int numSteps=50):
_verts( new osg::Vec3Array ),
_geometry( new osg::Geometry ),
_idx(0),
_numSteps(numSteps),
_maxY(-FLT_MAX),
_maxX(-FLT_MAX),
_minX(FLT_MAX),
_minY(FLT_MAX)
{
}
~Char3DInfo()
{
}
osg::Geometry* get()
{
int len = _verts->size()-_idx;
if (len)
{
_geometry->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::POLYGON, _idx, len ) );
_idx = _verts->size();
}
_geometry->setVertexArray(_verts.get());
return _geometry.get();
}
void moveTo(osg::Vec2 pos)
{
if (_verts->size())
{
int len = _verts->size()-_idx;
_geometry->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::POLYGON, _idx, len ) );
}
_idx = _verts->size();
_verts->push_back( osg::Vec3(pos.x(),pos.y(),0) );
setMinMax(pos);
}
void lineTo(osg::Vec2 pos)
{
_verts->push_back( osg::Vec3(pos.x(),pos.y(),0) );
setMinMax(pos);
}
void conicTo(osg::Vec2 control, osg::Vec2 pos)
{
osg::Vec3 p0 = _verts->back();
osg::Vec3 p1 = osg::Vec3(control.x(),control.y(),0);
osg::Vec3 p2 = osg::Vec3(pos.x(),pos.y(),0);
double dt = 1.0/_numSteps;
double u=0;
for (int i=0; i<=_numSteps; ++i)
{
double w = 1;
double bs = 1.0/( (1-u)*(1-u)+2*(1-u)*u*w +u*u );
osg::Vec3 p = (p0*((1-u)*(1-u)) + p1*(2*(1-u)*u*w) + p2*(u*u))*bs;
_verts->push_back( p );
u += dt;
}
setMinMax(pos);
}
void cubicTo(osg::Vec2 control1, osg::Vec2 control2, osg::Vec2 pos)
{
osg::Vec3 p0 = _verts->back();
osg::Vec3 p1 = osg::Vec3(control1.x(),control1.y(),0);
osg::Vec3 p2 = osg::Vec3(control2.x(),control2.y(),0);
osg::Vec3 p3 = osg::Vec3(pos.x(),pos.y(),0);
double cx = 3*(p1.x() - p0.x());
double bx = 3*(p2.x() - p1.x()) - cx;
double ax = p3.x() - p0.x() - cx - bx;
double cy = 3*(p1.y() - p0.y());
double by = 3*(p2.y() - p1.y()) - cy;
double ay = p3.y() - p0.y() - cy - by;
double dt = 1.0/_numSteps;
double u=0;
for (int i=0; i<=_numSteps; ++i)
{
osg::Vec3 p = osg::Vec3( ax*u*u*u + bx*u*u + cx*u + p0.x(),ay*u*u*u + by*u*u + cy*u + p0.y(),0 );
_verts->push_back( p );
u += dt;
}
setMinMax(pos);
}
void setMinMax(osg::Vec2 pos)
{
_maxY = std::max(_maxY, (double) pos.y());
_minY = std::min(_minY, (double) pos.y());
_maxX = std::max(_maxX, (double) pos.x());
_minX = std::min(_minX, (double) pos.x());
}
osg::ref_ptr<osg::Vec3Array> _verts;
osg::ref_ptr<osg::Geometry> _geometry;
int _idx;
int _numSteps;
double _maxY;
double _maxX;
double _minX;
double _minY;
};
#define FT_NUM(x) (x/64.0)
int moveTo( const FT_Vector* to, void* user )
{
Char3DInfo* char3d = (Char3DInfo*)user;
char3d->moveTo( osg::Vec2(FT_NUM(to->x),FT_NUM(to->y)) );
return 0;
}
int lineTo( const FT_Vector* to, void* user )
{
Char3DInfo* char3d = (Char3DInfo*)user;
char3d->lineTo( osg::Vec2(FT_NUM(to->x),FT_NUM(to->y)) );
return 0;
}
int conicTo( const FT_Vector* control,const FT_Vector* to, void* user )
{
Char3DInfo* char3d = (Char3DInfo*)user;
char3d->conicTo( osg::Vec2(FT_NUM(control->x),FT_NUM(control->y)), osg::Vec2(FT_NUM(to->x),FT_NUM(to->y)) );
return 0;
}
int cubicTo( const FT_Vector* control1,const FT_Vector* control2,const FT_Vector* to, void* user )
{
Char3DInfo* char3d = (Char3DInfo*)user;
char3d->cubicTo(
osg::Vec2(FT_NUM(control1->x),FT_NUM(control1->y)),
osg::Vec2(FT_NUM(control2->x),FT_NUM(control2->y)),
osg::Vec2(FT_NUM(to->x),FT_NUM(to->y)) );
return 0;
}
#undef FT_NUM
}
FreeTypeFont3D::FreeTypeFont3D(const std::string& filename, FT_Face face, unsigned int flags):
_filename(filename),
_buffer(0),
_face(face),
_flags(flags)
{
init();
}
FreeTypeFont3D::FreeTypeFont3D(FT_Byte* buffer, FT_Face face, unsigned int flags):
_filename(""),
_buffer(buffer),
_face(face),
_flags(flags)
{
init();
}
void FreeTypeFont3D::init()
{
FT_Error _error = FT_Set_Pixel_Sizes(_face, 32, 32);
if (_error)
{
osg::notify(osg::NOTICE) << "FreeTypeFont3D: set pixel sizes failed ..." << std::endl;
return;
}
FT_Set_Char_Size( _face, 64*64, 64*64, 600, 600);
int glyphIndex = FT_Get_Char_Index( _face, 'M' );
_error = FT_Load_Glyph( _face, glyphIndex, FT_LOAD_DEFAULT );
if (_error)
{
osg::notify(osg::NOTICE) << "FreeTypeFont3D: initial glyph load failed ..." << std::endl;
return;
}
if (_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
{
osg::notify(osg::NOTICE) << "FreeTypeFont3D: not a vector font" << std::endl;
return;
}
{
Char3DInfo char3d;
FT_Outline outline = _face->glyph->outline;
FT_Outline_Funcs funcs;
funcs.conic_to = (FT_Outline_ConicToFunc)&conicTo;
funcs.line_to = (FT_Outline_LineToFunc)&lineTo;
funcs.cubic_to = (FT_Outline_CubicToFunc)&cubicTo;
funcs.move_to = (FT_Outline_MoveToFunc)&moveTo;
funcs.shift = 0;
funcs.delta = 0;
_error = FT_Outline_Decompose(&outline,&funcs,&char3d);
if (_error)
{
osg::notify(osg::NOTICE) << "FreeTypeFont3D: - outline decompose failed ..." << std::endl;
return;
}
FT_BBox bb;
FT_Outline_Get_BBox(&outline,&bb);
long xmin = ft_floor( bb.xMin );
long xmax = ft_ceiling( bb.xMax );
long ymin = ft_floor( bb.yMin );
long ymax = ft_ceiling( bb.yMax );
double width = (xmax - xmin)/64.0;
double height = (ymax - ymin)/64.0;
_scale = 1.0/height;
double charHeight = char3d._maxY-char3d._minY;
double charWidth = char3d._maxX-char3d._minX;
double dh = fabs(bb.yMin/64.0)/height;
double dw = fabs(bb.xMin/64.0)/width;
_shiftY = char3d._minY + dh*charHeight;
_shiftX = char3d._minX + dw*charWidth;
_charScale = 1/charHeight;
}
}
FreeTypeFont3D::~FreeTypeFont3D()
{
if(_face)
{
FreeTypeLibrary* freeTypeLibrary = FreeTypeLibrary::instance();
if (freeTypeLibrary)
{
// remove myself from the local registry to ensure that
// not dangling pointers remain
freeTypeLibrary->removeFont3DImplmentation(this);
// free the freetype font face itself
FT_Done_Face(_face);
_face = 0;
// release memory held for FT_Face to work
if (_buffer)
{
delete [] _buffer;
_buffer = 0;
}
}
}
}
osgText::Font3D::Glyph3D * FreeTypeFont3D::getGlyph(unsigned int charcode)
{
//
// GT: fix for symbol fonts (i.e. the Webdings font) as the wrong character are being
// returned, for symbol fonts in windows (FT_ENCONDING_MS_SYMBOL in freetype) the correct
// values are from 0xF000 to 0xF0FF not from 0x000 to 0x00FF (0 to 255) as you would expect.
// Microsoft uses a private field for its symbol fonts
//
unsigned int charindex = charcode;
if (_face->charmap != NULL)
{
if (_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
{
charindex |= 0xF000;
}
}
FT_Error error = FT_Load_Char( _face, charindex, FT_LOAD_DEFAULT|_flags );
if (error)
{
osg::notify(osg::WARN) << "FT_Load_Char(...) error 0x"<<std::hex<<error<<std::dec<<std::endl;
return 0;
}
if (_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
{
osg::notify(osg::WARN) << "FreeTypeFont3D::getGlyph : not a vector font" << std::endl;
return 0;
}
// ** init FreeType to describe the glyph
Char3DInfo char3d;
FT_Outline outline = _face->glyph->outline;
FT_Outline_Funcs funcs;
funcs.conic_to = (FT_Outline_ConicToFunc)&conicTo;
funcs.line_to = (FT_Outline_LineToFunc)&lineTo;
funcs.cubic_to = (FT_Outline_CubicToFunc)&cubicTo;
funcs.move_to = (FT_Outline_MoveToFunc)&moveTo;
funcs.shift = 0;
funcs.delta = 0;
// ** record description
FT_Error _error = FT_Outline_Decompose(&outline, &funcs, &char3d);
if (_error)
{
osg::notify(osg::WARN) << "FreeTypeFont3D::getGlyph : - outline decompose failed ..." << std::endl;
return 0;
}
// ** create geometry for each part of the glyph
osg::ref_ptr<osg::Geometry> frontGeo(new osg::Geometry);
frontGeo->setVertexArray(char3d.get()->getVertexArray());
frontGeo->setPrimitiveSetList(char3d.get()->getPrimitiveSetList());
osg::ref_ptr<osg::Geometry> wallGeo(new osg::Geometry);
wallGeo->setVertexArray(frontGeo->getVertexArray());
osg::ref_ptr<osg::Geometry> backGeo(new osg::Geometry);
backGeo->setVertexArray(frontGeo->getVertexArray());
// ** for conveniance.
osg::Vec3Array * vertices = char3d._verts.get();
// ** duplicate the vertex for the back face
// ** with a depth equal to the font depth
std::size_t len = vertices->size();
std::size_t dlen = len * 2;
vertices->reserve(dlen);
osg::Vec3Array::iterator begin = vertices->begin();
osg::Vec3Array::iterator it = vertices->begin();
for (std::size_t i = 0; i != len; ++i, ++it)
vertices->push_back(*it);
// std::copy(begin, begin + len, begin + len + 1); TOCHECK
// ** and decal new vertices
unsigned int depth = _facade->getFontDepth();
for (std::size_t i = len; i != dlen; ++i)
{
(*vertices)[i].z() -= depth;
}
osg::Vec3Array::iterator end;
// ** create wall and back face from the front polygon
// ** then accumulate them in the apropriate geometry wallGeo and backGeo
for (std::size_t i=0; i < frontGeo->getNumPrimitiveSets(); ++i)
{
// ** get the front polygon
osg::ref_ptr<osg::DrawArrays> daFront(dynamic_cast<osg::DrawArrays*>(frontGeo->getPrimitiveSet(i)));
unsigned int idx = daFront->getFirst();
unsigned int cnt = daFront->getCount();
// ** reverse vertices to draw the front face in the CCW
std::reverse(begin + idx, begin + idx + cnt);
// ** create the back polygon
osg::ref_ptr<osg::DrawArrays> daBack(new osg::DrawArrays(osg::PrimitiveSet::POLYGON, idx + len, cnt));
backGeo->addPrimitiveSet(daBack.get());
// ** create the wall triangle strip
osg::ref_ptr<osg::DrawElementsUInt> deWall(new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLE_STRIP));
wallGeo->addPrimitiveSet(deWall.get());
// ** link triangle strip
deWall->push_back(idx + len);
for (unsigned int j = 1; j < cnt; ++j)
{
deWall->push_back(idx + cnt - j);
deWall->push_back(idx + len + j);
}
deWall->push_back(idx);
deWall->push_back(idx + len);
deWall->push_back(idx + cnt - 1);
}
// ** tesselate front and back face
{
osgUtil::Tessellator ts;
ts.setWindingType(osgUtil::Tessellator::TESS_WINDING_POSITIVE);
ts.setTessellationType(osgUtil::Tessellator::TESS_TYPE_GEOMETRY);
ts.retessellatePolygons(*frontGeo);
}
{
osgUtil::Tessellator ts;
ts.setWindingType(osgUtil::Tessellator::TESS_WINDING_POSITIVE);
ts.setTessellationType(osgUtil::Tessellator::TESS_TYPE_GEOMETRY);
ts.retessellatePolygons(*backGeo);
}
// ** generate normal
{
osgUtil::SmoothingVisitor sm;
osg::ref_ptr<osg::Geode> geode(new osg::Geode);
geode->addDrawable(wallGeo.get());
geode->accept(sm);
}
// ** save vertices and PrimitiveSetList of each face in the Glyph3D PrimitiveSet face list
osgText::Font3D::Glyph3D * glyph3D = new osgText::Font3D::Glyph3D(charcode);
glyph3D->setVertexArray(dynamic_cast<osg::Vec3Array*>(frontGeo->getVertexArray()));
glyph3D->getFrontPrimitiveSetList() = frontGeo->getPrimitiveSetList();
glyph3D->getWallPrimitiveSetList() = wallGeo->getPrimitiveSetList();
glyph3D->getBackPrimitiveSetList() = backGeo->getPrimitiveSetList();
FT_Glyph_Metrics* metrics = &(_face->glyph->metrics);
glyph3D->setHorizontalBearing(osg::Vec2((float)metrics->horiBearingX/64.0f,(float)(metrics->horiBearingY-metrics->height)/64.0f)); // bottom left.
glyph3D->setHorizontalAdvance((float)metrics->horiAdvance/64.0f);
glyph3D->setVerticalBearing(osg::Vec2((float)metrics->vertBearingX/64.0f,(float)(metrics->vertBearingY-metrics->height)/64.0f)); // top middle.
glyph3D->setVerticalAdvance((float)metrics->vertAdvance/64.0f);
glyph3D->setWidth((float)metrics->width / 64.0f);
glyph3D->setHeight((float)metrics->height / 64.0f);
FT_BBox ftbb;
FT_Outline_Get_BBox(&outline, &ftbb);
long xmin = ft_floor( ftbb.xMin );
long xmax = ft_ceiling( ftbb.xMax );
long ymin = ft_floor( ftbb.yMin );
long ymax = ft_ceiling( ftbb.yMax );
osg::BoundingBox bb(xmin / 64.0f, ymin / 64.0f, 0.0f, xmax / 64.0f, ymax / 64.0f, 0.0f);
glyph3D->setBoundingBox(bb);
return glyph3D;
}
osg::Vec2 FreeTypeFont3D::getKerning(unsigned int leftcharcode,unsigned int rightcharcode, osgText::KerningType kerningType)
{
if (!FT_HAS_KERNING(_face) || (kerningType == osgText::KERNING_NONE)) return osg::Vec2(0.0f,0.0f);
FT_Kerning_Mode mode = (kerningType==osgText::KERNING_DEFAULT) ? ft_kerning_default : ft_kerning_unfitted;
// convert character code to glyph index
FT_UInt left = FT_Get_Char_Index( _face, leftcharcode );
FT_UInt right = FT_Get_Char_Index( _face, rightcharcode );
// get the kerning distances.
FT_Vector kerning;
FT_Error error = FT_Get_Kerning( _face, // handle to face object
left, // left glyph index
right, // right glyph index
mode, // kerning mode
&kerning ); // target vector
if (error)
{
osg::notify(osg::WARN) << "FT_Get_Kerning(...) returned error code " <<std::hex<<error<<std::dec<< std::endl;
return osg::Vec2(0.0f,0.0f);
}
return osg::Vec2((float)kerning.x/64.0f,(float)kerning.y/64.0f);
}
bool FreeTypeFont3D::hasVertical() const
{
return FT_HAS_VERTICAL(_face)!=0;
}
float FreeTypeFont3D::getScale() const
{
return _scale;
}

View File

@ -0,0 +1,64 @@
/* -*-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.
*/
#ifndef FREETYPE_FONT3D
#define FREETYPE_FONT3D 1
#include <osgText/Font3D>
#include <ft2build.h>
#include FT_FREETYPE_H
class FreeTypeFont3D : public osgText::Font3D::Font3DImplementation
{
// declare the interface to a font.
public:
FreeTypeFont3D(const std::string& filename, FT_Face face, unsigned int flags);
FreeTypeFont3D(FT_Byte* buffer, FT_Face face, unsigned int flags);
virtual std::string getFileName() const { return _filename; }
// virtual void setFontResolution(unsigned int width, unsigned int height, unsigned int depth);
virtual osgText::Font3D::Glyph3D * getGlyph(unsigned int charcode);
virtual osg::Vec2 getKerning(unsigned int leftcharcode,unsigned int rightcharcode, osgText::KerningType _kerningType);
virtual bool hasVertical() const;
virtual float getScale() const;
protected:
void init();
long ft_round( long x ) { return (( x + 32 ) & -64); }
long ft_floor( long x ) { return (x & -64); }
long ft_ceiling( long x ){ return (( x + 63 ) & -64); }
virtual ~FreeTypeFont3D();
std::string _filename;
FT_Byte* _buffer;
FT_Face _face;
unsigned int _flags;
double _scale;
double _shiftY;
double _shiftX;
double _charScale;
};
#endif

View File

@ -0,0 +1,224 @@
/* -*-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 "FreeTypeFont.h"
#include "FreeTypeLibrary.h"
#include <osg/Notify>
#include <osgDB/WriteFile>
FreeTypeFont::FreeTypeFont(const std::string& filename, FT_Face face, unsigned int flags):
_filename(filename),
_buffer(0),
_face(face),
_flags(flags)
{
}
FreeTypeFont::FreeTypeFont(FT_Byte* buffer, FT_Face face, unsigned int flags):
_filename(""),
_buffer(buffer),
_face(face),
_flags(flags)
{
}
FreeTypeFont::~FreeTypeFont()
{
if(_face)
{
FreeTypeLibrary* freeTypeLibrary = FreeTypeLibrary::instance();
if (freeTypeLibrary)
{
// remove myself from the local registry to ensure that
// not dangling pointers remain
freeTypeLibrary->removeFontImplmentation(this);
// free the freetype font face itself
FT_Done_Face(_face);
_face = 0;
// release memory held for FT_Face to work
if (_buffer)
{
delete [] _buffer;
_buffer = 0;
}
}
}
}
void FreeTypeFont::setFontResolution(unsigned int width, unsigned int height)
{
int maxAxis = std::max(width, height);
int margin = _facade->getGlyphImageMargin() + (int)((float)maxAxis * _facade->getGlyphImageMarginRatio());
if (width+2*margin>_facade->getTextureWidthHint() ||
width+2*margin>_facade->getTextureHeightHint())
{
osg::notify(osg::WARN)<<"Warning: FreeTypeFont::setSize("<<width<<","<<height<<") sizes too large,"<<std::endl;
width = _facade->getTextureWidthHint()-2*margin;
height = _facade->getTextureHeightHint()-2*margin;
osg::notify(osg::WARN)<<" sizes capped ("<<width<<","<<height<<") to fit int current glyph texture size."<<std::endl;
}
FT_Error error = FT_Set_Pixel_Sizes( _face, /* handle to face object */
width, /* pixel_width */
height ); /* pixel_height */
if (error)
{
osg::notify(osg::WARN)<<"FT_Set_Pixel_Sizes() - error 0x"<<std::hex<<error<<std::dec<<std::endl;
}
else
{
setFontWidth(width);
setFontHeight(height);
}
}
osgText::Font::Glyph* FreeTypeFont::getGlyph(unsigned int charcode)
{
//
// GT: fix for symbol fonts (i.e. the Webdings font) as the wrong character are being
// returned, for symbol fonts in windows (FT_ENCONDING_MS_SYMBOL in freetype) the correct
// values are from 0xF000 to 0xF0FF not from 0x000 to 0x00FF (0 to 255) as you would expect.
// Microsoft uses a private field for its symbol fonts
//
unsigned int charindex = charcode;
if (_face->charmap != NULL)
{
if (_face->charmap->encoding == FT_ENCODING_MS_SYMBOL)
{
charindex |= 0xF000;
}
}
FT_Error error = FT_Load_Char( _face, charindex, FT_LOAD_RENDER|FT_LOAD_NO_BITMAP|_flags );
if (error)
{
osg::notify(osg::WARN) << "FT_Load_Char(...) error 0x"<<std::hex<<error<<std::dec<<std::endl;
return 0;
}
FT_GlyphSlot glyphslot = _face->glyph;
int pitch = glyphslot->bitmap.pitch;
unsigned char* buffer = glyphslot->bitmap.buffer;
unsigned int sourceWidth = glyphslot->bitmap.width;;
unsigned int sourceHeight = glyphslot->bitmap.rows;
unsigned int width = sourceWidth;
unsigned int height = sourceHeight;
osg::ref_ptr<osgText::Font::Glyph> glyph = new osgText::Font::Glyph;
unsigned int dataSize = width*height;
unsigned char* data = new unsigned char[dataSize];
// clear the image to zeros.
for(unsigned char* p=data;p<data+dataSize;) { *p++ = 0; }
glyph->setImage(width,height,1,
GL_ALPHA,
GL_ALPHA,GL_UNSIGNED_BYTE,
data,
osg::Image::USE_NEW_DELETE,
1);
glyph->setInternalTextureFormat(GL_ALPHA);
// copy image across to osgText::Glyph image.
switch(glyphslot->bitmap.pixel_mode)
{
case FT_PIXEL_MODE_MONO:
for(int r=sourceHeight-1;r>=0;--r)
{
unsigned char* ptr = buffer+r*pitch;
for(unsigned int c=0;c<sourceWidth;++c)
{
(*data++)= (ptr[c >> 3] & (1 << (~c & 7))) ? 255 : 0;
}
}
break;
case FT_PIXEL_MODE_GRAY:
for(int r=sourceHeight-1;r>=0;--r)
{
unsigned char* ptr = buffer+r*pitch;
for(unsigned int c=0;c<sourceWidth;++c,++ptr)
{
(*data++)=*ptr;
}
}
break;
default:
osg::notify(osg::WARN) << "FT_Load_Char(...) returned bitmap with unknown pixel_mode " << glyphslot->bitmap.pixel_mode << std::endl;
}
FT_Glyph_Metrics* metrics = &(glyphslot->metrics);
glyph->setHorizontalBearing(osg::Vec2((float)metrics->horiBearingX/64.0f,(float)(metrics->horiBearingY-metrics->height)/64.0f)); // bottom left.
glyph->setHorizontalAdvance((float)metrics->horiAdvance/64.0f);
glyph->setVerticalBearing(osg::Vec2((float)metrics->vertBearingX/64.0f,(float)(metrics->vertBearingY-metrics->height)/64.0f)); // top middle.
glyph->setVerticalAdvance((float)metrics->vertAdvance/64.0f);
addGlyph(_facade->getFontWidth(),_facade->getFontHeight(),charcode,glyph.get());
// cout << " in getGlyph() implementation="<<this<<" "<<_filename<<" facade="<<_facade<<endl;
return glyph.get();
}
osg::Vec2 FreeTypeFont::getKerning(unsigned int leftcharcode,unsigned int rightcharcode, osgText::KerningType kerningType)
{
if (!FT_HAS_KERNING(_face) || (kerningType == osgText::KERNING_NONE)) return osg::Vec2(0.0f,0.0f);
FT_Kerning_Mode mode = (kerningType==osgText::KERNING_DEFAULT) ? ft_kerning_default : ft_kerning_unfitted;
// convert character code to glyph index
FT_UInt left = FT_Get_Char_Index( _face, leftcharcode );
FT_UInt right = FT_Get_Char_Index( _face, rightcharcode );
// get the kerning distances.
FT_Vector kerning;
FT_Error error = FT_Get_Kerning( _face, // handle to face object
left, // left glyph index
right, // right glyph index
mode, // kerning mode
&kerning ); // target vector
if (error)
{
osg::notify(osg::WARN) << "FT_Get_Kerning(...) returned error code " <<std::hex<<error<<std::dec<< std::endl;
return osg::Vec2(0.0f,0.0f);
}
return osg::Vec2((float)kerning.x/64.0f,(float)kerning.y/64.0f);
}
bool FreeTypeFont::hasVertical() const
{
return FT_HAS_VERTICAL(_face)!=0;
}

View File

@ -0,0 +1,46 @@
/* -*-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.
*/
#ifndef FREETYPE_FONTBASE
#define FREETYPE_FONTBASE 1
#include <ft2build.h>
#include FT_FREETYPE_H
class FreeTypeFontBase : public osgText::Font::FontImplementation
{
// declare the interface to a font.
public:
FreeTypeFont(const std::string& filename, FT_Face face, unsigned int flags);
FreeTypeFont(FT_Byte* buffer, FT_Face face, unsigned int flags);
virtual ~FreeTypeFont();
virtual std::string getFileName() const { return _filename; }
virtual void setFontResolution(unsigned int width, unsigned int height);
virtual osg::Vec2 getKerning(unsigned int leftcharcode,unsigned int rightcharcode, osgText::KerningType _kerningType);
virtual bool hasVertical() const;
protected:
std::string _filename;
FT_Byte* _buffer;
FT_Face _face;
unsigned int _flags;
};
#endif

View File

@ -13,7 +13,7 @@
#include "FreeTypeLibrary.h"
#include <osg/Notify>
#include <ft2build.h>
//#include <ft2build.h>
//#define PRINT_OUT_FONT_DETAILS
#ifdef PRINT_OUT_FONT_DETAILS
@ -24,6 +24,7 @@
FreeTypeLibrary::FreeTypeLibrary()
{
osg::notify(osg::INFO) << "FreeTypeLibrary::FreeTypeLibrary()" << std::endl;
FT_Error error = FT_Init_FreeType( &_ftlibrary );
if (error)
{
@ -47,6 +48,14 @@ FreeTypeLibrary::~FreeTypeLibrary()
font->setImplementation(0);
}
while(!_font3DImplementationSet.empty())
{
FreeTypeFont3D* font3DImplementation = *_font3DImplementationSet.begin();
_font3DImplementationSet.erase(_font3DImplementationSet.begin());
osgText::Font3D* font3D = font3DImplementation->_facade;
font3D->setImplementation(0);
}
FT_Done_FreeType( _ftlibrary);
}
@ -56,22 +65,20 @@ FreeTypeLibrary* FreeTypeLibrary::instance()
return s_library.get();
}
osgText::Font* FreeTypeLibrary::getFont(const std::string& fontfile,unsigned int index, unsigned int flags)
bool FreeTypeLibrary::getFace(const std::string& fontfile,unsigned int index, FT_Face & face)
{
FT_Face face; /* handle to face object */
FT_Error error = FT_New_Face( _ftlibrary, fontfile.c_str(), index, &face );
if (error == FT_Err_Unknown_File_Format)
{
osg::notify(osg::WARN)<<" .... the font file could be opened and read, but it appears"<<std::endl;
osg::notify(osg::WARN)<<" .... that its font format is unsupported"<<std::endl;
return 0;
return false;
}
else if (error)
{
osg::notify(osg::WARN)<<" .... another error code means that the font file could notd"<<std::endl;
osg::notify(osg::WARN)<<" .... be opened, read or simply that it is broken..d"<<std::endl;
return 0;
return false;
}
#ifdef PRINT_OUT_FONT_DETAILS
@ -96,18 +103,11 @@ osgText::Font* FreeTypeLibrary::getFont(const std::string& fontfile,unsigned int
//
verifyCharacterMap(face);
FreeTypeFont* fontImp = new FreeTypeFont(fontfile,face,flags);
osgText::Font* font = new osgText::Font(fontImp);
_fontImplementationSet.insert(fontImp);
return font;
return true;
}
osgText::Font* FreeTypeLibrary::getFont(std::istream& fontstream, unsigned int index, unsigned int flags)
FT_Byte* FreeTypeLibrary::getFace(std::istream& fontstream, unsigned int index, FT_Face & face)
{
FT_Face face; /* handle to face object */
FT_Open_Args args;
std::streampos start = fontstream.tellg();
@ -142,12 +142,36 @@ osgText::Font* FreeTypeLibrary::getFont(std::istream& fontstream, unsigned int i
osg::notify(osg::WARN)<<" .... be opened, read or simply that it is broken..."<<std::endl;
return 0;
}
//
// GT: Fix to handle symbol fonts in MS Windows
//
verifyCharacterMap(face);
return buffer;
}
osgText::Font* FreeTypeLibrary::getFont(const std::string& fontfile, unsigned int index, unsigned int flags)
{
FT_Face face;
if (getFace(fontfile, index, face) == false) return (0);
FreeTypeFont* fontImp = new FreeTypeFont(fontfile,face,flags);
osgText::Font* font = new osgText::Font(fontImp);
_fontImplementationSet.insert(fontImp);
return font;
}
osgText::Font* FreeTypeLibrary::getFont(std::istream& fontstream, unsigned int index, unsigned int flags)
{
FT_Face face = 0;
FT_Byte * buffer = getFace(fontstream, index, face);
if (face == 0) return (0);
FreeTypeFont* fontImp = new FreeTypeFont(buffer,face,flags);
osgText::Font* font = new osgText::Font(fontImp);
@ -156,6 +180,34 @@ osgText::Font* FreeTypeLibrary::getFont(std::istream& fontstream, unsigned int i
return font;
}
osgText::Font3D* FreeTypeLibrary::getFont3D(const std::string& fontfile, unsigned int index, unsigned int flags)
{
FT_Face face;
if (getFace(fontfile, index, face) == false) return (0);
FreeTypeFont3D* font3DImp = new FreeTypeFont3D(fontfile,face,flags);
osgText::Font3D* font3D = new osgText::Font3D(font3DImp);
_font3DImplementationSet.insert(font3DImp);
return font3D;
}
osgText::Font3D* FreeTypeLibrary::getFont3D(std::istream& fontstream, unsigned int index, unsigned int flags)
{
FT_Face face = 0;
FT_Byte * buffer = getFace(fontstream, index, face);
if (face == 0) return (0);
FreeTypeFont3D* font3DImp = new FreeTypeFont3D(buffer,face,flags);
osgText::Font3D* font3D = new osgText::Font3D(font3DImp);
_font3DImplementationSet.insert(font3DImp);
return font3D;
}
void FreeTypeLibrary::verifyCharacterMap(FT_Face face)
{
//

View File

@ -15,10 +15,16 @@
#define FREETYPE_LIBRARY
#include "FreeTypeFont.h"
#include <osgText/Font>
#include "FreeTypeFont3D.h"
#include <set>
#include <istream>
#include <osgText/Font>
#include <osgText/Font3D>
#include <ft2build.h>
class FreeTypeLibrary : public osg::Referenced
{
public:
@ -32,10 +38,19 @@ public:
osgText::Font* getFont(const std::string& fontfile,unsigned int index=0, unsigned int flags=0);
osgText::Font* getFont(std::istream& fontstream, unsigned int index=0, unsigned int flags=0);
osgText::Font3D* getFont3D(const std::string& fontfile, unsigned int index=0, unsigned int flags=0);
osgText::Font3D* getFont3D(std::istream& fontstream, unsigned int index=0, unsigned int flags=0);
void removeFontImplmentation(FreeTypeFont* fontImpl) { _fontImplementationSet.erase(fontImpl); }
void removeFont3DImplmentation(FreeTypeFont3D* font3DImpl) { _font3DImplementationSet.erase(font3DImpl); }
protected:
/** common method to load a FT_Face from a file*/
bool getFace(const std::string& fontfile,unsigned int index, FT_Face & face);
/** common method to load a FT_Face from a stream */
FT_Byte* getFace(std::istream& fontstream, unsigned int index, FT_Face & face);
/** Verify the correct character mapping for MS windows */
void verifyCharacterMap(FT_Face face);
@ -44,10 +59,11 @@ protected:
FreeTypeLibrary();
typedef std::set< FreeTypeFont* > FontImplementationSet;
typedef std::set< FreeTypeFont3D* > Font3DImplementationSet;
FT_Library _ftlibrary;
FontImplementationSet _fontImplementationSet;
Font3DImplementationSet _font3DImplementationSet;
};

View File

@ -49,7 +49,10 @@ class ReaderWriterFreeType : public osgDB::ReaderWriter
return ReadResult::ERROR_IN_READING_FILE;
}
return freeTypeLibrary->getFont(fileName,0,getFlags(options));
if (options->getPluginData("3D"))
return freeTypeLibrary->getFont3D(fileName,0,getFlags(options));
else
return freeTypeLibrary->getFont(fileName,0,getFlags(options));
}
virtual ReadResult readObject(std::istream& stream, const osgDB::ReaderWriter::Options* options) const

View File

@ -170,6 +170,17 @@ extern "C" {
class ReaderWriterJP2 : public osgDB::ReaderWriter
{
public:
ReaderWriterJP2()
{
// little dance here to get around warnings created by jas_image_strtofmt use of char* rather than const char*
// as a parameted and modern compilers deprecating "jp2" string being treated as char*.
char* jp2 = strdup("jp2");
_fmt_jp2 = jas_image_strtofmt(jp2);
free(jp2);
}
virtual const char* className() const { return "RGB Image Reader/Writer"; }
virtual bool acceptsExtension(const std::string& extension) const
@ -411,7 +422,7 @@ class ReaderWriterJP2 : public osgDB::ReaderWriter
opt = new char[options->getOptionString().size() + 1];
strcpy(opt, options->getOptionString().c_str());
}
jas_image_encode(jimage, out, jas_image_strtofmt("jp2"), opt);
jas_image_encode(jimage, out, _fmt_jp2, opt);
if(opt) delete[] opt;
jas_stream_flush(out);
@ -491,7 +502,8 @@ class ReaderWriterJP2 : public osgDB::ReaderWriter
opt = new char[options->getOptionString().size() + 1];
strcpy(opt, options->getOptionString().c_str());
}
jas_image_encode(jimage, out, jas_image_strtofmt("jp2"), opt);
jas_image_encode(jimage, out, _fmt_jp2, opt);
if(opt) delete[] opt;
jas_stream_flush(out);
@ -511,6 +523,8 @@ class ReaderWriterJP2 : public osgDB::ReaderWriter
return WriteResult::FILE_SAVED;
}
int _fmt_jp2;
};
// now register with Registry to instantiate the above

View File

@ -1,7 +1,7 @@
#this file is automatically generated
SET(TARGET_SRC IO_Text.cpp )
SET(TARGET_SRC IO_TextBase.cpp IO_Text.cpp IO_Text3D.cpp )
SET(TARGET_ADDED_LIBRARIES osgText )
#### end var setup ###
SETUP_PLUGIN(osgtext)

View File

@ -20,11 +20,84 @@ osgDB::RegisterDotOsgWrapperProxy Text_Proxy
(
new osgText::Text,
"Text",
"Object Drawable Text",
"Object Drawable TextBase Text",
Text_readLocalData,
Text_writeLocalData
);
osgText::Text::BackdropType convertBackdropTypeStringToEnum(std::string & str)
{
if (str=="DROP_SHADOW_BOTTOM_RIGHT") return osgText::Text::DROP_SHADOW_BOTTOM_RIGHT;
else if (str=="DROP_SHADOW_CENTER_RIGHT") return osgText::Text::DROP_SHADOW_CENTER_RIGHT;
else if (str=="DROP_SHADOW_TOP_RIGHT") return osgText::Text::DROP_SHADOW_TOP_RIGHT;
else if (str=="DROP_SHADOW_BOTTOM_CENTER") return osgText::Text::DROP_SHADOW_BOTTOM_CENTER;
else if (str=="DROP_SHADOW_TOP_CENTER") return osgText::Text::DROP_SHADOW_TOP_CENTER;
else if (str=="DROP_SHADOW_BOTTOM_LEFT") return osgText::Text::DROP_SHADOW_BOTTOM_LEFT;
else if (str=="DROP_SHADOW_CENTER_LEFT") return osgText::Text::DROP_SHADOW_CENTER_LEFT;
else if (str=="DROP_SHADOW_TOP_LEFT") return osgText::Text::DROP_SHADOW_TOP_LEFT;
else if (str=="OUTLINE") return osgText::Text::OUTLINE;
else if (str=="NONE") return osgText::Text::NONE;
else return static_cast<osgText::Text::BackdropType>(-1);
}
std::string convertBackdropTypeEnumToString(osgText::Text::BackdropType backdropType)
{
switch (backdropType)
{
case osgText::Text::DROP_SHADOW_BOTTOM_RIGHT: return "DROP_SHADOW_BOTTOM_RIGHT";
case osgText::Text::DROP_SHADOW_CENTER_RIGHT: return "DROP_SHADOW_CENTER_RIGHT";
case osgText::Text::DROP_SHADOW_TOP_RIGHT: return "DROP_SHADOW_TOP_RIGHT";
case osgText::Text::DROP_SHADOW_BOTTOM_CENTER: return "DROP_SHADOW_BOTTOM_CENTER";
case osgText::Text::DROP_SHADOW_TOP_CENTER: return "DROP_SHADOW_TOP_CENTER";
case osgText::Text::DROP_SHADOW_BOTTOM_LEFT: return "DROP_SHADOW_BOTTOM_LEFT";
case osgText::Text::DROP_SHADOW_CENTER_LEFT: return "DROP_SHADOW_CENTER_LEFT";
case osgText::Text::DROP_SHADOW_TOP_LEFT: return "DROP_SHADOW_TOP_LEFT";
case osgText::Text::OUTLINE: return "OUTLINE";
case osgText::Text::NONE: return "NONE";
default : return "";
}
}
osgText::Text::BackdropImplementation convertBackdropImplementationStringToEnum(std::string & str)
{
if (str=="POLYGON_OFFSET") return osgText::Text::POLYGON_OFFSET;
else if (str=="NO_DEPTH_BUFFER") return osgText::Text::NO_DEPTH_BUFFER;
else if (str=="DEPTH_RANGE") return osgText::Text::DEPTH_RANGE;
else if (str=="STENCIL_BUFFER") return osgText::Text::STENCIL_BUFFER;
else return static_cast<osgText::Text::BackdropImplementation>(-1);
}
std::string convertBackdropImplementationEnumToString(osgText::Text::BackdropImplementation backdropImplementation)
{
switch (backdropImplementation)
{
case osgText::Text::POLYGON_OFFSET: return "POLYGON_OFFSET";
case osgText::Text::NO_DEPTH_BUFFER: return "NO_DEPTH_BUFFER";
case osgText::Text::DEPTH_RANGE: return "DEPTH_RANGE";
case osgText::Text::STENCIL_BUFFER: return "STENCIL_BUFFER";
default : return "";
}
}
osgText::Text::ColorGradientMode convertColorGradientModeStringToEnum(std::string & str)
{
if (str=="SOLID") return osgText::Text::SOLID;
else if (str=="PER_CHARACTER") return osgText::Text::PER_CHARACTER;
else if (str=="OVERALL") return osgText::Text::OVERALL;
else return static_cast<osgText::Text::ColorGradientMode>(-1);
}
std::string convertColorGradientModeEnumToString(osgText::Text::ColorGradientMode colorGradientMode)
{
switch (colorGradientMode)
{
case osgText::Text::SOLID: return "SOLID";
case osgText::Text::PER_CHARACTER: return "PER_CHARACTER";
case osgText::Text::OVERALL: return "OVERALL";
default : return "";
}
}
bool Text_readLocalData(osg::Object &obj, osgDB::Input &fr)
{
osgText::Text &text = static_cast<osgText::Text &>(obj);
@ -39,157 +112,6 @@ bool Text_readLocalData(osg::Object &obj, osgDB::Input &fr)
}
if (fr[0].matchWord("fontResolution") || fr[0].matchWord("fontSize"))
{
unsigned int width;
unsigned int height;
if (fr[1].getUInt(width) && fr[2].getUInt(height))
{
text.setFontResolution(width,height);
fr += 3;
itAdvanced = true;
}
}
if (fr[0].matchWord("characterSize"))
{
float height;
float aspectRatio;
if (fr[1].getFloat(height) && fr[2].getFloat(aspectRatio))
{
text.setCharacterSize(height,aspectRatio);
fr += 3;
itAdvanced = true;
}
}
if (fr.matchSequence("characterSizeMode %w"))
{
std::string str = fr[1].getStr();
if (str=="OBJECT_COORDS") text.setCharacterSizeMode(osgText::Text::OBJECT_COORDS);
else if (str=="SCREEN_COORDS") text.setCharacterSizeMode(osgText::Text::SCREEN_COORDS);
else if (str=="OBJECT_COORDS_WITH_MAXIMUM_SCREEN_SIZE_CAPPED_BY_FONT_HEIGHT") text.setCharacterSizeMode(osgText::Text::OBJECT_COORDS_WITH_MAXIMUM_SCREEN_SIZE_CAPPED_BY_FONT_HEIGHT);
}
// maximum dimentsions of text box.
if (fr[0].matchWord("maximumWidth"))
{
float width;
if (fr[1].getFloat(width))
{
text.setMaximumWidth(width);
fr += 2;
itAdvanced = true;
}
}
if (fr[0].matchWord("maximumHeight"))
{
float height;
if (fr[1].getFloat(height))
{
text.setMaximumHeight(height);
fr += 2;
itAdvanced = true;
}
}
if (fr[0].matchWord("lineSpacing"))
{
float height;
if (fr[1].getFloat(height))
{
text.setLineSpacing(height);
fr += 2;
itAdvanced = true;
}
}
if (fr.matchSequence("alignment %w"))
{
std::string str = fr[1].getStr();
if (str=="LEFT_TOP") text.setAlignment(osgText::Text::LEFT_TOP);
else if (str=="LEFT_CENTER") text.setAlignment(osgText::Text::LEFT_CENTER);
else if (str=="LEFT_BOTTOM") text.setAlignment(osgText::Text::LEFT_BOTTOM);
else if (str=="CENTER_TOP") text.setAlignment(osgText::Text::CENTER_TOP);
else if (str=="CENTER_CENTER") text.setAlignment(osgText::Text::CENTER_CENTER);
else if (str=="CENTER_BOTTOM") text.setAlignment(osgText::Text::CENTER_BOTTOM);
else if (str=="RIGHT_TOP") text.setAlignment(osgText::Text::RIGHT_TOP);
else if (str=="RIGHT_CENTER") text.setAlignment(osgText::Text::RIGHT_CENTER);
else if (str=="RIGHT_BOTTOM") text.setAlignment(osgText::Text::RIGHT_BOTTOM);
else if (str=="LEFT_BASE_LINE") text.setAlignment(osgText::Text::LEFT_BASE_LINE);
else if (str=="CENTER_BASE_LINE") text.setAlignment(osgText::Text::CENTER_BASE_LINE);
else if (str=="RIGHT_BASE_LINE") text.setAlignment(osgText::Text::RIGHT_BASE_LINE);
else if (str=="LEFT_BOTTOM_BASE_LINE") text.setAlignment(osgText::Text::LEFT_BOTTOM_BASE_LINE);
else if (str=="CENTER_BOTTOM_BASE_LINE") text.setAlignment(osgText::Text::CENTER_BOTTOM_BASE_LINE);
else if (str=="RIGHT_BOTTOM_BASE_LINE") text.setAlignment(osgText::Text::RIGHT_BOTTOM_BASE_LINE);
else if (str=="BASE_LINE") text.setAlignment(osgText::Text::BASE_LINE);
fr += 2;
itAdvanced = true;
}
if (fr.matchSequence("axisAlignment %w"))
{
std::string str = fr[1].getStr();
if (str=="XY_PLANE") text.setAxisAlignment(osgText::Text::XY_PLANE);
else if (str=="REVERSED_XY_PLANE") text.setAxisAlignment(osgText::Text::REVERSED_XY_PLANE);
else if (str=="XZ_PLANE") text.setAxisAlignment(osgText::Text::XZ_PLANE);
else if (str=="REVERSED_XZ_PLANE") text.setAxisAlignment(osgText::Text::REVERSED_XZ_PLANE);
else if (str=="YZ_PLANE") text.setAxisAlignment(osgText::Text::YZ_PLANE);
else if (str=="REVERSED_YZ_PLANE") text.setAxisAlignment(osgText::Text::REVERSED_YZ_PLANE);
else if (str=="SCREEN") text.setAxisAlignment(osgText::Text::SCREEN);
fr += 2;
itAdvanced = true;
}
if (fr.matchSequence("rotation"))
{
osg::Vec4 rotation;
if (fr[1].getFloat(rotation.x()) && fr[2].getFloat(rotation.y()) && fr[3].getFloat(rotation.z()) && fr[4].getFloat(rotation.w()))
{
text.setRotation(rotation);
fr += 4;
itAdvanced = true;
}
}
if (fr.matchSequence("autoRotateToScreen TRUE"))
{
text.setAutoRotateToScreen(true);
fr += 2;
itAdvanced = true;
}
if (fr.matchSequence("autoScaleToLimitScreenSizeToFontResolution TRUE"))
{
text.setCharacterSizeMode(osgText::Text::SCREEN_COORDS);
fr += 2;
itAdvanced = true;
}
if (fr.matchSequence("layout %w") && fr[1].getStr())
{
std::string str = fr[1].getStr();
if (str=="LEFT_TO_RIGHT") text.setLayout(osgText::Text::LEFT_TO_RIGHT);
else if (str=="RIGHT_TO_LEFT") text.setLayout(osgText::Text::RIGHT_TO_LEFT);
else if (str=="VERTICAL") text.setLayout(osgText::Text::VERTICAL);
fr += 2;
itAdvanced = true;
}
// position
if (fr[0].matchWord("position"))
{
osg::Vec3 p;
if (fr[1].getFloat(p.x()) && fr[2].getFloat(p.y()) && fr[3].getFloat(p.z()))
{
text.setPosition(p);
fr += 4;
itAdvanced = true;
}
}
// color
if (fr[0].matchWord("color"))
{
@ -202,57 +124,137 @@ bool Text_readLocalData(osg::Object &obj, osgDB::Input &fr)
}
}
// draw mode
if (fr[0].matchWord("drawMode"))
// backdropType
if (fr[0].matchWord("backdropType"))
{
int i;
if (fr[1].getInt(i)) {
text.setDrawMode(i);
std::string str = fr[1].getStr();
osgText::Text::BackdropType backdropType = convertBackdropTypeStringToEnum(str);
if (backdropType != static_cast<osgText::Text::BackdropType>(-1))
text.setBackdropType(backdropType);
fr += 2;
itAdvanced = true;
}
float backdropHorizontalOffset = text.getBackdropHorizontalOffset();
float backdropVerticalOffset = text.getBackdropVerticalOffset();
// backdropHorizontalOffset
if (fr[0].matchWord("backdropHorizontalOffset"))
{
if (fr[1].getFloat(backdropHorizontalOffset))
{
fr += 2;
itAdvanced = true;
}
}
// text
if (fr.matchSequence("text %s") && fr[1].getStr()) {
text.setText(std::string(fr[1].getStr()));
// backdropVerticalOffset
if (fr[0].matchWord("backdropVerticalOffset"))
{
if (fr[1].getFloat(backdropVerticalOffset))
{
fr += 2;
itAdvanced = true;
}
}
text.setBackdropOffset(backdropHorizontalOffset, backdropVerticalOffset);
// backdropColor
if (fr[0].matchWord("backdropColor"))
{
osg::Vec4 c;
if (fr[1].getFloat(c.x()) && fr[2].getFloat(c.y()) && fr[3].getFloat(c.z()) && fr[4].getFloat(c.w()))
{
text.setBackdropColor(c);
fr += 4;
itAdvanced = true;
}
}
// backdropImplementation
if (fr[0].matchWord("backdropImplementation"))
{
std::string str = fr[1].getStr();
osgText::Text::BackdropImplementation backdropImplementation = convertBackdropImplementationStringToEnum(str);
if (backdropImplementation != static_cast<osgText::Text::BackdropImplementation>(-1))
text.setBackdropImplementation(backdropImplementation);
fr += 2;
itAdvanced = true;
}
if (fr.matchSequence("text %i {"))
// ColorGradientMode
if (fr[0].matchWord("colorGradientMode"))
{
// pre 0.9.3 releases..
int entry = fr[0].getNoNestedBrackets();
int capacity;
fr[1].getInt(capacity);
osgText::String str;
str.reserve(capacity);
fr += 3;
while (!fr.eof() && fr[0].getNoNestedBrackets()>entry)
{
unsigned int c;
if (fr[0].getUInt(c))
{
++fr;
str.push_back(c);
}
else
{
++fr;
}
}
text.setText(str);
std::string str = fr[1].getStr();
osgText::Text::ColorGradientMode colorGradientMode = convertColorGradientModeStringToEnum(str);
if (colorGradientMode != static_cast<osgText::Text::ColorGradientMode>(-1))
text.setColorGradientMode(colorGradientMode);
fr += 2;
itAdvanced = true;
++fr;
}
// ** get default value;
osg::Vec4 colorGradientTopLeft = text.getColorGradientTopLeft();
osg::Vec4 colorGradientBottomLeft = text.getColorGradientBottomLeft();
osg::Vec4 colorGradientBottomRight = text.getColorGradientBottomRight();
osg::Vec4 colorGradientTopRight = text.getColorGradientTopRight();
// colorGradientTopLeft
if (fr[0].matchWord("colorGradientTopLeft"))
{
osg::Vec4 c;
if (fr[1].getFloat(c.x()) && fr[2].getFloat(c.y()) && fr[3].getFloat(c.z()) && fr[4].getFloat(c.w()))
{
colorGradientTopLeft = c;
fr += 4;
itAdvanced = true;
}
}
// colorGradientBottomLeft
if (fr[0].matchWord("colorGradientBottomLeft"))
{
osg::Vec4 c;
if (fr[1].getFloat(c.x()) && fr[2].getFloat(c.y()) && fr[3].getFloat(c.z()) && fr[4].getFloat(c.w()))
{
colorGradientBottomLeft = c;
fr += 4;
itAdvanced = true;
}
}
// colorGradientBottomRight
if (fr[0].matchWord("colorGradientBottomRight"))
{
osg::Vec4 c;
if (fr[1].getFloat(c.x()) && fr[2].getFloat(c.y()) && fr[3].getFloat(c.z()) && fr[4].getFloat(c.w()))
{
colorGradientBottomRight = c;
fr += 4;
itAdvanced = true;
}
}
// colorGradientTopRight
if (fr[0].matchWord("colorGradientTopRight"))
{
osg::Vec4 c;
if (fr[1].getFloat(c.x()) && fr[2].getFloat(c.y()) && fr[3].getFloat(c.z()) && fr[4].getFloat(c.w()))
{
colorGradientTopRight = c;
fr += 4;
itAdvanced = true;
}
}
text.setColorGradientCorners(colorGradientTopLeft, colorGradientBottomLeft, colorGradientBottomRight, colorGradientTopRight);
return itAdvanced;
}
@ -265,126 +267,44 @@ bool Text_writeLocalData(const osg::Object &obj, osgDB::Output &fw)
fw.indent() << "font " << text.getFont()->getFileName() << std::endl;
}
// font resolution
fw.indent() << "fontResolution " << text.getFontWidth() << " " << text.getFontHeight() << std::endl;
// charater size.
fw.indent() << "characterSize " << text.getCharacterHeight() << " " << text.getCharacterAspectRatio() << std::endl;
fw.indent() << "characterSizeMode ";
switch(text.getCharacterSizeMode())
{
case osgText::Text::OBJECT_COORDS : fw<<"OBJECT_COORDS"<<std::endl; break;
case osgText::Text::SCREEN_COORDS : fw<<"SCREEN_COORDS"<<std::endl; break;
case osgText::Text::OBJECT_COORDS_WITH_MAXIMUM_SCREEN_SIZE_CAPPED_BY_FONT_HEIGHT: fw<<"OBJECT_COORDS_WITH_MAXIMUM_SCREEN_SIZE_CAPPED_BY_FONT_HEIGHT"<<std::endl; break;
}
// maximum dimension of text box.
if (text.getMaximumWidth()>0.0f)
{
fw.indent() << "maximumWidth " << text.getMaximumWidth() << std::endl;
}
if (text.getMaximumHeight()>0.0f)
{
fw.indent() << "maximumHeight " << text.getMaximumHeight() << std::endl;
}
if (text.getLineSpacing()>0.0f)
{
fw.indent() << "lineSpacing " << text.getLineSpacing() << std::endl;
}
// alignment
fw.indent() << "alignment ";
switch(text.getAlignment())
{
case osgText::Text::LEFT_TOP: fw << "LEFT_TOP" << std::endl; break;
case osgText::Text::LEFT_CENTER : fw << "LEFT_CENTER" << std::endl; break;
case osgText::Text::LEFT_BOTTOM : fw << "LEFT_BOTTOM" << std::endl; break;
case osgText::Text::CENTER_TOP: fw << "CENTER_TOP" << std::endl; break;
case osgText::Text::CENTER_CENTER: fw << "CENTER_CENTER" << std::endl; break;
case osgText::Text::CENTER_BOTTOM: fw << "CENTER_BOTTOM" << std::endl; break;
case osgText::Text::RIGHT_TOP: fw << "RIGHT_TOP" << std::endl; break;
case osgText::Text::RIGHT_CENTER: fw << "RIGHT_CENTER" << std::endl; break;
case osgText::Text::RIGHT_BOTTOM: fw << "RIGHT_BOTTOM" << std::endl; break;
case osgText::Text::LEFT_BASE_LINE: fw << "LEFT_BASE_LINE" << std::endl; break;
case osgText::Text::CENTER_BASE_LINE:fw << "CENTER_BASE_LINE" << std::endl; break;
case osgText::Text::RIGHT_BASE_LINE: fw << "RIGHT_BASE_LINE" << std::endl; break;
case osgText::Text::LEFT_BOTTOM_BASE_LINE: fw << "LEFT_BOTTOM_BASE_LINE" << std::endl; break;
case osgText::Text::CENTER_BOTTOM_BASE_LINE:fw << "CENTER_BOTTOM_BASE_LINE" << std::endl; break;
case osgText::Text::RIGHT_BOTTOM_BASE_LINE: fw << "RIGHT_BOTTOM_BASE_LINE" << std::endl; break;
};
if (!text.getRotation().zeroRotation())
{
fw.indent() << "rotation " << text.getRotation() << std::endl;
}
if (text.getAutoRotateToScreen())
{
fw.indent() << "autoRotateToScreen TRUE"<< std::endl;
}
// layout
fw.indent() << "layout ";
switch(text.getLayout())
{
case osgText::Text::LEFT_TO_RIGHT: fw << "LEFT_TO_RIGHT" << std::endl; break;
case osgText::Text::RIGHT_TO_LEFT: fw << "RIGHT_TO_LEFT" << std::endl; break;
case osgText::Text::VERTICAL: fw << "VERTICAL" << std::endl; break;
};
// position
osg::Vec3 p = text.getPosition();
fw.indent() << "position " << p.x() << " " << p.y() << " " << p.z() << std::endl;
// color
osg::Vec4 c = text.getColor();
fw.indent() << "color " << c.x() << " " << c.y() << " " << c.z() << " " << c.w() << std::endl;
// draw mode
fw.indent() << "drawMode " << text.getDrawMode() << std::endl;
// text
const osgText::String& textstring = text.getText();
bool isACString = true;
osgText::String::const_iterator itr;
for(itr=textstring.begin();
itr!=textstring.end() && isACString;
++itr)
{
if (*itr==0 || *itr>256) isACString=false;
}
if (isACString)
{
std::string str;
for(itr=textstring.begin();
itr!=textstring.end();
++itr)
{
str += (char)(*itr);
}
//std::copy(textstring.begin(),textstring.end(),std::back_inserter(str));
// backdropType
fw.indent() << "backdropType " << convertBackdropTypeEnumToString(text.getBackdropType()) << std::endl;
// backdropHorizontalOffset
fw.indent() << "backdropHorizontalOffset " << text.getBackdropHorizontalOffset() << std::endl;
// backdropVerticalOffset
fw.indent() << "backdropVerticalOffset " << text.getBackdropVerticalOffset() << std::endl;
// backdropColor
c = text.getBackdropColor();
fw.indent() << "backdropColor " << c.x() << " " << c.y() << " " << c.z() << " " << c.w() << std::endl;
// backdropImplementation
fw.indent() << "backdropImplementation " << convertBackdropImplementationEnumToString(text.getBackdropImplementation()) << std::endl;
// colorGradientMode
fw.indent() << "colorGradientMode " << convertColorGradientModeEnumToString(text.getColorGradientMode()) << std::endl;
// colorGradientTopLeft
c = text.getColorGradientTopLeft();
fw.indent() << "colorGradientTopLeft " << c.x() << " " << c.y() << " " << c.z() << " " << c.w() << std::endl;
// colorGradientBottomLeft
c = text.getColorGradientBottomLeft();
fw.indent() << "colorGradientBottomLeft " << c.x() << " " << c.y() << " " << c.z() << " " << c.w() << std::endl;
// colorGradientBottomRight
c = text.getColorGradientBottomRight();
fw.indent() << "colorGradientBottomRight " << c.x() << " " << c.y() << " " << c.z() << " " << c.w() << std::endl;
fw.indent() << "text " << fw.wrapString(str) << std::endl;
}
else
{
// do it the hardway...output each character as an int
fw.indent() << "text "<<textstring.size()<<std::endl;;
osgDB::writeArray(fw,textstring.begin(),textstring.end());
}
// colorGradientTopRight
c = text.getColorGradientTopRight();
fw.indent() << "colorGradientTopRight " << c.x() << " " << c.y() << " " << c.z() << " " << c.w() << std::endl;
return true;
}

View File

@ -0,0 +1,99 @@
#include <osgText/Text3D>
#include <osgText/Font>
#include <iostream>
#include <string>
#include <osg/Vec3>
#include <osg/Vec4>
#include <osg/io_utils>
#include <osgDB/Registry>
#include <osgDB/Input>
#include <osgDB/Output>
#include <osgDB/ParameterOutput>
bool Text3D_readLocalData(osg::Object &obj, osgDB::Input &fr);
bool Text3D_writeLocalData(const osg::Object &obj, osgDB::Output &fw);
osgDB::RegisterDotOsgWrapperProxy Text3D_Proxy
(
new osgText::Text3D,
"Text3D",
"Object Drawable TextBase Text3D",
Text3D_readLocalData,
Text3D_writeLocalData
);
osgText::Text3D::RenderMode convertRenderModeStringToEnum(const std::string str)
{
if (str == "PER_GLYPH") return osgText::Text3D::PER_GLYPH;
else if (str == "PER_FACE") return osgText::Text3D::PER_FACE;
return static_cast<osgText::Text3D::RenderMode>(-1);
}
std::string convertRenderModeEnumToString(osgText::Text3D::RenderMode renderMode)
{
switch (renderMode)
{
case osgText::Text3D::PER_GLYPH: return "PER_GLYPH";
case osgText::Text3D::PER_FACE: return "PER_FACE";
default: return "";
}
}
bool Text3D_readLocalData(osg::Object &obj, osgDB::Input &fr)
{
osgText::Text3D &text = static_cast<osgText::Text3D &>(obj);
bool itAdvanced = false;
// font
if (fr.matchSequence("font %w"))
{
text.setFont(fr[1].getStr());
fr += 2;
itAdvanced = true;
}
// characterDepth
if (fr[0].matchWord("characterDepth"))
{
float depth;
if (fr[1].getFloat(depth))
{
text.setCharacterDepth(depth);
fr += 2;
itAdvanced = true;
}
}
// RenderMode
if (fr[0].matchWord("renderMode"))
{
osgText::Text3D::RenderMode renderMode = convertRenderModeStringToEnum(fr[1].getStr());
if (renderMode != static_cast<osgText::Text3D::RenderMode>(-1))
{
text.setRenderMode(renderMode);
}
fr += 2;
itAdvanced = true;
}
return itAdvanced;
}
bool Text3D_writeLocalData(const osg::Object &obj, osgDB::Output &fw)
{
const osgText::Text3D &text = static_cast<const osgText::Text3D &>(obj);
if (text.getFont())
{
fw.indent() << "font " << text.getFont()->getFileName() << std::endl;
}
fw.indent() << "characterDepth " << text.getCharacterDepth() << std::endl;
fw.indent() << "renderMode " << convertRenderModeEnumToString(text.getRenderMode()) << std::endl;
return true;
}

View File

@ -10,8 +10,12 @@ SET(HEADER_PATH ${OpenSceneGraph_SOURCE_DIR}/include/${LIB_NAME})
SET(LIB_PUBLIC_HEADERS
${HEADER_PATH}/Export
${HEADER_PATH}/Font
${HEADER_PATH}/Font3D
${HEADER_PATH}/KerningType
${HEADER_PATH}/String
${HEADER_PATH}/TextBase
${HEADER_PATH}/Text
${HEADER_PATH}/Text3D
${HEADER_PATH}/FadeText
${HEADER_PATH}/Version
)
@ -23,12 +27,17 @@ ADD_LIBRARY(${LIB_NAME}
DefaultFont.cpp
DefaultFont.h
Font.cpp
Font3D.cpp
String.cpp
FadeText.cpp
TextBase.cpp
Text.cpp
Text3D.cpp
Version.cpp
)
SET(TARGET_LIBRARIES_VARS FREETYPE_LIBRARY )
LINK_INTERNAL(${LIB_NAME}
osgDB
osg

View File

@ -34,8 +34,8 @@ static OpenThreads::ReentrantMutex s_FontFileMutex;
Font::FontMutex* osgText::Font::getSerializeFontCallsMutex()
{
static OpenThreads::Mutex s_FontCallsMutex;
return &s_FontCallsMutex;
static OpenThreads::Mutex s_serializeFontCallsMutex;
return &s_serializeFontCallsMutex;
}
std::string osgText::findFontFile(const std::string& str)

248
src/osgText/Font3D.cpp Normal file
View File

@ -0,0 +1,248 @@
/* -*-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/Font3D>
#include <osgText/Text>
//#include <osg/State>
#include <osg/Notify>
//#include <osg/ApplicationUsage>
#include <osgDB/ReadFile>
#include <osgDB/FileUtils>
#include <osgDB/FileNameUtils>
//#include <osg/GLU>
#include <OpenThreads/ReentrantMutex>
using namespace std;
//static osg::ApplicationUsageProxy Font3D_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_TEXT3D_INCREMENTAL_SUBLOADING <type>","ON | OFF");
static OpenThreads::ReentrantMutex s_Font3DFileMutex;
namespace osgText
{
Font::FontMutex* Font3D::getSerializeFontCallsMutex()
{
static OpenThreads::Mutex s_serializeFontCallsMutex;
return &s_serializeFontCallsMutex;
}
std::string findFont3DFile(const std::string& str)
{
// try looking in OSGFILEPATH etc first for fonts.
std::string filename = osgDB::findDataFile(str);
if (!filename.empty()) return filename;
OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(s_Font3DFileMutex);
static osgDB::FilePathList s_FontFilePath;
static bool initialized = false;
if (!initialized)
{
initialized = true;
#if defined(WIN32)
osgDB::convertStringPathIntoFilePathList(
".;C:/winnt/fonts;C:/windows/fonts",
s_FontFilePath);
char *ptr;
if ((ptr = getenv( "windir" )))
{
std::string winFontPath = ptr;
winFontPath += "\\fonts";
s_FontFilePath.push_back(winFontPath);
}
#else
osgDB::convertStringPathIntoFilePathList(
".:/usr/share/fonts/ttf:/usr/share/fonts/ttf/western:/usr/share/fonts/ttf/decoratives",
s_FontFilePath);
#endif
}
filename = osgDB::findFileInPath(str,s_FontFilePath);
if (!filename.empty()) return filename;
// Try filename without pathname, if it has a path
filename = osgDB::getSimpleFileName(str);
if(filename!=str)
{
filename = osgDB::findFileInPath(filename,s_FontFilePath);
if (!filename.empty()) return filename;
}
else
{
filename = osgText::findFont3DFile(std::string("fonts/")+filename);
if (!filename.empty()) return filename;
}
// Not found, return empty string
osg::notify(osg::WARN)<<"Warning: font file \""<<str<<"\" not found."<<std::endl;
return std::string();
}
osgText::Font3D* readFont3DFile(const std::string& filename, const osgDB::ReaderWriter::Options* userOptions)
{
if (filename=="") return 0;
std::string foundFile = findFont3DFile(filename);
if (foundFile.empty()) return 0;
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_Font3DFileMutex);
osg::ref_ptr<osgDB::ReaderWriter::Options> localOptions;
if (!userOptions)
{
localOptions = new osgDB::ReaderWriter::Options;
localOptions->setObjectCacheHint(osgDB::ReaderWriter::Options::CACHE_OBJECTS);
// ** HACK to load Font3D instead of Font
localOptions->setPluginData("3D", (void*) 1);
}
else
{
userOptions->setPluginData("3D", (void*) 1);
}
osg::Object* object = osgDB::readObjectFile(foundFile, userOptions ? userOptions : localOptions.get());
// if the object is a font then return it.
osgText::Font3D* font3D = dynamic_cast<osgText::Font3D*>(object);
if (font3D) return font3D;
// otherwise if the object has zero references then delete it by doing another unref().
if (object && object->referenceCount()==0) object->unref();
return 0;
}
osgText::Font3D* readFont3DStream(std::istream& stream, const osgDB::ReaderWriter::Options* userOptions)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_Font3DFileMutex);
osg::ref_ptr<osgDB::ReaderWriter::Options> localOptions;
if (!userOptions)
{
localOptions = new osgDB::ReaderWriter::Options;
localOptions->setObjectCacheHint(osgDB::ReaderWriter::Options::CACHE_OBJECTS);
localOptions->setPluginData("3D", (void*) 1);
}
else
{
userOptions->setPluginData("3D", (void*) 1);
}
// there should be a better way to get the FreeType ReaderWriter by name...
osgDB::ReaderWriter *reader = osgDB::Registry::instance()->getReaderWriterForExtension("ttf");
if (reader == 0) return 0;
osgDB::ReaderWriter::ReadResult rr = reader->readObject(stream, userOptions ? userOptions : localOptions.get());
if (rr.error())
{
osg::notify(osg::WARN) << rr.message() << std::endl;
return 0;
}
if (!rr.validObject()) return 0;
osg::Object *object = rr.takeObject();
// if the object is a font then return it.
osgText::Font3D* font3D = dynamic_cast<osgText::Font3D*>(object);
if (font3D) return font3D;
// otherwise if the object has zero references then delete it by doing another unref().
if (object && object->referenceCount()==0) object->unref();
return 0;
}
Font3D::Font3D(Font3DImplementation* implementation):
osg::Object(true),
_depth(1),
_width(64),
_height(64)
{
setImplementation(implementation);
}
Font3D::~Font3D()
{
if (_implementation.valid()) _implementation->_facade = 0;
}
void Font3D::setImplementation(Font3DImplementation* implementation)
{
if (_implementation.valid()) _implementation->_facade = 0;
_implementation = implementation;
if (_implementation.valid()) _implementation->_facade = this;
}
Font3D::Font3DImplementation* Font3D::getImplementation()
{
return _implementation.get();
}
const Font3D::Font3DImplementation* Font3D::getImplementation() const
{
return _implementation.get();
}
std::string Font3D::getFileName() const
{
if (_implementation.valid()) return _implementation->getFileName();
return "";
}
Font3D::Glyph3D* Font3D::getGlyph(unsigned int charcode)
{
Glyph3D * glyph3D = NULL;
Glyph3DMap::iterator itr = _glyph3DMap.find(charcode);
if (itr!=_glyph3DMap.end()) glyph3D = itr->second.get();
else if (_implementation.valid())
{
glyph3D = _implementation->getGlyph(charcode);
if (glyph3D) _glyph3DMap[charcode] = glyph3D;
}
return glyph3D;
}
void Font3D::setThreadSafeRefUnref(bool threadSafe)
{
Glyph3DMap::iterator it,end = _glyph3DMap.end();
for (it=_glyph3DMap.begin(); it!=end; ++it)
it->second->setThreadSafeRefUnref(threadSafe);
}
osg::Vec2 Font3D::getKerning(unsigned int leftcharcode,unsigned int rightcharcode, KerningType kerningType)
{
if (_implementation.valid()) return _implementation->getKerning(leftcharcode,rightcharcode,kerningType);
else return osg::Vec2(0.0f,0.0f);
}
bool Font3D::hasVertical() const
{
if (_implementation.valid()) return _implementation->hasVertical();
else return false;
}
void Font3D::Glyph3D::setThreadSafeRefUnref(bool threadSafe)
{
if (_vertexArray.valid()) _vertexArray->setThreadSafeRefUnref(threadSafe);
if (_normalArray.valid()) _normalArray->setThreadSafeRefUnref(threadSafe);
}
}

View File

@ -32,22 +32,7 @@ using namespace osgText;
//#define TREES_CODE_FOR_MAKING_SPACES_EDITABLE
Text::Text():
_fontWidth(32),
_fontHeight(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),
_color(1.0f,1.0f,1.0f,1.0f),
_drawMode(TEXT),
_kerningType(KERNING_DEFAULT),
_lineCount(0),
_backdropType(NONE),
_backdropImplementation(DEPTH_RANGE),
_backdropHorizontalOffset(0.07f),
@ -58,34 +43,12 @@ Text::Text():
_colorGradientBottomLeft(0.0f, 1.0f, 0.0f, 1.0f),
_colorGradientBottomRight(0.0f, 0.0f, 1.0f, 1.0f),
_colorGradientTopRight(1.0f, 1.0f, 1.0f, 1.0f)
{
setStateSet(DefaultFont::instance()->getStateSet());
setUseDisplayList(false);
setSupportsDisplayList(false);
}
{}
Text::Text(const Text& text,const osg::CopyOp& copyop):
osg::Drawable(text,copyop),
osgText::TextBase(text,copyop),
_font(text._font),
_fontWidth(text._fontWidth),
_fontHeight(text._fontHeight),
_characterHeight(text._characterHeight),
_characterAspectRatio(text._characterAspectRatio),
_characterSizeMode(text._characterSizeMode),
_maximumWidth(text._maximumWidth),
_maximumHeight(text._maximumHeight),
_lineSpacing(text._lineSpacing),
_text(text._text),
_position(text._position),
_alignment(text._alignment),
_axisAlignment(text._axisAlignment),
_rotation(text._rotation),
_autoRotateToScreen(text._autoRotateToScreen),
_layout(text._layout),
_color(text._color),
_drawMode(text._drawMode),
_kerningType(text._kerningType),
_lineCount(text._lineCount),
_backdropType(text._backdropType),
_backdropImplementation(text._backdropImplementation),
_backdropHorizontalOffset(text._backdropHorizontalOffset),
@ -126,182 +89,12 @@ void Text::setFont(const std::string& fontfile)
setFont(readFontFile(fontfile));
}
void Text::setFontResolution(unsigned int width, unsigned int height)
{
_fontWidth = width;
_fontHeight = height;
computeGlyphRepresentation();
}
void Text::setCharacterSize(float height,float aspectRatio)
{
_characterHeight = height;
_characterAspectRatio = aspectRatio;
computeGlyphRepresentation();
}
void Text::setMaximumWidth(float maximumWidth)
{
_maximumWidth = maximumWidth;
computeGlyphRepresentation();
}
void Text::setMaximumHeight(float maximumHeight)
{
_maximumHeight = maximumHeight;
computeGlyphRepresentation();
}
void Text::setLineSpacing(float lineSpacing)
{
_lineSpacing = lineSpacing;
computeGlyphRepresentation();
}
void Text::setText(const String& text)
{
if (_text==text) return;
_text = text;
computeGlyphRepresentation();
}
void Text::setText(const std::string& text)
{
setText(String(text));
}
void Text::setText(const std::string& text,String::Encoding encoding)
{
setText(String(text,encoding));
}
void Text::setText(const wchar_t* text)
{
setText(String(text));
}
void Text::setPosition(const osg::Vec3& pos)
{
if (_position==pos) return;
_position = pos;
computePositions();
}
void Text::setAlignment(AlignmentType alignment)
{
if (_alignment==alignment) return;
_alignment = alignment;
computePositions();
}
void Text::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;
}
}
void Text::setRotation(const osg::Quat& quat)
{
_rotation = quat;
computePositions();
}
void Text::setAutoRotateToScreen(bool autoRotateToScreen)
{
if (_autoRotateToScreen==autoRotateToScreen) return;
_autoRotateToScreen = autoRotateToScreen;
}
void Text::setLayout(Layout layout)
{
if (_layout==layout) return;
_layout = layout;
computeGlyphRepresentation();
}
void Text::setColor(const osg::Vec4& color)
{
_color = color;
}
void Text::setDrawMode(unsigned int mode)
{
if (_drawMode==mode) return;
_drawMode=mode;
}
osg::BoundingBox Text::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.
}
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.yMin(),_textBB.zMin())*matrix);
bbox.expandBy(osg::Vec3(_textBB.xMax(),_textBB.yMax(),_textBB.zMin())*matrix);
bbox.expandBy(osg::Vec3(_textBB.xMin(),_textBB.yMax(),_textBB.zMin())*matrix);
}
}
}
return bbox;
}
Font* Text::getActiveFont()
{
@ -466,11 +259,11 @@ void Text::computeGlyphRepresentation()
if (_text.empty())
{
_textBB.set(0,0,0,0,0,0);//no size text
computePositions(); //to reset the origin
TextBase::computePositions(); //to reset the origin
return;
}
OpenThreads::ScopedLock<Font::FontMutex> lock(*(Font::getSerializeFontCallsMutex()));
OpenThreads::ScopedLock<Font::FontMutex> lock(*(activefont->getSerializeFontCallsMutex()));
// initialize bounding box, it will be expanded during glyph position calculation
_textBB.init();
@ -746,7 +539,7 @@ void Text::computeGlyphRepresentation()
}
computePositions();
TextBase::computePositions();
computeBackdropBoundingBox();
computeColorGradients();
}
@ -803,22 +596,6 @@ bool Text::computeAverageGlyphWidthAndHeight(float& avg_width, float& avg_height
return is_valid_size;
}
void Text::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 Text::computePositions(unsigned int contextID) const
{
@ -1670,16 +1447,14 @@ void Text::accept(osg::PrimitiveFunctor& pf) const
void Text::setThreadSafeRefUnref(bool threadSafe)
{
Drawable::setThreadSafeRefUnref(threadSafe);
TextBase::setThreadSafeRefUnref(threadSafe);
getActiveFont()->setThreadSafeRefUnref(threadSafe);
}
void Text::resizeGLObjectBuffers(unsigned int maxSize)
{
Drawable::resizeGLObjectBuffers(maxSize);
_autoTransformCache.resize(maxSize);
TextBase::resizeGLObjectBuffers(maxSize);
getActiveFont()->resizeGLObjectBuffers(maxSize);
}
@ -1687,7 +1462,7 @@ void Text::resizeGLObjectBuffers(unsigned int maxSize)
void Text::releaseGLObjects(osg::State* state) const
{
Drawable::releaseGLObjects(state);
TextBase::releaseGLObjects(state);
getActiveFont()->releaseGLObjects(state);
}
@ -1983,7 +1758,6 @@ void Text::renderOnlyForegroundText(osg::State& state, const osg::Vec4& colorMul
}
void Text::renderWithPolygonOffset(osg::State& state, const osg::Vec4& colorMultiplier) const
{
unsigned int contextID = state.getContextID();
@ -2044,7 +1818,6 @@ void Text::renderWithPolygonOffset(osg::State& state, const osg::Vec4& colorMult
glPopAttrib();
}
void Text::renderWithNoDepthBuffer(osg::State& state, const osg::Vec4& colorMultiplier) const
{

719
src/osgText/Text3D.cpp Normal file
View File

@ -0,0 +1,719 @@
/* -*-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/Text3D>
#include <osg/io_utils>
namespace osgText
{
Text3D::Text3D():
_font(0),
_characterDepth(1),
_renderMode(PER_GLYPH)
{
}
Text3D::Text3D(const Text3D & text3D, const osg::CopyOp & copyop):
osgText::TextBase(text3D, copyop),
_font(text3D._font),
_characterDepth(text3D._characterDepth),
_renderMode(text3D._renderMode)
{
computeGlyphRepresentation();
}
//void Text3D::accept(osg::Drawable::ConstAttributeFunctor& af) const
//{
// TODO
//}
//void Text3D::accept(osg::PrimitiveFunctor& /*pf*/) const
//{
// TODO
//}
void Text3D::setFont(Font3D * font)
{
_font = font;
computeGlyphRepresentation();
}
void Text3D::setFont(const std::string & fontfile)
{
setFont(readFont3DFile(fontfile));
}
String::iterator Text3D::computeLastCharacterOnLine(osg::Vec2& cursor, String::iterator first,String::iterator last)
{
if (_font.valid() == false) return last;
bool kerning = true;
unsigned int previous_charcode = 0;
String::iterator lastChar = first;
std::set<unsigned int> deliminatorSet;
deliminatorSet.insert(' ');
deliminatorSet.insert('\n');
deliminatorSet.insert(':');
deliminatorSet.insert('/');
deliminatorSet.insert(',');
deliminatorSet.insert(';');
deliminatorSet.insert(':');
deliminatorSet.insert('.');
float maximumHeight = _maximumHeight / _font->getScale();
float maximumWidth = _maximumWidth / _font->getScale();
for(bool outOfSpace=false;lastChar!=last;++lastChar)
{
unsigned int charcode = *lastChar;
if (charcode=='\n')
{
return lastChar;
}
Font3D::Glyph3D* glyph = _font->getGlyph(charcode);
if (glyph)
{
const osg::BoundingBox & bb = glyph->getBoundingBox();
// adjust cursor position w.r.t any kerning.
if (previous_charcode)
{
if (_layout == RIGHT_TO_LEFT)
{
cursor.x() -= glyph->getHorizontalAdvance();
}
if (kerning)
{
switch (_layout)
{
case LEFT_TO_RIGHT:
{
cursor += _font->getKerning(previous_charcode, charcode, _kerningType);
break;
}
case RIGHT_TO_LEFT:
{
cursor -= _font->getKerning(charcode, previous_charcode, _kerningType);
break;
}
case VERTICAL:
break; // no kerning when vertical.
}
}
}
else
{
switch (_layout)
{
case LEFT_TO_RIGHT:
{
cursor.x() -= glyph->getHorizontalBearing().x();
break;
}
case RIGHT_TO_LEFT:
{
cursor.x() -= bb.xMax();
break;
}
case VERTICAL:
break;
}
}
switch(_layout)
{
case LEFT_TO_RIGHT:
{
if (maximumWidth>0.0f && cursor.x()+bb.xMax()>maximumWidth) outOfSpace=true;
if(maximumHeight>0.0f && cursor.y()<-maximumHeight) outOfSpace=true;
break;
}
case RIGHT_TO_LEFT:
{
if (maximumWidth>0.0f && cursor.x()+bb.xMin()<-maximumWidth) outOfSpace=true;
if(maximumHeight>0.0f && cursor.y()<-maximumHeight) outOfSpace=true;
break;
}
case VERTICAL:
if (maximumHeight>0.0f && cursor.y()<-maximumHeight) outOfSpace=true;
break;
}
// => word boundary detection & wrapping
if (outOfSpace) break;
// move the cursor onto the next character.
switch(_layout)
{
case LEFT_TO_RIGHT: cursor.x() += glyph->getHorizontalAdvance(); break;
case RIGHT_TO_LEFT: break;
case VERTICAL: cursor.y() -= glyph->getVerticalAdvance(); break;
}
previous_charcode = charcode;
}
}
// word boundary detection & wrapping
if (lastChar!=last)
{
if (deliminatorSet.count(*lastChar)==0)
{
String::iterator lastValidChar = lastChar;
while (lastValidChar!=first && deliminatorSet.count(*lastValidChar)==0)
{
--lastValidChar;
//Substract off glyphs from the cursor position (to correctly center text)
Font3D::Glyph3D* glyph = _font->getGlyph(*lastValidChar);
if (glyph)
{
switch(_layout)
{
case LEFT_TO_RIGHT: cursor.x() -= glyph->getHorizontalAdvance(); break;
case RIGHT_TO_LEFT: cursor.x() += glyph->getHorizontalAdvance(); break;
case VERTICAL: cursor.y() += glyph->getVerticalAdvance(); break;
}
}
}
if (first!=lastValidChar)
{
++lastValidChar;
lastChar = lastValidChar;
}
}
}
return lastChar;
}
void Text3D::computeGlyphRepresentation()
{
if (_font.valid() == false) return;
_textRenderInfo.clear();
_lineCount = 0;
if (_text.empty())
{
_textBB.set(0,0,0, 0,0,0);//no size text
TextBase::computePositions(); //to reset the origin
return;
}
OpenThreads::ScopedLock<Font3D::Font3DMutex> lock(*(_font->getSerializeFontCallsMutex()));
// initialize bounding box, it will be expanded during glyph position calculation
_textBB.init();
osg::Vec2 startOfLine_coords(0.0f,0.0f);
osg::Vec2 cursor(startOfLine_coords);
osg::Vec2 local(0.0f,0.0f);
osg::Vec2 startOffset(0.0f,0.0f);
unsigned int previous_charcode = 0;
unsigned int linelength = 0;
bool kerning = true;
unsigned int lineNumber = 0;
for(String::iterator itr=_text.begin(); itr!=_text.end(); )
{
_textRenderInfo.resize(lineNumber + 1);
LineRenderInfo & currentLineRenderInfo = _textRenderInfo.back();
// record the start of the current line
String::iterator startOfLine_itr = itr;
// find the end of the current line.
osg::Vec2 endOfLine_coords(cursor);
String::iterator endOfLine_itr = computeLastCharacterOnLine(endOfLine_coords, itr,_text.end());
// ** position the cursor function to the Layout and the alignement
TextBase::positionCursor(endOfLine_coords, cursor, (unsigned int) (endOfLine_itr - startOfLine_itr));
if (itr!=endOfLine_itr)
{
for(;itr!=endOfLine_itr;++itr)
{
unsigned int charcode = *itr;
Font3D::Glyph3D* glyph = _font->getGlyph(charcode);
if (glyph)
{
const osg::BoundingBox & bb = glyph->getBoundingBox();
// adjust cursor position w.r.t any kerning.
if (previous_charcode)
{
if (_layout == RIGHT_TO_LEFT)
{
cursor.x() -= glyph->getHorizontalAdvance();
}
if (kerning)
{
switch (_layout)
{
case LEFT_TO_RIGHT:
{
cursor += _font->getKerning(previous_charcode, charcode, _kerningType);
break;
}
case RIGHT_TO_LEFT:
{
cursor -= _font->getKerning(charcode, previous_charcode, _kerningType);
break;
}
case VERTICAL:
break; // no kerning when vertical.
}
}
}
else
{
switch (_layout)
{
case LEFT_TO_RIGHT:
{
cursor.x() -= glyph->getHorizontalBearing().x();
break;
}
case RIGHT_TO_LEFT:
{
cursor.x() -= bb.xMax();
break;
}
case VERTICAL:
{
// cursor.y() += glyph->getVerticalBearing().y();
break;
}
}
}
local = cursor;
if (_layout==VERTICAL)
{
local.x() += -glyph->getVerticalBearing().x();
local.y() += -glyph->getVerticalBearing().y();
}
// move the cursor onto the next character.
// also expand bounding box
switch (_layout)
{
case LEFT_TO_RIGHT:
_textBB.expandBy(osg::Vec3(cursor.x() + bb.xMin(), cursor.y() + bb.yMin(), 0.0f)); //lower left corner
_textBB.expandBy(osg::Vec3(cursor.x() + bb.xMax(), cursor.y() + bb.yMax(), 0.0f)); //upper right corner
cursor.x() += glyph->getHorizontalAdvance();
break;
case VERTICAL:
_textBB.expandBy(osg::Vec3(cursor.x(), cursor.y(), 0.0f)); //upper left corner
_textBB.expandBy(osg::Vec3(cursor.x() + glyph->getWidth(), cursor.y() - glyph->getHeight(), 0.0f)); //lower right corner
cursor.y() -= glyph->getVerticalAdvance();
break;
case RIGHT_TO_LEFT:
_textBB.expandBy(osg::Vec3(cursor.x()+bb.xMax(), cursor.y() + bb.yMax(), 0.0f)); //upper right corner
_textBB.expandBy(osg::Vec3(cursor.x()+bb.xMin(), cursor.y()+bb.yMin(), 0.0f)); //lower left corner
break;
}
osg::Vec3 pos = osg::Vec3(local.x(), local.y(), 0.0f);
currentLineRenderInfo.push_back(Text3D::GlyphRenderInfo(glyph, pos));
previous_charcode = charcode;
}
}
}
else
{
++itr;
}
if (itr!=_text.end())
{
// skip over return.
if (*itr=='\n') ++itr;
}
// move to new line.
switch(_layout)
{
case LEFT_TO_RIGHT:
case RIGHT_TO_LEFT:
{
startOfLine_coords.y() -= (1.0 + _lineSpacing) / _font->getScale();
++_lineCount;
break;
}
case VERTICAL:
{
startOfLine_coords.x() += _characterHeight / _font->getScale() / _characterAspectRatio * (1.0 + _lineSpacing);
// because _lineCount is the max vertical no. of characters....
_lineCount = (_lineCount >linelength)?_lineCount:linelength;
break;
}
default:
break;
}
cursor = startOfLine_coords;
previous_charcode = 0;
++lineNumber;
}
_textBB.expandBy(0.0f,0.0f,-1);
TextBase::computePositions();
}
void Text3D::computePositions(unsigned int contextID) const
{
if (_font.valid() == false) return;
switch(_alignment)
{
case LEFT_TOP: _offset.set(_textBB.xMin(),_textBB.yMax(),_textBB.zMin()); break;
case LEFT_CENTER: _offset.set(_textBB.xMin(),(_textBB.yMax()+_textBB.yMin())*0.5f,_textBB.zMin()); break;
case LEFT_BOTTOM: _offset.set(_textBB.xMin(),_textBB.yMin(),_textBB.zMin()); break;
case CENTER_TOP: _offset.set((_textBB.xMax()+_textBB.xMin())*0.5f,_textBB.yMax(),_textBB.zMin()); break;
case CENTER_CENTER: _offset.set((_textBB.xMax()+_textBB.xMin())*0.5f,(_textBB.yMax()+_textBB.yMin())*0.5f,_textBB.zMin()); break;
case CENTER_BOTTOM: _offset.set((_textBB.xMax()+_textBB.xMin())*0.5f,_textBB.yMin(),_textBB.zMin()); break;
case RIGHT_TOP: _offset.set(_textBB.xMax(),_textBB.yMax(),_textBB.zMin()); break;
case RIGHT_CENTER: _offset.set(_textBB.xMax(),(_textBB.yMax()+_textBB.yMin())*0.5f,_textBB.zMin()); break;
case RIGHT_BOTTOM: _offset.set(_textBB.xMax(),_textBB.yMin(),_textBB.zMin()); break;
case LEFT_BASE_LINE: _offset.set(0.0f,0.0f,0.0f); break;
case CENTER_BASE_LINE: _offset.set((_textBB.xMax()+_textBB.xMin())*0.5f,0.0f,0.0f); break;
case RIGHT_BASE_LINE: _offset.set(_textBB.xMax(),0.0f,0.0f); break;
case LEFT_BOTTOM_BASE_LINE: _offset.set(0.0f,-_characterHeight*(_lineCount-1),0.0f); break;
case CENTER_BOTTOM_BASE_LINE: _offset.set((_textBB.xMax()+_textBB.xMin())*0.5f,-_characterHeight*(_lineCount-1),0.0f); break;
case RIGHT_BOTTOM_BASE_LINE: _offset.set(_textBB.xMax(),-_characterHeight*(_lineCount-1),0.0f); break;
}
AutoTransformCache& atc = _autoTransformCache[contextID];
osg::Matrix& matrix = atc._matrix;
float scale = _font->getScale();
osg::Matrix scaleMatrix = osg::Matrix::scale(scale * _characterHeight,
scale * _characterHeight / _characterAspectRatio,
_characterDepth);
if (!_rotation.zeroRotation())
{
matrix.makeTranslate(-_offset);
matrix.postMult(scaleMatrix);
matrix.postMult(osg::Matrix::rotate(_rotation));
matrix.postMult(osg::Matrix::translate(_position));
}
else
{
matrix.makeTranslate(-_offset);
matrix.postMult(scaleMatrix);
matrix.postMult(osg::Matrix::translate(_position));
}
_normal = osg::Matrix::transform3x3(osg::Vec3(0.0f,0.0f,1.0f),matrix);
_normal.normalize();
const_cast<Text3D*>(this)->dirtyBound();
}
void Text3D::drawImplementation(osg::RenderInfo& renderInfo) const
{
osg::State & state = *renderInfo.getState();
unsigned int contextID = state.getContextID();
// ** save the previous modelview matrix
osg::ref_ptr<osg::RefMatrix> previous(new osg::RefMatrix(state.getModelViewMatrix()));
// ** get the modelview for this context
osg::ref_ptr<osg::RefMatrix> modelview(new osg::RefMatrix(_autoTransformCache[contextID]._matrix));
// ** mult previous by the modelview for this context
modelview->postMult(*previous.get());
// ** apply this new modelview matrix
state.applyModelViewMatrix(modelview.get());
if (_drawMode & TEXT)
{
renderInfo.getState()->disableAllVertexArrays();
glPushAttrib(GL_TRANSFORM_BIT);
glEnable(GL_RESCALE_NORMAL);
switch(_renderMode)
{
case PER_FACE: renderPerFace(*renderInfo.getState()); break;
case PER_GLYPH:
default: renderPerGlyph(*renderInfo.getState()); break;
}
glPopAttrib();
}
if (_drawMode & BOUNDINGBOX)
{
if (_textBB.valid())
{
osg::Vec3 c000(osg::Vec3(_textBB.xMin(),_textBB.yMin(),_textBB.zMax()));
osg::Vec3 c100(osg::Vec3(_textBB.xMax(),_textBB.yMin(),_textBB.zMax()));
osg::Vec3 c110(osg::Vec3(_textBB.xMax(),_textBB.yMax(),_textBB.zMax()));
osg::Vec3 c010(osg::Vec3(_textBB.xMin(),_textBB.yMax(),_textBB.zMax()));
osg::Vec3 c001(osg::Vec3(_textBB.xMin(),_textBB.yMin(),_textBB.zMin()));
osg::Vec3 c101(osg::Vec3(_textBB.xMax(),_textBB.yMin(),_textBB.zMin()));
osg::Vec3 c111(osg::Vec3(_textBB.xMax(),_textBB.yMax(),_textBB.zMin()));
osg::Vec3 c011(osg::Vec3(_textBB.xMin(),_textBB.yMax(),_textBB.zMin()));
glBegin(GL_LINE_LOOP);
glVertex3fv(c000.ptr());
glVertex3fv(c100.ptr());
glVertex3fv(c110.ptr());
glVertex3fv(c010.ptr());
glEnd();
glBegin(GL_LINE_LOOP);
glVertex3fv(c001.ptr());
glVertex3fv(c011.ptr());
glVertex3fv(c111.ptr());
glVertex3fv(c101.ptr());
glEnd();
glBegin(GL_LINES);
glVertex3fv(c000.ptr());
glVertex3fv(c001.ptr());
glVertex3fv(c100.ptr());
glVertex3fv(c101.ptr());
glVertex3fv(c110.ptr());
glVertex3fv(c111.ptr());
glVertex3fv(c010.ptr());
glVertex3fv(c011.ptr());
glEnd();
}
}
if (_drawMode & ALIGNMENT)
{
float cursorsize = _characterHeight*0.5f;
osg::Vec3 hl(osg::Vec3(_offset.x()-cursorsize,_offset.y(),_offset.z()));
osg::Vec3 hr(osg::Vec3(_offset.x()+cursorsize,_offset.y(),_offset.z()));
osg::Vec3 vt(osg::Vec3(_offset.x(),_offset.y()-cursorsize,_offset.z()));
osg::Vec3 vb(osg::Vec3(_offset.x(),_offset.y()+cursorsize,_offset.z()));
glBegin(GL_LINES);
glVertex3fv(hl.ptr());
glVertex3fv(hr.ptr());
glVertex3fv(vt.ptr());
glVertex3fv(vb.ptr());
glEnd();
}
// restore the previous modelview matrix
state.applyModelViewMatrix(previous.get());
}
void Text3D::renderPerGlyph(osg::State & state) const
{
// ** for each line, do ...
TextRenderInfo::const_iterator itLine, endLine = _textRenderInfo.end();
for (itLine = _textRenderInfo.begin(); itLine!=endLine; ++itLine)
{
// ** for each glyph in the line, do ...
LineRenderInfo::const_iterator it, end = itLine->end();
for (it = itLine->begin(); it!=end; ++it)
{
glPushMatrix();
glTranslatef(it->_position.x(), it->_position.y(), it->_position.z());
// ** apply the vertex array
state.setVertexPointer(it->_glyph->getVertexArray());
// ** render the front face of the glyph
glNormal3f(0.0f,0.0f,1.0f);
osg::Geometry::PrimitiveSetList & pslFront = it->_glyph->getFrontPrimitiveSetList();
for(osg::Geometry::PrimitiveSetList::const_iterator itr=pslFront.begin(), end = pslFront.end(); itr!=end; ++itr)
{
(*itr)->draw(state, false);
}
// ** render the wall face of the glyph
state.setNormalPointer(it->_glyph->getNormalArray());
osg::Geometry::PrimitiveSetList & pslWall = it->_glyph->getWallPrimitiveSetList();
for(osg::Geometry::PrimitiveSetList::const_iterator itr=pslWall.begin(), end=pslWall.end(); itr!=end; ++itr)
{
(*itr)->draw(state, false);
}
// ** render the back face of the glyph
glNormal3f(0.0f,0.0f,-1.0f);
osg::Geometry::PrimitiveSetList & pslBack = it->_glyph->getBackPrimitiveSetList();
for(osg::Geometry::PrimitiveSetList::const_iterator itr=pslBack.begin(), end=pslBack.end(); itr!=end; ++itr)
{
(*itr)->draw(state, false);
}
glPopMatrix();
}
}
}
void Text3D::renderPerFace(osg::State & state) const
{
// ** render all front faces
glNormal3f(0.0f,0.0f,1.0f);
TextRenderInfo::const_iterator itLine, endLine = _textRenderInfo.end();
for (itLine = _textRenderInfo.begin(); itLine!=endLine; ++itLine)
{
// ** for each glyph in the line, do ...
LineRenderInfo::const_iterator it, end = itLine->end();
for (it = itLine->begin(); it!=end; ++it)
{
glPushMatrix();
glTranslatef(it->_position.x(), it->_position.y(), it->_position.z());
state.setVertexPointer(it->_glyph->getVertexArray());
// ** render the front face of the glyph
osg::Geometry::PrimitiveSetList & psl = it->_glyph->getFrontPrimitiveSetList();
for(osg::Geometry::PrimitiveSetList::const_iterator itr=psl.begin(), end=psl.end(); itr!=end; ++itr)
{
(*itr)->draw(state, false);
}
glPopMatrix();
}
}
// ** render all wall face of the text
for (itLine = _textRenderInfo.begin(); itLine!=endLine; ++itLine)
{
// ** for each glyph in the line, do ...
LineRenderInfo::const_iterator it, end = itLine->end();
for (it = itLine->begin(); it!=end; ++it)
{
glPushMatrix();
glTranslatef(it->_position.x(), it->_position.y(), it->_position.z());
state.setVertexPointer(it->_glyph->getVertexArray());
state.setNormalPointer(it->_glyph->getNormalArray());
osg::Geometry::PrimitiveSetList & psl = it->_glyph->getWallPrimitiveSetList();
for(osg::Geometry::PrimitiveSetList::const_iterator itr=psl.begin(), end=psl.end(); itr!=end; ++itr)
{
(*itr)->draw(state, false);
}
glPopMatrix();
}
}
// ** render all back face of the text
glNormal3f(0.0f,0.0f,-1.0f);
for (itLine = _textRenderInfo.begin(); itLine!=endLine; ++itLine)
{
// ** for each glyph in the line, do ...
LineRenderInfo::const_iterator it, end = itLine->end();
for (it = itLine->begin(); it!=end; ++it)
{
glPushMatrix();
glTranslatef(it->_position.x(), it->_position.y(), it->_position.z());
state.setVertexPointer(it->_glyph->getVertexArray());
// ** render the back face of the glyph
osg::Geometry::PrimitiveSetList & psl = it->_glyph->getBackPrimitiveSetList();
for(osg::Geometry::PrimitiveSetList::const_iterator itr=psl.begin(), end=psl.end(); itr!=end; ++itr)
{
(*itr)->draw(state, false);
}
glPopMatrix();
}
}
}
void Text3D::setThreadSafeRefUnref(bool threadSafe)
{
TextBase::setThreadSafeRefUnref(threadSafe);
if (_font.valid()) _font->setThreadSafeRefUnref(threadSafe);
}
void Text3D::resizeGLObjectBuffers(unsigned int maxSize)
{
TextBase::resizeGLObjectBuffers(maxSize);
if (_font.valid()) _font->resizeGLObjectBuffers(maxSize);
}
void Text3D::releaseGLObjects(osg::State* state) const
{
TextBase::releaseGLObjects(state);
if (_font.valid()) _font->releaseGLObjects(state);
}
}

392
src/osgText/TextBase.cpp Normal file
View File

@ -0,0 +1,392 @@
/* -*-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():
_fontWidth(32),
_fontHeight(32),
_characterHeight(32),
_characterAspectRatio(1.0f),
_characterSizeMode(OBJECT_COORDS),
_maximumWidth(0.0f),
_maximumHeight(0.0f),
_lineSpacing(1.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),
_fontWidth(textBase._fontWidth),
_fontHeight(textBase._fontHeight),
_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)
{
_fontWidth = width;
_fontHeight = 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;
}
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.
}
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.yMin(),_textBB.zMin())*matrix);
bbox.expandBy(osg::Vec3(_textBB.xMax(),_textBB.yMax(),_textBB.zMax())*matrix);
// bbox.expandBy(osg::Vec3(_textBB.xMin(),_textBB.yMax(),_textBB.zMin())*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;
}
}
}