diff --git a/src/osgPlugins/dae/ReaderWriterDAE.cpp b/src/osgPlugins/dae/ReaderWriterDAE.cpp index 87cd9db9d..1fe0a11c1 100644 --- a/src/osgPlugins/dae/ReaderWriterDAE.cpp +++ b/src/osgPlugins/dae/ReaderWriterDAE.cpp @@ -221,6 +221,7 @@ ReaderWriterDAE::writeNode( const osg::Node& node, else if (opt == "daeLinkOriginalTexturesNoForce") { pluginOptions.linkOrignialTextures = true; pluginOptions.forceTexture = false; } else if (opt == "daeLinkOriginalTexturesForce") { pluginOptions.linkOrignialTextures = true; pluginOptions.forceTexture = true; } else if (opt == "daeNamesUseCodepage") pluginOptions.namesUseCodepage = true; + else if (opt == "daeRenameIds") pluginOptions.renameIds = true; else if (!opt.empty()) { OSG_NOTICE << std::endl << "COLLADA dae plugin: unrecognized option \"" << opt << std::endl; diff --git a/src/osgPlugins/dae/ReaderWriterDAE.h b/src/osgPlugins/dae/ReaderWriterDAE.h index 63ee6bd00..87f23c963 100644 --- a/src/osgPlugins/dae/ReaderWriterDAE.h +++ b/src/osgPlugins/dae/ReaderWriterDAE.h @@ -26,13 +26,14 @@ public: supportsOption("daeLinkOriginalTexturesNoForce", "(Write option) Writes reference to the original image if found, instead of writing the image in memory"); supportsOption("daeLinkOriginalTexturesForce", "(Write option) Writes reference to the original image even if not found, instead of writing the image in memory"); supportsOption("daeNamesUseCodepage", "(Write option) All names except filenames (materials, animation, geometries...) should be considered as encoded using current codepage (UTF8 if not). Filenames follow OSG_USE_UTF8_FILENAME."); + supportsOption("daeRenameIds", "(Write option) Rename all IDs (geometries, materials, etc.) to remove characters which may be interpreted as an URI. Useful if you want to ensure names having spaces or slashes behave correctly. This may be undesired if original naming must be somewhat kept."); supportsOption("StrictTransparency", "(Read option) Undocumented"); supportsOption("daeTessellateNone", "(Read option) Do not tessellate at all (Polygons are stored as GL_POLYGON - not suitable for concave polygons)"); supportsOption("daeTessellatePolygonsAsTriFans", "(Read option) Tessellate the old way (default), interpreting polygons as triangle fans (faster, but does not work for concave polygons)"); supportsOption("daeTessellatePolygons", "(Read option) Use full tessellation of polygons (slower, works for concave polygons)"); supportsOption("daeUsePredefinedTextureUnits", "(Read option) Texture units have fixed uses (0: ambient occlusion, 1: main texture...). May create non contiguous units (default)."); - supportsOption("daeUsePredefinedTextureUnits", "(Read option) Texture units are created in sequence (contiguous units)."); + supportsOption("daeUseSequencedTextureUnits", "(Read option) Texture units are created in sequence (contiguous units)."); } const char* className() const { return "COLLADA 1.4.x DAE reader/writer"; } diff --git a/src/osgPlugins/dae/daeWriter.cpp b/src/osgPlugins/dae/daeWriter.cpp index c9089bd54..c3fc69830 100644 --- a/src/osgPlugins/dae/daeWriter.cpp +++ b/src/osgPlugins/dae/daeWriter.cpp @@ -20,7 +20,7 @@ #include #include - +#include namespace osgDAE { @@ -71,6 +71,20 @@ daeWriter::ArrayNIndices::ArrayNIndices( osg::Array* valArray, osg::IndexArray* } +std::string toString(const osg::Vec2f& value) +{ + std::stringstream str; + str << value.x() << " " << value.y(); + return str.str(); +} + +std::string toString(const osg::Vec2d& value) +{ + std::stringstream str; + str << value.x() << " " << value.y(); + return str.str(); +} + std::string toString(const osg::Vec3f& value) { std::stringstream str; @@ -85,7 +99,22 @@ std::string toString(const osg::Vec3d& value) return str.str(); } -std::string toString(const osg::Matrix& value) +std::string toString(const osg::Vec4f& value) +{ + std::stringstream str; + str << value.x() << " " << value.y() << " " << value.z() << " " << value.w(); + return str.str(); +} + +std::string toString(const osg::Vec4d& value) +{ + std::stringstream str; + str << value.x() << " " << value.y() << " " << value.z() << " " << value.w(); + return str.str(); +} + +template +std::string matrixToString(T value) { std::stringstream str; str << value(0,0) << " " << value(1,0) << " " << value(2,0) << " " << value(3,0) << " " @@ -95,6 +124,15 @@ std::string toString(const osg::Matrix& value) return str.str(); } +std::string toString(const osg::Matrixf& value) +{ + return matrixToString(value); +} + +std::string toString(const osg::Matrixd& value) +{ + return matrixToString(value); +} daeWriter::Options::Options() : usePolygons(false), @@ -104,7 +142,8 @@ daeWriter::Options::Options() linkOrignialTextures(false), forceTexture(false), namesUseCodepage(false), - relativiseImagesPathNbUpDirs(0) + relativiseImagesPathNbUpDirs(0), + renameIds(false) {} daeWriter::daeWriter( DAE *dae_, const std::string & fileURI, const std::string & directory, const std::string & srcDirectory, const osgDB::ReaderWriter::Options * options, TraversalMode tm, const Options * pluginOptions) : osg::NodeVisitor( tm ), @@ -211,20 +250,29 @@ void daeWriter::updateCurrentDaeNode() std::string daeWriter::uniquify( const std::string &_name ) { - const std::string name( _pluginOptions.namesUseCodepage ? osgDB::convertStringFromCurrentCodePageToUTF8(_name) : _name ); - std::map< std::string, int >::iterator iter = uniqueNames.find( name ); - if ( iter != uniqueNames.end() ) + const std::string baseName( _pluginOptions.namesUseCodepage ? osgDB::convertStringFromCurrentCodePageToUTF8(_name) : _name ); + std::string newName( baseName ); + if (_pluginOptions.renameIds) { - iter->second++; + // Turn 'newName' into a simple ID + // Note: ConvertFilePathToColladaCompatibleURI(newName) did not the job: names such as "C:\somedir\somefile" become "/C:/somedir/somefile" and are not interpreted as a simple ID within Google Earth. + static const char * const REPLACE_CHARS = " /\\:#?=%&*"; + for(std::size_t found = newName.find_first_of(REPLACE_CHARS); found != std::string::npos; found = newName.find_first_of(REPLACE_CHARS)) newName[found] = '_'; + } + + // Loop while newName is in use + UniqueNames::iterator iter; + for (iter = uniqueNames.find(newName); iter != uniqueNames.end(); iter = uniqueNames.find(newName)) + { + if (iter->second == std::numeric_limits::max()) throw std::runtime_error("Not implemented: renaming DAE name above given limit."); + iter->second++; // Increment usage count std::ostringstream num; num << std::dec << iter->second; - return name + "_" + num.str(); - } - else - { - uniqueNames.insert( std::make_pair( name, 0 ) ); - return name; + newName = baseName + "_" + num.str(); } + + uniqueNames.insert( std::make_pair( newName, 0 ) ); + return newName; } void daeWriter::createAssetTag( bool isZUpAxis ) diff --git a/src/osgPlugins/dae/daeWriter.h b/src/osgPlugins/dae/daeWriter.h index a2f18d874..5a74132d9 100644 --- a/src/osgPlugins/dae/daeWriter.h +++ b/src/osgPlugins/dae/daeWriter.h @@ -89,9 +89,14 @@ std::string toString(T value) return str.str(); } +std::string toString(const osg::Vec2f& value); +std::string toString(const osg::Vec2d& value); std::string toString(const osg::Vec3f& value); std::string toString(const osg::Vec3d& value); -std::string toString(const osg::Matrix& value); +std::string toString(const osg::Vec4f& value); +std::string toString(const osg::Vec4d& value); +std::string toString(const osg::Matrixf& value); +std::string toString(const osg::Matrixd& value); // Collects all nodes that are targeted by an animation class FindAnimatedNodeVisitor : public osg::NodeVisitor @@ -164,6 +169,8 @@ public: bool forceTexture; bool namesUseCodepage; unsigned int relativiseImagesPathNbUpDirs; + /** Rename all IDs (geometries, materials, etc.) to remove characters which may be interpreted as an URI. */ + bool renameIds; }; daeWriter(DAE *dae_, const std::string &fileURI, const std::string & directory, const std::string & srcDirectory, const osgDB::ReaderWriter::Options * options, TraversalMode tm=TRAVERSE_ALL_CHILDREN, const Options * pluginOptions=NULL); virtual ~daeWriter(); @@ -264,7 +271,8 @@ protected: //members typedef std::map< osgAnimation::RigGeometry*, domController *> OsgRigGeometryDomControllerMap; typedef std::map< osgAnimation::MorphGeometry*, domController *> OsgMorphGeometryDomControllerMap; - std::map< std::string, int > uniqueNames; + typedef std::map< std::string, int > UniqueNames; + UniqueNames uniqueNames; OsgGeometryDomGeometryMap geometryMap; OsgRigGeometryDomControllerMap _osgRigGeometryDomControllerMap; OsgMorphGeometryDomControllerMap _osgMorphGeometryDomControllerMap;