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