Moved Glyph and Glyph3D out of Font header/source file into their own header/source file.
This commit is contained in:
parent
50be800787
commit
234cb82867
256
include/osgText/Glyph
Normal file
256
include/osgText/Glyph
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
/* -*-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_GLYPH
|
||||||
|
#define OSGTEXT_GLYPH 1
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <istream>
|
||||||
|
|
||||||
|
#include <osg/Vec2>
|
||||||
|
#include <osg/Image>
|
||||||
|
#include <osg/Texture2D>
|
||||||
|
#include <osg/StateSet>
|
||||||
|
#include <osg/Geometry>
|
||||||
|
|
||||||
|
#include <osgText/Export>
|
||||||
|
#include <osgText/KerningType>
|
||||||
|
|
||||||
|
#include <OpenThreads/Mutex>
|
||||||
|
|
||||||
|
namespace osgText {
|
||||||
|
|
||||||
|
class Font;
|
||||||
|
class Text;
|
||||||
|
class Glyph3D;
|
||||||
|
class GlyphTexture;
|
||||||
|
|
||||||
|
class OSGTEXT_EXPORT Glyph : public osg::Image
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
Glyph(Font* font, 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(Font* font, unsigned int glyphCode);
|
||||||
|
|
||||||
|
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; }
|
||||||
|
|
||||||
|
|
||||||
|
/** deprecated feature.*/
|
||||||
|
void computeText3DGeometryData();
|
||||||
|
|
||||||
|
/** 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() {}
|
||||||
|
|
||||||
|
Font* _font;
|
||||||
|
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;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
534
src/osgText/Glyph.cpp
Normal file
534
src/osgText/Glyph.cpp
Normal file
@ -0,0 +1,534 @@
|
|||||||
|
/* -*-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/Font>
|
||||||
|
#include <osgText/Text>
|
||||||
|
|
||||||
|
#include <osg/State>
|
||||||
|
#include <osg/Notify>
|
||||||
|
#include <osg/GLU>
|
||||||
|
|
||||||
|
#include <osgUtil/SmoothingVisitor>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "GlyphGeometry.h"
|
||||||
|
|
||||||
|
using namespace osgText;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
GlyphTexture::GlyphTexture():
|
||||||
|
_margin(1),
|
||||||
|
_marginRatio(0.02f),
|
||||||
|
_usedY(0),
|
||||||
|
_partUsedX(0),
|
||||||
|
_partUsedY(0)
|
||||||
|
{
|
||||||
|
setWrap(WRAP_S, CLAMP_TO_EDGE);
|
||||||
|
setWrap(WRAP_T, CLAMP_TO_EDGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
GlyphTexture::~GlyphTexture()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// return -1 if *this < *rhs, 0 if *this==*rhs, 1 if *this>*rhs.
|
||||||
|
int GlyphTexture::compare(const osg::StateAttribute& rhs) const
|
||||||
|
{
|
||||||
|
if (this<&rhs) return -1;
|
||||||
|
else if (this>&rhs) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool GlyphTexture::getSpaceForGlyph(Glyph* glyph, int& posX, int& posY)
|
||||||
|
{
|
||||||
|
int maxAxis = std::max(glyph->s(), glyph->t());
|
||||||
|
int margin = _margin + (int)((float)maxAxis * _marginRatio);
|
||||||
|
|
||||||
|
int width = glyph->s()+2*margin;
|
||||||
|
int height = glyph->t()+2*margin;
|
||||||
|
|
||||||
|
// first check box (_partUsedX,_usedY) to (width,height)
|
||||||
|
if (width <= (getTextureWidth()-_partUsedX) &&
|
||||||
|
height <= (getTextureHeight()-_usedY))
|
||||||
|
{
|
||||||
|
// can fit in existing row.
|
||||||
|
|
||||||
|
// record the position in which the texture will be stored.
|
||||||
|
posX = _partUsedX+margin;
|
||||||
|
posY = _usedY+margin;
|
||||||
|
|
||||||
|
// move used markers on.
|
||||||
|
_partUsedX += width;
|
||||||
|
if (_usedY+height>_partUsedY) _partUsedY = _usedY+height;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// start an new row.
|
||||||
|
if (width <= getTextureWidth() &&
|
||||||
|
height <= (getTextureHeight()-_partUsedY))
|
||||||
|
{
|
||||||
|
// can fit next row.
|
||||||
|
_partUsedX = 0;
|
||||||
|
_usedY = _partUsedY;
|
||||||
|
|
||||||
|
posX = _partUsedX+margin;
|
||||||
|
posY = _usedY+margin;
|
||||||
|
|
||||||
|
// move used markers on.
|
||||||
|
_partUsedX += width;
|
||||||
|
if (_usedY+height>_partUsedY) _partUsedY = _usedY+height;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// doesn't fit into glyph.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlyphTexture::addGlyph(Glyph* glyph, int posX, int posY)
|
||||||
|
{
|
||||||
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
||||||
|
|
||||||
|
_glyphs.push_back(glyph);
|
||||||
|
for(unsigned int i=0;i<_glyphsToSubload.size();++i)
|
||||||
|
{
|
||||||
|
_glyphsToSubload[i].push_back(glyph);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set up the details of where to place glyph's image in the texture.
|
||||||
|
glyph->setTexture(this);
|
||||||
|
glyph->setTexturePosition(posX,posY);
|
||||||
|
|
||||||
|
glyph->setMinTexCoord( osg::Vec2( static_cast<float>(posX)/static_cast<float>(getTextureWidth()),
|
||||||
|
static_cast<float>(posY)/static_cast<float>(getTextureHeight()) ) );
|
||||||
|
glyph->setMaxTexCoord( osg::Vec2( static_cast<float>(posX+glyph->s())/static_cast<float>(getTextureWidth()),
|
||||||
|
static_cast<float>(posY+glyph->t())/static_cast<float>(getTextureHeight()) ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlyphTexture::apply(osg::State& state) const
|
||||||
|
{
|
||||||
|
// get the contextID (user defined ID of 0 upwards) for the
|
||||||
|
// current OpenGL context.
|
||||||
|
const unsigned int contextID = state.getContextID();
|
||||||
|
|
||||||
|
if (contextID>=_glyphsToSubload.size())
|
||||||
|
{
|
||||||
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
||||||
|
|
||||||
|
// graphics context is beyond the number of glyphsToSubloads, so
|
||||||
|
// we must now copy the glyph list across, this is a potential
|
||||||
|
// threading issue though is multiple applies are happening the
|
||||||
|
// same time on this object - to avoid this condition number of
|
||||||
|
// graphics contexts should be set before create text.
|
||||||
|
for(unsigned int i=_glyphsToSubload.size();i<=contextID;++i)
|
||||||
|
{
|
||||||
|
GlyphPtrList& glyphPtrs = _glyphsToSubload[i];
|
||||||
|
for(GlyphRefList::const_iterator itr=_glyphs.begin();
|
||||||
|
itr!=_glyphs.end();
|
||||||
|
++itr)
|
||||||
|
{
|
||||||
|
glyphPtrs.push_back(itr->get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const Extensions* extensions = getExtensions(contextID,true);
|
||||||
|
bool generateMipMapSupported = extensions->isGenerateMipMapSupported();
|
||||||
|
|
||||||
|
// get the texture object for the current contextID.
|
||||||
|
TextureObject* textureObject = getTextureObject(contextID);
|
||||||
|
|
||||||
|
bool newTextureObject = (textureObject == 0);
|
||||||
|
|
||||||
|
if (newTextureObject)
|
||||||
|
{
|
||||||
|
GLint maxTextureSize = 256;
|
||||||
|
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
|
||||||
|
if (maxTextureSize < getTextureWidth() || maxTextureSize < getTextureHeight())
|
||||||
|
{
|
||||||
|
OSG_WARN<<"Warning: osgText::Font texture size of ("<<getTextureWidth()<<", "<<getTextureHeight()<<") too large, unable to create font texture."<<std::endl;
|
||||||
|
OSG_WARN<<" Maximum supported by hardward by native OpenGL implementation is ("<<maxTextureSize<<","<<maxTextureSize<<")."<<std::endl;
|
||||||
|
OSG_WARN<<" Please set OSG_MAX_TEXTURE_SIZE lenvironment variable to "<<maxTextureSize<<" and re-run application."<<std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// being bound for the first time, need to allocate the texture
|
||||||
|
|
||||||
|
_textureObjectBuffer[contextID] = textureObject = osg::Texture::generateTextureObject(
|
||||||
|
this, contextID,GL_TEXTURE_2D,1,GL_ALPHA,getTextureWidth(), getTextureHeight(),1,0);
|
||||||
|
|
||||||
|
textureObject->bind();
|
||||||
|
|
||||||
|
|
||||||
|
applyTexParameters(GL_TEXTURE_2D,state);
|
||||||
|
|
||||||
|
|
||||||
|
// need to look at generate mip map extension if mip mapping required.
|
||||||
|
switch(_min_filter)
|
||||||
|
{
|
||||||
|
case NEAREST_MIPMAP_NEAREST:
|
||||||
|
case NEAREST_MIPMAP_LINEAR:
|
||||||
|
case LINEAR_MIPMAP_NEAREST:
|
||||||
|
case LINEAR_MIPMAP_LINEAR:
|
||||||
|
if (generateMipMapSupported)
|
||||||
|
{
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS,GL_TRUE);
|
||||||
|
}
|
||||||
|
else glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, LINEAR);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// not mip mapping so no problems.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int imageDataSize = getTextureHeight()*getTextureWidth();
|
||||||
|
unsigned char* imageData = new unsigned char[imageDataSize];
|
||||||
|
for(unsigned int i=0; i<imageDataSize; ++i)
|
||||||
|
{
|
||||||
|
imageData[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// OSG_NOTICE<<"Texture width = "<<getTextureWidth()<<std::endl;
|
||||||
|
// OSG_NOTICE<<"Texture height = "<<getTextureHeight()<<std::endl;
|
||||||
|
|
||||||
|
// allocate the texture memory.
|
||||||
|
glTexImage2D( GL_TEXTURE_2D, 0, GL_ALPHA,
|
||||||
|
getTextureWidth(), getTextureHeight(), 0,
|
||||||
|
GL_ALPHA,
|
||||||
|
GL_UNSIGNED_BYTE,
|
||||||
|
imageData );
|
||||||
|
|
||||||
|
delete [] imageData;
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// reuse texture by binding.
|
||||||
|
textureObject->bind();
|
||||||
|
|
||||||
|
if (getTextureParameterDirty(contextID))
|
||||||
|
{
|
||||||
|
applyTexParameters(GL_TEXTURE_2D,state);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static const GLubyte* s_renderer = 0;
|
||||||
|
static bool s_subloadAllGlyphsTogether = false;
|
||||||
|
if (!s_renderer)
|
||||||
|
{
|
||||||
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
||||||
|
|
||||||
|
s_renderer = glGetString(GL_RENDERER);
|
||||||
|
OSG_INFO<<"glGetString(GL_RENDERER)=="<<s_renderer<<std::endl;
|
||||||
|
if (s_renderer && strstr((const char*)s_renderer,"IMPACT")!=0)
|
||||||
|
{
|
||||||
|
// we're running on an Octane, so need to work around its
|
||||||
|
// subloading bugs by loading all at once.
|
||||||
|
s_subloadAllGlyphsTogether = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_renderer &&
|
||||||
|
((strstr((const char*)s_renderer,"Radeon")!=0) ||
|
||||||
|
(strstr((const char*)s_renderer,"RADEON")!=0) ||
|
||||||
|
(strstr((const char*)s_renderer,"ALL-IN-WONDER")!=0)))
|
||||||
|
{
|
||||||
|
// we're running on an ATI, so need to work around its
|
||||||
|
// subloading bugs by loading all at once.
|
||||||
|
s_subloadAllGlyphsTogether = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_renderer && strstr((const char*)s_renderer,"Sun")!=0)
|
||||||
|
{
|
||||||
|
// we're running on an solaris x server, so need to work around its
|
||||||
|
// subloading bugs by loading all at once.
|
||||||
|
s_subloadAllGlyphsTogether = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* str = getenv("OSG_TEXT_INCREMENTAL_SUBLOADING");
|
||||||
|
if (str)
|
||||||
|
{
|
||||||
|
s_subloadAllGlyphsTogether = strcmp(str,"OFF")==0 || strcmp(str,"Off")==0 || strcmp(str,"off")==0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// now subload the glyphs that are outstanding for this graphics context.
|
||||||
|
GlyphPtrList& glyphsWereSubloading = _glyphsToSubload[contextID];
|
||||||
|
|
||||||
|
if (!glyphsWereSubloading.empty() || newTextureObject)
|
||||||
|
{
|
||||||
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
||||||
|
|
||||||
|
if (!s_subloadAllGlyphsTogether)
|
||||||
|
{
|
||||||
|
if (newTextureObject)
|
||||||
|
{
|
||||||
|
for(GlyphRefList::const_iterator itr=_glyphs.begin();
|
||||||
|
itr!=_glyphs.end();
|
||||||
|
++itr)
|
||||||
|
{
|
||||||
|
(*itr)->subload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // just subload the new entries.
|
||||||
|
{
|
||||||
|
// default way of subloading as required.
|
||||||
|
//std::cout<<"subloading"<<std::endl;
|
||||||
|
for(GlyphPtrList::iterator itr=glyphsWereSubloading.begin();
|
||||||
|
itr!=glyphsWereSubloading.end();
|
||||||
|
++itr)
|
||||||
|
{
|
||||||
|
(*itr)->subload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear the list since we have now subloaded them.
|
||||||
|
glyphsWereSubloading.clear();
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OSG_INFO<<"osgText::Font loading all glyphs as a single subload."<<std::endl;
|
||||||
|
|
||||||
|
// Octane has bugs in OGL driver which mean that subloads smaller
|
||||||
|
// than 32x32 produce errors, and also cannot handle general alignment,
|
||||||
|
// so to get round this copy all glyphs into a temporary image and
|
||||||
|
// then subload the whole lot in one go.
|
||||||
|
|
||||||
|
int tsize = getTextureHeight() * getTextureWidth();
|
||||||
|
unsigned char *local_data = new unsigned char[tsize];
|
||||||
|
memset( local_data, 0L, tsize);
|
||||||
|
|
||||||
|
for(GlyphRefList::const_iterator itr=_glyphs.begin();
|
||||||
|
itr!=_glyphs.end();
|
||||||
|
++itr)
|
||||||
|
{
|
||||||
|
//(*itr)->subload();
|
||||||
|
|
||||||
|
// Rather than subloading to graphics, we'll write the values
|
||||||
|
// of the glyphs into some intermediate data and subload the
|
||||||
|
// whole thing at the end
|
||||||
|
for( int t = 0; t < (*itr)->t(); t++ )
|
||||||
|
{
|
||||||
|
for( int s = 0; s < (*itr)->s(); s++ )
|
||||||
|
{
|
||||||
|
int sindex = (t*(*itr)->s()+s);
|
||||||
|
int dindex =
|
||||||
|
((((*itr)->getTexturePositionY()+t) * getTextureWidth()) +
|
||||||
|
((*itr)->getTexturePositionX()+s));
|
||||||
|
|
||||||
|
const unsigned char *sptr = &(*itr)->data()[sindex];
|
||||||
|
unsigned char *dptr = &local_data[dindex];
|
||||||
|
|
||||||
|
(*dptr) = (*sptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear the list since we have now subloaded them.
|
||||||
|
glyphsWereSubloading.clear();
|
||||||
|
|
||||||
|
// Subload the image once
|
||||||
|
glTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0,
|
||||||
|
getTextureWidth(),
|
||||||
|
getTextureHeight(),
|
||||||
|
GL_ALPHA, GL_UNSIGNED_BYTE, local_data );
|
||||||
|
|
||||||
|
delete [] local_data;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// OSG_INFO << "no need to subload "<<std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// if (generateMipMapTurnedOn)
|
||||||
|
// {
|
||||||
|
// glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS,GL_FALSE);
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlyphTexture::setThreadSafeRefUnref(bool threadSafe)
|
||||||
|
{
|
||||||
|
osg::Texture2D::setThreadSafeRefUnref(threadSafe);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlyphTexture::resizeGLObjectBuffers(unsigned int maxSize)
|
||||||
|
{
|
||||||
|
osg::Texture2D::resizeGLObjectBuffers(maxSize);
|
||||||
|
_glyphsToSubload.resize(maxSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// all the methods in Font::Glyph have been made non inline because VisualStudio6.0 is STUPID, STUPID, STUPID PILE OF JUNK.
|
||||||
|
Glyph::Glyph(Font* font, unsigned int glyphCode):
|
||||||
|
_font(font),
|
||||||
|
_glyphCode(glyphCode),
|
||||||
|
_horizontalBearing(0.0f,0.f),
|
||||||
|
_horizontalAdvance(0.f),
|
||||||
|
_verticalBearing(0.0f,0.f),
|
||||||
|
_verticalAdvance(0.f),
|
||||||
|
_texture(0),
|
||||||
|
_texturePosX(0),
|
||||||
|
_texturePosY(0),
|
||||||
|
_minTexCoord(0.0f,0.0f),
|
||||||
|
_maxTexCoord(0.0f,0.0f)
|
||||||
|
{
|
||||||
|
setThreadSafeRefUnref(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Glyph::~Glyph()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Glyph::setHorizontalBearing(const osg::Vec2& bearing) { _horizontalBearing=bearing; }
|
||||||
|
const osg::Vec2& Glyph::getHorizontalBearing() const { return _horizontalBearing; }
|
||||||
|
|
||||||
|
void Glyph::setHorizontalAdvance(float advance) { _horizontalAdvance=advance; }
|
||||||
|
float Glyph::getHorizontalAdvance() const { return _horizontalAdvance; }
|
||||||
|
|
||||||
|
void Glyph::setVerticalBearing(const osg::Vec2& bearing) { _verticalBearing=bearing; }
|
||||||
|
const osg::Vec2& Glyph::getVerticalBearing() const { return _verticalBearing; }
|
||||||
|
|
||||||
|
void Glyph::setVerticalAdvance(float advance) { _verticalAdvance=advance; }
|
||||||
|
float Glyph::getVerticalAdvance() const { return _verticalAdvance; }
|
||||||
|
|
||||||
|
void Glyph::setTexture(GlyphTexture* texture) { _texture = texture; }
|
||||||
|
GlyphTexture* Glyph::getTexture() { return _texture; }
|
||||||
|
const GlyphTexture* Glyph::getTexture() const { return _texture; }
|
||||||
|
|
||||||
|
void Glyph::setTexturePosition(int posX,int posY) { _texturePosX = posX; _texturePosY = posY; }
|
||||||
|
int Glyph::getTexturePositionX() const { return _texturePosX; }
|
||||||
|
int Glyph::getTexturePositionY() const { return _texturePosY; }
|
||||||
|
|
||||||
|
void Glyph::setMinTexCoord(const osg::Vec2& coord) { _minTexCoord=coord; }
|
||||||
|
const osg::Vec2& Glyph::getMinTexCoord() const { return _minTexCoord; }
|
||||||
|
|
||||||
|
void Glyph::setMaxTexCoord(const osg::Vec2& coord) { _maxTexCoord=coord; }
|
||||||
|
const osg::Vec2& Glyph::getMaxTexCoord() const { return _maxTexCoord; }
|
||||||
|
|
||||||
|
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 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 Glyph::subload(): detected OpenGL error number: "<<errorNo<<std::endl;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if(s() <= 0 || t() <= 0)
|
||||||
|
{
|
||||||
|
OSG_INFO<<"Glyph::subload(): texture sub-image width and/or height of 0, ignoring operation."<<std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
glPixelStorei(GL_UNPACK_ALIGNMENT,getPacking());
|
||||||
|
|
||||||
|
glTexSubImage2D(GL_TEXTURE_2D,0,
|
||||||
|
_texturePosX,_texturePosY,
|
||||||
|
s(),t(),
|
||||||
|
(GLenum)getPixelFormat(),
|
||||||
|
(GLenum)getDataType(),
|
||||||
|
data());
|
||||||
|
|
||||||
|
errorNo = glGetError();
|
||||||
|
if (errorNo!=GL_NO_ERROR)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef OSG_GLU_AVAILABLE
|
||||||
|
const GLubyte* msg = gluErrorString(errorNo);
|
||||||
|
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 Glyph::subload() : detected OpenGL error number: "<<errorNo<<std::endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
OSG_WARN<< "\tglTexSubImage2D(0x"<<hex<<GL_TEXTURE_2D<<dec<<" ,"<<0<<"\t"<<std::endl<<
|
||||||
|
"\t "<<_texturePosX<<" ,"<<_texturePosY<<std::endl<<
|
||||||
|
"\t "<<s()<<" ,"<<t()<<std::endl<<hex<<
|
||||||
|
"\t 0x"<<(GLenum)getPixelFormat()<<std::endl<<
|
||||||
|
"\t 0x"<<(GLenum)getDataType()<<std::endl<<
|
||||||
|
"\t 0x"<<(unsigned long)data()<<");"<<dec<<std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Glyph3D::Glyph3D(Font* font, unsigned int glyphCode):
|
||||||
|
osg::Referenced(true),
|
||||||
|
_font(font),
|
||||||
|
_glyphCode(glyphCode),
|
||||||
|
_horizontalBearing(0,0),
|
||||||
|
_horizontalAdvance(0),
|
||||||
|
_verticalBearing(0,0),
|
||||||
|
_verticalAdvance(0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void Glyph3D::setThreadSafeRefUnref(bool threadSafe)
|
||||||
|
{
|
||||||
|
if (_vertexArray.valid()) _vertexArray->setThreadSafeRefUnref(threadSafe);
|
||||||
|
if (_normalArray.valid()) _normalArray->setThreadSafeRefUnref(threadSafe);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Glyph3D::computeText3DGeometryData()
|
||||||
|
{
|
||||||
|
OSG_NOTICE<<"Glyph3D::computeText3DGeometryData()"<<std::endl;
|
||||||
|
|
||||||
|
float creaseAngle = 30.0f;
|
||||||
|
float width = _font->getFontDepth();
|
||||||
|
bool smooth = true;
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::Geometry> textGeometry = osgText::computeTextGeometry(this, width);
|
||||||
|
if (!textGeometry) return;
|
||||||
|
|
||||||
|
// create the normals
|
||||||
|
if (smooth && textGeometry.valid())
|
||||||
|
{
|
||||||
|
osgUtil::SmoothingVisitor::smooth(*textGeometry);
|
||||||
|
}
|
||||||
|
|
||||||
|
_vertexArray = dynamic_cast<osg::Vec3Array*>(textGeometry->getVertexArray());
|
||||||
|
_normalArray = dynamic_cast<osg::Vec3Array*>(textGeometry->getNormalArray());
|
||||||
|
|
||||||
|
for(osg::Geometry::PrimitiveSetList::iterator itr = textGeometry->getPrimitiveSetList().begin();
|
||||||
|
itr != textGeometry->getPrimitiveSetList().end();
|
||||||
|
++itr)
|
||||||
|
{
|
||||||
|
osg::PrimitiveSet* prim = itr->get();
|
||||||
|
if (prim->getName()=="front") _frontPrimitiveSetList.push_back(prim);
|
||||||
|
else if (prim->getName()=="back") _backPrimitiveSetList.push_back(prim);
|
||||||
|
else if (prim->getName()=="wall") _wallPrimitiveSetList.push_back(prim);
|
||||||
|
}
|
||||||
|
|
||||||
|
OSG_NOTICE<<" _frontPrimitiveSetList.size()=="<<_frontPrimitiveSetList.size()<<std::endl;
|
||||||
|
OSG_NOTICE<<" _backPrimitiveSetList.size()=="<<_backPrimitiveSetList.size()<<std::endl;
|
||||||
|
OSG_NOTICE<<" _wallPrimitiveSetList.size()=="<<_wallPrimitiveSetList.size()<<std::endl;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user