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 °rees, &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