diff --git a/include/osgText/Font b/include/osgText/Font index 369493891..e77a0e035 100644 --- a/include/osgText/Font +++ b/include/osgText/Font @@ -128,6 +128,10 @@ public: int getGlyphInterval() const; + void setGyphTextureFeatures(GlyphTexture::Features features) { _glyphTextureFeatures = features; } + GlyphTexture::Features getGlyphTextureFeatures() const { return _glyphTextureFeatures; } + + /** Set the size of texture to create to store the glyph images when rendering. * Note, this doesn't affect already created Texture Glhph's.*/ void setTextureSizeHint(unsigned int width,unsigned int height); @@ -145,6 +149,9 @@ public: void setMagFilterHint(osg::Texture::FilterMode mode); osg::Texture::FilterMode getMagFilterHint() const; + void setMaxAnisotropy(float anis) { _maxAnisotropy = anis; } + float getMaxAnisotropy() const { return _maxAnisotropy; } + unsigned int getFontDepth() const { return _depth; } void setNumberCurveSamples(unsigned int numSamples) { _numCurveSamples = numSamples; } @@ -203,11 +210,13 @@ protected: unsigned int _margin; float _marginRatio; int _glyphInterval; + GlyphTexture::Features _glyphTextureFeatures; unsigned int _textureWidthHint; unsigned int _textureHeightHint; osg::Texture::FilterMode _minFilterHint; osg::Texture::FilterMode _magFilterHint; + float _maxAnisotropy; unsigned int _depth; unsigned int _numCurveSamples; @@ -253,8 +262,6 @@ public: virtual bool getVerticalSize(float & /*ascender*/, float & /*descender*/) const { return false; } }; - - }; } diff --git a/include/osgText/Glyph b/include/osgText/Glyph index bb7d5192a..8dac38051 100644 --- a/include/osgText/Glyph +++ b/include/osgText/Glyph @@ -58,6 +58,9 @@ public: unsigned int getGlyphCode() const { return _glyphCode; } + void setFontResolution(const FontResolution& fontRes) { _fontResolution = fontRes; } + const FontResolution& getFontResolution() const { return _fontResolution; } + void setWidth(float width) { _width = width; } float getWidth() const { return _width; } @@ -90,8 +93,6 @@ public: void setMaxTexCoord(const osg::Vec2& coord); const osg::Vec2& getMaxTexCoord() const; - void subload() const; - protected: virtual ~Glyph(); @@ -99,6 +100,8 @@ protected: Font* _font; unsigned int _glyphCode; + FontResolution _fontResolution; + float _width; float _height; @@ -263,6 +266,17 @@ public: void setGlyphInterval(int interval) { _interval = interval; } int getGlyphInterval() const { return _interval; } + enum Features + { + GREYSCALE, + OUTLINE_GREYSCALE, + SIGNED_DISTANCE_FIELD, + ALL_FEATURES + }; + + void setGlyphTextureFeatures(Features features) { _glyphTextureFeatures = features; } + Features getGlyphTextureFeatures() const { return _glyphTextureFeatures; } + bool getSpaceForGlyph(Glyph* glyph, int& posX, int& posY); void addGlyph(Glyph* glyph,int posX, int posY); @@ -280,16 +294,19 @@ protected: virtual ~GlyphTexture(); + void copyGlyphImage(Glyph* glyph); + // parameter used to compute the size and position of empty space // in the texture which could accommodate new glyphs. - int _margin; - float _marginRatio; - int _interval; + int _margin; + float _marginRatio; + int _interval; + Features _glyphTextureFeatures; - int _usedY; - int _partUsedX; - int _partUsedY; + int _usedY; + int _partUsedX; + int _partUsedY; typedef std::vector< osg::ref_ptr > GlyphRefList; typedef std::vector< const Glyph* > GlyphPtrList; diff --git a/src/osgText/Font.cpp b/src/osgText/Font.cpp index 155acadff..c09285046 100644 --- a/src/osgText/Font.cpp +++ b/src/osgText/Font.cpp @@ -302,10 +302,16 @@ Font::Font(FontImplementation* implementation): _margin(1), _marginRatio(0.02), _glyphInterval(1), +#if 0 + _glyphTextureFeatures(GlyphTexture::ALL_FEATURES), +#else + _glyphTextureFeatures(GlyphTexture::GREYSCALE), +#endif _textureWidthHint(1024), _textureHeightHint(1024), _minFilterHint(osg::Texture::LINEAR_MIPMAP_LINEAR), _magFilterHint(osg::Texture::LINEAR), + _maxAnisotropy(16), _depth(1), _numCurveSamples(10) { @@ -411,6 +417,12 @@ float Font::getGlyphImageMarginRatio() const return _marginRatio; } +void Font::setGlyphInterval(int interval) +{ + _glyphInterval = interval; +} + + void Font::setTextureSizeHint(unsigned int width,unsigned int height) { _textureWidthHint = width; @@ -606,10 +618,11 @@ void Font::addGlyph(const FontResolution& fontRes, unsigned int charcode, Glyph* glyphTexture->setGlyphImageMargin(_margin); glyphTexture->setGlyphImageMarginRatio(_marginRatio); glyphTexture->setGlyphInterval(_glyphInterval); + glyphTexture->setGlyphTextureFeatures(_glyphTextureFeatures); glyphTexture->setTextureSize(_textureWidthHint,_textureHeightHint); glyphTexture->setFilter(osg::Texture::MIN_FILTER,_minFilterHint); glyphTexture->setFilter(osg::Texture::MAG_FILTER,_magFilterHint); - glyphTexture->setMaxAnisotropy(8); + glyphTexture->setMaxAnisotropy(_maxAnisotropy); _glyphTextureList.push_back(glyphTexture); diff --git a/src/osgText/Glyph.cpp b/src/osgText/Glyph.cpp index 2699b0627..fd6d61f9c 100644 --- a/src/osgText/Glyph.cpp +++ b/src/osgText/Glyph.cpp @@ -28,6 +28,14 @@ using namespace osgText; using namespace std; +#if 0 + #define TEXTURE_IMAGE_NUM_CHANNELS 1 + #define TEXTURE_IMAGE_FORMAT OSGTEXT_GLYPH_FORMAT +#else + #define TEXTURE_IMAGE_NUM_CHANNELS 4 + #define TEXTURE_IMAGE_FORMAT GL_RGBA +#endif + GlyphTexture::GlyphTexture(): _margin(1), _marginRatio(0.02f), @@ -121,8 +129,227 @@ void GlyphTexture::addGlyph(Glyph* glyph, int posX, int posY) glyph->setMaxTexCoord( osg::Vec2( static_cast(posX+glyph->s())/static_cast(getTextureWidth()), static_cast(posY+glyph->t())/static_cast(getTextureHeight()) ) ); - _image->copySubImage(glyph->getTexturePositionX(), glyph->getTexturePositionY(), 0, glyph); - _image->dirty(); + copyGlyphImage(glyph); +} + +void GlyphTexture::copyGlyphImage(Glyph* glyph) +{ + + if (_glyphTextureFeatures==GREYSCALE) + { + // OSG_NOTICE<<"GlyphTexture::copyGlyphImage() greyscale copy"<copySubImage(glyph->getTexturePositionX(), glyph->getTexturePositionY(), 0, glyph); + _image->dirty(); + return; + } + + // OSG_NOTICE<<"GlyphTexture::copyGlyphImage() generating signed distance field."<s(); + int src_rows = glyph->t(); + unsigned char* src_data = glyph->data(); + + int dest_columns = _image->s(); + int dest_rows = _image->t(); + unsigned char* dest_data = _image->data(glyph->getTexturePositionX(),glyph->getTexturePositionY()); + + int search_distance = glyph->getFontResolution().second/8; + + int left = -search_distance; + int right = glyph->s()+search_distance; + int lower = -search_distance; + int upper = glyph->t()+search_distance; + + float multiplier = 1.0/255.0f; + float max_distance = sqrtf(float(search_distance*search_distance)*2.0f); + + int num_channels = TEXTURE_IMAGE_NUM_CHANNELS; + + if ((left+glyph->getTexturePositionX())<0) left = -glyph->getTexturePositionX(); + if ((right+glyph->getTexturePositionX())>=dest_columns) right = dest_columns-glyph->getTexturePositionX()-1; + + if ((lower+glyph->getTexturePositionY())<0) lower = -glyph->getTexturePositionY(); + if ((upper+glyph->getTexturePositionY())>=dest_rows) upper = dest_rows-glyph->getTexturePositionY()-1; + + + for(int dr=lower; dr<=upper; ++dr) + { + for(int dc=left; dc<=right; ++dc) + { + unsigned char value = 0; + + unsigned char center_value = 0; + if (dr>=0 && dr=0 && dc0 && center_value<255) + { + if (center_value_f>=0.5f) + { + min_distance = center_value_f-0.5f; + value = 128+(min_distance/max_distance)*127; + } + else + { + min_distance = 0.5f-center_value_f; + value = 127-(min_distance/max_distance)*127; + } + } + else + { + for(int radius=1; radius=0 && r=0 && cabs(dy)) ? D/float(abs(dx)) : D/float(abs(dy)); + + float local_distance = sqrtf(float(radius*radius)+float(span*span)); + if (center_value==0) local_distance += (0.5f-local_value_f)*local_multiplier; + else local_distance += (local_value_f - 0.5f)*local_multiplier; + } + } + + { + // top + int dx = radius; + int dy = span; + + int c = dc+dx; + int r = dr+dy; + + unsigned char local_value = 0; + if (r>=0 && r=0 && cabs(dy)) ? D/float(abs(dx)) : D/float(abs(dy)); + + float local_distance = sqrtf(float(radius*radius)+float(span*span)); + if (center_value==0) local_distance += (0.5f-local_value_f)*local_multiplier; + else local_distance += (local_value_f - 0.5f)*local_multiplier; + } + } + + { + // right + int dx = radius; + int dy = -span; + + int c = dc+dx; + int r = dr+dy; + + unsigned char local_value = 0; + if (r>=0 && r=0 && cabs(dy)) ? D/float(abs(dx)) : D/float(abs(dy)); + + float local_distance = sqrtf(float(radius*radius)+float(span*span)); + if (center_value==0) local_distance += (0.5f-local_value_f)*local_multiplier; + else local_distance += (local_value_f - 0.5f)*local_multiplier; + if (local_distance=0 && r=0 && cabs(dy)) ? D/float(abs(dx)) : D/float(abs(dy)); + + float local_distance = sqrtf(float(radius*radius)+float(span*span)); + if (center_value==0) local_distance += (0.5f-local_value_f)*local_multiplier; + else local_distance += (local_value_f - 0.5f)*local_multiplier; + if (local_distance=0.5) + { + value = 128+(min_distance/max_distance)*127; + } + else + { + value = 127-(min_distance/max_distance)*127; + } + } + + + unsigned char* dest_ptr = dest_data + (dr*dest_columns + dc)*num_channels; + if (num_channels==4) + { + // signed distance field value + *(dest_ptr++) = value; + + float outline_distance = max_distance/4.0f; + + // compute the alpha value of outline, one texel thick + unsigned char outline = center_value; + if (center_value<255) + { + if (min_distanceallocateImage(getTextureWidth(), getTextureHeight(), 1, OSGTEXT_GLYPH_FORMAT, GL_UNSIGNED_BYTE); + + #if defined(OSG_GL3_AVAILABLE) && !defined(OSG_GL2_AVAILABLE) && !defined(OSG_GL1_AVAILABLE) + GLenum imageFormat = (_glyphTextureFeatures==GREYSCALE) ? GL_RED : GL_RGBA; + #else + GLenum imageFormat = (_glyphTextureFeatures==GREYSCALE) ? GL_ALPHA : GL_RGBA; + #endif + + _image->allocateImage(getTextureWidth(), getTextureHeight(), 1, imageFormat, GL_UNSIGNED_BYTE); memset(_image->data(), 0, _image->getTotalSizeInBytes()); for(GlyphRefList::iterator itr = _glyphs.begin(); @@ -161,7 +397,7 @@ osg::Image* GlyphTexture::createImage() ++itr) { Glyph* glyph = itr->get(); - _image->copySubImage(glyph->getTexturePositionX(), glyph->getTexturePositionY(), 0, glyph); + copyGlyphImage(glyph); } } @@ -217,53 +453,6 @@ 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) - { - const GLubyte* msg = osg::gluErrorString(errorNo); - if (msg) { OSG_WARN<<"before Glyph::subload(): detected OpenGL error: "<(data())<<");"<getMaxTexCoord(); osg::Vec2 vDiff = maxtc - mintc; - float fHorizTCMargin = 1.0f / glyph->getTexture()->getTextureWidth(); - float fVertTCMargin = 1.0f / glyph->getTexture()->getTextureHeight(); + float texelMargin = 4.0f; + + float fHorizTCMargin = texelMargin / glyph->getTexture()->getTextureWidth(); + float fVertTCMargin = texelMargin / glyph->getTexture()->getTextureHeight(); float fHorizQuadMargin = vDiff.x() == 0.0f ? 0.0f : width * fHorizTCMargin / vDiff.x(); float fVertQuadMargin = vDiff.y() == 0.0f ? 0.0f : height * fVertTCMargin / vDiff.y();