void FltExportVisitor::writeMesh( const osg::Geode& geode, const osg::Geometry& geom ) { enum DrawMode { SOLID_BACKFACE = 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 }; enum TemplateMode { FIXED_NO_ALPHA_BLENDING = 0, FIXED_ALPHA_BLENDING = 1, AXIAL_ROTATE_WITH_ALPHA_BLENDING = 2, POINT_ROTATE_WITH_ALPHA_BLENDING = 4 }; // const unsigned int TERRAIN_BIT = 0x80000000u >> 0; //const unsigned int NO_COLOR_BIT = 0x80000000u >> 1; //const unsigned int NO_ALT_COLOR_BIT = 0x80000000u >> 2; const unsigned int PACKED_COLOR_BIT = 0x80000000u >> 3; //const unsigned int FOOTPRINT_BIT = 0x80000000u >> 4; // Terrain culture cutout const unsigned int HIDDEN_BIT = 0x80000000u >> 5; //const unsigned int ROOFLINE_BIT = 0x80000000u >> 6; uint32 flags( PACKED_COLOR_BIT ); if (geode.getNodeMask() == 0) flags |= HIDDEN_BIT; enum LightMode { FACE_COLOR = 0, VERTEX_COLOR = 1, FACE_COLOR_LIGHTING = 2, VERTEX_COLOR_LIGHTING = 3 }; int8 lightMode; osg::Vec4 packedColorRaw( 1., 1., 1., 1. ); uint16 transparency( 0 ); if (geom.getColorBinding() == osg::Geometry::BIND_PER_VERTEX) { if (isLit( geom )) lightMode = VERTEX_COLOR_LIGHTING; else lightMode = VERTEX_COLOR; } else { const osg::Vec4Array* c = dynamic_cast<const osg::Vec4Array*>( geom.getColorArray() ); if (c && (c->size() > 0)) { packedColorRaw = (*c)[0]; transparency = flt::uint16((1. - packedColorRaw[3]) * (double)0xffff); } if (isLit( geom )) lightMode = FACE_COLOR_LIGHTING; else lightMode = FACE_COLOR; } uint32 packedColor; packedColor = (int)(packedColorRaw[3]*255) << 24 | (int)(packedColorRaw[2]*255) << 16 | (int)(packedColorRaw[1]*255) << 8 | (int)(packedColorRaw[0]*255); int8 drawType; osg::StateSet const* ss = getCurrentStateSet(); { // Default to no facet culling drawType = SOLID_NO_BACKFACE; // If facet-culling isn't *dis*abled, check whether the CullFace mode is BACK if (ss->getMode(GL_CULL_FACE) & osg::StateAttribute::ON) { osg::CullFace const* cullFace = static_cast<osg::CullFace const*>( ss->getAttribute(osg::StateAttribute::CULLFACE) ); if( cullFace->getMode() == osg::CullFace::BACK ) drawType = SOLID_BACKFACE; // Note: OpenFlt can't handle FRONT or FRONT_AND_BACK settings, so ignore these(??) } } // Determine the material properties for the face int16 materialIndex( -1 ); if (isLit( geom )) { osg::Material const* currMaterial = static_cast<osg::Material const*>( ss->getAttribute(osg::StateAttribute::MATERIAL) ); materialIndex = _materialPalette->add(currMaterial); } // Get base texture int16 textureIndex( -1 ); if (isTextured( 0, geom )) { const osg::Texture2D* texture = static_cast<const osg::Texture2D*>( ss->getTextureAttribute( 0, osg::StateAttribute::TEXTURE ) ); if (texture != NULL) textureIndex = _texturePalette->add( 0, texture ); else { std::string warning( "fltexp: Mesh is textured, but Texture2D StateAttribute is NULL." ); osg::notify( osg::WARN ) << warning << std::endl; _fltOpt->getWriteResult().warn( warning ); } } // Set the appropriate template mode based // on blending or Billboarding. TemplateMode templateMode( FIXED_NO_ALPHA_BLENDING ); const osg::Billboard* bb = dynamic_cast< const osg::Billboard* >( &geode ); if (bb != NULL) { if( bb->getMode() == osg::Billboard::AXIAL_ROT ) templateMode = AXIAL_ROTATE_WITH_ALPHA_BLENDING; else templateMode = POINT_ROTATE_WITH_ALPHA_BLENDING; } else if ( ss->getMode( GL_BLEND ) & osg::StateAttribute::ON ) { const osg::BlendFunc* bf = static_cast<const osg::BlendFunc*>( ss->getAttribute(osg::StateAttribute::BLENDFUNC) ); if( (bf->getSource() == osg::BlendFunc::SRC_ALPHA) && (bf->getDestination() == osg::BlendFunc::ONE_MINUS_SRC_ALPHA) ) templateMode = FIXED_ALPHA_BLENDING; } uint16 length( 84 ); IdHelper id( *this, geode.getName() ); _records->writeInt16( (int16) MESH_OP ); _records->writeUInt16( length ); _records->writeID( id ); _records->writeInt32( 0 ); // Reserved _records->writeInt32( 0 ); // IR color code _records->writeInt16( 0 ); // Relative priority _records->writeInt8( drawType ); // Draw type _records->writeInt8( 0 ); // Texture white _records->writeInt16( -1 ); // Color name index _records->writeInt16( -1 ); // Alternate color name index _records->writeInt8( 0 ); // Reserved _records->writeInt8( templateMode ); // Template (billboard) _records->writeInt16( -1 ); // Detail texture pattern index _records->writeInt16( textureIndex ); // Texture pattern index _records->writeInt16( materialIndex ); // Material index _records->writeInt16( 0 ); // Surface material code _records->writeInt16( 0 ); // Feature ID _records->writeInt32( 0 ); // IR material code _records->writeUInt16( transparency ); // Transparency _records->writeInt8( 0 ); // LOD generation control _records->writeInt8( 0 ); // Line style index _records->writeUInt32( flags ); // Flags _records->writeInt8( lightMode ); // Light mode _records->writeFill( 7 ); // Reserved _records->writeUInt32( packedColor ); // Packed color, primary _records->writeUInt32( 0x00ffffff ); // Packed color, alternate _records->writeInt16( -1 ); // Texture mapping index _records->writeInt16( 0 ); // Reserved _records->writeInt32( -1 ); // Primary color index _records->writeInt32( -1 ); // Alternate color index // Next four bytes: // 15.8: two 2-byte "reserved" fields // 15.9: one 4-byte "reserved" field _records->writeInt16( 0 ); // Reserved _records->writeInt16( -1 ); // Shader index }
void FltExportVisitor::writeLocalVertexPool( const osg::Geometry& geom ) { // 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; const osg::Array* v = geom.getVertexArray(); uint32 numVerts( v->getNumElements() ); osg::ref_ptr< const osg::Vec3dArray > v3 = VertexPaletteManager::asVec3dArray( v, numVerts ); if (!v3) { std::string warning( "fltexp: writeLocalVertexPool: VertexArray is not Vec3Array." ); osg::notify( osg::WARN ) << warning << std::endl; _fltOpt->getWriteResult().warn( warning ); return; } // Compute attribute bits and vertex size. const osg::Array* c = geom.getColorArray(); const osg::Array* n = geom.getNormalArray(); const osg::Array* t = geom.getTexCoordArray( 0 ); osg::ref_ptr< const osg::Vec4Array > c4 = VertexPaletteManager::asVec4Array( c, numVerts ); osg::ref_ptr< const osg::Vec3Array > n3 = VertexPaletteManager::asVec3Array( n, numVerts ); osg::ref_ptr< const osg::Vec2Array > t2 = VertexPaletteManager::asVec2Array( t, numVerts ); if (c && !c4) return; if (n && !n3) return; if (t && !t2) return; std::vector< osg::ref_ptr< const osg::Vec2Array > > mtc; mtc.resize( 8 ); int unit=1; for( ;unit<8; unit++) mtc[ unit ] = VertexPaletteManager::asVec2Array( geom.getTexCoordArray( unit ), numVerts ); uint32 attr( HAS_POSITION ); unsigned int vertSize( sizeof( float64 ) * 3 ); if ( ( c4 != NULL ) && ( geom.getColorBinding() == osg::Geometry::BIND_PER_VERTEX) ) { attr |= HAS_RGBA_COLOR; vertSize += sizeof( unsigned int ); } if ( ( n3 != NULL ) && ( geom.getNormalBinding() == osg::Geometry::BIND_PER_VERTEX) ) { attr |= HAS_NORMAL; vertSize += ( sizeof( float32 ) * 3 ); } if ( t2 != NULL ) { attr |= HAS_BASE_UV; vertSize += ( sizeof( float32 ) * 2 ); } // Add multitex if (isTextured( 1, geom )) { attr |= HAS_UV_LAYER1; vertSize += ( sizeof( float32 ) * 2 ); } if (isTextured( 2, geom )) { attr |= HAS_UV_LAYER2; vertSize += ( sizeof( float32 ) * 2 ); } if (isTextured( 3, geom )) { attr |= HAS_UV_LAYER3; vertSize += ( sizeof( float32 ) * 2 ); } if (isTextured( 4, geom )) { attr |= HAS_UV_LAYER4; vertSize += ( sizeof( float32 ) * 2 ); } if (isTextured( 5, geom )) { attr |= HAS_UV_LAYER5; vertSize += ( sizeof( float32 ) * 2 ); } if (isTextured( 6, geom )) { attr |= HAS_UV_LAYER6; vertSize += ( sizeof( float32 ) * 2 ); } if (isTextured( 7, geom )) { attr |= HAS_UV_LAYER7; vertSize += ( sizeof( float32 ) * 2 ); } unsigned int maxVerts = (0xffff - 12) / vertSize; unsigned int thisVertCount = (maxVerts > numVerts) ? numVerts : maxVerts; unsigned int currentIndexLimit = maxVerts; uint16 length( 12 + (vertSize * thisVertCount) ); _records->writeInt16( (int16) LOCAL_VERTEX_POOL_OP ); _records->writeUInt16( length ); _records->writeUInt32( numVerts ); // number of vertices _records->writeUInt32( attr ); // attribute bits unsigned int idx; for( idx=0; idx<numVerts; idx++ ) { _records->writeVec3d( (*v3)[ idx ] ); if (attr & HAS_RGBA_COLOR) { osg::Vec4 color = (*c4)[ idx ]; unsigned int packedColor = (int)(color[3]*255) << 24 | (int)(color[2]*255) << 16 | (int)(color[1]*255) << 8 | (int)(color[0]*255); _records->writeUInt32( packedColor ); } if (attr & HAS_NORMAL) _records->writeVec3f( (*n3)[ idx ] ); if (attr & HAS_BASE_UV) _records->writeVec2f( (*t2)[ idx ] ); if (attr & HAS_UV_LAYER1) _records->writeVec2f( (*mtc[1])[ idx ] ); if (attr & HAS_UV_LAYER2) _records->writeVec2f( (*mtc[2])[ idx ] ); if (attr & HAS_UV_LAYER3) _records->writeVec2f( (*mtc[3])[ idx ] ); if (attr & HAS_UV_LAYER4) _records->writeVec2f( (*mtc[4])[ idx ] ); if (attr & HAS_UV_LAYER5) _records->writeVec2f( (*mtc[5])[ idx ] ); if (attr & HAS_UV_LAYER6) _records->writeVec2f( (*mtc[6])[ idx ] ); if (attr & HAS_UV_LAYER7) _records->writeVec2f( (*mtc[7])[ idx ] ); // Handle continuation record if necessary. if ( (idx+1 == currentIndexLimit) && (idx+1 < numVerts) ) { currentIndexLimit += maxVerts; unsigned int remaining( numVerts - (idx+1) ); thisVertCount = (maxVerts > remaining) ? remaining : maxVerts; writeContinuationRecord( (vertSize * thisVertCount) ); } } }
void GeometryValidator::apply(osg::Geometry& geom) { if ( geom.getVertexArray() == 0L ) { OE_NOTICE << LC << "NULL vertex array!!\n"; return; } unsigned numVerts = geom.getVertexArray()->getNumElements(); if ( numVerts == 0 ) { OE_NOTICE << LC << "No verts!! name=" << geom.getName() << "\n"; return; } #if OSG_VERSION_GREATER_OR_EQUAL(3,1,9) std::set<osg::BufferObject*> _vbos; osg::Geometry::ArrayList arrays; geom.getArrayList(arrays); for(unsigned i=0; i<arrays.size(); ++i) { osg::Array* a = arrays[i].get(); if ( a == NULL ) { OE_NOTICE << LC << "Found a NULL array\n"; } else if ( a->getBinding() == a->BIND_OVERALL && a->getNumElements() != 1 ) { OE_NOTICE << LC << "Found an array with BIND_OVERALL and size <> 1\n"; } else if ( a->getBinding() == a->BIND_PER_VERTEX && a->getNumElements() != numVerts ) { OE_NOTICE << LC << "Found BIND_PER_VERTEX with wrong number of elements (expecting " << numVerts << "; found " << a->getNumElements() << ")\n"; } _vbos.insert( a->getVertexBufferObject() ); } if ( _vbos.size() != 1 ) { OE_NOTICE << LC << "Found a Geometry that uses more than one VBO (non-optimal sharing)\n"; } #else // pre-3.1.9 ... phase out. if ( geom.getColorArray() ) { if ( geom.getColorBinding() == osg::Geometry::BIND_OVERALL && geom.getColorArray()->getNumElements() != 1 ) { OE_NOTICE << "Color: BIND_OVERALL with wrong number of elements" << std::endl; } else if ( geom.getColorBinding() == osg::Geometry::BIND_PER_VERTEX && geom.getColorArray()->getNumElements() != numVerts ) { OE_NOTICE << "Color: BIND_PER_VERTEX with colors.size != verts.size" << std::endl; } } if ( geom.getNormalArray() ) { if ( geom.getNormalBinding() == osg::Geometry::BIND_OVERALL && geom.getNormalArray()->getNumElements() != 1 ) { OE_NOTICE << "Normal: BIND_OVERALL with wrong number of elements" << std::endl; } else if ( geom.getNormalBinding() == osg::Geometry::BIND_PER_VERTEX && geom.getNormalArray()->getNumElements() != numVerts ) { OE_NOTICE << "Normal: BIND_PER_VERTEX with normals.size != verts.size" << std::endl; } } #endif const osg::Geometry::PrimitiveSetList& plist = geom.getPrimitiveSetList(); std::set<osg::BufferObject*> _ebos; for( osg::Geometry::PrimitiveSetList::const_iterator p = plist.begin(); p != plist.end(); ++p ) { osg::PrimitiveSet* pset = p->get(); osg::DrawArrays* da = dynamic_cast<osg::DrawArrays*>(pset); if ( da ) { if ( da->getFirst() >= numVerts ) { OE_NOTICE << LC << "DrawArrays: first > numVerts\n"; } if ( da->getFirst()+da->getCount() > numVerts ) { OE_NOTICE << LC << "DrawArrays: first/count out of bounds\n"; } if ( da->getCount() < 1 ) { OE_NOTICE << LC << "DrawArrays: count is zero\n"; } } bool isDe = pset->getDrawElements() != 0L; osg::DrawElementsUByte* de_byte = dynamic_cast<osg::DrawElementsUByte*>(pset); if ( de_byte ) { validateDE(de_byte, 0xFF, numVerts ); _ebos.insert( de_byte->getElementBufferObject() ); } osg::DrawElementsUShort* de_short = dynamic_cast<osg::DrawElementsUShort*>(pset); if ( de_short ) { validateDE(de_short, 0xFFFF, numVerts ); _ebos.insert( de_short->getElementBufferObject() ); } osg::DrawElementsUInt* de_int = dynamic_cast<osg::DrawElementsUInt*>(pset); if ( de_int ) { validateDE(de_int, 0xFFFFFFFF, numVerts ); _ebos.insert( de_int->getElementBufferObject() ); } if ( pset->getNumIndices() == 0 ) { OE_NOTICE << LC << "Primset: num elements = 0; class=" << pset->className() << ", name=" << pset->getName() << "\n"; } else if ( pset->getType() >= GL_TRIANGLES && pset->getNumIndices() < 3 ) { OE_NOTICE << LC << "Primset: not enough indicies for surface prim type\n"; } else if ( pset->getType() >= GL_LINE_STRIP && pset->getNumIndices() < 2 ) { OE_NOTICE << LC << "Primset: not enough indicies for linear prim type\n"; } else if ( isDe && pset->getType() == GL_LINES && pset->getNumIndices() % 2 != 0 ) { OE_NOTICE << LC << "Primset: non-even index count for GL_LINES\n"; } } if ( _ebos.size() != 1 ) { OE_NOTICE << LC << "Found a Geometry that uses more than one EBO (non-optimal sharing)\n"; } }
void Tessellator::collectTessellation(osg::Geometry &geom, unsigned int originalIndex) { osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(geom.getVertexArray()); VertexPtrToIndexMap vertexPtrToIndexMap; // populate the VertexPtrToIndexMap. for(unsigned int vi=0;vi<vertices->size();++vi) { vertexPtrToIndexMap[&((*vertices)[vi])] = vi; } handleNewVertices(geom, vertexPtrToIndexMap); // we don't properly handle per primitive and per primitive_set bindings yet // will need to address this soon. Robert Oct 2002. { osg::Vec3Array* normals = NULL; // GWM Sep 2002 - add normals for extra facets int iprim=0; if (geom.getNormalBinding()==osg::Geometry::BIND_PER_PRIMITIVE || geom.getNormalBinding()==osg::Geometry::BIND_PER_PRIMITIVE_SET) { normals = dynamic_cast<osg::Vec3Array*>(geom.getNormalArray()); // GWM Sep 2002 } // GWM Dec 2003 - needed to add colours for extra facets osg::Vec4Array* cols4 = NULL; // GWM Dec 2003 colours are vec4 osg::Vec3Array* cols3 = NULL; // GWM Dec 2003 colours are vec3 if (geom.getColorBinding()==osg::Geometry::BIND_PER_PRIMITIVE || geom.getColorBinding()==osg::Geometry::BIND_PER_PRIMITIVE_SET) { Array* colours = geom.getColorArray(); // GWM Dec 2003 - need to duplicate face colours switch (colours->getType()) { case osg::Array::Vec4ArrayType: cols4=dynamic_cast<osg::Vec4Array *> (colours); break; case osg::Array::Vec3ArrayType: cols3=dynamic_cast<osg::Vec3Array *> (colours); break; default: break; } } // GWM Dec 2003 - these holders need to go outside the loop to // retain the flat shaded colour &/or normal for each tessellated polygon osg::Vec3 norm(0.0f,0.0f,0.0f); osg::Vec4 primCol4(0.0f,0.0f,0.0f,1.0f); osg::Vec3 primCol3(0.0f,0.0f,0.0f); for(PrimList::iterator primItr=_primList.begin(); primItr!=_primList.end(); ++primItr, ++_index) { Prim* prim=primItr->get(); int ntris=0; if(vertexPtrToIndexMap.size() <= 255) { osg::DrawElementsUByte* elements = new osg::DrawElementsUByte(prim->_mode); for(Prim::VecList::iterator vitr=prim->_vertices.begin(); vitr!=prim->_vertices.end(); ++vitr) { elements->push_back(vertexPtrToIndexMap[*vitr]); } // add to the drawn primitive list. geom.addPrimitiveSet(elements); ntris=elements->getNumIndices()/3; } else if(vertexPtrToIndexMap.size() > 255 && vertexPtrToIndexMap.size() <= 65535) { osg::DrawElementsUShort* elements = new osg::DrawElementsUShort(prim->_mode); for(Prim::VecList::iterator vitr=prim->_vertices.begin(); vitr!=prim->_vertices.end(); ++vitr) { elements->push_back(vertexPtrToIndexMap[*vitr]); } // add to the drawn primitive list. geom.addPrimitiveSet(elements); ntris=elements->getNumIndices()/3; } else { osg::DrawElementsUInt* elements = new osg::DrawElementsUInt(prim->_mode); for(Prim::VecList::iterator vitr=prim->_vertices.begin(); vitr!=prim->_vertices.end(); ++vitr) { elements->push_back(vertexPtrToIndexMap[*vitr]); } // add to the drawn primitive list. geom.addPrimitiveSet(elements); ntris=elements->getNumIndices()/3; } if (primItr==_primList.begin()) { // first primitive so collect primitive normal & colour. if (normals) { if (geom.getNormalBinding()==osg::Geometry::BIND_PER_PRIMITIVE) norm=(*normals)[originalIndex + _extraPrimitives]; else norm=(*normals)[iprim]; // GWM Sep 2002 the flat shaded normal } if (cols4) { primCol4=(*cols4)[iprim]; // GWM Dec 2003 the flat shaded rgba colour if (_index>=cols4->size()) { cols4->push_back(primCol4); // GWM Dec 2003 add flat shaded colour for new facet } } if (cols3) { primCol3=(*cols3)[iprim]; // GWM Dec 2003 flat shaded rgb colour if (_index>=cols3->size()) { cols3->push_back(primCol3); // GWM Dec 2003 add flat shaded colour for new facet } } } else { // later primitives use same colour if (normals) { if (geom.getNormalBinding()==osg::Geometry::BIND_PER_PRIMITIVE) { _extraPrimitives++; normals->insert(normals->begin() + originalIndex + _extraPrimitives, norm); } else normals->push_back(norm); // GWM Sep 2002 add flat shaded normal for new facet } if (cols4 && _index>=cols4->size()) { cols4->push_back(primCol4); // GWM Dec 2003 add flat shaded colour for new facet } if (cols3 && _index>=cols3->size()) { if (cols3) cols3->push_back(primCol3); // GWM Dec 2003 add flat shaded colour for new facet } if (prim->_mode==GL_TRIANGLES) { if (geom.getNormalBinding()==osg::Geometry::BIND_PER_PRIMITIVE_SET || geom.getNormalBinding()==osg::Geometry::BIND_PER_PRIMITIVE) { // need one per triangle? Not one per set. for (int ii=1; ii<ntris; ii++) { if (normals) normals->push_back(norm); // GWM Sep 2002 add flat shaded normal for new facet } } if (geom.getColorBinding()==osg::Geometry::BIND_PER_PRIMITIVE_SET || geom.getColorBinding()==osg::Geometry::BIND_PER_PRIMITIVE) { // need one per triangle? Not one per set. for (int ii=1; ii<ntris; ii++) { if (cols3 && _index>=cols3->size()) { if (cols3) cols3->push_back(primCol3); } if (cols4 && _index>=cols4->size()) { if (cols4) cols4->push_back(primCol4); } _index++; } } } // osg::notify(osg::WARN)<<"Add: "<< iprim << std::endl; } iprim++; // GWM Sep 2002 count which normal we should use } } }
void Tessellator::handleNewVertices(osg::Geometry& geom,VertexPtrToIndexMap &vertexPtrToIndexMap) { if (!_newVertexList.empty()) { osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(geom.getVertexArray()); osg::Vec3Array* normals = NULL; if (geom.getNormalBinding()==osg::Geometry::BIND_PER_VERTEX) { normals = dynamic_cast<osg::Vec3Array*>(geom.getNormalArray()); } typedef std::vector<osg::Array*> ArrayList; ArrayList arrays; if (geom.getColorBinding()==osg::Geometry::BIND_PER_VERTEX) { arrays.push_back(geom.getColorArray()); } if (geom.getSecondaryColorBinding()==osg::Geometry::BIND_PER_VERTEX) { arrays.push_back(geom.getSecondaryColorArray()); } if (geom.getFogCoordBinding()==osg::Geometry::BIND_PER_VERTEX) { arrays.push_back(geom.getFogCoordArray()); } osg::Geometry::ArrayDataList& tcal = geom.getTexCoordArrayList(); for(osg::Geometry::ArrayDataList::iterator tcalItr=tcal.begin(); tcalItr!=tcal.end(); ++tcalItr) { if (tcalItr->array.valid()) { arrays.push_back(tcalItr->array.get()); } } // now add any new vertices that are required. for(NewVertexList::iterator itr=_newVertexList.begin(); itr!=_newVertexList.end(); ++itr) { NewVertex& newVertex = (*itr); osg::Vec3* vertex = newVertex._vpos; // assign vertex. vertexPtrToIndexMap[vertex]=vertices->size(); vertices->push_back(*vertex); // assign normals if (normals) { osg::Vec3 norm(0.0f,0.0f,0.0f); if (newVertex._v1) norm += (*normals)[vertexPtrToIndexMap[newVertex._v1]] * newVertex._f1; if (newVertex._v2) norm += (*normals)[vertexPtrToIndexMap[newVertex._v2]] * newVertex._f2; if (newVertex._v3) norm += (*normals)[vertexPtrToIndexMap[newVertex._v3]] * newVertex._f3; if (newVertex._v4) norm += (*normals)[vertexPtrToIndexMap[newVertex._v4]] * newVertex._f4; norm.normalize(); normals->push_back(norm); } if (!arrays.empty()) { InsertNewVertices inv(newVertex._f1,vertexPtrToIndexMap[newVertex._v1], newVertex._f2,vertexPtrToIndexMap[newVertex._v2], newVertex._f3,vertexPtrToIndexMap[newVertex._v3], newVertex._f4,vertexPtrToIndexMap[newVertex._v4]); // assign the rest of the attributes. for(ArrayList::iterator aItr=arrays.begin(); aItr!=arrays.end(); ++aItr) { (*aItr)->accept(inv); } } } } }
void GeometryValidator::apply(osg::Geometry& geom) { unsigned numVerts = geom.getVertexArray()->getNumElements(); if ( geom.getColorArray() ) { if ( geom.getColorBinding() == osg::Geometry::BIND_OVERALL && geom.getColorArray()->getNumElements() != 1 ) { OE_WARN << "Color: BIND_OVERALL with wrong number of elements" << std::endl; } else if ( geom.getColorBinding() == osg::Geometry::BIND_PER_VERTEX && geom.getColorArray()->getNumElements() != numVerts ) { OE_WARN << "Color: BIND_PER_VERTEX with color.size != verts.size" << std::endl; } } if ( geom.getNormalArray() ) { if ( geom.getNormalBinding() == osg::Geometry::BIND_OVERALL && geom.getNormalArray()->getNumElements() != 1 ) { OE_WARN << "Normal: BIND_OVERALL with wrong number of elements" << std::endl; } else if ( geom.getNormalBinding() == osg::Geometry::BIND_PER_VERTEX && geom.getNormalArray()->getNumElements() != numVerts ) { OE_WARN << "Normal: BIND_PER_VERTEX with color.size != verts.size" << std::endl; } } const osg::Geometry::PrimitiveSetList& plist = geom.getPrimitiveSetList(); for( osg::Geometry::PrimitiveSetList::const_iterator p = plist.begin(); p != plist.end(); ++p ) { osg::PrimitiveSet* pset = p->get(); osg::DrawElementsUByte* de_byte = dynamic_cast<osg::DrawElementsUByte*>(pset); if ( de_byte ) { if ( numVerts > 0xFF ) { OE_WARN << "DrawElementsUByte used when numVerts > 255 (" << numVerts << ")" << std::endl; } validateDE(de_byte, 0xFF, numVerts ); } osg::DrawElementsUShort* de_short = dynamic_cast<osg::DrawElementsUShort*>(pset); if ( de_short ) { if ( numVerts > 0xFFFF ) { OE_WARN << "DrawElementsUShort used when numVerts > 65535 (" << numVerts << ")" << std::endl; } validateDE(de_short, 0xFFFF, numVerts ); } osg::DrawElementsUInt* de_int = dynamic_cast<osg::DrawElementsUInt*>(pset); if ( de_int ) { validateDE(de_int, 0xFFFFFFFF, numVerts ); } } }
void IndexMeshVisitor::apply(osg::Geometry& geom) { // TODO: this is deprecated if (geom.getNormalBinding() == osg::Geometry::BIND_PER_PRIMITIVE_SET) return; if (geom.getColorBinding() == osg::Geometry::BIND_PER_PRIMITIVE_SET) return; if (geom.getSecondaryColorBinding() == osg::Geometry::BIND_PER_PRIMITIVE_SET) return; if (geom.getFogCoordBinding() == osg::Geometry::BIND_PER_PRIMITIVE_SET) return; // no point optimizing if we don't have enough vertices. if (!geom.getVertexArray() || geom.getVertexArray()->getNumElements() < 3) return; osgUtil::SharedArrayOptimizer deduplicator; deduplicator.findDuplicatedUVs(geom); // duplicate shared arrays as it isn't safe to rearrange vertices when arrays are shared. if (geom.containsSharedArrays()) { geom.duplicateSharedArrays(); } osg::Geometry::PrimitiveSetList& primitives = geom.getPrimitiveSetList(); osg::Geometry::PrimitiveSetList::iterator itr; osg::Geometry::PrimitiveSetList new_primitives; new_primitives.reserve(primitives.size()); // compute duplicate vertices typedef std::vector<unsigned int> IndexList; unsigned int numVertices = geom.getVertexArray()->getNumElements(); IndexList indices(numVertices); unsigned int i, j; for(i = 0 ; i < numVertices ; ++ i) { indices[i] = i; } VertexAttribComparitor arrayComparitor(geom); std::sort(indices.begin(), indices.end(), arrayComparitor); unsigned int lastUnique = 0; unsigned int numUnique = 1; for(i = 1 ; i < numVertices ; ++ i) { if (arrayComparitor.compare(indices[lastUnique], indices[i]) != 0) { lastUnique = i; ++ numUnique; } } IndexList remapDuplicatesToOrignals(numVertices); lastUnique = 0; for(i = 1 ; i < numVertices ; ++ i) { if (arrayComparitor.compare(indices[lastUnique],indices[i]) != 0) { // found a new vertex entry, so previous run of duplicates needs // to be put together. unsigned int min_index = indices[lastUnique]; for(j = lastUnique + 1 ; j < i ; ++ j) { min_index = osg::minimum(min_index, indices[j]); } for(j = lastUnique ; j < i ; ++ j) { remapDuplicatesToOrignals[indices[j]] = min_index; } lastUnique = i; } } unsigned int min_index = indices[lastUnique]; for(j = lastUnique + 1 ; j < i ; ++ j) { min_index = osg::minimum(min_index, indices[j]); } for(j = lastUnique ; j < i ; ++ j) { remapDuplicatesToOrignals[indices[j]] = min_index; } // copy the arrays. IndexList finalMapping(numVertices); IndexList copyMapping; copyMapping.reserve(numUnique); unsigned int currentIndex = 0; for(i = 0 ; i < numVertices ; ++ i) { if (remapDuplicatesToOrignals[i] == i) { finalMapping[i] = currentIndex; copyMapping.push_back(i); currentIndex++; } else { finalMapping[i] = finalMapping[remapDuplicatesToOrignals[i]]; } } // remap any shared vertex attributes RemapArray ra(copyMapping); arrayComparitor.accept(ra); // triangulate faces { TriangleIndexor ti; ti._maxIndex = numVertices; ti._remapping = finalMapping; for(itr = primitives.begin() ; itr != primitives.end() ; ++ itr) { (*itr)->accept(ti); } addDrawElements(ti._indices, osg::PrimitiveSet::TRIANGLES, new_primitives); } // line-ify line-type primitives { LineIndexor li, wi; // lines and wireframes li._maxIndex = numVertices; wi._maxIndex = numVertices; li._remapping = finalMapping; wi._remapping = finalMapping; for(itr = primitives.begin() ; itr != primitives.end() ; ++ itr) { bool isWireframe = false; if((*itr)->getUserValue("wireframe", isWireframe) && isWireframe) { (*itr)->accept(wi); } else { (*itr)->accept(li); } } addDrawElements(li._indices, osg::PrimitiveSet::LINES, new_primitives); addDrawElements(wi._indices, osg::PrimitiveSet::LINES, new_primitives, "wireframe"); } // adds points primitives { IndexList points; for(itr = primitives.begin() ; itr != primitives.end() ; ++ itr) { if((*itr) && (*itr)->getMode() == osg::PrimitiveSet::POINTS) { for(unsigned int k = 0 ; k < (*itr)->getNumIndices() ; ++ k) { points.push_back(finalMapping[(*itr)->index(k)]); } } } addDrawElements(points, osg::PrimitiveSet::POINTS, new_primitives); } geom.setPrimitiveSetList(new_primitives); deduplicator.deduplicateUVs(geom); setProcessed(&geom); }