1 #include <stdio.h>
2 
3 #include <osg/ArgumentParser>
4 #include <osg/ApplicationUsage>
5 #include <osg/Group>
6 #include <osg/Notify>
7 #include <osg/Vec3>
8 #include <osg/ProxyNode>
9 #include <osg/Geometry>
10 #include <osg/Texture2D>
11 #include <osg/Texture3D>
12 #include <osg/BlendFunc>
13 #include <osg/Timer>
14 
15 #include <osgDB/Registry>
16 #include <osgDB/ReadFile>
17 #include <osgDB/WriteFile>
18 #include <osgDB/FileNameUtils>
19 #include <osgDB/ReaderWriter>
20 #include <osgDB/PluginQuery>
21 
22 #include <osgUtil/Optimizer>
23 #include <osgUtil/Simplifier>
24 #include <osgUtil/SmoothingVisitor>
25 
26 #include <osgViewer/GraphicsWindow>
27 #include <osgViewer/Version>
28 
29 #include <iostream>
30 
31 #include "OrientationConverter.h"
32 
33 typedef std::vector<std::string> FileNameList;
34 
35 class MyGraphicsContext {
36     public:
MyGraphicsContext()37         MyGraphicsContext()
38         {
39             osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
40             traits->x = 0;
41             traits->y = 0;
42             traits->width = 1;
43             traits->height = 1;
44             traits->windowDecoration = false;
45             traits->doubleBuffer = false;
46             traits->sharedContext = 0;
47             traits->pbuffer = true;
48             traits->readDISPLAY();
49             traits->setUndefinedScreenDetailsToDefaultScreen();
50 
51             _gc = osg::GraphicsContext::createGraphicsContext(traits.get());
52 
53             if (!_gc)
54             {
55                 osg::notify(osg::NOTICE)<<"Failed to create pbuffer, failing back to normal graphics window."<<std::endl;
56 
57                 traits->pbuffer = false;
58                 _gc = osg::GraphicsContext::createGraphicsContext(traits.get());
59             }
60 
61             if (_gc.valid())
62             {
63                 _gc->realize();
64                 _gc->makeCurrent();
65                 if (dynamic_cast<osgViewer::GraphicsWindow*>(_gc.get()))
66                 {
67                     std::cout<<"Realized graphics window for OpenGL operations."<<std::endl;
68                 }
69                 else
70                 {
71                     std::cout<<"Realized pbuffer for OpenGL operations."<<std::endl;
72                 }
73             }
74         }
75 
valid() const76         bool valid() const { return _gc.valid() && _gc->isRealized(); }
77 
78     private:
79         osg::ref_ptr<osg::GraphicsContext> _gc;
80 };
81 
82 class DefaultNormalsGeometryVisitor
83     : public osg::NodeVisitor
84 {
85 public:
86 
DefaultNormalsGeometryVisitor()87     DefaultNormalsGeometryVisitor()
88         : osg::NodeVisitor( osg::NodeVisitor::TRAVERSE_ALL_CHILDREN ) {
89     }
90 
apply(osg::Geode & geode)91     virtual void apply( osg::Geode & geode )
92     {
93         for( unsigned int ii = 0; ii < geode.getNumDrawables(); ++ii )
94         {
95             osg::ref_ptr< osg::Geometry > geometry = dynamic_cast< osg::Geometry * >( geode.getDrawable( ii ) );
96             if( geometry.valid() )
97             {
98                 osg::ref_ptr< osg::Vec3Array > newnormals = new osg::Vec3Array;
99                 newnormals->push_back( osg::Z_AXIS );
100                 geometry->setNormalArray( newnormals.get(), osg::Array::BIND_OVERALL );
101             }
102         }
103     }
104 
apply(osg::Node & node)105     virtual void apply( osg::Node & node )
106     {
107         traverse( node );
108     }
109 
110 };
111 
112 class CompressTexturesVisitor : public osg::NodeVisitor
113 {
114 public:
115 
CompressTexturesVisitor(osg::Texture::InternalFormatMode internalFormatMode)116     CompressTexturesVisitor(osg::Texture::InternalFormatMode internalFormatMode):
117         osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
118         _internalFormatMode(internalFormatMode) {}
119 
apply(osg::Node & node)120     virtual void apply(osg::Node& node)
121     {
122         if (node.getStateSet()) apply(*node.getStateSet());
123         traverse(node);
124     }
125 
apply(osg::Geode & node)126     virtual void apply(osg::Geode& node)
127     {
128         if (node.getStateSet()) apply(*node.getStateSet());
129 
130         for(unsigned int i=0;i<node.getNumDrawables();++i)
131         {
132             osg::Drawable* drawable = node.getDrawable(i);
133             if (drawable && drawable->getStateSet()) apply(*drawable->getStateSet());
134         }
135 
136         traverse(node);
137     }
138 
apply(osg::StateSet & stateset)139     virtual void apply(osg::StateSet& stateset)
140     {
141         // search for the existence of any texture object attributes
142         for(unsigned int i=0;i<stateset.getTextureAttributeList().size();++i)
143         {
144             osg::Texture* texture = dynamic_cast<osg::Texture*>(stateset.getTextureAttribute(i,osg::StateAttribute::TEXTURE));
145             if (texture)
146             {
147                 _textureSet.insert(texture);
148             }
149         }
150     }
151 
compress()152     void compress()
153     {
154         MyGraphicsContext context;
155         if (!context.valid())
156         {
157             osg::notify(osg::NOTICE)<<"Error: Unable to create graphis context, problem with running osgViewer-"<<osgViewerGetVersion()<<", cannot run compression."<<std::endl;
158             return;
159         }
160 
161         osg::ref_ptr<osg::State> state = new osg::State;
162         state->initializeExtensionProcs();
163 
164         for(TextureSet::iterator itr=_textureSet.begin();
165             itr!=_textureSet.end();
166             ++itr)
167         {
168             osg::Texture* texture = const_cast<osg::Texture*>(itr->get());
169 
170             osg::Texture2D* texture2D = dynamic_cast<osg::Texture2D*>(texture);
171             osg::Texture3D* texture3D = dynamic_cast<osg::Texture3D*>(texture);
172 
173             osg::ref_ptr<osg::Image> image = texture2D ? texture2D->getImage() : (texture3D ? texture3D->getImage() : 0);
174             if (image.valid() &&
175                 (image->getPixelFormat()==GL_RGB || image->getPixelFormat()==GL_RGBA) &&
176                 (image->s()>=32 && image->t()>=32))
177             {
178                 texture->setInternalFormatMode(_internalFormatMode);
179 
180                 // need to disable the unref after apply, otherwise the image could go out of scope.
181                 bool unrefImageDataAfterApply = texture->getUnRefImageDataAfterApply();
182                 texture->setUnRefImageDataAfterApply(false);
183 
184                 // get OpenGL driver to create texture from image.
185                 texture->apply(*state);
186 
187                 // restore the original setting
188                 texture->setUnRefImageDataAfterApply(unrefImageDataAfterApply);
189 
190                 image->readImageFromCurrentTexture(0,true);
191 
192                 texture->setInternalFormatMode(osg::Texture::USE_IMAGE_DATA_FORMAT);
193             }
194         }
195     }
196 
write(const std::string & dir)197     void write(const std::string &dir)
198     {
199         for(TextureSet::iterator itr=_textureSet.begin();
200             itr!=_textureSet.end();
201             ++itr)
202         {
203             osg::Texture* texture = const_cast<osg::Texture*>(itr->get());
204 
205             osg::Texture2D* texture2D = dynamic_cast<osg::Texture2D*>(texture);
206             osg::Texture3D* texture3D = dynamic_cast<osg::Texture3D*>(texture);
207 
208             osg::ref_ptr<osg::Image> image = texture2D ? texture2D->getImage() : (texture3D ? texture3D->getImage() : 0);
209             if (image.valid())
210             {
211                 std::string name = osgDB::getStrippedName(image->getFileName());
212                 name += ".dds";
213                 image->setFileName(name);
214                 std::string path = dir.empty() ? name : osgDB::concatPaths(dir, name);
215                 osgDB::writeImageFile(*image, path);
216                 osg::notify(osg::NOTICE) << "Image written to '" << path << "'." << std::endl;
217             }
218         }
219     }
220 
221     typedef std::set< osg::ref_ptr<osg::Texture> > TextureSet;
222     TextureSet                          _textureSet;
223     osg::Texture::InternalFormatMode    _internalFormatMode;
224 
225 };
226 
227 
228 class FixTransparencyVisitor : public osg::NodeVisitor
229 {
230 public:
231 
232     enum FixTransparencyMode
233     {
234         NO_TRANSPARANCY_FIXING,
235         MAKE_OPAQUE_TEXTURE_STATESET_OPAQUE,
236         MAKE_ALL_STATESET_OPAQUE
237     };
238 
FixTransparencyVisitor(FixTransparencyMode mode=MAKE_OPAQUE_TEXTURE_STATESET_OPAQUE)239     FixTransparencyVisitor(FixTransparencyMode mode=MAKE_OPAQUE_TEXTURE_STATESET_OPAQUE):
240         osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
241         _numTransparent(0),
242         _numOpaque(0),
243         _numTransparentMadeOpaque(0),
244         _mode(mode)
245     {
246         std::cout<<"Running FixTransparencyVisitor..."<<std::endl;
247     }
248 
~FixTransparencyVisitor()249     ~FixTransparencyVisitor()
250     {
251         std::cout<<"  Number of Transparent StateSet "<<_numTransparent<<std::endl;
252         std::cout<<"  Number of Opaque StateSet "<<_numOpaque<<std::endl;
253         std::cout<<"  Number of Transparent State made Opaque "<<_numTransparentMadeOpaque<<std::endl;
254     }
255 
apply(osg::Node & node)256     virtual void apply(osg::Node& node)
257     {
258         if (node.getStateSet()) isTransparent(*node.getStateSet());
259         traverse(node);
260     }
261 
apply(osg::Geode & node)262     virtual void apply(osg::Geode& node)
263     {
264         if (node.getStateSet()) isTransparent(*node.getStateSet());
265 
266         for(unsigned int i=0;i<node.getNumDrawables();++i)
267         {
268             osg::Drawable* drawable = node.getDrawable(i);
269             if (drawable && drawable->getStateSet()) isTransparent(*drawable->getStateSet());
270         }
271 
272         traverse(node);
273     }
274 
isTransparent(osg::StateSet & stateset)275     virtual bool isTransparent(osg::StateSet& stateset)
276     {
277         bool hasTranslucentTexture = false;
278         bool hasBlendFunc = dynamic_cast<osg::BlendFunc*>(stateset.getAttribute(osg::StateAttribute::BLENDFUNC))!=0;
279         bool hasTransparentRenderingHint = stateset.getRenderingHint()==osg::StateSet::TRANSPARENT_BIN;
280         bool hasDepthSortBin = (stateset.getRenderBinMode()==osg::StateSet::USE_RENDERBIN_DETAILS)?(stateset.getBinName()=="DepthSortedBin"):false;
281         bool hasTexture = false;
282 
283 
284         // search for the existence of any texture object attributes
285         for(unsigned int i=0;i<stateset.getTextureAttributeList().size();++i)
286         {
287             osg::Texture* texture = dynamic_cast<osg::Texture*>(stateset.getTextureAttribute(i,osg::StateAttribute::TEXTURE));
288             if (texture)
289             {
290                 hasTexture = true;
291                 for (unsigned int im=0;im<texture->getNumImages();++im)
292                 {
293                     osg::Image* image = texture->getImage(im);
294                     if (image && image->isImageTranslucent()) hasTranslucentTexture = true;
295                 }
296             }
297         }
298 
299         if (hasTranslucentTexture || hasBlendFunc || hasTransparentRenderingHint || hasDepthSortBin)
300         {
301             ++_numTransparent;
302 
303             bool makeNonTransparent = false;
304 
305             switch(_mode)
306             {
307             case(MAKE_OPAQUE_TEXTURE_STATESET_OPAQUE):
308                 if (hasTexture && !hasTranslucentTexture)
309                 {
310                     makeNonTransparent = true;
311                 }
312                 break;
313             case(MAKE_ALL_STATESET_OPAQUE):
314                 makeNonTransparent = true;
315                 break;
316             default:
317                 makeNonTransparent = false;
318                 break;
319             }
320 
321             if (makeNonTransparent)
322             {
323                 stateset.removeAttribute(osg::StateAttribute::BLENDFUNC);
324                 stateset.removeMode(GL_BLEND);
325                 stateset.setRenderingHint(osg::StateSet::DEFAULT_BIN);
326                 ++_numTransparentMadeOpaque;
327             }
328 
329 
330             return true;
331         }
332         else
333         {
334             ++_numOpaque;
335             return false;
336         }
337     }
338 
339     unsigned int _numTransparent;
340     unsigned int _numOpaque;
341     unsigned int _numTransparentMadeOpaque;
342     FixTransparencyMode _mode;
343 };
344 
345 class PruneStateSetVisitor : public osg::NodeVisitor
346 {
347 public:
348 
PruneStateSetVisitor()349     PruneStateSetVisitor():
350         osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
351         _numStateSetRemoved(0)
352     {
353         std::cout<<"Running PruneStateSet..."<<std::endl;
354     }
355 
~PruneStateSetVisitor()356     ~PruneStateSetVisitor()
357     {
358         std::cout<<"  Number of StateState removed "<<_numStateSetRemoved<<std::endl;
359     }
360 
apply(osg::Node & node)361     virtual void apply(osg::Node& node)
362     {
363         if (node.getStateSet())
364         {
365             node.setStateSet(0);
366             ++_numStateSetRemoved;
367         }
368         traverse(node);
369     }
370 
apply(osg::Geode & node)371     virtual void apply(osg::Geode& node)
372     {
373         if (node.getStateSet())
374         {
375             node.setStateSet(0);
376             ++_numStateSetRemoved;
377         }
378 
379         traverse(node);
380     }
381 
382     unsigned int _numStateSetRemoved;
383 };
384 
385 /** Add missing colours to osg::Geometry.*/
386 class AddMissingColoursToGeometryVisitor : public osg::NodeVisitor
387 {
388 public:
389 
AddMissingColoursToGeometryVisitor()390     AddMissingColoursToGeometryVisitor():osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}
391 
apply(osg::Geode & geode)392     virtual void apply(osg::Geode& geode)
393     {
394         for(unsigned int i=0;i<geode.getNumDrawables();++i)
395         {
396             osg::Geometry* geometry = dynamic_cast<osg::Geometry*>(geode.getDrawable(i));
397             if (geometry)
398             {
399                 if (geometry->getColorArray()==0 || geometry->getColorArray()->getNumElements()==0)
400                 {
401                     osg::Vec4Array* colours = new osg::Vec4Array(1);
402                     (*colours)[0].set(1.0f,1.0f,1.0f,1.0f);
403                     geometry->setColorArray(colours, osg::Array::BIND_OVERALL);
404                 }
405             }
406         }
407     }
408 
apply(osg::Node & node)409     virtual void apply(osg::Node& node) { traverse(node); }
410 
411 };
412 
413 
usage(const char * prog,const char * msg)414 static void usage( const char *prog, const char *msg )
415 {
416     if (msg)
417     {
418         osg::notify(osg::NOTICE)<< std::endl;
419         osg::notify(osg::NOTICE) << msg << std::endl;
420     }
421 
422     // basic usage
423     osg::notify(osg::NOTICE)<< std::endl;
424     osg::notify(osg::NOTICE)<<"usage:"<< std::endl;
425     osg::notify(osg::NOTICE)<<"    " << prog << " [options] infile1 [infile2 ...] outfile"<< std::endl;
426     osg::notify(osg::NOTICE)<< std::endl;
427 
428     // print env options - especially since optimizer is always _on_
429     osg::notify(osg::NOTICE)<<"environment:" << std::endl;
430     osg::ApplicationUsage::UsageMap um = osg::ApplicationUsage::instance()->getEnvironmentalVariables();
431     std::string envstring;
432     osg::ApplicationUsage::instance()->getFormattedString( envstring, um );
433     osg::notify(osg::NOTICE)<<envstring << std::endl;
434 
435     // print tool options
436     osg::notify(osg::NOTICE)<<"options:"<< std::endl;
437     osg::notify(osg::NOTICE)<<"    -O option          - ReaderWriter option"<< std::endl;
438     osg::notify(osg::NOTICE)<< std::endl;
439     osg::notify(osg::NOTICE)<<"    --compressed       - Enable the usage of compressed textures,"<< std::endl;
440     osg::notify(osg::NOTICE)<<"                         defaults to OpenGL ARB compressed textures."<< std::endl;
441     osg::notify(osg::NOTICE)<<"    --compressed-arb   - Enable the usage of OpenGL ARB compressed textures"<< std::endl;
442     osg::notify(osg::NOTICE)<<"    --compressed-dxt1  - Enable the usage of S3TC DXT1 compressed textures"<< std::endl;
443     osg::notify(osg::NOTICE)<<"    --compressed-dxt3  - Enable the usage of S3TC DXT3 compressed textures"<< std::endl;
444     osg::notify(osg::NOTICE)<<"    --compressed-dxt5  - Enable the usage of S3TC DXT5 compressed textures"<< std::endl;
445     osg::notify(osg::NOTICE)<< std::endl;
446     osg::notify(osg::NOTICE)<<"    --fix-transparency - fix statesets which are currently"<< std::endl;
447     osg::notify(osg::NOTICE)<<"                         declared as transparent, but should be opaque."<< std::endl;
448     osg::notify(osg::NOTICE)<<"                         Defaults to using the fixTranspancyMode"<< std::endl;
449     osg::notify(osg::NOTICE)<<"                         MAKE_OPAQUE_TEXTURE_STATESET_OPAQUE."<< std::endl;
450     osg::notify(osg::NOTICE)<<"    --fix-transparency-mode <mode_string>  - fix statesets which are currently"<< std::endl;
451     osg::notify(osg::NOTICE)<<"                         declared as transparent but should be opaque."<< std::endl;
452     osg::notify(osg::NOTICE)<<"                         The mode_string determines which algorithm is used"<< std::endl;
453     osg::notify(osg::NOTICE)<<"                         to fix the transparency, options are:"<< std::endl;
454     osg::notify(osg::NOTICE)<<"                                 MAKE_OPAQUE_TEXTURE_STATESET_OPAQUE,"<<std::endl;
455     osg::notify(osg::NOTICE)<<"                                 MAKE_ALL_STATESET_OPAQUE."<<std::endl;
456 
457     osg::notify(osg::NOTICE)<< std::endl;
458     osg::notify(osg::NOTICE)<<"    -l libraryName     - load plugin of name libraryName"<< std::endl;
459     osg::notify(osg::NOTICE)<<"                         i.e. -l osgdb_pfb"<< std::endl;
460     osg::notify(osg::NOTICE)<<"                         Useful for loading reader/writers which can load"<< std::endl;
461     osg::notify(osg::NOTICE)<<"                         other file formats in addition to its extension."<< std::endl;
462     osg::notify(osg::NOTICE)<<"    -e extensionName   - load reader/wrter plugin for file extension"<< std::endl;
463     osg::notify(osg::NOTICE)<<"                         i.e. -e pfb"<< std::endl;
464     osg::notify(osg::NOTICE)<<"                         Useful short hand for specifying full library name as"<< std::endl;
465     osg::notify(osg::NOTICE)<<"                         done with -l above, as it automatically expands to the"<< std::endl;
466     osg::notify(osg::NOTICE)<<"                         full library name appropriate for each platform."<< std::endl;
467     osg::notify(osg::NOTICE)<<"    -o orientation     - Convert geometry from input files to output files."<< std::endl;
468     osg::notify(osg::NOTICE)<<
469                               "                         Format of orientation argument must be the following:\n"
470                               "\n"
471                               "                             X1,Y1,Z1-X2,Y2,Z2\n"
472                               "                         or\n"
473                               "                             degrees-A0,A1,A2\n"
474                               "\n"
475                               "                         where X1,Y1,Z1 represent the UP vector in the input\n"
476                               "                         files and X2,Y2,Z2 represent the UP vector of the\n"
477                               "                         output file, or degrees is the rotation angle in\n"
478                               "                         degrees around axis (A0,A1,A2).  For example, to\n"
479                               "                         convert a model built in a Y-Up coordinate system to a\n"
480                               "                         model with a Z-up coordinate system, the argument may\n"
481                               "                         look like\n"
482                               "\n"
483                               "                             0,1,0-0,0,1"
484                               "\n"
485                               "                          or\n"
486                               "                             -90-1,0,0\n"
487                               "\n" << std::endl;
488     osg::notify(osg::NOTICE)<<"    -t translation     - Convert spatial position of output files.  Format of\n"
489                               "                         translation argument must be the following :\n"
490                               "\n"
491                               "                             X,Y,Z\n"
492                               "\n"
493                               "                         where X, Y, and Z represent the coordinates of the\n"
494                               "                         absolute position in world space\n"
495                               << std::endl;
496     osg::notify(osg::NOTICE)<<"    --use-world-frame  - Perform transformations in the world frame, rather\n"
497                               "                         than relative to the center of the bounding sphere.\n"
498                               << std::endl;
499     osg::notify(osg::NOTICE)<<"    --simplify n       - Run simplifier prior to output. Argument must be a" << std::endl
500                             <<"                         normalized value for the resultant percentage" << std::endl
501                             <<"                         reduction." << std::endl
502                             <<"                         Example: --simplify .5" << std::endl
503                             <<"                                 will produce a 50% reduced model." << std::endl
504                             << std::endl;
505     osg::notify(osg::NOTICE)<<"    -s scale           - Scale size of model.  Scale argument must be the \n"
506                               "                         following :\n"
507                               "\n"
508                               "                             SX,SY,SZ\n"
509                               "\n"
510                               "                         where SX, SY, and SZ represent the scale factors\n"
511                               "                         Caution: Scaling is done in destination orientation\n"
512                               << std::endl;
513     osg::notify(osg::NOTICE)<<"    --smooth           - Smooth the surface by regenerating surface normals on\n"
514                               "                         all geometry nodes"<< std::endl;
515     osg::notify(osg::NOTICE)<<"    --addMissingColors - Add a white color value to all geometry nodes\n"
516                               "                         that don't have their own color values\n"
517                               "                         (--addMissingColours also accepted)."<< std::endl;
518     osg::notify(osg::NOTICE)<<"    --overallNormal    - Replace normals with a single overall normal."<< std::endl;
519     osg::notify(osg::NOTICE)<<"    --enable-object-cache - Enable caching of objects, images, etc."<< std::endl;
520 
521     osg::notify( osg::NOTICE ) << std::endl;
522     osg::notify( osg::NOTICE ) <<
523         "    --formats          - List all supported formats and their supported options." << std::endl;
524     osg::notify( osg::NOTICE ) <<
525         "    --format <format>  - Display information about the specified <format>,\n"
526         "                         where <format> is the file extension, such as \"flt\"." << std::endl;
527     osg::notify( osg::NOTICE ) <<
528         "    --plugins          - List all supported plugin files." << std::endl;
529     osg::notify( osg::NOTICE ) <<
530         "    --plugin <plugin>  - Display information about the specified <plugin>,\n"
531         "                         where <plugin> is the plugin's full path and file name." << std::endl;
532 }
533 
534 
main(int argc,char ** argv)535 int main( int argc, char **argv )
536 {
537     // use an ArgumentParser object to manage the program arguments.
538     osg::ArgumentParser arguments(&argc,argv);
539 
540     // set up the usage document, in case we need to print out how to use this program.
541     arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName());
542     arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is a utility for converting between various input and output databases formats.");
543     arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
544     arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display command line parameters");
545     arguments.getApplicationUsage()->addCommandLineOption("--help-env","Display environmental variables available");
546     //arguments.getApplicationUsage()->addCommandLineOption("--formats","List supported file formats");
547     //arguments.getApplicationUsage()->addCommandLineOption("--plugins","List database olugins");
548 
549 
550     // if user request help write it out to cout.
551     if (arguments.read("-h") || arguments.read("--help"))
552     {
553         osg::setNotifyLevel(osg::NOTICE);
554         usage( arguments.getApplicationName().c_str(), 0 );
555         //arguments.getApplicationUsage()->write(std::cout);
556         return 1;
557     }
558 
559     if (arguments.read("--help-env"))
560     {
561         arguments.getApplicationUsage()->write(std::cout, osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE);
562         return 1;
563     }
564 
565     if (arguments.read("--plugins"))
566     {
567         osgDB::FileNameList plugins = osgDB::listAllAvailablePlugins();
568         for(osgDB::FileNameList::iterator itr = plugins.begin();
569             itr != plugins.end();
570             ++itr)
571         {
572             std::cout<<"Plugin "<<*itr<<std::endl;
573         }
574         return 0;
575     }
576 
577     std::string plugin;
578     if (arguments.read("--plugin", plugin))
579     {
580         osgDB::outputPluginDetails(std::cout, plugin);
581         return 0;
582     }
583 
584     std::string ext;
585     if (arguments.read("--format", ext))
586     {
587         plugin = osgDB::Registry::instance()->createLibraryNameForExtension(ext);
588         osgDB::outputPluginDetails(std::cout, plugin);
589         return 0;
590     }
591 
592     if (arguments.read("--formats"))
593     {
594         osgDB::FileNameList plugins = osgDB::listAllAvailablePlugins();
595         for(osgDB::FileNameList::iterator itr = plugins.begin();
596             itr != plugins.end();
597             ++itr)
598         {
599             osgDB::outputPluginDetails(std::cout,*itr);
600         }
601         return 0;
602     }
603 
604     if (arguments.argc()<=1)
605     {
606         arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION);
607         return 1;
608     }
609 
610     FileNameList fileNames;
611     OrientationConverter oc;
612     bool do_convert = false;
613 
614     if (arguments.read("--use-world-frame"))
615     {
616         oc.useWorldFrame(true);
617     }
618 
619     std::string str;
620     while (arguments.read("-O",str))
621     {
622         osgDB::ReaderWriter::Options* options = new osgDB::ReaderWriter::Options;
623         options->setOptionString(str);
624         osgDB::Registry::instance()->setOptions(options);
625     }
626 
627     while (arguments.read("-e",ext))
628     {
629         std::string libName = osgDB::Registry::instance()->createLibraryNameForExtension(ext);
630         if (osgDB::Registry::instance()->loadLibrary(libName)==osgDB::Registry::NOT_LOADED)
631         {
632             OSG_NOTICE<<"Unable to load library : "<<libName<<std::endl;
633         }
634     }
635 
636     std::string libName;
637     while (arguments.read("-l",libName))
638     {
639         if (osgDB::Registry::instance()->loadLibrary(libName)==osgDB::Registry::NOT_LOADED)
640         {
641             OSG_NOTICE<<"Unable to load library : "<<libName<<std::endl;
642         }
643     }
644 
645     while (arguments.read("-o",str))
646     {
647         osg::Vec3 from, to;
648         if( sscanf( str.c_str(), "%f,%f,%f-%f,%f,%f",
649                 &from[0], &from[1], &from[2],
650                 &to[0], &to[1], &to[2]  )
651             != 6 )
652         {
653             float degrees;
654             osg::Vec3 axis;
655             // Try deg-axis format
656             if( sscanf( str.c_str(), "%f-%f,%f,%f",
657                     &degrees, &axis[0], &axis[1], &axis[2]  ) != 4 )
658             {
659                 usage( argv[0], "Orientation argument format incorrect." );
660                 return 1;
661             }
662             else
663             {
664                 oc.setRotation( degrees, axis );
665                 do_convert = true;
666             }
667         }
668         else
669         {
670             oc.setRotation( from, to );
671             do_convert = true;
672         }
673     }
674 
675     while (arguments.read("-s",str))
676     {
677         osg::Vec3 scale(0,0,0);
678         if( sscanf( str.c_str(), "%f,%f,%f",
679                 &scale[0], &scale[1], &scale[2] ) != 3 )
680         {
681             usage( argv[0], "Scale argument format incorrect." );
682             return 1;
683         }
684         oc.setScale( scale );
685         do_convert = true;
686     }
687 
688     float simplifyPercent = 1.0;
689     bool do_simplify = false;
690     while ( arguments.read( "--simplify",str ) )
691     {
692         float nsimp = 1.0;
693         if( sscanf( str.c_str(), "%f",
694                 &nsimp ) != 1 )
695         {
696             usage( argv[0], "Scale argument format incorrect." );
697             return 1;
698         }
699         std::cout << str << " " << nsimp << std::endl;
700         simplifyPercent = nsimp;
701         osg::notify( osg::INFO ) << "Simplifying with percentage: " << simplifyPercent << std::endl;
702         do_simplify = true;
703     }
704 
705     while (arguments.read("-t",str))
706     {
707         osg::Vec3 trans(0,0,0);
708         if( sscanf( str.c_str(), "%f,%f,%f",
709                 &trans[0], &trans[1], &trans[2] ) != 3 )
710         {
711             usage( argv[0], "Translation argument format incorrect." );
712             return 1;
713         }
714         oc.setTranslation( trans );
715         do_convert = true;
716     }
717 
718 
719     FixTransparencyVisitor::FixTransparencyMode fixTransparencyMode = FixTransparencyVisitor::NO_TRANSPARANCY_FIXING;
720     std::string fixString;
721     while(arguments.read("--fix-transparency")) fixTransparencyMode = FixTransparencyVisitor::MAKE_OPAQUE_TEXTURE_STATESET_OPAQUE;
722     while(arguments.read("--fix-transparency-mode",fixString))
723     {
724          if (fixString=="MAKE_OPAQUE_TEXTURE_STATESET_OPAQUE") fixTransparencyMode = FixTransparencyVisitor::MAKE_OPAQUE_TEXTURE_STATESET_OPAQUE;
725          if (fixString=="MAKE_ALL_STATESET_OPAQUE") fixTransparencyMode = FixTransparencyVisitor::MAKE_ALL_STATESET_OPAQUE;
726     };
727 
728     bool pruneStateSet = false;
729     while(arguments.read("--prune-StateSet")) pruneStateSet = true;
730 
731     osg::Texture::InternalFormatMode internalFormatMode = osg::Texture::USE_IMAGE_DATA_FORMAT;
732     while(arguments.read("--compressed") || arguments.read("--compressed-arb")) { internalFormatMode = osg::Texture::USE_ARB_COMPRESSION; }
733 
734     while(arguments.read("--compressed-dxt1")) { internalFormatMode = osg::Texture::USE_S3TC_DXT1_COMPRESSION; }
735     while(arguments.read("--compressed-dxt3")) { internalFormatMode = osg::Texture::USE_S3TC_DXT3_COMPRESSION; }
736     while(arguments.read("--compressed-dxt5")) { internalFormatMode = osg::Texture::USE_S3TC_DXT5_COMPRESSION; }
737 
738     bool smooth = false;
739     while(arguments.read("--smooth")) { smooth = true; }
740 
741     bool addMissingColours = false;
742     while(arguments.read("--addMissingColours") || arguments.read("--addMissingColors")) { addMissingColours = true; }
743 
744     bool do_overallNormal = false;
745     while(arguments.read("--overallNormal")) { do_overallNormal = true; }
746 
747     bool enableObjectCache = false;
748     while(arguments.read("--enable-object-cache")) { enableObjectCache = true; }
749 
750     // any option left unread are converted into errors to write out later.
751     arguments.reportRemainingOptionsAsUnrecognized();
752 
753     // report any errors if they have occurred when parsing the program arguments.
754     if (arguments.errors())
755     {
756         arguments.writeErrorMessages(std::cout);
757         return 1;
758     }
759 
760     for(int pos=1;pos<arguments.argc();++pos)
761     {
762         if (!arguments.isOption(pos))
763         {
764             fileNames.push_back(arguments[pos]);
765         }
766     }
767 
768     if (enableObjectCache)
769     {
770         if (osgDB::Registry::instance()->getOptions()==0) osgDB::Registry::instance()->setOptions(new osgDB::Options());
771         osgDB::Registry::instance()->getOptions()->setObjectCacheHint(osgDB::Options::CACHE_ALL);
772     }
773 
774     std::string fileNameOut("converted.osgt");
775     if (fileNames.size()>1)
776     {
777         fileNameOut = fileNames.back();
778         fileNames.pop_back();
779     }
780 
781     osg::Timer_t startTick = osg::Timer::instance()->tick();
782 
783     typedef std::vector< osg::ref_ptr<osg::Image> > Images;
784     typedef std::vector< osg::ref_ptr<osg::Node> > Nodes;
785     typedef std::vector< osg::ref_ptr<osg::Object> > Objects;
786 
787     Images images;
788     Nodes nodes;
789     Objects objects;
790 
791     for(FileNameList::iterator itr = fileNames.begin();
792         itr != fileNames.end();
793         ++itr)
794     {
795         osg::ref_ptr<osg::Object> object = osgDB::readObjectFile(*itr);
796         if (object.valid())
797         {
798             if (object->asNode()) nodes.push_back(object->asNode());
799             else if (object->asImage()) images.push_back(object->asImage());
800             else objects.push_back(object);
801         }
802     }
803 
804     if (images.empty() && nodes.empty() && objects.empty())
805     {
806         osg::notify(osg::NOTICE)<<"Warning: failed to load any files"<<std::endl;
807         return 1;
808     }
809 
810 
811     osg::Timer_t endTick = osg::Timer::instance()->tick();
812     osg::notify(osg::INFO)<<"Time to load files "<<osg::Timer::instance()->delta_m(startTick, endTick)<<" ms"<<std::endl;
813 
814     osg::ref_ptr<osg::Node> root;
815 
816     if (nodes.size()==1) root = nodes.front();
817     else if (nodes.size()>1)
818     {
819         osg::ref_ptr<osg::Group> group = new osg::Group;
820         for(Nodes::iterator itr = nodes.begin();
821             itr != nodes.end();
822             ++itr)
823         {
824             group->addChild(itr->get());
825         }
826 
827         root = group;
828     }
829 
830     if ( root.valid() )
831     {
832         if (pruneStateSet)
833         {
834             PruneStateSetVisitor pssv;
835             root->accept(pssv);
836         }
837 
838         if (fixTransparencyMode != FixTransparencyVisitor::NO_TRANSPARANCY_FIXING)
839         {
840             FixTransparencyVisitor atv(fixTransparencyMode);
841             root->accept(atv);
842         }
843 
844         if (smooth)
845         {
846             osgUtil::SmoothingVisitor sv;
847             root->accept(sv);
848         }
849 
850         if (addMissingColours)
851         {
852             AddMissingColoursToGeometryVisitor av;
853             root->accept(av);
854         }
855 
856         // optimize the scene graph, remove redundant nodes and state etc.
857         osgUtil::Optimizer optimizer;
858         optimizer.optimize(root.get());
859 
860         if( do_convert )
861             root = oc.convert( root.get() );
862 
863         if (internalFormatMode != osg::Texture::USE_IMAGE_DATA_FORMAT)
864         {
865             ext = osgDB::getFileExtension(fileNameOut);
866             CompressTexturesVisitor ctv(internalFormatMode);
867             root->accept(ctv);
868             ctv.compress();
869 
870             osgDB::ReaderWriter::Options *options = osgDB::Registry::instance()->getOptions();
871             if (ext!="ive" || (options && options->getOptionString().find("noTexturesInIVEFile")!=std::string::npos))
872             {
873                 ctv.write(osgDB::getFilePath(fileNameOut));
874             }
875         }
876 
877         // scrub normals
878         if ( do_overallNormal )
879         {
880             DefaultNormalsGeometryVisitor dngv;
881             root->accept( dngv );
882         }
883 
884         // apply any user-specified simplification
885         if ( do_simplify )
886         {
887             osgUtil::Simplifier simple;
888             simple.setSmoothing( smooth );
889             osg::notify( osg::ALWAYS ) << " smoothing: " << smooth << std::endl;
890             simple.setSampleRatio( simplifyPercent );
891             root->accept( simple );
892         }
893 
894         osgDB::ReaderWriter::WriteResult result = osgDB::Registry::instance()->writeNode(*root,fileNameOut,osgDB::Registry::instance()->getOptions());
895         if (result.success())
896         {
897             osg::notify(osg::NOTICE)<<"Data written to '"<<fileNameOut<<"'."<< std::endl;
898         }
899         else if  (result.message().empty())
900         {
901             osg::notify(osg::NOTICE)<<"Warning: file write to '"<<fileNameOut<<"' not supported."<< std::endl;
902         }
903         else
904         {
905             osg::notify(osg::NOTICE)<<result.message()<< std::endl;
906         }
907     }
908     else if (!images.empty())
909     {
910         if (images.size()>1)
911         {
912             OSG_NOTICE<<"Warning: osgconv does not support writing multiple to a single file."<<std::endl;
913             return 1;
914         }
915 
916         osgDB::writeImageFile(*images.front(), fileNameOut);
917     }
918     else if (!objects.empty())
919     {
920         osgDB::writeObjectFile(*images.front(), fileNameOut);
921     }
922     else
923     {
924         osg::notify(osg::NOTICE)<<"Error no data loaded."<< std::endl;
925         return 1;
926     }
927 
928     return 0;
929 }
930