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