root/OpenSceneGraph/trunk/src/osgText/Glyph.cpp @ 13041

Revision 13041, 21.3 kB (checked in by robert, 2 years ago)

Ran script to remove trailing spaces and tabs

  • Property svn:eol-style set to native
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/GLU>
20
21#include <osgUtil/SmoothingVisitor>
22
23#include <string.h>
24#include <stdlib.h>
25
26#include "GlyphGeometry.h"
27
28using namespace osgText;
29using namespace std;
30
31GlyphTexture::GlyphTexture():
32    _margin(1),
33    _marginRatio(0.02f),
34    _usedY(0),
35    _partUsedX(0),
36    _partUsedY(0)
37{
38    setWrap(WRAP_S, CLAMP_TO_EDGE);
39    setWrap(WRAP_T, CLAMP_TO_EDGE);
40}
41
42GlyphTexture::~GlyphTexture()
43{
44}
45
46// return -1 if *this < *rhs, 0 if *this==*rhs, 1 if *this>*rhs.
47int GlyphTexture::compare(const osg::StateAttribute& rhs) const
48{
49    if (this<&rhs) return -1;
50    else if (this>&rhs) return 1;
51    return 0;
52}
53
54
55bool GlyphTexture::getSpaceForGlyph(Glyph* glyph, int& posX, int& posY)
56{
57    int maxAxis = std::max(glyph->s(), glyph->t());
58    int margin = _margin + (int)((float)maxAxis * _marginRatio);
59
60    int width = glyph->s()+2*margin;
61    int height = glyph->t()+2*margin;
62
63    // first check box (_partUsedX,_usedY) to (width,height)
64    if (width <= (getTextureWidth()-_partUsedX) &&
65        height <= (getTextureHeight()-_usedY))
66    {
67        // can fit in existing row.
68
69        // record the position in which the texture will be stored.
70        posX = _partUsedX+margin;
71        posY = _usedY+margin;
72
73        // move used markers on.
74        _partUsedX += width;
75        if (_usedY+height>_partUsedY) _partUsedY = _usedY+height;
76
77        return true;
78    }
79
80    // start an new row.
81    if (width <= getTextureWidth() &&
82        height <= (getTextureHeight()-_partUsedY))
83    {
84        // can fit next row.
85        _partUsedX = 0;
86        _usedY = _partUsedY;
87
88        posX = _partUsedX+margin;
89        posY = _usedY+margin;
90
91        // move used markers on.
92        _partUsedX += width;
93        if (_usedY+height>_partUsedY) _partUsedY = _usedY+height;
94
95        return true;
96    }
97
98    // doesn't fit into glyph.
99    return false;
100}
101
102void GlyphTexture::addGlyph(Glyph* glyph, int posX, int posY)
103{
104    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
105
106    _glyphs.push_back(glyph);
107    for(unsigned int i=0;i<_glyphsToSubload.size();++i)
108    {
109        _glyphsToSubload[i].push_back(glyph);
110    }
111
112    // set up the details of where to place glyph's image in the texture.
113    glyph->setTexture(this);
114    glyph->setTexturePosition(posX,posY);
115
116    glyph->setMinTexCoord( osg::Vec2( static_cast<float>(posX)/static_cast<float>(getTextureWidth()),
117                                      static_cast<float>(posY)/static_cast<float>(getTextureHeight()) ) );
118    glyph->setMaxTexCoord( osg::Vec2( static_cast<float>(posX+glyph->s())/static_cast<float>(getTextureWidth()),
119                                      static_cast<float>(posY+glyph->t())/static_cast<float>(getTextureHeight()) ) );
120}
121
122void GlyphTexture::apply(osg::State& state) const
123{
124    // get the contextID (user defined ID of 0 upwards) for the
125    // current OpenGL context.
126    const unsigned int contextID = state.getContextID();
127
128    if (contextID>=_glyphsToSubload.size())
129    {
130        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
131
132        // graphics context is beyond the number of glyphsToSubloads, so
133        // we must now copy the glyph list across, this is a potential
134        // threading issue though is multiple applies are happening the
135        // same time on this object - to avoid this condition number of
136        // graphics contexts should be set before create text.
137        for(unsigned int i=_glyphsToSubload.size();i<=contextID;++i)
138        {
139            GlyphPtrList& glyphPtrs = _glyphsToSubload[i];
140            for(GlyphRefList::const_iterator itr=_glyphs.begin();
141                itr!=_glyphs.end();
142                ++itr)
143            {
144                glyphPtrs.push_back(itr->get());
145            }
146        }
147    }
148
149
150    const Extensions* extensions = getExtensions(contextID,true);
151    bool generateMipMapSupported = extensions->isGenerateMipMapSupported();
152
153    // get the texture object for the current contextID.
154    TextureObject* textureObject = getTextureObject(contextID);
155
156    bool newTextureObject = (textureObject == 0);
157
158    #if defined(OSG_GLES2_AVAILABLE)
159    bool requiresGenerateMipmapCall = false;
160
161    // need to look to see generate mip map call is required.
162    switch(_min_filter)
163    {
164    case NEAREST_MIPMAP_NEAREST:
165    case NEAREST_MIPMAP_LINEAR:
166    case LINEAR_MIPMAP_NEAREST:
167    case LINEAR_MIPMAP_LINEAR:
168        requiresGenerateMipmapCall = generateMipMapSupported;
169        break;
170    default:
171        break;
172    }
173    #endif
174
175    if (newTextureObject)
176    {
177        GLint maxTextureSize = 256;
178        glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
179        if (maxTextureSize < getTextureWidth() || maxTextureSize < getTextureHeight())
180        {
181            OSG_WARN<<"Warning: osgText::Font texture size of ("<<getTextureWidth()<<", "<<getTextureHeight()<<") too large, unable to create font texture."<<std::endl;
182            OSG_WARN<<"         Maximum supported by hardward by native OpenGL implementation is ("<<maxTextureSize<<","<<maxTextureSize<<")."<<std::endl;
183            OSG_WARN<<"         Please set OSG_MAX_TEXTURE_SIZE lenvironment variable to "<<maxTextureSize<<" and re-run application."<<std::endl;
184            return;
185        }
186
187        // being bound for the first time, need to allocate the texture
188
189        _textureObjectBuffer[contextID] = textureObject = osg::Texture::generateTextureObject(
190                this, contextID,GL_TEXTURE_2D,1,GL_ALPHA,getTextureWidth(), getTextureHeight(),1,0);
191
192        textureObject->bind();
193
194
195        applyTexParameters(GL_TEXTURE_2D,state);
196
197        // need to look at generate mip map extension if mip mapping required.
198        switch(_min_filter)
199        {
200        case NEAREST_MIPMAP_NEAREST:
201        case NEAREST_MIPMAP_LINEAR:
202        case LINEAR_MIPMAP_NEAREST:
203        case LINEAR_MIPMAP_LINEAR:
204            if (generateMipMapSupported)
205            {
206            #if !defined(OSG_GLES2_AVAILABLE)
207                glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS,GL_TRUE);
208            #endif
209            }
210            else glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, LINEAR);
211            break;
212        default:
213            // not mip mapping so no problems.
214            break;
215        }
216
217        unsigned int imageDataSize = getTextureHeight()*getTextureWidth();
218        unsigned char* imageData = new unsigned char[imageDataSize];
219        for(unsigned int i=0; i<imageDataSize; ++i)
220        {
221            imageData[i] = 0;
222        }
223
224
225        // allocate the texture memory.
226        glTexImage2D( GL_TEXTURE_2D, 0, GL_ALPHA,
227                getTextureWidth(), getTextureHeight(), 0,
228                GL_ALPHA,
229                GL_UNSIGNED_BYTE,
230                imageData );
231
232        delete [] imageData;
233
234    }
235    else
236    {
237        // reuse texture by binding.
238        textureObject->bind();
239
240        if (getTextureParameterDirty(contextID))
241        {
242            applyTexParameters(GL_TEXTURE_2D,state);
243        }
244
245
246    }
247
248    static const GLubyte* s_renderer = 0;
249    static bool s_subloadAllGlyphsTogether = false;
250    if (!s_renderer)
251    {
252        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
253
254        s_renderer = glGetString(GL_RENDERER);
255        OSG_INFO<<"glGetString(GL_RENDERER)=="<<s_renderer<<std::endl;
256        if (s_renderer && strstr((const char*)s_renderer,"IMPACT")!=0)
257        {
258            // we're running on an Octane, so need to work around its
259            // subloading bugs by loading all at once.
260            s_subloadAllGlyphsTogether = true;
261        }
262
263        if (s_renderer &&
264            ((strstr((const char*)s_renderer,"Radeon")!=0) ||
265            (strstr((const char*)s_renderer,"RADEON")!=0) ||
266            (strstr((const char*)s_renderer,"ALL-IN-WONDER")!=0)))
267        {
268            // we're running on an ATI, so need to work around its
269            // subloading bugs by loading all at once.
270            s_subloadAllGlyphsTogether = true;
271        }
272
273        if (s_renderer && strstr((const char*)s_renderer,"Sun")!=0)
274        {
275            // we're running on an solaris x server, so need to work around its
276            // subloading bugs by loading all at once.
277            s_subloadAllGlyphsTogether = true;
278        }
279
280        const char* str = getenv("OSG_TEXT_INCREMENTAL_SUBLOADING");
281        if (str)
282        {
283            s_subloadAllGlyphsTogether = strcmp(str,"OFF")==0 || strcmp(str,"Off")==0 || strcmp(str,"off")==0;
284        }
285    }
286
287
288    // now subload the glyphs that are outstanding for this graphics context.
289    GlyphPtrList& glyphsWereSubloading = _glyphsToSubload[contextID];
290
291    if (!glyphsWereSubloading.empty() || newTextureObject)
292    {
293        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
294
295        bool subloadAllGlyphsTogether = s_subloadAllGlyphsTogether;
296
297        #if defined(OSG_GLES2_AVAILABLE)
298        if (requiresGenerateMipmapCall) subloadAllGlyphsTogether = true;
299        #endif
300
301        if (!subloadAllGlyphsTogether)
302        {
303            if (newTextureObject)
304            {
305                for(GlyphRefList::const_iterator itr=_glyphs.begin();
306                    itr!=_glyphs.end();
307                    ++itr)
308                {
309                    (*itr)->subload();
310                }
311            }
312            else // just subload the new entries.
313            {
314                // default way of subloading as required.
315                //std::cout<<"subloading"<<std::endl;
316                for(GlyphPtrList::iterator itr=glyphsWereSubloading.begin();
317                    itr!=glyphsWereSubloading.end();
318                    ++itr)
319                {
320                    (*itr)->subload();
321                }
322            }
323
324            // clear the list since we have now subloaded them.
325            glyphsWereSubloading.clear();
326
327        }
328        else
329        {
330            OSG_INFO<<"osgText::Font loading all glyphs as a single subload."<<std::endl;
331
332            // Octane has bugs in OGL driver which mean that subloads smaller
333            // than 32x32 produce errors, and also cannot handle general alignment,
334            // so to get round this copy all glyphs into a temporary image and
335            // then subload the whole lot in one go.
336
337            int tsize = getTextureHeight() * getTextureWidth();
338            unsigned char *local_data = new unsigned char[tsize];
339            memset( local_data, 0L, tsize);
340
341            for(GlyphRefList::const_iterator itr=_glyphs.begin();
342                itr!=_glyphs.end();
343                ++itr)
344            {
345                //(*itr)->subload();
346
347                // Rather than subloading to graphics, we'll write the values
348                // of the glyphs into some intermediate data and subload the
349                // whole thing at the end
350                for( int t = 0; t < (*itr)->t(); t++ )
351                {
352                    for( int s = 0; s < (*itr)->s(); s++ )
353                    {
354                        int sindex = (t*(*itr)->s()+s);
355                        int dindex =
356                            ((((*itr)->getTexturePositionY()+t) * getTextureWidth()) +
357                            ((*itr)->getTexturePositionX()+s));
358
359                        const unsigned char *sptr = &(*itr)->data()[sindex];
360                        unsigned char *dptr       = &local_data[dindex];
361
362                        (*dptr)   = (*sptr);
363                    }
364                }
365            }
366
367            // clear the list since we have now subloaded them.
368            glyphsWereSubloading.clear();
369
370            // Subload the image once
371            glTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0,
372                    getTextureWidth(),
373                    getTextureHeight(),
374                    GL_ALPHA, GL_UNSIGNED_BYTE, local_data );
375
376            #if defined(OSG_GLES2_AVAILABLE)
377            if (requiresGenerateMipmapCall) glGenerateMipmap(GL_TEXTURE_2D);
378            #endif
379
380            delete [] local_data;
381
382        }
383    }
384    else
385    {
386//        OSG_INFO << "no need to subload "<<std::endl;
387    }
388
389
390
391//     if (generateMipMapTurnedOn)
392//     {
393//         glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS,GL_FALSE);
394//     }
395
396
397}
398
399void GlyphTexture::setThreadSafeRefUnref(bool threadSafe)
400{
401    osg::Texture2D::setThreadSafeRefUnref(threadSafe);
402}
403
404void GlyphTexture::resizeGLObjectBuffers(unsigned int maxSize)
405{
406    osg::Texture2D::resizeGLObjectBuffers(maxSize);
407
408    unsigned int initialSize = _glyphsToSubload.size();
409    _glyphsToSubload.resize(maxSize);
410
411    for(unsigned i=initialSize; i<_glyphsToSubload.size(); ++i)
412    {
413        for(GlyphRefList::iterator itr = _glyphs.begin();
414            itr != _glyphs.end();
415            ++itr)
416        {
417            _glyphsToSubload[i].push_back(itr->get());
418        }
419    }
420}
421
422osg::Image* GlyphTexture::createImage()
423{
424    osg::ref_ptr<osg::Image> image = new osg::Image;
425    image->allocateImage(getTextureWidth(), getTextureHeight(), 1, GL_ALPHA, GL_UNSIGNED_BYTE);
426    memset(image->data(), 0, image->getTotalSizeInBytes());
427
428    for(GlyphRefList::iterator itr = _glyphs.begin();
429        itr != _glyphs.end();
430        ++itr)
431    {
432        Glyph* glyph = itr->get();
433        image->copySubImage(glyph->getTexturePositionX(), glyph->getTexturePositionY(), 0, glyph);
434    }
435
436    return image.release();
437}
438
439// all the methods in Font::Glyph have been made non inline because VisualStudio6.0 is STUPID, STUPID, STUPID PILE OF JUNK.
440Glyph::Glyph(Font* font, unsigned int glyphCode):
441    _font(font),
442    _glyphCode(glyphCode),
443    _width(1.0f),
444    _height(1.0f),
445    _horizontalBearing(0.0f,0.f),
446    _horizontalAdvance(0.f),
447    _verticalBearing(0.0f,0.f),
448    _verticalAdvance(0.f),
449    _texture(0),
450    _texturePosX(0),
451    _texturePosY(0),
452    _minTexCoord(0.0f,0.0f),
453    _maxTexCoord(0.0f,0.0f)
454{
455    setThreadSafeRefUnref(true);
456}
457
458Glyph::~Glyph()
459{
460}
461
462void Glyph::setHorizontalBearing(const osg::Vec2& bearing) {  _horizontalBearing=bearing; }
463const osg::Vec2& Glyph::getHorizontalBearing() const { return _horizontalBearing; }
464
465void Glyph::setHorizontalAdvance(float advance) { _horizontalAdvance=advance; }
466float Glyph::getHorizontalAdvance() const { return _horizontalAdvance; }
467
468void Glyph::setVerticalBearing(const osg::Vec2& bearing) {  _verticalBearing=bearing; }
469const osg::Vec2& Glyph::getVerticalBearing() const { return _verticalBearing; }
470
471void Glyph::setVerticalAdvance(float advance) {  _verticalAdvance=advance; }
472float Glyph::getVerticalAdvance() const { return _verticalAdvance; }
473
474void Glyph::setTexture(GlyphTexture* texture) { _texture = texture; }
475GlyphTexture* Glyph::getTexture() { return _texture; }
476const GlyphTexture* Glyph::getTexture() const { return _texture; }
477
478void Glyph::setTexturePosition(int posX,int posY) { _texturePosX = posX; _texturePosY = posY; }
479int Glyph::getTexturePositionX() const { return _texturePosX; }
480int Glyph::getTexturePositionY() const { return _texturePosY; }
481
482void Glyph::setMinTexCoord(const osg::Vec2& coord) { _minTexCoord=coord; }
483const osg::Vec2& Glyph::getMinTexCoord() const { return _minTexCoord; }
484
485void Glyph::setMaxTexCoord(const osg::Vec2& coord) { _maxTexCoord=coord; }
486const osg::Vec2& Glyph::getMaxTexCoord() const { return _maxTexCoord; }
487
488void Glyph::subload() const
489{
490    GLenum errorNo = glGetError();
491    if (errorNo!=GL_NO_ERROR)
492    {
493        const GLubyte* msg = osg::gluErrorString(errorNo);
494        if (msg) { OSG_WARN<<"before Glyph::subload(): detected OpenGL error: "<<msg<<std::endl; }
495        else  { OSG_WARN<<"before Glyph::subload(): detected OpenGL error number: "<<errorNo<<std::endl; }
496    }
497
498    if(s() <= 0 || t() <= 0)
499    {
500        OSG_INFO<<"Glyph::subload(): texture sub-image width and/or height of 0, ignoring operation."<<std::endl;
501        return;
502    }
503
504    glPixelStorei(GL_UNPACK_ALIGNMENT,getPacking());
505
506    #if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE)
507    glPixelStorei(GL_UNPACK_ROW_LENGTH,getRowLength());
508    #endif
509
510    glTexSubImage2D(GL_TEXTURE_2D,0,
511                    _texturePosX,_texturePosY,
512                    s(),t(),
513                    (GLenum)getPixelFormat(),
514                    (GLenum)getDataType(),
515                    data());
516
517    errorNo = glGetError();
518    if (errorNo!=GL_NO_ERROR)
519    {
520
521
522        const GLubyte* msg = osg::gluErrorString(errorNo);
523        if (msg) { OSG_WARN<<"after Glyph::subload() : detected OpenGL error: "<<msg<<std::endl; }
524        else { OSG_WARN<<"after Glyph::subload() : detected OpenGL error number: "<<errorNo<<std::endl; }
525
526        OSG_WARN<< "\tglTexSubImage2D(0x"<<hex<<GL_TEXTURE_2D<<dec<<" ,"<<0<<"\t"<<std::endl<<
527                                 "\t                "<<_texturePosX<<" ,"<<_texturePosY<<std::endl<<
528                                 "\t                "<<s()<<" ,"<<t()<<std::endl<<hex<<
529                                 "\t                0x"<<(GLenum)getPixelFormat()<<std::endl<<
530                                 "\t                0x"<<(GLenum)getDataType()<<std::endl<<
531                                 "\t                0x"<<(unsigned long)data()<<");"<<dec<<std::endl;
532    }
533}
534
535Glyph3D::Glyph3D(Font* font, unsigned int glyphCode):
536    osg::Referenced(true),
537    _font(font),
538    _glyphCode(glyphCode),
539    _width(1.0f),
540    _height(1.0f),
541    _horizontalBearing(0,0),
542    _horizontalAdvance(0),
543    _verticalBearing(0,0),
544    _verticalAdvance(0)
545    {}
546
547void Glyph3D::setThreadSafeRefUnref(bool threadSafe)
548{
549    for(GlyphGeometries::iterator itr = _glyphGeometries.begin();
550        itr != _glyphGeometries.end();
551        ++itr)
552    {
553        (*itr)->setThreadSafeRefUnref(threadSafe);
554    }
555}
556
557GlyphGeometry* Glyph3D::getGlyphGeometry(const Style* style)
558{
559
560    for(GlyphGeometries::iterator itr = _glyphGeometries.begin();
561        itr != _glyphGeometries.end();
562        ++itr)
563    {
564        GlyphGeometry* glyphGeometry = itr->get();
565        if (glyphGeometry->match(style))
566        {
567            OSG_INFO<<"Glyph3D::getGlyphGeometry(Style* style) found matching GlyphGeometry."<<std::endl;
568            return glyphGeometry;
569        }
570    }
571
572    OSG_INFO<<"Glyph3D::getGlyphGeometry(Style* style) could not find matching GlyphGeometry, creating a new one."<<std::endl;
573
574    osg::ref_ptr<GlyphGeometry> glyphGeometry = new GlyphGeometry();
575    glyphGeometry->setup(this, style);
576    _glyphGeometries.push_back(glyphGeometry);
577
578    return glyphGeometry.get();
579}
580
581
582GlyphGeometry::GlyphGeometry()
583{
584}
585
586void GlyphGeometry::setThreadSafeRefUnref(bool threadSafe)
587{
588    if (_geode.valid()) _geode->setThreadSafeRefUnref(threadSafe);
589}
590
591void GlyphGeometry::setup(const Glyph3D* glyph, const Style* style)
592{
593    float creaseAngle = 30.0f;
594    bool smooth = true;
595    osg::ref_ptr<osg::Geometry> shellGeometry;
596
597    if (!style)
598    {
599        OSG_INFO<<"GlyphGeometry::setup(const Glyph* glyph, NULL) creating default glyph geometry."<<std::endl;
600
601        float width = 0.1f;
602
603        _geometry = osgText::computeTextGeometry(glyph, width);
604    }
605    else
606    {
607        OSG_INFO<<"GlyphGeometry::setup(const Glyph* glyph, NULL) create glyph geometry with custom Style."<<std::endl;
608
609        // record the style
610        _style = dynamic_cast<Style*>(style->clone(osg::CopyOp::DEEP_COPY_ALL));
611
612        const Bevel* bevel = style ? style->getBevel() : 0;
613        bool outline = style ? style->getOutlineRatio()>0.0f : false;
614        float width = style->getThicknessRatio();
615
616        if (bevel)
617        {
618            float thickness = bevel->getBevelThickness();
619
620            osg::ref_ptr<osg::Geometry> glyphGeometry = osgText::computeGlyphGeometry(glyph, thickness, width);
621
622            _geometry = osgText::computeTextGeometry(glyphGeometry.get(), *bevel, width);
623            shellGeometry = outline ? osgText::computeShellGeometry(glyphGeometry.get(), *bevel, width) : 0;
624        }
625        else
626        {
627            _geometry = osgText::computeTextGeometry(glyph, width);
628        }
629    }
630
631    if (!_geometry)
632    {
633        OSG_INFO<<"Warning: GlyphGeometry::setup(const Glyph* glyph, const Style* style) failed."<<std::endl;
634        return;
635    }
636
637    _geode = new osg::Geode;
638    _geode->addDrawable(_geometry.get());
639    if (shellGeometry.valid()) _geode->addDrawable(shellGeometry.get());
640
641    // create the normals
642    if (smooth)
643    {
644        osgUtil::SmoothingVisitor::smooth(*_geometry, osg::DegreesToRadians(creaseAngle));
645    }
646
647    _vertices = dynamic_cast<osg::Vec3Array*>(_geometry->getVertexArray());
648    _normals = dynamic_cast<osg::Vec3Array*>(_geometry->getNormalArray());
649
650    for(osg::Geometry::PrimitiveSetList::iterator itr = _geometry->getPrimitiveSetList().begin();
651        itr != _geometry->getPrimitiveSetList().end();
652        ++itr)
653    {
654        osg::PrimitiveSet* prim = itr->get();
655        if (prim->getName()=="front") _frontPrimitiveSetList.push_back(prim);
656        else if (prim->getName()=="back") _backPrimitiveSetList.push_back(prim);
657        else if (prim->getName()=="wall") _wallPrimitiveSetList.push_back(prim);
658    }
659}
660
661bool GlyphGeometry::match(const Style* style) const
662{
663    if (_style == style) return true;
664    if (!_style || !style) return false;
665
666    return (*_style==*style);
667}
Note: See TracBrowser for help on using the browser.