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