From a90704261839979cb25d9f073850a454e88d6317 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Wed, 6 Oct 2004 19:19:22 +0000 Subject: [PATCH] From Jason Daly, fix to multi-texturing/detail texture handling. --- src/osgPlugins/flt/GeoSetBuilder.cpp | 110 ++++++++++++++++++--------- src/osgPlugins/flt/GeoSetBuilder.h | 110 ++++++++++++++++++++++----- src/osgPlugins/flt/flt2osg.cpp | 84 ++++++++++++-------- 3 files changed, 218 insertions(+), 86 deletions(-) diff --git a/src/osgPlugins/flt/GeoSetBuilder.cpp b/src/osgPlugins/flt/GeoSetBuilder.cpp index 9632b0a31..1600e7ae3 100644 --- a/src/osgPlugins/flt/GeoSetBuilder.cpp +++ b/src/osgPlugins/flt/GeoSetBuilder.cpp @@ -13,7 +13,6 @@ #include "Pool.h" #include "opcodes.h" #include "GeoSetBuilder.h" -#include "AttrData.h" #include #include @@ -55,7 +54,23 @@ void DynGeoSet::append(DynGeoSet* source) APPEND_DynGeoSet_List(_coordList) if (_normal_binding==osg::Geometry::BIND_PER_VERTEX || _normal_binding==osg::Geometry::BIND_PER_PRIMITIVE) APPEND_DynGeoSet_List(_normalList) if (_color_binding==osg::Geometry::BIND_PER_VERTEX || _color_binding==osg::Geometry::BIND_PER_PRIMITIVE) APPEND_DynGeoSet_List(_colorList) - if (_texture_binding==osg::Geometry::BIND_PER_VERTEX || _texture_binding==osg::Geometry::BIND_PER_PRIMITIVE) APPEND_DynGeoSet_List(_tcoordList) + + for (unsigned int i = 0; i < source->_tcoordLists.size(); i++) + { + if ((getTextureBinding(i)==osg::Geometry::BIND_PER_VERTEX) || + (getTextureBinding(i)==osg::Geometry::BIND_PER_PRIMITIVE)) + { + if (source->_tcoordLists.size() > 0) + { + if (_tcoordLists.size() <= i) + _tcoordLists.resize(i+1); + + _tcoordLists[i].insert(_tcoordLists[i].end(), + source->_tcoordLists[i].begin(), + source->_tcoordLists[i].end()); + } + } + } } @@ -88,21 +103,28 @@ DynGeoSet::DynGeoSet() _primtype = NO_PRIMITIVE_TYPE; _normal_binding = osg::Geometry::BIND_OFF; _color_binding = osg::Geometry::BIND_OFF; - _texture_binding = osg::Geometry::BIND_OFF; + + _detailTextureEnabled = false; _geom = new osg::Geometry; } void DynGeoSet::setBinding() { + unsigned int i; + VERIFY_DynGeoSet_Binding(_normal_binding, _normalList) VERIFY_DynGeoSet_Binding(_color_binding, _colorList) - VERIFY_DynGeoSet_Binding(_texture_binding, _tcoordList) + + for (i = 0; i < _tcoordLists.size(); i++) + VERIFY_DynGeoSet_Binding(_texture_bindings[i], _tcoordLists[i]) // Set bindings setNormalBinding(_normal_binding); setColorBinding(_color_binding); - setTextureBinding(_texture_binding); + + for (i = 0; i < _tcoordLists.size(); i++) + setTextureBinding(i, _texture_bindings[i]); osg::StateSet* stateset = getStateSet(); if (stateset) @@ -153,37 +175,58 @@ void DynGeoSet::addToGeometry(osg::Geometry* geom) } } - if (!_tcoordList.empty()) + for (unsigned int i = 0; i < _tcoordLists.size(); i++) { - osg::Vec2Array* texcoords = dynamic_cast(geom->getTexCoordArray(0)); - if (texcoords) - { - texcoords->insert(texcoords->end(),_tcoordList.begin(),_tcoordList.end()); - } - else - { - texcoords = new osg::Vec2Array(_tcoordList.begin(),_tcoordList.end()); - geom->setTexCoordArray(0,texcoords); + if (!_tcoordLists[i].empty()) + { + // Grab the current layer's texture coordinate array from the + // geometry + osg::Vec2Array* texcoords = + dynamic_cast(geom->getTexCoordArray(i)); - // If we got detail texture defined for this geometry, we need to setup new texcoord - // related on base texture ones. Using txDetail_m and txDetail_n values we read in - // ReaderWriterATTR and we got in AttrData class. - // - // We apply those values multiplying original texcoord.x by txDetail_m and texcoord.y - // by txDetail_n to get detail texture repeated. - // - // Julian Ortiz, June 18th 2003. - - if ( (_attrdata != NULL) && (_attrdata->useDetail > 0) ) { - osg::Vec2Array *texcoords2 = new osg::Vec2Array(_tcoordList.begin(),_tcoordList.end()); - for(unsigned int index=0;indexsize();index++) { - (*texcoords2)[index][0]=(*texcoords)[index][0]*_attrdata->txDetail_m; - (*texcoords2)[index][1]=(*texcoords)[index][1]*_attrdata->txDetail_n; - } - geom->setTexCoordArray(1,texcoords2); - } - } + // See if we need to create the texture coordinate array or add to + // it + if (texcoords) + { + // Append the new texture coordinates to the end of the existing + // list + texcoords->insert(texcoords->end(),_tcoordLists[i].begin(), + _tcoordLists[i].end()); + } + else + { + // Create a new texture coordinate array + texcoords = new osg::Vec2Array(_tcoordLists[i].begin(), + _tcoordLists[i].end()); + geom->setTexCoordArray(i,texcoords); + } + } } + + // If this geometry uses a detail texture, we apply the detail texture + // scalars to the texture coordinates on layer 0 to get the detail texture + // coordinates, which we put on layer 1. Note that this assumes that + // layer 1 is not in use for multitexturing. This means that + // multitexturing and detail texturing are not supported at the same time. + if ((_detailTextureEnabled) && (!_tcoordLists.empty()) && + (!_tcoordLists[0].empty())) + { + // Create a new texture coordinate array for the detail texture + // coordinates + osg::Vec2Array *texcoords2 = new osg::Vec2Array(_tcoordLists[0].begin(), + _tcoordLists[0].end()); + + // Scale the texture coordinates from layer 0 + for(unsigned int index=0;indexsize();index++) + { + (*texcoords2)[index][0] *= _detailTexCoord_m; + (*texcoords2)[index][1] *= _detailTexCoord_n; + } + + // Set the new texcoord array on layer 1 (this wipes out any existing + // texture coordinates there) + geom->setTexCoordArray(1,texcoords2); + } if (!_colorList.empty()) { @@ -222,7 +265,6 @@ void DynGeoSet::addToGeometry(osg::Geometry* geom) indexBase += *itr; } } - } diff --git a/src/osgPlugins/flt/GeoSetBuilder.h b/src/osgPlugins/flt/GeoSetBuilder.h index 8b30a3d53..2dda5bcd7 100644 --- a/src/osgPlugins/flt/GeoSetBuilder.h +++ b/src/osgPlugins/flt/GeoSetBuilder.h @@ -1,8 +1,14 @@ #ifndef __FLT_GEOSETBUILDER_H #define __FLT_GEOSETBUILDER_H -// Added DynGeoSet::setDetailTextureAttrData that is used to store texture Attributes +// Added DynGeoSet::setDetailTextureAttrData that is used to store texture +// Attributes // Julian Ortiz, June 18th 2003. +// --- +// Added support for multiple layers of texture coordinates. Changed the +// detail texture support to only store the M & N scalar values instead of +// the whole AttrData structure. +// Jason Daly, Sept 25, 2004 #include #include @@ -13,8 +19,6 @@ #include #include -#include "AttrData.h" - #include #include @@ -52,7 +56,14 @@ class DynGeoSet : public osg::Referenced { COMPARE_DynGeoSet_Parameter(_color_binding) COMPARE_DynGeoSet_Parameter(_normal_binding) - COMPARE_DynGeoSet_Parameter(_texture_binding) + + for (unsigned int i = 0; i < _texture_bindings.size(); i++) + { + if (getTextureBinding(i)rhs.getTextureBinding(i)) + return 1; + } if (_color_binding == osg::Geometry::BIND_OVERALL) { @@ -74,7 +85,14 @@ class DynGeoSet : public osg::Referenced { COMPARE_DynGeoSet_Parameter(_color_binding) - COMPARE_DynGeoSet_Parameter(_texture_binding) + + for (unsigned int i = 0; i < _texture_bindings.size(); i++) + { + if (getTextureBinding(i)rhs.getTextureBinding(i)) + return 1; + } int result=getStateSet()->compare(*rhs.getStateSet(), true); if (result!=0) return result; @@ -94,7 +112,6 @@ class DynGeoSet : public osg::Referenced } return 0; - } bool operator < (const DynGeoSet& rhs) const { return compare(rhs)<0; } @@ -110,11 +127,29 @@ class DynGeoSet : public osg::Referenced void setColorBinding(osg::Geometry::AttributeBinding bind) { _color_binding = bind; } void setNormalBinding(osg::Geometry::AttributeBinding bind) { _normal_binding = bind; } - void setTextureBinding(osg::Geometry::AttributeBinding bind) { _texture_binding = bind; } + void setTextureBinding(osg::Geometry::AttributeBinding bind) + { + setTextureBinding(0, bind); + } + void setTextureBinding(unsigned int index, + osg::Geometry::AttributeBinding bind) + { + if (_texture_bindings.size() <= index) + _texture_bindings.resize(index+1); + + _texture_bindings[index] = bind; + } osg::Geometry::AttributeBinding getColorBinding() const { return _color_binding; } osg::Geometry::AttributeBinding getNormalBinding() const { return _normal_binding; } - osg::Geometry::AttributeBinding getTextureBinding() const { return _texture_binding; } + osg::Geometry::AttributeBinding getTextureBinding() const { return getTextureBinding(0); } + osg::Geometry::AttributeBinding getTextureBinding(unsigned int index) const + { + if (_texture_bindings.size() > index) + return _texture_bindings[index]; + else + return osg::Geometry::BIND_OFF; + } void setPrimType(osg::PrimitiveSet::Mode type) { _primtype=type; } osg::PrimitiveSet::Mode getPrimType() const { return _primtype; } @@ -123,17 +158,33 @@ class DynGeoSet : public osg::Referenced inline void addCoord(const osg::Vec3& coord) { _coordList.push_back(coord); } inline void addNormal(const osg::Vec3& normal) { _normalList.push_back(normal); } inline void addColor(const osg::Vec4& color) { _colorList.push_back(color); } - inline void addTCoord(const osg::Vec2& tcoord) { _tcoordList.push_back(tcoord); } + inline void addTCoord(const osg::Vec2& tcoord) { addTCoord(0, tcoord); } + inline void addTCoord(unsigned int index, const osg::Vec2& tcoord) + { + if (_tcoordLists.size() <= index) + _tcoordLists.resize(index+1); - typedef std::vector CoordList; - typedef std::vector NormalList; - typedef std::vector ColorList; - typedef std::vector TcoordList; + _tcoordLists[index].push_back(tcoord); + } + + typedef std::vector CoordList; + typedef std::vector NormalList; + typedef std::vector ColorList; + typedef std::vector TcoordList; + typedef std::vector TcoordLists; + typedef std::vector TextureBindings; const CoordList& getCoordList() { return _coordList; } const NormalList& getNormalList() { return _normalList; } const ColorList& getColorList() { return _colorList; } - const TcoordList& getTcoordList() { return _tcoordList; } + const TcoordList& getTcoordList() { return getTcoordList(0); } + const TcoordList& getTcoordList(unsigned int index) + { + if (_tcoordLists.size() <= index) + _tcoordLists.resize(index+1); + + return _tcoordLists[index]; + } void append(DynGeoSet* source); void setBinding(); @@ -144,8 +195,27 @@ class DynGeoSet : public osg::Referenced inline int coordListSize() const { return _coordList.size(); } inline int normalListSize() const { return _normalList.size(); } inline int colorListSize() const { return _colorList.size(); } - inline int tcoordListSize() const { return _tcoordList.size(); } - inline void setDetailTextureAttrData(AttrData *attrdata) {_attrdata=attrdata; } + inline int tcoordListSize() const { return tcoordListSize(0); } + inline int tcoordListSize(unsigned int index) const + { + if (_tcoordLists.size() <= index) + return _tcoordLists[index].size() ; + else + return 0; + } + + inline void enableDetailTexture() { _detailTextureEnabled=true; } + inline void disableDetailTexture() { _detailTextureEnabled=false; } + inline void setDetailTexCoords(int32 m, int32 n) + { + // If somebody knows what the other TX_DETAIL parameters do, + // please add them. I looked through the OF specs as well as + // the SGIS_detail_texture extension, and I didn't find any + // clear explanation. The only reason this is here at all is + // because of Julian Ortiz' previous work. + _detailTexCoord_m = m; + _detailTexCoord_n = n; + } osg::Geometry* getGeometry() { CERR << "_geom.get(): " << _geom.get() @@ -173,10 +243,12 @@ class DynGeoSet : public osg::Referenced osg::Geometry::AttributeBinding _color_binding; ColorList _colorList; - osg::Geometry::AttributeBinding _texture_binding; - TcoordList _tcoordList; + TextureBindings _texture_bindings; + TcoordLists _tcoordLists; - AttrData *_attrdata; + int32 _detailTexCoord_m; + int32 _detailTexCoord_n; + bool _detailTextureEnabled; }; diff --git a/src/osgPlugins/flt/flt2osg.cpp b/src/osgPlugins/flt/flt2osg.cpp index efbe9cb04..9b4e7189b 100644 --- a/src/osgPlugins/flt/flt2osg.cpp +++ b/src/osgPlugins/flt/flt2osg.cpp @@ -1572,19 +1572,25 @@ void ConvertFromFLT::setTexture ( FaceRecord *rec, SFace *pSFace, osg::StateSet } } - //Now, an ugly thing,... we have detected that in Creator we defined that a texture will we used as - //detail texture, and we load it as it using texture unit 1,... but we also need to create texture - //coordinates to map this detail texture, I found that texture coordinates assigment is made in - //DynGeoSet::addToGeometry and the easy way I found to create those new coordinates is to add a method - //to DynGeoSet class named setDetailTextureStatus that pass detail Texture AttrData class, so when - //DynGeoSet::addToGeometry runs it reads this class and create new texture coordinates if we got a valid - //AttrData object. I now this is not a good way to do it, and I expect someone with more osg knowledge - //could make it in a better way. - // Julian Ortiz, June 18th 2003. - if (pSFace->iDetailTexturePattern != -1 && detailTextureAttrData && detailTextureAttrData->stateset) - dgset->setDetailTextureAttrData(detailTextureAttrData); + // If a detail texture structure exists, set the texture + // coordinate scalars on the current DynGeoSet, so the correct + // detail texture coordinates get generated later. + if (pSFace->iDetailTexturePattern != -1 && + detailTextureAttrData && + detailTextureAttrData->stateset) + { + // Set the texture coordinate scalars + dgset->setDetailTexCoords(detailTextureAttrData->txDetail_m, + detailTextureAttrData->txDetail_n); + + // Make sure detail texturing is on + dgset->enableDetailTexture(); + } else - dgset->setDetailTextureAttrData(NULL); + { + // Make sure detail texturing is off + dgset->disableDetailTexture(); + } // Merge face stateset with texture stateset osgStateSet->merge(*textureStateSet); @@ -1671,9 +1677,18 @@ ConvertFromFLT::addMultiTexture( DynGeoSet* dgset, MultiTextureRecord* mtr ) return; } - osg::StateSet *textureStateSet = dynamic_cast ((pTexturePool->getTexture((int)mt->data[l].texture,mtr->getFlightVersion()))->stateset); + // Get the texture attribute data from the texture pool + flt::AttrData *textureAttrData = dynamic_cast (pTexturePool->getTexture((int)mt->data[l].texture,mtr->getFlightVersion())); CERR << "pTexturePool->getTexture((int)mt->data[l].texture): " << pTexturePool->getTexture((int)mt->data[l].texture,mtr->getFlightVersion()) << "\n"; + if (!textureAttrData) + { + CERR << "unable to set up multi-texture layer." << std::endl; + return; + } + + // Get the texture state set from the attribute data structure + osg::StateSet *textureStateSet = textureAttrData->stateset; CERR << "textureStateSet: " << textureStateSet << "\n"; if (!textureStateSet) @@ -1709,10 +1724,13 @@ ConvertFromFLT::addMultiTexture( DynGeoSet* dgset, MultiTextureRecord* mtr ) CERR << ", referenceCount: " << geom->referenceCount() << "\n"; + // Get the state set from the current geometry osg::StateSet* geom_stateset = geom->getStateSet(); CERR << "geom_stateset: " << geom_stateset << "\n"; + // See if we need to merge or set the texture state set on the + // geometry if ( geom_stateset ) { geom_stateset->merge( *texture_stateset ); @@ -1722,6 +1740,10 @@ ConvertFromFLT::addMultiTexture( DynGeoSet* dgset, MultiTextureRecord* mtr ) CERR << "Setting layer " << i << "\n"; } + // Set the texture binding on the current texture unit to + // per-vertex + dgset->setTextureBinding(i, osg::Geometry::BIND_PER_VERTEX); + l++; } } @@ -1730,9 +1752,7 @@ ConvertFromFLT::addMultiTexture( DynGeoSet* dgset, MultiTextureRecord* mtr ) void ConvertFromFLT::addUVList( DynGeoSet* dgset, UVListRecord* uvr ) { - osg::Geometry* geom = dgset->getGeometry(); - - if (!geom || !uvr || !uvr->isAncillaryRecord()) + if (!dgset || !uvr || !uvr->isAncillaryRecord()) { osg::notify(osg::WARN)<<"ConvertFromFLT::addUVList( DynGeoSet*, UVListRecord*) has been passed invalid paramters."<layers ) { - osg::Vec2Array* tcoords = new osg::Vec2Array; CERR << "Has layer " << i << "\n"; + // Assume we are working with vertex lists for now for ( int v = l*num_coords; v < (l+1)*num_coords; v++ ) { uvl->coords.vertex[v].endian(); CERR << "( u: " << uvl->coords.vertex[v].coords[1] << ", " - << "v: " << uvl->coords.vertex[v].coords[0] << ")\n"; - /// FIXME: should be (x,y) instead of (y,x) - ENDIAN problem??? - tcoords->push_back( osg::Vec2( uvl->coords.vertex[v].coords[1], - uvl->coords.vertex[v].coords[0] ) ); - } - if ( !tcoords->empty() ) - { - CERR << "Setting tcoords " << i << ": " << tcoords << "\n"; - geom->setTexCoordArray( i, tcoords ); + << "v: " << uvl->coords.vertex[v].coords[0] << ")\n"; + + /// FIXME: should be (x,y) instead of (y,x) - ENDIAN problem??? + // Add the texture coordinates to the current DynGeoSet + dgset->addTCoord(i, + osg::Vec2(uvl->coords.vertex[v].coords[1], + uvl->coords.vertex[v].coords[0])); } l++; @@ -1819,9 +1837,6 @@ void ConvertFromFLT::visitFace(GeoSetBuilder* pBuilder, osg::Group& osgParent, F // Vertices addVertices(pBuilder, osgParent, rec); - // Add face to builder pool - pBuilder->addPrimitive(); - // Visit ancillary records for(int i=0; i < rec->getNumChildren(); i++) { @@ -1842,9 +1857,9 @@ void ConvertFromFLT::visitFace(GeoSetBuilder* pBuilder, osg::Group& osgParent, F } // original code, but causes crash becayse addPrimitive can invalidate teh dgset pointer. - // addMultiTexture( dgset, mtr ); + addMultiTexture( dgset, mtr ); - addMultiTexture( pBuilder->getDynGeoSet(), mtr ); + // addMultiTexture( pBuilder->getDynGeoSet(), mtr ); } break; @@ -1860,6 +1875,9 @@ void ConvertFromFLT::visitFace(GeoSetBuilder* pBuilder, osg::Group& osgParent, F } } + // Add face to builder pool + pBuilder->addPrimitive(); + // Look for subfaces { _nSubfaceLevel++; @@ -3012,7 +3030,7 @@ uint32 ConvertFromFLT::setMeshNormals ( const uint32 &numVerts, const LocalVerte { if (!pool || !mesh || !geometry) { - osg::notify(osg::WARN)<<"OpenFlight loader detected error:: ConvertFromFLT::setMeshTexCoordinates passed null objects."<