root/OpenSceneGraph/trunk/src/osgPlugins/dae/ReaderWriterDAE.cpp @ 13041

Revision 13041, 10.3 kB (checked in by robert, 2 years ago)

Ran script to remove trailing spaces and tabs

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This application is open source and may be redistributed and/or modified
4 * freely and without restriction, both in commercial and non commercial
5 * applications, as long as this copyright notice is maintained.
6 *
7 * This application is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 *
11*/
12
13#include <sstream>
14#include <memory>
15
16#include <osg/Notify>
17#include <osg/NodeVisitor>
18#include <osgDB/ReaderWriter>
19#include <osgDB/FileNameUtils>
20#include <osgDB/Registry>
21#include <osgDB/ConvertUTF>
22
23#include <OpenThreads/ScopedLock>
24
25#include "ReaderWriterDAE.h"
26#include "daeReader.h"
27#include "daeWriter.h"
28
29#ifdef WIN32
30#include "windows.h"
31#endif
32
33#define SERIALIZER() OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_serializerMutex)
34
35osgDB::ReaderWriter::ReadResult
36ReaderWriterDAE::readNode(const std::string& fname,
37        const osgDB::ReaderWriter::Options* options) const
38{
39    SERIALIZER();
40
41    bool bOwnDAE = false;
42    DAE* pDAE = NULL;
43
44    // Process options
45    osgDAE::daeReader::Options pluginOptions;
46    if( options )
47    {
48        pDAE = (DAE*)options->getPluginData("DAE");
49
50        pluginOptions.precisionHint = options->getPrecisionHint();
51
52        std::istringstream iss( options->getOptionString() );
53        std::string opt;
54        while (iss >> opt)
55        {
56            if( opt == "StrictTransparency") pluginOptions.strictTransparency = true;
57            else if (opt == "daeTessellateNone")              pluginOptions.tessellateMode = osgDAE::daeReader::TESSELLATE_NONE;
58            else if (opt == "daeTessellatePolygonsAsTriFans") pluginOptions.tessellateMode = osgDAE::daeReader::TESSELLATE_POLYGONS_AS_TRIFAN;
59            else if (opt == "daeTessellatePolygons")          pluginOptions.tessellateMode = osgDAE::daeReader::TESSELLATE_POLYGONS;
60            else if (opt == "daeUsePredefinedTextureUnits") pluginOptions.usePredefinedTextureUnits = true;
61            else if (opt == "daeUseSequencedTextureUnits")  pluginOptions.usePredefinedTextureUnits = false;
62        }
63    }
64
65
66    std::string ext( osgDB::getLowerCaseFileExtension(fname) );
67    if( ! acceptsExtension(ext) ) return ReadResult::FILE_NOT_HANDLED;
68
69    std::string fileName( osgDB::findDataFile( fname, options ) );
70    if( fileName.empty() ) return ReadResult::FILE_NOT_FOUND;
71
72    OSG_INFO << "ReaderWriterDAE( \"" << fileName << "\" )" << std::endl;
73
74    if (NULL == pDAE)
75    {
76        bOwnDAE = true;
77        pDAE = new DAE;
78    }
79    std::auto_ptr<DAE> scopedDae(bOwnDAE ? pDAE : NULL);        // Deallocates locally created structure at scope exit
80
81    osgDAE::daeReader daeReader(pDAE, &pluginOptions);
82
83    // Convert file name to URI
84    std::string fileURI = ConvertFilePathToColladaCompatibleURI(fileName);
85
86    if ( ! daeReader.convert( fileURI ) )
87    {
88        OSG_WARN << "Load failed in COLLADA DOM conversion" << std::endl;
89        return ReadResult::ERROR_IN_READING_FILE;
90    }
91
92    if ( options )
93    {
94        // Return the document URI
95        if (options->getPluginData("DAE-DocumentURI"))
96            *(std::string*)options->getPluginData("DAE-DocumentURI") = fileURI;
97        // Return some additional information about the document
98        if (options->getPluginData("DAE-AssetUnitName"))
99             *(std::string*)options->getPluginData("DAE-AssetUnitName") = daeReader.getAssetUnitName();
100        if (options->getPluginData("DAE-AssetUnitMeter"))
101            *(float*)options->getPluginData("DAE-AssetUnitMeter") = daeReader.getAssetUnitMeter();
102        if (options->getPluginData("DAE-AssetUp_axis"))
103            *(domUpAxisType*)options->getPluginData("DAE-AssetUp_axis") = daeReader.getAssetUpAxis();
104    }
105
106    osg::Node* rootNode( daeReader.getRootNode() );
107    return rootNode;
108}
109
110///////////////////////////////////////////////////////////////////////////
111
112osgDB::ReaderWriter::WriteResult
113ReaderWriterDAE::writeNode( const osg::Node& node,
114        const std::string& fname, const osgDB::ReaderWriter::Options* options ) const
115{
116    SERIALIZER();
117
118    bool bOwnDAE = false;
119    DAE* pDAE = NULL;
120
121    std::string ext( osgDB::getLowerCaseFileExtension(fname) );
122    if( ! acceptsExtension(ext) ) return WriteResult::FILE_NOT_HANDLED;
123
124    // Process options
125    osgDAE::daeWriter::Options pluginOptions;
126    std::string srcDirectory( osgDB::getFilePath(node.getName().empty() ? fname : node.getName()) );        // Base dir when relativising images paths
127    if( options )
128    {
129        pDAE = (DAE*)options->getPluginData("DAE");
130
131        const std::string & baseDir = options->getPluginStringData("baseImageDir");        // Rename "srcModelPath" (and call getFilePath() on it)?
132        if (!baseDir.empty()) srcDirectory = baseDir;
133
134        const std::string & relativiseImagesPathNbUpDirs = options->getPluginStringData("DAE-relativiseImagesPathNbUpDirs");
135        if (!relativiseImagesPathNbUpDirs.empty()) {
136            std::istringstream iss(relativiseImagesPathNbUpDirs);
137            iss >> pluginOptions.relativiseImagesPathNbUpDirs;
138        }
139
140        // Sukender's note: I don't know why DAE seems to accept comma-sparated options instead of space-separated options as other ReaderWriters. However, to avoid breaking compatibility, here's a workaround:
141        std::string optString( options->getOptionString() );
142        for(std::string::iterator it=optString.begin(); it!=optString.end(); ++it) {
143            if (*it == ' ') *it = ',';
144        }
145        std::istringstream iss( optString );
146        std::string opt;
147
148        //while (iss >> opt)
149        while( std::getline( iss, opt, ',' ) )
150        {
151            if( opt == "polygon") pluginOptions.usePolygons = true;
152            else if (opt == "GoogleMode") pluginOptions.googleMode = true;
153            else if (opt == "NoExtras") pluginOptions.writeExtras = false;
154            else if (opt == "daeEarthTex") pluginOptions.earthTex = true;
155            else if (opt == "daeZUpAxis") {}    // Nothing (old option)
156            else if (opt == "daeLinkOriginalTexturesNoForce") { pluginOptions.linkOrignialTextures = true; pluginOptions.forceTexture = false; }
157            else if (opt == "daeLinkOriginalTexturesForce")   { pluginOptions.linkOrignialTextures = true; pluginOptions.forceTexture = true; }
158            else if (opt == "daeNamesUseCodepage") pluginOptions.namesUseCodepage = true;
159            else if (!opt.empty())
160            {
161                OSG_NOTICE << std::endl << "COLLADA dae plugin: unrecognized option \"" << opt <<  std::endl;
162            }
163        }
164    }
165
166    if (NULL == pDAE)
167    {
168        bOwnDAE = true;
169        pDAE = new DAE;
170    }
171    std::auto_ptr<DAE> scopedDae(bOwnDAE ? pDAE : NULL);        // Deallocates locally created structure at scope exit
172
173    // Convert file name to URI
174    std::string fileURI = ConvertFilePathToColladaCompatibleURI(fname);
175
176    osg::NodeVisitor::TraversalMode traversalMode = pluginOptions.writeExtras ? osg::NodeVisitor::TRAVERSE_ALL_CHILDREN : osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN;
177
178    osgDAE::daeWriter daeWriter(pDAE, fileURI, osgDB::getFilePath(fname), srcDirectory, options, traversalMode, &pluginOptions);
179    daeWriter.setRootNode( node );
180    const_cast<osg::Node*>(&node)->accept( daeWriter );
181
182    osgDB::ReaderWriter::WriteResult retVal( WriteResult::ERROR_IN_WRITING_FILE );
183    if ( daeWriter.isSuccess() )
184    {
185        if (pDAE->write(fileURI))
186            retVal = WriteResult::FILE_SAVED;
187    }
188
189    if ( options )
190    {
191        if (!bOwnDAE)
192        {
193            // Return the document URI used so that users of an external DAE object
194            // can locate the correct database
195            if (options->getPluginData("DAE-DocumentURI"))
196                *(std::string*)options->getPluginData("DAE-DocumentURI") = fileURI;
197        }
198    }
199
200    return retVal;
201}
202
203static void replace(std::string & str, const char from, const std::string & to)
204{
205    // Replace for all occurences
206    for(std::string::size_type pos=str.find(from); pos!=std::string::npos; pos=str.find(from))
207    {
208        str.replace(pos, 1, to);
209    }
210}
211
212static void replace(std::string & str, const std::string & from, const std::string & to)
213{
214    // Replace for all occurences
215    std::size_t lenFrom = from.size();
216    std::size_t lenTo = to.size();
217    for(std::string::size_type pos=str.find(from); pos!=std::string::npos; pos = str.find(from, pos+lenTo))
218    {
219        str.replace(pos, lenFrom, to);
220    }
221}
222
223std::string ReaderWriterDAE::ConvertFilePathToColladaCompatibleURI(const std::string& FilePath)
224{
225#ifdef OSG_USE_UTF8_FILENAME
226    std::string path( cdom::nativePathToUri( FilePath ) );
227#else
228    std::string path( cdom::nativePathToUri( osgDB::convertStringFromCurrentCodePageToUTF8(FilePath) ) );
229#endif
230
231    // Unfortunately, cdom::nativePathToUri() does not convert '#' characters to "%23" as expected.
232    // So having /a/#b/c will generate a wrong conversion, as '#' will be misinterpreted as an URI fragment.
233    // Here are listed all special chars, but only # was found problematic. I (Sukender) tested #{}^~[]`;@=&$ under Windows.
234    // Uncomment lines if you find issues with some other special characters.
235
236    //replace(path, '%', "%25");        // % at first
237    //replace(path, ' ', "%20");
238    replace(path, '#', "%23");
239    //replace(path, '<', "%3C");
240    //replace(path, '>', "%3E");
241    //replace(path, '{', "%7B");
242    //replace(path, '}', "%7D");
243    //replace(path, '|', "%7C");
244    //replace(path, '^', "%5E");
245    //replace(path, '~', "%7E");
246    //replace(path, '[', "%5B");
247    //replace(path, '}', "%5D");
248    //replace(path, '`', "%60");
249    //replace(path, ';', "%3B");
250    //replace(path, '?', "%3F");
251    //replace(path, '@', "%40");
252    //replace(path, '=', "%3D");
253    //replace(path, '&', "%26");
254    //replace(path, '$', "%24");
255    return path;
256}
257
258std::string ReaderWriterDAE::ConvertColladaCompatibleURIToFilePath(const std::string& uri)
259{
260    // Reciprocal of ConvertFilePathToColladaCompatibleURI()
261#ifdef OSG_USE_UTF8_FILENAME
262    std::string path( cdom::uriToNativePath( uri ) );
263#else
264    std::string path( osgDB::convertStringFromCurrentCodePageToUTF8( cdom::uriToNativePath(uri) ) );
265#endif
266    replace(path, "%23", "#");
267    return path;
268}
269
270///////////////////////////////////////////////////////////////////////////
271// Add ourself to the Registry to instantiate the reader/writer.
272
273REGISTER_OSGPLUGIN(dae, ReaderWriterDAE)
274
275// vim: set sw=4 ts=8 et ic ai:
Note: See TracBrowser for help on using the browser.