// // OpenFlightŪ texture attribute loader for Open Scene Graph // // Copyright (C) 2001 Brede Johansen // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would be // appreciated but is not required. // 2. Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. // 3. This notice may not be removed or altered from any source distribution. // // The Open Scene Graph (OSG) is a cross platform C++/OpenGL library for // real-time rendering of large 3D photo-realistic models. // The OSG homepage is http://www.openscenegraph.org/ // // MultiGen, OpenFlight, and Flight Format are registered trademarks of MultiGen Inc. // #include #include #include #include #include #include #include #include #include #include #include #include #include #include "AttrData.h" typedef signed char int8; typedef unsigned char uint8; typedef signed short int16; typedef unsigned short uint16; typedef signed int int32; typedef unsigned int uint32; typedef float float32; typedef double float64; #define READ(DST) readField(file, (void*)&(DST), sizeof(DST)) static int isLittleEndianMachine() { int a = 1; return (int)(*(char*)&a); } static void endian2(void* pSrc, int nSrc, void* pDst) { if (nSrc == 2) { short tmp1; tmp1 = *(short *)pSrc; tmp1 = (tmp1 << 8) | ((tmp1 >> 8) & 0xff); *(short *)pDst = tmp1; } else if (nSrc == 4) { uint32 tmp1; tmp1 = *(uint32 *)pSrc; tmp1 = (tmp1 << 24) | ((tmp1 << 8) & 0xff0000) | ((tmp1 >> 8) & 0xff00) | ((tmp1 >> 24) & 0xff); *(uint32 *)pDst = tmp1; } else if (nSrc == 8) { uint32 tmp1, tmp2; tmp1 = *(uint32 *)pSrc; tmp2 = *(1 + (uint32 *)pSrc); tmp1 = (tmp1 << 24) | ((tmp1 << 8) & 0xff0000) | ((tmp1 >> 8) & 0xff00) | ((tmp1 >> 24) & 0xff); tmp2 = (tmp2 << 24) | ((tmp2 << 8) & 0xff0000) | ((tmp2 >> 8) & 0xff00) | ((tmp2 >> 24) & 0xff); *(uint32 *)pDst = tmp2; *(1 + (uint32 *)pDst) = tmp1; } } using namespace osg; class Attr { public : enum MinFilterMode { MIN_FILTER_POINT = 0, MIN_FILTER_BILINEAR = 1, MIN_FILTER_MIPMAP = 2, // (Obsolete) MIN_FILTER_MIPMAP_POINT = 3, MIN_FILTER_MIPMAP_LINEAR = 4, MIN_FILTER_MIPMAP_BILINEAR = 5, MIN_FILTER_MIPMAP_TRILINEAR = 6, MIN_FILTER_NONE = 7, MIN_FILTER_BICUBIC = 8, MIN_FILTER_BILINEAR_GEQUAL = 9, MIN_FILTER_BILINEAR_LEQUAL = 10, MIN_FILTER_BICUBIC_GEQUAL = 11, MIN_FILTER_BICUBIC_LEQUAL = 12 }; enum MagFilterMode { MAG_FILTER_POINT = 0, MAG_FILTER_BILINEAR = 1, MAG_FILTER_NONE = 2, MAG_FILTER_BICUBIC = 3, MAG_FILTER_SHARPEN = 4, MAG_FILTER_ADD_DETAIL = 5, MAG_FILTER_MODULATE_DETAIL = 6, MAG_FILTER_BILINEAR_GEQUAL = 7, MAG_FILTER_BILINEAR_LEQUAL = 8, MAG_FILTER_BICUBIC_GEQUAL = 9, MAG_FILTER_BICUBIC_LEQUAL = 10 }; enum WrapMode { WRAP_REPEAT = 0, WRAP_CLAMP = 1 }; enum TexEnvMode { TEXENV_MODULATE = 0, TEXENV_BLEND = 1, TEXENV_DECAL = 2, TEXENV_COLOR = 3 }; enum Projection { PROJECTION_FLAT = 0, PROJECTION_LAMBERT_CONIC = 3, PROJECTION_UTM = 4, PROJECTION_UNDEFINED = 7 }; enum Datum { DATUM_WGS84 = 0, DATUM_WGS72 = 1, DATUM_BESSEL = 2, DATUM_CLARK_1866 = 3, DATUM_NAD27 = 4 }; Attr(int version) : _flt_version(version) { init(); } void init(); void readField(std::ifstream& file, void* buf, size_t size); bool readAttrFile(const char* szName); flt::AttrData* createOsgStateSet(); int32 texels_u; // Number of texels in u direction int32 textel_v; // Number of texels in v direction int32 direction_u; // Real world size u direction int32 direction_v; // Real world size v direction int32 x_up; // x component of up vector int32 y_up; // y component of up vector int32 fileFormat; // File format type // -1 Not used // 0 AT&T image 8 pattern // 1 AT&T image 8 template // 2 SGI intensity modulation // 3 SGI intensity w/ alpha // 4 SGI RGB // 5 SGI RGB w/ alpha int32 minFilterMode; // Minification filter type // 0 - TX_POINT // 1 - TX_BILINEAR // 2 - TX_MIPMAP (Obsolete) // 3 - TX_MIPMAP_POINT // 4 - TX_MIPMAP_LINEAR // 5 - TX_MIPMAP_BILINEAR // 6 - TX_MIPMAP_TRILINEAR // 7 - None // 8 - TX_BICUBIC // 9 - TX_BILINEAR_GEQUAL // 10 - TX_BILINEAR_LEQUAL // 11 - TX_BICUBIC_GEQUAL // 12 - TX_BICUBIC_LEQUAL int32 magFilterMode; // Magnification filter type // 0 - TX_POINT // 1 - TX_BILINEAR // 2 - None // 3 - TX_BICUBIC // 4 - TX_SHARPEN // 5 - TX_ADD_DETAIL // 6 - TX_MODULATE_DETAIL // 7 - TX_BILINEAR_GEQUAL // 8 - TX_BILINEAR_LEQUAL // 9 - TX_BICUBIC_GEQUAL // 10 - TX_BICUBIC_LEQUAL int32 wrapMode; // Repetition type // 0 - TX_REPEAT // 1 - TX_CLAMP // 2 - (Obsolete) int32 wrapMode_u; // Repetition type in u direction (see above) int32 wrapMode_v; // Repetition type in v direction (see above) int32 modifyFlag; // Modify flag (for internal use) int32 pivot_x; // x pivot point for rotating textures int32 pivot_y; // y pivot point for rotating textures // -------------- // v11 ends here // -------------- int32 texEnvMode; // Environment type // 0 - TV_MODULATE // 1 - TV_BLEND // 2 - TV_DECAL // 3 - TV_COLOR int32 intensityAsAlpha; // TRUE if intensity pattern to be loaded in alpha with white in color int32 spare1[8]; // 8 words of spare float64 size_u; // Real world size u for floating point databases float64 size_v; // Real world size v for floating point databases int32 originCode; // Code for origin of imported texture int32 kernelVersion; // Kernel version number int32 intFormat; // Internal format type // 0 - Default // 1 - TX_I_12A_4 // 2 - TX_IA_8 // 3 - TX_RGB_5 // 4 - TX_RGBA_4 // 5 - TX_IA_12 // 6 - TX_RGBA_8 // 7 - TX_RGBA_12 // 8 - TX_I_16 (shadow mode only) // 9 - TX_RGB_12 int32 extFormat; // External format type // 0 - Default // 1 - TX_PACK_8 // 2 - TX_PACK_16 int32 useMips; // TRUE if using following 8 floats for MIPMAP kernel float32 _mipMapKernel[8]; // 8 floats for kernel of separable symmetric filter int32 useLodScale; // Boolean if TRUE send: float32 lod0; // LOD0 for TX_CONTROL_POINT float32 scale0; // SCALE0 for TX_CONTROL_POINT float32 lod1; // LOD1 for TX_CONTROL_POINT float32 scale1; // SCALE1 for TX_CONTROL_POINT float32 lod2; // LOD2 for TX_CONTROL_POINT float32 scale2; // SCALE2 for TX_CONTROL_POINT float32 lod3; // LOD3 for TX_CONTROL_POINT float32 scale3; // SCALE3 for TX_CONTROL_POINT float32 lod4; // LOD4 for TX_CONTROL_POINT float32 scale4; // SCALE4 for TX_CONTROL_POINT float32 lod5; // LOD5 for TX_CONTROL_POINT float32 scale5; // SCALE5 for TX_CONTROL_POINT float32 lod6; // LOD6 for TX_CONTROL_POINT float32 scale6; // SCALE6 for TX_CONTROL_POINT float32 lod7; // LOD7 for TX_CONTROL_POINT float32 scale7; // SCALE7 for TX_CONTROL_POINT float32 clamp; // Clamp int32 magFilterAlpha; // magfilteralpha: // 0 = TX_POINT // 1 = TX_BILINEAR // 2 = None // 3 = TX_BICUBIC // 4 = TX_SHARPEN // 5 = TX_ADD_DETAIL // 6 = TX_MODULATE_DETAIL // 7 = TX_BILINEAR_GEQUAL // 8 = TX_BILINEAR_LEQUAL // 9 = TX_BICUBIC_GEQUAL // 10 = TX_BIBICUBIC_LEQUAL int32 magFilterColor; // magfiltercolor: // 0 = TX_POINT // 1 = TX_BILINEAR // 2 = None // 3 = TX_BICUBIC // 4 = TX_SHARPEN // 5 = TX_ADD_DETAIL // 6 = TX_MODULATE_DETAIL // 7 = TX_BILINEAR_GEQUAL // 8 = TX_BILINEAR_LEQUAL // 9 = TX_BICUBIC_GEQUAL // 10 = TX_BIBICUBIC_LEQUAL float32 reserved1; // Reserved float32 reserved2[8]; // Reserved float64 lambertMeridian; // Lambert conic projection central meridian float64 lambertUpperLat; // Lambert conic projection upper latitude float64 lambertlowerLat; // Lambert conic projection lower latitude float64 reserved3; // Reserved float32 spare2[5]; // Spare int32 useDetail; // TRUE if using next 5 integers for detail texture int32 txDetail_j; // J argument for TX_DETAIL int32 txDetail_k; // K argument for TX_DETAIL int32 txDetail_m; // M argument for TX_DETAIL int32 txDetail_n; // N argument for TX_DETAIL int32 txDetail_s; // Scramble argument for TX_DETAIL int32 useTile; // TRUE if using next for floats for TX_TILE float32 txTile_ll_u; // Lower-left u value for TX_TILE float32 txTile_ll_v; // Lower-left v value for TX_TILE float32 txTile_ur_u; // Upper-right u value for TX_TILE float32 txTile_ur_v; // Upper-right v value for TX_TILE int32 projection; // Projection // 0 = Flat earth // 3 = Lambert conic // 4 = UTM // 7 = Undefined projection int32 earthModel; // Earth model // 0 = WGS84 // 1 = WGS72 // 2 = Bessel // 3 = Clark 1866 // 4 = NAD27 int32 reserved4; // Reserved int32 utmZone; // UTM zone int32 imageOrigin; // Image origin // 0 = Lower-left // 1 = Upper-left int32 geoUnits; // Geospecific points units // 0 = Degrees // 1 = Meters // 2 = Pixels int32 reserved5; // Reserved int32 reserved6; // Reserved int32 hemisphere; // Hemisphere for geospecific points units // 0 = Southern // 1 = Northern int32 reserved7; // Reserved int32 reserved8; // Reserved int32 spare3[149]; // Spare char comments[512]; // Comments // -------------- // v12 ends here // -------------- int32 reserved9[13]; // Reserved int32 attrVersion; // Attribute file version number int32 controlPoints; // Number of geospecific control points // If the number of geospecific control points is > 0, // the following fields are also in the attribute file: int32 reserved10; // Reserved #if 0 // For each geospecific control point: { float64 texel_u; // Texel u of geospecific control point float64 texel_v; // Texel v of geospecific control point float64 geoPoint[2]; // Real earth coordinate of geospecific control point // (this value depends on the projection, earth model, // and geospecific points units) } // ---------------- // v15.6 ends here // ---------------- // After all geospecific control points are listed, the following subtexture // information appears: int32 subtextures; // Number of subtexture definitions contained in the // texture attribute file // If the number of subtexture definitions is >0, // the following fields are repeated for each subtexture definition: { char name[32]; // name of subtexture definition int32 left; // Coordinate of left edge of subtexture // definition measured in texels. int32 bottom; // Coordinate of bottom edge of subtexture // definition measured in texels. int32 right; // Coordinate of right edge of subtexture // definition measured in texels. int32 top; // Coordinate of top edge of subtexture // definition measured in texels. } #endif void read(); private : int _flt_version; }; void Attr::init() { texels_u = 0; textel_v = 0; direction_u = 0; direction_v = 0; x_up = 0; y_up = 0; fileFormat = -1; // -1 Not used minFilterMode = MIN_FILTER_NONE; magFilterMode = MAG_FILTER_POINT; wrapMode = WRAP_REPEAT; wrapMode_u = WRAP_REPEAT; wrapMode_v = WRAP_REPEAT; modifyFlag = 0; pivot_x = 0; pivot_y = 0; texEnvMode = TEXENV_MODULATE; intensityAsAlpha = 0; size_u = 0; size_v = 0; originCode = 0; kernelVersion = 0; intFormat = 0; // 0 - Default extFormat = 0; // 0 - Default useMips = 0; // float32 _mipMapKernel[8]; useLodScale = 0; // float32 lod0; // float32 scale0; // ... // float32 lod7; // float32 scale7; clamp = 0; magFilterAlpha = 2; // 2 = None magFilterColor = 2; // 2 = None lambertMeridian = 0; lambertUpperLat = 0; lambertlowerLat = 0; useDetail = 0; txDetail_j = 0; txDetail_k = 0; txDetail_m = 0; txDetail_n = 0; txDetail_s = 0; useTile = 0; txTile_ll_u = 0; txTile_ll_v = 0; txTile_ur_u = 0; txTile_ur_v = 0; projection = PROJECTION_UNDEFINED; earthModel = DATUM_WGS84; utmZone = 0; imageOrigin = 0; geoUnits = 0; hemisphere = 1; comments[0] = '\0'; attrVersion = 0; controlPoints = 0; // TODO: } void Attr::readField(std::ifstream& file, void* buf, size_t size) { if (file.eof()) return; file.read((char*)buf, size); if(::isLittleEndianMachine()) ::endian2(buf, size, buf); } bool Attr::readAttrFile(const char* szName) { int n; std::ifstream file; file.open (szName, std::ios::in | std::ios::binary); READ( texels_u ); READ( textel_v ); READ( direction_u ); READ( direction_v ); READ( x_up ); READ( y_up ); READ( fileFormat ); READ( minFilterMode ); READ( magFilterMode ); READ( wrapMode ); READ( wrapMode_u ); READ( wrapMode_v ); READ( modifyFlag ); READ( pivot_x ); READ( pivot_y ); // v11 ends here if (_flt_version <= 11) return true; READ( texEnvMode ); READ( intensityAsAlpha ); for (n=0; n<8; n++) { READ(spare1[n]); } READ( size_u ); READ( size_v ); READ( originCode ); READ( kernelVersion ); READ( intFormat ); READ( extFormat ); READ( useMips ); for (n=0; n<8; n++) { READ(_mipMapKernel[n]); } READ( useLodScale ); READ( lod0 ); READ( scale0 ); READ( lod1 ); READ( scale1 ); READ( lod2 ); READ( scale2 ); READ( lod3 ); READ( scale3 ); READ( lod4 ); READ( scale4 ); READ( lod5 ); READ( scale5 ); READ( lod6 ); READ( scale6 ); READ( lod7 ); READ( scale7 ); READ( clamp ); READ( magFilterAlpha ); READ( magFilterColor ); READ( reserved1 ); for (n=0; n<8; n++) { READ(reserved2[n]); } READ( lambertMeridian ); READ( lambertUpperLat ); READ( lambertlowerLat ); READ( reserved3 ); for (n=0; n<5; n++) { READ(spare2[n]); } // I don't know why I get a 4 bytes displacement before reading Detail Texture parameters // My ATTR files have been created with Creator 2.5.1 // Julian Ortiz, June 18th 2003. int32 dummyAjust; READ( dummyAjust); READ( useDetail ); READ( txDetail_j ); READ( txDetail_k ); READ( txDetail_m ); READ( txDetail_n ); READ( txDetail_s ); READ( useTile ); READ( txTile_ll_u ); READ( txTile_ll_v ); READ( txTile_ur_u ); READ( txTile_ur_v ); READ( projection ); READ( earthModel ); READ( reserved4 ); READ( utmZone ); READ( imageOrigin); READ( geoUnits ); READ( reserved5 ); READ( reserved6 ); READ( hemisphere ); READ( reserved7 ); READ( reserved8 ); for (n=0; n<149; n++) { READ(spare3[n]); } file.read(comments, sizeof(comments)); // v12 ends here if (_flt_version <= 12) return true; for (n=0; n<13; n++) { READ(reserved9[n]); } READ( attrVersion ); READ( controlPoints); READ( reserved10 ); file.close(); return true; } flt::AttrData* Attr::createOsgStateSet() { TexEnv* osgTexEnv = new TexEnv; Texture2D* osgTexture = new Texture2D; flt::AttrData* attrdata = new flt::AttrData; if ((wrapMode_u != WRAP_CLAMP) && ((wrapMode_u != WRAP_REPEAT))) wrapMode_u = wrapMode; if ((wrapMode_v != WRAP_CLAMP) && ((wrapMode_v != WRAP_REPEAT))) wrapMode_v = wrapMode; if (wrapMode_u == WRAP_CLAMP) osgTexture->setWrap(Texture2D::WRAP_S,Texture2D::CLAMP); else osgTexture->setWrap(Texture2D::WRAP_S,Texture2D::REPEAT); if (wrapMode_v == WRAP_CLAMP) osgTexture->setWrap(Texture2D::WRAP_T,Texture2D::CLAMP); else osgTexture->setWrap(Texture2D::WRAP_T,Texture2D::REPEAT); switch (texEnvMode) { case TEXENV_MODULATE: osgTexEnv->setMode(TexEnv::MODULATE); break; case TEXENV_BLEND: osgTexEnv->setMode(TexEnv::BLEND); break; case TEXENV_DECAL: osgTexEnv->setMode(TexEnv::DECAL); break; case TEXENV_COLOR: osgTexEnv->setMode(TexEnv::REPLACE); break; } /* An email on ATTR mappings to OpenGL : "[osg-news] OpenFlight Texture Filter Modes" from Joseph Steel: I posted a query on a forum on the Multigen web site re. the OpenFlight texture filer modes. This is the reply: Here are the mappings used by Creator under OpenGL: For Minification: Point (0): GL_NEAREST Bilinear (1): GL_LINEAR Mipmap Point (3): GL_NEAREST_MIPMAP_NEAREST Mipmap Linear (4): GL_NEAREST_MIPMAP_LINEAR Mipmap Bilinear (5): GL_LINEAR_MIPMAP_NEAREST Mipmap Trilinear (6): GL_LINEAR_MIPMAP_LINEAR Bicubic (8): GL_LINEAR_MIPMAP_NEAREST Bilinear Greater/Equal (9): GL_LINEAR_MIPMAP_NEAREST Bilinear Less/Equal (10): GL_LINEAR_MIPMAP_NEAREST Bicubic Greater/Equal (11): GL_LINEAR_MIPMAP_NEAREST Bicubic Less/Equal (12): GL_LINEAR_MIPMAP_NEAREST For Magnification: Point (0): GL_NEAREST Bilinear (1): GL_LINEAR Bicubic (3): GL_LINEAR Sharpen (4): GL_LINEAR Add Detail (5): GL_LINEAR Modulate Detail (6): GL_LINEAR Bilinear Greater/Equal (7): GL_LINEAR Bilinear Less/Equal (8): GL_LINEAR Bicubic Greater/Equal (9): GL_LINEAR Bicubic Less/Equal (10): GL_LINEAR Note that mode 2 for both minification & magnification are no longer supported. */ // ----------- // Min filter // ----------- switch (minFilterMode) { case MIN_FILTER_POINT: osgTexture->setFilter(osg::Texture2D::MIN_FILTER, Texture2D::NEAREST); break; case MIN_FILTER_BILINEAR: osgTexture->setFilter(osg::Texture2D::MIN_FILTER, Texture2D::LINEAR); break; case MIN_FILTER_MIPMAP_POINT: osgTexture->setFilter(osg::Texture2D::MIN_FILTER, Texture2D::NEAREST_MIPMAP_NEAREST); break; case MIN_FILTER_MIPMAP_LINEAR: osgTexture->setFilter(osg::Texture2D::MIN_FILTER, Texture2D::NEAREST_MIPMAP_LINEAR); break; case MIN_FILTER_MIPMAP_BILINEAR: osgTexture->setFilter(osg::Texture2D::MIN_FILTER, Texture2D::LINEAR_MIPMAP_NEAREST); break; case MIN_FILTER_MIPMAP_TRILINEAR: osgTexture->setFilter(osg::Texture2D::MIN_FILTER, Texture2D::LINEAR_MIPMAP_LINEAR); break; case MIN_FILTER_BICUBIC: case MIN_FILTER_BILINEAR_GEQUAL: case MIN_FILTER_BILINEAR_LEQUAL: case MIN_FILTER_BICUBIC_GEQUAL: case MIN_FILTER_BICUBIC_LEQUAL: osgTexture->setFilter(osg::Texture2D::MIN_FILTER, Texture2D::LINEAR_MIPMAP_NEAREST); break; default: osgTexture->setFilter(osg::Texture2D::MIN_FILTER, Texture2D::LINEAR_MIPMAP_LINEAR); break; break; } // ----------- // Mag filter // ----------- switch (magFilterMode) { case MAG_FILTER_POINT: osgTexture->setFilter(osg::Texture2D::MAG_FILTER, Texture2D::NEAREST); break; case MAG_FILTER_BILINEAR: case MAG_FILTER_BILINEAR_GEQUAL: case MAG_FILTER_BILINEAR_LEQUAL: case MAG_FILTER_SHARPEN: case MAG_FILTER_BICUBIC: case MAG_FILTER_BICUBIC_GEQUAL: case MAG_FILTER_BICUBIC_LEQUAL: case MAG_FILTER_ADD_DETAIL: case MAG_FILTER_MODULATE_DETAIL: osgTexture->setFilter(osg::Texture2D::MAG_FILTER, Texture2D::LINEAR); break; } // I have just ported the two below set*Attribute lines to use the new // texture attribute methods, however this tieing to the texture unit 0 // is probably inappropriate. Perhaps it would be better to create a // StateSet to store the texture an modes, it is probably best // to use an intermediate data structure for the flt loader to use to // encapsulate ATTR files. Need to speak to Brede about this issue. // Robert Osfield, July 9th 2002. // This is now a bit diferrent. We create a new AttrData object, and StateSet object // is instead with attribute information needed to setup detail texutre // // Julian Ortiz, June 18th 2003. attrdata->stateset = new StateSet; attrdata->stateset->setTextureAttribute( 0, osgTexEnv ); attrdata->stateset->setTextureAttributeAndModes( 0, osgTexture, StateAttribute::ON ); attrdata->useDetail = useDetail; attrdata->txDetail_j = txDetail_j; attrdata->txDetail_k = txDetail_k; attrdata->txDetail_m = txDetail_m; attrdata->txDetail_n = txDetail_n; attrdata->txDetail_s = txDetail_s; if (magFilterMode == MAG_FILTER_MODULATE_DETAIL) attrdata->modulateDetail = true; else attrdata->modulateDetail = false; return attrdata; } class ReaderWriterATTR : public osgDB::ReaderWriter { public: virtual const char* className() const { return "ATTR Image Attribute Reader/Writer"; } virtual bool acceptsExtension(const std::string& extension) const { return osgDB::equalCaseInsensitive(extension,"attr"); } virtual ReadResult readObject(const std::string& file, const osgDB::ReaderWriter::Options* options) const { std::string ext = osgDB::getLowerCaseFileExtension(file); if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED; std::string fileName = osgDB::findDataFile( file, options ); if (fileName.empty()) return ReadResult::FILE_NOT_FOUND; int version = 0; // Check the options string for the OpenFlight file version if (options) { // Get the character index of the FLT_VER option in the option // string std::string::size_type optionIndex = options->getOptionString().find("FLT_VER"); // Default to zero for the version if it's not found if (optionIndex == std::string::npos) version = 0; else { // Copy the option string, starting with the F in FLT_VER std::string fltVersionStr(options->getOptionString(), optionIndex); std::string optionText; // Read the version from the string std::istringstream ins(fltVersionStr); ins >> optionText >> version; } } Attr attr(version); if (!attr.readAttrFile(fileName.c_str())) { return "Unable to open \""+fileName+"\""; } //StateSet* stateset = attr.createOsgStateSet(); // Julian Ortiz, June 18th 2003. flt::AttrData* attrdata = attr.createOsgStateSet(); notify(INFO) << "texture attribute read ok" << std::endl; return attrdata; } }; // now register with Registry to instantiate the above // reader/writer. osgDB::RegisterReaderWriterProxy g_readerWriter_ATTR_Proxy;