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/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