diff --git a/src/osgPlugins/dae/ReaderWriterDAE.cpp b/src/osgPlugins/dae/ReaderWriterDAE.cpp index 51611f92e..e4c90cc33 100644 --- a/src/osgPlugins/dae/ReaderWriterDAE.cpp +++ b/src/osgPlugins/dae/ReaderWriterDAE.cpp @@ -109,9 +109,11 @@ ReaderWriterDAE::writeNode( const osg::Node& node, bool usePolygon(false); // Use plugin option "polygon" to enable bool googleMode(false); // Use plugin option "GoogleMode" to enable bool writeExtras(true); // Use plugin option "NoExtras" to disable - bool earthTex(false); // Use plugin option "DaeEarthTex" to enable - bool zUpAxis(false); // Use plugin option "ZUpAxis" to enable - bool forceTexture(false); // Use plugin option "ForceTexture" to enable + bool earthTex(false); // Use plugin option "daeEarthTex" to enable + bool zUpAxis(false); // Use plugin option "daeZUpAxis" to enable + bool linkOrignialTextures(false); + bool forceTexture(false); + bool namesUseCodepage(false); if( options ) { pDAE = (DAE*)options->getPluginData("DAE"); @@ -131,7 +133,9 @@ ReaderWriterDAE::writeNode( const osg::Node& node, else if (opt == "NoExtras") writeExtras = false; else if (opt == "daeEarthTex") earthTex = true; else if (opt == "daeZUpAxis") zUpAxis = true; - else if (opt == "daeForceTexture") forceTexture = true; + else if (opt == "daeLinkOriginalTexturesNoForce") { linkOrignialTextures = true; forceTexture = false; } + else if (opt == "daeLinkOriginalTexturesForce") { linkOrignialTextures = true; forceTexture = true; } + else if (opt == "daeNamesUseCodepage") namesUseCodepage = true; else if (!opt.empty()) { OSG_NOTICE << std::endl << "COLLADA dae plugin: unrecognized option \"" << opt << std::endl; @@ -150,7 +154,7 @@ ReaderWriterDAE::writeNode( const osg::Node& node, osg::NodeVisitor::TraversalMode traversalMode = writeExtras ? osg::NodeVisitor::TRAVERSE_ALL_CHILDREN : osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN; - osgDAE::daeWriter daeWriter(pDAE, fileURI, usePolygon, googleMode, traversalMode, writeExtras, earthTex, zUpAxis, forceTexture); + osgDAE::daeWriter daeWriter(pDAE, fileURI, osgDB::getFilePath(fname), osgDB::getFilePath(node.getName().empty() ? fname : node.getName()), options, usePolygon, googleMode, traversalMode, writeExtras, earthTex, zUpAxis, linkOrignialTextures, forceTexture, namesUseCodepage); daeWriter.setRootNode( node ); const_cast(&node)->accept( daeWriter ); @@ -178,7 +182,8 @@ ReaderWriterDAE::writeNode( const osg::Node& node, return retVal; } -static void replace(std::string & str, const char from, const std::string & to) { +static void replace(std::string & str, const char from, const std::string & to) +{ // Replace for all occurences for(std::string::size_type pos=str.find(from); pos!=std::string::npos; pos=str.find(from)) { @@ -188,7 +193,11 @@ static void replace(std::string & str, const char from, const std::string & to) std::string ReaderWriterDAE::ConvertFilePathToColladaCompatibleURI(const std::string& FilePath) { - std::string path( cdom::nativePathToUri(FilePath) ); +#ifdef OSG_USE_UTF8_FILENAME + std::string path( cdom::nativePathToUri( FilePath ) ); +#else + std::string path( cdom::nativePathToUri( osgDB::convertStringFromCurrentCodePageToUTF8(FilePath) ) ); +#endif // Unfortunately, cdom::nativePathToUri() does not convert '#' characters to "%23" as expected. // So having /a/#b/c will generate a wrong conversion, as '#' will be misinterpreted as an URI fragment. diff --git a/src/osgPlugins/dae/ReaderWriterDAE.h b/src/osgPlugins/dae/ReaderWriterDAE.h index f7a417888..8fab8039b 100644 --- a/src/osgPlugins/dae/ReaderWriterDAE.h +++ b/src/osgPlugins/dae/ReaderWriterDAE.h @@ -23,7 +23,9 @@ public: supportsOption("NoExtras", "(Write option) Undocumented"); supportsOption("daeEarthTex", "(Write option) DAE settings for writing earth textures"); supportsOption("daeZUpAxis", "(Write option) Indicates the up axis is Z instead of Y"); - supportsOption("daeForceTexture", "(Write option) Force writing references to an image for a texture, even if the file is not found"); + 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("StrictTransparency", "(Read option) Undocumented"); } diff --git a/src/osgPlugins/dae/daeWAnimations.cpp b/src/osgPlugins/dae/daeWAnimations.cpp index f390b8a66..0b88788b4 100644 --- a/src/osgPlugins/dae/daeWAnimations.cpp +++ b/src/osgPlugins/dae/daeWAnimations.cpp @@ -29,12 +29,14 @@ #include #include #include +#include using namespace osgDAE; void daeWriter::writeAnimations( osg::Node &node ) { + const std::string nodeNameUTF( _namesUseCodepage ? osgDB::convertStringFromCurrentCodePageToUTF8(node.getName()) : node.getName() ); osg::NodeCallback* ncb = node.getUpdateCallback(); if (ncb) { @@ -54,7 +56,7 @@ void daeWriter::writeAnimations( osg::Node &node ) domAnimation* pMainDomAnimation = pDomAnimation; osg::ref_ptr animation = animationList[i]; - std::string animationName = animation->getName(); + std::string animationName( animation->getName() ); if (animationName.empty()) animationName = "animation"; animationName = uniquify( animationName ); @@ -65,7 +67,8 @@ void daeWriter::writeAnimations( osg::Node &node ) for (size_t j=0; j < animationChannels.size(); j++) { osgAnimation::Channel* channel = animationChannels[j].get(); - std::string channelName = channel->getName(); + std::string channelName( channel->getName() ); + std::string channelNameUTF( _namesUseCodepage ? osgDB::convertStringFromCurrentCodePageToUTF8(channelName) : channelName ); // Wrap each animation channel into it's own child when more than 1 channel if (animationChannels.size() > 1) @@ -73,15 +76,18 @@ void daeWriter::writeAnimations( osg::Node &node ) pDomAnimation = daeSafeCast< domAnimation >( pMainDomAnimation->add( COLLADA_ELEMENT_ANIMATION ) ); if (channelName.empty()) + { channelName = "channel"; + channelNameUTF = channelName; + } animationName = uniquify( channelName ); - pDomAnimation->setId(channelName.c_str()); + pDomAnimation->setId(channelNameUTF.c_str()); } - std::string sourceName = channelName + "_sampler"; - std::string inputSourceName = channelName + "_input"; - std::string outputSourceName = channelName + "_output"; - std::string interpolationSourceName = channelName + "_interpolation"; + std::string sourceName( channelNameUTF + "_sampler" ); + std::string inputSourceName( channelNameUTF + "_input" ); + std::string outputSourceName( channelNameUTF + "_output" ); + std::string interpolationSourceName( channelNameUTF + "_interpolation" ); // Fill dom sources based on sampler osgAnimation::Sampler* animationSampler = channel->getSampler(); @@ -104,7 +110,7 @@ void daeWriter::writeAnimations( osg::Node &node ) osg::Vec3 vec = (*v3kc)[i].getValue(); // This needs some serious cleanup - if (channelName.find("euler") != std::string::npos) + if (channelNameUTF.find("euler") != std::string::npos) { frameValues.append(osg::RadiansToDegrees(vec.x())); frameValues.append(osg::RadiansToDegrees(vec.y())); @@ -179,7 +185,7 @@ void daeWriter::writeAnimations( osg::Node &node ) pDomParam->setType(COLLADA_TYPE_NAME); // Split up access to the euler float array into three sources, because we need to target three separate transforms - if (channelName.find("euler") != std::string::npos) + if (channelNameUTF.find("euler") != std::string::npos) { pDomSource = daeSafeCast< domSource >(pDomAnimation->add(COLLADA_ELEMENT_SOURCE)); std::string outputSourceNameX = outputSourceName + "_X"; @@ -283,7 +289,7 @@ void daeWriter::writeAnimations( osg::Node &node ) osg::Node* node = _animatedNodeCollector.getTargetNode(targetName); if (node) { - std::string domChannelTargetName = node->getName() + "/rotateX.ANGLE"; + std::string domChannelTargetName = nodeNameUTF + "/rotateX.ANGLE"; pDomChannel->setTarget(domChannelTargetName.c_str()); } else @@ -327,7 +333,7 @@ void daeWriter::writeAnimations( osg::Node &node ) osg::Node* node = _animatedNodeCollector.getTargetNode(targetName); if (node) { - std::string domChannelTargetName = node->getName() + "/rotateY.ANGLE"; + std::string domChannelTargetName = nodeNameUTF + "/rotateY.ANGLE"; pDomChannel->setTarget(domChannelTargetName.c_str()); } else @@ -371,7 +377,7 @@ void daeWriter::writeAnimations( osg::Node &node ) osg::Node* node = _animatedNodeCollector.getTargetNode(targetName); if (node) { - std::string domChannelTargetName = node->getName() + "/rotateZ.ANGLE"; + std::string domChannelTargetName = nodeNameUTF + "/rotateZ.ANGLE"; pDomChannel->setTarget(domChannelTargetName.c_str()); } else @@ -457,13 +463,13 @@ void daeWriter::writeAnimations( osg::Node &node ) osg::Node* node = _animatedNodeCollector.getTargetNode(targetName); if (node) { - std::string domChannelTargetName = node->getName(); + std::string domChannelTargetName = nodeNameUTF; - if (channelName.find("position") != std::string::npos) + if (channelNameUTF.find("position") != std::string::npos) { domChannelTargetName += "/translate"; } - else if (channelName.find("scale") != std::string::npos) + else if (channelNameUTF.find("scale") != std::string::npos) { domChannelTargetName += "/scale"; } diff --git a/src/osgPlugins/dae/daeWMaterials.cpp b/src/osgPlugins/dae/daeWMaterials.cpp index 8b5f2d304..0e2bde8aa 100644 --- a/src/osgPlugins/dae/daeWMaterials.cpp +++ b/src/osgPlugins/dae/daeWMaterials.cpp @@ -20,6 +20,9 @@ #include #include +#include +#include +#include //#include //#include @@ -35,7 +38,7 @@ void daeWriter::processMaterial( osg::StateSet *ss, domBind_material *pDomBindMa osg::ref_ptr ssClean = CleanStateSet(ss); // Need to hold a ref to this or the materialMap.find() will delete it domBind_material::domTechnique_common *tc = daeSafeCast< domBind_material::domTechnique_common >( pDomBindMaterial->add( COLLADA_ELEMENT_TECHNIQUE_COMMON ) ); domInstance_material *pDomInstanceMaterial = daeSafeCast< domInstance_material >( tc->add( COLLADA_ELEMENT_INSTANCE_MATERIAL ) ); - std::string symbol = geoName + "_material"; + const std::string symbol( _namesUseCodepage ? osgDB::convertStringFromCurrentCodePageToUTF8(geoName + "_material") : (geoName + "_material") ); pDomInstanceMaterial->setSymbol( symbol.c_str() ); // See if material already exists in cache @@ -53,7 +56,7 @@ void daeWriter::processMaterial( osg::StateSet *ss, domBind_material *pDomBindMa } domMaterial *mat = daeSafeCast< domMaterial >( lib_mats->add( COLLADA_ELEMENT_MATERIAL ) ); - std::string name = ssClean->getName(); + std::string name( ssClean->getName() ); if ( name.empty() ) { name = "material"; @@ -99,16 +102,71 @@ void daeWriter::processMaterial( osg::StateSet *ss, domBind_material *pDomBindMa osg::Image *osgimg = tex->getImage( 0 ); domImage::domInit_from *imgif = daeSafeCast< domImage::domInit_from >( img->add( COLLADA_ELEMENT_INIT_FROM ) ); - std::string fileURI = ReaderWriterDAE::ConvertFilePathToColladaCompatibleURI(osgDB::findDataFile(osgimg->getFileName())); - if (fileURI=="" && m_ForceTexture) + + std::string fileURI; + if (m_linkOrignialTextures) { - fileURI = osgimg->getFileName(); + // We link to orignial images. + fileURI = osgDB::findDataFile(osgimg->getFileName()); + if (fileURI=="" && m_ForceTexture) + { + fileURI = osgDB::getRealPath(osgimg->getFileName()); + } } + else + { + // We do not link to orignial images. Then must ensure to write the image. + // Following code block is borrowed from FBX's WriterNodeVisitor::Material::Material(). + ImageSet::iterator it = _imageSet.find(osgimg); + if (it == _imageSet.end()) + { + fileURI = osgDB::getRealPath(osgDB::convertFileNameToNativeStyle(osgimg->getFileName())); + std::string destPath; + std::string relativePath; + if (fileURI.empty()) + { + static const unsigned int MAX_IMAGE_NUMBER = UINT_MAX-1; // -1 to allow doing +1 without an overflow + unsigned int imageNumber; + for (imageNumber=_lastGeneratedImageFileName+1; imageNumbersetValue( dd ); // The document URI should contain the canonical path it was created with - imgif->getValue().makeRelativeTo(doc->getDocumentURI()); + if (m_linkOrignialTextures) imgif->getValue().makeRelativeTo(doc->getDocumentURI()); if (!m_EarthTex) { diff --git a/src/osgPlugins/dae/daeWriter.cpp b/src/osgPlugins/dae/daeWriter.cpp index 5c6092266..6146369b6 100644 --- a/src/osgPlugins/dae/daeWriter.cpp +++ b/src/osgPlugins/dae/daeWriter.cpp @@ -19,6 +19,7 @@ #include #include +#include namespace osgDAE { @@ -95,7 +96,7 @@ std::string toString(const osg::Matrix& value) } -daeWriter::daeWriter( DAE *dae_, const std::string &fileURI, bool _usePolygons, bool googleMode, TraversalMode tm, bool _writeExtras, bool earthTex, bool zUpAxis, bool forceTexture) : osg::NodeVisitor( tm ), +daeWriter::daeWriter( DAE *dae_, const std::string & fileURI, const std::string & directory, const std::string & srcDirectory, const osgDB::ReaderWriter::Options * options, bool _usePolygons, bool googleMode, TraversalMode tm, bool _writeExtras, bool earthTex, bool zUpAxis, bool linkOrignialTextures, bool forceTexture, bool namesUseCodepage) : osg::NodeVisitor( tm ), dae(dae_), _domLibraryAnimations(NULL), writeExtras(_writeExtras), @@ -104,8 +105,14 @@ daeWriter::daeWriter( DAE *dae_, const std::string &fileURI, bool _usePolygons, m_GoogleMode(googleMode), m_EarthTex(earthTex), m_ZUpAxis(zUpAxis), + m_linkOrignialTextures(linkOrignialTextures), m_ForceTexture(forceTexture), - m_CurrentRenderingHint(osg::StateSet::DEFAULT_BIN) + _namesUseCodepage(namesUseCodepage), + m_CurrentRenderingHint(osg::StateSet::DEFAULT_BIN), + _lastGeneratedImageFileName(0), + _directory(directory), + _srcDirectory(srcDirectory), + _options(options) { success = true; @@ -198,8 +205,9 @@ void daeWriter::updateCurrentDaeNode() } } -std::string daeWriter::uniquify( const std::string &name ) +std::string daeWriter::uniquify( const std::string &_name ) { + const std::string name( _namesUseCodepage ? osgDB::convertStringFromCurrentCodePageToUTF8(_name) : _name ); std::map< std::string, int >::iterator iter = uniqueNames.find( name ); if ( iter != uniqueNames.end() ) { diff --git a/src/osgPlugins/dae/daeWriter.h b/src/osgPlugins/dae/daeWriter.h index 1bbab37e8..d07ae3ec6 100644 --- a/src/osgPlugins/dae/daeWriter.h +++ b/src/osgPlugins/dae/daeWriter.h @@ -136,7 +136,7 @@ class daeWriter : public osg::NodeVisitor protected: class ArrayNIndices; public: - daeWriter( DAE *dae_, const std::string &fileURI, bool usePolygons=false, bool googleMode = false, TraversalMode tm=TRAVERSE_ALL_CHILDREN, bool writeExtras = true, bool earthTex = false, bool zUpAxis=false, bool forceTexture=false); + daeWriter( DAE *dae_, const std::string &fileURI, const std::string & directory, const std::string & srcDirectory, const osgDB::ReaderWriter::Options * options, bool usePolygons=false, bool googleMode = false, TraversalMode tm=TRAVERSE_ALL_CHILDREN, bool writeExtras = true, bool earthTex = false, bool zUpAxis=false, bool linkOrignialTextures=false, bool forceTexture=false, bool namesUseCodepage=false); virtual ~daeWriter(); void setRootNode( const osg::Node &node ); @@ -310,7 +310,10 @@ private: //members /** indicates if the up axis is on Z axis*/ bool m_ZUpAxis; - /** force the use an image for a texture, even if the file is not found*/ + /** link to original images instead of exporting */ + bool m_linkOrignialTextures; + + /** force the use an image for a texture, even if the file is not found (when m_linkOrignialTextures). */ bool m_ForceTexture; /** Current RenderingHint */ @@ -318,6 +321,18 @@ private: //members int m_CurrentRenderingHint; FindAnimatedNodeVisitor _animatedNodeCollector; + + /** Number used when writing images with no name, to generate a file name. */ + unsigned int _lastGeneratedImageFileName; + std::string _directory; + std::string _srcDirectory; + const osgDB::ReaderWriter::Options * _options; + bool _namesUseCodepage; + + typedef std::map ImageSet; + typedef std::set ImageFilenameSet; // Sub-optimal because strings are doubled (in ImageSet). Moreover, an unordered_set (= hashset) would be more efficient (Waiting for unordered_set to be included in C++ standard ;) ). + ImageSet _imageSet; + ImageFilenameSet _imageFilenameSet; }; }