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 di=0; di<geode->getNumDrawables(); ++di)
70     {
71         const osg::Geometry* geometry = dynamic_cast<const osg::Geometry*>(geode->getDrawable(di));
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 pi = 0; pi < geom->getNumPrimitiveSets( ); ++pi )
79             {
80                 osg::DrawArrays* drawarray = dynamic_cast<osg::DrawArrays*>( geom->getPrimitiveSet( pi ) );
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         // terrain
479         if (document.getPreserveNonOsgAttrsAsUserData() && 0 != isTerrain())
480         {
481           _geometry->setUserValue("<UA:Terrain>", true);
482         }
483 
484         // roofline
485         if (document.getPreserveNonOsgAttrsAsUserData() && 0 != isRoofline())
486         {
487           _geometry->setUserValue("<UA:Roofline>", true);
488         }
489 
490         // footprint
491         if (document.getPreserveNonOsgAttrsAsUserData() && 0 != isFootprint())
492         {
493           _geometry->setUserValue("<UA:Footprint>", true);
494         }
495 
496         // Shaders
497         if (shaderIndex >= 0)
498         {
499             ShaderPool* sp = document.getOrCreateShaderPool();
500             osg::Program* program = sp->get(shaderIndex);
501             if (program)
502                 stateset->setAttributeAndModes(program, osg::StateAttribute::ON);
503         }
504 
505          // Texture
506         TexturePool* tp = document.getOrCreateTexturePool();
507         osg::StateSet* textureStateSet = tp->get(textureIndex);
508         if (textureStateSet)
509         {
510             // Merge face stateset with texture stateset
511             stateset->merge(*textureStateSet);
512         }
513 
514         // Cull face
515         switch(_drawFlag)
516         {
517         case SOLID_BACKFACED:     // Enable backface culling
518         {
519             static osg::ref_ptr<osg::CullFace> cullFace = new osg::CullFace(osg::CullFace::BACK);
520             stateset->setAttributeAndModes(cullFace.get(), osg::StateAttribute::ON);
521             break;
522         }
523         case SOLID_NO_BACKFACE:   // Disable backface culling
524             if( document.getReplaceDoubleSidedPolys( ) )
525             {
526                 static osg::ref_ptr<osg::CullFace> cullFace = new osg::CullFace(osg::CullFace::BACK);
527                 stateset->setAttributeAndModes(cullFace.get(), osg::StateAttribute::ON);
528             }
529             else
530             {
531                 stateset->setMode(GL_CULL_FACE,osg::StateAttribute::OFF);
532             }
533             break;
534         }
535 
536         // Subface
537         if (document.subfaceLevel() > 0)
538         {
539             stateset->setAttributeAndModes(document.getSubSurfacePolygonOffset(document.subfaceLevel()), osg::StateAttribute::ON);
540             stateset->setAttribute(document.getSubSurfaceDepth());
541 
542             stateset->setRenderBinDetails(document.subfaceLevel(),"RenderBin");
543         }
544 
545         _geode->setStateSet(stateset.get());
546 
547         // Add to parent.
548         if (_parent.valid())
549             _parent->addChild(*_geode);
550     }
551 
getPrimitiveSetMode(int numVertices)552     osg::PrimitiveSet::Mode getPrimitiveSetMode(int numVertices)
553     {
554         switch(getDrawMode())
555         {
556             case WIREFRAME_NOT_CLOSED:
557                 return osg::PrimitiveSet::LINE_STRIP;
558             case WIREFRAME_CLOSED:
559                 return osg::PrimitiveSet::LINE_LOOP;
560             case OMNIDIRECTIONAL_LIGHT:
561             case UNIDIRECTIONAL_LIGHT:
562             case BIDIRECTIONAL_LIGHT:
563                 return osg::PrimitiveSet::POINTS;
564             default: break;
565         }
566 
567         switch (numVertices)
568         {
569             case 1: return osg::PrimitiveSet::POINTS;
570             case 2: return osg::PrimitiveSet::LINES;
571             case 3: return osg::PrimitiveSet::TRIANGLES;
572             case 4: return osg::PrimitiveSet::QUADS;
573             default: break;
574         }
575 
576         return osg::PrimitiveSet::POLYGON;
577     }
578 
dispose(Document & document)579     virtual void dispose(Document& document)
580     {
581         if (_geode.valid())
582         {
583             // Insert transform(s)
584             if (_matrix.valid())
585             {
586                 insertMatrixTransform(*_geode,*_matrix,_numberOfReplications);
587             }
588 
589             // Add primitives, set bindings etc.
590             for (unsigned int i=0; i<_geode->getNumDrawables(); ++i)
591             {
592                 osg::Geometry* geometry = dynamic_cast<osg::Geometry*>(_geode->getDrawable(i));
593                 if (geometry)
594                 {
595                     osg::Array* vertices = geometry->getVertexArray();
596                     if (vertices)
597                     {
598                         GLint first = 0;
599                         GLsizei count = vertices->getNumElements();
600                         osg::PrimitiveSet::Mode mode = getPrimitiveSetMode(count);
601                         geometry->addPrimitiveSet(new osg::DrawArrays(mode,first,count));
602                     }
603 
604                     // Color binding
605                     if (isGouraud())
606                     {
607                         // Color per vertex
608                         if (geometry->getColorArray()) geometry->getColorArray()->setBinding(osg::Array::BIND_PER_VERTEX);
609                     }
610                     else
611                     {
612                         // Color per face
613                         osg::Vec4 col = getPrimaryColor();
614                         col[3] = 1.0f - getTransparency();
615 
616                         osg::Vec4Array* colors = new osg::Vec4Array(1);
617                         (*colors)[0] = col;
618                         geometry->setColorArray(colors, osg::Array::BIND_OVERALL);
619                     }
620 
621                     // Normal binding
622                     if (isLit())
623                     {
624                         if (geometry->getNormalArray()) geometry->getNormalArray()->setBinding(osg::Array::BIND_PER_VERTEX);
625                     }
626                     else
627                     {
628                         geometry->setNormalArray(0);
629                     }
630                 }
631             }
632 
633             if( getDrawMode( ) == SOLID_NO_BACKFACE && document.getReplaceDoubleSidedPolys( ) )
634             {
635                 addDrawableAndReverseWindingOrder( _geode.get() );
636             }
637 
638             osg::StateSet* stateset =  _geode->getOrCreateStateSet();
639 
640             // Translucent image?
641             bool isImageTranslucent = false;
642             if (document.getUseTextureAlphaForTransparancyBinning())
643             {
644                 for (unsigned int i=0; i<stateset->getTextureAttributeList().size(); ++i)
645                 {
646                     osg::StateAttribute* sa = stateset->getTextureAttribute(i,osg::StateAttribute::TEXTURE);
647                     osg::Texture2D* texture = dynamic_cast<osg::Texture2D*>(sa);
648                     if (texture)
649                     {
650                         osg::Image* image = texture->getImage();
651                         if (image && image->isImageTranslucent())
652                             isImageTranslucent = true;
653                     }
654                 }
655             }
656 
657             // Transparent Material?
658             bool isMaterialTransparent = false;
659             osg::Material* material = dynamic_cast<osg::Material*>(stateset->getAttribute(osg::StateAttribute::MATERIAL));
660             if (material)
661             {
662                 isMaterialTransparent = material->getDiffuse(osg::Material::FRONT).a() < 0.99f;
663             }
664 
665             // Enable alpha blend?
666             if (isAlphaBlend() || isTransparent() || isImageTranslucent || isMaterialTransparent)
667             {
668                 static osg::ref_ptr<osg::BlendFunc> blendFunc = new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA);
669                 stateset->setAttributeAndModes(blendFunc.get(), osg::StateAttribute::ON);
670                 stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
671             }
672 
673             if (document.getUseBillboardCenter())
674             {
675                 // Set billboard rotation point to center of face.
676                 osg::Billboard* billboard = dynamic_cast<osg::Billboard*>(_geode.get());
677                 if (billboard)
678                 {
679                     for (unsigned int i=0; i<billboard->getNumDrawables(); ++i)
680                     {
681                         const osg::BoundingBox& bb = billboard->getDrawable(i)->getBoundingBox();
682                         billboard->setPosition(i,bb.center());
683 
684                         osgUtil::TransformAttributeFunctor tf(osg::Matrix::translate(-bb.center()));
685                         billboard->getDrawable(i)->accept(tf);
686 
687                         billboard->getDrawable(i)->dirtyBound();
688                     }
689 
690                     billboard->dirtyBound();
691                 }
692             }
693         }
694     }
695 };
696 
697 REGISTER_FLTRECORD(Face, FACE_OP)
698 
699 
700 
701 /** VertexList -
702   * The VertexList is a leaf record.
703   * Possible parents: Face, Mesh & LightPoint
704   */
705 class VertexListRecord : public PrimaryRecord
706 {
707 public:
708 
VertexListRecord()709     VertexListRecord() {}
710 
META_Record(VertexListRecord)711     META_Record(VertexListRecord)
712 
713     virtual void addVertex(Vertex& vertex)
714     {
715         // forward vertex to parent.
716         if (_parent.valid())
717             _parent->addVertex(vertex);
718     }
719 
addVertexUV(int layer,const osg::Vec2 & uv)720     virtual void addVertexUV(int layer,const osg::Vec2& uv)
721     {
722         // forward uv to parent.
723         if (_parent.valid())
724             _parent->addVertexUV(layer,uv);
725     }
726 
727 protected:
728 
~VertexListRecord()729     virtual ~VertexListRecord() {}
730 
readRecord(RecordInputStream & in,Document & document)731     virtual void readRecord(RecordInputStream& in, Document& document)
732     {
733         VertexPool* vp = document.getVertexPool();
734         if (vp)
735         {
736             int vertices = (in.getRecordSize()-4) / 4;
737 
738             // Use the Vertex pool as a record stream.
739             RecordInputStream inVP(vp->rdbuf());
740             for (int n=0; n<vertices; n++)
741             {
742                 // Get position of vertex.
743                 uint32 pos = in.readUInt32();
744 
745                 // Get vertex from vertex pool.
746                 inVP.seekg((std::istream::pos_type)pos);
747                 inVP.readRecord(document);
748             }
749         }
750     }
751 };
752 
753 
754 REGISTER_FLTRECORD(VertexListRecord, VERTEX_LIST_OP)
755 
756 
757 
758 /** MorphVertexList -
759   * The MorphVertexList is a leaf record.
760   */
761 class MorphVertexList : public PrimaryRecord
762 {
763     enum Mode
764     {
765         UNDEFINED,
766         MORPH_0,
767         MORPH_100
768     };
769 
770     Mode _mode;
771     Vertex _vertex0;
772     Vertex _vertex100;
773 
774 public:
775 
MorphVertexList()776     MorphVertexList():
777         _mode(UNDEFINED)
778     {
779     }
780 
META_Record(MorphVertexList)781     META_Record(MorphVertexList)
782 
783     virtual void addVertex(Vertex& vertex)
784     {
785         switch (_mode)
786         {
787         case MORPH_0:
788             _vertex0 = vertex;
789             break;
790         case MORPH_100:
791             _vertex100 = vertex;
792 
793             // forward vertex to parent.
794             if (_parent.valid())
795                 _parent->addMorphVertex(_vertex0, _vertex100);
796             break;
797         case UNDEFINED:
798             break;
799         }
800     }
801 
802     //virtual void addVertexUV(int layer,const osg::Vec2& uv)
803     //{
804     //    // forward uv to parent.
805     //    if (_parent.valid())
806     //        _parent->addVertexUV(layer,uv);
807     //}
808 
809 protected:
810 
~MorphVertexList()811     virtual ~MorphVertexList() {}
812 
readRecord(RecordInputStream & in,Document & document)813     virtual void readRecord(RecordInputStream& in, Document& document)
814     {
815         VertexPool* vp = document.getVertexPool();
816         if (vp)
817         {
818             int vertices = (in.getRecordSize()-4) / 8;
819 
820             // Use the Vertex pool as a record stream.
821             RecordInputStream inVP(vp->rdbuf());
822             for (int n=0; n<vertices; n++)
823             {
824                 // Get position of vertex.
825                 uint32 offset0 = in.readUInt32();
826                 uint32 offset100 = in.readUInt32();
827 
828                 // Get vertex from vertex pool.
829 
830                 // 0%
831                 _mode = MORPH_0;
832                 inVP.seekg((std::istream::pos_type)offset0);
833                 inVP.readRecord(document);
834 
835                 // 100%
836                 _mode = MORPH_100;
837                 inVP.seekg((std::istream::pos_type)offset100);
838                 inVP.readRecord(document);
839             }
840         }
841     }
842 };
843 
844 REGISTER_FLTRECORD(MorphVertexList, MORPH_VERTEX_LIST_OP)
845 
846 
847 
848 /* Mesh record
849  */
850 class Mesh : public PrimaryRecord
851 {
852     // flags
853     static const unsigned int TERRAIN_BIT      = 0x80000000u >> 0;
854     static const unsigned int NO_COLOR_BIT     = 0x80000000u >> 1;
855     static const unsigned int NO_ALT_COLOR_BIT = 0x80000000u >> 2;
856     static const unsigned int PACKED_COLOR_BIT = 0x80000000u >> 3;
857     static const unsigned int FOOTPRINT_BIT    = 0x80000000u >> 4;    // Terrain culture cutout
858     static const unsigned int HIDDEN_BIT       = 0x80000000u >> 5;
859     static const unsigned int ROOFLINE_BIT     = 0x80000000u >> 6;
860 
861     osg::Vec4   _primaryColor;
862     uint8       _drawFlag;
863     uint8       _template;
864     uint16      _transparency;
865     uint32      _flags;
866     uint8       _lightMode;
867 
868     osg::ref_ptr<osg::Geode> _geode;
869 
870 public:
871 
Mesh()872     Mesh() :
873         _primaryColor(1,1,1,1),
874         _drawFlag(SOLID_NO_BACKFACE),
875         _template(FIXED_NO_ALPHA_BLENDING),
876         _transparency(0),
877         _flags(0),
878         _lightMode(FACE_COLOR)
879     {
880     }
881 
882     META_Record(Mesh)
883 
884     META_setID(_geode)
885     META_setComment(_geode)
886     META_setMultitexture(_geode)
887 
888     // draw mode
889     enum DrawMode
890     {
891         SOLID_BACKFACED = 0,
892         SOLID_NO_BACKFACE = 1,
893         WIREFRAME_CLOSED = 2,
894         WIREFRAME_NOT_CLOSED = 3,
895         SURROUND_ALTERNATE_COLOR = 4,
896         OMNIDIRECTIONAL_LIGHT = 8,
897         UNIDIRECTIONAL_LIGHT = 9,
898         BIDIRECTIONAL_LIGHT = 10
899     };
900 
getDrawMode() const901     inline DrawMode getDrawMode() const { return (DrawMode)_drawFlag; }
902 
903     // lighting
904     enum LightMode
905     {
906         FACE_COLOR = 0,
907         VERTEX_COLOR = 1,
908         FACE_COLOR_LIGHTING = 2,
909         VERTEX_COLOR_LIGHTING = 3
910     };
911 
getLightMode() const912     inline LightMode getLightMode() const { return (LightMode)_lightMode; }
isLit() const913     inline bool isLit() const { return (_lightMode==FACE_COLOR_LIGHTING) || (_lightMode==VERTEX_COLOR_LIGHTING); }
isGouraud() const914     inline bool isGouraud() const { return (_lightMode==VERTEX_COLOR) || (_lightMode==VERTEX_COLOR_LIGHTING); }
915 
916     // flags
noColor() const917     inline bool noColor()         const { return (_flags & NO_COLOR_BIT)!=0; }
isHidden() const918     inline bool isHidden()        const { return (_flags & HIDDEN_BIT)!=0; }
isTerrain() const919     inline bool isTerrain()       const { return (_flags & TERRAIN_BIT)!=0; }
isFootprint() const920     inline bool isFootprint()     const { return (_flags & FOOTPRINT_BIT)!=0; }
isRoofline() const921     inline bool isRoofline()      const { return (_flags & ROOFLINE_BIT)!=0; }
packedColorMode() const922     inline bool packedColorMode() const { return (_flags & PACKED_COLOR_BIT)!=0; }
923 
924     // billboard
925     enum TemplateMode
926     {
927         FIXED_NO_ALPHA_BLENDING = 0,
928         FIXED_ALPHA_BLENDING = 1,
929         AXIAL_ROTATE_WITH_ALPHA_BLENDING = 2,
930         POINT_ROTATE_WITH_ALPHA_BLENDING = 4
931     };
932 
getTemplateMode() const933     inline TemplateMode getTemplateMode() const { return (TemplateMode)_template; }
934 
935     // transparency & alpha
isAlphaBlend() const936     inline bool isAlphaBlend() const
937     {
938         return (_template==FIXED_ALPHA_BLENDING) ||
939                (_template==AXIAL_ROTATE_WITH_ALPHA_BLENDING) ||
940                (_template==POINT_ROTATE_WITH_ALPHA_BLENDING);
941     }
942 
getPrimaryColor() const943     inline osg::Vec4 getPrimaryColor() const { return _primaryColor; }
getTransparency() const944     inline float getTransparency() const { return (float)_transparency / 65535.0f; }
isTransparent() const945     inline bool isTransparent() const { return _transparency > 0; }
946 
addChild(osg::Node & child)947     virtual void addChild(osg::Node& child)
948     {
949         // Add subface to parent.
950         if (_parent.valid())
951             _parent->addChild(child);
952     }
953 
addGeometry(osg::Geometry & geometry)954     virtual void addGeometry(osg::Geometry& geometry)
955     {
956         _geode->addDrawable(&geometry);
957     }
958 
959 protected:
960 
readRecord(RecordInputStream & in,Document & document)961     virtual void readRecord(RecordInputStream& in, Document& document)
962     {
963         std::string id = in.readString(8);
964         in.forward(4);
965         int32 IRColor = in.readInt32();
966         /*int16 relativePriority =*/ in.readInt16();
967         _drawFlag = in.readUInt8(SOLID_NO_BACKFACE);
968         uint8 texturedWhite = in.readUInt8();
969         int16 primaryNameIndex = in.readInt16(-1);
970         /*int16 secondaryNameIndex =*/ in.readInt16(-1);
971         in.forward(1);
972         _template = in.readUInt8(FIXED_NO_ALPHA_BLENDING);
973         /*int detailTexture =*/ in.readInt16(-1);
974         int textureIndex = in.readInt16(-1);
975         int materialIndex = in.readInt16(-1);
976         int16 surface = in.readInt16();
977         int16 feature = in.readInt16();
978         int32 IRMaterial = in.readInt32(-1);
979         _transparency = in.readUInt16(0);
980         // version > 13
981         /*uint8 influenceLOD =*/ in.readUInt8();
982         /*uint8 linestyle =*/ in.readUInt8();
983         _flags = in.readUInt32(0);
984         _lightMode = in.readUInt8(FACE_COLOR);
985         in.forward(7);
986         osg::Vec4 primaryPackedColor = in.readColor32();
987         /*osg::Vec4 secondaryPackedColor =*/ in.readColor32();
988         // version >= VERSION_15_1
989         /*int textureMappingIndex =*/ in.readInt16(-1);
990         in.forward(2);
991         int primaryColorIndex = in.readInt32(-1);
992         /*int alternateColorIndex =*/ in.readInt32(-1);
993         // version >= 16
994         in.forward(2);
995         int shaderIndex = in.readInt16(-1);
996 
997         // Create Geode or Billboard.
998         switch (_template)
999         {
1000         case AXIAL_ROTATE_WITH_ALPHA_BLENDING:
1001             {
1002                 osg::Billboard* billboard = new osg::Billboard;
1003                 billboard->setMode(osg::Billboard::AXIAL_ROT);
1004                 _geode = billboard;
1005             }
1006             break;
1007         case POINT_ROTATE_WITH_ALPHA_BLENDING:
1008             {
1009                 osg::Billboard* billboard = new osg::Billboard;
1010                 billboard->setMode(osg::Billboard::POINT_ROT_WORLD);
1011                 _geode = billboard;
1012             }
1013             break;
1014         default:
1015             _geode = new osg::Geode;
1016         }
1017 
1018         _geode->setDataVariance(osg::Object::STATIC);
1019         _geode->setName(id);
1020 
1021         // StateSet
1022         osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet;
1023 
1024         // Hidden
1025         if (isHidden())
1026             _geode->setNodeMask(0);
1027 
1028         // Face color
1029         if (texturedWhite!=0 && textureIndex>=0)
1030         {
1031             _primaryColor = osg::Vec4(1,1,1,1);
1032         }
1033         else
1034         {
1035             if (packedColorMode())
1036             {
1037                 _primaryColor = primaryPackedColor;
1038             }
1039             else
1040             {
1041                 if (document.version() < VERSION_15_1)
1042                     _primaryColor = document.getColorPool()->getColor(primaryNameIndex);
1043 
1044                 else // >= VERSION_15_1
1045                     _primaryColor = document.getColorPool()->getColor(primaryColorIndex);
1046             }
1047         }
1048 
1049         // Lighting
1050         stateset->setMode(GL_LIGHTING, isLit() ? osg::StateAttribute::ON : osg::StateAttribute::OFF);
1051 
1052         // Material
1053         if (isLit() || materialIndex>=0)
1054         {
1055             // MaterialPool will return a "default" material if no material is defined for materialIndex.
1056             // http://www.multigen-paradigm.com/ubb/Forum1/HTML/000228.html
1057             osg::Vec4 col = _primaryColor;
1058             col.a() = 1.0f - getTransparency();
1059             osg::Material* material = document.getOrCreateMaterialPool()->getOrCreateMaterial(materialIndex,col);
1060             stateset->setAttribute(material);
1061         }
1062 
1063         // IRColor (IRC)
1064         if (document.getPreserveNonOsgAttrsAsUserData() && 0 != IRColor)
1065         {
1066           _geode->setUserValue("<UA:IRC>", IRColor);
1067         }
1068 
1069         // IR Material ID (IRM)
1070         if (document.getPreserveNonOsgAttrsAsUserData() && 0 != IRMaterial)
1071         {
1072           _geode->setUserValue("<UA:IRM>", IRMaterial);
1073         }
1074 
1075         // surface (SMC)
1076         if (document.getPreserveNonOsgAttrsAsUserData() && 0 != surface)
1077         {
1078           _geode->setUserValue("<UA:SMC>", surface);
1079         }
1080 
1081         // feature (FID)
1082         if (document.getPreserveNonOsgAttrsAsUserData() && 0 != feature)
1083         {
1084           _geode->setUserValue("<UA:FID>", feature);
1085         }
1086 
1087         // terrain
1088         if (document.getPreserveNonOsgAttrsAsUserData() && 0 != isTerrain())
1089         {
1090           _geode->setUserValue("<UA:Terrain>", true);
1091         }
1092 
1093         // roofline
1094         if (document.getPreserveNonOsgAttrsAsUserData() && 0 != isRoofline())
1095         {
1096           _geode->setUserValue("<UA:Roofline>", true);
1097         }
1098 
1099         // footprint
1100         if (document.getPreserveNonOsgAttrsAsUserData() && 0 != isFootprint())
1101         {
1102           _geode->setUserValue("<UA:Footprint>", true);
1103         }
1104 
1105         // Shaders
1106         if (shaderIndex >= 0)
1107         {
1108             ShaderPool* sp = document.getOrCreateShaderPool();
1109             osg::Program* program = sp->get(shaderIndex);
1110             if (program)
1111                 stateset->setAttributeAndModes(program, osg::StateAttribute::ON);
1112         }
1113 
1114          // Texture
1115         TexturePool* tp = document.getOrCreateTexturePool();
1116         osg::StateSet* textureStateSet = tp->get(textureIndex);
1117         if (textureStateSet)
1118         {
1119             // Merge face stateset with texture stateset
1120             stateset->merge(*textureStateSet);
1121         }
1122 
1123         // Cull face
1124         switch(_drawFlag)
1125         {
1126         case SOLID_BACKFACED:     // Enable backface culling
1127         {
1128             static osg::ref_ptr<osg::CullFace> cullFace = new osg::CullFace(osg::CullFace::BACK);
1129             stateset->setAttributeAndModes(cullFace.get(), osg::StateAttribute::ON);
1130             break;
1131         }
1132         case SOLID_NO_BACKFACE:   // Disable backface culling
1133             if( document.getReplaceDoubleSidedPolys( ) )
1134             {
1135                 static osg::ref_ptr<osg::CullFace> cullFace = new osg::CullFace(osg::CullFace::BACK);
1136                 stateset->setAttributeAndModes(cullFace.get(), osg::StateAttribute::ON);
1137             }
1138             else
1139             {
1140                 stateset->setMode(GL_CULL_FACE,osg::StateAttribute::OFF);
1141             }
1142             break;
1143         }
1144 
1145         // Subface
1146         if (document.subfaceLevel() > 0)
1147         {
1148             stateset->setAttributeAndModes(document.getSubSurfacePolygonOffset(document.subfaceLevel()), osg::StateAttribute::ON);
1149             stateset->setAttribute(document.getSubSurfaceDepth());
1150 
1151             stateset->setRenderBinDetails(document.subfaceLevel(),"RenderBin");
1152         }
1153 
1154         _geode->setStateSet(stateset.get());
1155 
1156         // Add to parent.
1157         if (_parent.valid())
1158             _parent->addChild(*_geode);
1159     }
1160 
dispose(Document & document)1161     virtual void dispose(Document& document)
1162     {
1163         if (_geode.valid())
1164         {
1165             // Insert transform(s)
1166             if (_matrix.valid())
1167             {
1168                 insertMatrixTransform(*_geode,*_matrix,_numberOfReplications);
1169             }
1170 
1171             if( getDrawMode( ) == SOLID_NO_BACKFACE && document.getReplaceDoubleSidedPolys( ) )
1172             {
1173                 addDrawableAndReverseWindingOrder( _geode.get() );
1174             }
1175 
1176             osg::StateSet* stateset =  _geode->getOrCreateStateSet();
1177 
1178             // Translucent image?
1179             bool isImageTranslucent = false;
1180             if (document.getUseTextureAlphaForTransparancyBinning())
1181             {
1182                 for (unsigned int i=0; i<stateset->getTextureAttributeList().size(); ++i)
1183                 {
1184                     osg::StateAttribute* sa = stateset->getTextureAttribute(i,osg::StateAttribute::TEXTURE);
1185                     osg::Texture2D* texture = dynamic_cast<osg::Texture2D*>(sa);
1186                     if (texture)
1187                     {
1188                         osg::Image* image = texture->getImage();
1189                         if (image && image->isImageTranslucent())
1190                             isImageTranslucent = true;
1191                     }
1192                 }
1193             }
1194 
1195             // Transparent Material?
1196             bool isMaterialTransparent = false;
1197             osg::Material* material = dynamic_cast<osg::Material*>(stateset->getAttribute(osg::StateAttribute::MATERIAL));
1198             if (material)
1199             {
1200                 isMaterialTransparent = material->getDiffuse(osg::Material::FRONT).a() < 0.99f;
1201             }
1202 
1203             // Enable alpha blend?
1204             if (isAlphaBlend() || isTransparent() || isImageTranslucent || isMaterialTransparent)
1205             {
1206                 static osg::ref_ptr<osg::BlendFunc> blendFunc = new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA);
1207                 stateset->setAttributeAndModes(blendFunc.get(), osg::StateAttribute::ON);
1208                 stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
1209             }
1210 
1211             if (document.getUseBillboardCenter())
1212             {
1213                 // Set billboard rotation point to center of face.
1214                 osg::Billboard* billboard = dynamic_cast<osg::Billboard*>(_geode.get());
1215                 if (billboard)
1216                 {
1217                     for (unsigned int i=0; i<billboard->getNumDrawables(); ++i)
1218                     {
1219                         const osg::BoundingBox& bb = billboard->getDrawable(i)->getBoundingBox();
1220                         billboard->setPosition(i,bb.center());
1221 
1222                         osgUtil::TransformAttributeFunctor tf(osg::Matrix::translate(-bb.center()));
1223                         billboard->getDrawable(i)->accept(tf);
1224 
1225                         billboard->getDrawable(i)->dirtyBound();
1226                     }
1227 
1228                     billboard->dirtyBound();
1229                 }
1230             }
1231         }
1232     }
1233 };
1234 
1235 REGISTER_FLTRECORD(Mesh, MESH_OP)
1236 
1237 
1238 
1239 
1240 /** LocalVertexPool -
1241   */
1242 class LocalVertexPool : public Record
1243 {
1244     // Attribute Mask
1245     static const unsigned int HAS_POSITION      = 0x80000000u >> 0;
1246     static const unsigned int HAS_COLOR_INDEX   = 0x80000000u >> 1;
1247     static const unsigned int HAS_RGBA_COLOR    = 0x80000000u >> 2;
1248     static const unsigned int HAS_NORMAL        = 0x80000000u >> 3;
1249     static const unsigned int HAS_BASE_UV       = 0x80000000u >> 4;
1250     static const unsigned int HAS_UV_LAYER1     = 0x80000000u >> 5;
1251     static const unsigned int HAS_UV_LAYER2     = 0x80000000u >> 6;
1252     static const unsigned int HAS_UV_LAYER3     = 0x80000000u >> 7;
1253     static const unsigned int HAS_UV_LAYER4     = 0x80000000u >> 8;
1254     static const unsigned int HAS_UV_LAYER5     = 0x80000000u >> 9;
1255     static const unsigned int HAS_UV_LAYER6     = 0x80000000u >> 10;
1256     static const unsigned int HAS_UV_LAYER7     = 0x80000000u >> 11;
1257 
1258 public:
1259 
LocalVertexPool()1260     LocalVertexPool() {}
1261 
1262     META_Record(LocalVertexPool)
1263 
1264 protected:
1265 
~LocalVertexPool()1266     virtual ~LocalVertexPool() {}
1267 
readRecord(RecordInputStream & in,Document & document)1268     virtual void readRecord(RecordInputStream& in, Document& document)
1269     {
1270 
1271         uint32 vertices = in.readUInt32();
1272         uint32 mask = in.readUInt32();
1273 
1274         osg::ref_ptr<VertexList> _vertexList = new VertexList(vertices);
1275 
1276 
1277         for (unsigned int n=0; n<vertices; n++)
1278         {
1279             Vertex vertex;
1280 
1281             if (mask & HAS_POSITION)
1282             {
1283                 osg::Vec3d coord = in.readVec3d();
1284                 vertex.setCoord(coord*document.unitScale());
1285 
1286                 if (!coord.valid())
1287                 {
1288                     OSG_NOTICE<<"Warning: data error detected in LocalVertexPool::readRecord coord="<<coord.x()<<" "<<coord.y()<<" "<<coord.z()<<std::endl;
1289                 }
1290             }
1291 
1292             if (mask & HAS_COLOR_INDEX)
1293             {
1294                 uint32 alphaIndex = in.readUInt32();
1295                 int index = alphaIndex & 0x00ffffff;
1296                 uint8 alpha = alphaIndex >> 24;
1297                 osg::Vec4 color = document.getColorPool()->getColor(index);
1298                 color.a() = (float)alpha/255;
1299                 vertex.setColor(color);
1300 
1301                 if (!color.valid())
1302                 {
1303                     OSG_NOTICE<<"Warning: data error detected in LocalVertexPool::readRecord color="<<color.r()<<" "<<color.g()<<" "<<color.b()<<" "<<color.a()<<std::endl;
1304                 }
1305             }
1306 
1307             if (mask & HAS_RGBA_COLOR)
1308             {
1309                 osg::Vec4f color = in.readColor32();
1310                 vertex.setColor(color);
1311 
1312                 if (!color.valid())
1313                 {
1314                     OSG_NOTICE<<"Warning: data error detected in LocalVertexPool::readRecord color="<<color.r()<<" "<<color.g()<<" "<<color.b()<<" "<<color.a()<<std::endl;
1315                 }
1316             }
1317 
1318             if (mask & HAS_NORMAL)
1319             {
1320                 osg::Vec3f normal = in.readVec3f();
1321                 vertex.setNormal(normal);
1322 
1323                 if (!normal.valid())
1324                 {
1325                     OSG_NOTICE<<"Warning: data error detected in LocalVertexPool::readRecord normal="<<normal.x()<<" "<<normal.y()<<" "<<normal.z()<<std::endl;
1326                 }
1327             }
1328 
1329             for (unsigned int layer=0; layer<8; layer++)
1330             {
1331                 if (mask & (HAS_BASE_UV >> layer))
1332                 {
1333                     osg::Vec2f uv = in.readVec2f();
1334                     vertex.setUV(layer,uv);
1335 
1336                     if (!uv.valid())
1337                     {
1338                         OSG_NOTICE<<"Warning: data error detected in LocalVertexPool::readRecord uv="<<uv.x()<<" "<<uv.y()<<std::endl;
1339                     }
1340 
1341                 }
1342             }
1343 
1344             (*_vertexList)[n] = vertex;
1345         }
1346 
1347         if (_parent.valid())
1348             _parent->setLocalVertexPool(_vertexList.get());
1349 
1350     }
1351 };
1352 
1353 REGISTER_FLTRECORD(LocalVertexPool, LOCAL_VERTEX_POOL_OP)
1354 
1355 
1356 
1357 
1358 /** MeshPrimitive -
1359   */
1360 class MeshPrimitive : public PrimaryRecord
1361 {
1362     enum PrimitiveType
1363     {
1364         TRIANGLE_STRIP = 1,
1365         TRIANGLE_FAN = 2,
1366         QUADRILATERAL_STRIP = 3,
1367         INDEXED_POLYGON = 4
1368     };
1369 
1370 public:
1371 
MeshPrimitive()1372     MeshPrimitive() {}
1373 
1374     META_Record(MeshPrimitive)
1375 
1376 protected:
1377 
~MeshPrimitive()1378     virtual ~MeshPrimitive() {}
1379 
readRecord(RecordInputStream & in,Document &)1380     virtual void readRecord(RecordInputStream& in, Document& /*document*/)
1381     {
1382         Mesh* mesh = dynamic_cast<Mesh*>(_parent.get());
1383         if (!mesh) return;
1384 
1385         VertexList* vertexList = mesh->getLocalVertexPool();
1386         if (!vertexList) return;
1387 
1388         int16 type = in.readInt16();
1389         uint16 indexSize = in.readUInt16();
1390         uint32 vertexCount = in.readUInt32();
1391 
1392         GLenum mode = 0;
1393         switch(type)
1394         {
1395         case TRIANGLE_STRIP:
1396             mode = osg::PrimitiveSet::TRIANGLE_STRIP;
1397             break;
1398         case TRIANGLE_FAN:
1399             mode = osg::PrimitiveSet::TRIANGLE_FAN;
1400             break;
1401         case QUADRILATERAL_STRIP:
1402             mode = osg::PrimitiveSet::QUAD_STRIP;
1403             break;
1404         case INDEXED_POLYGON:
1405             mode = osg::PrimitiveSet::POLYGON;
1406             break;
1407         }
1408 
1409         osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
1410         geometry->addPrimitiveSet(new osg::DrawArrays(mode,0,vertexCount));
1411 
1412         for (unsigned int n=0; n<vertexCount; n++)
1413         {
1414             unsigned int index = 0;
1415             switch (indexSize)
1416             {
1417             case 1:
1418                 index = in.readUInt8();
1419                 break;
1420             case 2:
1421                 index = in.readUInt16();
1422                 break;
1423             case 4:
1424                 index = in.readUInt32();
1425                 break;
1426             }
1427 
1428             if (index < vertexList->size())
1429             {
1430                 Vertex& vertex = (*vertexList)[index];
1431 
1432                 osg::Vec3Array* vertices = getOrCreateVertexArray(*geometry);
1433                 vertices->push_back(vertex._coord);
1434 
1435                 if (vertex.validColor())
1436                 {
1437                     osg::Vec4Array* colors = getOrCreateColorArray(*geometry);
1438                     colors->push_back(vertex._color);
1439                 }
1440 
1441                 if (vertex.validNormal())
1442                 {
1443                     osg::Vec3Array* normals = getOrCreateNormalArray(*geometry);
1444                     normals->push_back(vertex._normal);
1445                 }
1446 
1447                 for (int layer=0; layer<Vertex::MAX_LAYERS; layer++)
1448                 {
1449                     if (vertex.validUV(layer))
1450                     {
1451                         osg::Vec2Array* UVs = getOrCreateTextureArray(*geometry,layer);
1452                         UVs->push_back(vertex._uv[layer]);
1453                     }
1454                 }
1455             }
1456         }
1457 
1458         // Color binding
1459         if (mesh->isGouraud())
1460         {
1461             // Color per vertex
1462             if (geometry->getColorArray()) geometry->getColorArray()->setBinding(osg::Array::BIND_PER_VERTEX);
1463         }
1464         else
1465         {
1466             // Color per face
1467             osg::Vec4 col = mesh->getPrimaryColor();
1468             col[3] = 1.0f - mesh->getTransparency();
1469 
1470 
1471             osg::Vec4Array* colors = new osg::Vec4Array(1);
1472             (*colors)[0] = col;
1473             geometry->setColorArray(colors, osg::Array::BIND_OVERALL);
1474         }
1475 
1476         // Normal binding
1477         if (mesh->isLit())
1478         {
1479             if (geometry->getNormalArray()) geometry->getNormalArray()->setBinding(osg::Array::BIND_PER_VERTEX);
1480         }
1481         else
1482         {
1483             geometry->setNormalArray(0);
1484         }
1485 
1486         mesh->addGeometry(*geometry);
1487 
1488     }
1489 };
1490 
1491 REGISTER_FLTRECORD(MeshPrimitive, MESH_PRIMITIVE_OP)
1492 
1493 
1494 
1495 } // end namespace
1496 
1497 
1498 
1499 
1500