/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * OpenSceneGraph Public License for more details. */ // // OpenFlightŪ loader for OpenSceneGraph // // Copyright (C) 2005-2007 Brede Johansen // #include #include #include #include #include #include #include #include #include "Registry.h" #include "Document.h" #include "RecordInputStream.h" namespace flt { /* Face record */ class Face : public PrimaryRecord { // flags static const unsigned int TERRAIN_BIT = 0x80000000u >> 0; static const unsigned int NO_COLOR_BIT = 0x80000000u >> 1; static const unsigned int NO_ALT_COLOR_BIT = 0x80000000u >> 2; static const unsigned int PACKED_COLOR_BIT = 0x80000000u >> 3; static const unsigned int FOOTPRINT_BIT = 0x80000000u >> 4; // Terrain culture cutout static const unsigned int HIDDEN_BIT = 0x80000000u >> 5; static const unsigned int ROOFLINE_BIT = 0x80000000u >> 6; osg::Vec4 _primaryColor; uint8 _drawFlag; uint8 _template; uint16 _transparency; uint32 _flags; uint8 _lightMode; osg::ref_ptr _geode; osg::ref_ptr _geometry; public: Face() : _primaryColor(1,1,1,1), _drawFlag(SOLID_NO_BACKFACE), _template(FIXED_NO_ALPHA_BLENDING), _transparency(0), _flags(0), _lightMode(FACE_COLOR) { } META_Record(Face) META_setID(_geode) META_setComment(_geode) META_setMultitexture(_geode) // draw mode enum DrawMode { SOLID_BACKFACED = 0, SOLID_NO_BACKFACE = 1, WIREFRAME_CLOSED = 2, WIREFRAME_NOT_CLOSED = 3, SURROUND_ALTERNATE_COLOR = 4, OMNIDIRECTIONAL_LIGHT = 8, UNIDIRECTIONAL_LIGHT = 9, BIDIRECTIONAL_LIGHT = 10 }; inline DrawMode getDrawMode() const { return (DrawMode)_drawFlag; } // lighting enum LightMode { FACE_COLOR = 0, VERTEX_COLOR = 1, FACE_COLOR_LIGHTING = 2, VERTEX_COLOR_LIGHTING = 3 }; inline LightMode getLightMode() const { return (LightMode)_lightMode; } inline bool isLit() const { return (_lightMode==FACE_COLOR_LIGHTING) || (_lightMode==VERTEX_COLOR_LIGHTING); } inline bool isGouraud() const { return (_lightMode==VERTEX_COLOR) || (_lightMode==VERTEX_COLOR_LIGHTING); } // flags inline bool noColor() const { return (_flags & NO_COLOR_BIT)!=0; } inline bool isHidden() const { return (_flags & HIDDEN_BIT)!=0; } inline bool isTerrain() const { return (_flags & TERRAIN_BIT)!=0; } inline bool isFootprint() const { return (_flags & FOOTPRINT_BIT)!=0; } inline bool isRoofline() const { return (_flags & ROOFLINE_BIT)!=0; } inline bool packedColorMode() const { return (_flags & PACKED_COLOR_BIT)!=0; } // billboard enum TemplateMode { FIXED_NO_ALPHA_BLENDING = 0, FIXED_ALPHA_BLENDING = 1, AXIAL_ROTATE_WITH_ALPHA_BLENDING = 2, POINT_ROTATE_WITH_ALPHA_BLENDING = 4 }; inline TemplateMode getTemplateMode() const { return (TemplateMode)_template; } // transparency & alpha inline bool isAlphaBlend() const { return (_template==FIXED_ALPHA_BLENDING) || (_template==AXIAL_ROTATE_WITH_ALPHA_BLENDING) || (_template==POINT_ROTATE_WITH_ALPHA_BLENDING); } inline osg::Vec4 getPrimaryColor() const { return _primaryColor; } inline float getTransparency() const { return (float)_transparency / 65535.0f; } inline bool isTransparent() const { return _transparency > 0; } virtual void addChild(osg::Node& child) { // Add subface to parent. if (_parent.valid()) _parent->addChild(child); } virtual void addVertex(Vertex& vertex) { osg::Vec3Array* vertices = getOrCreateVertexArray(*_geometry); vertices->push_back(vertex._coord); if (isGouraud()) { osg::Vec4Array* colors = getOrCreateColorArray(*_geometry); if (vertex.validColor()) { colors->push_back(vertex._color); } else { // Use face color if vertex color is -1 in a gouraud polygon. // http://www.multigen-paradigm.com/ubb/Forum1/HTML/000967.html colors->push_back(_primaryColor); } } bool strict = false; // prepare for "strict" reader option. if (strict) { if (vertex.validNormal()) { osg::Vec3Array* normals = getOrCreateNormalArray(*_geometry); normals->push_back(vertex._normal); } } else { // Add normal only if lit. if (isLit()) { osg::Vec3Array* normals = getOrCreateNormalArray(*_geometry); if (vertex.validNormal()) normals->push_back(vertex._normal); else // if lit and no normal in Vertex { // Use previous normal if available. if (normals->empty()) normals->push_back(osg::Vec3(0,0,1)); else normals->push_back(normals->back()); } } } for (int layer=0; layerpush_back(vertex._uv[layer]); } } } virtual void addVertexUV(int unit, const osg::Vec2& uv) { osg::Vec2Array* UVs = getOrCreateTextureArray(*_geometry,unit); UVs->push_back(uv); } virtual void addMorphVertex(Vertex& vertex0, Vertex& /*vertex100*/) { osg::Vec3Array* vertices = getOrCreateVertexArray(*_geometry); vertices->push_back(vertex0._coord); if (isGouraud()) { osg::Vec4Array* colors = getOrCreateColorArray(*_geometry); if (vertex0.validColor()) { colors->push_back(vertex0._color); } else { // Use face color if vertex color is -1 in a gouraud polygon. // http://www.multigen-paradigm.com/ubb/Forum1/HTML/000967.html colors->push_back(_primaryColor); } } if (vertex0.validNormal()) { osg::Vec3Array* normals = getOrCreateNormalArray(*_geometry); normals->push_back(vertex0._normal); } for (int layer=0; layerpush_back(vertex0._uv[layer]); } } } protected: virtual void readRecord(RecordInputStream& in, Document& document) { std::string id = in.readString(8); /*int32 IRColor =*/ in.readInt32(); /*int16 relativePriority =*/ in.readInt16(); _drawFlag = in.readUInt8(SOLID_NO_BACKFACE); uint8 texturedWhite = in.readUInt8(); int16 primaryNameIndex = in.readInt16(-1); /*int16 secondaryNameIndex =*/ in.readInt16(-1); in.forward(1); _template = in.readUInt8(FIXED_NO_ALPHA_BLENDING); /*int detailTexture =*/ in.readInt16(-1); int textureIndex = in.readInt16(-1); int materialIndex = in.readInt16(-1); /*int16 surface =*/ in.readInt16(); /*int16 feature =*/ in.readInt16(); /*int32 IRMaterial =*/ in.readInt32(-1); _transparency = in.readUInt16(0); // version > 13 /*uint8 influenceLOD =*/ in.readUInt8(); /*uint8 linestyle =*/ in.readUInt8(); _flags = in.readUInt32(0); _lightMode = in.readUInt8(FACE_COLOR); in.forward(7); osg::Vec4 primaryPackedColor = in.readColor32(); osg::Vec4 secondaryPackedColor = in.readColor32(); // version >= VERSION_15_1 /*int textureMappingIndex =*/ in.readInt16(-1); in.forward(2); int primaryColorIndex = in.readInt32(-1); /*int alternateColorIndex =*/ in.readInt32(-1); // version >= 16 in.forward(2); int shaderIndex = in.readInt16(-1); // Create Geode or Billboard. switch (_template) { case AXIAL_ROTATE_WITH_ALPHA_BLENDING: { osg::Billboard* billboard = new osg::Billboard; billboard->setMode(osg::Billboard::AXIAL_ROT); _geode = billboard; } break; case POINT_ROTATE_WITH_ALPHA_BLENDING: { osg::Billboard* billboard = new osg::Billboard; billboard->setMode(osg::Billboard::POINT_ROT_WORLD); _geode = billboard; } break; default: _geode = new osg::Geode; } _geode->setDataVariance(osg::Object::STATIC); _geode->setName(id); _geometry = new osg::Geometry; _geometry->setDataVariance(osg::Object::STATIC); _geode->addDrawable(_geometry.get()); // StateSet osg::ref_ptr stateset = new osg::StateSet; // Hidden if (isHidden()) _geode->setNodeMask(0); // Face color if (texturedWhite!=0 && textureIndex>=0) { _primaryColor = osg::Vec4(1,1,1,1); } else { if (packedColorMode()) { _primaryColor = primaryPackedColor; } else { if (document.version() < VERSION_15_1) _primaryColor = document.getColorPool()->getColor(primaryNameIndex); else // >= VERSION_15_1 _primaryColor = document.getColorPool()->getColor(primaryColorIndex); } } // Lighting stateset->setMode(GL_LIGHTING, isLit() ? osg::StateAttribute::ON : osg::StateAttribute::OFF); // Material if (isLit() || materialIndex>=0) { // MaterialPool will return a "default" material if no material is defined for materialIndex. // http://www.multigen-paradigm.com/ubb/Forum1/HTML/000228.html osg::Vec4 col = _primaryColor; col.a() = 1.0f - getTransparency(); osg::Material* material = document.getOrCreateMaterialPool()->getOrCreateMaterial(materialIndex,col); stateset->setAttribute(material); } // Shaders if (shaderIndex >= 0) { ShaderPool* sp = document.getOrCreateShaderPool(); osg::Program* program = sp->get(shaderIndex); if (program) stateset->setAttributeAndModes(program, osg::StateAttribute::ON); } // Texture TexturePool* tp = document.getOrCreateTexturePool(); osg::StateSet* textureStateSet = tp->get(textureIndex); if (textureStateSet) { // Merge face stateset with texture stateset stateset->merge(*textureStateSet); } // Cull face switch(_drawFlag) { case SOLID_BACKFACED: // Enable backface culling { static osg::ref_ptr cullFace = new osg::CullFace(osg::CullFace::BACK); stateset->setAttributeAndModes(cullFace.get(), osg::StateAttribute::ON); break; } case SOLID_NO_BACKFACE: // Disable backface culling stateset->setMode(GL_CULL_FACE,osg::StateAttribute::OFF); break; } // Subface if (document.subfaceLevel() > 0) { stateset->setAttributeAndModes(document.getSubSurfacePolygonOffset(document.subfaceLevel()), osg::StateAttribute::ON); stateset->setAttribute(document.getSubSurfaceDepth()); stateset->setRenderBinDetails(document.subfaceLevel(),"RenderBin"); } _geode->setStateSet(stateset.get()); // Add to parent. if (_parent.valid()) _parent->addChild(*_geode); } osg::PrimitiveSet::Mode getPrimitiveSetMode(int numVertices) { switch(getDrawMode()) { case WIREFRAME_NOT_CLOSED: return osg::PrimitiveSet::LINE_STRIP; case WIREFRAME_CLOSED: return osg::PrimitiveSet::LINE_LOOP; case OMNIDIRECTIONAL_LIGHT: case UNIDIRECTIONAL_LIGHT: case BIDIRECTIONAL_LIGHT: return osg::PrimitiveSet::POINTS; default: break; } switch (numVertices) { case 1: return osg::PrimitiveSet::POINTS; case 2: return osg::PrimitiveSet::LINES; case 3: return osg::PrimitiveSet::TRIANGLES; case 4: return osg::PrimitiveSet::QUADS; default: break; } return osg::PrimitiveSet::POLYGON; } virtual void dispose(Document& document) { if (_geode.valid()) { // Insert transform(s) if (_matrix.valid()) { insertMatrixTransform(*_geode,*_matrix,_numberOfReplications); } // Add primitives, set bindings etc. for (unsigned int i=0; i<_geode->getNumDrawables(); ++i) { osg::Geometry* geometry = dynamic_cast(_geode->getDrawable(i)); if (geometry) { osg::Array* vertices = geometry->getVertexArray(); if (vertices) { GLint first = 0; GLsizei count = vertices->getNumElements(); osg::PrimitiveSet::Mode mode = getPrimitiveSetMode(count); geometry->addPrimitiveSet(new osg::DrawArrays(mode,first,count)); } // Color binding if (isGouraud()) { // Color per vertex geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX); } else { // Color per face osg::Vec4 col = getPrimaryColor(); col[3] = 1.0f - getTransparency(); geometry->setColorBinding(osg::Geometry::BIND_OVERALL); osg::Vec4Array* colors = new osg::Vec4Array(1); (*colors)[0] = col; geometry->setColorArray(colors); } // Normal binding if (isLit()) { geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX ); } else { geometry->setNormalBinding(osg::Geometry::BIND_OFF); geometry->setNormalArray(NULL); } } } osg::StateSet* stateset = _geode->getOrCreateStateSet(); // Translucent image? bool isImageTranslucent = false; if (document.getUseTextureAlphaForTransparancyBinning()) { for (unsigned int i=0; igetTextureAttributeList().size(); ++i) { osg::StateAttribute* sa = stateset->getTextureAttribute(i,osg::StateAttribute::TEXTURE); osg::Texture2D* texture = dynamic_cast(sa); if (texture) { osg::Image* image = texture->getImage(); if (image && image->isImageTranslucent()) isImageTranslucent = true; } } } // Transparent Material? bool isMaterialTransparent = false; osg::Material* material = dynamic_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); if (material) { isMaterialTransparent = material->getDiffuse(osg::Material::FRONT).a() < 0.99f; } // Enable alpha blend? if (isAlphaBlend() || isTransparent() || isImageTranslucent || isMaterialTransparent) { static osg::ref_ptr blendFunc = new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA); stateset->setAttributeAndModes(blendFunc.get(), osg::StateAttribute::ON); stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); } if (document.getUseBillboardCenter()) { // Set billboard rotation point to center of face. osg::Billboard* billboard = dynamic_cast(_geode.get()); if (billboard) { for (unsigned int i=0; igetNumDrawables(); ++i) { osg::BoundingBox bb = billboard->getDrawable(i)->getBound(); billboard->setPosition(i,bb.center()); osgUtil::TransformAttributeFunctor tf(osg::Matrix::translate(-bb.center())); billboard->getDrawable(i)->accept(tf); billboard->getDrawable(i)->dirtyBound(); } billboard->dirtyBound(); } } } } }; REGISTER_FLTRECORD(Face, FACE_OP) /** VertexList - * The VertexList is a leaf record. * Possible parents: Face, Mesh & LightPoint */ class VertexListRecord : public PrimaryRecord { public: VertexListRecord() {} META_Record(VertexListRecord) virtual void addVertex(Vertex& vertex) { // forward vertex to parent. if (_parent.valid()) _parent->addVertex(vertex); } virtual void addVertexUV(int layer,const osg::Vec2& uv) { // forward uv to parent. if (_parent.valid()) _parent->addVertexUV(layer,uv); } protected: virtual ~VertexListRecord() {} virtual void readRecord(RecordInputStream& in, Document& document) { VertexPool* vp = document.getVertexPool(); if (vp) { int vertices = (in.getRecordSize()-4) / 4; // Use the Vertex pool as a record stream. RecordInputStream inVP(vp->rdbuf()); for (int n=0; naddMorphVertex(_vertex0, _vertex100); break; case UNDEFINED: break; } } //virtual void addVertexUV(int layer,const osg::Vec2& uv) //{ // // forward uv to parent. // if (_parent.valid()) // _parent->addVertexUV(layer,uv); //} protected: virtual ~MorphVertexList() {} virtual void readRecord(RecordInputStream& in, Document& document) { VertexPool* vp = document.getVertexPool(); if (vp) { int vertices = (in.getRecordSize()-4) / 8; // Use the Vertex pool as a record stream. RecordInputStream inVP(vp->rdbuf()); for (int n=0; n> 0; static const unsigned int NO_COLOR_BIT = 0x80000000u >> 1; static const unsigned int NO_ALT_COLOR_BIT = 0x80000000u >> 2; static const unsigned int PACKED_COLOR_BIT = 0x80000000u >> 3; static const unsigned int FOOTPRINT_BIT = 0x80000000u >> 4; // Terrain culture cutout static const unsigned int HIDDEN_BIT = 0x80000000u >> 5; static const unsigned int ROOFLINE_BIT = 0x80000000u >> 6; osg::Vec4 _primaryColor; uint8 _drawFlag; uint8 _template; uint16 _transparency; uint32 _flags; uint8 _lightMode; osg::ref_ptr _geode; public: Mesh() : _primaryColor(1,1,1,1), _drawFlag(SOLID_NO_BACKFACE), _template(FIXED_NO_ALPHA_BLENDING), _transparency(0), _flags(0), _lightMode(FACE_COLOR) { } META_Record(Mesh) META_setID(_geode) META_setComment(_geode) META_setMultitexture(_geode) // draw mode enum DrawMode { SOLID_BACKFACED = 0, SOLID_NO_BACKFACE = 1, WIREFRAME_CLOSED = 2, WIREFRAME_NOT_CLOSED = 3, SURROUND_ALTERNATE_COLOR = 4, OMNIDIRECTIONAL_LIGHT = 8, UNIDIRECTIONAL_LIGHT = 9, BIDIRECTIONAL_LIGHT = 10 }; inline DrawMode getDrawMode() const { return (DrawMode)_drawFlag; } // lighting enum LightMode { FACE_COLOR = 0, VERTEX_COLOR = 1, FACE_COLOR_LIGHTING = 2, VERTEX_COLOR_LIGHTING = 3 }; inline LightMode getLightMode() const { return (LightMode)_lightMode; } inline bool isLit() const { return (_lightMode==FACE_COLOR_LIGHTING) || (_lightMode==VERTEX_COLOR_LIGHTING); } inline bool isGouraud() const { return (_lightMode==VERTEX_COLOR) || (_lightMode==VERTEX_COLOR_LIGHTING); } // flags inline bool noColor() const { return (_flags & NO_COLOR_BIT)!=0; } inline bool isHidden() const { return (_flags & HIDDEN_BIT)!=0; } inline bool isTerrain() const { return (_flags & TERRAIN_BIT)!=0; } inline bool isFootprint() const { return (_flags & FOOTPRINT_BIT)!=0; } inline bool isRoofline() const { return (_flags & ROOFLINE_BIT)!=0; } inline bool packedColorMode() const { return (_flags & PACKED_COLOR_BIT)!=0; } // billboard enum TemplateMode { FIXED_NO_ALPHA_BLENDING = 0, FIXED_ALPHA_BLENDING = 1, AXIAL_ROTATE_WITH_ALPHA_BLENDING = 2, POINT_ROTATE_WITH_ALPHA_BLENDING = 4 }; inline TemplateMode getTemplateMode() const { return (TemplateMode)_template; } // transparency & alpha inline bool isAlphaBlend() const { return (_template==FIXED_ALPHA_BLENDING) || (_template==AXIAL_ROTATE_WITH_ALPHA_BLENDING) || (_template==POINT_ROTATE_WITH_ALPHA_BLENDING); } inline osg::Vec4 getPrimaryColor() const { return _primaryColor; } inline float getTransparency() const { return (float)_transparency / 65535.0f; } inline bool isTransparent() const { return _transparency > 0; } virtual void addChild(osg::Node& child) { // Add subface to parent. if (_parent.valid()) _parent->addChild(child); } virtual void addGeometry(osg::Geometry& geometry) { _geode->addDrawable(&geometry); } protected: virtual void readRecord(RecordInputStream& in, Document& document) { std::string id = in.readString(8); in.forward(4); /*int32 IRColor =*/ in.readInt32(); /*int16 relativePriority =*/ in.readInt16(); _drawFlag = in.readUInt8(SOLID_NO_BACKFACE); uint8 texturedWhite = in.readUInt8(); int16 primaryNameIndex = in.readInt16(-1); /*int16 secondaryNameIndex =*/ in.readInt16(-1); in.forward(1); _template = in.readUInt8(FIXED_NO_ALPHA_BLENDING); /*int detailTexture =*/ in.readInt16(-1); int textureIndex = in.readInt16(-1); int materialIndex = in.readInt16(-1); /*int16 surface =*/ in.readInt16(); /*int16 feature =*/ in.readInt16(); /*int32 IRMaterial =*/ in.readInt32(-1); _transparency = in.readUInt16(0); // version > 13 /*uint8 influenceLOD =*/ in.readUInt8(); /*uint8 linestyle =*/ in.readUInt8(); _flags = in.readUInt32(0); _lightMode = in.readUInt8(FACE_COLOR); in.forward(7); osg::Vec4 primaryPackedColor = in.readColor32(); osg::Vec4 secondaryPackedColor = in.readColor32(); // version >= VERSION_15_1 /*int textureMappingIndex =*/ in.readInt16(-1); in.forward(2); int primaryColorIndex = in.readInt32(-1); /*int alternateColorIndex =*/ in.readInt32(-1); // version >= 16 in.forward(2); int shaderIndex = in.readInt16(-1); // Create Geode or Billboard. switch (_template) { case AXIAL_ROTATE_WITH_ALPHA_BLENDING: { osg::Billboard* billboard = new osg::Billboard; billboard->setMode(osg::Billboard::AXIAL_ROT); _geode = billboard; } break; case POINT_ROTATE_WITH_ALPHA_BLENDING: { osg::Billboard* billboard = new osg::Billboard; billboard->setMode(osg::Billboard::POINT_ROT_WORLD); _geode = billboard; } break; default: _geode = new osg::Geode; } _geode->setDataVariance(osg::Object::STATIC); _geode->setName(id); // StateSet osg::ref_ptr stateset = new osg::StateSet; // Hidden if (isHidden()) _geode->setNodeMask(0); // Face color if (texturedWhite!=0 && textureIndex>=0) { _primaryColor = osg::Vec4(1,1,1,1); } else { if (packedColorMode()) { _primaryColor = primaryPackedColor; } else { if (document.version() < VERSION_15_1) _primaryColor = document.getColorPool()->getColor(primaryNameIndex); else // >= VERSION_15_1 _primaryColor = document.getColorPool()->getColor(primaryColorIndex); } } // Lighting stateset->setMode(GL_LIGHTING, isLit() ? osg::StateAttribute::ON : osg::StateAttribute::OFF); // Material if (isLit() || materialIndex>=0) { // MaterialPool will return a "default" material if no material is defined for materialIndex. // http://www.multigen-paradigm.com/ubb/Forum1/HTML/000228.html osg::Vec4 col = _primaryColor; col.a() = 1.0f - getTransparency(); osg::Material* material = document.getOrCreateMaterialPool()->getOrCreateMaterial(materialIndex,col); stateset->setAttribute(material); } // Shaders if (shaderIndex >= 0) { ShaderPool* sp = document.getOrCreateShaderPool(); osg::Program* program = sp->get(shaderIndex); if (program) stateset->setAttributeAndModes(program, osg::StateAttribute::ON); } // Texture TexturePool* tp = document.getOrCreateTexturePool(); osg::StateSet* textureStateSet = tp->get(textureIndex); if (textureStateSet) { // Merge face stateset with texture stateset stateset->merge(*textureStateSet); } // Cull face switch(_drawFlag) { case SOLID_BACKFACED: // Enable backface culling { static osg::ref_ptr cullFace = new osg::CullFace(osg::CullFace::BACK); stateset->setAttributeAndModes(cullFace.get(), osg::StateAttribute::ON); break; } case SOLID_NO_BACKFACE: // Disable backface culling stateset->setMode(GL_CULL_FACE,osg::StateAttribute::OFF); break; } // Subface if (document.subfaceLevel() > 0) { stateset->setAttributeAndModes(document.getSubSurfacePolygonOffset(document.subfaceLevel()), osg::StateAttribute::ON); stateset->setAttribute(document.getSubSurfaceDepth()); stateset->setRenderBinDetails(document.subfaceLevel(),"RenderBin"); } _geode->setStateSet(stateset.get()); // Add to parent. if (_parent.valid()) _parent->addChild(*_geode); } virtual void dispose(Document& document) { if (_geode.valid()) { // Insert transform(s) if (_matrix.valid()) { insertMatrixTransform(*_geode,*_matrix,_numberOfReplications); } osg::StateSet* stateset = _geode->getOrCreateStateSet(); // Translucent image? bool isImageTranslucent = false; if (document.getUseTextureAlphaForTransparancyBinning()) { for (unsigned int i=0; igetTextureAttributeList().size(); ++i) { osg::StateAttribute* sa = stateset->getTextureAttribute(i,osg::StateAttribute::TEXTURE); osg::Texture2D* texture = dynamic_cast(sa); if (texture) { osg::Image* image = texture->getImage(); if (image && image->isImageTranslucent()) isImageTranslucent = true; } } } // Transparent Material? bool isMaterialTransparent = false; osg::Material* material = dynamic_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); if (material) { isMaterialTransparent = material->getDiffuse(osg::Material::FRONT).a() < 0.99f; } // Enable alpha blend? if (isAlphaBlend() || isTransparent() || isImageTranslucent || isMaterialTransparent) { static osg::ref_ptr blendFunc = new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA); stateset->setAttributeAndModes(blendFunc.get(), osg::StateAttribute::ON); stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); } if (document.getUseBillboardCenter()) { // Set billboard rotation point to center of face. osg::Billboard* billboard = dynamic_cast(_geode.get()); if (billboard) { for (unsigned int i=0; igetNumDrawables(); ++i) { osg::BoundingBox bb = billboard->getDrawable(i)->getBound(); billboard->setPosition(i,bb.center()); osgUtil::TransformAttributeFunctor tf(osg::Matrix::translate(-bb.center())); billboard->getDrawable(i)->accept(tf); billboard->getDrawable(i)->dirtyBound(); } billboard->dirtyBound(); } } } } }; REGISTER_FLTRECORD(Mesh, MESH_OP) /** LocalVertexPool - */ class LocalVertexPool : public Record { // Attribute Mask static const unsigned int HAS_POSITION = 0x80000000u >> 0; static const unsigned int HAS_COLOR_INDEX = 0x80000000u >> 1; static const unsigned int HAS_RGBA_COLOR = 0x80000000u >> 2; static const unsigned int HAS_NORMAL = 0x80000000u >> 3; static const unsigned int HAS_BASE_UV = 0x80000000u >> 4; static const unsigned int HAS_UV_LAYER1 = 0x80000000u >> 5; static const unsigned int HAS_UV_LAYER2 = 0x80000000u >> 6; static const unsigned int HAS_UV_LAYER3 = 0x80000000u >> 7; static const unsigned int HAS_UV_LAYER4 = 0x80000000u >> 8; static const unsigned int HAS_UV_LAYER5 = 0x80000000u >> 9; static const unsigned int HAS_UV_LAYER6 = 0x80000000u >> 10; static const unsigned int HAS_UV_LAYER7 = 0x80000000u >> 11; public: LocalVertexPool() {} META_Record(LocalVertexPool) protected: virtual ~LocalVertexPool() {} virtual void readRecord(RecordInputStream& in, Document& document) { uint32 vertices = in.readUInt32(); uint32 mask = in.readUInt32(); osg::ref_ptr _vertexList = new VertexList(vertices); for (unsigned int n=0; n> 24; osg::Vec4 color = document.getColorPool()->getColor(index); color.a() = (float)alpha/255; vertex.setColor(color); if (!color.valid()) { osg::notify(osg::NOTICE)<<"Warning: data error detected in LocalVertexPool::readRecord color="<> layer)) { osg::Vec2f uv = in.readVec2f(); vertex.setUV(layer,uv); if (!uv.valid()) { osg::notify(osg::NOTICE)<<"Warning: data error detected in LocalVertexPool::readRecord uv="<setLocalVertexPool(_vertexList.get()); } }; REGISTER_FLTRECORD(LocalVertexPool, LOCAL_VERTEX_POOL_OP) /** MeshPrimitive - */ class MeshPrimitive : public PrimaryRecord { enum PrimitiveType { TRIANGLE_STRIP = 1, TRIANGLE_FAN = 2, QUADRILATERAL_STRIP = 3, INDEXED_POLYGON = 4 }; public: MeshPrimitive() {} META_Record(MeshPrimitive) protected: virtual ~MeshPrimitive() {} virtual void readRecord(RecordInputStream& in, Document& /*document*/) { Mesh* mesh = dynamic_cast(_parent.get()); if (!mesh) return; VertexList* vertexList = mesh->getLocalVertexPool(); if (!vertexList) return; int16 type = in.readInt16(); uint16 indexSize = in.readUInt16(); uint32 vertexCount = in.readUInt32(); GLenum mode = 0; switch(type) { case TRIANGLE_STRIP: mode = osg::PrimitiveSet::TRIANGLE_STRIP; break; case TRIANGLE_FAN: mode = osg::PrimitiveSet::TRIANGLE_FAN; break; case QUADRILATERAL_STRIP: mode = osg::PrimitiveSet::QUAD_STRIP; break; case INDEXED_POLYGON: mode = osg::PrimitiveSet::POLYGON; break; } osg::ref_ptr geometry = new osg::Geometry; geometry->addPrimitiveSet(new osg::DrawArrays(mode,0,vertexCount)); for (unsigned int n=0; nsize()) { Vertex& vertex = (*vertexList)[index]; osg::Vec3Array* vertices = getOrCreateVertexArray(*geometry); vertices->push_back(vertex._coord); if (vertex.validColor()) { osg::Vec4Array* colors = getOrCreateColorArray(*geometry); colors->push_back(vertex._color); } if (vertex.validNormal()) { osg::Vec3Array* normals = getOrCreateNormalArray(*geometry); normals->push_back(vertex._normal); } for (int layer=0; layerpush_back(vertex._uv[layer]); } } } } // Color binding if (mesh->isGouraud()) { // Color per vertex geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX); } else { // Color per face osg::Vec4 col = mesh->getPrimaryColor(); col[3] = 1.0f - mesh->getTransparency(); geometry->setColorBinding(osg::Geometry::BIND_OVERALL); osg::Vec4Array* colors = new osg::Vec4Array(1); (*colors)[0] = col; geometry->setColorArray(colors); } // Normal binding if (mesh->isLit()) { geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX ); } else { geometry->setNormalBinding(osg::Geometry::BIND_OFF); geometry->setNormalArray(NULL); } mesh->addGeometry(*geometry); } }; REGISTER_FLTRECORD(MeshPrimitive, MESH_PRIMITIVE_OP) } // end namespace