Index: /OpenSceneGraph/trunk/src/osgPlugins/3ds/WriterCompareTriangle.h
===================================================================
--- /OpenSceneGraph/trunk/src/osgPlugins/3ds/WriterCompareTriangle.h (revision 10853)
+++ /OpenSceneGraph/trunk/src/osgPlugins/3ds/WriterCompareTriangle.h (revision 11056)
Index: /OpenSceneGraph/trunk/src/osgPlugins/3ds/WriterNodeVisitor.cpp
===================================================================
--- /OpenSceneGraph/trunk/src/osgPlugins/3ds/WriterNodeVisitor.cpp (revision 10938)
+++ /OpenSceneGraph/trunk/src/osgPlugins/3ds/WriterNodeVisitor.cpp (revision 11056)
@@ -92,7 +92,8 @@
 
 /// Tests if the given string is a path supported by 3DS format (8.3, 63 chars max).
-bool is3DSpath(const std::string & s) {
+bool is3DSpath(const std::string & s, bool extendedFilePaths) {
     unsigned int len = s.length();
     if (len >= 64 || len == 0) return false;
+    if (extendedFilePaths) return true;        // Extended paths are simply those that fits the 64 bytes buffer!
 
     unsigned int tokenBegin = 0;
@@ -146,5 +147,5 @@
           triangle.t3 = i3;
           triangle.material = _material;
-          _listTriangles.push_back(std::make_pair(triangle, _drawable_n));
+          _listTriangles.push_back(std::pair<Triangle, unsigned int>(triangle, _drawable_n));
       }
       virtual void begin(GLenum mode)
@@ -335,5 +336,5 @@
         //break;
     default:
-        osg::notify(osg::WARN) << "WriterNodeVisitor :: can't handle mode " << mode << std::endl;
+        osg::notify(osg::WARN) << "3DS WriterNodeVisitor: can't handle mode " << mode << std::endl;
         break;
     }
@@ -400,33 +401,52 @@
 
 
-std::string
-getPathRelative(const std::string & srcBad,
-                const std::string & dstBad)
-{
-    if(srcBad.empty())
-        return osgDB::getSimpleFileName(dstBad);
-    const std::string & src = osgDB::convertFileNameToNativeStyle(srcBad);
-    const std::string & dst = osgDB::convertFileNameToNativeStyle(dstBad);
-    std::string::const_iterator itDst = dst.begin();
-    std::string::const_iterator itSrc = src.begin();
-
-    std::string result = "";
-
-    while(itDst != dst.end())
-    {
-        if (itSrc != src.end() && *itDst == *itSrc)
-            ++itSrc;
-        else if (!result.empty() || *itDst != '\\')  
-            result += *itDst;
-        ++itDst;
-    }
-    if (itSrc != src.end())
-        result = osgDB::getSimpleFileName(dst);
-    return result;
+// If 'to' is in a subdirectory of 'from' then this function returns the
+// subpath. Otherwise it just returns the file name.
+// (Same as in FBX plugin)
+std::string getPathRelative(const std::string& from/*directory*/,
+                            const std::string& to/*file path*/)
+{
+
+    std::string::size_type slash = to.find_last_of('/');
+    std::string::size_type backslash = to.find_last_of('\\');
+    if (slash == std::string::npos) 
+    {
+        if (backslash == std::string::npos) return to;
+        slash = backslash;
+    }
+    else if (backslash != std::string::npos && backslash > slash)
+    {
+        slash = backslash;
+    }
+
+    if (from.empty() || from.length() > to.length())
+        return osgDB::getSimpleFileName(to);
+
+    std::string::const_iterator itTo = to.begin();
+    for (std::string::const_iterator itFrom = from.begin();
+        itFrom != from.end(); ++itFrom, ++itTo)
+    {
+        char a = tolower(*itFrom), b = tolower(*itTo);
+        if (a == '\\') a = '/';
+        if (b == '\\') b = '/';
+        if (a != b || itTo == to.begin() + slash + 1)
+        {
+            return osgDB::getSimpleFileName(to);
+        }
+    }
+
+    while (itTo != to.end() && (*itTo == '\\' || *itTo == '/'))
+    {
+        ++itTo;
+    }
+
+    return std::string(itTo, to.end());
 }
 
 /// Converts an extension to a 3-letters long one equivalent.
-std::string convertExt(const std::string & path)
-{
+std::string convertExt(const std::string & path, bool extendedFilePaths)
+{
+    if (extendedFilePaths) return path;        // Extensions are not truncated for extended filenames
+
     std::string ext = osgDB::getFileExtensionIncludingDot(path);
     if (ext == ".tiff") ext = ".tif";
@@ -435,4 +455,35 @@
     return osgDB::getNameLessExtension(path) + ext;
 }
+
+
+WriterNodeVisitor::WriterNodeVisitor(Lib3dsFile * file3ds, const std::string & fileName, 
+                const osgDB::ReaderWriter::Options* options, 
+                const std::string & srcDirectory) :
+    osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
+    _suceedLastApply(true),
+    _srcDirectory(srcDirectory),
+    file3ds(file3ds),
+    _currentStateSet(new osg::StateSet()),
+    _lastMaterialIndex(0),
+    _lastMeshIndex(0),
+    _cur3dsNode(NULL),
+    options(options),
+    _imageCount(0),
+    _extendedFilePaths(false)
+{
+    if (!fileName.empty())
+        _directory = options->getDatabasePathList().empty() ? osgDB::getFilePath(fileName) : options->getDatabasePathList().front();
+
+    if (options) {
+        std::istringstream iss(options->getOptionString());
+        std::string opt;
+        while (iss >> opt)
+        {
+            if (opt == "extended3dsFilePaths" || opt == "extended3DSFilePaths")
+                _extendedFilePaths = true;
+        }
+    }
+}
+
 
 void WriterNodeVisitor::writeMaterials()
@@ -471,7 +522,7 @@
                     path = getPathRelative(_srcDirectory, mat.image->getFileName());
                 }
-                path = convertExt(path);
-
-                if(!is3DSpath(path)) {
+                path = convertExt(path, _extendedFilePaths);
+
+                if(!is3DSpath(path, _extendedFilePaths)) {
                     path = getUniqueName(path, "", true);
                     //path = osgDB::getSimpleFileName(path);
@@ -483,5 +534,9 @@
 
                 //if (mat.image->valid()) osgDB::writeImageFile(*(mat.image), path);
-                osgDB::writeImageFile(*(mat.image), path);
+                if(_imageSet.find(mat.image.get()) == _imageSet.end())
+                {
+                    _imageSet.insert(mat.image.get());
+                    osgDB::writeImageFile(*(mat.image), path);
+                }
                 if (mat.texture_transparency) tex.flags |= LIB3DS_TEXTURE_ALPHA_SOURCE;
                 if (mat.texture_no_tile) tex.flags |= LIB3DS_TEXTURE_NO_TILE;
@@ -498,9 +553,10 @@
 
 std::string WriterNodeVisitor::getUniqueName(const std::string& _defaultValue, const std::string & _defaultPrefix, bool nameIsPath) {
-    if (_defaultPrefix.length()>=4) throw "Default prefix is too long";            // Arbitrarily defined to 3 chars. You can modify this, but you may have to change the code so that finding a number is okay, even when changing the default prefix length.
+    static const unsigned int MAX_PREFIX_LEGNTH = 4;
+    if (_defaultPrefix.length()>MAX_PREFIX_LEGNTH) throw "Default prefix is too long";            // Arbitrarily defined to 4 chars.
 
     // Tests if default name is valid and unique
     bool defaultIs83 = is83(_defaultValue);
-    bool defaultIsValid = nameIsPath ? is3DSpath(_defaultValue) : defaultIs83;
+    bool defaultIsValid = nameIsPath ? is3DSpath(_defaultValue, _extendedFilePaths) : defaultIs83;
     if (defaultIsValid && _nameMap.find(_defaultValue) == _nameMap.end()) {
         _nameMap.insert(_defaultValue);
@@ -509,7 +565,8 @@
 
     // Handling of paths is not well done yet. Defaulting to something very simple.
-    // We should actually ensure each component is 8 chars long, and final filename is 8.3, and total is <64 chars.
+    // We should actually ensure each component is 8 chars long, and final filename is 8.3, and total is <64 chars, or simply ensure total length for extended 3DS paths.
     std::string defaultValue(nameIsPath ? osgDB::getSimpleFileName(_defaultValue) : _defaultValue);
     std::string ext(nameIsPath ? osgDB::getFileExtensionIncludingDot(_defaultValue).substr(0, std::min<unsigned int>(_defaultValue.size(), 4)) : "");        // 4 chars = dot + 3 chars
+    if (ext == ".") ext = "";
 
     std::string defaultPrefix(_defaultPrefix.empty() ? "_" : _defaultPrefix);
@@ -517,5 +574,5 @@
     unsigned int max_val = 0;
     std::string truncDefaultValue = "";
-    for (unsigned int i = 0; i < std::min<unsigned int>(defaultValue.size(), 4); ++i)
+    for (unsigned int i = 0; i < std::min<unsigned int>(defaultValue.size(), MAX_PREFIX_LEGNTH); ++i)
     {
         if (defaultValue[i] == '.')
@@ -526,14 +583,17 @@
     }
     if (truncDefaultValue.empty())
-        truncDefaultValue = defaultValue.substr(0, std::min<unsigned int>(defaultValue.size(), 4));
+        truncDefaultValue = defaultValue.substr(0, std::min<unsigned int>(defaultValue.size(), MAX_PREFIX_LEGNTH));
+    assert(truncDefaultValue.size() <= MAX_PREFIX_LEGNTH);
     std::map<std::string, unsigned int>::iterator pairPrefix;
+
+    // TODO - Handle the case of extended 3DS paths and allow more than 8 chars
     defaultIs83 = is83(truncDefaultValue);
     if (defaultIs83)
     {
-        max_val = static_cast<unsigned int>(pow(10., 8. - truncDefaultValue.length() - 1)) -1;        // defaultPrefix.length()-1 because we add an underscore ("_")
+        max_val = static_cast<unsigned int>(pow(10., 8. - truncDefaultValue.length())) -1;
         pairPrefix = _mapPrefix.find(truncDefaultValue);
     }  
 
-    if (defaultIs83 && (_mapPrefix.end() == pairPrefix || pairPrefix->second <= max_val))
+    if (defaultIs83 && (pairPrefix == _mapPrefix.end() || pairPrefix->second <= max_val))
     {
         defaultPrefix = truncDefaultValue;
@@ -541,24 +601,22 @@
     else
     {
-        max_val = static_cast<unsigned int>(pow(10., 8. - defaultPrefix.length() - 1)) -  1;        // defaultPrefix.length()-1 because we add an underscore ("_")
+        max_val = static_cast<unsigned int>(pow(10., 8. - defaultPrefix.length())) -1;
         pairPrefix = _mapPrefix.find(defaultPrefix);
     }
 
     unsigned int searchStart = 0;
-    if (pairPrefix != _mapPrefix.end())
+    if (pairPrefix != _mapPrefix.end()) {
         searchStart = pairPrefix->second;
+    }
 
     for(unsigned int i = searchStart; i <= max_val; ++i) {
         std::stringstream ss;
-        ss << defaultPrefix << "_" << i;
+        ss << defaultPrefix << i;
         const std::string & res = ss.str();
         if (_nameMap.find(res) == _nameMap.end()) {
-            if (pairPrefix != _mapPrefix.end())
-            {
+            if (pairPrefix != _mapPrefix.end()) {
                 pairPrefix->second = i + 1;
-            }
-            else
-            {
-                _mapPrefix.insert(std::make_pair(defaultPrefix, i + 1));
+            } else {
+                _mapPrefix.insert(std::pair<std::string, unsigned int>(defaultPrefix, i + 1));
             }
             _nameMap.insert(res);
@@ -566,5 +624,10 @@
         }
     }
-    if (defaultPrefix == "_") _lastGeneratedNumberedName = max_val;
+
+    // Failed finding a name
+    // Try with a shorter prefix if possible
+    if (defaultPrefix.length()>1) return getUniqueName(_defaultValue, defaultPrefix.substr(0, defaultPrefix.length()-1), nameIsPath);
+    // Try with default prefix if not arleady done
+    if (defaultPrefix != std::string("_")) return getUniqueName(_defaultValue, "_", nameIsPath);
     throw "No more names available! Is default prefix too long?";
 }
@@ -603,8 +666,8 @@
                                                 unsigned int drawable_n)
 {
-    MapIndices::iterator itIndex = index_vert.find(std::make_pair(index, drawable_n));
+    MapIndices::iterator itIndex = index_vert.find(std::pair<unsigned int, unsigned int>(index, drawable_n));
     if (itIndex == index_vert.end()) {
         unsigned int indexMesh = index_vert.size();
-        index_vert.insert(std::make_pair(std::make_pair(index, drawable_n), indexMesh));
+        index_vert.insert(std::make_pair(std::pair<unsigned int, unsigned int>(index, drawable_n), indexMesh));
         return indexMesh;
     }
@@ -693,5 +756,5 @@
        ((nbVertices) >= MAX_VERTICES-2))
     {
-        osg::notify(osg::ALWAYS) << "Sorting elements..." << std::endl;
+        osg::notify(osg::INFO) << "Sorting elements..." << std::endl;
         WriterCompareTriangle cmp(geo, nbVertices);
         std::sort(listTriangles.begin(), listTriangles.end(), cmp);
Index: /OpenSceneGraph/trunk/src/osgPlugins/3ds/WriterNodeVisitor.h
===================================================================
--- /OpenSceneGraph/trunk/src/osgPlugins/3ds/WriterNodeVisitor.h (revision 10945)
+++ /OpenSceneGraph/trunk/src/osgPlugins/3ds/WriterNodeVisitor.h (revision 11056)
@@ -42,4 +42,5 @@
 #include "lib3ds/lib3ds.h"
 #include "WriterCompareTriangle.h"
+#include <set>
 
 void copyOsgMatrixToLib3dsMatrix(Lib3dsMatrix lib3ds_matrix, const osg::Matrix& osg_matrix);
@@ -50,5 +51,4 @@
 class WriterNodeVisitor: public osg::NodeVisitor
 {
-
     public:
         static const unsigned int MAX_VERTICES = 65000;
@@ -57,21 +57,5 @@
         WriterNodeVisitor(Lib3dsFile * file3ds, const std::string & fileName, 
                         const osgDB::ReaderWriter::Options* options, 
-                        const std::string & srcDirectory) :
-            osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
-            _suceedLastApply(true),
-            _srcDirectory(srcDirectory),
-            file3ds(file3ds),
-            _currentStateSet(new osg::StateSet()),
-            _lastGeneratedNumberedName(0),
-            _lastMaterialIndex(0),
-            _lastMeshIndex(0),
-            _cur3dsNode(NULL),
-            options(options),
-            _imageCount(0)
-        {
-            //supportsOption("flipTexture", "flip texture upside-down");
-            if (!fileName.empty())
-                _directory = options->getDatabasePathList().empty() ? osgDB::getFilePath(fileName) : options->getDatabasePathList().front();
-        }
+                        const std::string & srcDirectory);
 
         bool        suceedLastApply() const;
@@ -216,8 +200,7 @@
         StateSetStack                       _stateSetStack;
         osg::ref_ptr<osg::StateSet>         _currentStateSet;
-        std::map<std::string, unsigned int> _mapPrefix;
+        std::map<std::string, unsigned int> _mapPrefix;            ///< List of next number to use in unique name generation, for each prefix
         std::set<std::string>                _nameMap;
         MaterialMap                         _materialMap;
-        unsigned int                        _lastGeneratedNumberedName;
         unsigned int                        _lastMaterialIndex;
         unsigned int                        _lastMeshIndex;
@@ -225,4 +208,6 @@
         const osgDB::ReaderWriter::Options* options;
         unsigned int                        _imageCount;
+        bool                                _extendedFilePaths;
+        std::set<osg::Image *>              _imageSet;
 };
 
Index: /OpenSceneGraph/trunk/src/osgPlugins/3ds/ReaderWriter3DS.cpp
===================================================================
--- /OpenSceneGraph/trunk/src/osgPlugins/3ds/ReaderWriter3DS.cpp (revision 10942)
+++ /OpenSceneGraph/trunk/src/osgPlugins/3ds/ReaderWriter3DS.cpp (revision 11056)
@@ -1,3 +1,2 @@
-#define ENABLE_3DS_WRITER      1            // Enables the 3DS writer (the define should be removed when the writer will be stable and tested enough)
 
 #include <osg/Notify>
@@ -21,7 +20,5 @@
 #include <osg/NodeVisitor>
 
-#ifdef ENABLE_3DS_WRITER
-    #include "WriterNodeVisitor.h"
-#endif
+#include "WriterNodeVisitor.h"
 #include "lib3ds/lib3ds.h"
 #include <stdlib.h>
@@ -172,15 +169,14 @@
     virtual ReadResult readNode(const std::string& file, const osgDB::ReaderWriter::Options* options) const;
     virtual ReadResult readNode(std::istream& fin, const Options* options) const;
-#if ENABLE_3DS_WRITER
+    virtual ReadResult doReadNode(std::istream& fin, const Options* options, const std::string & fileNamelib3ds) const;        ///< Subfunction of readNode()s functions.
+
     virtual WriteResult writeNode(const osg::Node& /*node*/,const std::string& /*fileName*/,const Options* =NULL) const;
     virtual WriteResult writeNode(const osg::Node& /*node*/,std::ostream& /*fout*/,const Options* =NULL) const;
-#endif
+    virtual WriteResult doWriteNode(const osg::Node& /*node*/,std::ostream& /*fout*/,const Options*, const std::string & fileNamelib3ds) const;
 
 protected:
     ReadResult constructFrom3dsFile(Lib3dsFile *f,const std::string& filename, const Options* options) const;
 
-#if ENABLE_3DS_WRITER
     bool createFileObject(const osg::Node& node, Lib3dsFile * file3ds,const std::string& fileName, const osgDB::ReaderWriter::Options* options) const;
-#endif
 
     class ReaderObject
@@ -221,5 +217,10 @@
 {
     supportsExtension("3ds","3D Studio model format");
-    supportsOption("OutputTextureFiles","Write out the texture images to file");
+    //supportsOption("OutputTextureFiles","Write out the texture images to file");
+    //supportsOption("flipTexture", "flip texture upside-down");
+    supportsOption("extended3dsFilePaths", "Keeps long texture filenames (not 8.3) when exporting 3DS, but can lead to compatibility problems.");
+    supportsOption("noMatrixTransforms", "Set the plugin to apply matrices into the mesh vertices (\"old behaviour\") instead of restoring them (\"new behaviour\"). You may use this option to avoid a few rounding errors.");
+    supportsOption("checkForEspilonIdentityMatrices", "If not set, then consider \"almost identity\" matrices to be identity ones (in case of rounding errors).");
+    supportsOption("restoreMatrixTransformsNoMeshes", "Makes an exception to the behaviour when 'noMatrixTransforms' is not set for mesh instances. When a mesh instance has a transform on it, the reader creates a MatrixTransform above the Geode. If you don't want the hierarchy to be modified, then you can use this option to merge the transform into vertices.");
     setByteOrder();
 
@@ -253,14 +254,16 @@
     restoreMatrixTransformsNoMeshes(false)
 {
-    std::istringstream iss(options->getOptionString());
-    std::string opt; 
-    while (iss >> opt) 
-    {
-        if (opt == "noMatrixTransforms")
-            noMatrixTransforms = true;
-        if (opt == "checkForEspilonIdentityMatrices")
-            checkForEspilonIdentityMatrices = true;
-        if (opt == "restoreMatrixTransformsNoMeshes")
-            restoreMatrixTransformsNoMeshes = true;
+    if (options) {
+        std::istringstream iss(options->getOptionString());
+        std::string opt; 
+        while (iss >> opt) 
+        {
+            if (opt == "noMatrixTransforms")
+                noMatrixTransforms = true;
+            if (opt == "checkForEspilonIdentityMatrices")
+                checkForEspilonIdentityMatrices = true;
+            if (opt == "restoreMatrixTransformsNoMeshes")
+                restoreMatrixTransformsNoMeshes = true;
+        }
     }
 }
@@ -557,5 +560,4 @@
 }
 
-#if ENABLE_3DS_WRITER
 static long fileo_seek_func(void *self, long offset, Lib3dsIoSeek origin) {
     std::ostream *f = reinterpret_cast<std::ostream*>(self);
@@ -567,5 +569,4 @@
     return f->fail() ? -1 : 0;
 }
-#endif
 
 static long filei_tell_func(void *self) {
@@ -574,10 +575,8 @@
 }
 
-#if ENABLE_3DS_WRITER
 static long fileo_tell_func(void *self) {
     std::ostream *f = reinterpret_cast<std::ostream*>(self);
     return f->tellp();
 }
-#endif
 
 
@@ -588,5 +587,4 @@
 }
 
-#if ENABLE_3DS_WRITER
 static size_t fileo_write_func(void *self, const void *buffer, size_t size) {
     std::ostream *f = reinterpret_cast<std::ostream*>(self);
@@ -594,11 +592,11 @@
     return f->fail() ? 0 : size;
 }
-#endif
 
 static void fileio_log_func(void *self, Lib3dsLogLevel level, int indent, const char *msg)
 {
     osg::NotifySeverity l = osg::INFO;
-    if (level == LIB3DS_LOG_ERROR) l = osg::FATAL;
-    else if (level == LIB3DS_LOG_WARN) l = osg::WARN;
+    // Intentionally NOT mapping 3DS levels with OSG levels
+    if (level == LIB3DS_LOG_ERROR) l = osg::WARN;
+    else if (level == LIB3DS_LOG_WARN) l = osg::NOTICE;
     else if (level == LIB3DS_LOG_INFO) l = osg::INFO;
     else if (level == LIB3DS_LOG_DEBUG) l = osg::DEBUG_INFO;
@@ -609,7 +607,5 @@
 osgDB::ReaderWriter::ReadResult ReaderWriter3DS::readNode(std::istream& fin,  const osgDB::ReaderWriter::Options* options) const
 {
-    osgDB::ReaderWriter::ReadResult result = ReadResult::FILE_NOT_HANDLED;
-
-    std::string optFileName = "";
+    std::string optFileName;
     if (options)
     {
@@ -617,4 +613,13 @@
         if (optFileName.empty()) optFileName = options->getPluginStringData("filename");
     }
+    return doReadNode(fin, options, optFileName);
+}
+
+osgDB::ReaderWriter::ReadResult ReaderWriter3DS::doReadNode(std::istream& fin,  const osgDB::ReaderWriter::Options* options, const std::string & fileNamelib3ds) const
+{
+    osg::ref_ptr<Options> local_opt = options ? static_cast<Options*>(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options;
+    local_opt->getDatabasePathList().push_front(osgDB::getFilePath(fileNamelib3ds));
+
+    osgDB::ReaderWriter::ReadResult result = ReadResult::FILE_NOT_HANDLED;
 
     // Prepare io structure to tell how to read the stream
@@ -630,5 +635,5 @@
     if (lib3ds_file_read(file3ds, &io) != 0)
     {
-        result = constructFrom3dsFile(file3ds,optFileName,options);
+        result = constructFrom3dsFile(file3ds,fileNamelib3ds,options);
         lib3ds_file_free(file3ds);
     }
@@ -639,6 +644,4 @@
 osgDB::ReaderWriter::ReadResult ReaderWriter3DS::readNode(const std::string& file, const osgDB::ReaderWriter::Options* options) const
 {
-    osgDB::ReaderWriter::ReadResult result = ReadResult::FILE_NOT_HANDLED;
-
     std::string ext = osgDB::getLowerCaseFileExtension(file);
     if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
@@ -647,5 +650,13 @@
     if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
 
-    Lib3dsFile *f = lib3ds_file_open(fileName.c_str() /*,options*/);
+    // Do not use the lib3ds_file_open() as:
+    //   1. It relies on FILE* instead of iostreams (less safe)
+    //   2. It doesn't allow us to set a custom log output
+    std::ifstream fin(file.c_str(), std::ios_base::in | std::ios_base::binary);
+    if (!fin.good()) return ReadResult::ERROR_IN_READING_FILE;
+    return doReadNode(fin, options, fileName);
+/*
+    osgDB::ReaderWriter::ReadResult result = ReadResult::FILE_NOT_HANDLED;
+    Lib3dsFile *f = lib3ds_file_open(fileName.c_str());        // ,options
 
     if (f)
@@ -659,4 +670,5 @@
 
     return result;
+*/
 }
 
@@ -1059,12 +1071,13 @@
 
 
-
-#if ENABLE_3DS_WRITER
 osgDB::ReaderWriter::WriteResult ReaderWriter3DS::writeNode(const osg::Node& node,const std::string& fileName,const Options* options) const {
     std::string ext = osgDB::getLowerCaseFileExtension(fileName);
     if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED;
 
-    //osg::notify(osg::WARN) << "!!WARNING!! 3DS write support is incomplete" << std::endl;
-
+    osgDB::makeDirectoryForFile(fileName.c_str());
+    std::ofstream fout(fileName.c_str(), std::ios_base::out | std::ios_base::binary);
+    if (!fout.good()) return WriteResult::ERROR_IN_WRITING_FILE;
+    return doWriteNode(node, fout, options, fileName);
+/*
     bool ok = true;
     Lib3dsFile * file3ds = lib3ds_file_new();
@@ -1075,5 +1088,5 @@
         local_opt->getDatabasePathList().push_front(osgDB::getFilePath(fileName));
 
-        if (!createFileObject(node, file3ds, fileName, local_opt.get())) ok = false;
+        if (!createFileObject(node, file3ds, fileName, local_opt)) ok = false;
         if (ok && !lib3ds_file_save(file3ds, fileName.c_str())) ok = false;
     } catch (...) {
@@ -1084,5 +1097,5 @@
 
     return ok ? WriteResult(WriteResult::FILE_SAVED) : WriteResult(WriteResult::ERROR_IN_WRITING_FILE);
-    //return ok ? WriteResult(WriteResult::FILE_SAVED) : WriteResult(WriteResult::FILE_NOT_HANDLED);
+*/
 }
 
@@ -1090,9 +1103,15 @@
 osgDB::ReaderWriter::WriteResult ReaderWriter3DS::writeNode(const osg::Node& node,std::ostream& fout,const Options* options) const {
     //osg::notify(osg::WARN) << "!!WARNING!! 3DS write support is incomplete" << std::endl;
-    std::string optFileName = "";
-    if (options)
-    {
+    std::string optFileName;
+    if (options) {
         optFileName = options->getPluginStringData("STREAM_FILENAME");
     }
+
+    return doWriteNode(node, fout, options, optFileName);
+}
+
+osgDB::ReaderWriter::WriteResult ReaderWriter3DS::doWriteNode(const osg::Node& node,std::ostream& fout, const Options* options, const std::string & fileNamelib3ds) const {
+    osg::ref_ptr<Options> local_opt = options ? static_cast<Options*>(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options;
+    local_opt->getDatabasePathList().push_front(osgDB::getFilePath(fileNamelib3ds));
 
     Lib3dsIo io;
@@ -1105,10 +1124,9 @@
     
     Lib3dsFile * file3ds = lib3ds_file_new();
+    if (!file3ds) return WriteResult(WriteResult::ERROR_IN_WRITING_FILE);
+
     bool ok = true;
     try {
-        osg::ref_ptr<Options> local_opt = options ? static_cast<Options*>(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options;
-        local_opt->getDatabasePathList().push_front(osgDB::getFilePath(optFileName));
-
-        if (!createFileObject(node, file3ds, optFileName, local_opt.get())) ok = false;
+        if (!createFileObject(node, file3ds, fileNamelib3ds, local_opt.get())) ok = false;
         if (ok && !lib3ds_file_write(file3ds, &io)) ok = false;
         
@@ -1123,27 +1141,7 @@
 }
 
-const std::string getParent(const std::string & pathBad)
-{
-    const std::string & path = osgDB::convertFileNameToNativeStyle(pathBad);
-
-    std::string parent = "";
-    std::string tmp = "";
-    for(std::string::const_iterator itPath = path.begin();; ++itPath)
-    {
-        if (!parent.empty())
-            parent += '\\';
-        parent += tmp;
-        tmp.clear();
-        for(;itPath != path.end() && *itPath != '\\'; ++itPath)
-            tmp += *itPath;
-        if (itPath == path.end())
-            break;
-    }
-    return parent;
-}
-
 bool ReaderWriter3DS::createFileObject(const osg::Node& node, Lib3dsFile * file3ds,const std::string& fileName, const osgDB::ReaderWriter::Options* options) const {
-    WriterNodeVisitor w(file3ds, fileName, options, getParent(node.getName()));
-    const_cast<osg::Node &>(node).accept(w);                // TODO Remove that ugly const_cast<>. Any idea?
+    WriterNodeVisitor w(file3ds, fileName, options, osgDB::getFilePath(node.getName()));
+    const_cast<osg::Node &>(node).accept(w);                // Ugly const_cast<> for visitor...
     if (!w.suceedLastApply())
         return false;
@@ -1151,3 +1149,3 @@
     return true;    //w.good();
 }
-#endif    // ENABLE_3DS_WRITER
+
Index: /OpenSceneGraph/trunk/src/osgPlugins/3ds/WriterCompareTriangle.cpp
===================================================================
--- /OpenSceneGraph/trunk/src/osgPlugins/3ds/WriterCompareTriangle.cpp (revision 10853)
+++ /OpenSceneGraph/trunk/src/osgPlugins/3ds/WriterCompareTriangle.cpp (revision 11056)
@@ -33,8 +33,8 @@
 {
     static const unsigned int min = 1;
-    static const unsigned int max = 5;		// Number of blocks used to divide the scene (arbitrary but seems ok)
-	nbVerticesX = osg::clampBetween<unsigned int>(nbVerticesX, min, max);
-	nbVerticesY = osg::clampBetween<unsigned int>(nbVerticesY, min, max);
-	nbVerticesZ = osg::clampBetween<unsigned int>(nbVerticesZ, min, max);
+    static const unsigned int max = 5;        // Number of blocks used to divide the scene (arbitrary but seems ok)
+    nbVerticesX = osg::clampBetween<unsigned int>(nbVerticesX, min, max);
+    nbVerticesY = osg::clampBetween<unsigned int>(nbVerticesY, min, max);
+    nbVerticesZ = osg::clampBetween<unsigned int>(nbVerticesZ, min, max);
 }
 
@@ -43,6 +43,6 @@
     osg::BoundingBox::vec_type length = sceneBox._max - sceneBox._min;
 
-    static const float k = 1.3f;		// Arbitrary constant multiplier for density computation ("simulates" non-uniform point distributions)
-	// Computes "density" of points, and thus the number of blocks to divide the mesh into
+    static const float k = 1.3f;        // Arbitrary constant multiplier for density computation ("simulates" non-uniform point distributions)
+    // Computes "density" of points, and thus the number of blocks to divide the mesh into
     unsigned int nbVerticesX = static_cast<unsigned int>( (nbVertices * k) / (length.z() * length.y()) );
     unsigned int nbVerticesY = static_cast<unsigned int>( (nbVertices * k) / (length.z() * length.x()) );
@@ -132,4 +132,4 @@
 
 int WriterCompareTriangle::inWhichBox(const osg::BoundingBox::vec_type & point) const {
-	return inWhichBox(point.x(), point.y(), point.z());
+    return inWhichBox(point.x(), point.y(), point.z());
 }
