From David Callu, added support of 3D text to osgText and associated plugins.
This commit is contained in:
parent
9b56dbe83a
commit
f69a48e552
@ -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)
|
||||
|
7
examples/osgtext3D/CMakeLists.txt
Normal file
7
examples/osgtext3D/CMakeLists.txt
Normal 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)
|
137
examples/osgtext3D/osgtext3D.cpp
Normal file
137
examples/osgtext3D/osgtext3D.cpp
Normal 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;
|
||||
}
|
||||
|
||||
|
@ -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
284
include/osgText/Font3D
Normal 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
|
26
include/osgText/KerningType
Normal file
26
include/osgText/KerningType
Normal 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*/
|
@ -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
292
include/osgText/TextBase
Normal 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
|
||||
|
@ -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 ###
|
||||
|
@ -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;
|
||||
|
521
src/osgPlugins/freetype/FreeTypeFont3D.cpp
Normal file
521
src/osgPlugins/freetype/FreeTypeFont3D.cpp
Normal 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;
|
||||
}
|
64
src/osgPlugins/freetype/FreeTypeFont3D.h
Normal file
64
src/osgPlugins/freetype/FreeTypeFont3D.h
Normal 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
|
224
src/osgPlugins/freetype/FreeTypeFontBase.cpp
Normal file
224
src/osgPlugins/freetype/FreeTypeFontBase.cpp
Normal 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;
|
||||
}
|
46
src/osgPlugins/freetype/FreeTypeFontBase.h
Normal file
46
src/osgPlugins/freetype/FreeTypeFontBase.h
Normal 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
|
@ -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)
|
||||
{
|
||||
//
|
||||
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
99
src/osgPlugins/osgText/IO_Text3D.cpp
Normal file
99
src/osgPlugins/osgText/IO_Text3D.cpp
Normal 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;
|
||||
}
|
@ -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
|
||||
|
@ -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
248
src/osgText/Font3D.cpp
Normal 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);
|
||||
}
|
||||
}
|
@ -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
719
src/osgText/Text3D.cpp
Normal 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
392
src/osgText/TextBase.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user