root/OpenSceneGraph/trunk/src/osgText/Font.cpp @ 11172

Revision 11172, 29.1 kB (checked in by robert, 4 years ago)

From Mathias Froehlich, "If you want to have that qfont plugin loader, this is the updated
implementation which uses osgQt and includes the changes to make fonts load
without a file on disk."

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under 
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13
14#include <osgText/Font>
15#include <osgText/Text>
16
17#include <osg/State>
18#include <osg/Notify>
19#include <osg/ApplicationUsage>
20
21#include <osgDB/ReadFile>
22#include <osgDB/FileUtils>
23#include <osgDB/FileNameUtils>
24#include <osg/GLU>
25
26#include <string.h>
27
28#include <OpenThreads/ReentrantMutex>
29
30using namespace osgText;
31using namespace std;
32
33static osg::ApplicationUsageProxy Font_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_TEXT_INCREMENTAL_SUBLOADING <type>","ON | OFF");
34
35static OpenThreads::ReentrantMutex s_FontFileMutex;
36
37std::string osgText::findFontFile(const std::string& str)
38{
39    // try looking in OSGFILEPATH etc first for fonts.
40    std::string filename = osgDB::findDataFile(str);
41    if (!filename.empty()) return filename;
42
43    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(s_FontFileMutex);
44
45    static osgDB::FilePathList s_FontFilePath;
46    static bool initialized = false;
47    if (!initialized)
48    {
49        initialized = true;
50    #if defined(WIN32)
51        osgDB::convertStringPathIntoFilePathList(
52            ".;C:/winnt/fonts;C:/windows/fonts",
53            s_FontFilePath);
54
55        char *ptr;
56        if ((ptr = getenv( "windir" )))
57        {
58            std::string winFontPath = ptr;
59            winFontPath += "\\fonts";
60            s_FontFilePath.push_back(winFontPath);
61        }
62    #else
63        osgDB::convertStringPathIntoFilePathList(
64            ".:/usr/share/fonts/ttf:/usr/share/fonts/ttf/western:/usr/share/fonts/ttf/decoratives",
65            s_FontFilePath);
66    #endif
67    }
68
69    filename = osgDB::findFileInPath(str,s_FontFilePath);
70    if (!filename.empty()) return filename;
71
72    // Try filename without pathname, if it has a path
73    filename = osgDB::getSimpleFileName(str);
74    if(filename!=str)
75    {
76        filename = osgDB::findFileInPath(filename,s_FontFilePath);
77        if (!filename.empty()) return filename;
78    }
79    else
80    {
81        filename = osgText::findFontFile(std::string("fonts/")+filename);
82        if (!filename.empty()) return filename;
83    }
84
85    // Not found, return empty string
86    osg::notify(osg::INFO)<<"Warning: font file \""<<str<<"\" not found."<<std::endl;   
87    return std::string();
88}
89
90osgText::Font* osgText::readFontFile(const std::string& filename, const osgDB::ReaderWriter::Options* userOptions)
91{
92    if (filename.empty()) return 0;
93
94    std::string foundFile = findFontFile(filename);
95    if (foundFile.empty())
96        foundFile = filename;
97   
98    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_FontFileMutex);
99
100    osg::ref_ptr<osgDB::ReaderWriter::Options> localOptions;
101    if (!userOptions)
102    {
103        localOptions = new osgDB::ReaderWriter::Options;
104        localOptions->setObjectCacheHint(osgDB::ReaderWriter::Options::CACHE_OBJECTS);
105    }
106
107    osg::Object* object = osgDB::readObjectFile(foundFile, userOptions ? userOptions : localOptions.get());
108
109    // if the object is a font then return it.
110    osgText::Font* font = dynamic_cast<osgText::Font*>(object);
111    if (font) return font;
112
113    // otherwise if the object has zero references then delete it by doing another unref().
114    if (object && object->referenceCount()==0) object->unref();
115    return 0;
116}
117
118osgText::Font* osgText::readFontStream(std::istream& stream, const osgDB::ReaderWriter::Options* userOptions)
119{
120    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_FontFileMutex);
121
122    osg::ref_ptr<osgDB::ReaderWriter::Options> localOptions;
123    if (!userOptions)
124    {
125        localOptions = new osgDB::ReaderWriter::Options;
126        localOptions->setObjectCacheHint(osgDB::ReaderWriter::Options::CACHE_OBJECTS);
127    }
128
129    // there should be a better way to get the FreeType ReaderWriter by name...
130    osgDB::ReaderWriter *reader = osgDB::Registry::instance()->getReaderWriterForExtension("ttf");
131    if (reader == 0) return 0;
132    osgDB::ReaderWriter::ReadResult rr = reader->readObject(stream, userOptions ? userOptions : localOptions.get());
133    if (rr.error())
134    {
135        osg::notify(osg::WARN) << rr.message() << std::endl;
136        return 0;
137    }
138    if (!rr.validObject()) return 0;
139   
140    osg::Object *object = rr.takeObject();
141
142    // if the object is a font then return it.
143    osgText::Font* font = dynamic_cast<osgText::Font*>(object);
144    if (font) return font;
145
146    // otherwise if the object has zero references then delete it by doing another unref().
147    if (object && object->referenceCount()==0) object->unref();
148    return 0;
149}
150
151osg::ref_ptr<Font> osgText::readRefFontFile(const std::string& filename, const osgDB::ReaderWriter::Options* userOptions)
152{
153    if (filename.empty()) return 0;
154
155    std::string foundFile = findFontFile(filename);
156    if (foundFile.empty())
157        foundFile = filename;
158   
159    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_FontFileMutex);
160
161    osg::ref_ptr<osgDB::ReaderWriter::Options> localOptions;
162    if (!userOptions)
163    {
164        localOptions = new osgDB::ReaderWriter::Options;
165        localOptions->setObjectCacheHint(osgDB::ReaderWriter::Options::CACHE_OBJECTS);
166    }
167
168    osg::ref_ptr<osg::Object> object = osgDB::readRefObjectFile(foundFile, userOptions ? userOptions : localOptions.get());
169
170    // if the object is a font then return it.
171    osgText::Font* font = dynamic_cast<osgText::Font*>(object.get());
172    if (font) return osg::ref_ptr<Font>(font);
173
174    return 0;
175}
176
177osg::ref_ptr<Font> osgText::readRefFontStream(std::istream& stream, const osgDB::ReaderWriter::Options* userOptions)
178{
179    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_FontFileMutex);
180
181    osg::ref_ptr<osgDB::ReaderWriter::Options> localOptions;
182    if (!userOptions)
183    {
184        localOptions = new osgDB::ReaderWriter::Options;
185        localOptions->setObjectCacheHint(osgDB::ReaderWriter::Options::CACHE_OBJECTS);
186    }
187
188    // there should be a better way to get the FreeType ReaderWriter by name...
189    osgDB::ReaderWriter *reader = osgDB::Registry::instance()->getReaderWriterForExtension("ttf");
190    if (reader == 0) return 0;
191    osgDB::ReaderWriter::ReadResult rr = reader->readObject(stream, userOptions ? userOptions : localOptions.get());
192    if (rr.error())
193    {
194        osg::notify(osg::WARN) << rr.message() << std::endl;
195        return 0;
196    }
197    if (!rr.validObject()) return 0;
198   
199    // if the object is a font then return it.
200    osgText::Font* font = dynamic_cast<osgText::Font*>(rr.getObject());
201    if (font) return osg::ref_ptr<Font>(font);
202
203    return 0;
204}
205
206Font::Font(FontImplementation* implementation):
207    osg::Object(true),
208    _margin(1),
209    _marginRatio(0.02),
210    _textureWidthHint(1024),
211    _textureHeightHint(1024),
212    _minFilterHint(osg::Texture::LINEAR_MIPMAP_LINEAR),
213    _magFilterHint(osg::Texture::LINEAR)
214{
215    setImplementation(implementation);
216
217    _texenv = new osg::TexEnv;
218    _stateset = new osg::StateSet;
219    _stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
220
221    char *ptr;
222    if( (ptr = getenv("OSG_MAX_TEXTURE_SIZE")) != 0)
223    {
224        unsigned int osg_max_size = atoi(ptr);
225
226        if (osg_max_size<_textureWidthHint) _textureWidthHint = osg_max_size;
227        if (osg_max_size<_textureHeightHint) _textureHeightHint = osg_max_size;
228    }
229
230}
231
232Font::~Font()
233{
234    if (_implementation.valid()) _implementation->_facade = 0;
235}
236
237void Font::setImplementation(FontImplementation* implementation)
238{
239    if (_implementation.valid()) _implementation->_facade = 0;
240    _implementation = implementation;
241    if (_implementation.valid()) _implementation->_facade = this;
242}
243
244Font::FontImplementation* Font::getImplementation()
245{
246    return _implementation.get();
247}
248
249const Font::FontImplementation* Font::getImplementation() const
250{
251    return _implementation.get();
252}
253
254std::string Font::getFileName() const
255{
256    if (_implementation.valid()) return _implementation->getFileName();
257    return std::string();
258}
259
260void Font::setGlyphImageMargin(unsigned int margin)
261{
262    _margin = margin;
263}
264
265unsigned int Font::getGlyphImageMargin() const
266{
267    return _margin;
268}
269
270void Font::setGlyphImageMarginRatio(float ratio)
271{
272    _marginRatio = ratio;
273}
274
275float Font::getGlyphImageMarginRatio() const
276{
277    return _marginRatio;
278}
279
280void Font::setTextureSizeHint(unsigned int width,unsigned int height)
281{
282    _textureWidthHint = width;
283    _textureHeightHint = height;
284
285    char *ptr;
286    if( (ptr = getenv("OSG_MAX_TEXTURE_SIZE")) != 0)
287    {
288        unsigned int osg_max_size = atoi(ptr);
289
290        if (osg_max_size<_textureWidthHint) _textureWidthHint = osg_max_size;
291        if (osg_max_size<_textureHeightHint) _textureHeightHint = osg_max_size;
292    }
293}
294
295unsigned int Font::getTextureWidthHint() const
296{
297    return _textureWidthHint;
298}
299
300unsigned int Font::getTextureHeightHint() const
301{
302    return _textureHeightHint;
303}   
304
305
306void Font::setMinFilterHint(osg::Texture::FilterMode mode)
307{
308    _minFilterHint = mode;
309}
310
311osg::Texture::FilterMode Font::getMinFilterHint() const
312{
313    return _minFilterHint;
314}
315
316/** Set the magnification texture filter to use when creating the texture to store the glyph images when rendering.
317  * Note, this doesn't affect already created Texture Glhph's.*/
318void Font::setMagFilterHint(osg::Texture::FilterMode mode)
319{
320    _magFilterHint = mode;
321}
322
323osg::Texture::FilterMode Font::getMagFilterHint() const
324{
325    return _magFilterHint;
326}
327
328
329Font::Glyph* Font::getGlyph(const FontResolution& fontRes, unsigned int charcode)
330{
331    {
332        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_glyphMapMutex);
333        FontSizeGlyphMap::iterator itr = _sizeGlyphMap.find(fontRes);
334        if (itr!=_sizeGlyphMap.end())
335        {
336            GlyphMap& glyphmap = itr->second;   
337            GlyphMap::iterator gitr = glyphmap.find(charcode);
338            if (gitr!=glyphmap.end()) return gitr->second.get();
339        }
340    }
341   
342    if (_implementation.valid()) return _implementation->getGlyph(fontRes, charcode);
343    else return 0;
344}
345
346void Font::setThreadSafeRefUnref(bool threadSafe)
347{
348   osg::Object::setThreadSafeRefUnref(threadSafe);
349   
350    if (_texenv.valid()) _texenv->setThreadSafeRefUnref(threadSafe);
351    if (_stateset.valid()) _stateset->setThreadSafeRefUnref(threadSafe);
352
353    for(GlyphTextureList::const_iterator itr=_glyphTextureList.begin();
354        itr!=_glyphTextureList.end();
355        ++itr)
356    {
357        (*itr)->setThreadSafeRefUnref(threadSafe);
358    }   
359}
360
361void Font::resizeGLObjectBuffers(unsigned int maxSize)
362{
363    if (_stateset.valid()) _stateset->resizeGLObjectBuffers(maxSize);
364
365    for(GlyphTextureList::const_iterator itr=_glyphTextureList.begin();
366        itr!=_glyphTextureList.end();
367        ++itr)
368    {
369        (*itr)->resizeGLObjectBuffers(maxSize);
370    }   
371}
372
373void Font::releaseGLObjects(osg::State* state) const
374{
375    if (_stateset.valid()) _stateset->releaseGLObjects(state);
376
377    for(GlyphTextureList::const_iterator itr=_glyphTextureList.begin();
378        itr!=_glyphTextureList.end();
379        ++itr)
380    {
381        (*itr)->releaseGLObjects(state);
382    }
383   
384    // const_cast<Font*>(this)->_glyphTextureList.clear();
385    // const_cast<Font*>(this)->_sizeGlyphMap.clear();
386}
387
388osg::Vec2 Font::getKerning(const FontResolution& fontRes, unsigned int leftcharcode,unsigned int rightcharcode, KerningType kerningType)
389{
390    if (_implementation.valid()) return _implementation->getKerning(fontRes, leftcharcode,rightcharcode,kerningType);
391    else return osg::Vec2(0.0f,0.0f);
392}
393
394bool Font::hasVertical() const
395{
396    if (_implementation.valid()) return _implementation->hasVertical();
397    else return false;
398}
399
400
401
402void Font::addGlyph(const FontResolution& fontRes, unsigned int charcode, Glyph* glyph)
403{
404    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_glyphMapMutex);
405
406    _sizeGlyphMap[fontRes][charcode]=glyph;
407   
408    int posX=0,posY=0;
409   
410    GlyphTexture* glyphTexture = 0;
411    for(GlyphTextureList::iterator itr=_glyphTextureList.begin();
412        itr!=_glyphTextureList.end() && !glyphTexture;
413        ++itr)
414    {
415        if ((*itr)->getSpaceForGlyph(glyph,posX,posY)) glyphTexture = itr->get();
416    }
417   
418    if (glyphTexture)
419    {
420        //cout << "    found space for texture "<<glyphTexture<<" posX="<<posX<<" posY="<<posY<<endl;
421    }
422   
423    if (!glyphTexture)
424    {
425       
426        glyphTexture = new GlyphTexture;
427       
428        static int numberOfTexturesAllocated = 0;
429        ++numberOfTexturesAllocated;
430
431        osg::notify(osg::INFO)<< "   Font " << this<< ", numberOfTexturesAllocated "<<numberOfTexturesAllocated<<std::endl;
432
433        // reserve enough space for the glyphs.
434        glyphTexture->setGlyphImageMargin(_margin);
435        glyphTexture->setGlyphImageMarginRatio(_marginRatio);
436        glyphTexture->setTextureSize(_textureWidthHint,_textureHeightHint);
437        glyphTexture->setFilter(osg::Texture::MIN_FILTER,_minFilterHint);
438        glyphTexture->setFilter(osg::Texture::MAG_FILTER,_magFilterHint);
439        glyphTexture->setMaxAnisotropy(8);
440       
441        _glyphTextureList.push_back(glyphTexture);
442       
443        if (!glyphTexture->getSpaceForGlyph(glyph,posX,posY))
444        {
445            osg::notify(osg::WARN)<<"Warning: unable to allocate texture big enough for glyph"<<std::endl;
446            return;
447        }
448
449    }   
450   
451    // add the glyph into the texture.
452    glyphTexture->addGlyph(glyph,posX,posY);
453   
454}
455
456
457Font::GlyphTexture::GlyphTexture():
458    _margin(1),
459    _marginRatio(0.02f),
460    _usedY(0),
461    _partUsedX(0),
462    _partUsedY(0)
463{
464}
465
466Font::GlyphTexture::~GlyphTexture()
467{
468}
469
470// return -1 if *this < *rhs, 0 if *this==*rhs, 1 if *this>*rhs.
471int Font::GlyphTexture::compare(const osg::StateAttribute& rhs) const
472{
473    if (this<&rhs) return -1;
474    else if (this>&rhs) return 1;
475    return 0;
476}
477
478
479bool Font::GlyphTexture::getSpaceForGlyph(Glyph* glyph, int& posX, int& posY)
480{
481    int maxAxis = std::max(glyph->s(), glyph->t());
482    int margin = _margin + (int)((float)maxAxis * _marginRatio);
483   
484    int width = glyph->s()+2*margin;
485    int height = glyph->t()+2*margin;
486
487    // first check box (_partUsedX,_usedY) to (width,height)
488    if (width <= (getTextureWidth()-_partUsedX) &&
489        height <= (getTextureHeight()-_usedY))
490    {
491        // can fit in existing row.
492
493        // record the position in which the texture will be stored.
494        posX = _partUsedX+margin;
495        posY = _usedY+margin;       
496
497        // move used markers on.
498        _partUsedX += width;
499        if (_usedY+height>_partUsedY) _partUsedY = _usedY+height;
500       
501        return true;
502    }
503   
504    // start an new row.
505    if (width <= getTextureWidth() &&
506        height <= (getTextureHeight()-_partUsedY))
507    {
508        // can fit next row.
509        _partUsedX = 0;
510        _usedY = _partUsedY;
511
512        posX = _partUsedX+margin;
513        posY = _usedY+margin;       
514
515        // move used markers on.
516        _partUsedX += width;
517        if (_usedY+height>_partUsedY) _partUsedY = _usedY+height;
518       
519        return true;
520    }
521
522    // doesn't fit into glyph.
523    return false;
524}
525
526void Font::GlyphTexture::addGlyph(Glyph* glyph, int posX, int posY)
527{
528    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
529
530    _glyphs.push_back(glyph);
531    for(unsigned int i=0;i<_glyphsToSubload.size();++i)
532    {
533        _glyphsToSubload[i].push_back(glyph);
534    }
535
536    // set up the details of where to place glyph's image in the texture.
537    glyph->setTexture(this);
538    glyph->setTexturePosition(posX,posY);
539    unsigned int sizeAdjustment = 1;
540    glyph->setMinTexCoord(osg::Vec2((float)(posX)/(float)(getTextureWidth()-sizeAdjustment),(float)(posY)/(float)(getTextureHeight()-sizeAdjustment)));
541    glyph->setMaxTexCoord(osg::Vec2((float)(posX+glyph->s())/(float)(getTextureWidth()-sizeAdjustment),(float)(posY+glyph->t())/(float)(getTextureHeight()-sizeAdjustment)));
542}
543
544void Font::GlyphTexture::apply(osg::State& state) const
545{
546    // get the contextID (user defined ID of 0 upwards) for the
547    // current OpenGL context.
548    const unsigned int contextID = state.getContextID();
549
550    if (contextID>=_glyphsToSubload.size())
551    {
552        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
553
554        // graphics context is beyond the number of glyphsToSubloads, so
555        // we must now copy the glyph list across, this is a potential
556        // threading issue though is multiple applies are happening the
557        // same time on this object - to avoid this condition number of
558        // graphics contexts should be set before create text.
559        for(unsigned int i=_glyphsToSubload.size();i<=contextID;++i)
560        {
561            GlyphPtrList& glyphPtrs = _glyphsToSubload[i];
562            for(GlyphRefList::const_iterator itr=_glyphs.begin();
563                itr!=_glyphs.end();
564                ++itr)
565            {
566                glyphPtrs.push_back(itr->get());
567            }
568        }
569    }
570
571
572    const Extensions* extensions = getExtensions(contextID,true);
573    bool generateMipMapSupported = extensions->isGenerateMipMapSupported();
574
575    // get the texture object for the current contextID.
576    TextureObject* textureObject = getTextureObject(contextID);
577   
578    bool newTextureObject = (textureObject == 0);
579
580    if (newTextureObject)
581    {
582        GLint maxTextureSize = 256;
583        glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
584        if (maxTextureSize < getTextureWidth() || maxTextureSize < getTextureHeight())
585        {
586            osg::notify(osg::WARN)<<"Warning: osgText::Font texture size of ("<<getTextureWidth()<<", "<<getTextureHeight()<<") too large, unable to create font texture."<<std::endl;
587            osg::notify(osg::WARN)<<"         Maximum supported by hardward by native OpenGL implementation is ("<<maxTextureSize<<","<<maxTextureSize<<")."<<std::endl;
588            osg::notify(osg::WARN)<<"         Please set OSG_MAX_TEXTURE_SIZE lenvironment variable to "<<maxTextureSize<<" and re-run application."<<std::endl;
589            return;
590        }
591       
592        // being bound for the first time, need to allocate the texture
593
594        _textureObjectBuffer[contextID] = textureObject = osg::Texture::generateTextureObject(
595                this, contextID,GL_TEXTURE_2D,1,GL_ALPHA,getTextureWidth(), getTextureHeight(),1,0);
596
597        textureObject->bind();
598
599
600        applyTexParameters(GL_TEXTURE_2D,state);
601
602       
603        // need to look at generate mip map extension if mip mapping required.
604        switch(_min_filter)
605        {
606        case NEAREST_MIPMAP_NEAREST:
607        case NEAREST_MIPMAP_LINEAR:
608        case LINEAR_MIPMAP_NEAREST:
609        case LINEAR_MIPMAP_LINEAR:
610            if (generateMipMapSupported)
611            {
612                glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS,GL_TRUE);
613            }
614            else glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, LINEAR);
615            break;
616        default:
617            // not mip mapping so no problems.
618            break;
619        }
620       
621        unsigned int imageDataSize = getTextureHeight()*getTextureWidth();
622        unsigned char* imageData = new unsigned char[imageDataSize];
623        for(unsigned int i=0; i<imageDataSize; ++i)
624        {
625            imageData[i] = 0;
626        }
627       
628
629//        osg::notify(osg::NOTICE)<<"Texture width = "<<getTextureWidth()<<std::endl;
630//        osg::notify(osg::NOTICE)<<"Texture height = "<<getTextureHeight()<<std::endl;
631               
632        // allocate the texture memory.
633        glTexImage2D( GL_TEXTURE_2D, 0, GL_ALPHA,
634                getTextureWidth(), getTextureHeight(), 0,
635                GL_ALPHA,
636                GL_UNSIGNED_BYTE,
637                imageData );
638               
639        delete [] imageData;
640   
641    }
642    else
643    {
644        // reuse texture by binding.
645        textureObject->bind();
646       
647        if (getTextureParameterDirty(contextID))
648        {
649            applyTexParameters(GL_TEXTURE_2D,state);
650        }
651
652
653    }
654   
655    static const GLubyte* s_renderer = 0;
656    static bool s_subloadAllGlyphsTogether = false;
657    if (!s_renderer)
658    {
659        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
660
661        s_renderer = glGetString(GL_RENDERER);
662        osg::notify(osg::INFO)<<"glGetString(GL_RENDERER)=="<<s_renderer<<std::endl;
663        if (s_renderer && strstr((const char*)s_renderer,"IMPACT")!=0)
664        {
665            // we're running on an Octane, so need to work around its
666            // subloading bugs by loading all at once.
667            s_subloadAllGlyphsTogether = true;
668        }
669       
670        if (s_renderer &&
671            ((strstr((const char*)s_renderer,"Radeon")!=0) ||
672            (strstr((const char*)s_renderer,"RADEON")!=0) ||
673            (strstr((const char*)s_renderer,"ALL-IN-WONDER")!=0)))
674        {
675            // we're running on an ATI, so need to work around its
676            // subloading bugs by loading all at once.
677            s_subloadAllGlyphsTogether = true;
678        }
679
680        if (s_renderer && strstr((const char*)s_renderer,"Sun")!=0)
681        {
682            // we're running on an solaris x server, so need to work around its
683            // subloading bugs by loading all at once.
684            s_subloadAllGlyphsTogether = true;
685        }
686
687        const char* str = getenv("OSG_TEXT_INCREMENTAL_SUBLOADING");
688        if (str)
689        {
690            s_subloadAllGlyphsTogether = strcmp(str,"OFF")==0 || strcmp(str,"Off")==0 || strcmp(str,"off")==0;
691        }
692    }
693
694
695    // now subload the glyphs that are outstanding for this graphics context.
696    GlyphPtrList& glyphsWereSubloading = _glyphsToSubload[contextID];
697
698    if (!glyphsWereSubloading.empty() || newTextureObject)
699    {
700        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
701
702        if (!s_subloadAllGlyphsTogether)
703        {
704            if (newTextureObject)
705            {
706                for(GlyphRefList::const_iterator itr=_glyphs.begin();
707                    itr!=_glyphs.end();
708                    ++itr)
709                {
710                    (*itr)->subload();
711                }
712            }
713            else // just subload the new entries.
714            {           
715                // default way of subloading as required.
716                //std::cout<<"subloading"<<std::endl;
717                for(GlyphPtrList::iterator itr=glyphsWereSubloading.begin();
718                    itr!=glyphsWereSubloading.end();
719                    ++itr)
720                {
721                    (*itr)->subload();
722                }
723            }
724           
725            // clear the list since we have now subloaded them.
726            glyphsWereSubloading.clear();
727           
728        }
729        else
730        {
731            osg::notify(osg::INFO)<<"osgText::Font loading all glyphs as a single subload."<<std::endl;
732
733            // Octane has bugs in OGL driver which mean that subloads smaller
734            // than 32x32 produce errors, and also cannot handle general alignment,
735            // so to get round this copy all glyphs into a temporary image and
736            // then subload the whole lot in one go.
737
738            int tsize = getTextureHeight() * getTextureWidth();
739            unsigned char *local_data = new unsigned char[tsize];
740            memset( local_data, 0L, tsize);
741
742            for(GlyphRefList::const_iterator itr=_glyphs.begin();
743                itr!=_glyphs.end();
744                ++itr)
745            {
746                //(*itr)->subload();
747
748                // Rather than subloading to graphics, we'll write the values
749                // of the glyphs into some intermediate data and subload the
750                // whole thing at the end
751                for( int t = 0; t < (*itr)->t(); t++ )
752                {
753                    for( int s = 0; s < (*itr)->s(); s++ )
754                    {
755                        int sindex = (t*(*itr)->s()+s);
756                        int dindex = 
757                            ((((*itr)->getTexturePositionY()+t) * getTextureWidth()) +
758                            ((*itr)->getTexturePositionX()+s));
759
760                        const unsigned char *sptr = &(*itr)->data()[sindex];
761                        unsigned char *dptr       = &local_data[dindex];
762
763                        (*dptr)   = (*sptr);
764                    }
765                }
766            }
767
768            // clear the list since we have now subloaded them.
769            glyphsWereSubloading.clear();
770
771            // Subload the image once
772            glTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0,
773                    getTextureWidth(),
774                    getTextureHeight(),
775                    GL_ALPHA, GL_UNSIGNED_BYTE, local_data );
776
777            delete [] local_data;
778
779        }
780    }
781    else
782    {
783//        osg::notify(osg::INFO) << "no need to subload "<<std::endl;
784    }
785
786
787
788//     if (generateMipMapTurnedOn)
789//     {
790//         glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS,GL_FALSE);
791//     }
792
793
794}
795
796void Font::GlyphTexture::setThreadSafeRefUnref(bool threadSafe)
797{
798    osg::Texture2D::setThreadSafeRefUnref(threadSafe);
799}
800
801void Font::GlyphTexture::resizeGLObjectBuffers(unsigned int maxSize)
802{
803    osg::Texture2D::resizeGLObjectBuffers(maxSize);
804    _glyphsToSubload.resize(maxSize);
805}
806
807
808// all the methods in Font::Glyph have been made non inline because VisualStudio6.0 is STUPID, STUPID, STUPID PILE OF JUNK.
809Font::Glyph::Glyph(unsigned int glyphCode):
810    _font(0),
811    _glyphCode(glyphCode),
812    _horizontalBearing(0.0f,0.f),
813    _horizontalAdvance(0.f),
814    _verticalBearing(0.0f,0.f),
815    _verticalAdvance(0.f),
816    _texture(0),
817    _texturePosX(0),
818    _texturePosY(0),
819    _minTexCoord(0.0f,0.0f),
820    _maxTexCoord(0.0f,0.0f)
821{
822    setThreadSafeRefUnref(true);
823}
824
825Font::Glyph::~Glyph()
826{
827}
828
829void Font::Glyph::setHorizontalBearing(const osg::Vec2& bearing) {  _horizontalBearing=bearing; }
830const osg::Vec2& Font::Glyph::getHorizontalBearing() const { return _horizontalBearing; }
831
832void Font::Glyph::setHorizontalAdvance(float advance) { _horizontalAdvance=advance; }
833float Font::Glyph::getHorizontalAdvance() const { return _horizontalAdvance; }
834
835void Font::Glyph::setVerticalBearing(const osg::Vec2& bearing) {  _verticalBearing=bearing; }
836const osg::Vec2& Font::Glyph::getVerticalBearing() const { return _verticalBearing; }
837
838void Font::Glyph::setVerticalAdvance(float advance) {  _verticalAdvance=advance; }
839float Font::Glyph::getVerticalAdvance() const { return _verticalAdvance; }
840
841void Font::Glyph::setTexture(GlyphTexture* texture) { _texture = texture; }
842Font::GlyphTexture* Font::Glyph::getTexture() { return _texture; }
843const Font::GlyphTexture* Font::Glyph::getTexture() const { return _texture; }
844
845void Font::Glyph::setTexturePosition(int posX,int posY) { _texturePosX = posX; _texturePosY = posY; }
846int Font::Glyph::getTexturePositionX() const { return _texturePosX; }
847int Font::Glyph::getTexturePositionY() const { return _texturePosY; }
848
849void Font::Glyph::setMinTexCoord(const osg::Vec2& coord) { _minTexCoord=coord; }
850const osg::Vec2& Font::Glyph::getMinTexCoord() const { return _minTexCoord; }
851
852void Font::Glyph::setMaxTexCoord(const osg::Vec2& coord) { _maxTexCoord=coord; }
853const osg::Vec2& Font::Glyph::getMaxTexCoord() const { return _maxTexCoord; }
854
855void Font::Glyph::subload() const
856{
857    GLenum errorNo = glGetError();
858    if (errorNo!=GL_NO_ERROR)
859    {
860#ifdef OSG_GLU_AVAILABLE
861        const GLubyte* msg = gluErrorString(errorNo);
862        if (msg) osg::notify(osg::WARN)<<"before Font::Glyph::subload(): detected OpenGL error: "<<msg<<std::endl;
863        else  osg::notify(osg::WARN)<<"before Font::Glyph::subload(): detected OpenGL error number: "<<errorNo<<std::endl;
864#else
865        osg::notify(osg::WARN)<<"before Font::Glyph::subload(): detected OpenGL error number: "<<errorNo<<std::endl;
866#endif
867    }
868
869    if(s() <= 0 || t() <= 0)
870    {
871        osg::notify(osg::INFO)<<"Font::Glyph::subload(): texture sub-image width and/or height of 0, ignoring operation."<<std::endl;     
872        return;
873    }
874
875    glPixelStorei(GL_UNPACK_ALIGNMENT,getPacking());
876
877    glTexSubImage2D(GL_TEXTURE_2D,0,
878                    _texturePosX,_texturePosY,
879                    s(),t(),
880                    (GLenum)getPixelFormat(),
881                    (GLenum)getDataType(),
882                    data());
883                   
884    errorNo = glGetError();
885    if (errorNo!=GL_NO_ERROR)
886    {
887
888
889#ifdef OSG_GLU_AVAILABLE
890        const GLubyte* msg = gluErrorString(errorNo);
891        if (msg) osg::notify(osg::WARN)<<"after Font::Glyph::subload() : detected OpenGL error: "<<msg<<std::endl;
892        else osg::notify(osg::WARN)<<"after Font::Glyph::subload() : detected OpenGL error number: "<<errorNo<<std::endl;
893#else
894        osg::notify(osg::WARN)<<"after Font::Glyph::subload() : detected OpenGL error number: "<<errorNo<<std::endl;
895#endif
896
897        osg::notify(osg::WARN)<< "\tglTexSubImage2D(0x"<<hex<<GL_TEXTURE_2D<<dec<<" ,"<<0<<"\t"<<std::endl<<
898                                 "\t                "<<_texturePosX<<" ,"<<_texturePosY<<std::endl<<
899                                 "\t                "<<s()<<" ,"<<t()<<std::endl<<hex<<
900                                 "\t                0x"<<(GLenum)getPixelFormat()<<std::endl<<
901                                 "\t                0x"<<(GLenum)getDataType()<<std::endl<<
902                                 "\t                0x"<<(unsigned long)data()<<");"<<dec<<std::endl;
903    }                   
904}
Note: See TracBrowser for help on using the browser.