Refactored osgText::Font so that it now supports both 2D and 3D glyphs.

Added TextNode.h and TextNode.cpp to examples/osgtext3D in prep for introducing the new node to osgText library
This commit is contained in:
Robert Osfield
2010-09-03 08:26:46 +00:00
parent d1e90b6878
commit 8c3e3055e7
26 changed files with 1396 additions and 398 deletions

View File

@@ -2,10 +2,12 @@
SET(TARGET_H
GlyphGeometry.h
TextNode.h
)
SET(TARGET_SRC
GlyphGeometry.cpp
TextNode.cpp
osgtext3D_orig.cpp
osgtext3D_test.cpp
osgtext3D.cpp

View File

@@ -520,7 +520,7 @@ struct CollectTriangleIndicesFunctor
};
osg::Geometry* computeGlyphGeometry(osgText::Font3D::Glyph3D* glyph, float bevelThickness, float shellThickness)
osg::Geometry* computeGlyphGeometry(osgText::Glyph3D* glyph, float bevelThickness, float shellThickness)
{
osg::Vec3Array* orig_vertices = glyph->getRawVertexArray();
osg::Geometry::PrimitiveSetList& orig_primitives = glyph->getRawFacePrimitiveSetList();

View File

@@ -42,7 +42,7 @@ class BevelProfile
Vertices _vertices;
};
extern osg::Geometry* computeGlyphGeometry(osgText::Font3D::Glyph3D* glyph, float bevelThickness, float shellThickness);
extern osg::Geometry* computeGlyphGeometry(osgText::Glyph3D* glyph, float bevelThickness, float shellThickness);
extern osg::Geometry* computeTextGeometry(osg::Geometry* glyphGeometry, BevelProfile& profile, float width);

View File

@@ -0,0 +1,289 @@
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2010 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 "TextNode.h"
#include <osg/io_utils>
using namespace osgText;
/////////////////////////////////////////////////////////////////////////////////////////
//
// Bevel
//
Bevel::Bevel()
{
_thickness = 0.1f;
flatBevel();
}
Bevel::Bevel(const Bevel& bevel, const osg::CopyOp&):
_thickness(bevel._thickness),
_vertices(bevel._vertices)
{
}
void Bevel::flatBevel(float width)
{
_vertices.clear();
if (width>0.5f) width = 0.5f;
_vertices.push_back(osg::Vec2(0.0f,0.0f));
_vertices.push_back(osg::Vec2(width,1.0f));
if (width<0.5f) _vertices.push_back(osg::Vec2(1-width,1.0f));
_vertices.push_back(osg::Vec2(1.0f,0.0f));
}
void Bevel::roundedBevel(float width, unsigned int numSteps)
{
_vertices.clear();
if (width>0.5f) width = 0.5f;
unsigned int i = 0;
for(; i<=numSteps; ++i)
{
float angle = float(osg::PI)*0.5f*(float(i)/float(numSteps));
_vertices.push_back( osg::Vec2((1.0f-cosf(angle))*width, sinf(angle)) );
}
// start the second half one into the curve if the width is half way across
i = width<0.5f ? 0 : 1;
for(; i<=numSteps; ++i)
{
float angle = float(osg::PI)*0.5f*(float(numSteps-i)/float(numSteps));
_vertices.push_back( osg::Vec2(1.0-(1.0f-cosf(angle))*width, sin(angle)) );
}
}
void Bevel::roundedBevel2(float width, unsigned int numSteps)
{
_vertices.clear();
if (width>0.5f) width = 0.5f;
float h = 0.1f;
float r = 1.0f-h;
_vertices.push_back(osg::Vec2(0.0,0.0));
unsigned int i = 0;
for(; i<=numSteps; ++i)
{
float angle = float(osg::PI)*0.5f*(float(i)/float(numSteps));
_vertices.push_back( osg::Vec2((1.0f-cosf(angle))*width, h + sinf(angle)*r) );
}
// start the second half one into the curve if the width is half way across
i = width<0.5f ? 0 : 1;
for(; i<=numSteps; ++i)
{
float angle = float(osg::PI)*0.5f*(float(numSteps-i)/float(numSteps));
_vertices.push_back( osg::Vec2(1.0-(1.0f-cosf(angle))*width, h + sin(angle)*r) );
}
_vertices.push_back(osg::Vec2(1.0,0.0));
}
void Bevel::print(std::ostream& fout)
{
OSG_NOTICE<<"print bevel"<<std::endl;
for(Vertices::iterator itr = _vertices.begin();
itr != _vertices.end();
++itr)
{
OSG_NOTICE<<" "<<*itr<<std::endl;
}
}
/////////////////////////////////////////////////////////////////////////////////////////
//
// Style
//
Style::Style():
_widthRatio(1.0f),
_thicknessRatio(0.0f),
_outlineRatio(0.0f),
_sampleDensity(1.0f)
{
}
Style::Style(const Style& style, const osg::CopyOp& copyop):
osg::Object(style,copyop),
_bevel(dynamic_cast<Bevel*>(copyop(style._bevel.get()))),
_widthRatio(style._widthRatio),
_thicknessRatio(style._thicknessRatio),
_outlineRatio(style._outlineRatio),
_sampleDensity(style._sampleDensity)
{
}
/// default Layout implementation used if no other is specified on TextNode
osg::ref_ptr<Style>& Style::getDefaultStyle()
{
static OpenThreads::Mutex s_DefaultStyleMutex;
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_DefaultStyleMutex);
static osg::ref_ptr<Style> s_defaultStyle = new Style;
return s_defaultStyle;
}
/////////////////////////////////////////////////////////////////////////////////////////
//
// Layout
//
Layout::Layout()
{
}
Layout::Layout(const Layout& layout, const osg::CopyOp& copyop):
osg::Object(layout,copyop)
{
}
osg::ref_ptr<Layout>& Layout::getDefaultLayout()
{
static OpenThreads::Mutex s_DefaultLayoutMutex;
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_DefaultLayoutMutex);
static osg::ref_ptr<Layout> s_defaultLayout = new Layout;
return s_defaultLayout;
}
void Layout::layout(TextNode& text) const
{
OSG_NOTICE<<"Layout::layout"<<std::endl;
Font* font = text.getActiveFont();
Style* style = text.getActiveStyle();
TextTechnique* technique = text.getTextTechnique();
if (!text.getTextTechnique())
{
OSG_NOTICE<<"Warning: no TextTechnique assigned to Layout"<<std::endl;
return;
}
technique->start();
technique->finish();
}
/////////////////////////////////////////////////////////////////////////////////////////
//
// TextTechnique
//
TextTechnique::TextTechnique():
_textNode(0)
{
}
TextTechnique::TextTechnique(const TextTechnique& technique, const osg::CopyOp& copyop):
osg::Object(technique, copyop),
_textNode(0)
{
}
osg::ref_ptr<TextTechnique>& TextTechnique::getDefaultTextTechinque()
{
static OpenThreads::Mutex s_DefaultTextTechniqueMutex;
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_DefaultTextTechniqueMutex);
static osg::ref_ptr<TextTechnique> s_defaultTextTechnique = new TextTechnique;
return s_defaultTextTechnique;
}
void TextTechnique::start()
{
OSG_NOTICE<<"TextTechnique::start()"<<std::endl;
}
void TextTechnique::addCharacter(const osg::Vec3& position, const osg::Vec3& size, Glyph* glyph, Style* style)
{
OSG_NOTICE<<"TextTechnique::addCharacter("<<position<<", "<<size<<", "<<glyph<<", "<<style<<")"<<std::endl;
}
void TextTechnique::finish()
{
OSG_NOTICE<<"TextTechnique::finish()"<<std::endl;
}
void TextTechnique::traverse(osg::NodeVisitor& nv)
{
OSG_NOTICE<<"TextTechnique::traverse()"<<std::endl;
}
/////////////////////////////////////////////////////////////////////////////////////////
//
// TextNode
//
TextNode::TextNode()
{
}
TextNode::TextNode(const TextNode& text, const osg::CopyOp& copyop):
osg::Group(text, copyop)
{
}
TextNode::~TextNode()
{
setTextTechnique(0);
}
void TextNode::traverse(osg::NodeVisitor& nv)
{
if (_technique.valid())
{
_technique->traverse(nv);
}
else
{
Group::traverse(nv);
}
}
void TextNode::setTextTechnique(TextTechnique* technique)
{
if (_technique==technique) return;
if (TextTechnique::getDefaultTextTechinque()==technique)
{
OSG_NOTICE<<"Warning: Attempt to assign DefaultTextTechnique() prototype to TextNode::setTextTechnique(..), assigning a clone() of it instead."<<std::endl;
technique = new TextTechnique(*TextTechnique::getDefaultTextTechinque());
}
if (_technique.valid()) _technique->setTextNode(0);
_technique = technique;
if (_technique.valid()) _technique->setTextNode(this);
}
void TextNode::update()
{
getActiveLayout()->layout(*this);
}
void TextNode::setText(const std::string& str)
{
_string.set(str);
}

View File

@@ -0,0 +1,226 @@
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2010 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_TEXTNODE
#define OSGTEXT_TEXTNODE 1
#include <osg/Group>
#include <osg/Quat>
#include <osgUtil/CullVisitor>
#include <osgText/Font>
#include <osgText/String>
namespace osgText {
// forward declare
class TextNode;
class Glyph;
class Bevel : public osg::Object
{
public:
Bevel();
Bevel(const Bevel& bevel, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY);
META_Object(osgText, Bevel)
void setBevelThickness(float thickness) { _thickness = thickness; }
float getBevelThickness() const { return _thickness; }
void flatBevel(float width=0.25f);
void roundedBevel(float width=0.5f, unsigned int numSteps=10);
void roundedBevel2(float width=0.5f, unsigned int numSteps=10);
typedef std::vector<osg::Vec2> Vertices;
void setVertices(const Vertices& vertices) { _vertices = vertices; }
Vertices& getVertices() { return _vertices; }
const Vertices& getVertices() const { return _vertices; }
void print(std::ostream& fout);
protected:
float _thickness;
Vertices _vertices;
};
class Style : public osg::Object
{
public:
Style();
Style(const Style& style, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY);
META_Object(osgText, Style)
/// default Layout implementation used if no other is specified on TextNode
static osg::ref_ptr<Style>& getDefaultStyle();
/// NULL is no bevel
void setBevel(Bevel* bevel) { _bevel = bevel; }
const Bevel* getBevel() const { return _bevel.get(); }
/// 1 is the default width of the text
void setWidthRatio(float widthRatio) { _widthRatio = widthRatio; }
float getWidthRatio() const { return _widthRatio; }
/// 0 is 2D text
void setThicknessRatio(float thicknessRatio) { _thicknessRatio = thicknessRatio; }
float getThicknessRatio() const { return _thicknessRatio; }
/// 0 is off
void setOutlineRatio(float outlineRatio) { _outlineRatio = outlineRatio; }
float getOutlineRatio() const { return _outlineRatio; }
/// 1.0 is default number of samples
void setSampleDensity(float sd) { _sampleDensity = sd; }
float getSampleDensity() const { return _sampleDensity; }
protected:
osg::ref_ptr<Bevel> _bevel;
float _widthRatio;
float _thicknessRatio;
float _outlineRatio;
float _sampleDensity;
};
class Layout : public osg::Object
{
public:
Layout();
Layout(const Layout& layout, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY);
META_Object(osgText,Layout)
/// default Layout implementation used if no other is specified on TextNode
static osg::ref_ptr<Layout>& getDefaultLayout();
virtual void layout(TextNode& text) const;
protected:
};
class TextTechnique : public osg::Object
{
public:
TextTechnique();
TextTechnique(const TextTechnique& technique, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY);
META_Object(osgText, TextTechnique)
TextNode* getTextNode() { return _textNode; }
const TextNode* getTextNode() const { return _textNode; }
/// default TextTechnique implementation used if no other is specified on TextNode
static osg::ref_ptr<TextTechnique>& getDefaultTextTechinque();
/// start building a new charater layout
virtual void start();
/// called by Layout engine to place individual characters
virtual void addCharacter(const osg::Vec3& position, const osg::Vec3& size, Glyph* glyph, Style* style);
/// finish building new charater layout
virtual void finish();
/// provide traversal control
virtual void traverse(osg::NodeVisitor& nv);
protected:
friend class TextNode;
void setTextNode(TextNode* textNode) { _textNode = textNode; }
TextNode* _textNode;
};
class TextNode : public osg::Group
{
public:
TextNode();
TextNode(const TextNode& text, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY);
META_Node(osgText, TextNode)
virtual void traverse(osg::NodeVisitor& nv);
void setFont(Font* font) { _font = font; }
Font* getFont() { return _font.get(); }
const Font* getFont() const { return _font.get(); }
Font* getActiveFont() { return _font.valid() ? _font.get() : Font::getDefaultFont().get(); }
const Font* getActiveFont() const { return _font.valid() ? _font.get() : Font::getDefaultFont().get(); }
void setStyle(Style* style) { _style = style; }
Style* getStyle() { return _style.get(); }
const Style* getStyle() const { return _style.get(); }
Style* getActiveStyle() { return _style.valid() ? _style.get() : Style::getDefaultStyle().get(); }
const Style* getActiveStyle() const { return _style.valid() ? _style.get() : Style::getDefaultStyle().get(); }
void setLayout(Layout* layout) { _layout = layout; }
Layout* getLayout() { return _layout.get(); }
const Layout* getLayout() const { return _layout.get(); }
const Layout* getActiveLayout() const { return _layout.valid() ? _layout.get() : Layout::getDefaultLayout().get(); }
void setTextTechnique(TextTechnique* technique);
TextTechnique* getTextTechnique() { return _technique.get(); }
const TextTechnique* getTextTechnique() const { return _technique.get(); }
void setText(const std::string& str);
void setText(const String& str) { _string = str; }
String& getText() { return _string; }
const String& getText() const { return _string; }
void setPosition(const osg::Vec3d& position) { _position = position; }
const osg::Vec3d& getPosition() const { return _position; }
void setRotation(const osg::Quat& rotation) { _rotation = rotation; }
const osg::Quat& getRotation() const { return _rotation; }
void setCharacterSize(float characterSize) { _characterSize = characterSize; }
float getCharacterSize() const { return _characterSize; }
/// force a regeneration of the rendering backend required to represent the text.
virtual void update();
protected:
virtual ~TextNode();
osg::ref_ptr<Font> _font;
osg::ref_ptr<Style> _style;
osg::ref_ptr<Layout> _layout;
osg::ref_ptr<TextTechnique> _technique;
String _string;
osg::Vec3d _position;
osg::Quat _rotation;
float _characterSize;
};
}
#endif

View File

@@ -32,23 +32,13 @@
#include <osg/io_utils>
#include "GlyphGeometry.h"
#include "TextNode.h"
extern int main_orig(int, char**);
extern int main_test(int, char**);
int main(int argc, char** argv)
int main_experimental(osg::ArgumentParser& arguments)
{
osg::ArgumentParser arguments(&argc, argv);
if (arguments.read("--test"))
{
return main_test(argc,argv);
}
else if (arguments.read("--original") || arguments.read("--orig"))
{
return main_orig(argc,argv);
}
std::string fontFile("arial.ttf");
while(arguments.read("-f",fontFile)) {}
@@ -65,7 +55,7 @@ int main(int argc, char** argv)
while(arguments.read("-w",word)) {}
osg::ref_ptr<osgText::Font3D> font = osgText::readFont3DFile(fontFile);
osg::ref_ptr<osgText::Font> font = osgText::readFontFile(fontFile);
if (!font) return 1;
OSG_NOTICE<<"Read font "<<fontFile<<" font="<<font.get()<<std::endl;
@@ -110,7 +100,7 @@ int main(int argc, char** argv)
for(unsigned int i=0; i<word.size(); ++i)
{
osg::ref_ptr<osgText::Font3D::Glyph3D> glyph = font->getGlyph(word[i]);
osg::ref_ptr<osgText::Glyph3D> glyph = font->getGlyph3D(word[i]);
if (!glyph) return 1;
osg::ref_ptr<osg::PositionAttitudeTransform> transform = new osg::PositionAttitudeTransform;
@@ -147,3 +137,42 @@ int main(int argc, char** argv)
viewer.addEventHandler(new osgViewer::StatsHandler);
return viewer.run();
}
int main(int argc, char** argv)
{
osg::ArgumentParser arguments(&argc, argv);
if (arguments.read("--test"))
{
return main_test(argc,argv);
}
else if (arguments.read("--original") || arguments.read("--orig"))
{
return main_orig(argc,argv);
}
else if (arguments.read("--exp"))
{
return main_experimental(arguments);
}
osgViewer::Viewer viewer(arguments);
std::string fontFile("arial.ttf");
while(arguments.read("-f",fontFile)) {}
osg::ref_ptr<osgText::Font> font = osgText::readFontFile(fontFile);
if (!font) return 1;
OSG_NOTICE<<"Read font "<<fontFile<<" font="<<font.get()<<std::endl;
std::string word("This is a new test.");
while (arguments.read("-w",word)) {}
osgText::TextNode* text = new osgText::TextNode;
text->setText(word);
text->setTextTechnique(new osgText::TextTechnique);
text->update();
viewer.setSceneData(text);
return viewer.run();
}

View File

@@ -31,10 +31,12 @@ public:
virtual std::string getFileName() const;
void setFontResolution(const osgText::FontResolution& fontSize);
virtual osgText::Font::Glyph* getGlyph(const osgText::FontResolution& fontRes, unsigned int charcode);
virtual osgText::Glyph* getGlyph(const osgText::FontResolution& fontRes, unsigned int charcode);
virtual osgText::Glyph3D* getGlyph3D(unsigned int charcode) { return 0; }
virtual osg::Vec2 getKerning(const osgText::FontResolution& fontRes, unsigned int leftcharcode,
unsigned int rightcharcode, osgText::KerningType kerningType);
virtual bool hasVertical() const;
virtual float getScale() const { return 1.0f; }
protected:

View File

@@ -23,6 +23,7 @@
#include <osg/StateSet>
#include <osg/buffered_value>
#include <osg/TexEnv>
#include <osg/Geometry>
#include <osgDB/ReaderWriter>
#include <osgText/Export>
@@ -34,6 +35,223 @@ namespace osgText {
class Font;
class Text;
class Glyph3D;
class GlyphTexture;
class OSGTEXT_EXPORT Glyph : public osg::Image
{
public:
Glyph(unsigned int glyphCode);
unsigned int getGlyphCode() const { return _glyphCode; }
void setHorizontalBearing(const osg::Vec2& bearing);
const osg::Vec2& getHorizontalBearing() const;
void setHorizontalAdvance(float advance);
float getHorizontalAdvance() const;
void setVerticalBearing(const osg::Vec2& bearing);
const osg::Vec2& getVerticalBearing() const;
void setVerticalAdvance(float advance);
float getVerticalAdvance() const;
void setTexture(GlyphTexture* texture);
GlyphTexture* getTexture();
const GlyphTexture* getTexture() const;
void setTexturePosition(int posX,int posY);
int getTexturePositionX() const;
int getTexturePositionY() const;
void setMinTexCoord(const osg::Vec2& coord);
const osg::Vec2& getMinTexCoord() const;
void setMaxTexCoord(const osg::Vec2& coord);
const osg::Vec2& getMaxTexCoord() const;
void subload() const;
protected:
virtual ~Glyph();
Font* _font;
unsigned int _glyphCode;
osg::Vec2 _horizontalBearing;
float _horizontalAdvance;
osg::Vec2 _verticalBearing;
float _verticalAdvance;
GlyphTexture* _texture;
int _texturePosX;
int _texturePosY;
osg::Vec2 _minTexCoord;
osg::Vec2 _maxTexCoord;
typedef osg::buffered_value<GLuint> GLObjectList;
mutable GLObjectList _globjList;
};
class OSGTEXT_EXPORT Glyph3D : public osg::Referenced
{
public:
Glyph3D(unsigned int glyphCode):
osg::Referenced(true),
_glyphCode(glyphCode),
_horizontalBearing(0,0),
_horizontalAdvance(0),
_verticalBearing(0,0),
_verticalAdvance(0)
{}
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);
void setRawVertexArray(osg::Vec3Array* vertices) { _rawVertexArray = vertices; }
osg::Vec3Array* getRawVertexArray() { return _rawVertexArray.get(); }
/** Get the PrimitiveSetList for the raw face which hasn't been tessellated. */
osg::Geometry::PrimitiveSetList & getRawFacePrimitiveSetList() { return _rawFacePrimitiveSetList; }
/** 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(); }
/** Set the VertexArray of the glyph. */
void setNormalArray(osg::Vec3Array * na) { _normalArray = na; }
/** 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;
osg::ref_ptr<osg::Vec3Array> _rawVertexArray;
osg::Geometry::PrimitiveSetList _rawFacePrimitiveSetList;
};
class OSGTEXT_EXPORT GlyphTexture : public osg::Texture2D
{
public:
GlyphTexture();
const char* className() const { return "GlyphTexture"; }
/** return -1 if *this < *rhs, 0 if *this==*rhs, 1 if *this>*rhs.*/
virtual int compare(const osg::StateAttribute& rhs) const;
/** Set the margin around each glyph, to ensure that texture filtering doesn't bleed adjacent glyph's into each other.*/
void setGlyphImageMargin(unsigned int margin) { _margin = margin; }
unsigned int getGlyphImageMargin() const { return _margin; }
void setGlyphImageMarginRatio(float margin) { _marginRatio = margin; }
float getGlyphImageMarginRatio() const { return _marginRatio; }
bool getSpaceForGlyph(Glyph* glyph, int& posX, int& posY);
void addGlyph(Glyph* glyph,int posX, int posY);
virtual void apply(osg::State& state) const;
/** 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);
protected:
virtual ~GlyphTexture();
// parameter used to compute the size and position of empty space
// in the texture which could accommodate new glyphs.
int _margin;
float _marginRatio;
int _usedY;
int _partUsedX;
int _partUsedY;
typedef std::vector< osg::ref_ptr<Glyph> > GlyphRefList;
typedef std::vector< const Glyph* > GlyphPtrList;
typedef osg::buffered_object< GlyphPtrList > GlyphBuffer;
GlyphRefList _glyphs;
mutable GlyphBuffer _glyphsToSubload;
mutable OpenThreads::Mutex _mutex;
};
/** 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:
@@ -74,8 +292,6 @@ class OSGTEXT_EXPORT Font : public osg::Object
public:
// forward declare nested classes.
class Glyph;
class GlyphTexture;
class FontImplementation;
public:
@@ -89,6 +305,8 @@ public:
virtual std::string getFileName() const;
static osg::ref_ptr<Font>& getDefaultFont();
void setTexEnv(osg::TexEnv* texenv) { if (texenv) _texenv = texenv; }
inline osg::TexEnv* getTexEnv() { return _texenv.get(); }
inline const osg::TexEnv* getTexEnv() const { return _texenv.get(); }
@@ -103,10 +321,16 @@ public:
/** Get a Glyph for specified charcode, and the font size nearest to the current font size hint.*/
virtual Glyph* getGlyph(const FontResolution& fontSize, unsigned int charcode);
/** Get a Glyph3D for specified charcode.*/
virtual Glyph3D* getGlyph3D(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(); };
/** Set the margin around each glyph,
* to ensure that texture filtering doesn't bleed adjacent glyph's into each other.
* Default margin is 1 texels.*/
@@ -137,6 +361,12 @@ public:
void setMagFilterHint(osg::Texture::FilterMode mode);
osg::Texture::FilterMode getMagFilterHint() const;
unsigned int getFontDepth() const { return _depth; }
void setNumberCurveSamples(unsigned int numSamples) { _numCurveSamples = numSamples; }
unsigned int getNumberCurveSamples() const { return _numCurveSamples; }
// make Text a friend to allow it add and remove its entry in the Font's _textList.
friend class FontImplementation;
@@ -161,22 +391,26 @@ public:
protected:
virtual ~Font();
void addGlyph(const FontResolution& fontRes, unsigned int charcode, Glyph* glyph);
typedef std::vector< osg::ref_ptr<GlyphTexture> > GlyphTextureList;
typedef std::vector< osg::ref_ptr<osg::StateSet> > StateSetList;
typedef std::map< unsigned int, osg::ref_ptr<Glyph> > GlyphMap;
typedef std::map< FontResolution, GlyphMap > FontSizeGlyphMap;
typedef std::map< unsigned int, osg::ref_ptr<Glyph3D> > Glyph3DMap;
typedef std::map< FontResolution, GlyphMap > FontSizeGlyphMap;
mutable OpenThreads::Mutex _glyphMapMutex;
osg::ref_ptr<osg::TexEnv> _texenv;
osg::ref_ptr<osg::StateSet> _stateset;
FontSizeGlyphMap _sizeGlyphMap;
GlyphTextureList _glyphTextureList;
Glyph3DMap _glyph3DMap;
// current active size of font
FontResolution _fontSize;
unsigned int _margin;
@@ -186,6 +420,10 @@ protected:
unsigned int _textureHeightHint;
osg::Texture::FilterMode _minFilterHint;
osg::Texture::FilterMode _magFilterHint;
unsigned int _depth;
unsigned int _numCurveSamples;
osg::ref_ptr<FontImplementation> _implementation;
@@ -206,12 +444,18 @@ public:
/** Get a Glyph for specified charcode, and the font size nearest to the current font size hint.*/
virtual Glyph* getGlyph(const FontResolution& fontRes, unsigned int charcode) = 0;
/** Get a Glyph3D for specified charcode.*/
virtual Glyph3D* getGlyph3D(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(const FontResolution& fontRes, 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;
/** Return scale of font, used by 3D text.*/
virtual float getScale() const = 0;
void addGlyph(const FontResolution& fontRes, unsigned int charcode, Glyph* glyph)
{
_facade->addGlyph(fontRes, charcode, glyph);
@@ -220,120 +464,6 @@ public:
Font* _facade;
};
class OSGTEXT_EXPORT GlyphTexture : public osg::Texture2D
{
public:
GlyphTexture();
const char* className() const { return "GlyphTexture"; }
/** return -1 if *this < *rhs, 0 if *this==*rhs, 1 if *this>*rhs.*/
virtual int compare(const osg::StateAttribute& rhs) const;
/** Set the margin around each glyph, to ensure that texture filtering doesn't bleed adjacent glyph's into each other.*/
void setGlyphImageMargin(unsigned int margin) { _margin = margin; }
unsigned int getGlyphImageMargin() const { return _margin; }
void setGlyphImageMarginRatio(float margin) { _marginRatio = margin; }
float getGlyphImageMarginRatio() const { return _marginRatio; }
bool getSpaceForGlyph(Glyph* glyph, int& posX, int& posY);
void addGlyph(Glyph* glyph,int posX, int posY);
virtual void apply(osg::State& state) const;
/** 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);
protected:
virtual ~GlyphTexture();
// parameter used to compute the size and position of empty space
// in the texture which could accommodate new glyphs.
int _margin;
float _marginRatio;
int _usedY;
int _partUsedX;
int _partUsedY;
typedef std::vector< osg::ref_ptr<Glyph> > GlyphRefList;
typedef std::vector< const Glyph* > GlyphPtrList;
typedef osg::buffered_object< GlyphPtrList > GlyphBuffer;
GlyphRefList _glyphs;
mutable GlyphBuffer _glyphsToSubload;
mutable OpenThreads::Mutex _mutex;
};
class OSGTEXT_EXPORT Glyph : public osg::Image
{
public:
Glyph(unsigned int glyphCode);
unsigned int getGlyphCode() const { return _glyphCode; }
void setHorizontalBearing(const osg::Vec2& bearing);
const osg::Vec2& getHorizontalBearing() const;
void setHorizontalAdvance(float advance);
float getHorizontalAdvance() const;
void setVerticalBearing(const osg::Vec2& bearing);
const osg::Vec2& getVerticalBearing() const;
void setVerticalAdvance(float advance);
float getVerticalAdvance() const;
void setTexture(GlyphTexture* texture);
GlyphTexture* getTexture();
const GlyphTexture* getTexture() const;
void setTexturePosition(int posX,int posY);
int getTexturePositionX() const;
int getTexturePositionY() const;
void setMinTexCoord(const osg::Vec2& coord);
const osg::Vec2& getMinTexCoord() const;
void setMaxTexCoord(const osg::Vec2& coord);
const osg::Vec2& getMaxTexCoord() const;
void subload() const;
protected:
virtual ~Glyph();
Font* _font;
unsigned int _glyphCode;
osg::Vec2 _horizontalBearing;
float _horizontalAdvance;
osg::Vec2 _verticalBearing;
float _verticalAdvance;
GlyphTexture* _texture;
int _texturePosX;
int _texturePosY;
osg::Vec2 _minTexCoord;
osg::Vec2 _maxTexCoord;
typedef osg::buffered_value<GLuint> GLObjectList;
mutable GLObjectList _globjList;
};
};

View File

@@ -22,6 +22,7 @@
#include <osgDB/ReaderWriter>
#include <osgText/Export>
#include <osgText/KerningType>
#include <osgText/Font>
#include <OpenThreads/Mutex>
@@ -30,6 +31,7 @@ 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
@@ -69,7 +71,6 @@ class OSGTEXT_EXPORT Font3D : public osg::Object
public:
// forward declare nested classes.
class Glyph3D;
class Font3DImplementation;
public:
@@ -168,126 +169,9 @@ public:
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):
osg::Referenced(true),
_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);
void setRawVertexArray(osg::Vec3Array* vertices) { _rawVertexArray = vertices; }
osg::Vec3Array* getRawVertexArray() { return _rawVertexArray.get(); }
/** Get the PrimitiveSetList for the raw face which hasn't been tessellated. */
osg::Geometry::PrimitiveSetList & getRawFacePrimitiveSetList() { return _rawFacePrimitiveSetList; }
/** 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(); }
/** Set the VertexArray of the glyph. */
void setNormalArray(osg::Vec3Array * na) { _normalArray = na; }
/** 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;
osg::ref_ptr<osg::Vec3Array> _rawVertexArray;
osg::Geometry::PrimitiveSetList _rawFacePrimitiveSetList;
};
};

View File

@@ -295,7 +295,7 @@ public:
// internal structures, variable and methods used for rendering of characters.
struct OSGTEXT_EXPORT GlyphQuads
{
typedef std::vector<Font::Glyph*> Glyphs;
typedef std::vector<Glyph*> Glyphs;
typedef std::vector<unsigned int> LineNumbers;
typedef std::vector<osg::Vec2> Coords2;
typedef std::vector<osg::Vec3> Coords3;
@@ -327,10 +327,10 @@ public:
const LineNumbers& getLineNumbers() const { return _lineNumbers; }
};
typedef std::map<osg::ref_ptr<Font::GlyphTexture>,GlyphQuads> TextureGlyphQuadMap;
typedef std::map<osg::ref_ptr<GlyphTexture>,GlyphQuads> TextureGlyphQuadMap;
/** Direct Access to GlyphQuads */
const GlyphQuads* getGlyphQuads(Font::GlyphTexture* texture) const
const GlyphQuads* getGlyphQuads(GlyphTexture* texture) const
{
TextureGlyphQuadMap::iterator itGlyphQuad = _textureGlyphQuadMap.find(texture);
if (itGlyphQuad == _textureGlyphQuadMap.end()) return NULL;

View File

@@ -144,10 +144,10 @@ protected:
// ** glyph and other information to render the glyph
struct GlyphRenderInfo
{
GlyphRenderInfo(Font3D::Glyph3D * glyph, osg::Vec3 & pos) :
GlyphRenderInfo(Glyph3D * glyph, osg::Vec3 & pos) :
_glyph(glyph), _position(pos) {}
osg::ref_ptr<Font3D::Glyph3D> _glyph;
osg::ref_ptr<Glyph3D> _glyph;
osg::Vec3 _position;
};

View File

@@ -14,16 +14,178 @@
#include "FreeTypeFont.h"
#include "FreeTypeLibrary.h"
#include <freetype/ftoutln.h>
#include <freetype/ftbbox.h>
#include <osg/Notify>
#include <osgDB/WriteFile>
#include <osgUtil/SmoothingVisitor>
#include <osgUtil/Tessellator>
namespace FreeType
{
struct Char3DInfo
{
Char3DInfo(int numSteps):
_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 addVertex(const osg::Vec3& pos)
{
if (!_verts->empty() && _verts->back()==pos)
{
// OSG_NOTICE<<"addVertex("<<pos<<") duplicate, ignoring"<<std::endl;
return;
}
_verts->push_back( pos );
setMinMax(pos);
}
void moveTo(const osg::Vec2& pos)
{
if (_verts->size())
{
int len = _verts->size()-_idx;
_geometry->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::POLYGON, _idx, len ) );
}
_idx = _verts->size();
addVertex( osg::Vec3(pos.x(),pos.y(),0) );
}
void lineTo(const osg::Vec2& pos)
{
addVertex( osg::Vec3(pos.x(),pos.y(),0) );
}
void conicTo(const osg::Vec2& control, const 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;
addVertex( p );
u += dt;
}
}
void cubicTo(const osg::Vec2& control1, const osg::Vec2& control2, const 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 );
addVertex( p );
u += dt;
}
}
void setMinMax(const osg::Vec3& 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
}
FreeTypeFont::FreeTypeFont(const std::string& filename, FT_Face face, unsigned int flags):
_currentRes(osgText::FontResolution(0,0)),
_filename(filename),
_buffer(0),
_face(face),
_flags(flags)
_flags(flags),
_scale(1.0f)
{
init();
}
FreeTypeFont::FreeTypeFont(FT_Byte* buffer, FT_Face face, unsigned int flags):
@@ -31,8 +193,10 @@ FreeTypeFont::FreeTypeFont(FT_Byte* buffer, FT_Face face, unsigned int flags):
_filename(""),
_buffer(buffer),
_face(face),
_flags(flags)
_flags(flags),
_scale(1.0f)
{
init();
}
FreeTypeFont::~FreeTypeFont()
@@ -60,6 +224,65 @@ FreeTypeFont::~FreeTypeFont()
}
}
void FreeTypeFont::init()
{
FT_Error _error = FT_Set_Pixel_Sizes(_face, 32, 32);
if (_error)
{
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_NOTICE << "FreeTypeFont3D: initial glyph load failed ..." << std::endl;
return;
}
if (_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
{
OSG_NOTICE << "FreeTypeFont3D: not a vector font" << std::endl;
return;
}
{
FreeType::Char3DInfo char3d(10);
FT_Outline outline = _face->glyph->outline;
FT_Outline_Funcs funcs;
funcs.conic_to = (FT_Outline_ConicToFunc)&FreeType::conicTo;
funcs.line_to = (FT_Outline_LineToFunc)&FreeType::lineTo;
funcs.cubic_to = (FT_Outline_CubicToFunc)&FreeType::cubicTo;
funcs.move_to = (FT_Outline_MoveToFunc)&FreeType::moveTo;
funcs.shift = 0;
funcs.delta = 0;
_error = FT_Outline_Decompose(&outline,&funcs,&char3d);
if (_error)
{
OSG_NOTICE << "FreeTypeFont3D: - outline decompose failed ..." << std::endl;
return;
}
FT_BBox bb;
FT_Outline_Get_BBox(&outline,&bb);
long ymin = ft_floor( bb.yMin );
long ymax = ft_ceiling( bb.yMax );
double height = double(ymax - ymin)/64.0;
// long xmin = ft_floor( bb.xMin );
// long xmax = ft_ceiling( bb.xMax );
// double width = (xmax - xmin)/64.0;
_scale = 1.0/height;
}
}
void FreeTypeFont::setFontResolution(const osgText::FontResolution& fontSize)
{
if (fontSize==_currentRes) return;
@@ -95,7 +318,7 @@ void FreeTypeFont::setFontResolution(const osgText::FontResolution& fontSize)
}
osgText::Font::Glyph* FreeTypeFont::getGlyph(const osgText::FontResolution& fontRes, unsigned int charcode)
osgText::Glyph* FreeTypeFont::getGlyph(const osgText::FontResolution& fontRes, unsigned int charcode)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(FreeTypeLibrary::instance()->getMutex());
@@ -135,7 +358,7 @@ osgText::Font::Glyph* FreeTypeFont::getGlyph(const osgText::FontResolution& font
unsigned int width = sourceWidth;
unsigned int height = sourceHeight;
osg::ref_ptr<osgText::Font::Glyph> glyph = new osgText::Font::Glyph(charcode);
osg::ref_ptr<osgText::Glyph> glyph = new osgText::Glyph(charcode);
unsigned int dataSize = width*height;
unsigned char* data = new unsigned char[dataSize];
@@ -191,14 +414,212 @@ osgText::Font::Glyph* FreeTypeFont::getGlyph(const osgText::FontResolution& font
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(fontRes,charcode,glyph.get());
// cout << " in getGlyph() implementation="<<this<<" "<<_filename<<" facade="<<_facade<<endl;
return glyph.get();
return glyph.release();
}
osgText::Glyph3D * FreeTypeFont::getGlyph3D(unsigned int charcode)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(FreeTypeLibrary::instance()->getMutex());
//
// 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_WARN << "FT_Load_Char(...) error 0x"<<std::hex<<error<<std::dec<<std::endl;
return 0;
}
if (_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
{
OSG_WARN << "FreeTypeFont3D::getGlyph : not a vector font" << std::endl;
return 0;
}
// ** init FreeType to describe the glyph
FreeType::Char3DInfo char3d(_facade->getNumberCurveSamples());
FT_Outline outline = _face->glyph->outline;
FT_Outline_Funcs funcs;
funcs.conic_to = (FT_Outline_ConicToFunc)&FreeType::conicTo;
funcs.line_to = (FT_Outline_LineToFunc)&FreeType::lineTo;
funcs.cubic_to = (FT_Outline_CubicToFunc)&FreeType::cubicTo;
funcs.move_to = (FT_Outline_MoveToFunc)&FreeType::moveTo;
funcs.shift = 0;
funcs.delta = 0;
// ** record description
FT_Error _error = FT_Outline_Decompose(&outline, &funcs, &char3d);
if (_error)
{
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);
osg::ref_ptr<osg::Vec3Array> rawVertices = new osg::Vec3Array(*(char3d._verts));
osg::Geometry::PrimitiveSetList rawPrimitives;
for(osg::Geometry::PrimitiveSetList::iterator itr = char3d.get()->getPrimitiveSetList().begin();
itr != char3d.get()->getPrimitiveSetList().end();
++itr)
{
rawPrimitives.push_back(dynamic_cast<osg::PrimitiveSet*>((*itr)->clone(osg::CopyOp::DEEP_COPY_ALL)));
}
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 convenience.
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 appropriate 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
osg::ref_ptr<osgText::Glyph3D> glyph3D = new osgText::Glyph3D(charcode);
// copy the raw primitive set list before we tessellate it.
glyph3D->getRawFacePrimitiveSetList() = rawPrimitives;
glyph3D->setRawVertexArray(rawVertices.get());
glyph3D->setVertexArray(dynamic_cast<osg::Vec3Array*>(frontGeo->getVertexArray()));
glyph3D->setNormalArray(dynamic_cast<osg::Vec3Array*>(wallGeo->getNormalArray()));
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.release();
}
osg::Vec2 FreeTypeFont::getKerning(const osgText::FontResolution& fontRes, unsigned int leftcharcode,unsigned int rightcharcode, osgText::KerningType kerningType)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(FreeTypeLibrary::instance()->getMutex());

View File

@@ -31,22 +31,33 @@ public:
virtual std::string getFileName() const { return _filename; }
virtual osgText::Font::Glyph* getGlyph(const osgText::FontResolution& fontRes,unsigned int charcode);
virtual osgText::Glyph* getGlyph(const osgText::FontResolution& fontRes,unsigned int charcode);
virtual osgText::Glyph3D* getGlyph3D(unsigned int charcode);
virtual osg::Vec2 getKerning(const osgText::FontResolution& fontRes, unsigned int leftcharcode,unsigned int rightcharcode, osgText::KerningType _kerningType);
virtual bool hasVertical() const;
virtual float getScale() const { return _scale; }
protected:
void init();
void setFontResolution(const osgText::FontResolution& fontSize);
osgText::FontResolution _currentRes;
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); }
std::string _filename;
FT_Byte* _buffer;
FT_Face _face;
unsigned int _flags;
float _scale;
};
#endif

View File

@@ -14,6 +14,9 @@
#include "FreeTypeFont3D.h"
#include "FreeTypeLibrary.h"
#include <freetype/ftoutln.h>
#include <freetype/ftbbox.h>
#include <limits.h>
#include <fstream>
@@ -26,12 +29,6 @@
#include <osgUtil/Tessellator>
#include <ft2build.h>
#include FT_FREETYPE_H
#include <freetype/ftoutln.h>
#include <freetype/ftbbox.h>
#include <osg/io_utils>
namespace
@@ -195,10 +192,7 @@ FreeTypeFont3D::FreeTypeFont3D(const std::string& filename, FT_Face face, unsign
_buffer(0),
_face(face),
_flags(flags),
_scale(1.0),
_shiftY(0.0),
_shiftX(0.0),
_charScale(1.0)
_scale(1.0)
{
init();
}
@@ -208,10 +202,7 @@ FreeTypeFont3D::FreeTypeFont3D(FT_Byte* buffer, FT_Face face, unsigned int flags
_buffer(buffer),
_face(face),
_flags(flags),
_scale(1.0),
_shiftY(0.0),
_shiftX(0.0),
_charScale(1.0)
_scale(1.0)
{
init();
}
@@ -263,26 +254,15 @@ void FreeTypeFont3D::init()
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 height = double(ymax - ymin)/64.0;
double width = (xmax - xmin)/64.0;
double height = (ymax - ymin)/64.0;
// long xmin = ft_floor( bb.xMin );
// long xmax = ft_ceiling( bb.xMax );
// double width = (xmax - xmin)/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;
}
}
@@ -312,7 +292,7 @@ FreeTypeFont3D::~FreeTypeFont3D()
}
osgText::Font3D::Glyph3D * FreeTypeFont3D::getGlyph(unsigned int charcode)
osgText::Glyph3D * FreeTypeFont3D::getGlyph(unsigned int charcode)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(FreeTypeLibrary::instance()->getMutex());
@@ -472,7 +452,7 @@ osgText::Font3D::Glyph3D * FreeTypeFont3D::getGlyph(unsigned int charcode)
}
// ** save vertices and PrimitiveSetList of each face in the Glyph3D PrimitiveSet face list
osgText::Font3D::Glyph3D * glyph3D = new osgText::Font3D::Glyph3D(charcode);
osgText::Glyph3D * glyph3D = new osgText::Glyph3D(charcode);
// copy the raw primitive set list before we tessellate it.
glyph3D->getRawFacePrimitiveSetList() = rawPrimitives;

View File

@@ -29,7 +29,7 @@ public:
virtual std::string getFileName() const { return _filename; }
virtual osgText::Font3D::Glyph3D * getGlyph(unsigned int charcode);
virtual osgText::Glyph3D * getGlyph(unsigned int charcode);
virtual osg::Vec2 getKerning(unsigned int leftcharcode,unsigned int rightcharcode, osgText::KerningType _kerningType);
@@ -52,11 +52,7 @@ protected:
FT_Face _face;
unsigned int _flags;
double _scale;
double _shiftY;
double _shiftX;
double _charScale;
};
#endif

View File

@@ -81,8 +81,7 @@ TXFFont::getFileName() const
return _filename;
}
osgText::Font::Glyph*
TXFFont::getGlyph(const osgText::FontResolution&, unsigned int charcode)
osgText::Glyph* TXFFont::getGlyph(const osgText::FontResolution&, unsigned int charcode)
{
GlyphMap::iterator i = _chars.find(charcode);
if (i != _chars.end())
@@ -96,7 +95,6 @@ TXFFont::getGlyph(const osgText::FontResolution&, unsigned int charcode)
if (i != _chars.end())
{
_chars[charcode] = i->second;
addGlyph(osgText::FontResolution(i->second->s(), i->second->t()), charcode, i->second.get());
return i->second.get();
}
}
@@ -106,7 +104,6 @@ TXFFont::getGlyph(const osgText::FontResolution&, unsigned int charcode)
if (i != _chars.end())
{
_chars[charcode] = i->second;
addGlyph(osgText::FontResolution(i->second->s(), i->second->t()), charcode, i->second.get());
return i->second.get();
}
}
@@ -230,7 +227,7 @@ TXFFont::loadFont(std::istream& stream)
continue;
// add the characters ...
osgText::Font::Glyph* glyph = new osgText::Font::Glyph(glyphs[i].ch);
osgText::Glyph* glyph = new osgText::Glyph(glyphs[i].ch);
unsigned sourceWidth = glyphs[i].width;
unsigned sourceHeight = glyphs[i].height;
@@ -267,11 +264,12 @@ TXFFont::loadFont(std::istream& stream)
- glyphs[i].height*texToVertY));
_chars[glyphs[i].ch] = glyph;
addGlyph(fontResolution, glyphs[i].ch, glyph);
}
// insert a trivial blank character
osgText::Font::Glyph* glyph = new osgText::Font::Glyph(' ');
osgText::Glyph* glyph = new osgText::Glyph(' ');
unsigned width = 1;
unsigned height = 1;

View File

@@ -28,16 +28,20 @@ public:
virtual std::string getFileName() const;
virtual osgText::Font::Glyph* getGlyph(const osgText::FontResolution& fontRes, unsigned int charcode);
virtual osgText::Glyph* getGlyph(const osgText::FontResolution& fontRes, unsigned int charcode);
virtual osgText::Glyph3D* getGlyph3D(unsigned int) { return 0; }
virtual bool hasVertical() const;
virtual osg::Vec2 getKerning(const osgText::FontResolution& fontRes, unsigned int leftcharcode,unsigned int rightcharcode, osgText::KerningType kerningType);
virtual float getScale() const { return 1.0; }
bool loadFont(std::istream& stream);
protected:
typedef std::map<unsigned int, osg::ref_ptr<osgText::Font::Glyph> > GlyphMap;
typedef std::map<unsigned int, osg::ref_ptr<osgText::Glyph> > GlyphMap;
std::string _filename;
GlyphMap _chars;

View File

@@ -51,7 +51,7 @@ QFontImplementation::setFontResolution(const osgText::FontResolution& fontSize)
_font.setPixelSize(fontSize.second);
}
osgText::Font::Glyph*
osgText::Glyph*
QFontImplementation::getGlyph(const osgText::FontResolution& fontRes, unsigned int charcode)
{
setFontResolution(fontRes);
@@ -83,7 +83,7 @@ QFontImplementation::getGlyph(const osgText::FontResolution& fontRes, unsigned i
painter.end();
// Transfer the rendered image to osg
osg::ref_ptr<osgText::Font::Glyph> glyph = new osgText::Font::Glyph(charcode);
osg::ref_ptr<osgText::Glyph> glyph = new osgText::Glyph(charcode);
unsigned int dataSize = imageWidth*imageHeight;
unsigned char* data = new unsigned char[dataSize];

View File

@@ -33,23 +33,12 @@ DefaultFont::~DefaultFont()
{
}
DefaultFont* DefaultFont::instance()
{
static OpenThreads::Mutex s_DefaultFontMutex;
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_DefaultFontMutex);
static osg::ref_ptr<DefaultFont> s_defaultFont = new DefaultFont;
return s_defaultFont.get();
}
void DefaultFont::setSize(unsigned int, unsigned int)
{
OSG_INFO<<"DefaultFont::setSize(,) call is ignored."<<std::endl;
}
Font::Glyph* DefaultFont::getGlyph(const FontResolution& fontRes, unsigned int charcode)
osgText::Glyph* DefaultFont::getGlyph(const FontResolution& fontRes, unsigned int charcode)
{
if (_sizeGlyphMap.empty()) return 0;

View File

@@ -26,22 +26,25 @@ class DefaultFont : public Font
{
public:
static DefaultFont* instance();
DefaultFont();
virtual std::string getFileName() const { return ""; }
/** NOP with DefaultFont since it only supports a single fixed sized font. */
virtual void setSize(unsigned int width, unsigned int height);
virtual Font::Glyph* getGlyph(const FontResolution& fontRes, unsigned int charcode);
virtual osgText::Glyph* getGlyph(const FontResolution& fontRes, unsigned int charcode);
virtual osgText::Glyph3D* getGlyph3D(unsigned int charcode) { return 0; }
virtual osg::Vec2 getKerning(const FontResolution&, unsigned int leftcharcode,unsigned int rightcharcode, KerningType kerningType);
virtual bool hasVertical() const;
virtual float getScale() const { return 1.0; }
protected:
DefaultFont();
virtual ~DefaultFont();
void constructGlyphs();

View File

@@ -27,11 +27,23 @@
#include <OpenThreads/ReentrantMutex>
#include "DefaultFont.h"
using namespace osgText;
using namespace std;
static osg::ApplicationUsageProxy Font_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_TEXT_INCREMENTAL_SUBLOADING <type>","ON | OFF");
osg::ref_ptr<Font>& Font::getDefaultFont()
{
static OpenThreads::Mutex s_DefaultFontMutex;
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_DefaultFontMutex);
static osg::ref_ptr<Font> s_defaultFont = new DefaultFont;
return s_defaultFont;
}
static OpenThreads::ReentrantMutex s_FontFileMutex;
std::string osgText::findFontFile(const std::string& str)
@@ -210,7 +222,9 @@ Font::Font(FontImplementation* implementation):
_textureWidthHint(1024),
_textureHeightHint(1024),
_minFilterHint(osg::Texture::LINEAR_MIPMAP_LINEAR),
_magFilterHint(osg::Texture::LINEAR)
_magFilterHint(osg::Texture::LINEAR),
_depth(1),
_numCurveSamples(10)
{
setImplementation(implementation);
@@ -326,23 +340,46 @@ osg::Texture::FilterMode Font::getMagFilterHint() const
}
Font::Glyph* Font::getGlyph(const FontResolution& fontRes, unsigned int charcode)
Glyph* Font::getGlyph(const FontResolution& fontRes, unsigned int charcode)
{
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_glyphMapMutex);
FontSizeGlyphMap::iterator itr = _sizeGlyphMap.find(fontRes);
if (itr!=_sizeGlyphMap.end())
{
GlyphMap& glyphmap = itr->second;
GlyphMap& glyphmap = itr->second;
GlyphMap::iterator gitr = glyphmap.find(charcode);
if (gitr!=glyphmap.end()) return gitr->second.get();
}
}
if (_implementation.valid()) return _implementation->getGlyph(fontRes, charcode);
Glyph* glyph = _implementation.valid() ? _implementation->getGlyph(fontRes, charcode) : 0;
if (glyph)
{
addGlyph(fontRes, charcode, glyph);
return glyph;
}
else return 0;
}
Glyph3D* Font::getGlyph3D(unsigned int charcode)
{
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_glyphMapMutex);
Glyph3DMap::iterator itr = _glyph3DMap.find(charcode);
if (itr!=_glyph3DMap.end()) return itr->second.get();
}
Glyph3D* glyph = _implementation.valid() ? _implementation->getGlyph3D(charcode) : 0;
if (glyph)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_glyphMapMutex);
_glyph3DMap[charcode] = glyph;
return glyph;
}
return 0;
}
void Font::setThreadSafeRefUnref(bool threadSafe)
{
osg::Object::setThreadSafeRefUnref(threadSafe);
@@ -454,7 +491,7 @@ void Font::addGlyph(const FontResolution& fontRes, unsigned int charcode, Glyph*
}
Font::GlyphTexture::GlyphTexture():
GlyphTexture::GlyphTexture():
_margin(1),
_marginRatio(0.02f),
_usedY(0),
@@ -465,12 +502,12 @@ Font::GlyphTexture::GlyphTexture():
setWrap(WRAP_T, CLAMP_TO_EDGE);
}
Font::GlyphTexture::~GlyphTexture()
GlyphTexture::~GlyphTexture()
{
}
// return -1 if *this < *rhs, 0 if *this==*rhs, 1 if *this>*rhs.
int Font::GlyphTexture::compare(const osg::StateAttribute& rhs) const
int GlyphTexture::compare(const osg::StateAttribute& rhs) const
{
if (this<&rhs) return -1;
else if (this>&rhs) return 1;
@@ -478,7 +515,7 @@ int Font::GlyphTexture::compare(const osg::StateAttribute& rhs) const
}
bool Font::GlyphTexture::getSpaceForGlyph(Glyph* glyph, int& posX, int& posY)
bool GlyphTexture::getSpaceForGlyph(Glyph* glyph, int& posX, int& posY)
{
int maxAxis = std::max(glyph->s(), glyph->t());
int margin = _margin + (int)((float)maxAxis * _marginRatio);
@@ -525,7 +562,7 @@ bool Font::GlyphTexture::getSpaceForGlyph(Glyph* glyph, int& posX, int& posY)
return false;
}
void Font::GlyphTexture::addGlyph(Glyph* glyph, int posX, int posY)
void GlyphTexture::addGlyph(Glyph* glyph, int posX, int posY)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
@@ -545,7 +582,7 @@ void Font::GlyphTexture::addGlyph(Glyph* glyph, int posX, int posY)
static_cast<float>(posY+glyph->t())/static_cast<float>(getTextureHeight()) ) );
}
void Font::GlyphTexture::apply(osg::State& state) const
void GlyphTexture::apply(osg::State& state) const
{
// get the contextID (user defined ID of 0 upwards) for the
// current OpenGL context.
@@ -797,12 +834,12 @@ void Font::GlyphTexture::apply(osg::State& state) const
}
void Font::GlyphTexture::setThreadSafeRefUnref(bool threadSafe)
void GlyphTexture::setThreadSafeRefUnref(bool threadSafe)
{
osg::Texture2D::setThreadSafeRefUnref(threadSafe);
}
void Font::GlyphTexture::resizeGLObjectBuffers(unsigned int maxSize)
void GlyphTexture::resizeGLObjectBuffers(unsigned int maxSize)
{
osg::Texture2D::resizeGLObjectBuffers(maxSize);
_glyphsToSubload.resize(maxSize);
@@ -810,7 +847,7 @@ void Font::GlyphTexture::resizeGLObjectBuffers(unsigned int maxSize)
// all the methods in Font::Glyph have been made non inline because VisualStudio6.0 is STUPID, STUPID, STUPID PILE OF JUNK.
Font::Glyph::Glyph(unsigned int glyphCode):
Glyph::Glyph(unsigned int glyphCode):
_font(0),
_glyphCode(glyphCode),
_horizontalBearing(0.0f,0.f),
@@ -826,53 +863,53 @@ Font::Glyph::Glyph(unsigned int glyphCode):
setThreadSafeRefUnref(true);
}
Font::Glyph::~Glyph()
Glyph::~Glyph()
{
}
void Font::Glyph::setHorizontalBearing(const osg::Vec2& bearing) { _horizontalBearing=bearing; }
const osg::Vec2& Font::Glyph::getHorizontalBearing() const { return _horizontalBearing; }
void Glyph::setHorizontalBearing(const osg::Vec2& bearing) { _horizontalBearing=bearing; }
const osg::Vec2& Glyph::getHorizontalBearing() const { return _horizontalBearing; }
void Font::Glyph::setHorizontalAdvance(float advance) { _horizontalAdvance=advance; }
float Font::Glyph::getHorizontalAdvance() const { return _horizontalAdvance; }
void Glyph::setHorizontalAdvance(float advance) { _horizontalAdvance=advance; }
float Glyph::getHorizontalAdvance() const { return _horizontalAdvance; }
void Font::Glyph::setVerticalBearing(const osg::Vec2& bearing) { _verticalBearing=bearing; }
const osg::Vec2& Font::Glyph::getVerticalBearing() const { return _verticalBearing; }
void Glyph::setVerticalBearing(const osg::Vec2& bearing) { _verticalBearing=bearing; }
const osg::Vec2& Glyph::getVerticalBearing() const { return _verticalBearing; }
void Font::Glyph::setVerticalAdvance(float advance) { _verticalAdvance=advance; }
float Font::Glyph::getVerticalAdvance() const { return _verticalAdvance; }
void Glyph::setVerticalAdvance(float advance) { _verticalAdvance=advance; }
float Glyph::getVerticalAdvance() const { return _verticalAdvance; }
void Font::Glyph::setTexture(GlyphTexture* texture) { _texture = texture; }
Font::GlyphTexture* Font::Glyph::getTexture() { return _texture; }
const Font::GlyphTexture* Font::Glyph::getTexture() const { return _texture; }
void Glyph::setTexture(GlyphTexture* texture) { _texture = texture; }
GlyphTexture* Glyph::getTexture() { return _texture; }
const GlyphTexture* Glyph::getTexture() const { return _texture; }
void Font::Glyph::setTexturePosition(int posX,int posY) { _texturePosX = posX; _texturePosY = posY; }
int Font::Glyph::getTexturePositionX() const { return _texturePosX; }
int Font::Glyph::getTexturePositionY() const { return _texturePosY; }
void Glyph::setTexturePosition(int posX,int posY) { _texturePosX = posX; _texturePosY = posY; }
int Glyph::getTexturePositionX() const { return _texturePosX; }
int Glyph::getTexturePositionY() const { return _texturePosY; }
void Font::Glyph::setMinTexCoord(const osg::Vec2& coord) { _minTexCoord=coord; }
const osg::Vec2& Font::Glyph::getMinTexCoord() const { return _minTexCoord; }
void Glyph::setMinTexCoord(const osg::Vec2& coord) { _minTexCoord=coord; }
const osg::Vec2& Glyph::getMinTexCoord() const { return _minTexCoord; }
void Font::Glyph::setMaxTexCoord(const osg::Vec2& coord) { _maxTexCoord=coord; }
const osg::Vec2& Font::Glyph::getMaxTexCoord() const { return _maxTexCoord; }
void Glyph::setMaxTexCoord(const osg::Vec2& coord) { _maxTexCoord=coord; }
const osg::Vec2& Glyph::getMaxTexCoord() const { return _maxTexCoord; }
void Font::Glyph::subload() const
void Glyph::subload() const
{
GLenum errorNo = glGetError();
if (errorNo!=GL_NO_ERROR)
{
#ifdef OSG_GLU_AVAILABLE
const GLubyte* msg = gluErrorString(errorNo);
if (msg) { OSG_WARN<<"before Font::Glyph::subload(): detected OpenGL error: "<<msg<<std::endl; }
else { OSG_WARN<<"before Font::Glyph::subload(): detected OpenGL error number: "<<errorNo<<std::endl; }
if (msg) { OSG_WARN<<"before Glyph::subload(): detected OpenGL error: "<<msg<<std::endl; }
else { OSG_WARN<<"before Glyph::subload(): detected OpenGL error number: "<<errorNo<<std::endl; }
#else
OSG_WARN<<"before Font::Glyph::subload(): detected OpenGL error number: "<<errorNo<<std::endl;
OSG_WARN<<"before Glyph::subload(): detected OpenGL error number: "<<errorNo<<std::endl;
#endif
}
if(s() <= 0 || t() <= 0)
{
OSG_INFO<<"Font::Glyph::subload(): texture sub-image width and/or height of 0, ignoring operation."<<std::endl;
OSG_INFO<<"Glyph::subload(): texture sub-image width and/or height of 0, ignoring operation."<<std::endl;
return;
}
@@ -892,10 +929,10 @@ void Font::Glyph::subload() const
#ifdef OSG_GLU_AVAILABLE
const GLubyte* msg = gluErrorString(errorNo);
if (msg) { OSG_WARN<<"after Font::Glyph::subload() : detected OpenGL error: "<<msg<<std::endl; }
else { OSG_WARN<<"after Font::Glyph::subload() : detected OpenGL error number: "<<errorNo<<std::endl; }
if (msg) { OSG_WARN<<"after Glyph::subload() : detected OpenGL error: "<<msg<<std::endl; }
else { OSG_WARN<<"after Glyph::subload() : detected OpenGL error number: "<<errorNo<<std::endl; }
#else
OSG_WARN<<"after Font::Glyph::subload() : detected OpenGL error number: "<<errorNo<<std::endl;
OSG_WARN<<"after Glyph::subload() : detected OpenGL error number: "<<errorNo<<std::endl;
#endif
OSG_WARN<< "\tglTexSubImage2D(0x"<<hex<<GL_TEXTURE_2D<<dec<<" ,"<<0<<"\t"<<std::endl<<

View File

@@ -277,7 +277,7 @@ std::string Font3D::getFileName() const
return "";
}
Font3D::Glyph3D* Font3D::getGlyph(unsigned int charcode)
Glyph3D* Font3D::getGlyph(unsigned int charcode)
{
Glyph3D * glyph3D = NULL;
@@ -312,7 +312,7 @@ bool Font3D::hasVertical() const
else return false;
}
void Font3D::Glyph3D::setThreadSafeRefUnref(bool threadSafe)
void Glyph3D::setThreadSafeRefUnref(bool threadSafe)
{
if (_vertexArray.valid()) _vertexArray->setThreadSafeRefUnref(threadSafe);
if (_normalArray.valid()) _normalArray->setThreadSafeRefUnref(threadSafe);

View File

@@ -24,8 +24,6 @@
#include <osgDB/ReadFile>
#include "DefaultFont.h"
using namespace osg;
using namespace osgText;
@@ -71,8 +69,8 @@ void Text::setFont(osg::ref_ptr<Font> font)
{
if (_font==font) return;
osg::StateSet* previousFontStateSet = _font.valid() ? _font->getStateSet() : DefaultFont::instance()->getStateSet();
osg::StateSet* newFontStateSet = font.valid() ? font->getStateSet() : DefaultFont::instance()->getStateSet();
osg::StateSet* previousFontStateSet = _font.valid() ? _font->getStateSet() : Font::getDefaultFont()->getStateSet();
osg::StateSet* newFontStateSet = font.valid() ? font->getStateSet() : Font::getDefaultFont()->getStateSet();
if (getStateSet() == previousFontStateSet)
{
@@ -98,12 +96,12 @@ void Text::setColor(const osg::Vec4& color)
Font* Text::getActiveFont()
{
return _font.valid() ? _font.get() : DefaultFont::instance();
return _font.valid() ? _font.get() : Font::getDefaultFont().get();
}
const Font* Text::getActiveFont() const
{
return _font.valid() ? _font.get() : DefaultFont::instance();
return _font.valid() ? _font.get() : Font::getDefaultFont().get();
}
String::iterator Text::computeLastCharacterOnLine(osg::Vec2& cursor, String::iterator first,String::iterator last)
@@ -128,7 +126,7 @@ String::iterator Text::computeLastCharacterOnLine(osg::Vec2& cursor, String::ite
return lastChar;
}
Font::Glyph* glyph = activefont->getGlyph(_fontSize, charcode);
Glyph* glyph = activefont->getGlyph(_fontSize, charcode);
if (glyph)
{
@@ -223,7 +221,7 @@ String::iterator Text::computeLastCharacterOnLine(osg::Vec2& cursor, String::ite
// Subtract off glyphs from the cursor position (to correctly center text)
if(*prevChar != '-')
{
Font::Glyph* glyph = activefont->getGlyph(_fontSize, *prevChar);
Glyph* glyph = activefont->getGlyph(_fontSize, *prevChar);
if (glyph)
{
switch(_layout)
@@ -397,7 +395,7 @@ void Text::computeGlyphRepresentation()
{
unsigned int charcode = *itr;
Font::Glyph* glyph = activefont->getGlyph(_fontSize, charcode);
Glyph* glyph = activefont->getGlyph(_fontSize, charcode);
if (glyph)
{
float width = (float)(glyph->s()) * wr;

View File

@@ -135,7 +135,7 @@ String::iterator Text3D::computeLastCharacterOnLine(osg::Vec2& cursor, String::i
return lastChar;
}
Font3D::Glyph3D* glyph = _font->getGlyph(charcode);
Glyph3D* glyph = _font->getGlyph(charcode);
if (glyph)
{
const osg::BoundingBox & bb = glyph->getBoundingBox();
@@ -245,7 +245,7 @@ String::iterator Text3D::computeLastCharacterOnLine(osg::Vec2& cursor, String::i
// Subtract off glyphs from the cursor position (to correctly center text)
if(*prevChar != '-')
{
Font3D::Glyph3D* glyph = _font->getGlyph(*prevChar);
Glyph3D* glyph = _font->getGlyph(*prevChar);
if (glyph)
{
switch(_layout)
@@ -316,7 +316,7 @@ void Text3D::computeGlyphRepresentation()
{
unsigned int charcode = *itr;
Font3D::Glyph3D* glyph = _font->getGlyph(charcode);
Glyph3D* glyph = _font->getGlyph(charcode);
if (glyph)
{
const osg::BoundingBox & bb = glyph->getBoundingBox();

View File

@@ -13,6 +13,7 @@
#include <osgText/TextBase>
#include <osgText/Font>
#include <osg/Math>
#include <osg/GL>
@@ -24,8 +25,6 @@
#include <osgDB/ReadFile>
#include "DefaultFont.h"
using namespace osg;
using namespace osgText;
@@ -49,7 +48,7 @@ TextBase::TextBase():
_kerningType(KERNING_DEFAULT),
_lineCount(0)
{
setStateSet(DefaultFont::instance()->getStateSet());
setStateSet(Font::getDefaultFont()->getStateSet());
setUseDisplayList(false);
setSupportsDisplayList(false);
}

View File

@@ -114,7 +114,7 @@ void Input::_calculateCursorOffsets() {
osgText::Text::TextureGlyphQuadMap::iterator tgqmi = tgqm.begin();
std::vector<osg::Vec2> coords;
std::vector<osgText::Font::Glyph*> glyphs;
std::vector<osgText::Glyph*> glyphs;
for ( ; tgqmi != tgqm.end(); tgqmi++ )
{
const osgText::Text::GlyphQuads& gq = tgqmi->second;
@@ -140,9 +140,9 @@ void Input::_calculateCursorOffsets() {
unsigned int key = keys.front();
for (unsigned int i=0; i<glyphs.size(); ++i)
{
static osgText::Font::Glyph* previous_g = 0;
static osgText::Glyph* previous_g = 0;
osgText::Font::Glyph* g = glyphs.at(i);
osgText::Glyph* g = glyphs.at(i);
if (g->getGlyphCode()==key)
{
lr = coords[2 + (i * 4)];
@@ -653,7 +653,7 @@ unsigned int Input::calculateBestYOffset(const std::string& s)
for(osgText::String::iterator i = utf.begin(); i != utf.end(); i++) {
osgText::Font* font = const_cast<osgText::Font*>(_text->getFont());
osgText::Font::Glyph* glyph = font->getGlyph(fr, *i);
osgText::Glyph* glyph = font->getGlyph(fr, *i);
unsigned int d = abs((int)glyph->getHorizontalBearing().y());
if(d > descent) descent = d;