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

Revision 12912, 20.7 kB (checked in by robert, 2 years ago)

Added support for using GL_UNPACK_ROW_LENGTH in conjunction with texture's + osg::Image via new RowLength?
parameter in osg::Image. To support this Image::setData(..) now has a new optional rowLength parameter which
defaults to 0, which provides the original behaviour, Image::setRowLength(int) and int Image::getRowLength() are also provided.

With the introduction of RowLength? support in osg::Image it is now possible to create a sub image where
the t size of the image are smaller than the row length, useful for when you have a large image on the CPU
and which to use a small portion of it on the GPU. However, when these sub images are created the data
within the image is no longer contiguous so data access can no longer assume that all the data is in
one block. The new method Image::isDataContiguous() enables the user to check whether the data is contiguous,
and if not one can either access the data row by row using Image::data(column,row,image) accessor, or use the
new Image::DataIterator? for stepping through each block on memory assocatied with the image.

To support the possibility of non contiguous osg::Image usage of image objects has had to be updated to
check DataContiguous? and handle the case or use access via the DataIerator? or by row by row. To achieve
this a relatively large number of files has had to be modified, in particular the texture classes and
image plugins that doing writing.

  • 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 (newTextureObject)
159    {
160        GLint maxTextureSize = 256;
161        glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
162        if (maxTextureSize < getTextureWidth() || maxTextureSize < getTextureHeight())
163        {
164            OSG_WARN<<"Warning: osgText::Font texture size of ("<<getTextureWidth()<<", "<<getTextureHeight()<<") too large, unable to create font texture."<<std::endl;
165            OSG_WARN<<"         Maximum supported by hardward by native OpenGL implementation is ("<<maxTextureSize<<","<<maxTextureSize<<")."<<std::endl;
166            OSG_WARN<<"         Please set OSG_MAX_TEXTURE_SIZE lenvironment variable to "<<maxTextureSize<<" and re-run application."<<std::endl;
167            return;
168        }
169       
170        // being bound for the first time, need to allocate the texture
171
172        _textureObjectBuffer[contextID] = textureObject = osg::Texture::generateTextureObject(
173                this, contextID,GL_TEXTURE_2D,1,GL_ALPHA,getTextureWidth(), getTextureHeight(),1,0);
174
175        textureObject->bind();
176
177
178        applyTexParameters(GL_TEXTURE_2D,state);
179
180       
181        // need to look at generate mip map extension if mip mapping required.
182        switch(_min_filter)
183        {
184        case NEAREST_MIPMAP_NEAREST:
185        case NEAREST_MIPMAP_LINEAR:
186        case LINEAR_MIPMAP_NEAREST:
187        case LINEAR_MIPMAP_LINEAR:
188            if (generateMipMapSupported)
189            {
190                glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS,GL_TRUE);
191            }
192            else glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, LINEAR);
193            break;
194        default:
195            // not mip mapping so no problems.
196            break;
197        }
198       
199        unsigned int imageDataSize = getTextureHeight()*getTextureWidth();
200        unsigned char* imageData = new unsigned char[imageDataSize];
201        for(unsigned int i=0; i<imageDataSize; ++i)
202        {
203            imageData[i] = 0;
204        }
205       
206
207        // allocate the texture memory.
208        glTexImage2D( GL_TEXTURE_2D, 0, GL_ALPHA,
209                getTextureWidth(), getTextureHeight(), 0,
210                GL_ALPHA,
211                GL_UNSIGNED_BYTE,
212                imageData );
213               
214        delete [] imageData;
215   
216    }
217    else
218    {
219        // reuse texture by binding.
220        textureObject->bind();
221       
222        if (getTextureParameterDirty(contextID))
223        {
224            applyTexParameters(GL_TEXTURE_2D,state);
225        }
226
227
228    }
229   
230    static const GLubyte* s_renderer = 0;
231    static bool s_subloadAllGlyphsTogether = false;
232    if (!s_renderer)
233    {
234        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
235
236        s_renderer = glGetString(GL_RENDERER);
237        OSG_INFO<<"glGetString(GL_RENDERER)=="<<s_renderer<<std::endl;
238        if (s_renderer && strstr((const char*)s_renderer,"IMPACT")!=0)
239        {
240            // we're running on an Octane, so need to work around its
241            // subloading bugs by loading all at once.
242            s_subloadAllGlyphsTogether = true;
243        }
244       
245        if (s_renderer &&
246            ((strstr((const char*)s_renderer,"Radeon")!=0) ||
247            (strstr((const char*)s_renderer,"RADEON")!=0) ||
248            (strstr((const char*)s_renderer,"ALL-IN-WONDER")!=0)))
249        {
250            // we're running on an ATI, so need to work around its
251            // subloading bugs by loading all at once.
252            s_subloadAllGlyphsTogether = true;
253        }
254
255        if (s_renderer && strstr((const char*)s_renderer,"Sun")!=0)
256        {
257            // we're running on an solaris x server, so need to work around its
258            // subloading bugs by loading all at once.
259            s_subloadAllGlyphsTogether = true;
260        }
261
262        const char* str = getenv("OSG_TEXT_INCREMENTAL_SUBLOADING");
263        if (str)
264        {
265            s_subloadAllGlyphsTogether = strcmp(str,"OFF")==0 || strcmp(str,"Off")==0 || strcmp(str,"off")==0;
266        }
267    }
268
269
270    // now subload the glyphs that are outstanding for this graphics context.
271    GlyphPtrList& glyphsWereSubloading = _glyphsToSubload[contextID];
272
273    if (!glyphsWereSubloading.empty() || newTextureObject)
274    {
275        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
276
277        if (!s_subloadAllGlyphsTogether)
278        {
279            if (newTextureObject)
280            {
281                for(GlyphRefList::const_iterator itr=_glyphs.begin();
282                    itr!=_glyphs.end();
283                    ++itr)
284                {
285                    (*itr)->subload();
286                }
287            }
288            else // just subload the new entries.
289            {           
290                // default way of subloading as required.
291                //std::cout<<"subloading"<<std::endl;
292                for(GlyphPtrList::iterator itr=glyphsWereSubloading.begin();
293                    itr!=glyphsWereSubloading.end();
294                    ++itr)
295                {
296                    (*itr)->subload();
297                }
298            }
299           
300            // clear the list since we have now subloaded them.
301            glyphsWereSubloading.clear();
302           
303        }
304        else
305        {
306            OSG_INFO<<"osgText::Font loading all glyphs as a single subload."<<std::endl;
307
308            // Octane has bugs in OGL driver which mean that subloads smaller
309            // than 32x32 produce errors, and also cannot handle general alignment,
310            // so to get round this copy all glyphs into a temporary image and
311            // then subload the whole lot in one go.
312
313            int tsize = getTextureHeight() * getTextureWidth();
314            unsigned char *local_data = new unsigned char[tsize];
315            memset( local_data, 0L, tsize);
316
317            for(GlyphRefList::const_iterator itr=_glyphs.begin();
318                itr!=_glyphs.end();
319                ++itr)
320            {
321                //(*itr)->subload();
322
323                // Rather than subloading to graphics, we'll write the values
324                // of the glyphs into some intermediate data and subload the
325                // whole thing at the end
326                for( int t = 0; t < (*itr)->t(); t++ )
327                {
328                    for( int s = 0; s < (*itr)->s(); s++ )
329                    {
330                        int sindex = (t*(*itr)->s()+s);
331                        int dindex = 
332                            ((((*itr)->getTexturePositionY()+t) * getTextureWidth()) +
333                            ((*itr)->getTexturePositionX()+s));
334
335                        const unsigned char *sptr = &(*itr)->data()[sindex];
336                        unsigned char *dptr       = &local_data[dindex];
337
338                        (*dptr)   = (*sptr);
339                    }
340                }
341            }
342
343            // clear the list since we have now subloaded them.
344            glyphsWereSubloading.clear();
345
346            // Subload the image once
347            glTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0,
348                    getTextureWidth(),
349                    getTextureHeight(),
350                    GL_ALPHA, GL_UNSIGNED_BYTE, local_data );
351
352            delete [] local_data;
353
354        }
355    }
356    else
357    {
358//        OSG_INFO << "no need to subload "<<std::endl;
359    }
360
361
362
363//     if (generateMipMapTurnedOn)
364//     {
365//         glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS,GL_FALSE);
366//     }
367
368
369}
370
371void GlyphTexture::setThreadSafeRefUnref(bool threadSafe)
372{
373    osg::Texture2D::setThreadSafeRefUnref(threadSafe);
374}
375
376void GlyphTexture::resizeGLObjectBuffers(unsigned int maxSize)
377{
378    osg::Texture2D::resizeGLObjectBuffers(maxSize);
379
380    unsigned int initialSize = _glyphsToSubload.size();
381    _glyphsToSubload.resize(maxSize);
382   
383    for(unsigned i=initialSize; i<_glyphsToSubload.size(); ++i)
384    {
385        for(GlyphRefList::iterator itr = _glyphs.begin();
386            itr != _glyphs.end();
387            ++itr)
388        {
389            _glyphsToSubload[i].push_back(itr->get());
390        }
391    }
392}
393
394osg::Image* GlyphTexture::createImage()
395{
396    osg::ref_ptr<osg::Image> image = new osg::Image;
397    image->allocateImage(getTextureWidth(), getTextureHeight(), 1, GL_ALPHA, GL_UNSIGNED_BYTE);
398    memset(image->data(), 0, image->getTotalSizeInBytes());
399
400    for(GlyphRefList::iterator itr = _glyphs.begin();
401        itr != _glyphs.end();
402        ++itr)
403    {
404        Glyph* glyph = itr->get();
405        image->copySubImage(glyph->getTexturePositionX(), glyph->getTexturePositionY(), 0, glyph);
406    }
407
408    return image.release();
409}
410
411// all the methods in Font::Glyph have been made non inline because VisualStudio6.0 is STUPID, STUPID, STUPID PILE OF JUNK.
412Glyph::Glyph(Font* font, unsigned int glyphCode):
413    _font(font),
414    _glyphCode(glyphCode),
415    _width(1.0f),
416    _height(1.0f),
417    _horizontalBearing(0.0f,0.f),
418    _horizontalAdvance(0.f),
419    _verticalBearing(0.0f,0.f),
420    _verticalAdvance(0.f),
421    _texture(0),
422    _texturePosX(0),
423    _texturePosY(0),
424    _minTexCoord(0.0f,0.0f),
425    _maxTexCoord(0.0f,0.0f)
426{
427    setThreadSafeRefUnref(true);
428}
429
430Glyph::~Glyph()
431{
432}
433
434void Glyph::setHorizontalBearing(const osg::Vec2& bearing) {  _horizontalBearing=bearing; }
435const osg::Vec2& Glyph::getHorizontalBearing() const { return _horizontalBearing; }
436
437void Glyph::setHorizontalAdvance(float advance) { _horizontalAdvance=advance; }
438float Glyph::getHorizontalAdvance() const { return _horizontalAdvance; }
439
440void Glyph::setVerticalBearing(const osg::Vec2& bearing) {  _verticalBearing=bearing; }
441const osg::Vec2& Glyph::getVerticalBearing() const { return _verticalBearing; }
442
443void Glyph::setVerticalAdvance(float advance) {  _verticalAdvance=advance; }
444float Glyph::getVerticalAdvance() const { return _verticalAdvance; }
445
446void Glyph::setTexture(GlyphTexture* texture) { _texture = texture; }
447GlyphTexture* Glyph::getTexture() { return _texture; }
448const GlyphTexture* Glyph::getTexture() const { return _texture; }
449
450void Glyph::setTexturePosition(int posX,int posY) { _texturePosX = posX; _texturePosY = posY; }
451int Glyph::getTexturePositionX() const { return _texturePosX; }
452int Glyph::getTexturePositionY() const { return _texturePosY; }
453
454void Glyph::setMinTexCoord(const osg::Vec2& coord) { _minTexCoord=coord; }
455const osg::Vec2& Glyph::getMinTexCoord() const { return _minTexCoord; }
456
457void Glyph::setMaxTexCoord(const osg::Vec2& coord) { _maxTexCoord=coord; }
458const osg::Vec2& Glyph::getMaxTexCoord() const { return _maxTexCoord; }
459
460void Glyph::subload() const
461{
462    GLenum errorNo = glGetError();
463    if (errorNo!=GL_NO_ERROR)
464    {
465        const GLubyte* msg = osg::gluErrorString(errorNo);
466        if (msg) { OSG_WARN<<"before Glyph::subload(): detected OpenGL error: "<<msg<<std::endl; }
467        else  { OSG_WARN<<"before Glyph::subload(): detected OpenGL error number: "<<errorNo<<std::endl; }
468    }
469
470    if(s() <= 0 || t() <= 0)
471    {
472        OSG_INFO<<"Glyph::subload(): texture sub-image width and/or height of 0, ignoring operation."<<std::endl;
473        return;
474    }
475
476    glPixelStorei(GL_UNPACK_ALIGNMENT,getPacking());
477    glPixelStorei(GL_UNPACK_ROW_LENGTH,getRowLength());
478
479    glTexSubImage2D(GL_TEXTURE_2D,0,
480                    _texturePosX,_texturePosY,
481                    s(),t(),
482                    (GLenum)getPixelFormat(),
483                    (GLenum)getDataType(),
484                    data());
485                   
486    errorNo = glGetError();
487    if (errorNo!=GL_NO_ERROR)
488    {
489
490
491        const GLubyte* msg = osg::gluErrorString(errorNo);
492        if (msg) { OSG_WARN<<"after Glyph::subload() : detected OpenGL error: "<<msg<<std::endl; }
493        else { OSG_WARN<<"after Glyph::subload() : detected OpenGL error number: "<<errorNo<<std::endl; }
494
495        OSG_WARN<< "\tglTexSubImage2D(0x"<<hex<<GL_TEXTURE_2D<<dec<<" ,"<<0<<"\t"<<std::endl<<
496                                 "\t                "<<_texturePosX<<" ,"<<_texturePosY<<std::endl<<
497                                 "\t                "<<s()<<" ,"<<t()<<std::endl<<hex<<
498                                 "\t                0x"<<(GLenum)getPixelFormat()<<std::endl<<
499                                 "\t                0x"<<(GLenum)getDataType()<<std::endl<<
500                                 "\t                0x"<<(unsigned long)data()<<");"<<dec<<std::endl;
501    }                   
502}
503
504Glyph3D::Glyph3D(Font* font, unsigned int glyphCode):
505    osg::Referenced(true),
506    _font(font),
507    _glyphCode(glyphCode),
508    _width(1.0f),
509    _height(1.0f),
510    _horizontalBearing(0,0),
511    _horizontalAdvance(0),
512    _verticalBearing(0,0),
513    _verticalAdvance(0)
514    {}
515
516void Glyph3D::setThreadSafeRefUnref(bool threadSafe)
517{
518    GlyphGeometries _glyphGeometries;
519    for(GlyphGeometries::iterator itr = _glyphGeometries.begin();
520        itr != _glyphGeometries.end();
521        ++itr)
522    {
523        (*itr)->setThreadSafeRefUnref(threadSafe);
524    }
525}
526
527GlyphGeometry* Glyph3D::getGlyphGeometry(const Style* style)
528{
529
530    for(GlyphGeometries::iterator itr = _glyphGeometries.begin();
531        itr != _glyphGeometries.end();
532        ++itr)
533    {
534        GlyphGeometry* glyphGeometry = itr->get();
535        if (glyphGeometry->match(style))
536        {
537            OSG_INFO<<"Glyph3D::getGlyphGeometry(Style* style) found matching GlyphGeometry."<<std::endl;
538            return glyphGeometry;
539        }
540    }
541
542    OSG_INFO<<"Glyph3D::getGlyphGeometry(Style* style) could not find matching GlyphGeometry, creating a new one."<<std::endl;
543
544    osg::ref_ptr<GlyphGeometry> glyphGeometry = new GlyphGeometry();
545    glyphGeometry->setup(this, style);
546    _glyphGeometries.push_back(glyphGeometry);
547
548    return glyphGeometry.get();
549}
550
551
552GlyphGeometry::GlyphGeometry()
553{
554}
555
556void GlyphGeometry::setThreadSafeRefUnref(bool threadSafe)
557{
558    if (_geode.valid()) _geode->setThreadSafeRefUnref(threadSafe);
559}
560
561void GlyphGeometry::setup(const Glyph3D* glyph, const Style* style)
562{
563    float creaseAngle = 30.0f;
564    bool smooth = true;
565    osg::ref_ptr<osg::Geometry> shellGeometry;
566
567    if (!style)
568    {
569        OSG_INFO<<"GlyphGeometry::setup(const Glyph* glyph, NULL) creating default glyph geometry."<<std::endl;
570
571        float width = 0.1f;
572
573        _geometry = osgText::computeTextGeometry(glyph, width);
574    }
575    else
576    {
577        OSG_INFO<<"GlyphGeometry::setup(const Glyph* glyph, NULL) create glyph geometry with custom Style."<<std::endl;
578
579        // record the style
580        _style = dynamic_cast<Style*>(style->clone(osg::CopyOp::DEEP_COPY_ALL));
581
582        const Bevel* bevel = style ? style->getBevel() : 0;
583        bool outline = style ? style->getOutlineRatio()>0.0f : false;
584        float width = style->getThicknessRatio();
585
586        if (bevel)
587        {
588            float thickness = bevel->getBevelThickness();
589
590            osg::ref_ptr<osg::Geometry> glyphGeometry = osgText::computeGlyphGeometry(glyph, thickness, width);
591
592            _geometry = osgText::computeTextGeometry(glyphGeometry.get(), *bevel, width);
593            shellGeometry = outline ? osgText::computeShellGeometry(glyphGeometry.get(), *bevel, width) : 0;
594        }
595        else
596        {
597            _geometry = osgText::computeTextGeometry(glyph, width);
598        }
599    }
600
601    if (!_geometry)
602    {
603        OSG_INFO<<"Warning: GlyphGeometry::setup(const Glyph* glyph, const Style* style) failed."<<std::endl;
604        return;
605    }
606
607    _geode = new osg::Geode;
608    _geode->addDrawable(_geometry.get());
609    if (shellGeometry.valid()) _geode->addDrawable(shellGeometry.get());
610
611    // create the normals
612    if (smooth)
613    {
614        osgUtil::SmoothingVisitor::smooth(*_geometry, osg::DegreesToRadians(creaseAngle));
615    }
616
617    _vertices = dynamic_cast<osg::Vec3Array*>(_geometry->getVertexArray());
618    _normals = dynamic_cast<osg::Vec3Array*>(_geometry->getNormalArray());
619
620    for(osg::Geometry::PrimitiveSetList::iterator itr = _geometry->getPrimitiveSetList().begin();
621        itr != _geometry->getPrimitiveSetList().end();
622        ++itr)
623    {
624        osg::PrimitiveSet* prim = itr->get();
625        if (prim->getName()=="front") _frontPrimitiveSetList.push_back(prim);
626        else if (prim->getName()=="back") _backPrimitiveSetList.push_back(prim);
627        else if (prim->getName()=="wall") _wallPrimitiveSetList.push_back(prim);
628    }
629}
630
631bool GlyphGeometry::match(const Style* style) const
632{
633    if (_style == style) return true;
634    if (!_style || !style) return false;
635
636    return (*_style==*style);
637}
Note: See TracBrowser for help on using the browser.