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

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

Added setting of the charcode during construction of osgText::Font::Glyph()

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