Show
Ignore:
Timestamp:
02/11/10 12:56:43 (3 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"

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • 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);