root/OpenSceneGraph/trunk/src/osgPlugins/OpenFlight/GeometryRecords.cpp @ 9041

Revision 9041, 41.9 kB (checked in by robert, 6 years ago)

#if'd out an premature StateSet? optimization that was causing problems with datasets that mixed multi-texture coord geometry with single texture coord geometries in a single scene graph.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
RevLine 
[7748]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
[5038]14//
15// OpenFlight® loader for OpenSceneGraph
16//
[7748]17//  Copyright (C) 2005-2007  Brede Johansen
[5038]18//
19
[5375]20#include <assert.h>
[5038]21#include <osg/Geode>
22#include <osg/Billboard>
23#include <osg/Geometry>
24#include <osg/Texture2D>
25#include <osg/CullFace>
26#include <osg/PolygonOffset>
27#include <osg/Depth>
28#include <osg/BlendFunc>
[5610]29#include <osgUtil/TransformAttributeFunctor>
[5038]30#include "Registry.h"
31#include "Document.h"
32#include "RecordInputStream.h"
33
34namespace flt {
35
[5136]36/* Face record
37 */
[5038]38class Face : public PrimaryRecord
39{
40    // flags
41    static const unsigned int TERRAIN_BIT      = 0x80000000u >> 0;
42    static const unsigned int NO_COLOR_BIT     = 0x80000000u >> 1;
43    static const unsigned int NO_ALT_COLOR_BIT = 0x80000000u >> 2;
44    static const unsigned int PACKED_COLOR_BIT = 0x80000000u >> 3;
45    static const unsigned int FOOTPRINT_BIT    = 0x80000000u >> 4;    // Terrain culture cutout
46    static const unsigned int HIDDEN_BIT       = 0x80000000u >> 5;
47    static const unsigned int ROOFLINE_BIT     = 0x80000000u >> 6;
48
49    osg::Vec4   _primaryColor;
50    uint8       _drawFlag;
51    uint8       _template;
52    uint16      _transparency;
53    uint32      _flags;
54    uint8       _lightMode;
55
56    osg::ref_ptr<osg::Geode> _geode;
57    osg::ref_ptr<osg::Geometry> _geometry;
58
59public:
60
61    Face() :
[5625]62        _primaryColor(1,1,1,1),
63        _drawFlag(SOLID_NO_BACKFACE),
64        _template(FIXED_NO_ALPHA_BLENDING),
65        _transparency(0),
66        _flags(0),
67        _lightMode(FACE_COLOR)
[5038]68    {
69    }
70
71    META_Record(Face)
72
73    META_setID(_geode)
74    META_setComment(_geode)
75    META_setMultitexture(_geode)
76
77    // draw mode
78    enum DrawMode
79    {
80        SOLID_BACKFACED = 0,
81        SOLID_NO_BACKFACE = 1,
82        WIREFRAME_CLOSED = 2,
83        WIREFRAME_NOT_CLOSED = 3,
84        SURROUND_ALTERNATE_COLOR = 4,
85        OMNIDIRECTIONAL_LIGHT = 8,
86        UNIDIRECTIONAL_LIGHT = 9,
87        BIDIRECTIONAL_LIGHT = 10
88    };
89
90    inline DrawMode getDrawMode() const { return (DrawMode)_drawFlag; }
91
92    // lighting
93    enum LightMode
94    {
95        FACE_COLOR = 0,
96        VERTEX_COLOR = 1,
97        FACE_COLOR_LIGHTING = 2,
98        VERTEX_COLOR_LIGHTING = 3
99    };
100
101    inline LightMode getLightMode() const { return (LightMode)_lightMode; }
102    inline bool isLit() const { return (_lightMode==FACE_COLOR_LIGHTING) || (_lightMode==VERTEX_COLOR_LIGHTING); }
103    inline bool isGouraud() const { return (_lightMode==VERTEX_COLOR) || (_lightMode==VERTEX_COLOR_LIGHTING); }
104
105    // flags
106    inline bool noColor()         const { return (_flags & NO_COLOR_BIT)!=0; }
107    inline bool isHidden()        const { return (_flags & HIDDEN_BIT)!=0; }
108    inline bool isTerrain()       const { return (_flags & TERRAIN_BIT)!=0; }
109    inline bool isFootprint()     const { return (_flags & FOOTPRINT_BIT)!=0; }
110    inline bool isRoofline()      const { return (_flags & ROOFLINE_BIT)!=0; }
111    inline bool packedColorMode() const { return (_flags & PACKED_COLOR_BIT)!=0; }
112
113    // billboard
114    enum TemplateMode
115    {
116        FIXED_NO_ALPHA_BLENDING = 0,
117        FIXED_ALPHA_BLENDING = 1,
118        AXIAL_ROTATE_WITH_ALPHA_BLENDING = 2,
119        POINT_ROTATE_WITH_ALPHA_BLENDING = 4
120    };
121
122    inline TemplateMode getTemplateMode() const { return (TemplateMode)_template; }
123
124    // transparency & alpha
125    inline bool isAlphaBlend() const
126    {
127        return (_template==FIXED_ALPHA_BLENDING) ||
[5136]128               (_template==AXIAL_ROTATE_WITH_ALPHA_BLENDING) ||
129               (_template==POINT_ROTATE_WITH_ALPHA_BLENDING);
[5038]130    }
131
[5136]132    inline osg::Vec4 getPrimaryColor() const { return _primaryColor; }
[5122]133    inline float getTransparency() const { return (float)_transparency / 65535.0f; }
[5038]134    inline bool isTransparent() const { return _transparency > 0; }
135
136    virtual void addChild(osg::Node& child)
137    {
138        // Add subface to parent.
139        if (_parent.valid())
140            _parent->addChild(child);
141    }
142
143    virtual void addVertex(Vertex& vertex)
144    {
145        osg::Vec3Array* vertices = getOrCreateVertexArray(*_geometry);
146        vertices->push_back(vertex._coord);
147
148        if (isGouraud())
149        {
150            osg::Vec4Array* colors = getOrCreateColorArray(*_geometry);
151            if (vertex.validColor())
152            {
153                colors->push_back(vertex._color);
154            }
155            else
156            {
157                // Use face color if vertex color is -1 in a gouraud polygon.
158                // http://www.multigen-paradigm.com/ubb/Forum1/HTML/000967.html
159                colors->push_back(_primaryColor);
160            }
161        }
162
[6165]163        bool strict = false; // prepare for "strict" reader option.
164        if (strict)
[5038]165        {
[6165]166            if (vertex.validNormal())
167            {
168                osg::Vec3Array* normals = getOrCreateNormalArray(*_geometry);
169                normals->push_back(vertex._normal);
170            }
[5038]171        }
[6165]172        else
173        {
174            // Add normal only if lit.
175            if (isLit())
176            {
177                osg::Vec3Array* normals = getOrCreateNormalArray(*_geometry);
[5038]178
[6165]179                if (vertex.validNormal())
180                    normals->push_back(vertex._normal);
181                else // if lit and no normal in Vertex
182                {
183                    // Use previous normal if available.
184                    if (normals->empty())
185                        normals->push_back(osg::Vec3(0,0,1));
186                    else
187                        normals->push_back(normals->back());
188                }
189            }
190        }
191
[5136]192        for (int layer=0; layer<Vertex::MAX_LAYERS; layer++)
[5038]193        {
[5136]194            if (vertex.validUV(layer))
195            {
196                osg::Vec2Array* UVs = getOrCreateTextureArray(*_geometry,layer);
197                UVs->push_back(vertex._uv[layer]);
198            }
[5038]199        }
200    }
201
202    virtual void addVertexUV(int unit, const osg::Vec2& uv)
203    {
204        osg::Vec2Array* UVs = getOrCreateTextureArray(*_geometry,unit);
205        UVs->push_back(uv);
206    }
207
[5229]208    virtual void addMorphVertex(Vertex& vertex0, Vertex& /*vertex100*/)
[5038]209    {
210        osg::Vec3Array* vertices = getOrCreateVertexArray(*_geometry);
211        vertices->push_back(vertex0._coord);
212
213        if (isGouraud())
214        {
215            osg::Vec4Array* colors = getOrCreateColorArray(*_geometry);
216            if (vertex0.validColor())
217            {
218                colors->push_back(vertex0._color);
219            }
220            else
221            {
222                // Use face color if vertex color is -1 in a gouraud polygon.
223                // http://www.multigen-paradigm.com/ubb/Forum1/HTML/000967.html
224                colors->push_back(_primaryColor);
225            }
226        }
227
228        if (vertex0.validNormal())
229        {
230            osg::Vec3Array* normals = getOrCreateNormalArray(*_geometry);
231            normals->push_back(vertex0._normal);
232        }
233
[5136]234        for (int layer=0; layer<Vertex::MAX_LAYERS; layer++)
[5038]235        {
[5136]236            if (vertex0.validUV(layer))
237            {
238                osg::Vec2Array* UVs = getOrCreateTextureArray(*_geometry,layer);
239                UVs->push_back(vertex0._uv[layer]);
240            }
[5038]241        }
242    }
243
244protected:
245
246    virtual void readRecord(RecordInputStream& in, Document& document)
247    {
248        std::string id = in.readString(8);
[5229]249        /*int32 IRColor =*/ in.readInt32();
250        /*int16 relativePriority =*/ in.readInt16();
[5625]251        _drawFlag = in.readUInt8(SOLID_NO_BACKFACE);
[5136]252        uint8 texturedWhite = in.readUInt8();
253        int16 primaryNameIndex = in.readInt16(-1);
[5229]254        /*int16 secondaryNameIndex =*/ in.readInt16(-1);
[5038]255        in.forward(1);
256        _template = in.readUInt8(FIXED_NO_ALPHA_BLENDING);
[5229]257        /*int detailTexture =*/ in.readInt16(-1);
[5136]258        int textureIndex = in.readInt16(-1);
259        int materialIndex = in.readInt16(-1);
[5229]260        /*int16 surface =*/ in.readInt16();
261        /*int16 feature =*/ in.readInt16();
262        /*int32 IRMaterial =*/ in.readInt32(-1);
[5038]263        _transparency = in.readUInt16(0);
264        // version > 13
[5229]265        /*uint8 influenceLOD =*/ in.readUInt8();
266        /*uint8 linestyle =*/ in.readUInt8();
[5038]267        _flags = in.readUInt32(0);
268        _lightMode = in.readUInt8(FACE_COLOR);
269        in.forward(7);
[5136]270        osg::Vec4 primaryPackedColor = in.readColor32();
271        osg::Vec4 secondaryPackedColor = in.readColor32();
[5038]272        // version >= VERSION_15_1
[5229]273        /*int textureMappingIndex =*/ in.readInt16(-1);
[5038]274        in.forward(2);
[5136]275        int primaryColorIndex = in.readInt32(-1);
[5229]276        /*int alternateColorIndex =*/ in.readInt32(-1);
[5038]277        // version >= 16
278        in.forward(2);
[5136]279        int shaderIndex = in.readInt16(-1);
[5038]280
281        // Create Geode or Billboard.
282        switch (_template)
283        {
284        case AXIAL_ROTATE_WITH_ALPHA_BLENDING:
285            {
286                osg::Billboard* billboard = new osg::Billboard;
287                billboard->setMode(osg::Billboard::AXIAL_ROT);
288                _geode = billboard;
289            }
290            break;
291        case POINT_ROTATE_WITH_ALPHA_BLENDING:
292            {
293                osg::Billboard* billboard = new osg::Billboard;
294                billboard->setMode(osg::Billboard::POINT_ROT_WORLD);
295                _geode = billboard;
296            }
297            break;
298        default:
299            _geode = new osg::Geode;
300        }
301
302        _geode->setDataVariance(osg::Object::STATIC);
303        _geode->setName(id);
304
305        _geometry = new osg::Geometry;
306        _geometry->setDataVariance(osg::Object::STATIC);
307        _geode->addDrawable(_geometry.get());
308
309        // StateSet
[5122]310        osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet;
[5038]311
312        // Hidden
313        if (isHidden())
314            _geode->setNodeMask(0);
315
316        // Face color
[5136]317        if (texturedWhite!=0 && textureIndex>=0)
[5038]318        {
319            _primaryColor = osg::Vec4(1,1,1,1);
320        }
321        else
322        {
323            if (packedColorMode())
324            {
[5136]325                _primaryColor = primaryPackedColor;
[5038]326            }
327            else
328            {
329                if (document.version() < VERSION_15_1)
[5136]330                    _primaryColor = document.getColorPool()->getColor(primaryNameIndex);
[5038]331
332                else // >= VERSION_15_1
[5136]333                    _primaryColor = document.getColorPool()->getColor(primaryColorIndex);
[5038]334            }
335        }
336
337        // Lighting
338        stateset->setMode(GL_LIGHTING, isLit() ? osg::StateAttribute::ON : osg::StateAttribute::OFF);
339
340        // Material
[5640]341        if (isLit() || materialIndex>=0)
[5038]342        {
[5640]343            // MaterialPool will return a "default" material if no material is defined for materialIndex.
344            // http://www.multigen-paradigm.com/ubb/Forum1/HTML/000228.html
[5038]345            osg::Vec4 col = _primaryColor;
346            col.a() = 1.0f - getTransparency();
[5136]347            osg::Material* material = document.getOrCreateMaterialPool()->getOrCreateMaterial(materialIndex,col);
[5038]348            stateset->setAttribute(material);
349        }
350
351        // Shaders
[5136]352        if (shaderIndex >= 0)
[5038]353        {
354            ShaderPool* sp = document.getOrCreateShaderPool();
[5136]355            osg::Program* program = sp->get(shaderIndex);
[5038]356            if (program)
357                stateset->setAttributeAndModes(program, osg::StateAttribute::ON);
358        }
359
360         // Texture
361        TexturePool* tp = document.getOrCreateTexturePool();
[5136]362        osg::StateSet* textureStateSet = tp->get(textureIndex);
[5038]363        if (textureStateSet)
364        {
365            // Merge face stateset with texture stateset
366            stateset->merge(*textureStateSet);
367        }
368
369        // Cull face
370        switch(_drawFlag)
371        {
372        case SOLID_BACKFACED:     // Enable backface culling
[5122]373        {
374            static osg::ref_ptr<osg::CullFace> cullFace = new osg::CullFace(osg::CullFace::BACK);
375            stateset->setAttributeAndModes(cullFace.get(), osg::StateAttribute::ON);
[5038]376            break;
[5122]377        }
[5038]378        case SOLID_NO_BACKFACE:   // Disable backface culling
379            stateset->setMode(GL_CULL_FACE,osg::StateAttribute::OFF);
380            break;
381        }
382
383        // Subface
384        if (document.subfaceLevel() > 0)
385        {
[5122]386            static osg::ref_ptr<osg::PolygonOffset> polygonOffset = new osg::PolygonOffset(-10.0f, -40.0f);
387            stateset->setAttributeAndModes(polygonOffset.get(), osg::StateAttribute::ON);
[5038]388
[5122]389            static osg::ref_ptr<osg::Depth> depth = new osg::Depth(osg::Depth::LESS, 0.0, 1.0,false);
390            stateset->setAttribute(depth.get());
[5038]391
392            stateset->setRenderBinDetails(document.subfaceLevel(),"RenderBin");
393        }
[5136]394
[9041]395#if 0
396// note from Robert Osfield, this "optimization" breaks multi-textured datasets that mix single texture
397// and mulit-texture geometries as the Multitexture parsing can come after the below code, and accidentally
398// polute the non multi-texture geometries StateSet.
399
[5122]400        // A simple share stateset optimization.
401        static osg::ref_ptr<osg::StateSet> lastStateset;
402        if (lastStateset.valid() && (stateset->compare(*lastStateset,false)==0))
403            stateset = lastStateset;
404        else
405            lastStateset = stateset;
[9041]406#endif
[5136]407
[5122]408        _geode->setStateSet(stateset.get());
[5038]409
410        // Add to parent.
411        if (_parent.valid())
412            _parent->addChild(*_geode);
413    }
414
415    osg::PrimitiveSet::Mode getPrimitiveSetMode(int numVertices)
416    {
417        switch(getDrawMode())
418        {
419            case WIREFRAME_NOT_CLOSED:
420                return osg::PrimitiveSet::LINE_STRIP;
421            case WIREFRAME_CLOSED:
422                return osg::PrimitiveSet::LINE_LOOP;
423            case OMNIDIRECTIONAL_LIGHT:
424            case UNIDIRECTIONAL_LIGHT:
425            case BIDIRECTIONAL_LIGHT:
426                return osg::PrimitiveSet::POINTS;
427            default: break;
428        }
429
430        switch (numVertices)
431        {
432            case 1: return osg::PrimitiveSet::POINTS;
433            case 2: return osg::PrimitiveSet::LINES;
434            case 3: return osg::PrimitiveSet::TRIANGLES;
435            case 4: return osg::PrimitiveSet::QUADS;
436            default: break;
437        }
438
439        return osg::PrimitiveSet::POLYGON;
440    }
441
[7756]442    virtual void dispose(Document& document)
[5038]443    {
444        if (_geode.valid())
445        {
[7756]446            // Insert transform(s)
447            if (_matrix.valid())
448            {
449                insertMatrixTransform(*_geode,*_matrix,_numberOfReplications);
450            }
451
452            // Add primitives, set bindings etc.
[5038]453            for (unsigned int i=0; i<_geode->getNumDrawables(); ++i)
454            {
455                osg::Geometry* geometry = dynamic_cast<osg::Geometry*>(_geode->getDrawable(i));
456                if (geometry)
457                {
458                    osg::Array* vertices = geometry->getVertexArray();
459                    if (vertices)
460                    {
461                        GLint first = 0;
462                        GLsizei count = vertices->getNumElements();
463                        osg::PrimitiveSet::Mode mode = getPrimitiveSetMode(count);
464                        geometry->addPrimitiveSet(new osg::DrawArrays(mode,first,count));
465                    }
466
467                    // Color binding
468                    if (isGouraud())
469                    {
470                        // Color per vertex
471                        geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
472                    }
473                    else
474                    {
475                        // Color per face
476                        osg::Vec4 col = getPrimaryColor();
477                        col[3] = 1.0f - getTransparency();
478
479                        geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
480                        osg::Vec4Array* colors = new osg::Vec4Array(1);
481                        (*colors)[0] = col;
482                        geometry->setColorArray(colors);
483                    }
484
485                    // Normal binding
486                    if (isLit())
487                    {
488                        geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX );
489                    }
490                    else
491                    {
492                        geometry->setNormalBinding(osg::Geometry::BIND_OFF);
493                        geometry->setNormalArray(NULL);
494                    }
495                }
496            }
[5610]497
[5625]498            osg::StateSet* stateset =  _geode->getOrCreateStateSet();
499
500            // Translucent image?
501            bool isImageTranslucent = false;
502            if (document.getUseTextureAlphaForTransparancyBinning())
503            {
504                for (unsigned int i=0; i<stateset->getTextureAttributeList().size(); ++i)
505                {
506                    osg::StateAttribute* sa = stateset->getTextureAttribute(i,osg::StateAttribute::TEXTURE);
507                    osg::Texture2D* texture = dynamic_cast<osg::Texture2D*>(sa);
508                    if (texture)
509                    {
510                        osg::Image* image = texture->getImage();
511                        if (image && image->isImageTranslucent())
512                            isImageTranslucent = true;
513                    }
514                }
515            }
516
517            // Transparent Material?
518            bool isMaterialTransparent = false;
519            osg::Material* material = dynamic_cast<osg::Material*>(stateset->getAttribute(osg::StateAttribute::MATERIAL));
520            if (material)
521            {
522                isMaterialTransparent = material->getDiffuse(osg::Material::FRONT).a() < 0.99f;
523            }
524
525            // Enable alpha blend?
526            if (isAlphaBlend() || isTransparent() || isImageTranslucent || isMaterialTransparent)
527            {
528                static osg::ref_ptr<osg::BlendFunc> blendFunc = new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA);
529                stateset->setAttributeAndModes(blendFunc.get(), osg::StateAttribute::ON);
530                stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
531            }
532
[5610]533            if (document.getUseBillboardCenter())
534            {
535                // Set billboard rotation point to center of face.
536                osg::Billboard* billboard = dynamic_cast<osg::Billboard*>(_geode.get());
537                if (billboard)
538                {
539                    for (unsigned int i=0; i<billboard->getNumDrawables(); ++i)
540                    {
541                        osg::BoundingBox bb = billboard->getDrawable(i)->getBound();
542                        billboard->setPosition(i,bb.center());
543
544                        osgUtil::TransformAttributeFunctor tf(osg::Matrix::translate(-bb.center()));
545                        billboard->getDrawable(i)->accept(tf);
546
547                        billboard->getDrawable(i)->dirtyBound();
548                    }
549                   
550                    billboard->dirtyBound();
551                }
552            }
[5038]553        }
554    }
555};
556
557RegisterRecordProxy<Face> g_Face(FACE_OP);
558
559
560/** VertexList -
561  * The VertexList is a leaf record.
562  * Possible parents: Face, Mesh & LightPoint
563  */
[5136]564class VertexListRecord : public PrimaryRecord
[5038]565{
566public:
567
[5136]568    VertexListRecord() {}
[5038]569
[5136]570    META_Record(VertexListRecord)
[5038]571
572    virtual void addVertex(Vertex& vertex)
573    {
574        // forward vertex to parent.
575        if (_parent.valid())
576            _parent->addVertex(vertex);
577    }
578
579    virtual void addVertexUV(int layer,const osg::Vec2& uv)
580    {
581        // forward uv to parent.
582        if (_parent.valid())
583            _parent->addVertexUV(layer,uv);
584    }
585
586protected:
587
[5136]588    virtual ~VertexListRecord() {}
[5038]589
590    virtual void readRecord(RecordInputStream& in, Document& document)
591    {
592        VertexPool* vp = document.getVertexPool();
593        if (vp)
594        {
595            int vertices = (in.getRecordSize()-4) / 4;
596
597            // Use the Vertex pool as a record stream.
[5205]598            RecordInputStream inVP(vp->rdbuf());
[5038]599            for (int n=0; n<vertices; n++)
600            {
601                // Get position of vertex.
602                uint32 pos = in.readUInt32();
603
604                // Get vertex from vertex pool.
[5205]605                inVP.seekg((std::istream::pos_type)pos);
[5038]606                inVP.readRecord(document);
607            }
608        }
609    }
610};
611
612
[5136]613RegisterRecordProxy<VertexListRecord> g_VertexList(VERTEX_LIST_OP);
[5038]614
615
616/** MorphVertexList -
617  * The MorphVertexList is a leaf record.
618  */
619class MorphVertexList : public PrimaryRecord
620{
621    enum Mode
622    {
623        UNDEFINED,
624        MORPH_0,
625        MORPH_100
626    };
627
628    Mode _mode;
629    Vertex _vertex0;
630    Vertex _vertex100;
631
632public:
633
634    MorphVertexList():
635        _mode(UNDEFINED)
636    {
637    }
638
639    META_Record(MorphVertexList)
640
641    virtual void addVertex(Vertex& vertex)
642    {
643        switch (_mode)
644        {
645        case MORPH_0:
646            _vertex0 = vertex;
647            break;
648        case MORPH_100:
649            _vertex100 = vertex;
650
651            // forward vertex to parent.
652            if (_parent.valid())
653                _parent->addMorphVertex(_vertex0, _vertex100);
654            break;
[5229]655        case UNDEFINED:
656            break;
[5038]657        }
658    }
659
660    //virtual void addVertexUV(int layer,const osg::Vec2& uv)
661    //{
662    //    // forward uv to parent.
663    //    if (_parent.valid())
664    //        _parent->addVertexUV(layer,uv);
665    //}
666
667protected:
668
669    virtual ~MorphVertexList() {}
670
671    virtual void readRecord(RecordInputStream& in, Document& document)
672    {
673        VertexPool* vp = document.getVertexPool();
674        if (vp)
675        {
676            int vertices = (in.getRecordSize()-4) / 8;
677
678            // Use the Vertex pool as a record stream.
[5205]679            RecordInputStream inVP(vp->rdbuf());
[5038]680            for (int n=0; n<vertices; n++)
681            {
682                // Get position of vertex.
683                uint32 offset0 = in.readUInt32();
684                uint32 offset100 = in.readUInt32();
685
686                // Get vertex from vertex pool.
687
688                // 0%
689                _mode = MORPH_0;
[5205]690                inVP.seekg((std::istream::pos_type)offset0);
[5038]691                inVP.readRecord(document);
692
693                // 100%
694                _mode = MORPH_100;
[5205]695                inVP.seekg((std::istream::pos_type)offset100);
[5038]696                inVP.readRecord(document);
697            }
698        }
699    }
700};
701
702RegisterRecordProxy<MorphVertexList> g_MorphVertexList(MORPH_VERTEX_LIST_OP);
703
[5122]704
[5136]705/* Mesh record
706 */
707class Mesh : public PrimaryRecord
708{
709    // flags
710    static const unsigned int TERRAIN_BIT      = 0x80000000u >> 0;
711    static const unsigned int NO_COLOR_BIT     = 0x80000000u >> 1;
712    static const unsigned int NO_ALT_COLOR_BIT = 0x80000000u >> 2;
713    static const unsigned int PACKED_COLOR_BIT = 0x80000000u >> 3;
714    static const unsigned int FOOTPRINT_BIT    = 0x80000000u >> 4;    // Terrain culture cutout
715    static const unsigned int HIDDEN_BIT       = 0x80000000u >> 5;
716    static const unsigned int ROOFLINE_BIT     = 0x80000000u >> 6;
[5122]717
[5136]718    osg::Vec4   _primaryColor;
719    uint8       _drawFlag;
720    uint8       _template;
721    uint16      _transparency;
722    uint32      _flags;
723    uint8       _lightMode;
[5122]724
[5136]725    osg::ref_ptr<osg::Geode> _geode;
[5122]726
[5136]727public:
[5122]728
[5136]729    Mesh() :
[5625]730        _primaryColor(1,1,1,1),
731        _drawFlag(SOLID_NO_BACKFACE),
732        _template(FIXED_NO_ALPHA_BLENDING),
733        _transparency(0),
734        _flags(0),
735        _lightMode(FACE_COLOR)
[5136]736    {
737    }
[5122]738
[5136]739    META_Record(Mesh)
[5122]740
[5136]741    META_setID(_geode)
742    META_setComment(_geode)
743    META_setMultitexture(_geode)
[5122]744
[5136]745    // draw mode
746    enum DrawMode
747    {
748        SOLID_BACKFACED = 0,
749        SOLID_NO_BACKFACE = 1,
750        WIREFRAME_CLOSED = 2,
751        WIREFRAME_NOT_CLOSED = 3,
752        SURROUND_ALTERNATE_COLOR = 4,
753        OMNIDIRECTIONAL_LIGHT = 8,
754        UNIDIRECTIONAL_LIGHT = 9,
755        BIDIRECTIONAL_LIGHT = 10
756    };
[5122]757
[5136]758    inline DrawMode getDrawMode() const { return (DrawMode)_drawFlag; }
[5122]759
[5136]760    // lighting
761    enum LightMode
762    {
763        FACE_COLOR = 0,
764        VERTEX_COLOR = 1,
765        FACE_COLOR_LIGHTING = 2,
766        VERTEX_COLOR_LIGHTING = 3
767    };
[5122]768
[5136]769    inline LightMode getLightMode() const { return (LightMode)_lightMode; }
770    inline bool isLit() const { return (_lightMode==FACE_COLOR_LIGHTING) || (_lightMode==VERTEX_COLOR_LIGHTING); }
771    inline bool isGouraud() const { return (_lightMode==VERTEX_COLOR) || (_lightMode==VERTEX_COLOR_LIGHTING); }
[5122]772
[5136]773    // flags
774    inline bool noColor()         const { return (_flags & NO_COLOR_BIT)!=0; }
775    inline bool isHidden()        const { return (_flags & HIDDEN_BIT)!=0; }
776    inline bool isTerrain()       const { return (_flags & TERRAIN_BIT)!=0; }
777    inline bool isFootprint()     const { return (_flags & FOOTPRINT_BIT)!=0; }
778    inline bool isRoofline()      const { return (_flags & ROOFLINE_BIT)!=0; }
779    inline bool packedColorMode() const { return (_flags & PACKED_COLOR_BIT)!=0; }
780
781    // billboard
782    enum TemplateMode
783    {
784        FIXED_NO_ALPHA_BLENDING = 0,
785        FIXED_ALPHA_BLENDING = 1,
786        AXIAL_ROTATE_WITH_ALPHA_BLENDING = 2,
787        POINT_ROTATE_WITH_ALPHA_BLENDING = 4
788    };
789
790    inline TemplateMode getTemplateMode() const { return (TemplateMode)_template; }
791
792    // transparency & alpha
793    inline bool isAlphaBlend() const
794    {
795        return (_template==FIXED_ALPHA_BLENDING) ||
796               (_template==AXIAL_ROTATE_WITH_ALPHA_BLENDING) ||
797               (_template==POINT_ROTATE_WITH_ALPHA_BLENDING);
798    }
799
800    inline osg::Vec4 getPrimaryColor() const { return _primaryColor; }
801    inline float getTransparency() const { return (float)_transparency / 65535.0f; }
802    inline bool isTransparent() const { return _transparency > 0; }
803
804    virtual void addChild(osg::Node& child)
805    {
806        // Add subface to parent.
807        if (_parent.valid())
808            _parent->addChild(child);
809    }
810
811    virtual void addGeometry(osg::Geometry& geometry)
812    {
813        _geode->addDrawable(&geometry);
814    }
815
816protected:
817
818    virtual void readRecord(RecordInputStream& in, Document& document)
819    {
820        std::string id = in.readString(8);
821        in.forward(4);
[5229]822        /*int32 IRColor =*/ in.readInt32();
823        /*int16 relativePriority =*/ in.readInt16();
[5625]824        _drawFlag = in.readUInt8(SOLID_NO_BACKFACE);
[5136]825        uint8 texturedWhite = in.readUInt8();
826        int16 primaryNameIndex = in.readInt16(-1);
[5229]827        /*int16 secondaryNameIndex =*/ in.readInt16(-1);
[5136]828        in.forward(1);
829        _template = in.readUInt8(FIXED_NO_ALPHA_BLENDING);
[5229]830        /*int detailTexture =*/ in.readInt16(-1);
[5136]831        int textureIndex = in.readInt16(-1);
832        int materialIndex = in.readInt16(-1);
[5229]833        /*int16 surface =*/ in.readInt16();
834        /*int16 feature =*/ in.readInt16();
835        /*int32 IRMaterial =*/ in.readInt32(-1);
[5136]836        _transparency = in.readUInt16(0);
837        // version > 13
[5229]838        /*uint8 influenceLOD =*/ in.readUInt8();
839        /*uint8 linestyle =*/ in.readUInt8();
[5136]840        _flags = in.readUInt32(0);
841        _lightMode = in.readUInt8(FACE_COLOR);
842        in.forward(7);
843        osg::Vec4 primaryPackedColor = in.readColor32();
844        osg::Vec4 secondaryPackedColor = in.readColor32();
845        // version >= VERSION_15_1
[5229]846        /*int textureMappingIndex =*/ in.readInt16(-1);
[5136]847        in.forward(2);
848        int primaryColorIndex = in.readInt32(-1);
[5229]849        /*int alternateColorIndex =*/ in.readInt32(-1);
[5136]850        // version >= 16
851        in.forward(2);
852        int shaderIndex = in.readInt16(-1);
853
854        // Create Geode or Billboard.
855        switch (_template)
856        {
857        case AXIAL_ROTATE_WITH_ALPHA_BLENDING:
858            {
859                osg::Billboard* billboard = new osg::Billboard;
860                billboard->setMode(osg::Billboard::AXIAL_ROT);
861                _geode = billboard;
862            }
863            break;
864        case POINT_ROTATE_WITH_ALPHA_BLENDING:
865            {
866                osg::Billboard* billboard = new osg::Billboard;
867                billboard->setMode(osg::Billboard::POINT_ROT_WORLD);
868                _geode = billboard;
869            }
870            break;
871        default:
872            _geode = new osg::Geode;
873        }
874
875        _geode->setDataVariance(osg::Object::STATIC);
876        _geode->setName(id);
877
878        // StateSet
879        osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet;
880
881        // Hidden
882        if (isHidden())
883            _geode->setNodeMask(0);
884
885        // Face color
886        if (texturedWhite!=0 && textureIndex>=0)
887        {
888            _primaryColor = osg::Vec4(1,1,1,1);
889        }
890        else
891        {
892            if (packedColorMode())
893            {
894                _primaryColor = primaryPackedColor;
895            }
896            else
897            {
898                if (document.version() < VERSION_15_1)
899                    _primaryColor = document.getColorPool()->getColor(primaryNameIndex);
900
901                else // >= VERSION_15_1
902                    _primaryColor = document.getColorPool()->getColor(primaryColorIndex);
903            }
904        }
905
906        // Lighting
907        stateset->setMode(GL_LIGHTING, isLit() ? osg::StateAttribute::ON : osg::StateAttribute::OFF);
908
909        // Material
[5640]910        if (isLit() || materialIndex>=0)
[5136]911        {
[5640]912            // MaterialPool will return a "default" material if no material is defined for materialIndex.
913            // http://www.multigen-paradigm.com/ubb/Forum1/HTML/000228.html
[5136]914            osg::Vec4 col = _primaryColor;
915            col.a() = 1.0f - getTransparency();
916            osg::Material* material = document.getOrCreateMaterialPool()->getOrCreateMaterial(materialIndex,col);
917            stateset->setAttribute(material);
918        }
919
920        // Shaders
921        if (shaderIndex >= 0)
922        {
923            ShaderPool* sp = document.getOrCreateShaderPool();
924            osg::Program* program = sp->get(shaderIndex);
925            if (program)
926                stateset->setAttributeAndModes(program, osg::StateAttribute::ON);
927        }
928
929         // Texture
930        TexturePool* tp = document.getOrCreateTexturePool();
931        osg::StateSet* textureStateSet = tp->get(textureIndex);
932        if (textureStateSet)
933        {
934            // Merge face stateset with texture stateset
935            stateset->merge(*textureStateSet);
936        }
937
938        // Cull face
939        switch(_drawFlag)
940        {
941        case SOLID_BACKFACED:     // Enable backface culling
942        {
943            static osg::ref_ptr<osg::CullFace> cullFace = new osg::CullFace(osg::CullFace::BACK);
944            stateset->setAttributeAndModes(cullFace.get(), osg::StateAttribute::ON);
945            break;
946        }
947        case SOLID_NO_BACKFACE:   // Disable backface culling
948            stateset->setMode(GL_CULL_FACE,osg::StateAttribute::OFF);
949            break;
950        }
951
952        // Subface
953        if (document.subfaceLevel() > 0)
954        {
955            static osg::ref_ptr<osg::PolygonOffset> polygonOffset = new osg::PolygonOffset(-10.0f, -40.0f);
956            stateset->setAttributeAndModes(polygonOffset.get(), osg::StateAttribute::ON);
957
958            static osg::ref_ptr<osg::Depth> depth = new osg::Depth(osg::Depth::LESS, 0.0, 1.0,false);
959            stateset->setAttribute(depth.get());
960
961            stateset->setRenderBinDetails(document.subfaceLevel(),"RenderBin");
962        }
963
[9041]964#if 0
965// note from Robert Osfield, this "optimization" breaks multi-textured datasets that mix single texture
966// and mulit-texture geometries as the Multitexture parsing can come after the below code, and accidentally
967// polute the non multi-texture geometries StateSet.
968
[5136]969        // A simple share stateset optimization.
970        static osg::ref_ptr<osg::StateSet> lastStateset;
971        if (lastStateset.valid() && (stateset->compare(*lastStateset,false)==0))
972            stateset = lastStateset;
973        else
974            lastStateset = stateset;
[9041]975#endif
[5136]976
977        _geode->setStateSet(stateset.get());
978
979        // Add to parent.
980        if (_parent.valid())
981            _parent->addChild(*_geode);
982    }
983
[7756]984    virtual void dispose(Document& document)
[5625]985    {
986        if (_geode.valid())
987        {
[7756]988            // Insert transform(s)
989            if (_matrix.valid())
990            {
991                insertMatrixTransform(*_geode,*_matrix,_numberOfReplications);
992            }
993
[5625]994            osg::StateSet* stateset =  _geode->getOrCreateStateSet();
995
996            // Translucent image?
997            bool isImageTranslucent = false;
998            if (document.getUseTextureAlphaForTransparancyBinning())
999            {
1000                for (unsigned int i=0; i<stateset->getTextureAttributeList().size(); ++i)
1001                {
1002                    osg::StateAttribute* sa = stateset->getTextureAttribute(i,osg::StateAttribute::TEXTURE);
1003                    osg::Texture2D* texture = dynamic_cast<osg::Texture2D*>(sa);
1004                    if (texture)
1005                    {
1006                        osg::Image* image = texture->getImage();
1007                        if (image && image->isImageTranslucent())
1008                            isImageTranslucent = true;
1009                    }
1010                }
1011            }
1012
1013            // Transparent Material?
1014            bool isMaterialTransparent = false;
1015            osg::Material* material = dynamic_cast<osg::Material*>(stateset->getAttribute(osg::StateAttribute::MATERIAL));
1016            if (material)
1017            {
1018                isMaterialTransparent = material->getDiffuse(osg::Material::FRONT).a() < 0.99f;
1019            }
1020
1021            // Enable alpha blend?
1022            if (isAlphaBlend() || isTransparent() || isImageTranslucent || isMaterialTransparent)
1023            {
1024                static osg::ref_ptr<osg::BlendFunc> blendFunc = new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA);
1025                stateset->setAttributeAndModes(blendFunc.get(), osg::StateAttribute::ON);
1026                stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
1027            }
1028
1029            if (document.getUseBillboardCenter())
1030            {
1031                // Set billboard rotation point to center of face.
1032                osg::Billboard* billboard = dynamic_cast<osg::Billboard*>(_geode.get());
1033                if (billboard)
1034                {
1035                    for (unsigned int i=0; i<billboard->getNumDrawables(); ++i)
1036                    {
1037                        osg::BoundingBox bb = billboard->getDrawable(i)->getBound();
1038                        billboard->setPosition(i,bb.center());
1039
1040                        osgUtil::TransformAttributeFunctor tf(osg::Matrix::translate(-bb.center()));
1041                        billboard->getDrawable(i)->accept(tf);
1042
1043                        billboard->getDrawable(i)->dirtyBound();
1044                    }
1045                   
1046                    billboard->dirtyBound();
1047                }
1048            }
1049        }
1050    }
[5136]1051};
1052
1053RegisterRecordProxy<Mesh> g_Mesh(MESH_OP);
1054
1055
1056
1057/** LocalVertexPool -
1058  */
1059class LocalVertexPool : public Record
1060{
1061    // Attribute Mask
1062    static const unsigned int HAS_POSITION      = 0x80000000u >> 0;
1063    static const unsigned int HAS_COLOR_INDEX   = 0x80000000u >> 1;
1064    static const unsigned int HAS_RGBA_COLOR    = 0x80000000u >> 2;
1065    static const unsigned int HAS_NORMAL        = 0x80000000u >> 3;
1066    static const unsigned int HAS_BASE_UV       = 0x80000000u >> 4;
1067    static const unsigned int HAS_UV_LAYER1     = 0x80000000u >> 5;
1068    static const unsigned int HAS_UV_LAYER2     = 0x80000000u >> 6;
1069    static const unsigned int HAS_UV_LAYER3     = 0x80000000u >> 7;
1070    static const unsigned int HAS_UV_LAYER4     = 0x80000000u >> 8;
1071    static const unsigned int HAS_UV_LAYER5     = 0x80000000u >> 9;
1072    static const unsigned int HAS_UV_LAYER6     = 0x80000000u >> 10;
1073    static const unsigned int HAS_UV_LAYER7     = 0x80000000u >> 11;
1074
1075public:
1076
1077    LocalVertexPool() {}
1078
1079    META_Record(LocalVertexPool)
1080
1081protected:
1082
1083    virtual ~LocalVertexPool() {}
1084
1085    virtual void readRecord(RecordInputStream& in, Document& document)
1086    {
1087
1088        uint32 vertices = in.readUInt32();
1089        uint32 mask = in.readUInt32();
1090
1091        osg::ref_ptr<VertexList> _vertexList = new VertexList(vertices);
1092
1093
1094        for (unsigned int n=0; n<vertices; n++)
1095        {
1096            Vertex vertex;
1097
1098            if (mask & HAS_POSITION)
1099            {
1100                osg::Vec3d coord = in.readVec3d();
1101                vertex.setCoord(coord*document.unitScale());
[5407]1102
1103                if (!coord.valid())
1104                {
1105                    osg::notify(osg::NOTICE)<<"Warning: data error detected in LocalVertexPool::readRecord coord="<<coord.x()<<" "<<coord.y()<<" "<<coord.z()<<std::endl;
1106                }
[5136]1107            }
1108
1109            if (mask & HAS_COLOR_INDEX)
1110            {
1111                uint32 alphaIndex = in.readUInt32();
1112                int index = alphaIndex & 0x00ffffff;
1113                uint8 alpha = alphaIndex >> 24;
1114                osg::Vec4 color = document.getColorPool()->getColor(index);
1115                color.a() = (float)alpha/255;
1116                vertex.setColor(color);
[5407]1117
1118                if (!color.valid())
1119                {
1120                    osg::notify(osg::NOTICE)<<"Warning: data error detected in LocalVertexPool::readRecord color="<<color.r()<<" "<<color.g()<<" "<<color.b()<<" "<<color.a()<<std::endl;
1121                }
[5136]1122            }
1123
1124            if (mask & HAS_RGBA_COLOR)
1125            {
1126                osg::Vec4f color = in.readColor32();
1127                vertex.setColor(color);
[5407]1128
1129                if (!color.valid())
1130                {
1131                    osg::notify(osg::NOTICE)<<"Warning: data error detected in LocalVertexPool::readRecord color="<<color.r()<<" "<<color.g()<<" "<<color.b()<<" "<<color.a()<<std::endl;
1132                }
[5136]1133            }
1134
1135            if (mask & HAS_NORMAL)
1136            {
1137                osg::Vec3f normal = in.readVec3f();
1138                vertex.setNormal(normal);
[5407]1139
1140                if (!normal.valid())
1141                {
1142                    osg::notify(osg::NOTICE)<<"Warning: data error detected in LocalVertexPool::readRecord normal="<<normal.x()<<" "<<normal.y()<<" "<<normal.z()<<std::endl;
1143                }
[5136]1144            }
1145
1146            for (unsigned int layer=0; layer<8; layer++)
1147            {
1148                if (mask & (HAS_BASE_UV >> layer))
1149                {
1150                    osg::Vec2f uv = in.readVec2f();
1151                    vertex.setUV(layer,uv);
[5407]1152                   
1153                    if (!uv.valid())
1154                    {
1155                        osg::notify(osg::NOTICE)<<"Warning: data error detected in LocalVertexPool::readRecord uv="<<uv.x()<<" "<<uv.y()<<std::endl;
1156                    }
1157
[5136]1158                }
1159            }
1160
1161            (*_vertexList)[n] = vertex;
1162        }
1163
1164        if (_parent.valid())
1165            _parent->setLocalVertexPool(_vertexList.get());
1166
1167    }
1168};
1169
1170RegisterRecordProxy<LocalVertexPool> g_LocalVertexPool(LOCAL_VERTEX_POOL_OP);
1171
1172
1173
1174/** MeshPrimitive -
1175  */
1176class MeshPrimitive : public PrimaryRecord
1177{
1178    enum PrimitiveType
1179    {
1180        TRIANGLE_STRIP = 1,
1181        TRIANGLE_FAN = 2,
1182        QUADRILATERAL_STRIP = 3,
1183        INDEXED_POLYGON = 4
1184    };
1185
1186public:
1187
1188    MeshPrimitive() {}
1189
1190    META_Record(MeshPrimitive)
1191
1192protected:
1193
1194    virtual ~MeshPrimitive() {}
1195
[5229]1196    virtual void readRecord(RecordInputStream& in, Document& /*document*/)
[5136]1197    {
1198        Mesh* mesh = dynamic_cast<Mesh*>(_parent.get());
1199        if (!mesh) return;
1200
1201        VertexList* vertexList = mesh->getLocalVertexPool();
1202        if (!vertexList) return;
1203
1204        int16 type = in.readInt16();
1205        uint16 indexSize = in.readUInt16();
1206        uint32 vertexCount = in.readUInt32();
1207
1208        GLenum mode = 0;
1209        switch(type)
1210        {
1211        case TRIANGLE_STRIP:
1212            mode = osg::PrimitiveSet::TRIANGLE_STRIP;
1213            break;
1214        case TRIANGLE_FAN:
1215            mode = osg::PrimitiveSet::TRIANGLE_FAN;
1216            break;
1217        case QUADRILATERAL_STRIP:
1218            mode = osg::PrimitiveSet::QUAD_STRIP;
1219            break;
1220        case INDEXED_POLYGON:
1221            mode = osg::PrimitiveSet::POLYGON;
1222            break;
1223        }
1224
1225        osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
1226        geometry->addPrimitiveSet(new osg::DrawArrays(mode,0,vertexCount));
1227
1228        for (unsigned int n=0; n<vertexCount; n++)
1229        {
1230            unsigned int index = 0;
1231            switch (indexSize)
1232            {
1233            case 1:
1234                index = in.readUInt8();
1235                break;
1236            case 2:
1237                index = in.readUInt16();
1238                break;
1239            case 4:
1240                index = in.readUInt32();
1241                break;
1242            }
1243           
1244            if (index < vertexList->size())
1245            {
1246                Vertex& vertex = (*vertexList)[index];
1247
1248                osg::Vec3Array* vertices = getOrCreateVertexArray(*geometry);
1249                vertices->push_back(vertex._coord);
1250
1251                if (vertex.validColor())
1252                {
1253                    osg::Vec4Array* colors = getOrCreateColorArray(*geometry);
1254                    colors->push_back(vertex._color);
1255                }
1256
1257                if (vertex.validNormal())
1258                {
1259                    osg::Vec3Array* normals = getOrCreateNormalArray(*geometry);
1260                    normals->push_back(vertex._normal);
1261                }
1262
1263                for (int layer=0; layer<Vertex::MAX_LAYERS; layer++)
1264                {
1265                    if (vertex.validUV(layer))
1266                    {
1267                        osg::Vec2Array* UVs = getOrCreateTextureArray(*geometry,layer);
1268                        UVs->push_back(vertex._uv[layer]);
1269                    }
1270                }
1271            }
1272        }
1273
1274        // Color binding
1275        if (mesh->isGouraud())
1276        {
1277            // Color per vertex
1278            geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
1279        }
1280        else
1281        {
1282            // Color per face
1283            osg::Vec4 col = mesh->getPrimaryColor();
1284            col[3] = 1.0f - mesh->getTransparency();
1285
1286            geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
1287            osg::Vec4Array* colors = new osg::Vec4Array(1);
1288            (*colors)[0] = col;
1289            geometry->setColorArray(colors);
1290        }
1291
1292        // Normal binding
1293        if (mesh->isLit())
1294        {
1295            geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX );
1296        }
1297        else
1298        {
1299            geometry->setNormalBinding(osg::Geometry::BIND_OFF);
1300            geometry->setNormalArray(NULL);
1301        }
1302
1303        mesh->addGeometry(*geometry);
1304
1305    }
1306};
1307
1308RegisterRecordProxy<MeshPrimitive> g_MeshPrimitive(MESH_PRIMITIVE_OP);
1309
1310
1311} // end namespace
1312
1313
1314
Note: See TracBrowser for help on using the browser.