Changeset 11056

Show
Ignore:
Timestamp:
02/11/10 12:56:43 (5 years ago)
Author:
robert
Message:

From Sukender, "- Added support for extended filenames (=not 8.3) for images: reads without crashing, optionnally write extended filenames (correctly truncate names if option is OFF). Write option is OFF by default.
- Improved identifiers generation in duplicate name handling (was limited to 1000 name collisions, which can be very short for some usages).
- Set all read/write operations use a custom log function that will redirect lib3DS log to osg::notify() (was only used for streams)
- Removed custom code (now uses osgDB::getFilePath())
- Added missing supportsOption() calls
- Cleaned a few minor things"

Location:
OpenSceneGraph/trunk/src/osgPlugins/3ds
Files:
4 modified

Legend:

Unmodified
Added
Removed
  • OpenSceneGraph/trunk/src/osgPlugins/3ds/ReaderWriter3DS.cpp

    r10942 r11056  
    1 #define ENABLE_3DS_WRITER      1            // Enables the 3DS writer (the define should be removed when the writer will be stable and tested enough) 
    21 
    32#include <osg/Notify> 
     
    2120#include <osg/NodeVisitor> 
    2221 
    23 #ifdef ENABLE_3DS_WRITER 
    24     #include "WriterNodeVisitor.h" 
    25 #endif 
     22#include "WriterNodeVisitor.h" 
    2623#include "lib3ds/lib3ds.h" 
    2724#include <stdlib.h> 
     
    172169    virtual ReadResult readNode(const std::string& file, const osgDB::ReaderWriter::Options* options) const; 
    173170    virtual ReadResult readNode(std::istream& fin, const Options* options) const; 
    174 #if ENABLE_3DS_WRITER 
     171    virtual ReadResult doReadNode(std::istream& fin, const Options* options, const std::string & fileNamelib3ds) const;        ///< Subfunction of readNode()s functions. 
     172 
    175173    virtual WriteResult writeNode(const osg::Node& /*node*/,const std::string& /*fileName*/,const Options* =NULL) const; 
    176174    virtual WriteResult writeNode(const osg::Node& /*node*/,std::ostream& /*fout*/,const Options* =NULL) const; 
    177 #endif 
     175    virtual WriteResult doWriteNode(const osg::Node& /*node*/,std::ostream& /*fout*/,const Options*, const std::string & fileNamelib3ds) const; 
    178176 
    179177protected: 
    180178    ReadResult constructFrom3dsFile(Lib3dsFile *f,const std::string& filename, const Options* options) const; 
    181179 
    182 #if ENABLE_3DS_WRITER 
    183180    bool createFileObject(const osg::Node& node, Lib3dsFile * file3ds,const std::string& fileName, const osgDB::ReaderWriter::Options* options) const; 
    184 #endif 
    185181 
    186182    class ReaderObject 
     
    221217{ 
    222218    supportsExtension("3ds","3D Studio model format"); 
    223     supportsOption("OutputTextureFiles","Write out the texture images to file"); 
     219    //supportsOption("OutputTextureFiles","Write out the texture images to file"); 
     220    //supportsOption("flipTexture", "flip texture upside-down"); 
     221    supportsOption("extended3dsFilePaths", "Keeps long texture filenames (not 8.3) when exporting 3DS, but can lead to compatibility problems."); 
     222    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."); 
     223    supportsOption("checkForEspilonIdentityMatrices", "If not set, then consider \"almost identity\" matrices to be identity ones (in case of rounding errors)."); 
     224    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."); 
    224225    setByteOrder(); 
    225226 
     
    253254    restoreMatrixTransformsNoMeshes(false) 
    254255{ 
    255     std::istringstream iss(options->getOptionString()); 
    256     std::string opt;  
    257     while (iss >> opt)  
    258     { 
    259         if (opt == "noMatrixTransforms") 
    260             noMatrixTransforms = true; 
    261         if (opt == "checkForEspilonIdentityMatrices") 
    262             checkForEspilonIdentityMatrices = true; 
    263         if (opt == "restoreMatrixTransformsNoMeshes") 
    264             restoreMatrixTransformsNoMeshes = true; 
     256    if (options) { 
     257        std::istringstream iss(options->getOptionString()); 
     258        std::string opt;  
     259        while (iss >> opt)  
     260        { 
     261            if (opt == "noMatrixTransforms") 
     262                noMatrixTransforms = true; 
     263            if (opt == "checkForEspilonIdentityMatrices") 
     264                checkForEspilonIdentityMatrices = true; 
     265            if (opt == "restoreMatrixTransformsNoMeshes") 
     266                restoreMatrixTransformsNoMeshes = true; 
     267        } 
    265268    } 
    266269} 
     
    557560} 
    558561 
    559 #if ENABLE_3DS_WRITER 
    560562static long fileo_seek_func(void *self, long offset, Lib3dsIoSeek origin) { 
    561563    std::ostream *f = reinterpret_cast<std::ostream*>(self); 
     
    567569    return f->fail() ? -1 : 0; 
    568570} 
    569 #endif 
    570571 
    571572static long filei_tell_func(void *self) { 
     
    574575} 
    575576 
    576 #if ENABLE_3DS_WRITER 
    577577static long fileo_tell_func(void *self) { 
    578578    std::ostream *f = reinterpret_cast<std::ostream*>(self); 
    579579    return f->tellp(); 
    580580} 
    581 #endif 
    582581 
    583582 
     
    588587} 
    589588 
    590 #if ENABLE_3DS_WRITER 
    591589static size_t fileo_write_func(void *self, const void *buffer, size_t size) { 
    592590    std::ostream *f = reinterpret_cast<std::ostream*>(self); 
     
    594592    return f->fail() ? 0 : size; 
    595593} 
    596 #endif 
    597594 
    598595static void fileio_log_func(void *self, Lib3dsLogLevel level, int indent, const char *msg) 
    599596{ 
    600597    osg::NotifySeverity l = osg::INFO; 
    601     if (level == LIB3DS_LOG_ERROR) l = osg::FATAL; 
    602     else if (level == LIB3DS_LOG_WARN) l = osg::WARN; 
     598    // Intentionally NOT mapping 3DS levels with OSG levels 
     599    if (level == LIB3DS_LOG_ERROR) l = osg::WARN; 
     600    else if (level == LIB3DS_LOG_WARN) l = osg::NOTICE; 
    603601    else if (level == LIB3DS_LOG_INFO) l = osg::INFO; 
    604602    else if (level == LIB3DS_LOG_DEBUG) l = osg::DEBUG_INFO; 
     
    609607osgDB::ReaderWriter::ReadResult ReaderWriter3DS::readNode(std::istream& fin,  const osgDB::ReaderWriter::Options* options) const 
    610608{ 
    611     osgDB::ReaderWriter::ReadResult result = ReadResult::FILE_NOT_HANDLED; 
    612  
    613     std::string optFileName = ""; 
     609    std::string optFileName; 
    614610    if (options) 
    615611    { 
     
    617613        if (optFileName.empty()) optFileName = options->getPluginStringData("filename"); 
    618614    } 
     615    return doReadNode(fin, options, optFileName); 
     616} 
     617 
     618osgDB::ReaderWriter::ReadResult ReaderWriter3DS::doReadNode(std::istream& fin,  const osgDB::ReaderWriter::Options* options, const std::string & fileNamelib3ds) const 
     619{ 
     620    osg::ref_ptr<Options> local_opt = options ? static_cast<Options*>(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options; 
     621    local_opt->getDatabasePathList().push_front(osgDB::getFilePath(fileNamelib3ds)); 
     622 
     623    osgDB::ReaderWriter::ReadResult result = ReadResult::FILE_NOT_HANDLED; 
    619624 
    620625    // Prepare io structure to tell how to read the stream 
     
    630635    if (lib3ds_file_read(file3ds, &io) != 0) 
    631636    { 
    632         result = constructFrom3dsFile(file3ds,optFileName,options); 
     637        result = constructFrom3dsFile(file3ds,fileNamelib3ds,options); 
    633638        lib3ds_file_free(file3ds); 
    634639    } 
     
    639644osgDB::ReaderWriter::ReadResult ReaderWriter3DS::readNode(const std::string& file, const osgDB::ReaderWriter::Options* options) const 
    640645{ 
    641     osgDB::ReaderWriter::ReadResult result = ReadResult::FILE_NOT_HANDLED; 
    642  
    643646    std::string ext = osgDB::getLowerCaseFileExtension(file); 
    644647    if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED; 
     
    647650    if (fileName.empty()) return ReadResult::FILE_NOT_FOUND; 
    648651 
    649     Lib3dsFile *f = lib3ds_file_open(fileName.c_str() /*,options*/); 
     652    // Do not use the lib3ds_file_open() as: 
     653    //   1. It relies on FILE* instead of iostreams (less safe) 
     654    //   2. It doesn't allow us to set a custom log output 
     655    std::ifstream fin(file.c_str(), std::ios_base::in | std::ios_base::binary); 
     656    if (!fin.good()) return ReadResult::ERROR_IN_READING_FILE; 
     657    return doReadNode(fin, options, fileName); 
     658/* 
     659    osgDB::ReaderWriter::ReadResult result = ReadResult::FILE_NOT_HANDLED; 
     660    Lib3dsFile *f = lib3ds_file_open(fileName.c_str());        // ,options 
    650661 
    651662    if (f) 
     
    659670 
    660671    return result; 
     672*/ 
    661673} 
    662674 
     
    10591071 
    10601072 
    1061  
    1062 #if ENABLE_3DS_WRITER 
    10631073osgDB::ReaderWriter::WriteResult ReaderWriter3DS::writeNode(const osg::Node& node,const std::string& fileName,const Options* options) const { 
    10641074    std::string ext = osgDB::getLowerCaseFileExtension(fileName); 
    10651075    if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED; 
    10661076 
    1067     //osg::notify(osg::WARN) << "!!WARNING!! 3DS write support is incomplete" << std::endl; 
    1068  
     1077    osgDB::makeDirectoryForFile(fileName.c_str()); 
     1078    std::ofstream fout(fileName.c_str(), std::ios_base::out | std::ios_base::binary); 
     1079    if (!fout.good()) return WriteResult::ERROR_IN_WRITING_FILE; 
     1080    return doWriteNode(node, fout, options, fileName); 
     1081/* 
    10691082    bool ok = true; 
    10701083    Lib3dsFile * file3ds = lib3ds_file_new(); 
     
    10751088        local_opt->getDatabasePathList().push_front(osgDB::getFilePath(fileName)); 
    10761089 
    1077         if (!createFileObject(node, file3ds, fileName, local_opt.get())) ok = false; 
     1090        if (!createFileObject(node, file3ds, fileName, local_opt)) ok = false; 
    10781091        if (ok && !lib3ds_file_save(file3ds, fileName.c_str())) ok = false; 
    10791092    } catch (...) { 
     
    10841097 
    10851098    return ok ? WriteResult(WriteResult::FILE_SAVED) : WriteResult(WriteResult::ERROR_IN_WRITING_FILE); 
    1086     //return ok ? WriteResult(WriteResult::FILE_SAVED) : WriteResult(WriteResult::FILE_NOT_HANDLED); 
     1099*/ 
    10871100} 
    10881101 
     
    10901103osgDB::ReaderWriter::WriteResult ReaderWriter3DS::writeNode(const osg::Node& node,std::ostream& fout,const Options* options) const { 
    10911104    //osg::notify(osg::WARN) << "!!WARNING!! 3DS write support is incomplete" << std::endl; 
    1092     std::string optFileName = ""; 
    1093     if (options) 
    1094     { 
     1105    std::string optFileName; 
     1106    if (options) { 
    10951107        optFileName = options->getPluginStringData("STREAM_FILENAME"); 
    10961108    } 
     1109 
     1110    return doWriteNode(node, fout, options, optFileName); 
     1111} 
     1112 
     1113osgDB::ReaderWriter::WriteResult ReaderWriter3DS::doWriteNode(const osg::Node& node,std::ostream& fout, const Options* options, const std::string & fileNamelib3ds) const { 
     1114    osg::ref_ptr<Options> local_opt = options ? static_cast<Options*>(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options; 
     1115    local_opt->getDatabasePathList().push_front(osgDB::getFilePath(fileNamelib3ds)); 
    10971116 
    10981117    Lib3dsIo io; 
     
    11051124     
    11061125    Lib3dsFile * file3ds = lib3ds_file_new(); 
     1126    if (!file3ds) return WriteResult(WriteResult::ERROR_IN_WRITING_FILE); 
     1127 
    11071128    bool ok = true; 
    11081129    try { 
    1109         osg::ref_ptr<Options> local_opt = options ? static_cast<Options*>(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options; 
    1110         local_opt->getDatabasePathList().push_front(osgDB::getFilePath(optFileName)); 
    1111  
    1112         if (!createFileObject(node, file3ds, optFileName, local_opt.get())) ok = false; 
     1130        if (!createFileObject(node, file3ds, fileNamelib3ds, local_opt.get())) ok = false; 
    11131131        if (ok && !lib3ds_file_write(file3ds, &io)) ok = false; 
    11141132         
     
    11231141} 
    11241142 
    1125 const std::string getParent(const std::string & pathBad) 
    1126 { 
    1127     const std::string & path = osgDB::convertFileNameToNativeStyle(pathBad); 
    1128  
    1129     std::string parent = ""; 
    1130     std::string tmp = ""; 
    1131     for(std::string::const_iterator itPath = path.begin();; ++itPath) 
    1132     { 
    1133         if (!parent.empty()) 
    1134             parent += '\\'; 
    1135         parent += tmp; 
    1136         tmp.clear(); 
    1137         for(;itPath != path.end() && *itPath != '\\'; ++itPath) 
    1138             tmp += *itPath; 
    1139         if (itPath == path.end()) 
    1140             break; 
    1141     } 
    1142     return parent; 
    1143 } 
    1144  
    11451143bool ReaderWriter3DS::createFileObject(const osg::Node& node, Lib3dsFile * file3ds,const std::string& fileName, const osgDB::ReaderWriter::Options* options) const { 
    1146     WriterNodeVisitor w(file3ds, fileName, options, getParent(node.getName())); 
    1147     const_cast<osg::Node &>(node).accept(w);                // TODO Remove that ugly const_cast<>. Any idea? 
     1144    WriterNodeVisitor w(file3ds, fileName, options, osgDB::getFilePath(node.getName())); 
     1145    const_cast<osg::Node &>(node).accept(w);                // Ugly const_cast<> for visitor... 
    11481146    if (!w.suceedLastApply()) 
    11491147        return false; 
     
    11511149    return true;    //w.good(); 
    11521150} 
    1153 #endif    // ENABLE_3DS_WRITER 
     1151 
  • OpenSceneGraph/trunk/src/osgPlugins/3ds/WriterCompareTriangle.cpp

    r10853 r11056  
    3333{ 
    3434    static const unsigned int min = 1; 
    35     static const unsigned int max = 5;          // Number of blocks used to divide the scene (arbitrary but seems ok) 
    36         nbVerticesX = osg::clampBetween<unsigned int>(nbVerticesX, min, max); 
    37         nbVerticesY = osg::clampBetween<unsigned int>(nbVerticesY, min, max); 
    38         nbVerticesZ = osg::clampBetween<unsigned int>(nbVerticesZ, min, max); 
     35    static const unsigned int max = 5;        // Number of blocks used to divide the scene (arbitrary but seems ok) 
     36    nbVerticesX = osg::clampBetween<unsigned int>(nbVerticesX, min, max); 
     37    nbVerticesY = osg::clampBetween<unsigned int>(nbVerticesY, min, max); 
     38    nbVerticesZ = osg::clampBetween<unsigned int>(nbVerticesZ, min, max); 
    3939} 
    4040 
     
    4343    osg::BoundingBox::vec_type length = sceneBox._max - sceneBox._min; 
    4444 
    45     static const float k = 1.3f;                // Arbitrary constant multiplier for density computation ("simulates" non-uniform point distributions) 
    46         // Computes "density" of points, and thus the number of blocks to divide the mesh into 
     45    static const float k = 1.3f;        // Arbitrary constant multiplier for density computation ("simulates" non-uniform point distributions) 
     46    // Computes "density" of points, and thus the number of blocks to divide the mesh into 
    4747    unsigned int nbVerticesX = static_cast<unsigned int>( (nbVertices * k) / (length.z() * length.y()) ); 
    4848    unsigned int nbVerticesY = static_cast<unsigned int>( (nbVertices * k) / (length.z() * length.x()) ); 
     
    132132 
    133133int WriterCompareTriangle::inWhichBox(const osg::BoundingBox::vec_type & point) const { 
    134         return inWhichBox(point.x(), point.y(), point.z()); 
     134    return inWhichBox(point.x(), point.y(), point.z()); 
    135135} 
  • OpenSceneGraph/trunk/src/osgPlugins/3ds/WriterNodeVisitor.cpp

    r10938 r11056  
    9292 
    9393/// Tests if the given string is a path supported by 3DS format (8.3, 63 chars max). 
    94 bool is3DSpath(const std::string & s) { 
     94bool is3DSpath(const std::string & s, bool extendedFilePaths) { 
    9595    unsigned int len = s.length(); 
    9696    if (len >= 64 || len == 0) return false; 
     97    if (extendedFilePaths) return true;        // Extended paths are simply those that fits the 64 bytes buffer! 
    9798 
    9899    unsigned int tokenBegin = 0; 
     
    146147          triangle.t3 = i3; 
    147148          triangle.material = _material; 
    148           _listTriangles.push_back(std::make_pair(triangle, _drawable_n)); 
     149          _listTriangles.push_back(std::pair<Triangle, unsigned int>(triangle, _drawable_n)); 
    149150      } 
    150151      virtual void begin(GLenum mode) 
     
    335336        //break; 
    336337    default: 
    337         osg::notify(osg::WARN) << "WriterNodeVisitor :: can't handle mode " << mode << std::endl; 
     338        osg::notify(osg::WARN) << "3DS WriterNodeVisitor: can't handle mode " << mode << std::endl; 
    338339        break; 
    339340    } 
     
    400401 
    401402 
    402 std::string 
    403 getPathRelative(const std::string & srcBad, 
    404                 const std::string & dstBad) 
    405 { 
    406     if(srcBad.empty()) 
    407         return osgDB::getSimpleFileName(dstBad); 
    408     const std::string & src = osgDB::convertFileNameToNativeStyle(srcBad); 
    409     const std::string & dst = osgDB::convertFileNameToNativeStyle(dstBad); 
    410     std::string::const_iterator itDst = dst.begin(); 
    411     std::string::const_iterator itSrc = src.begin(); 
    412  
    413     std::string result = ""; 
    414  
    415     while(itDst != dst.end()) 
    416     { 
    417         if (itSrc != src.end() && *itDst == *itSrc) 
    418             ++itSrc; 
    419         else if (!result.empty() || *itDst != '\\')   
    420             result += *itDst; 
    421         ++itDst; 
    422     } 
    423     if (itSrc != src.end()) 
    424         result = osgDB::getSimpleFileName(dst); 
    425     return result; 
     403// If 'to' is in a subdirectory of 'from' then this function returns the 
     404// subpath. Otherwise it just returns the file name. 
     405// (Same as in FBX plugin) 
     406std::string getPathRelative(const std::string& from/*directory*/, 
     407                            const std::string& to/*file path*/) 
     408{ 
     409 
     410    std::string::size_type slash = to.find_last_of('/'); 
     411    std::string::size_type backslash = to.find_last_of('\\'); 
     412    if (slash == std::string::npos)  
     413    { 
     414        if (backslash == std::string::npos) return to; 
     415        slash = backslash; 
     416    } 
     417    else if (backslash != std::string::npos && backslash > slash) 
     418    { 
     419        slash = backslash; 
     420    } 
     421 
     422    if (from.empty() || from.length() > to.length()) 
     423        return osgDB::getSimpleFileName(to); 
     424 
     425    std::string::const_iterator itTo = to.begin(); 
     426    for (std::string::const_iterator itFrom = from.begin(); 
     427        itFrom != from.end(); ++itFrom, ++itTo) 
     428    { 
     429        char a = tolower(*itFrom), b = tolower(*itTo); 
     430        if (a == '\\') a = '/'; 
     431        if (b == '\\') b = '/'; 
     432        if (a != b || itTo == to.begin() + slash + 1) 
     433        { 
     434            return osgDB::getSimpleFileName(to); 
     435        } 
     436    } 
     437 
     438    while (itTo != to.end() && (*itTo == '\\' || *itTo == '/')) 
     439    { 
     440        ++itTo; 
     441    } 
     442 
     443    return std::string(itTo, to.end()); 
    426444} 
    427445 
    428446/// Converts an extension to a 3-letters long one equivalent. 
    429 std::string convertExt(const std::string & path) 
    430 { 
     447std::string convertExt(const std::string & path, bool extendedFilePaths) 
     448{ 
     449    if (extendedFilePaths) return path;        // Extensions are not truncated for extended filenames 
     450 
    431451    std::string ext = osgDB::getFileExtensionIncludingDot(path); 
    432452    if (ext == ".tiff") ext = ".tif"; 
     
    435455    return osgDB::getNameLessExtension(path) + ext; 
    436456} 
     457 
     458 
     459WriterNodeVisitor::WriterNodeVisitor(Lib3dsFile * file3ds, const std::string & fileName,  
     460                const osgDB::ReaderWriter::Options* options,  
     461                const std::string & srcDirectory) : 
     462    osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), 
     463    _suceedLastApply(true), 
     464    _srcDirectory(srcDirectory), 
     465    file3ds(file3ds), 
     466    _currentStateSet(new osg::StateSet()), 
     467    _lastMaterialIndex(0), 
     468    _lastMeshIndex(0), 
     469    _cur3dsNode(NULL), 
     470    options(options), 
     471    _imageCount(0), 
     472    _extendedFilePaths(false) 
     473{ 
     474    if (!fileName.empty()) 
     475        _directory = options->getDatabasePathList().empty() ? osgDB::getFilePath(fileName) : options->getDatabasePathList().front(); 
     476 
     477    if (options) { 
     478        std::istringstream iss(options->getOptionString()); 
     479        std::string opt; 
     480        while (iss >> opt) 
     481        { 
     482            if (opt == "extended3dsFilePaths" || opt == "extended3DSFilePaths") 
     483                _extendedFilePaths = true; 
     484        } 
     485    } 
     486} 
     487 
    437488 
    438489void WriterNodeVisitor::writeMaterials() 
     
    471522                    path = getPathRelative(_srcDirectory, mat.image->getFileName()); 
    472523                } 
    473                 path = convertExt(path); 
    474  
    475                 if(!is3DSpath(path)) { 
     524                path = convertExt(path, _extendedFilePaths); 
     525 
     526                if(!is3DSpath(path, _extendedFilePaths)) { 
    476527                    path = getUniqueName(path, "", true); 
    477528                    //path = osgDB::getSimpleFileName(path); 
     
    483534 
    484535                //if (mat.image->valid()) osgDB::writeImageFile(*(mat.image), path); 
    485                 osgDB::writeImageFile(*(mat.image), path); 
     536                if(_imageSet.find(mat.image.get()) == _imageSet.end()) 
     537                { 
     538                    _imageSet.insert(mat.image.get()); 
     539                    osgDB::writeImageFile(*(mat.image), path); 
     540                } 
    486541                if (mat.texture_transparency) tex.flags |= LIB3DS_TEXTURE_ALPHA_SOURCE; 
    487542                if (mat.texture_no_tile) tex.flags |= LIB3DS_TEXTURE_NO_TILE; 
     
    498553 
    499554std::string WriterNodeVisitor::getUniqueName(const std::string& _defaultValue, const std::string & _defaultPrefix, bool nameIsPath) { 
    500     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. 
     555    static const unsigned int MAX_PREFIX_LEGNTH = 4; 
     556    if (_defaultPrefix.length()>MAX_PREFIX_LEGNTH) throw "Default prefix is too long";            // Arbitrarily defined to 4 chars. 
    501557 
    502558    // Tests if default name is valid and unique 
    503559    bool defaultIs83 = is83(_defaultValue); 
    504     bool defaultIsValid = nameIsPath ? is3DSpath(_defaultValue) : defaultIs83; 
     560    bool defaultIsValid = nameIsPath ? is3DSpath(_defaultValue, _extendedFilePaths) : defaultIs83; 
    505561    if (defaultIsValid && _nameMap.find(_defaultValue) == _nameMap.end()) { 
    506562        _nameMap.insert(_defaultValue); 
     
    509565 
    510566    // Handling of paths is not well done yet. Defaulting to something very simple. 
    511     // We should actually ensure each component is 8 chars long, and final filename is 8.3, and total is <64 chars. 
     567    // 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. 
    512568    std::string defaultValue(nameIsPath ? osgDB::getSimpleFileName(_defaultValue) : _defaultValue); 
    513569    std::string ext(nameIsPath ? osgDB::getFileExtensionIncludingDot(_defaultValue).substr(0, std::min<unsigned int>(_defaultValue.size(), 4)) : "");        // 4 chars = dot + 3 chars 
     570    if (ext == ".") ext = ""; 
    514571 
    515572    std::string defaultPrefix(_defaultPrefix.empty() ? "_" : _defaultPrefix); 
     
    517574    unsigned int max_val = 0; 
    518575    std::string truncDefaultValue = ""; 
    519     for (unsigned int i = 0; i < std::min<unsigned int>(defaultValue.size(), 4); ++i) 
     576    for (unsigned int i = 0; i < std::min<unsigned int>(defaultValue.size(), MAX_PREFIX_LEGNTH); ++i) 
    520577    { 
    521578        if (defaultValue[i] == '.') 
     
    526583    } 
    527584    if (truncDefaultValue.empty()) 
    528         truncDefaultValue = defaultValue.substr(0, std::min<unsigned int>(defaultValue.size(), 4)); 
     585        truncDefaultValue = defaultValue.substr(0, std::min<unsigned int>(defaultValue.size(), MAX_PREFIX_LEGNTH)); 
     586    assert(truncDefaultValue.size() <= MAX_PREFIX_LEGNTH); 
    529587    std::map<std::string, unsigned int>::iterator pairPrefix; 
     588 
     589    // TODO - Handle the case of extended 3DS paths and allow more than 8 chars 
    530590    defaultIs83 = is83(truncDefaultValue); 
    531591    if (defaultIs83) 
    532592    { 
    533         max_val = static_cast<unsigned int>(pow(10., 8. - truncDefaultValue.length() - 1)) -1;        // defaultPrefix.length()-1 because we add an underscore ("_") 
     593        max_val = static_cast<unsigned int>(pow(10., 8. - truncDefaultValue.length())) -1; 
    534594        pairPrefix = _mapPrefix.find(truncDefaultValue); 
    535595    }   
    536596 
    537     if (defaultIs83 && (_mapPrefix.end() == pairPrefix || pairPrefix->second <= max_val)) 
     597    if (defaultIs83 && (pairPrefix == _mapPrefix.end() || pairPrefix->second <= max_val)) 
    538598    { 
    539599        defaultPrefix = truncDefaultValue; 
     
    541601    else 
    542602    { 
    543         max_val = static_cast<unsigned int>(pow(10., 8. - defaultPrefix.length() - 1)) -  1;        // defaultPrefix.length()-1 because we add an underscore ("_") 
     603        max_val = static_cast<unsigned int>(pow(10., 8. - defaultPrefix.length())) -1; 
    544604        pairPrefix = _mapPrefix.find(defaultPrefix); 
    545605    } 
    546606 
    547607    unsigned int searchStart = 0; 
    548     if (pairPrefix != _mapPrefix.end()) 
     608    if (pairPrefix != _mapPrefix.end()) { 
    549609        searchStart = pairPrefix->second; 
     610    } 
    550611 
    551612    for(unsigned int i = searchStart; i <= max_val; ++i) { 
    552613        std::stringstream ss; 
    553         ss << defaultPrefix << "_" << i; 
     614        ss << defaultPrefix << i; 
    554615        const std::string & res = ss.str(); 
    555616        if (_nameMap.find(res) == _nameMap.end()) { 
    556             if (pairPrefix != _mapPrefix.end()) 
    557             { 
     617            if (pairPrefix != _mapPrefix.end()) { 
    558618                pairPrefix->second = i + 1; 
    559             } 
    560             else 
    561             { 
    562                 _mapPrefix.insert(std::make_pair(defaultPrefix, i + 1)); 
     619            } else { 
     620                _mapPrefix.insert(std::pair<std::string, unsigned int>(defaultPrefix, i + 1)); 
    563621            } 
    564622            _nameMap.insert(res); 
     
    566624        } 
    567625    } 
    568     if (defaultPrefix == "_") _lastGeneratedNumberedName = max_val; 
     626 
     627    // Failed finding a name 
     628    // Try with a shorter prefix if possible 
     629    if (defaultPrefix.length()>1) return getUniqueName(_defaultValue, defaultPrefix.substr(0, defaultPrefix.length()-1), nameIsPath); 
     630    // Try with default prefix if not arleady done 
     631    if (defaultPrefix != std::string("_")) return getUniqueName(_defaultValue, "_", nameIsPath); 
    569632    throw "No more names available! Is default prefix too long?"; 
    570633} 
     
    603666                                                unsigned int drawable_n) 
    604667{ 
    605     MapIndices::iterator itIndex = index_vert.find(std::make_pair(index, drawable_n)); 
     668    MapIndices::iterator itIndex = index_vert.find(std::pair<unsigned int, unsigned int>(index, drawable_n)); 
    606669    if (itIndex == index_vert.end()) { 
    607670        unsigned int indexMesh = index_vert.size(); 
    608         index_vert.insert(std::make_pair(std::make_pair(index, drawable_n), indexMesh)); 
     671        index_vert.insert(std::make_pair(std::pair<unsigned int, unsigned int>(index, drawable_n), indexMesh)); 
    609672        return indexMesh; 
    610673    } 
     
    693756       ((nbVertices) >= MAX_VERTICES-2)) 
    694757    { 
    695         osg::notify(osg::ALWAYS) << "Sorting elements..." << std::endl; 
     758        osg::notify(osg::INFO) << "Sorting elements..." << std::endl; 
    696759        WriterCompareTriangle cmp(geo, nbVertices); 
    697760        std::sort(listTriangles.begin(), listTriangles.end(), cmp); 
  • OpenSceneGraph/trunk/src/osgPlugins/3ds/WriterNodeVisitor.h

    r10945 r11056  
    4242#include "lib3ds/lib3ds.h" 
    4343#include "WriterCompareTriangle.h" 
     44#include <set> 
    4445 
    4546void copyOsgMatrixToLib3dsMatrix(Lib3dsMatrix lib3ds_matrix, const osg::Matrix& osg_matrix); 
     
    5051class WriterNodeVisitor: public osg::NodeVisitor 
    5152{ 
    52  
    5353    public: 
    5454        static const unsigned int MAX_VERTICES = 65000; 
     
    5757        WriterNodeVisitor(Lib3dsFile * file3ds, const std::string & fileName,  
    5858                        const osgDB::ReaderWriter::Options* options,  
    59                         const std::string & srcDirectory) : 
    60             osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), 
    61             _suceedLastApply(true), 
    62             _srcDirectory(srcDirectory), 
    63             file3ds(file3ds), 
    64             _currentStateSet(new osg::StateSet()), 
    65             _lastGeneratedNumberedName(0), 
    66             _lastMaterialIndex(0), 
    67             _lastMeshIndex(0), 
    68             _cur3dsNode(NULL), 
    69             options(options), 
    70             _imageCount(0) 
    71         { 
    72             //supportsOption("flipTexture", "flip texture upside-down"); 
    73             if (!fileName.empty()) 
    74                 _directory = options->getDatabasePathList().empty() ? osgDB::getFilePath(fileName) : options->getDatabasePathList().front(); 
    75         } 
     59                        const std::string & srcDirectory); 
    7660 
    7761        bool        suceedLastApply() const; 
     
    216200        StateSetStack                       _stateSetStack; 
    217201        osg::ref_ptr<osg::StateSet>         _currentStateSet; 
    218         std::map<std::string, unsigned int> _mapPrefix; 
     202        std::map<std::string, unsigned int> _mapPrefix;            ///< List of next number to use in unique name generation, for each prefix 
    219203        std::set<std::string>                _nameMap; 
    220204        MaterialMap                         _materialMap; 
    221         unsigned int                        _lastGeneratedNumberedName; 
    222205        unsigned int                        _lastMaterialIndex; 
    223206        unsigned int                        _lastMeshIndex; 
     
    225208        const osgDB::ReaderWriter::Options* options; 
    226209        unsigned int                        _imageCount; 
     210        bool                                _extendedFilePaths; 
     211        std::set<osg::Image *>              _imageSet; 
    227212}; 
    228213