diff --git a/src/osgPlugins/dx/AreaGeoSetTriangulator.cpp b/src/osgPlugins/dx/AreaGeoSetTriangulator.cpp deleted file mode 100644 index 93097a1d6..000000000 --- a/src/osgPlugins/dx/AreaGeoSetTriangulator.cpp +++ /dev/null @@ -1,642 +0,0 @@ -#include - -#include -#include - -#include "AreaGeoSetTriangulator.h" - -namespace dx { - -class AreaGeoSetTriangulator - // Used to convert area primitive GeoSets into TRIANGLE Geosets. - // Efficiently collects the various data arrays, which GeoSet can't do. -{ -protected: - std::vector< unsigned int > _cindex; - std::vector< unsigned int > _nindex; - std::vector< unsigned int > _colindex; - std::vector< unsigned int > _tindex; - const osg::GeoSet &_area_geoset; - -public: - AreaGeoSetTriangulator( const osg::GeoSet &area_geoset ); - - void operator() ( unsigned int v1, unsigned int v2, unsigned int v3, - unsigned int prim_index, unsigned int prim_tri_index, - unsigned int v1_geoset, unsigned int v2_geoset, - unsigned int v3_geoset ); - // Passed triangles as primitives are triangulated - - osg::GeoSet *BuildGeoSet(); -}; - -//--------------------------------------------------------------------------- -AreaGeoSetTriangulator::AreaGeoSetTriangulator( const osg::GeoSet &area_geoset) - : _area_geoset(area_geoset) -{ - // Check type - switch ( area_geoset.getPrimType() ) { - case osg::GeoSet::TRIANGLE_STRIP: - case osg::GeoSet::FLAT_TRIANGLE_STRIP: - case osg::GeoSet::TRIANGLES: - case osg::GeoSet::QUAD_STRIP: - case osg::GeoSet::QUADS: - case osg::GeoSet::TRIANGLE_FAN: - case osg::GeoSet::FLAT_TRIANGLE_FAN: - case osg::GeoSet::POLYGON: - break; - default: - fprintf( stderr, - "Invalid primitive type passed to AreaGeoSetTriangulator\n" ); - exit(1); - } - - // NOTE: _coords, _normals, _colors, and _tcoords are maintained - // from the original geoset. The new geoset will always have - // indexed coords/normals/colors/tcoords (to save space). -} - -//--------------------------------------------------------------------------- -void AreaGeoSetTriangulator::operator() ( - unsigned int v1, unsigned int v2, unsigned int v3, - unsigned int prim_index, unsigned int prim_tri_index, - unsigned int v1_geoset, unsigned int v2_geoset, - unsigned int v3_geoset ) - // Passed triangles as primitives are triangulated from the original - // GeoSet. Note that the v? params are indicies into the Coord array, - // whereas the v?_geoset params are vertex numbers relative to the - // entire "area GeoSet" (which are different when the coords are - // indexed). The latter is needed to look up colors/normals/tcoords). -{ - osg::GeoSet::BindingType binding; - osg::GeoSet::PrimitiveType primtype = _area_geoset.getPrimType(); - int area_is_flatprim = ( primtype == osg::GeoSet::FLAT_TRIANGLE_STRIP || - primtype == osg::GeoSet::FLAT_TRIANGLE_FAN ); - - // Store the triangle coord indicies - _cindex.push_back( v1 ); - _cindex.push_back( v2 ); - _cindex.push_back( v3 ); - - int index; - const osg::GeoSet::IndexPointer *ip; - - // Store normals (as needed) - if ( _area_geoset.getNumNormals() ) { - ip = &_area_geoset.getNormalIndices(); - - // Grrr... FLAT_ primitives lie about binding type... like Performer - binding = _area_geoset.getNormalBinding(); - if ( area_is_flatprim && binding == osg::GeoSet::BIND_PERVERTEX ) - binding = osg::GeoSet::BIND_PERPRIM; - - switch ( binding ) { - - case osg::GeoSet::BIND_OVERALL : // Only once - if ( prim_index == 0 && prim_tri_index == 0 ) { - index = ip->valid() ? (*ip)[0] : 0; - _nindex.push_back( index ); - break; - } - - case osg::GeoSet::BIND_PERPRIM : // Once per tri - index = ip->valid() ? (*ip)[prim_index] : prim_index; - _nindex.push_back( index ); - break; - - case osg::GeoSet::BIND_PERVERTEX : // Each vertex - index = ip->valid() ? (*ip)[v1_geoset] : v1_geoset; - _nindex.push_back( index ); - index = ip->valid() ? (*ip)[v2_geoset] : v2_geoset; - _nindex.push_back( index ); - index = ip->valid() ? (*ip)[v3_geoset] : v3_geoset; - _nindex.push_back( index ); - break; - - case osg::GeoSet::BIND_OFF: - case osg::GeoSet::BIND_DEFAULT: - // Nonsensical cases - break; - } - } - - // Store colors (as needed) - if ( _area_geoset.getNumColors() ) { - ip = &_area_geoset.getColorIndices(); - - // Grrr... FLAT_ primitives lie about binding type... like Performer - binding = _area_geoset.getColorBinding(); - if ( area_is_flatprim && binding == osg::GeoSet::BIND_PERVERTEX ) - binding = osg::GeoSet::BIND_PERPRIM; - - switch ( binding ) { - - case osg::GeoSet::BIND_OVERALL : // Only once - if ( prim_index == 0 && prim_tri_index == 0 ) { - index = ip->valid() ? (*ip)[0] : 0; - _colindex.push_back( index ); - break; - } - - case osg::GeoSet::BIND_PERPRIM : // Once per tri - index = ip->valid() ? (*ip)[prim_index] : prim_index; - _colindex.push_back( index ); - break; - - case osg::GeoSet::BIND_PERVERTEX : // Each vertex - index = ip->valid() ? (*ip)[v1_geoset] : v1_geoset; - _colindex.push_back( index ); - index = ip->valid() ? (*ip)[v2_geoset] : v2_geoset; - _colindex.push_back( index ); - index = ip->valid() ? (*ip)[v3_geoset] : v3_geoset; - _colindex.push_back( index ); - break; - - case osg::GeoSet::BIND_OFF: - case osg::GeoSet::BIND_DEFAULT: - // Nonsensical cases - break; - } - } - - // Store tcoords (as needed) - if ( _area_geoset.getNumTextureCoords() ) { - ip = &_area_geoset.getTextureIndices(); - - switch ( _area_geoset.getTextureBinding() ) { - - case osg::GeoSet::BIND_OVERALL : // Only once - if ( prim_index == 0 && prim_tri_index == 0 ) { - index = ip->valid() ? (*ip)[0] : 0; - _tindex.push_back( index ); - break; - } - - case osg::GeoSet::BIND_PERPRIM : // Once per tri - index = ip->valid() ? (*ip)[prim_index] : prim_index; - _tindex.push_back( index ); - break; - - case osg::GeoSet::BIND_PERVERTEX : // Each vertex - index = ip->valid() ? (*ip)[v1_geoset] : v1_geoset; - _tindex.push_back( index ); - index = ip->valid() ? (*ip)[v2_geoset] : v2_geoset; - _tindex.push_back( index ); - index = ip->valid() ? (*ip)[v3_geoset] : v3_geoset; - _tindex.push_back( index ); - break; - - case osg::GeoSet::BIND_OFF: - case osg::GeoSet::BIND_DEFAULT: - // Nonsensical cases - break; - } - } - -} - -//---------------------------------------------------------------------------- -// Shamelessly lifted from the GeoSet header and adapted for our uses -// This is the same except that: 1) it passes the coordinate indices -// to the op function insted of the Vec3s, and 2) it passes an original -// primitive index and "triangle-in-primitive" index to the op function, -// 3) it also passes the absolute vertex numbers in the primitive so they -// can be used to look up normals/colors/tcoords, and 4) fixes some -// problems with vertex ordering which caused FRONT/BACK confusion with -// normals and lighting. -// With this, we can construct a new TRIANGLE GeoSet from any area GeoSet. - -/** Template function for iterating through a GeoSet operating on triangles - with templated functor. Function automatically decomposes quads and polygons - into sub triangles which are passed onto functor.*/ - -template -void for_each_triangle2(const osg::GeoSet& gset,T& op) -{ - switch(gset.getPrimType()) - { - case(osg::GeoSet::TRIANGLE_STRIP): - case(osg::GeoSet::FLAT_TRIANGLE_STRIP): - { - if (gset.getCoordIndices().valid()) - { - if (gset.getCoordIndices()._is_ushort) - { - unsigned short* base = gset.getCoordIndices()._ptr._ushort; - unsigned short* iptr = base; - const int numPrim = gset.getNumPrims(); - for(int i=0; i0) - { - unsigned short *start = iptr; - unsigned short* iend = iptr+primLength; - ++iptr; - for(int j = 2; j < primLength; ++j ) - { - op(*start,*(iptr),*(iptr+1),i,tri++, - start-base, iptr-base,(iptr+1)-base); - ++iptr; - } - iptr=iend; - } - } - } - else - { - GLuint* base = gset.getCoordIndices()._ptr._uint; - GLuint* iptr = base; - const int numPrim = gset.getNumPrims(); - for(int i=0; i0) - { - GLuint *start = iptr; - GLuint* iend = iptr+primLength; - ++iptr; - for(int j = 2; j < primLength; ++j ) - { - op(*start,*(iptr),*(iptr+1),i,tri++, - start-base, iptr-base,(iptr+1)-base); - ++iptr; - } - iptr=iend; - } - } - } - } - else - { - unsigned int cindex = 0; - const int numPrim = gset.getNumPrims(); - for(int i=0; i0) - { - unsigned int cindex_start = cindex; - unsigned int cindex_end = cindex+primLength; - ++cindex; - for(int j = 2; j < primLength; ++j) - { - op(cindex_start,cindex,cindex+1,i,tri++, - cindex_start,cindex,cindex+1); - ++cindex; - } - cindex = cindex_end; - } - } - } - } - break; - default: - break; - } - -} - - -//--------------------------------------------------------------------------- -osg::GeoSet *AreaGeoSetTriangulator::BuildGeoSet() - // After a triangulation pass, generate a valid TRIANGLE GeoSet containing - // the resulting triangles (w/ colors, normals, and tcoords). -{ - int num_tris = _cindex.size() / 3; - - osg::GeoSet *res = new osg::GeoSet; - res->setPrimType( osg::GeoSet::TRIANGLES ); - res->setNumPrims( num_tris ); - - // First, dup all of the data arrays -- they haven't changed - // NOTE: We generate fresh arrays for the new GeoSet to be compatible - // with the delete [] behavior of the default GeoSet - // AttributeDeleteFunctor, which is invoked in GeoSet::~GeoSet. - - osg::Vec3 *new_coords = 0; - osg::Vec3 *new_normals = 0; - osg::Vec4 *new_colors = 0; - osg::Vec2 *new_tcoords = 0; - - const osg::Vec3 *coords = _area_geoset.getCoords(); - const osg::Vec3 *normals = _area_geoset.getNormals(); - const osg::Vec4 *colors = _area_geoset.getColors(); - const osg::Vec2 *tcoords = _area_geoset.getTextureCoords(); - - if ( coords ) - new_coords = new osg::Vec3[ _area_geoset.getNumCoords() ]; - if ( normals ) - new_normals = new osg::Vec3[ _area_geoset.getNumNormals() ]; - if ( colors ) - new_colors = new osg::Vec4[ _area_geoset.getNumColors() ]; - if ( tcoords ) - new_tcoords = new osg::Vec2[ _area_geoset.getNumTextureCoords() ]; - - memcpy( new_coords, coords, - sizeof(osg::Vec3) * _area_geoset.getNumCoords() ); - memcpy( new_normals, normals, - sizeof(osg::Vec3) * _area_geoset.getNumNormals() ); - memcpy( new_colors, colors, - sizeof(osg::Vec4) * _area_geoset.getNumColors() ); - memcpy( new_tcoords, tcoords, - sizeof(osg::Vec2) * _area_geoset.getNumTextureCoords() ); - - // Now generate the index arrays - GLuint *new_cindex = 0; - GLuint *new_nindex = 0; - GLuint *new_colindex = 0; - GLuint *new_tindex = 0; - - if ( _cindex.size() ) new_cindex = new GLuint[ _cindex.size() ]; - if ( _nindex.size() ) new_nindex = new GLuint[ _nindex.size() ]; - if ( _colindex.size() ) new_colindex = new GLuint[ _colindex.size() ]; - if ( _tindex.size() ) new_tindex = new GLuint[ _tindex.size() ]; - - memcpy( new_cindex , &_cindex [0], sizeof(GLuint) * _cindex.size() ); - memcpy( new_nindex , &_nindex [0], sizeof(GLuint) * _nindex.size() ); - memcpy( new_colindex, &_colindex[0], sizeof(GLuint) * _colindex.size() ); - memcpy( new_tindex , &_tindex [0], sizeof(GLuint) * _tindex.size() ); - - res->setCoords ( new_coords , new_cindex ); - res->setNormals( new_normals, new_nindex ); - res->setColors ( new_colors , new_colindex ); - res->setTextureCoords( new_tcoords, new_tindex ); - - // And finally, set the normal/color/tcoord binding - // (Grrr... FLAT_ primitives lie about binding type... like Performer) - osg::GeoSet::BindingType nbinding = _area_geoset.getNormalBinding(); - osg::GeoSet::BindingType cbinding = _area_geoset.getColorBinding(); - if ( _area_geoset.getPrimType() == osg::GeoSet::FLAT_TRIANGLE_STRIP || - _area_geoset.getPrimType() == osg::GeoSet::FLAT_TRIANGLE_FAN ) { - if ( nbinding == osg::GeoSet::BIND_PERVERTEX ) - nbinding = osg::GeoSet::BIND_PERPRIM; - if ( cbinding == osg::GeoSet::BIND_PERVERTEX ) - cbinding = osg::GeoSet::BIND_PERPRIM; - } - - res->setNormalBinding ( nbinding ); - res->setColorBinding ( cbinding ); - res->setTextureBinding( _area_geoset.getTextureBinding() ); - - return res; -} - -//--------------------------------------------------------------------------- -osg::GeoSet *TriangulateAreaGeoSet( const osg::GeoSet &geoset ) - // The strategy here is to generate new coord/normal/color/tcoord index - // arrays as we bust up the primitives into triangles. The data arrays - // don't change between the old and new geoset. -{ - geoset.computeNumVerts(); // Update # coords/# normals from index arrays - - AreaGeoSetTriangulator triangulator( geoset ); - for_each_triangle2( geoset, triangulator ); - return triangulator.BuildGeoSet(); -} - -}; // namespace dx diff --git a/src/osgPlugins/dx/AreaGeoSetTriangulator.h b/src/osgPlugins/dx/AreaGeoSetTriangulator.h deleted file mode 100644 index 60f164b36..000000000 --- a/src/osgPlugins/dx/AreaGeoSetTriangulator.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __OSG_AREA_GEOSET_TRIANGULATOR_H -#define __OSG_AREA_GEOSET_TRIANGULATOR_H - -#include - -namespace dx { - -osg::GeoSet *TriangulateAreaGeoSet( const osg::GeoSet &geoset ); - -}; - -#endif diff --git a/src/osgPlugins/dx/DXWriter.cpp b/src/osgPlugins/dx/DXWriter.cpp deleted file mode 100644 index 792cf9910..000000000 --- a/src/osgPlugins/dx/DXWriter.cpp +++ /dev/null @@ -1,2691 +0,0 @@ -// This plugin writes an IBM Data Explorer (aka OpenDX) native file. -// (c) Randall Hopper, 2002. -// -// For details on the OpenDX visualization tool, its use, and its file format, -// refer to: -// -// http://www.opendx.org/ -// http://www.opendx.org/support.html#docs -// http://www.research.ibm.com/dx/ -// http://ftp.cs.umt.edu/DX/ -// -// SUPPORTED: -// -// - Objects without color are assigned a default opaque light gray color -// - All GeoSet primitive types: -// POINTS, LINES, TRIANGLES, QUADS, LINE_STRIP, FLAT_LINE_STRIP, -// LINE_LOOP, TRIANGLE_STRIP, FLAT_TRIANGLE_STRIP, TRIANGLE_FAN, -// FLAT_TRIANGLE_FAN, QUAD_STRIP, POLYGON -// NOTE: area strips, fans, polygons, and quads are mapped to triangles -// fields; line strips and loops are mapped to polylines fields -// - OSG Node Types: -// Geode, Group, Billboards (hack), LOD (hack), Switch (hack) -// NOTES: Billboards - written as a translation Transform parenting -// the Geode Fields, so they do not rotate in DX like they should; -// LODs - only the most detailed child is written; -// Switches - only the active child is written -// - Coords, colors, normals, tcoords; with all binding types -// (per vertex/primitive/overall) -// - MATERIAL attributes -- all except ColorMode -// - Single texturing (TEXTURE_0), with RGB, RGBA, LUMINANCE, LUMINANCE_ALPHA -// textures (note: you'll need a recent DX from CVS for this to work); -// note that LUMINANCE* textures are expanded to RGB* in the conversion -// - Texture function, texture min/mag filters -// - Cull face -// -// UNSUPPORTED: -// -// - OSG Scene Graph Node Types: -// LightSource, Transform, Imposter, ClearNode, -// Switch - only active child written -// LOD - only most detailed child written -// Billboard - only static translation transform parenting child written, -// and only one Geode per Billboard is supported; DX has -// no concept just like Performer/OSG billboards that rotate -// to face the camera but scale and translate with the scene -// -// - Interleaved GeoSet data (interleaved set, no coords set) -// -// - Report just the unhandled GL modes/attributes, not all of them -// -// - DX only supports UNSIGNED_BYTE GL_RGB (and now GL_RGBA in recent CVS) -// textures, so we convert LUMINANCE* textures to RGB* -// -// - Handle other attributes in StateSet -// -// - TEXTURE_[1-3], and rest of subattributes in TEXTURE_0 -// - MATERIAL - ColorMode (read but never processed); specifies that -// certain material attributes are set by glColor -// - ALPHAFUNC -// - ANTIALIAS -// - COLORTABLE -// - FOG -// - FRONTFACE -// - LIGHT, LIGHT_[0-7] -// - POINT -// - LINEWIDTH -// - POLYGONMODE -// - POLYGONOFFSET -// - TEXENV -// - TEXGEN -// - TEXMAT -// - TRANSPARENCY -// - STENCIL -// - COLORMASK -// - DEPTH -// - VIEWPORT -// - CLIPPLANE, CLIPPLANE_[0-5] -// - COLORMATRIX -// -// OTHER TO DO: -// -// - Use more meaningful names for nameless nodes (based on parent names) -// - Don't write a colormap when OSG colors aren't indexed unless num -// colors > 256 or something (see cane example) -// - Support ReaderWriter::Options for exporter switches -// - Support saving DX stream in both ASCII and binary -// - Handle normal/color/tcoord collisions (aliasing) when coords are indexed -// (See comment in DXArrayWriter::WritePerVertexNormals for details) -// Same applies for normals, colors, and tcoords -// - Handle accumulation of more than just Geodes in Groups (?) -// - Consider support for writing DX file with interleaved arrays, -// arrays at end, arrays in diff file in DX file -// - char [] -> std::string, globally -// -// DXWriter.h - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include "DXWriter.h" -#include "AreaGeoSetTriangulator.h" -#include "StateSetStr.h" - - -#if defined(__sgi) || defined(__FreeBSD__) - #include - #include -#else - #include - #if (defined(WIN32) || defined (__APPLE__)) && !defined(__CYGWIN__) - #include - #else - #include - #endif -#endif - -#if defined(WIN32) && !defined(__CYGWIN__) -#define vsnprintf _vsnprintf -#define snprintf _snprintf -#endif - - -namespace dx { - -//---------------------------------------------------------------------------- -// COMPILATION TWEAKS -//---------------------------------------------------------------------------- - -//#define SKIP_SINGLE_MEMBER_DXGROUPS - -//---------------------------------------------------------------------------- - -const osg::Vec3 INVALID_NORMAL ( -99,-99,-99 ); -const osg::Vec3 INVALID_COLOR ( 0,0,0 ); -const float INVALID_OPACITY = 1.0; -const float ALPHA_OPAQUE = 1.0; - -#define ARRAY_LEN(a) (sizeof(a)/sizeof((a)[0])) - -typedef unsigned char Vec4UB[4]; -typedef unsigned char Vec3UB[3]; - -//---------------------------------------------------------------------------- - -class DXNameManager - // Generates unique object names -{ - public: - std::string GetUnique( const std::string &suggestion ); - - protected: - std::map< std::string, int > dict; -}; - -std::string DXNameManager::GetUnique( const std::string &suggestion ) -{ - std::string name = suggestion; - int counter = 1; - char buf[30]; - - while ( dict.find( name ) != dict.end() ) { - sprintf( buf, " #%d", counter++ ); - name = ( suggestion.empty() ? "Object" : suggestion ) + buf; - } - dict[name] = 1; - return name; -} - -//---------------------------------------------------------------------------- - -class DXTextureManager - // Keeps track of what textures we've already written and their field names -{ - public: - void Register( const osg::Image *image, std::string dx_name ) - { dict[ image ] = dx_name; } - bool IsRegistered( const osg::Image *image ) - { return dict.find( image ) != dict.end(); } - std::string Lookup( const osg::Image *image ) - { return dict[ image ]; } - - protected: - std::map< const osg::Image *, std::string > dict; -}; - -//---------------------------------------------------------------------------- - -class MessageBin -{ - protected: - typedef std::vector< std::string > MessageList; - MessageList msg_list; - - public: - void Add( char fmt[], ... ) - { - char msg[1024]; - va_list args; - va_start(args, fmt); - vsnprintf(msg, sizeof(msg), fmt, args); - va_end(args); - - msg_list.push_back( std::string( msg ) ); - } - - std::string GetPending() - { - std::string result; - for ( unsigned i = 0; i < msg_list.size(); i++ ) { - if ( !result.empty() ) - result += '\n'; - result += msg_list[i]; - } - return result; - } - - void Clear() - { msg_list.clear(); } -}; - -//---------------------------------------------------------------------------- - -class DXField -{ - public: - struct Component { - std::string name; - std::string value; - Component( const char name[], const char value[] ) - : name(name), value(value) {} - }; - - std::vector< Component > comp; - std::string name; - - DXField( DXNameManager &name_mgr, const std::string *name_suggestion ) - { if ( name_suggestion && !name_suggestion->empty() ) - name = *name_suggestion; - else - name = "Field"; - name = name_mgr.GetUnique( name ); - } - - std::string &GetName() { return name; } - - void AddComponent( const char name[], const char value[] ) - { comp.push_back( Component( name, value ) ); } - - void Write( FILE *fp, const char *attr=0 ) - { - fprintf( fp, "object \"%s\" class field\n", name.c_str() ); - for ( unsigned i = 0; i < comp.size(); i++ ) - fprintf( fp, "component \"%s\" value \"%s\"\n", - comp[i].name.c_str(), comp[i].value.c_str() ); - if ( attr ) - fprintf( fp, "%s\n", attr ); - fprintf( fp, "#\n\n" ); - } -}; - -//---------------------------------------------------------------------------- - -class DXGroup -{ - public: - typedef std::vector< std::string > MemberList; - MemberList members; - std::string name; - - DXGroup( DXNameManager &name_mgr, - const std::string *name_suggestion = 0, - const std::string *fallback_suggestion = 0 ) - { if ( name_suggestion && !name_suggestion->empty() ) - name = *name_suggestion; - else if ( fallback_suggestion ) - name = fallback_suggestion->c_str(); - else - name = "Group"; - name = name_mgr.GetUnique( name ); - } - - void AddMember( const char member_name[] ) - { members.push_back( std::string( member_name ) ); } - - void RemoveMember( const char member_name[] ) - { - for(MemberList::iterator itr=members.begin(); - itr!=members.end(); - ++itr) - if ( *itr == member_name ) { - members.erase(itr); - break; - } - } - - int GetNumMembers() { return members.size(); } - - std::string &GetName() { return name; } - - void Write( FILE *fp, const char *attr=0 ) - { - fprintf( fp, "object \"%s\" class group\n", GetName().c_str() ); - for ( unsigned i = 0; i < members.size(); i++ ) - fprintf( fp, "member %d value \"%s\"\n", i, members[i].c_str() ); - if ( attr ) - fprintf( fp, "%s\n", attr ); - fprintf( fp, "#\n\n" ); - } -}; - -//---------------------------------------------------------------------------- - -class DXArrayWriter -{ - protected: - FILE *fp; - MessageBin *msg_bin; - - public: - void SetFP ( FILE *_fp ) { fp = _fp; } - void SetMsgBin( MessageBin *_msg_bin ) { msg_bin = _msg_bin; } - - void DeNanify( float &f, float subst ); - void DeNanify( osg::Vec3 &v, const osg::Vec3 &subst ); - void OSGColorToDX( const osg::Vec4 &osg_color, - osg::Vec3 &dx_color, float &dx_opacity ); - void OSGColorToDX( const Vec4UB osg_color, - Vec3UB dx_color, float &dx_opacity ); - int WriteMapsYN( osg::GeoSet::IndexPointer *ip, int num_colors ); - void WriteAttributes( const char *ref, const char *dep, const char *attr ); - void WriteFloatConstArray( float f, int len, const char name[], - const char *ref, const char *dep, const char *attr=0 ); - void WriteVec3ConstArray( const osg::Vec3 &v, int len, const char name[], - const char *ref, const char *dep, const char *attr=0 ); - void WriteFloatArray( const float *array, osg::GeoSet::IndexPointer *ip, - int len, const char name[], - const char *ref, const char *dep, const char *attr=0 ); - void WriteVec2Array( const osg::Vec2 *array, osg::GeoSet::IndexPointer *ip, - int len, const char name[], - const char *ref, const char *dep, const char *attr=0 ); - void WriteVec3Array( const osg::Vec3 *array, osg::GeoSet::IndexPointer *ip, - int len, const char name[], - const char *ref, const char *dep, const char *attr=0 ); - void WriteVec4Array( const osg::Vec4 *array, osg::GeoSet::IndexPointer *ip, - int len, const char name[], - const char *ref, const char *dep, const char *attr=0 ); - void WriteUByte3Array( - const Vec3UB *arrayp, osg::GeoSet::IndexPointer *ip, - int len, const char name[], - const char *ref, const char *dep, const char *attr=0 ); - - void WriteIndexArray( const osg::GeoSet::IndexPointer &ip, int len, - int rank, int shape, int ubyte, const char name[], - const char *ref, const char *dep, const char *attr=0 ); - void WriteColors( const osg::Vec4 *colors, int num_colors, - osg::GeoSet::IndexPointer *ip, int num_cindices, - const char colors_name[], const char colormap_name[], - const char opacities_name[], const char opacitymap_name[], - int do_opacities, const char *dep, int &wrote_maps ); - - void WriteColors( const Vec4UB colors[], int num_colors, - osg::GeoSet::IndexPointer *ip, int num_cindices, - const char colors_name[], const char colormap_name[], - const char opacities_name[], const char opacitymap_name[], - int do_opacities, const char *dep, int &wrote_maps ); - - void WritePerVertexNormals( const osg::GeoSet &geoset, const char name[] ); - void WritePerVertexColors( const osg::GeoSet &geoset, - const char colors_name[], - const char colormap_name[], - const char opacities_name[], - const char opacitymap_name[], - int do_opacities, // FIXME - int &wrote_maps ); - void WritePerVertexTCoords( const osg::GeoSet &geoset, const char name[] ); -}; - -//---------------------------------------------------------------------------- - -class MyStateSet -{ - protected: - MessageBin &msg_bin; - - public: - - std::map< osg::StateAttribute::Type, int > attr; - - // MATERIAL (osg::Material) - osg::Material::ColorMode colormode; - osg::Vec4 ambient_f, ambient_b; // Front and back colors - bool ambient_f_and_b; // Use front color for front and back - osg::Vec4 diffuse_f, diffuse_b; - bool diffuse_f_and_b; - osg::Vec4 specular_f, specular_b; - bool specular_f_and_b; - osg::Vec4 emission_f, emission_b; - bool emission_f_and_b; - float shininess_f, shininess_b; - bool shininess_f_and_b; - - // TEXTURE / TEXTURE_0 - const osg::Image *image; - osg::Texture2D::WrapMode wrap_s, wrap_t; - osg::Texture2D::FilterMode min_filter, mag_filter; - - // TEXENV - osg::TexEnv::Mode texture_func; - - MyStateSet( MessageBin &msg_bin ) : msg_bin(msg_bin), image(0) {} - - // CULLFACE - osg::CullFace::Mode cullface_mode; - - void Show( osg::StateSet &sset ); - void AddAttribute( osg::StateAttribute::Type type ) - { attr[ type ] = 1; } - bool HasAttribute( osg::StateAttribute::Type type ) - { return attr.find( type ) != attr.end(); } - void Query( const osg::StateSet &sset ); - void Write(); -}; - -//---------------------------------------------------------------------------- - -class StateSetCopy : public osg::StateSet -{ - public: - StateSetCopy() {} - ~StateSetCopy() {} - - StateSetCopy( const osg::StateSet &sset ) - { - // Can't use operator = because StateSet broke it - _modeList = sset.getModeList(); - _attributeList = sset.getAttributeList(); - _renderingHint = sset.getRenderingHint(); - _binMode = sset.getRenderBinMode(); - _binNum = sset.getBinNumber(); - _binName = sset.getBinName(); - } -}; - -//---------------------------------------------------------------------------- - -class DXWriter -{ - protected: - DXArrayWriter w; - - typedef std::map ModeList; - typedef std::map AttrList; - ModeList unsupported_modes; - AttrList unsupported_attrs; - - public: - FILE *fp; - WriterParms parms; - DXNameManager name_mgr; - DXTextureManager texture_mgr; - MessageBin msg_bin; - - void SetParms( const WriterParms &p ) - { memcpy( &parms, &p, sizeof(parms) ); } - - void Open(); - void Close(); - - std::string BuildStateSetAttributes( MyStateSet &sset, - int diffuse_is_color, - int diffuse_is_opacity ); - - std::string WriteImage( const osg::Image &image ); - - void WritePolylineConnections( osg::GeoSet &geoset, - DXField &field ); - std::string WriteGeoSetField( const std::string &field_name, - osg::GeoSet &geoset, - MyStateSet &sset ); - std::string WriteGeoSet( osg::GeoSet &geoset, - const osg::StateSet &active_sset, - std::string &field_name ); - std::string WriteGeode( osg::Geode &geode, - const osg::StateSet &active_sset ); - - void CollectUnhandledModesAndAttrs( osg::StateSet *sset ); - void ReportUnhandledModesAndAttrs(); -}; - -//---------------------------------------------------------------------------- - -inline int WARNING( char fmt[], ... ) -{ - va_list args; - va_start(args, fmt); - int ret = vfprintf(stderr, fmt, args); - va_end(args); - return ret; -} - -//---------------------------------------------------------------------------- - -void GetParms( int argc, char *argv[], - char infile [ DX_PATH_MAX ], WriterParms &parms ) -{ - WriterParms defaults; - - /* Init defaults */ - parms = defaults; - - /* Parse user args */ - int c, i, errflg = 0; - char *arg = NULL; - - /* We'd use getopt(), but we have args with leading minus chars... */ - for ( i = 1; i < argc && !errflg; i++ ) { - if ( argv[i][0] == '\0' ) continue; - - if ( argv[i][0] != '-' ) - break; - - c = argv[i][1]; - if ( strchr( "c", c ) ) { - if ( i+1 >= argc ) { - WARNING( "Missing argument to -%c option.\n\n", c ); - errflg++; - break; - } - - arg = argv[++i]; - } - - switch ( c ) { - case 'c': parms.set_default_color = 1; - sscanf( arg, "%g,%g,%g,%g", - &parms.default_color[0], &parms.default_color[1], - &parms.default_color[2], &parms.default_color[3] ); - break; - case '?': - default : - errflg++; - } - } - - if ( i != argc - 2 ) - errflg++; - - if (errflg) { - WARNING( "\n" - "Converts 3D model files to IBM Data Explorer format.\n\n" - "Usage: osg2dx\n" - " [-c r,g,b,a] # Give uncolored objs this color\n" - " # Input model pathname\n" - " # Output DX pathname (- = stdout)\n" - "\n" ); - exit(2); - } - - infile[0] = parms.outfile[0] = '\0'; - strncat( infile , argv[ i ], DX_PATH_MAX-1 ); - strncat( parms.outfile, argv[i+1], sizeof(parms.outfile)-1 ); -} - -//---------------------------------------------------------------------------- - -inline int IsNaNorInf( float f ) -{ -#if defined(__sgi) - int c = fpclass( double(f) ); - switch (c) - { - case FP_SNAN : - case FP_QNAN : - case FP_NINF : - case FP_PINF : return 1; - default : return 0; - } -#elif defined(__FreeBSD__) || defined(__APPLE__) - return isnan(f) || isinf(f); // isnanf is deprecated -#elif defined(__linux) || defined(__CYGWIN__) - return isnanf(f) || isinf(f); -#elif defined(__sun) - return isnan(f); // KLUDGE - hack to get this to compile w/g++. -#elif defined(WIN32) - return _isnan(f) || !_finite(f); -#elif defined(__hpux__) - // this is a hack - cmath from gcc 3.1 #undef's isinf() but does not - // redefine it (at least for me), enabling _GLIBCPP_USE_C99 also - // doesn't help (loads of compilation errors), so I just repeat the - // definition of isinf() from math.h here. - return isnan(f) || (_ISINF(f)); -#else -# error Teach me how to find non-numbers on this platform. -return 0; -#endif -} - - -void DXArrayWriter::DeNanify( float &f, float subst ) -{ - if ( IsNaNorInf((double)f) ) { - msg_bin->Add( "WARNING: Denanifying double.\n" ); - f = subst; - } -} - -void DXArrayWriter::DeNanify( osg::Vec3 &v, const osg::Vec3 &subst ) -{ - // An old OSG bug generated NaN normals from 0,0,0 normals; - // consider removing this someday. - // Also, Performer town has a NaN in one of the colormaps. - if ( IsNaNorInf((double)v[0]) || IsNaNorInf((double)v[1]) || - IsNaNorInf((double)v[2]) ) { - msg_bin->Add( "WARNING: Denanifying 3D vector.\n" ); - v = subst; - } -} - -//---------------------------------------------------------------------------- - -void DXArrayWriter::OSGColorToDX( const osg::Vec4 &osg_color, - osg::Vec3 &dx_color, float &dx_opacity ) -{ - dx_color.set( osg_color[0], osg_color[1], osg_color[2] ); - dx_opacity = osg_color[3]; // alpha==1.0 -> opaque -} - -//---------------------------------------------------------------------------- - -void DXArrayWriter::OSGColorToDX( const Vec4UB osg_color, - Vec3UB dx_color, float &dx_opacity ) -{ - dx_color[0] = osg_color[0]; - dx_color[1] = osg_color[1]; - dx_color[2] = osg_color[2]; - dx_opacity = osg_color[3] / 255.0; // alpha==1.0 -> opaque -} - -//---------------------------------------------------------------------------- - -int DXArrayWriter::WriteMapsYN( osg::GeoSet::IndexPointer *ip, int num_colors ) -{ - // Yes, if we have indexed colors and the number of colors mapped to - // is <= 256. - return ( ip && ip->valid() && num_colors <= 256 ); -} - -//---------------------------------------------------------------------------- - -void DXArrayWriter::WriteAttributes( const char *ref, const char *dep, - const char *attr ) -{ - if ( attr && attr[0] ) - fprintf( fp, "%s\n", attr ); - if ( ref ) - fprintf( fp, "attribute \"ref\" string \"%s\"\n", ref ); - if ( dep ) - fprintf( fp, "attribute \"dep\" string \"%s\"\n", dep ); -} - -//---------------------------------------------------------------------------- - -void DXArrayWriter::WriteFloatConstArray( - float f, int len, const char name[], - const char *ref, const char *dep, const char *attr ) -{ - fprintf( fp, "object \"%s\" class constantarray type float" - " rank 0 items %d data follows\n", - name, len ); - fprintf( fp, " %g\n", f ); - WriteAttributes( ref, dep, attr ); - fprintf( fp, "#\n\n" ); -} - -//---------------------------------------------------------------------------- - -void DXArrayWriter::WriteVec3ConstArray( - const osg::Vec3 &v, int len, const char name[], - const char *ref, const char *dep, const char *attr ) -{ - fprintf( fp, "object \"%s\" class constantarray type float" - " rank 1 shape 3 items %d data follows\n", - name, len ); - fprintf( fp, " %g %g %g\n", v[0], v[1], v[2] ); - WriteAttributes( ref, dep, attr ); - fprintf( fp, "#\n\n" ); -} - -//---------------------------------------------------------------------------- - -void DXArrayWriter::WriteFloatArray( - const float *array, osg::GeoSet::IndexPointer *ip, - int len, const char name[], - const char *ref, const char *dep, const char *attr ) - // If ip && ip.valid(), use it to index; else index array directly -{ - int index; - - fprintf( fp, "object \"%s\" class array type float" - " rank 0 items %d data follows\n", - name, len ); - for ( int i = 0; i < len; i++ ) { - index = ( ip && ip->valid() ) ? (*ip)[i] : i; - - fprintf( fp, " %g\n", array[index] ); - } - WriteAttributes( ref, dep, attr ); - fprintf( fp, "#\n\n" ); -} - -//---------------------------------------------------------------------------- - -void DXArrayWriter::WriteVec2Array( - const osg::Vec2 *array, osg::GeoSet::IndexPointer *ip, - int len, const char name[], - const char *ref, const char *dep, const char *attr ) - // If ip && ip.valid(), use it to index; else index array directly -{ - int index; - - fprintf( fp, "object \"%s\" class array type float" - " rank 1 shape 2 items %d data follows\n", - name, len ); - for ( int i = 0; i < len; i++ ) { - index = ( ip && ip->valid() ) ? (*ip)[i] : i; - - fprintf( fp, " %g %g\n", array[index][0], array[index][1] ); - } - WriteAttributes( ref, dep, attr ); - fprintf( fp, "#\n\n" ); -} - -//---------------------------------------------------------------------------- - -void DXArrayWriter::WriteVec3Array( - const osg::Vec3 *array, osg::GeoSet::IndexPointer *ip, - int len, const char name[], - const char *ref, const char *dep, const char *attr ) - // If ip && ip.valid(), use it to index; else index array directly -{ - int index; - - fprintf( fp, "object \"%s\" class array type float" - " rank 1 shape 3 items %d data follows\n", - name, len ); - for ( int i = 0; i < len; i++ ) { - index = ( ip && ip->valid() ) ? (*ip)[i] : i; - - fprintf( fp, " %g %g %g\n", - array[index][0], array[index][1], array[index][2] ); - } - WriteAttributes( ref, dep, attr ); - fprintf( fp, "#\n\n" ); -} - -//---------------------------------------------------------------------------- - -void DXArrayWriter::WriteVec4Array( - const osg::Vec4 *array, osg::GeoSet::IndexPointer *ip, - int len, const char name[], - const char *ref, const char *dep, const char *attr ) - // If ip && ip.valid(), use it to index; else index array directly -{ - int index; - - fprintf( fp, "object \"%s\" class array type float" - " rank 1 shape 4 items %d data follows\n", - name, len ); - for ( int i = 0; i < len; i++ ) { - index = ( ip && ip->valid() ) ? (*ip)[i] : i; - - fprintf( fp, " %g %g %g %g\n", - array[index][0], array[index][1], - array[index][2], array[index][3] ); - } - WriteAttributes( ref, dep, attr ); - fprintf( fp, "#\n\n" ); -} - -//---------------------------------------------------------------------------- - -void DXArrayWriter::WriteIndexArray( - const osg::GeoSet::IndexPointer &ip, int len, - int rank, int shape, int ubyte, - const char name[], - const char *ref, const char *dep, const char *attr ) - // If ip.null(), write a sequential index (0,1,2,3,...) -{ - const char *type_str = ( ubyte ? "unsigned byte" : "int" ); - char shape_str[40]; - - assert( rank == 0 || rank == 1 ); - if ( rank == 0 ) - shape_str[0] = '\0'; - else - sprintf( shape_str, "shape %d ", shape ); - fprintf( fp, "object \"%s\" class array type %s" - " rank %d %sitems %d data follows\n", - name, type_str, rank, shape_str, len/shape ); - - for ( int i = 0; i < len; i++ ) { - if ( i % shape == 0 ) - fprintf( fp, " " ); - { - if ( ip.null() ) fprintf( fp, " %d", i ); - else fprintf( fp, " %d", static_cast( ip[i] ) ); - } - if ( (i+1) % shape == 0 ) - fprintf( fp, "\n" ); - } - WriteAttributes( ref, dep, attr ); - fprintf( fp, "#\n\n" ); -} - -//---------------------------------------------------------------------------- - -void DXArrayWriter::WriteUByte3Array( - const Vec3UB *array, osg::GeoSet::IndexPointer *ip, - int len, const char name[], - const char *ref, const char *dep, const char *attr ) - // If ip && ip.valid(), use it to index; else index array directly -{ - int index; - - fprintf( fp, "object \"%s\" class array type unsigned byte" - " rank 1 shape 3 items %d data follows\n", - name, len ); - for ( int i = 0; i < len; i++ ) { - index = ( ip && ip->valid() ) ? (*ip)[i] : i; - - fprintf( fp, " %d %d %d\n", - array[index][0], array[index][1], array[index][2] ); - } - WriteAttributes( ref, dep, attr ); - fprintf( fp, "#\n\n" ); -} - -//---------------------------------------------------------------------------- - -void DXArrayWriter::WriteColors( - const osg::Vec4 *colors, int num_colors, - osg::GeoSet::IndexPointer *ip, int num_cindices, - const char colors_name[], const char colormap_name[], - const char opacities_name[], const char opacitymap_name[], - int do_opacities, const char *dep, int &wrote_maps ) -{ - int do_maps = WriteMapsYN( ip, num_colors ); - int i; - - // If should write color/opacity maps... - if ( do_maps ) { - - // Separate colors and opacities - osg::Vec3 *colors2 = new osg::Vec3[256]; - float *opacities2 = new float [256]; - for ( i = 0; i < num_colors; i++ ) { - OSGColorToDX( colors[i], colors2[i], opacities2[i] ); - DeNanify( colors2[i], INVALID_COLOR ); - DeNanify( opacities2[i], INVALID_OPACITY ); - } - - for ( ; i < 256; i++ ) - colors2[i].set( 0,0,0 ), opacities2[i] = 0; - - // Write color/opacity maps - WriteVec3Array( colors2, 0, 256, colormap_name, 0, 0 ); - if ( do_opacities ) - WriteFloatArray( opacities2, 0, 256, opacitymap_name, 0, 0); - - // Write colors/opacities - WriteIndexArray( *ip, num_cindices, 0, 1, 1, colors_name, - "color map", dep ); - - if ( do_opacities ) - WriteIndexArray( *ip, num_cindices, 0, 1, 1, opacities_name, - "opacity map", dep ); - - delete [] colors2; - delete [] opacities2; - } - - // Else write direct colors/opacities... - else { - int len = ip && ip->valid() ? num_cindices : num_colors; - - // Separate colors and opacities - osg::Vec3 *colors2 = new osg::Vec3[ len ]; - float *opacities2 = new float [ len ]; - for ( i = 0; i < len; i++ ) { - int index = ip && ip->valid() ? (*ip)[i] : i; - OSGColorToDX( colors[ index ], colors2[i], opacities2[i] ); - DeNanify( colors2[i], INVALID_COLOR ); - DeNanify( opacities2[i], INVALID_OPACITY ); - } - - WriteVec3Array( colors2, 0, len, colors_name, 0, dep ); - if ( do_opacities ) - WriteFloatArray( opacities2, 0, len, opacities_name, 0, dep ); - - delete [] colors2; - delete [] opacities2; - } - - wrote_maps = do_maps; -} - -//---------------------------------------------------------------------------- - -void DXArrayWriter::WriteColors( - const Vec4UB colors[], int num_colors, - osg::GeoSet::IndexPointer *ip, int num_cindices, - const char colors_name[], const char colormap_name[], - const char opacities_name[], const char opacitymap_name[], - int do_opacities, const char *dep, int &wrote_maps ) -{ - int do_maps = WriteMapsYN( ip, num_colors ); - int i; - - // If should write color/opacity maps... - if ( do_maps ) { - - // Separate colors and opacities - Vec3UB *colors2 = new Vec3UB[256]; - float *opacities2 = new float [256]; - for ( i = 0; i < num_colors; i++ ) - OSGColorToDX( colors[i], colors2[i], opacities2[i] ); - - for ( ; i < 256; i++ ) { - colors2[i][0] = colors2[i][1] = colors2[i][2] = 0; - opacities2[i] = 0.0; - } - - // Write color/opacity maps - WriteUByte3Array( colors2, 0, 256, colormap_name, 0, 0 ); - if ( do_opacities ) - WriteFloatArray( opacities2, 0, 256, opacitymap_name, 0, 0); - - // Write colors/opacities - WriteIndexArray( *ip, num_cindices, 0, 1, 1, colors_name, - "color map", dep ); - - if ( do_opacities ) - WriteIndexArray( *ip, num_cindices, 0, 1, 1, opacities_name, - "opacity map", dep ); - - delete [] colors2; - delete [] opacities2; - } - - // Else write direct colors/opacities... - else { - int len = ip && ip->valid() ? num_cindices : num_colors; - - // Separate colors and opacities - Vec3UB *colors2 = new Vec3UB[ len ]; - float *opacities2 = new float [ len ]; - for ( i = 0; i < len; i++ ) { - int index = ip && ip->valid() ? (*ip)[i] : i; - OSGColorToDX( colors[ index ], colors2[i], opacities2[i] ); - } - - WriteUByte3Array( colors2, 0, len, colors_name, 0, dep ); - if ( do_opacities ) - WriteFloatArray( opacities2, 0, len, opacities_name, 0, dep ); - - delete [] colors2; - delete [] opacities2; - } - - wrote_maps = do_maps; -} - -//---------------------------------------------------------------------------- - -void DXArrayWriter::WritePerVertexNormals( - const osg::GeoSet &geoset, - const char name[] ) - // throws 1 -{ - // FIXME: - // NOTE: Strictly speaking this routine is not correct, but is - // probably good enough for now. - // - // THE ISSUE: - // In OSG, PER_VERTEX normals, colors, and texture coordinates are - // stored per vertex "instance", while in DX normals, colors, and - // tcoords dep positions are stored per vertex "definition" (DX has no - // vertex instances to which normals, colors, and tcoords can be - // separately attached). - // - // (So e.g. for normals:) in OSG/Performer when coordinates (positions) - // are indexed, C coords and CI coord indices are defined to draw the - // primitives. When normals are defined per-vertex, there are N - // normals (and optionally NI normal indices). - // - // Note that CI == N (or NI, when normals are indexed). C != N (or NI). - // So, while we have one normal instance per point "instance", we may - // potentially have multiple normal instances mapped to the - // same point "definition". - // - // THE CORRECT SOLUTION: - // The right way to approach this is to pre-scan the Geodes whose - // Coords are indexed and which have either normals, colors, or tcoords - // bound to vertices, and replicate points (positions) which have - // multiple "different" normals, colors, or texture coordinates mapped - // To them. - // - // WHAT IS IMPLEMENTED BELOW: - // Below we take a short cut and map normals for vertex instances to - // vertex definitions. If a collision occurs, we just report it - // so someone will know it's a problem. - // - - int num_points = geoset.getNumCoords(); - int num_pindices = geoset.getNumCoordIndices(); - int num_normals = geoset.getNumNormals(); - int num_nindices = geoset.getNumNormalIndices(); - //const osg::Vec3 *points = geoset.getCoords(); - const osg::Vec3 *normals = geoset.getNormals(); - const osg::GeoSet::IndexPointer &pindices = geoset.getCoordIndices(); - const osg::GeoSet::IndexPointer &nindices = geoset.getNormalIndices(); - - // Create a list of normals per vertex "definition" - osg::Vec3 *pt_normals = new osg::Vec3[ num_points ]; - int *set = new int[ num_points ]; - - try { - memset( set, '\0', num_points * sizeof(int) ); - - int num_pt_instances = num_pindices ? num_pindices : num_points; - int num_norm_instances = num_nindices ? num_nindices : num_normals; - if ( num_pt_instances != num_norm_instances ) { - msg_bin->Add( "ERROR: Incorrect number of normals found\n" ); - throw 1; - } - - for ( int i = 0; i < num_pt_instances; i++ ) - { - int pindex = pindices.valid() ? pindices[i] : i; - int nindex = nindices.valid() ? nindices[i] : i; - osg::Vec3 normal = normals[nindex]; - - DeNanify( normal, INVALID_NORMAL ); - - if ( set[pindex] && !( pt_normals[pindex] == normal ) ) { - msg_bin->Add("ERROR: Vertex normal aliasing!!! Ask somebody to expand\n" - " the implementation of DXArrayWriter::" - "WritePerVertexNormals().\n" ); - //printf( "%d: %g %g %g\n", - // nindex, normal[0], normal[1], normal[2] ); - //printf( " %g %g %g\n", - // pt_normals[pindex][0], - // pt_normals[pindex][1], - // pt_normals[pindex][2] ); - } - set[pindex] = 1; - pt_normals[pindex] = normal; - } - - // Now write the normals - WriteVec3Array( pt_normals, 0, num_points, name, 0, "positions" ); - } - catch (...) { - delete [] set; - delete [] pt_normals; - throw; - } - delete [] set; - delete [] pt_normals; -} - -//---------------------------------------------------------------------------- - -void DXArrayWriter::WritePerVertexColors( - const osg::GeoSet &geoset, - const char colors_name[], - const char colormap_name[], - const char opacities_name[], - const char opacitymap_name[], - int do_opacities, - int &wrote_maps ) - // throws 1 -{ - // FIXME: - // NOTE: Strictly speaking this routine is not correct, but is - // probably good enough for now. - // - // THE ISSUE: - // (See the opening comment in DXArrayWriter::WritePerVertexNormals. The - // same applies here, namely that there may be multiple colors - // mapping to the same point definiton.) - - unsigned int num_points = geoset.getNumCoords(); - unsigned int num_pindices = geoset.getNumCoordIndices(); - unsigned int num_colors = geoset.getNumColors(); - unsigned int num_cindices = geoset.getNumColorIndices(); - const osg::Vec4 *colors = geoset.getColors(); - const osg::GeoSet::IndexPointer &pindices = geoset.getCoordIndices(); - const osg::GeoSet::IndexPointer &cindices = geoset.getColorIndices(); - - // Create a list of color indices per vertex "definition" - GLuint *pt_cindices = new GLuint[ num_points ]; - int *set = new int[ num_points ]; - - try { - memset( set, '\0', num_points * sizeof(int) ); - - unsigned int num_pt_instances = num_pindices ? num_pindices : num_points; - unsigned int num_color_instances = num_cindices ? num_cindices : num_colors; - if ( num_pt_instances != num_color_instances ) { - msg_bin->Add( "ERROR: Incorrect number of colors found\n" ); - throw 1; - } - - for ( unsigned int i = 0; i < num_pt_instances; i++ ) - { - unsigned int pindex = pindices.valid() ? pindices[i] : i; - unsigned int cindex = cindices.valid() ? cindices[i] : i; - - if ( set[pindex] && ( pt_cindices[pindex] != cindex ) ) - msg_bin->Add( "ERROR: Vertex color aliasing!!! Ask somebody to expand\n" - " the implementation of DXArrayWriter::" - "WritePerVertexColors()." ); - - set[pindex] = 1; - pt_cindices[pindex] = cindex; - } - - // Cook an IndexPointer to write colors/opacities via std methods - osg::GeoSet::IndexPointer ip; - ip.set( num_points, pt_cindices ); - - // Write colors (and opacities, and possibly associated maps) - WriteColors( colors, num_colors, &ip, num_points, - colors_name, colormap_name, opacities_name, opacitymap_name, - do_opacities, "positions", wrote_maps ); - - } - catch (...) { - delete [] set; - delete [] pt_cindices; - throw; - } - delete [] set; - delete [] pt_cindices; -} - -//---------------------------------------------------------------------------- - -void DXArrayWriter::WritePerVertexTCoords( - const osg::GeoSet &geoset, const char name[] ) - // throws 1 -{ - // FIXME: - // NOTE: Strictly speaking this routine is not correct, but is - // probably good enough for now. - // - // THE ISSUE: - // (See the opening comment in DXArrayWriter::WritePerVertexNormals. The - // same applies here, namely that there may be multiple tcoords - // mapping to the same point definiton.) - - int num_points = geoset.getNumCoords(); - int num_pindices = geoset.getNumCoordIndices(); - int num_tcoords = geoset.getNumTextureCoords(); - int num_tindices = geoset.getNumTextureIndices(); - //const osg::Vec3 *points = geoset.getCoords(); - const osg::Vec2 *tcoords = geoset.getTextureCoords(); - const osg::GeoSet::IndexPointer &pindices = geoset.getCoordIndices(); - const osg::GeoSet::IndexPointer &tindices = geoset.getTextureIndices(); - - // Create a list of tcoords per vertex "definition" - osg::Vec2 *pt_tcoords = new osg::Vec2[ num_points ]; - int *set = new int[ num_points ]; - - try { - memset( set, '\0', num_points * sizeof(int) ); - - int num_pt_instances = num_pindices ? num_pindices : num_points; - int num_tcoord_instances = num_tindices ? num_tindices : num_tcoords; - if ( num_pt_instances != num_tcoord_instances ) { - msg_bin->Add( "ERROR: Incorrect number of texture coordinates found\n" ); - throw 1; - } - - for ( int i = 0; i < num_pt_instances; i++ ) - { - int pindex = pindices.valid() ? pindices[i] : i; - int tindex = tindices.valid() ? tindices[i] : i; - - if ( set[pindex] && !( pt_tcoords[pindex] == tcoords[tindex] ) ) - msg_bin->Add( "ERROR: Vertex texture coordinate aliasing!!!\n" - " Ask somebody to expand the implementation of\n" - " DXArrayWriter::WritePerVertexTcoords().\n" ); - - set[pindex] = 1; - pt_tcoords[pindex] = tcoords[tindex]; - } - - // Now write the tcoords - WriteVec2Array( pt_tcoords, 0, num_points, name, 0, "positions" ); - - } - catch (...) { - delete [] set; - delete [] pt_tcoords; - throw; - } - delete [] set; - delete [] pt_tcoords; -} - -//---------------------------------------------------------------------------- - -inline float Luminance( const osg::Vec4 &v ) - { return 0.2122*v[0] + 0.7013*v[1] * 0.0865*v[2]; } - -inline char *Vec4AttributeString( char buf[], - char name[], - int front_and_back, - osg::Vec4 &front, - osg::Vec4 &back ) -{ - if ( front_and_back ) - sprintf( buf, "attribute \"osg %s\" string \"%g %g %g %g\"\n", - name, front[0], front[1], front[2], front[3] ); - else - sprintf( buf, "attribute \"osg front %s\" string \"%g %g %g %g\"\n" - "attribute \"osg back %s\" string \"%g %g %g %g\"\n", - name, front[0], front[1], front[2], front[3], - name, back[0], back[1], back[2], back[3] ); - return buf; -} - - -std::string DXWriter::BuildStateSetAttributes( MyStateSet &sset, - int diffuse_is_color, - int diffuse_is_opacity ) -{ - std::string str; - char buf[160]; - - // Material - if ( sset.HasAttribute( osg::StateAttribute::MATERIAL ) ) { - - // DX Lighting Model: - // I = KaAC+KdLC(n*l)+KsL(n*h)^shiny - // OpenGL: - // I = Ke+KaA+sum(stuff*KdA(n*l)+KsLs(n*h)^shiny - // NOTES: - // 1. DX specular doesn't depend on object color - // 2. DX doesn't have separate RGB color fields for specular, diffuse, - // ambient, emission - // 3. DX's material attributes are all scalars - // 4. DX lights don't separate specular and diffuse - // etc. - // Notice that the lighting models differ enough that it doesn't make - // much sense to set the DX material attributes (they're all scalars). - // So we'll just attach what the original attributes were to - // non-reserved attribute names and let the user fiddle with Shade() - // to set "shininess", "specular", "diffuse", "ambient" attributes to - // get the look they want. - - if ( diffuse_is_color ) { - sprintf( buf, "attribute \"diffuse is colors component\" number 1\n" ); - str += buf; - } - - if ( diffuse_is_opacity ) { - sprintf( buf, "attribute \"diffuse is opacities component\" number 1\n" ); - str += buf; - } - - if ( sset.shininess_f_and_b ) - sprintf( buf, "attribute \"osg shininess\" number %g\n", - sset.shininess_f ); - else - sprintf( buf, "attribute \"osg front shininess\" number %g\n" - "attribute \"osg back shininess\" number %g\n", - sset.shininess_f, sset.shininess_b ); - str += buf; - - str += Vec4AttributeString( buf, "emission", sset.emission_f_and_b, - sset.emission_f, sset.emission_b ); - str += Vec4AttributeString( buf, "specular", sset.specular_f_and_b, - sset.specular_f, sset.specular_b ); - str += Vec4AttributeString( buf, "diffuse", sset.diffuse_f_and_b, - sset.diffuse_f, sset.diffuse_b ); - str += Vec4AttributeString( buf, "ambient", sset.ambient_f_and_b, - sset.ambient_f, sset.ambient_b ); - - // NOTE: Didn't write "colormode" - } - - // Texture - if ( sset.HasAttribute( osg::StateAttribute::TEXTURE ) ) { - sprintf( buf, "attribute \"texture wrap s\" string \"%s\"\n", - sset.wrap_s == GL_CLAMP ? "clamp" : "repeat" ); - str += buf; - sprintf( buf, "attribute \"texture wrap t\" string \"%s\"\n", - sset.wrap_t == GL_CLAMP ? "clamp" : "repeat" ); - str += buf; - - static struct - { GLenum val; char *str; } - filter_to_str[] = { - { GL_NEAREST , "nearest" }, - { GL_LINEAR , "linear" }, - { GL_NEAREST_MIPMAP_NEAREST, "nearest_mipmap_nearest" }, - { GL_NEAREST_MIPMAP_LINEAR , "nearest_mipmap_linear" }, - { GL_LINEAR_MIPMAP_NEAREST , "linear_mipmap_nearest" }, - { GL_LINEAR_MIPMAP_LINEAR , "linear_mipmap_linear" } }; - unsigned i; - for ( i = 0; i < ARRAY_LEN(filter_to_str); i++ ) - if ( filter_to_str[i].val == (GLenum) sset.min_filter ) - break; - if ( i >= ARRAY_LEN(filter_to_str) ) - msg_bin.Add( "WARNING: Bad texture min filter: %d\n", sset.min_filter ); - else { - sprintf( buf, "attribute \"texture min filter\" string \"%s\"\n", - filter_to_str[i].str ); - str += buf; - } - - for ( i = 0; i < ARRAY_LEN(filter_to_str); i++ ) - if ( filter_to_str[i].val == (GLenum) sset.mag_filter ) - break; - if ( i >= ARRAY_LEN(filter_to_str) ) - msg_bin.Add( "WARNING: Bad texture mag filter: %d\n", sset.mag_filter ); - else { - sprintf( buf, "attribute \"texture mag filter\" string \"%s\"\n", - filter_to_str[i].str ); - str += buf; - } - } - - // TexEnv - if ( sset.HasAttribute( osg::StateAttribute::TEXENV ) ) { - char *func = 0; - switch ( sset.texture_func ) { - case osg::TexEnv::DECAL : func = "decal" ; break; - case osg::TexEnv::MODULATE : func = "modulate"; break; - case osg::TexEnv::BLEND : func = "blend" ; break; - case osg::TexEnv::REPLACE : func = "replace" ; break; - default: - msg_bin.Add( "WARNING: Bad texture function: %d\n", sset.texture_func ); - } - if ( func ) { - sprintf( buf, "attribute \"texture function\" string \"%s\"\n", func ); - str += buf; - } - } - - // CullFace - if ( sset.HasAttribute( osg::StateAttribute::CULLFACE ) ) { - sprintf( buf, "attribute \"cull face\" string \"%s\"\n", - sset.cullface_mode == osg::CullFace::FRONT ? "front" : - sset.cullface_mode == osg::CullFace::BACK ? "back" : - "front and back" ); - str += buf; - } - else { - sprintf( buf, "attribute \"cull face\" string \"off\"\n" ); - str += buf; - } - - return str; -} - -//---------------------------------------------------------------------------- - -std::string DXWriter::WriteImage( const osg::Image &image ) - // Ok, so this writes a field and not just an array. Clean this up later... - // throws 1 -{ - // If this image has already been written, don't write it again - if ( texture_mgr.IsRegistered( &image ) ) - return texture_mgr.Lookup( &image ); - - // Get the path to the image file, and build a uniquely named DX field - const std::string &path = image.getFileName(); - const char *base = strrchr( path.c_str(), '/' ); - if ( base ) - base++; - else - base = path.c_str(); - std::string basename( base ); - DXField field( name_mgr, &basename ); - std::string name = field.GetName(); - - // Write positions - std::string pos_name = name_mgr.GetUnique( name + " image positions" ); - fprintf( fp, "object \"%s\" class gridpositions counts %d %d\n" - " origin 0 0\n" - " delta 0 1\n" - " delta 1 0\n" - "attribute \"dep\" string \"positions\"\n" - "#\n", - pos_name.c_str(), image.t(), image.s() ); - field.AddComponent( "positions", pos_name.c_str() ); - - // Write connections - std::string conn_name = name_mgr.GetUnique( name + " image connections" ); - fprintf( fp, "object \"%s\" class gridconnections counts %d %d\n" - "attribute \"element type\" string \"quads\"\n" - "attribute \"dep\" string \"connections\"\n" - "attribute \"ref\" string \"positions\"\n" - "#\n", - conn_name.c_str(), image.t(), image.s() ); - field.AddComponent( "connections", conn_name.c_str() ); - - // Generate colors - unsigned int pixel_fmt = image.getPixelFormat(); // A user-friendly int_fmt - unsigned int data_type = image.getDataType(); // Sample data type - const unsigned char *data = image.data(); - int r_dim = image.r(); - - // FIXME: Support other image formats - if ( r_dim != 1 ) { - msg_bin.Add( "ERROR: Currently only 2D textures are supported.\n" ); - throw 1; - } - if ( data_type != GL_UNSIGNED_BYTE ) { - msg_bin.Add( "ERROR: Currently only ubyte textures are supported.\n" ); - throw 1; - } - - switch ( pixel_fmt ) { - case GL_RGB : - case GL_RGBA : - case GL_LUMINANCE : - case GL_LUMINANCE_ALPHA : - break; - default : - msg_bin.Add( "ERROR: Currently only RGB, RGBA, LUMINANCE, and \n" - " LUMINANCE_ALPHA textures are supported. Found %d.\n", - pixel_fmt ); - throw 1; - } - - unsigned num_pixels = image.s() * image.t(); - unsigned char opaque = (unsigned char) (ALPHA_OPAQUE * 255.0 ); - Vec4UB *colors = new Vec4UB[ num_pixels ]; - unsigned i; - - if ( pixel_fmt == GL_RGB || pixel_fmt == GL_RGBA ) - for ( i = 0; i < num_pixels; i++, data += (pixel_fmt==GL_RGB?3:4)) - colors[i][0] = data[0], - colors[i][1] = data[1], - colors[i][2] = data[2], - colors[i][3] = ( pixel_fmt == GL_RGB ? opaque : data[3] ); - else - for ( i = 0; i < num_pixels; - i++, data += (pixel_fmt==GL_LUMINANCE?1:2) ) - colors[i][0] = colors[i][1] = colors[i][2] = data[0], - colors[i][3] = ( pixel_fmt == GL_LUMINANCE ? opaque : data[1] ); - - // Write colors - int found_transparent = 0; - for ( i = 0; i < num_pixels && !found_transparent; i++ ) - found_transparent = (colors[i][3] != opaque); - - int do_opacities = ((pixel_fmt == GL_RGBA || - pixel_fmt == GL_LUMINANCE_ALPHA ) && - found_transparent); - - // NOTE: DX used to only support UNSIGNED_BYTE GL_RGB textures. Added - // Jan 2002: Added support to DX for RGBA textures w/ depth sorting. - // So we always write RGBA textures as image texture maps with opacities. - - std::string colors_name = name_mgr.GetUnique( name + " image colors"); - std::string colormap_name = name_mgr.GetUnique( name + " color map" ); - std::string opacities_name = name_mgr.GetUnique( name + " opacities" ); - std::string opacitymap_name = name_mgr.GetUnique( name + " opacity map" ); - int wrote_maps; - w.WriteColors( colors, num_pixels, 0, 0, - colors_name.c_str(), colormap_name.c_str(), - opacities_name.c_str(), opacitymap_name.c_str(), - do_opacities, "positions", wrote_maps ); - delete [] colors; - - field.AddComponent( "colors", colors_name.c_str() ); - if ( do_opacities ) - field.AddComponent( "opacities", opacities_name.c_str() ); - if ( wrote_maps ) - { - field.AddComponent( "color map", colormap_name.c_str() ); - if ( do_opacities ) - field.AddComponent( "opacity map", opacitymap_name.c_str() ); - } - - // Finally, write the image field - field.Write( fp, 0 ); - - // And keep track of this image to attach to future referring fields - texture_mgr.Register( &image, name ); - return name; -} - -//---------------------------------------------------------------------------- - -void DXWriter::WritePolylineConnections( osg::GeoSet &geoset, - DXField &field ) - // Writes the "edges" and "polylines" field components for LINE_STRIPs, - // FLAT_LINE_STRIPs, and LINE_LOOPs. -{ - assert( geoset.getPrimType() == osg::GeoSet::LINE_STRIP || - geoset.getPrimType() == osg::GeoSet::FLAT_LINE_STRIP || - geoset.getPrimType() == osg::GeoSet::LINE_LOOP ); - - int num_prims = geoset.getNumPrims(); - const int *prim_lengths = geoset.getPrimLengths(); - int line_loops = geoset.getPrimType() == osg::GeoSet::LINE_LOOP; - int i,j; - const osg::GeoSet::IndexPointer &pindices = geoset.getCoordIndices(); - - // ---- Write "edges" components ---- - std::string edges_name = name_mgr.GetUnique( field.GetName() + " edges" ); - - // Count number of points in all polylines, and set up an index pointer - int count = 0; - for ( i = 0; i < num_prims; i++ ) - count += ( line_loops ? prim_lengths[i]+1 : prim_lengths[i] ); - GLuint *indices = new GLuint[ count ]; - osg::GeoSet::IndexPointer ip; - ip.set( count, indices ); - - // If no coordinate indices, then position indices are implicit; else explicit - int idx = 0; - for ( i = 0; i < num_prims; i++ ) { - int start_idx = idx; - for ( j = 0; j < prim_lengths[i]; j++, idx++ ) - indices[ idx ] = pindices.valid() ? pindices[ idx ] : idx; - if ( line_loops ) { - indices[ idx ] = pindices.valid() ? pindices[start_idx] : start_idx; - idx++; - } - } - - // Write component - w.WriteIndexArray( ip, count, 0, 1, 0, edges_name.c_str(), "positions", 0 ); - field.AddComponent( "edges", edges_name.c_str() ); - - // ---- Write "polylines" components ---- - std::string polylines_name = name_mgr.GetUnique( field.GetName() + - " polylines" ); - - idx = 0; - for ( i = 0; i < num_prims; i++ ) { - indices[i] = idx; - idx += ( line_loops ? prim_lengths[i]+1 : prim_lengths[i] ); - } - w.WriteIndexArray( ip, num_prims, 0, 1, 0, polylines_name.c_str(), - "edges", 0 ); - field.AddComponent( "polylines", polylines_name.c_str() ); - - delete indices; -} - -//---------------------------------------------------------------------------- - -std::string DXWriter::WriteGeoSetField( const std::string &field_name, - osg::GeoSet &geoset, - MyStateSet &sset ) - // throw 1 - - // Writes POINTS, LINES, TRIANGLES, LINE_STRIPs, FLAT_LINE_STRIPs, and - // LINE_LOOPs. - // - // QUADS NOTE: This routine almost supports QUADS. However, OSG/OpenGL - // quad vertices are ordered as a walk around the boundary of the polygon - // whereas DX swaps the last two vertices. So to support quads, - // we'd need to swap the 3rd and 4th coords (or coord indices) in - // each primitive, and for any normals/colors/tcoords, we'd also need - // to swap the 3rd and 4th data value (or data index) in each primitive. - // FIXME: For now, we'll just triangulate QUADS into TRIANGLES, and - // write those (see DXWriter::WriteGeoSet). Later consider swapping and - // writing quads connections if it doesn't obfuscate this routine too - // badly. -{ - // No QUADS -- see above comment - assert( geoset.getPrimType() != osg::GeoSet::QUADS ); - - geoset.computeNumVerts(); // Update # coords/# normals from index arrays - - int num_prims = geoset.getNumPrims(); - int num_points = geoset.getNumCoords(); - int num_pindices = geoset.getNumCoordIndices(); - int num_colors = geoset.getNumColors(); - int num_cindices = geoset.getNumColorIndices(); - int num_normals = geoset.getNumNormals(); - //int num_nindices = geoset.getNumNormalIndices(); - int num_tcoords = geoset.getNumTextureCoords(); - osg::GeoSet::BindingType cbinding = geoset.getColorBinding(); - osg::GeoSet::BindingType nbinding = geoset.getNormalBinding(); - osg::GeoSet::BindingType tbinding = geoset.getTextureBinding(); - int i, prim_length, polylines = 0; - char *connection_type = 0; - - // Give the file pointer to the DX array writer - w.SetFP( fp ); - w.SetMsgBin( &msg_bin ); - msg_bin.Clear(); - - // If texturing is on, write the texture as a DX image field, and give - // us back the name of field - int has_uv = num_tcoords > 0 && tbinding == osg::GeoSet::BIND_PERVERTEX; - int has_texture = sset.HasAttribute( osg::StateAttribute::TEXTURE ); - int has_texgen = sset.HasAttribute( osg::StateAttribute::TEXGEN ); - - std::string texture_name; - if ( has_texture && has_uv ) - try { - texture_name = WriteImage( *sset.image ); - } catch (...) { throw; } - else if ( has_texture && !has_uv && has_texgen ) { - static int been_here = 0; - if ( !been_here ) { - msg_bin.Add( "WARNING: " - "Texture/uv not written; TEXGEN not supported yet\n" ); - been_here = 1; - } - } - - // Create a new DX field with a unique name - DXField field( name_mgr, &field_name ); - std::string name = field.GetName(); - - // Determine "element type" and primitive length of connections component - switch ( geoset.getPrimType() ) { - case osg::GeoSet::POINTS : - prim_length = 1, connection_type = 0 ; break; - case osg::GeoSet::LINES : - prim_length = 2, connection_type = "lines" ; break; - case osg::GeoSet::TRIANGLES : - prim_length = 3, connection_type = "triangles"; break; - case osg::GeoSet::QUADS : - prim_length = 4, connection_type = "quads" ; break; - case osg::GeoSet::LINE_STRIP : - case osg::GeoSet::FLAT_LINE_STRIP : - case osg::GeoSet::LINE_LOOP : - prim_length = 0, connection_type = "polylines"; - polylines = 1; - break; - - default: - msg_bin.Add( "ERROR: GeoSet passed to WriteGeoSetField is wrong type\n" ); - throw 1; - } - - // Ensure we "don't" have interleaved GeoSet data - // FIXME: Add support for this - if (( num_points == 0 ) && geoset.getInterleavedArray() != 0 ) { - msg_bin.Add( "ERROR: Interleaved Array GeoSets not yet supported\n" ); - throw 1; - } - - // Write "positions" component - std::string pos_name = name_mgr.GetUnique( name + " points" ); - w.WriteVec3Array( geoset.getCoords(), 0, num_points, pos_name.c_str(), - 0, "positions" ); - field.AddComponent( "positions", pos_name.c_str() ); - - // Write "connections" component (lines, triangles, or quads); pts have none - char *conn_dep_name = 0; - - if ( prim_length == 1 ) - // For points, there are no connections, so don't make colors or normals - // dep on them in the OVERALL or PERPRIM cases - conn_dep_name = "positions"; - else if ( polylines ) { - WritePolylineConnections( geoset, field ); - conn_dep_name = "polylines"; - } - else { - std::string conn_name = name_mgr.GetUnique( name + " connections" ); - int len = num_pindices ? num_pindices : num_points; - char attr[80]; - sprintf( attr, "attribute \"element type\" string \"%s\"", connection_type); - - w.WriteIndexArray( geoset.getCoordIndices(), len, 1, prim_length, 0, - conn_name.c_str(), "positions", "connections", attr ); - field.AddComponent( "connections", conn_name.c_str() ); - conn_dep_name = "connections"; - } - - // Write "normals" component - if ( num_normals > 0 ) { - std::string normals_name = name_mgr.GetUnique( name + " normals" ); - - // DX doesn't support a "normal map", so expand to Vec3 if normals indexed - // Also see notes in WritePerVertexNormals. - int index; - osg::GeoSet::IndexPointer *ip; - switch( nbinding ) { - - case osg::GeoSet::BIND_OVERALL : - ip = &geoset.getNormalIndices(); - index = ip->valid() ? (*ip)[0] : 0; - w.WriteVec3ConstArray( geoset.getNormals()[index], num_prims, - normals_name.c_str(), 0, conn_dep_name ); - break; - - case osg::GeoSet::BIND_PERPRIM : - w.WriteVec3Array( geoset.getNormals(), &geoset.getNormalIndices(), - num_prims, normals_name.c_str(), - 0, conn_dep_name ); - break; - - case osg::GeoSet::BIND_PERVERTEX : - try { - w.WritePerVertexNormals( geoset, normals_name.c_str() ); - } catch (...) { throw; } - break; - - case osg::GeoSet::BIND_OFF: - case osg::GeoSet::BIND_DEFAULT: - // Nonsensical cases - break; - } - field.AddComponent( "normals", normals_name.c_str() ); - } - - // Write "colors" (and possibly "opacities") - // If indexed colors and numcolors <= 256, create "color map"/"opacity map" - std::string colors_name = name_mgr.GetUnique( name + " colors" ); - std::string colormap_name = name_mgr.GetUnique( name + " color map" ); - std::string opacities_name = name_mgr.GetUnique( name + " opacities" ); - std::string opacitymap_name = name_mgr.GetUnique( name + " opacity map" ); - int has_maps = 0; - int diffuse_is_color = 0, diffuse_is_opacity = 0; - - // 4 cases: Choose/write colors/opacities in order of preference from: - // colors, diffuse material, default color. - // If none specified, write no colors/opacities components. - - if ( num_colors > 0 ) { - - osg::Vec4 *colors = geoset.getColors(); - osg::GeoSet::IndexPointer &ip = geoset.getColorIndices(); - int index, do_opacities, wrote_maps; - - // See if any non-opaque colors used - for ( i = 0; i < num_colors; i++ ) - if ( colors[i][3] != ALPHA_OPAQUE ) - break; - do_opacities = ( i < num_colors ); - - osg::Vec3 color; - float opacity; - - switch( cbinding ) { - - case osg::GeoSet::BIND_OVERALL : - index = ip.valid() ? ip[0] : 0; - w.OSGColorToDX( colors[index], color, opacity ); - w.WriteVec3ConstArray( color, num_prims, colors_name.c_str(), - 0, conn_dep_name ); - if ( do_opacities ) - w.WriteFloatConstArray( opacity, num_prims, opacities_name.c_str(), - 0, conn_dep_name ); - wrote_maps = 0; - break; - - case osg::GeoSet::BIND_PERPRIM : - w.WriteColors( colors, num_colors, - &geoset.getColorIndices(), num_cindices, - colors_name.c_str(), colormap_name.c_str(), - opacities_name.c_str(), opacitymap_name.c_str(), - do_opacities, conn_dep_name, wrote_maps ); - break; - - case osg::GeoSet::BIND_PERVERTEX : - try { - w.WritePerVertexColors( geoset, - colors_name.c_str() , colormap_name.c_str(), - opacities_name.c_str(), opacitymap_name.c_str(), - do_opacities, wrote_maps ); - } catch (...) { throw; } - break; - case osg::GeoSet::BIND_OFF: - case osg::GeoSet::BIND_DEFAULT: - // Nonsensical cases - break; - } - - // Register added components - field.AddComponent( "colors", colors_name.c_str() ); - if ( do_opacities ) - field.AddComponent( "opacities", opacities_name.c_str() ); - if ( wrote_maps ) - { - field.AddComponent( "color map", colormap_name.c_str() ); - if ( do_opacities ) - field.AddComponent( "opacity map", opacitymap_name.c_str() ); - } - } - - // Else no explicit colors specific. Fall back on diffuse Material - else if ( sset.HasAttribute( osg::StateAttribute::MATERIAL ) ) { - osg::Vec3 color; - float opacity; - w.OSGColorToDX( sset.diffuse_f, color, opacity ); - int do_opacities = opacity != ALPHA_OPAQUE; - - // Same as the BIND_OVERALL case above, except can have front/back colors - if ( do_opacities ) { - w.WriteFloatConstArray( opacity, num_prims, opacities_name.c_str(), - 0, conn_dep_name ); - field.AddComponent( "opacities", opacities_name.c_str() ); - } - - std::string front_colors_name = name_mgr.GetUnique( name +" front colors" ); - std::string back_colors_name = name_mgr.GetUnique( name +" back colors" ); - - if ( sset.diffuse_f_and_b ) { - w.WriteVec3ConstArray( color, num_prims, colors_name.c_str(), - 0, conn_dep_name ); - field.AddComponent( "colors", colors_name.c_str() ); - } - else { - w.WriteVec3ConstArray( color, num_prims, front_colors_name.c_str(), - 0, conn_dep_name ); - field.AddComponent( "colors", front_colors_name.c_str() ); - w.OSGColorToDX( sset.diffuse_b, color, opacity ); - w.WriteVec3ConstArray( color, num_prims, back_colors_name.c_str(), - 0, conn_dep_name ); - field.AddComponent( "colors", back_colors_name.c_str() ); - } - diffuse_is_color = 1; - diffuse_is_opacity = do_opacities; - } - - // No explicit colors or diffuse Material color. Give user provided default. - else if ( parms.set_default_color ) { - osg::Vec3 color; - float opacity; - w.OSGColorToDX( parms.default_color, color, opacity ); - int do_opacities = opacity != ALPHA_OPAQUE; - - // Same as the BIND_OVERALL case above, except can have front/back colors - w.WriteVec3ConstArray( color, num_prims, colors_name.c_str(), - 0, conn_dep_name ); - field.AddComponent( "colors", colors_name.c_str() ); - - if ( do_opacities ) { - w.WriteFloatConstArray( opacity, num_prims, opacities_name.c_str(), - 0, conn_dep_name ); - field.AddComponent( "opacities", opacities_name.c_str() ); - } - - diffuse_is_color = 1; - diffuse_is_opacity = do_opacities; - } - - // Write "uv" texture coordinates - std::string uv_name = name_mgr.GetUnique( name + " uv" ); - if ( num_tcoords > 0 && tbinding == osg::GeoSet::BIND_PERVERTEX ) { - try { - w.WritePerVertexTCoords( geoset, uv_name.c_str() ); - } catch (...) { throw; } - field.AddComponent( "uv", uv_name.c_str() ); - } - - // Generate field attributes - std::string attr( has_maps ? "attribute \"direct color map\" number 1\n" :""); - attr += BuildStateSetAttributes( sset, diffuse_is_color, diffuse_is_opacity ); - // If texturing is on, tack on a "texture" attribute with it's field name - if ( has_uv && has_texture ) { - char buf[160]; - //int size_ok = sset.image->s() >= 64 && sset.image->t() >= 64; - //char *attr_name = size_ok ? "texture" : "texture - too small"; - char *attr_name = "texture"; - - // FIXME: DX textures must be powers of two and >= 64 on a side. - // Now that we generate MIPmaps that's no longer true, and just remove - // the 64x64 min size check from DX. - // NOTE: FIXED in DX now that we mipmap everything - - //if ( !size_ok ) { - // // FIXME: When we generalize this, remove the static hack - // static int been_here = 0; - // if ( !been_here ) { - // msg_bin.Add( - // "WARNING: DX min texture size is 64x64. Renaming texture\n" - // " attribute to \"texture - too small\" for these" - // " small textures.\n" ); - // been_here = 1; - // } - //} - - sprintf( buf, "attribute \"%s\" value \"%s\"\n", - attr_name, texture_name.c_str() ); - attr += buf; - } - - if ( attr[ attr.length()-1 ] == '\n' ) - attr.assign( attr, 0, attr.length()-1 ); - - // Finally, write the field - field.Write( fp, attr.c_str() ); - return name; - - // FIXME: Need to handle "texture" image attribute, GeoState colors - // storing GeoState attributes on field object, etc. -} - -//---------------------------------------------------------------------------- - -void MyStateSet::Show( osg::StateSet &sset ) -{ - osg::StateSet::ModeList &mode_list = sset.getModeList(); - osg::StateSet::AttributeList &attr_list = sset.getAttributeList(); - //int rend_hint = sset.getRenderingHint(); - //bool use_rend_bin_details = sset.useRenderBinDetails(); - //int bin_num = sset.getBinNumber(); - //const std::string &bin_name = sset.getBinName(); - //osg::StateSet::RenderBinMode rendbin_mode = sset.getRenderBinMode(); - - // Iterate over all mode mappings (GLMode->GLModeValue) - for( osg::StateSet::ModeList::const_iterator mitr = mode_list.begin(); - mitr != mode_list.end(); - ++mitr ) - msg_bin.Add( " GLMode %d = GLValue %d\n", mitr->first, mitr->second ); - - // Iterate over all attribute mappings - // (Type -> pair< ref_ptr, OverrideValue >) - for( osg::StateSet::AttributeList::const_iterator aitr = attr_list.begin(); - aitr != attr_list.end(); - ++aitr ) - msg_bin.Add( " Attr Type %d (Attr Name \"%s\"), OverrideValue = %d\n", - aitr->first, aitr->second.first.get()->className(), - aitr->second.second ); - - // mgs_bin.Add( " Rendering Hint = %d\n", rend_hint ); - // mgs_bin.Add( " Use Rend Bin Details = %d\n", use_rend_bin_details ); - // mgs_bin.Add( " Bin Number = %d\n", bin_num ); - // mgs_bin.Add( " Bin Name = %s\n", bin_name.c_str() ); - // mgs_bin.Add( " Bin Mode = %d\n", rendbin_mode ); -} - -//---------------------------------------------------------------------------- - -void MyStateSet::Query( const osg::StateSet &sset ) -{ - const osg::StateAttribute *attr; - - //MyStateSet::Show( *drawable_state ); - - // FIXME: Ignore override flags for now - - // MATERIAL - attr = sset.getAttribute( osg::StateAttribute::MATERIAL ); - if ( attr ) { - AddAttribute( osg::StateAttribute::MATERIAL ); - - const osg::Material &mat = (const osg::Material &) (*attr); - colormode = mat.getColorMode(); // GL_COLOR_MATERIAL - - ambient_f = mat.getAmbient ( osg::Material::FRONT ); - ambient_b = mat.getAmbient ( osg::Material::BACK ); - diffuse_f = mat.getDiffuse ( osg::Material::FRONT ); - diffuse_b = mat.getDiffuse ( osg::Material::BACK ); - specular_f = mat.getSpecular ( osg::Material::FRONT ); - specular_b = mat.getSpecular ( osg::Material::BACK ); - emission_f = mat.getEmission ( osg::Material::FRONT ); - emission_b = mat.getEmission ( osg::Material::BACK ); - shininess_f = mat.getShininess( osg::Material::FRONT ); - shininess_b = mat.getShininess( osg::Material::BACK ); - - ambient_f_and_b = mat.getAmbientFrontAndBack (); - diffuse_f_and_b = mat.getDiffuseFrontAndBack (); - specular_f_and_b = mat.getSpecularFrontAndBack (); - emission_f_and_b = mat.getEmissionFrontAndBack (); - shininess_f_and_b = mat.getShininessFrontAndBack(); - } - - // TEXTURE / TEXTURE_0 - // ( and only for 2D textures right now... RO August 2002) - attr = dynamic_cast(sset.getTextureAttribute(0, osg::StateAttribute::TEXTURE )); - if ( attr && - ( sset.getTextureMode(0, GL_TEXTURE_2D ) & osg::StateAttribute::ON )) { - - const osg::Texture2D &texture = (const osg::Texture2D &) (*attr); - - // NOTE: If OSG failed to load the texture, we'll get a NULL right here - image = texture.getImage(); - if ( image ) - AddAttribute( osg::StateAttribute::TEXTURE ); - - // NOTE: DX limitations - // Traditional DX doesn't support any texture control besides specifying - // the texture ("texture" attribute) and the texture coordinates ("uv" - // component). DX was hard-coded to use these 2D texture settings: - // GL_TEXTURE_WRAP_S = GL_CLAMP - // GL_TEXTURE_WRAP_T = GL_CLAMP - // GL_TEXTURE_MIN_FILTER = GL_NEAREST - // GL_TEXTURE_MAG_FILTER = GL_NEAREST - // GL_TEXTURE_ENV_MODE = GL_MODULATE - // DX also registers a level 0 texture - // A DX patch I recently committed (1/02) creates mipmapped textures and - // adds the following DX textured field attributes: - // attribute "texture wrap s" string ["clamp"|"repeat"] - // attribute "texture wrap t" string ["clamp"|"repeat"] - // attribute "texture min filter" string ["nearest"|"linear"| - // "nearest_mipmap_nearest"|"nearest_mipmap_linear"| - // "linear_mipmap_nearest"|"linear_mipmap_linear"] - // attribute "texture mag filter" string ["nearest"|"linear"] - // attribute "texture function" string ["decal"|"replace"|"modulate" - // "blend"] - - wrap_s = texture.getWrap( osg::Texture2D::WRAP_S ); - wrap_t = texture.getWrap( osg::Texture2D::WRAP_T ); - min_filter = texture.getFilter( osg::Texture2D::MIN_FILTER ); - mag_filter = texture.getFilter( osg::Texture2D::MAG_FILTER ); - - if ( texture.getInternalFormatMode() != - osg::Texture2D::USE_IMAGE_DATA_FORMAT ) { - // FIXME: When we generalize this, remove the static hack - static int been_here = 0; - if ( !been_here ) { - msg_bin.Add( "WARNING: Only texture image data format supported.\n"); - been_here = 1; - } - } - - } - - // TEXENV - attr = sset.getTextureAttribute(0, osg::StateAttribute::TEXENV ); - if ( attr && - ( sset.getTextureMode(0, GL_TEXTURE_2D ) & osg::StateAttribute::ON )) { - AddAttribute( osg::StateAttribute::TEXENV ); - - const osg::TexEnv &texenv = (const osg::TexEnv &) (*attr); - - texture_func = texenv.getMode(); - } - - // TEXGEN - attr = sset.getTextureAttribute(0, osg::StateAttribute::TEXGEN ); - if ( attr && - ( sset.getTextureMode(0, GL_TEXTURE_2D ) & osg::StateAttribute::ON )) { - - // FIXME: Just note that it is there for now. We don't actually support - // texture coordinate generation yet (i.e. generating the "uv" component - // for DX without explicit texture coordinates in the model) - AddAttribute( osg::StateAttribute::TEXGEN ); - } - - // CULLFACE - attr = sset.getAttribute( osg::StateAttribute::CULLFACE ); - if ( attr && - ( sset.getMode( GL_CULL_FACE ) & osg::StateAttribute::ON )) { - - AddAttribute( osg::StateAttribute::CULLFACE ); - const osg::CullFace &cullface = (const osg::CullFace &) (*attr); - cullface_mode = cullface.getMode(); - } - - // FIXME: Also consider supporting: - //exenv - // ALPHAFUNC, ANTIALIAS, COLORTABLE, FOG, FRONTFACE, - // LIGHTING, POINT, POLYGONMODE, POLYGONOFFSET, TEXGEN, TEXMAT, - // TEXTURE_1, TEXTURE_2, TEXTURE_3, TRANSPARENCY, - // STENCIL, COLORMASK, CLIPPLANE, CLIPPLANE_0, CLIPPLANE_1, - // CLIPPLANE_2, CLIPPLANE_3, CLIPPLANE_4, CLIPPLANE_5, DEPTH -} - -//---------------------------------------------------------------------------- - -void DXWriter::Open() -{ - if ( strcmp( parms.outfile, "-" ) == 0 ) - fp = stdout; - else - fp = fopen( parms.outfile, "wt" ); - - w.SetFP( fp ); - w.SetMsgBin( &msg_bin ); -} - -//---------------------------------------------------------------------------- - -void DXWriter::Close() -{ - if ( fp != stdout ) - fclose( fp ); - w.SetFP( NULL ); -} - -//---------------------------------------------------------------------------- - -std::string DXWriter::WriteGeoSet( osg::GeoSet &geoset, - const osg::StateSet &active_sset, - std::string &field_name ) - // throws 1 -{ - std::string dx_name; - MyStateSet my_sset(msg_bin); - - // Update the active state for this Drawable (GeoSet), if it has a StateSet - const osg::StateSet *sset; - StateSetCopy *new_sset = 0; - osg::StateSet *drawable_state = geoset.getStateSet(); - - if ( drawable_state ) { - new_sset = new StateSetCopy( active_sset ); - new_sset->merge( *drawable_state ); - sset = new_sset; - - // Collect unhandled modes/attributes in this geoset's stateset - CollectUnhandledModesAndAttrs( drawable_state ); - } - else - sset = &active_sset; - - my_sset.Query( *sset ); - delete new_sset; - - // Now write the GeoSet to a DX field - osg::GeoSet::PrimitiveType prim_type = geoset.getPrimType(); - osg::GeoSet *tri_geoset; - - switch( prim_type ) { - case osg::GeoSet::POINTS : - case osg::GeoSet::LINES : - case osg::GeoSet::TRIANGLES : - case osg::GeoSet::LINE_STRIP : - case osg::GeoSet::FLAT_LINE_STRIP : - case osg::GeoSet::LINE_LOOP : - - try { - dx_name = WriteGeoSetField( field_name, geoset, my_sset ); - } catch (...) { throw; } - break; - - case osg::GeoSet::QUADS : - case osg::GeoSet::TRIANGLE_STRIP : - case osg::GeoSet::FLAT_TRIANGLE_STRIP : - case osg::GeoSet::TRIANGLE_FAN : - case osg::GeoSet::FLAT_TRIANGLE_FAN : - case osg::GeoSet::QUAD_STRIP : - case osg::GeoSet::POLYGON : - - // For all of these cases, bust up the area primitive GeoSet into - // a TRIANGLES GeoSet, and then simply write that. DX doesn't - // support any of these primitive types except POLYGON and QUADS - // anyway, and its polygon support is a bit quirky (e.g. - // $DX_NESTED_LOOPS). - tri_geoset = TriangulateAreaGeoSet( geoset ); - try { - dx_name = WriteGeoSetField( field_name, *tri_geoset, my_sset ); - } catch (...) { - tri_geoset->unref(); - throw; - } - tri_geoset->unref(); - break; - - case osg::GeoSet::NO_TYPE : - // Nonsensical cases - break; - } - - // Return the name of the written field, or "" if not written - return dx_name; -} - -//---------------------------------------------------------------------------- - -std::string DXWriter::WriteGeode( osg::Geode &geode, - const osg::StateSet &active_sset ) - // throws 1 -{ - const std::string &name = geode.getName(); - std::string field_name; - DXGroup *group = 0; - std::string dx_name; - - // If there are multiple GeoSets in this Geode, then we will encase them - // in a DX group - if ( geode.getNumDrawables() > 1 ) - group = new DXGroup( name_mgr, &name ); - - // For all GeoSets in this Geode... - for (unsigned int i = 0; i < geode.getNumDrawables(); i++ ) { - osg::GeoSet *geoset = dynamic_cast( geode.getDrawable(i) ); - - // If we have multiple GeoSets per Geode, we need to generate different - // DX field names for each - if ( geode.getNumDrawables() > 1 ) { - char prim_num_str[20]; - sprintf( prim_num_str, " %d", i+1 ); - field_name = name + prim_num_str; - } - else - field_name = name; - - try { - dx_name = WriteGeoSet( *geoset, active_sset, field_name ); - } catch (...) { throw; } - - if ( !dx_name.empty() && group ) - group->AddMember( dx_name.c_str() ); - } - - // If collecting fields in a Group, write the Group - if ( group ) { - // If no members were written successfully, don't write this group - // or include it in any parent groups - if ( group->GetNumMembers() == 0 ) - dx_name = ""; - else { - group->Write( fp ); - dx_name = group->GetName(); - } - delete group; - } - - return dx_name; -} - -//---------------------------------------------------------------------------- - -void DXWriter::CollectUnhandledModesAndAttrs( osg::StateSet *sset ) -{ - if ( !sset ) - return; - - // FIXME: For now we're collecting all of them, not just the - // unhandled ones - osg::StateSet::ModeList &modelist = sset->getModeList(); - osg::StateSet::AttributeList &attrlist = sset->getAttributeList(); - - // Loop through the mode settings - for( osg::StateSet::ModeList::const_iterator mitr = modelist.begin(); - mitr != modelist.end(); - ++mitr ) - unsupported_modes[ mitr->first ] = 1; - - // Loop through the attribute settings - for( osg::StateSet::AttributeList::const_iterator aitr = attrlist.begin(); - aitr != attrlist.end(); - ++aitr ) - unsupported_attrs[ aitr->first ] = 1; -} - -//---------------------------------------------------------------------------- - -void DXWriter::ReportUnhandledModesAndAttrs() -{ - char msg[1024]; - - msg_bin.Add( "\n" ); - - // Loop through the mode settings... - msg_bin.Add( "OpenGL Modes Encounted:\n " ); - msg[0] = '\0'; - for( DXWriter::ModeList::const_iterator mitr = unsupported_modes.begin(); - mitr != unsupported_modes.end(); - ++mitr ) { - const char *mode_str = GLModeToModeStr( mitr->first ); - if ( mode_str ) - snprintf( msg+strlen(msg), sizeof(msg)-strlen(msg), - " %s", mode_str ); - else - snprintf( msg+strlen(msg), sizeof(msg)-strlen(msg), - " %d", mitr->first ); - } - msg_bin.Add( msg ); - msg_bin.Add( "" ); - - // ...and the attribute settings - msg_bin.Add( "OpenSceneGraph Attributes Encountered:\n " ); - msg[0] = '\0'; - for( DXWriter::AttrList::const_iterator aitr = unsupported_attrs.begin(); - aitr != unsupported_attrs.end(); - ++aitr ) { - const char *attr_str = OSGAttrToAttrStr( aitr->first ); - if ( attr_str ) - snprintf( msg+strlen(msg), sizeof(msg)-strlen(msg), - " %s", attr_str ); - else - snprintf( msg+strlen(msg), sizeof(msg)-strlen(msg), - " %d", aitr->first ); - } - msg_bin.Add( msg ); - msg_bin.Add( "" ); -} - -//---------------------------------------------------------------------------- - -// NOTES ON TRAVERSAL: -// -// So what's up with the StateSetVisitor and StateSetActionVisitor -// pair? Well it's all to make sure that when the user's apply() -// method is called for a Node, we can just hand over the current state -// (attributes and modes) without the user having to go figure it out. -// -// So why are two passes needed? One to update the state. One to -// execute the user's apply method with that state. Basically, -// StateSetVisitor is the master traversal object, and we gosub into -// the StateSetActionVisitor just long enough to invoke the apply -// method stack for a Node, and then we gosub back out to continue -// traversal on the main StateSetVisitor. StateSetVisitor's handles -// keeping the active StateSet up-to-date. -// -// Here's how it works: traversal is invoked on a StateSetVisitor (a -// NodeVisitor). It's constructor accepts a reference to a -// StateSetActionVisitor, which has the user's apply methods. -// -// StateSetVisitor: In it's constructor, we give the -// StateSetActionVisitor we've been handed a handle to ourself. Then -// during traversal when we hit a Node, we push a new StateSet onto our -// StateSet stack which is a copy of the top of the stack merged with -// this Node's StateSet. This new StateSet is then given to the -// StateSetActionVisitor instance, and a new traversal is invoked on -// this Node with the StateSetActionVisitor instance as the visitor. -// When it returns, we pop the stack. -// -// StateSetActionVisitor: When StateSetVisitor initiates a traversal on -// a Node with us, we simply call the apply() method stack for the -// current Node. At the bottom in apply(Node&), we traverse back to -// the StateSetVisitor traversal using node.traverse, which continues -// traversal on the node's children. - -// need to add this to get round incompatibilities between the MipsPro7.3 -// and VisualStudio compiles handling of NodeVisitor:: method calls, VS -// seems broke so can't handle osg::NodeVisitor intpreting it as a -// static method call?!? Anyway no osg:: but using namespace osg seems to -// keep both happy. Robert, Feb 2002. -using namespace osg; - -class StateSetVisitor; - -class StateSetActionVisitor : public osg::NodeVisitor - // Second pass for StateSetVisitor. Users should override apply() - // methods on this object, pass an instance of this object to - // the StateSetVisitor constructor, and initiate traversal on the - // resulting StateSetVisitor instance. - // - // NOTE: We need two passes per Node to update the state correctly so that - // users can still override accept() and get the current state, without - // the user having to call methods to keep it current. - // The first pass updates the state for the node; the second actually - // calls the user's accept methods. In those methods, they can - // call GetActiveStateSet() to get the current state inclusive of that - // node. - // The trick that allows this all to work is that this object's - // apply(Node&) method (at the bottom of the apply stack) transfers - // traversal back over to the StateSetVisitor starting with the children - // of the current node (_traversalMode is also set to TRAVERSE_NONE, - // not that that ever comes into play). So basically we gosub - // into StateSetActionVisitor just long enough to invoke the apply - // methods and then gosub right back out to the main traverser, - // alternating back and forth as we move down the scene graph. -{ - public: - friend class StateSetVisitor; - - StateSetActionVisitor() - : osg::NodeVisitor( osg::NodeVisitor::TRAVERSE_NONE ) {} - - // Give first pass traversal control back to StateSetVisitor - void apply(osg::Node& node); - - void apply(osg::Geode& node) { NodeVisitor::apply(node); } - void apply(osg::Billboard& node) { NodeVisitor::apply(node); } - void apply(osg::LightSource& node){ NodeVisitor::apply(node); } - void apply(osg::Group& node) { NodeVisitor::apply(node); } - void apply(osg::Transform& node) { NodeVisitor::apply(node); } - void apply(osg::Switch& node) { NodeVisitor::apply(node); } - void apply(osg::LOD& node) { NodeVisitor::apply(node); } - void apply(osg::Impostor& node) { NodeVisitor::apply(node); } - void apply(osg::ClearNode& node) { NodeVisitor::apply(node); } - - - const osg::StateSet &GetActiveStateSet() - { return *_current_stateset; } - - protected: - void SetStateSetVisitor( StateSetVisitor *nv ) - { _ssvisitor = nv; } - void SetActiveStateSet( osg::StateSet *sset ) - { _current_stateset = sset; } - - StateSetVisitor *_ssvisitor; - osg::StateSet *_current_stateset; -}; - -//---------------------------------------------------------------------------- - -class StateSetVisitor : public osg::NodeVisitor - // First pass for StateSetVisitor. Users should override apply() - // methods on the StateSetActionVisitor object, pass an instance of it - // to this object's constructor, and initiate traversal on the - // resulting StateSetVisitor instance. - // - // See StateSetActionVisitor for more details. -{ - public: - - StateSetVisitor( StateSetActionVisitor *av ) - // ACTIVE_CHILDREN - Only traverse the most-detailed LOD and - // active children in a Switch - : osg::NodeVisitor( osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN ), - _actionTraversalVisitor(av) - { - _actionTraversalVisitor->SetStateSetVisitor( this ); - } - - void apply(osg::Node& node) - { - // In this first apply() pass, update state with node's StateSet. - osg::StateSet *node_state = node.getStateSet(); - osg::ref_ptr sset; - - if ( node_state ) { - sset = new StateSetCopy( *_state_stack.back() ); - sset->merge( *node_state ); - } - else - if ( !_state_stack.empty() ) - sset = _state_stack.back(); - else - sset = new StateSetCopy(); - - // Now push state, traverse using action visitor, and then pop state - _state_stack.push_back( sset ); - //traverse(node); - _actionTraversalVisitor->SetActiveStateSet( sset.get() ); - node.accept(*_actionTraversalVisitor); - _state_stack.pop_back(); - } - - protected: - StateSetActionVisitor *_actionTraversalVisitor; - std::vector< osg::ref_ptr > _state_stack; -}; - -//---------------------------------------------------------------------------- - -// Give first pass traversal control back to StateSetVisitor -void StateSetActionVisitor::apply(osg::Node& node) - { assert( _ssvisitor ); - // Flip back to StateSetVisitor and traverse node's kids - node.traverse( *_ssvisitor ); } - -//---------------------------------------------------------------------------- - -class DXWriteVisitor : public StateSetActionVisitor -{ - protected: - DXWriter &dx; - std::vector< DXGroup * > group_stack; - MessageBin &msg_bin; - - enum NodeTypes { LOD, BILLBOARD, LIGHTSOURCE, TRANSFORM, SWITCH, - IMPOSTER, CLEARNODE }; - - typedef std::map< NodeTypes, int > StringMap; - StringMap problem_nodes; - - public: - - DXWriteVisitor( DXWriter &dx ) : dx(dx), msg_bin(dx.msg_bin) {} - - void apply(osg::Node& node) - { - dx.CollectUnhandledModesAndAttrs( node.getStateSet() ); - StateSetActionVisitor::apply( node ); // Flip back to StateSetVisitor - } - - void apply(osg::Geode& node) - { - std::string name; - try { - name = dx.WriteGeode( node, GetActiveStateSet() ); - } catch (...) { throw; } - - // Accumulate fields (Geodes) in groups - if ( !name.empty() && group_stack.size() > 0 ) - group_stack[ group_stack.size()-1 ]->AddMember( name.c_str() ); - apply((osg::Node&)node); - } - - void apply(osg::Group& node) - { - DXGroup *group = 0; - - // Only start a new DX group if there are 2 or more kids -#ifdef SKIP_SINGLE_MEMBER_DXGROUPS - if ( node.getNumChildren() >= 2 ) { -#else - if ( 1 ) { -#endif - // New group - group = new DXGroup( dx.name_mgr, &node.getName() ); - group_stack.push_back( group ); - - // Add to any parent group - if ( group_stack.size() >= 2 ) - group_stack[ group_stack.size()-2 ]->AddMember( - group->GetName().c_str() ); - } - - // Process children - // (Children will be added to this DX group, or a parent DX group - // if we didn't start a new DX group above, or no DX group if - // none active right now). - apply((osg::Node&)node); - - // If we started a new DX group above - if ( group ) { - // If wrote some children, write group; else remove from parent group - if ( group_stack.back()->GetNumMembers() > 0 ) - group_stack.back()->Write( dx.fp ); - else if ( group_stack.size() >= 2 ) - group_stack[ group_stack.size()-2 ]->RemoveMember( - group->GetName().c_str() ); - - // Delete group - group_stack.pop_back(); - delete group; - } - } - - void apply(osg::LOD& node) - { problem_nodes[ LOD ]++; apply((osg::Node&)node); } - void apply(osg::Switch& node) - { problem_nodes[ SWITCH ]++; apply((osg::Node&)node); } - - // FIXME - void apply(osg::Billboard& node) - { - // FIXME: Right now we're just treating this like a transformed Geode - // ignoring the other Billboard properties - problem_nodes[ BILLBOARD ]++; - - DXGroup *group = 0; - - // New dummy group (to snap up our child Geode's DX object name) - std::string fallback_name( "Billboard" ); - group = new DXGroup( dx.name_mgr, &node.getName(), &fallback_name ); - group_stack.push_back( group ); - - // Add to any parent group - if ( group_stack.size() >= 2 ) - group_stack[ group_stack.size()-2 ]->AddMember( - group->GetName().c_str() ); - - // Process child - apply((osg::Geode&)node); - - // FIXME: Currently only support one GeoSet per Billboard - if ( group->GetNumMembers() > 1 ) - msg_bin.Add( - "WARNING: Currently only 1 GeoSet per Billboard is supported\n" - " Using same transform for all GeoSets.\n"); - - // Write billboard transform - fprintf( dx.fp, "object \"%s\" class transform of \"%s\"\n", - group->GetName().c_str(), - group->members[ group->members.size()-1 ].c_str() ); - fprintf( dx.fp, - " times 1 0 0\n" - " 0 1 0\n" - " 0 0 1\n" - " plus %g %g %g\n", - node.getPos(0).x(), node.getPos(0).y(), node.getPos(0).z() ); - fprintf( dx.fp, "#\n\n" ); - - // Delete group - group_stack.pop_back(); - delete group; - } - void apply(osg::LightSource& node) - { problem_nodes[ LIGHTSOURCE ]++; apply((osg::Node&)node); } - void apply(osg::Transform& node) - { problem_nodes[ TRANSFORM ]++; apply((osg::Group&)node); } - void apply(osg::Impostor& node) - { problem_nodes[ IMPOSTER ]++; apply((osg::LOD&)node); } - void apply(osg::ClearNode& node) - { problem_nodes[ CLEARNODE ]++; apply((osg::Group&)node); } - - void ReportProblems(); -}; - -//---------------------------------------------------------------------------- - -void DXWriteVisitor::ReportProblems() -{ - for( StringMap::const_iterator smitr = problem_nodes.begin(); - smitr != problem_nodes.end(); - ++smitr ) - switch ( smitr->first ) { - case LOD : msg_bin.Add( "WARNING: %d LOD(s) found ... " - "Traversed only the most detailed child of each.\n", - smitr->second ); - break; - case SWITCH : - msg_bin.Add( "WARNING: %d Switch(s) found ... " - "Traversed only the active child of each.\n", - smitr->second ); - break; - case BILLBOARD : - msg_bin.Add( "WARNING: %d Billboard(s) found ... " - "represented as simple Geodes with Transforms.\n", - smitr->second ); - break; - case LIGHTSOURCE : - msg_bin.Add( "WARNING: %d LightSource(s) found ... Skipped.\n", - smitr->second ); - break; - case TRANSFORM : - msg_bin.Add( "WARNING: %d Transform(s) found ... Skipped.\n", - smitr->second ); - break; - case IMPOSTER : - msg_bin.Add( "WARNING: %d Imposter(s) found ... Skipped.\n", - smitr->second ); - break; - case CLEARNODE : - msg_bin.Add( "WARNING: %d ClearNode(s) found ... Skipped.\n", - smitr->second ); - break; - } -} - -//---------------------------------------------------------------------------- - -bool WriteDX( const osg::Node &node, WriterParms &parms, std::string &messages ) -{ - messages = ""; - - DXWriter dx; - dx.SetParms( parms ); - dx.Open(); - - // Yes, this looks a bit weird. - // See the comment in the StateSetActionVisitor decl for more details. - DXWriteVisitor dxvisitor(dx); - StateSetVisitor ssv(&dxvisitor); - - bool success = false; - try { - // Arg. Node::accept isn't a const method. - ((osg::Node &)node).accept( ssv ); - success = true; - } - catch (...) { - unlink( parms.outfile ); - } - dx.Close(); - - dx.ReportUnhandledModesAndAttrs(); - dxvisitor.ReportProblems(); - messages = dx.msg_bin.GetPending(); - return success; - -} - -}; // namespace dx diff --git a/src/osgPlugins/dx/DXWriter.h b/src/osgPlugins/dx/DXWriter.h deleted file mode 100644 index 34aa86a67..000000000 --- a/src/osgPlugins/dx/DXWriter.h +++ /dev/null @@ -1,49 +0,0 @@ -// This plugin writes an IBM Data Explorer (aka OpenDX) native file. -// (c) Randall Hopper, 2002. -// -// For details on the OpenDX visualization tool, its use, and its file format, -// refer to: -// -// http://www.opendx.org/ -// http://www.opendx.org/support.html#docs -// http://www.research.ibm.com/dx/ -// http://ftp.cs.umt.edu/DX/ -// -// SUPPORTED : Refer to DXWriter.cpp -// UNSUPPORTED: Refer to DXWriter.cpp -// - -// DXWriter.h - -#ifndef __OSG_DXWRITER_H -#define __OSG_DXWRITER_H - -#include -#include - -const int DX_PATH_MAX = 512; - -namespace dx { - -//---------------------------------------------------------------------------- - -struct WriterParms { - bool set_default_color; // Give color to uncolored objects - osg::Vec4 default_color; // Color to assign to uncolored objects - char outfile[ DX_PATH_MAX ]; // Output pathname - //bool binary_mode; // Write DX arrays in binary format - - WriterParms() - { set_default_color = 0, outfile[0] = '\0'; } -}; - -//---------------------------------------------------------------------------- - -bool WriteDX( const osg::Node &node, WriterParms &parms, - std::string &messages ); - -}; // namespace dx - -//---------------------------------------------------------------------------- - -#endif // __OSG_DXWRITER_H diff --git a/src/osgPlugins/dx/GNUmakefile b/src/osgPlugins/dx/GNUmakefile deleted file mode 100644 index 02dc2024b..000000000 --- a/src/osgPlugins/dx/GNUmakefile +++ /dev/null @@ -1,16 +0,0 @@ -TOPDIR = ../../.. -include $(TOPDIR)/Make/makedefs - -CXXFILES =\ - ReaderWriterDX.cpp \ - DXWriter.cpp \ - AreaGeoSetTriangulator.cpp \ - StateSetStr.cpp - -LIBS += $(OSG_LIBS) $(GLUT_LIBS) $(OTHER_LIBS) - -TARGET_BASENAME = dx -include $(TOPDIR)/Make/cygwin_plugin_def -PLUGIN = $(PLUGIN_PREFIX)$(TARGET_BASENAME).$(PLUGIN_EXT) - -include $(TOPDIR)/Make/makerules diff --git a/src/osgPlugins/dx/ReaderWriterDX.cpp b/src/osgPlugins/dx/ReaderWriterDX.cpp deleted file mode 100644 index 8a669fb35..000000000 --- a/src/osgPlugins/dx/ReaderWriterDX.cpp +++ /dev/null @@ -1,75 +0,0 @@ -// This plugin writes an IBM Data Explorer (aka OpenDX) native file. -// (c) Randall Hopper, 2002. -// -// For details on the OpenDX visualization tool, its use, and its file format, -// refer to: -// -// http://www.opendx.org/ -// http://www.opendx.org/support.html#docs -// http://www.research.ibm.com/dx/ -// http://ftp.cs.umt.edu/DX/ -// -// SUPPORTED : Refer to DXWriter.cpp -// UNSUPPORTED: Refer to DXWriter.cpp -// - -// ReaderWriterDX.cpp - -#include - -#include -#include - -#include "ReaderWriterDX.h" -#include "DXWriter.h" - -// FIXME: Support options -osgDB::ReaderWriter::WriteResult ReaderWriterDX::writeObject(const osg::Object &obj, const std::string &filename, const Options *options ) const -{ - const osg::Node *node = dynamic_cast(&obj); - - if ( node != 0 ) - return writeNode( *node, filename, options ); - else - // FIXME: This should probably be "OBJECT_NOT_HANDLED" - return osgDB::ReaderWriter::WriteResult::FILE_NOT_HANDLED; -} - - -osgDB::ReaderWriter::WriteResult ReaderWriterDX::writeNode(const osg::Node &node, const std::string &filename, const Options *) const -{ - dx::WriterParms parms; - std::string messages; - bool ret; - osgDB::ReaderWriter::WriteResult result; - - std::string ext = osgDB::getFileExtension(filename); - if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED; - - parms.outfile[0] = '\0'; - strncat( parms.outfile, filename.c_str(), sizeof(parms.outfile)-1 ); - - // FIXME: Allow specification via Options - parms.set_default_color = 1; - parms.default_color[0] = - parms.default_color[1] = - parms.default_color[2] = 0.75; - parms.default_color[3] = 1.0; // opaque light gray - - ret = dx::WriteDX( node, parms, messages ); - - if ( ret ) - result = osgDB::ReaderWriter::WriteResult( - osgDB::ReaderWriter::WriteResult::FILE_SAVED ); - else - result = osgDB::ReaderWriter::WriteResult( messages ); - - osg::notify( osg::DEBUG_INFO ) << messages; - - return result; -} - - -// now register with Registry to instantiate the above -// reader/writer. -osgDB::RegisterReaderWriterProxy g_dxReaderWriterProxy; diff --git a/src/osgPlugins/dx/ReaderWriterDX.h b/src/osgPlugins/dx/ReaderWriterDX.h deleted file mode 100644 index ec4619aa1..000000000 --- a/src/osgPlugins/dx/ReaderWriterDX.h +++ /dev/null @@ -1,43 +0,0 @@ -// This plugin writes an IBM Data Explorer (aka OpenDX) native file. -// (c) Randall Hopper, 2002. -// -// For details on the OpenDX visualization tool, its use, and its file format, -// refer to: -// -// http://www.opendx.org/ -// http://www.opendx.org/support.html#docs -// http://www.research.ibm.com/dx/ -// http://ftp.cs.umt.edu/DX/ -// -// SUPPORTED : Refer to DXWriter.cpp -// UNSUPPORTED: Refer to DXWriter.cpp -// - -// ReaderWriterDX.h - -#ifndef __OSG_READER_WRITER_DX_H -#define __OSG_READER_WRITER_DX_H - -#include -#include -#include -#include -#include -#include - - -class ReaderWriterDX : public osgDB::ReaderWriter -{ - public: - - virtual const char* className() { return "OpenDX Writer"; } - virtual bool acceptsExtension( const std::string &extension ) const - { return osgDB::equalCaseInsensitive( extension, "dx" ); } - - virtual WriteResult writeObject( const osg::Object &obj, const std::string &filename, const Options *options = NULL ) const; - - virtual WriteResult writeNode ( const osg::Node&node, const std::string &filename, const Options *options = NULL ) const; - -}; - -#endif // __READER_WRITER_DX_H diff --git a/src/osgPlugins/dx/StateSetStr.cpp b/src/osgPlugins/dx/StateSetStr.cpp deleted file mode 100644 index a15ca6d35..000000000 --- a/src/osgPlugins/dx/StateSetStr.cpp +++ /dev/null @@ -1,159 +0,0 @@ -#include - -#include -#include -#include - -namespace dx { - -typedef std::map ModeMap; - -static ModeMap S_mode_map; - -#define ADD_NAME(str,mode) (S_mode_map[(mode)] = (str)); - -// This is a copy of some of the code in src/osgPlugins/osg/StateSet.cpp. -// We need to translate GLModes and StateSet attributes into strings, -// and that's not available in an OSG public API (yet). - -static void initGLNames() -{ - static bool first_time = true; - if (!first_time) return; - - ADD_NAME("GL_ALPHA_TEST",GL_ALPHA_TEST) - ADD_NAME("GL_BLEND",GL_BLEND) - ADD_NAME("GL_COLOR_MATERIAL",GL_COLOR_MATERIAL) - ADD_NAME("GL_CULL_FACE",GL_CULL_FACE) - ADD_NAME("GL_DEPTH_TEST",GL_DEPTH_TEST) - ADD_NAME("GL_FOG",GL_FOG) - ADD_NAME("GL_LIGHTING",GL_LIGHTING) - ADD_NAME("GL_POINT_SMOOTH",GL_POINT_SMOOTH) - ADD_NAME("GL_POLYGON_OFFSET_FILL",GL_POLYGON_OFFSET_FILL) - ADD_NAME("GL_POLYGON_OFFSET_LINE",GL_POLYGON_OFFSET_LINE) - ADD_NAME("GL_POLYGON_OFFSET_POINT",GL_POLYGON_OFFSET_POINT) - - ADD_NAME("GL_TEXTURE_2D",GL_TEXTURE_2D) - ADD_NAME("GL_TEXTURE_GEN_Q",GL_TEXTURE_GEN_Q) - ADD_NAME("GL_TEXTURE_GEN_R",GL_TEXTURE_GEN_R) - ADD_NAME("GL_TEXTURE_GEN_S",GL_TEXTURE_GEN_S) - ADD_NAME("GL_TEXTURE_GEN_T",GL_TEXTURE_GEN_T) - - ADD_NAME("GL_STENCIL_TEST",GL_STENCIL_TEST) - - ADD_NAME("GL_CLIP_PLANE0",GL_CLIP_PLANE0); - ADD_NAME("GL_CLIP_PLANE1",GL_CLIP_PLANE1); - ADD_NAME("GL_CLIP_PLANE2",GL_CLIP_PLANE2); - ADD_NAME("GL_CLIP_PLANE3",GL_CLIP_PLANE3); - ADD_NAME("GL_CLIP_PLANE4",GL_CLIP_PLANE4); - ADD_NAME("GL_CLIP_PLANE5",GL_CLIP_PLANE5); - - ADD_NAME("GL_LIGHT0",GL_LIGHT0); - ADD_NAME("GL_LIGHT1",GL_LIGHT1); - ADD_NAME("GL_LIGHT2",GL_LIGHT2); - ADD_NAME("GL_LIGHT3",GL_LIGHT3); - ADD_NAME("GL_LIGHT4",GL_LIGHT4); - ADD_NAME("GL_LIGHT5",GL_LIGHT5); - ADD_NAME("GL_LIGHT6",GL_LIGHT6); - ADD_NAME("GL_LIGHT7",GL_LIGHT7); - - first_time = false; -} - -const char *GLModeToModeStr( osg::StateAttribute::GLMode mode ) -{ - initGLNames(); - ModeMap::const_iterator mitr = S_mode_map.find(mode); - if ( mitr != S_mode_map.end() ) - return mitr->second.c_str(); - else - return 0; -} - -osg::StateAttribute::GLMode GLModeStrToMode( const char mode_str[] ) -{ - initGLNames(); - for( ModeMap::const_iterator mitr = S_mode_map.begin(); - mitr != S_mode_map.end(); - ++mitr ) - if ( strcmp( mode_str, mitr->second.c_str() ) == 0 ) - return mitr->first; - return (osg::StateAttribute::GLMode) -1; -} - -//=========================================================================== - -typedef std::map AttrMap; - -static AttrMap S_attr_map; - -#define ADD_ATTR(attr,str) (S_attr_map[(attr)] = (str)); - -static void initOSGAttrNames() -{ - static bool first_time = true; - if (!first_time) return; - - ADD_ATTR( osg::StateAttribute::TEXTURE , "TEXTURE" ); - ADD_ATTR( osg::StateAttribute::MATERIAL , "MATERIAL" ); - ADD_ATTR( osg::StateAttribute::ALPHAFUNC , "ALPHAFUNC" ); - ADD_ATTR( osg::StateAttribute::ANTIALIAS , "ANTIALIAS" ); - ADD_ATTR( osg::StateAttribute::COLORTABLE , "COLORTABLE" ); - ADD_ATTR( osg::StateAttribute::CULLFACE , "CULLFACE" ); - ADD_ATTR( osg::StateAttribute::FOG , "FOG" ); - ADD_ATTR( osg::StateAttribute::FRONTFACE , "FRONTFACE" ); - ADD_ATTR( osg::StateAttribute::LIGHT , "LIGHT" ); - ADD_ATTR( osg::StateAttribute::LIGHT_0 , "LIGHT_0" ); - ADD_ATTR( osg::StateAttribute::LIGHT_1 , "LIGHT_1" ); - ADD_ATTR( osg::StateAttribute::LIGHT_2 , "LIGHT_2" ); - ADD_ATTR( osg::StateAttribute::LIGHT_3 , "LIGHT_3" ); - ADD_ATTR( osg::StateAttribute::LIGHT_4 , "LIGHT_4" ); - ADD_ATTR( osg::StateAttribute::LIGHT_5 , "LIGHT_5" ); - ADD_ATTR( osg::StateAttribute::LIGHT_6 , "LIGHT_6" ); - ADD_ATTR( osg::StateAttribute::LIGHT_7 , "LIGHT_7" ); - ADD_ATTR( osg::StateAttribute::POINT , "POINT" ); - ADD_ATTR( osg::StateAttribute::LINEWIDTH , "LINEWIDTH" ); - ADD_ATTR( osg::StateAttribute::POLYGONMODE , "POLYGONMODE" ); - ADD_ATTR( osg::StateAttribute::POLYGONOFFSET , "POLYGONOFFSET"); - ADD_ATTR( osg::StateAttribute::TEXENV , "TEXENV" ); - ADD_ATTR( osg::StateAttribute::TEXGEN , "TEXGEN" ); - ADD_ATTR( osg::StateAttribute::TEXMAT , "TEXMAT" ); - ADD_ATTR( osg::StateAttribute::BLENDFUNC , "BLENDFUNC" ); - ADD_ATTR( osg::StateAttribute::STENCIL , "STENCIL" ); - ADD_ATTR( osg::StateAttribute::COLORMASK , "COLORMASK" ); - ADD_ATTR( osg::StateAttribute::DEPTH , "DEPTH" ); - ADD_ATTR( osg::StateAttribute::VIEWPORT , "VIEWPORT" ); - ADD_ATTR( osg::StateAttribute::CLIPPLANE , "CLIPPLANE" ); - ADD_ATTR( osg::StateAttribute::CLIPPLANE_0 , "CLIPPLANE_0" ); - ADD_ATTR( osg::StateAttribute::CLIPPLANE_1 , "CLIPPLANE_1" ); - ADD_ATTR( osg::StateAttribute::CLIPPLANE_2 , "CLIPPLANE_2" ); - ADD_ATTR( osg::StateAttribute::CLIPPLANE_3 , "CLIPPLANE_3" ); - ADD_ATTR( osg::StateAttribute::CLIPPLANE_4 , "CLIPPLANE_4" ); - ADD_ATTR( osg::StateAttribute::CLIPPLANE_5 , "CLIPPLANE_5" ); - ADD_ATTR( osg::StateAttribute::COLORMATRIX , "COLORMATRIX" ); - - first_time = false; -} - -const char *OSGAttrToAttrStr( osg::StateAttribute::Type attr ) -{ - initOSGAttrNames(); - AttrMap::const_iterator aitr = S_attr_map.find(attr); - if ( aitr != S_attr_map.end() ) - return aitr->second.c_str(); - else - return 0; -} - -osg::StateAttribute::Type OSGAttrStrToAttr( const char attr_str[] ) -{ - initGLNames(); - for( AttrMap::const_iterator aitr = S_attr_map.begin(); - aitr != S_attr_map.end(); - ++aitr ) - if ( strcmp( attr_str, aitr->second.c_str() ) == 0 ) - return aitr->first; - return (osg::StateAttribute::Type) -1; -} - -}; // namespace dx diff --git a/src/osgPlugins/dx/StateSetStr.h b/src/osgPlugins/dx/StateSetStr.h deleted file mode 100644 index 7c8bca66e..000000000 --- a/src/osgPlugins/dx/StateSetStr.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef __OSG_STATESETSTR_H -#define __OSG_STATESETSTR_H - -#include - -namespace dx { - -const char *GLModeToModeStr( osg::StateAttribute::GLMode mode ); - -osg::StateAttribute::GLMode GLModeStrToMode( const char mode_str[] ); - -const char *OSGAttrToAttrStr( osg::StateAttribute::Type attr ); - -osg::StateAttribute::Type OSGAttrStrToAttr( const char attr_str[] ); - -}; - -#endif