| 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/Geometry> |
|---|
| 9 | #include <osg/Texture2D> |
|---|
| 10 | |
|---|
| 11 | #include <osgDB/Registry> |
|---|
| 12 | #include <osgDB/ReadFile> |
|---|
| 13 | #include <osgDB/WriteFile> |
|---|
| 14 | #include <osgDB/FileNameUtils> |
|---|
| 15 | #include <osgDB/ReaderWriter> |
|---|
| 16 | |
|---|
| 17 | #include <osgUtil/Optimizer> |
|---|
| 18 | |
|---|
| 19 | #include <osgProducer/Viewer> |
|---|
| 20 | |
|---|
| 21 | #include <iostream> |
|---|
| 22 | |
|---|
| 23 | #include "OrientationConverter.h" |
|---|
| 24 | #include "GeoSet.h" |
|---|
| 25 | |
|---|
| 26 | typedef std::vector<std::string> FileNameList; |
|---|
| 27 | |
|---|
| 28 | |
|---|
| 29 | |
|---|
| 30 | |
|---|
| 31 | |
|---|
| 32 | |
|---|
| 33 | |
|---|
| 34 | class ConvertGeoSetsToGeometryVisitor : public osg::NodeVisitor |
|---|
| 35 | { |
|---|
| 36 | public: |
|---|
| 37 | |
|---|
| 38 | ConvertGeoSetsToGeometryVisitor():osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {} |
|---|
| 39 | |
|---|
| 40 | virtual void apply(osg::Geode& geode) |
|---|
| 41 | { |
|---|
| 42 | for(unsigned int i=0;i<geode.getNumDrawables();++i) |
|---|
| 43 | { |
|---|
| 44 | osg::GeoSet* geoset = dynamic_cast<osg::GeoSet*>(geode.getDrawable(i)); |
|---|
| 45 | if (geoset) |
|---|
| 46 | { |
|---|
| 47 | osg::Geometry* geom = geoset->convertToGeometry(); |
|---|
| 48 | if (geom) |
|---|
| 49 | { |
|---|
| 50 | osg::notify(osg::NOTICE)<<"Successfully converted GeoSet to Geometry"<<std::endl; |
|---|
| 51 | geode.replaceDrawable(geoset,geom); |
|---|
| 52 | } |
|---|
| 53 | else |
|---|
| 54 | { |
|---|
| 55 | osg::notify(osg::NOTICE)<<"*** Failed to convert GeoSet to Geometry"<<std::endl; |
|---|
| 56 | } |
|---|
| 57 | |
|---|
| 58 | } |
|---|
| 59 | } |
|---|
| 60 | } |
|---|
| 61 | |
|---|
| 62 | virtual void apply(osg::Node& node) { traverse(node); } |
|---|
| 63 | |
|---|
| 64 | }; |
|---|
| 65 | |
|---|
| 66 | class GraphicsContext { |
|---|
| 67 | public: |
|---|
| 68 | GraphicsContext() |
|---|
| 69 | { |
|---|
| 70 | rs = new Producer::RenderSurface; |
|---|
| 71 | rs->setWindowRectangle(0,0,1,1); |
|---|
| 72 | rs->useBorder(false); |
|---|
| 73 | rs->useConfigEventThread(false); |
|---|
| 74 | rs->realize(); |
|---|
| 75 | std::cout<<"Realized window"<<std::endl; |
|---|
| 76 | } |
|---|
| 77 | |
|---|
| 78 | virtual ~GraphicsContext() |
|---|
| 79 | { |
|---|
| 80 | } |
|---|
| 81 | |
|---|
| 82 | private: |
|---|
| 83 | Producer::ref_ptr<Producer::RenderSurface> rs; |
|---|
| 84 | }; |
|---|
| 85 | |
|---|
| 86 | class CompressTexturesVisitor : public osg::NodeVisitor |
|---|
| 87 | { |
|---|
| 88 | public: |
|---|
| 89 | |
|---|
| 90 | CompressTexturesVisitor():osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {} |
|---|
| 91 | |
|---|
| 92 | virtual void apply(osg::Node& node) |
|---|
| 93 | { |
|---|
| 94 | if (node.getStateSet()) apply(*node.getStateSet()); |
|---|
| 95 | traverse(node); |
|---|
| 96 | } |
|---|
| 97 | |
|---|
| 98 | virtual void apply(osg::Geode& node) |
|---|
| 99 | { |
|---|
| 100 | if (node.getStateSet()) apply(*node.getStateSet()); |
|---|
| 101 | |
|---|
| 102 | for(unsigned int i=0;i<node.getNumDrawables();++i) |
|---|
| 103 | { |
|---|
| 104 | osg::Drawable* drawable = node.getDrawable(i); |
|---|
| 105 | if (drawable && drawable->getStateSet()) apply(*drawable->getStateSet()); |
|---|
| 106 | } |
|---|
| 107 | |
|---|
| 108 | traverse(node); |
|---|
| 109 | } |
|---|
| 110 | |
|---|
| 111 | virtual void apply(osg::StateSet& stateset) |
|---|
| 112 | { |
|---|
| 113 | |
|---|
| 114 | for(unsigned int i=0;i<stateset.getTextureAttributeList().size();++i) |
|---|
| 115 | { |
|---|
| 116 | osg::Texture2D* texture = dynamic_cast<osg::Texture2D*>(stateset.getTextureAttribute(i,osg::StateAttribute::TEXTURE)); |
|---|
| 117 | if (texture) |
|---|
| 118 | { |
|---|
| 119 | _textureSet.insert(texture); |
|---|
| 120 | } |
|---|
| 121 | } |
|---|
| 122 | } |
|---|
| 123 | |
|---|
| 124 | void compress() |
|---|
| 125 | { |
|---|
| 126 | GraphicsContext context; |
|---|
| 127 | |
|---|
| 128 | osg::ref_ptr<osg::State> state = new osg::State; |
|---|
| 129 | |
|---|
| 130 | for(TextureSet::iterator itr=_textureSet.begin(); |
|---|
| 131 | itr!=_textureSet.end(); |
|---|
| 132 | ++itr) |
|---|
| 133 | { |
|---|
| 134 | osg::Texture2D* texture = const_cast<osg::Texture2D*>(itr->get()); |
|---|
| 135 | osg::Image* image = texture->getImage(); |
|---|
| 136 | if (image && |
|---|
| 137 | (image->getPixelFormat()==GL_RGB || image->getPixelFormat()==GL_RGBA) && |
|---|
| 138 | (image->s()>=32 && image->t()>=32)) |
|---|
| 139 | { |
|---|
| 140 | texture->setInternalFormatMode(osg::Texture::USE_S3TC_DXT3_COMPRESSION); |
|---|
| 141 | |
|---|
| 142 | |
|---|
| 143 | texture->apply(*state); |
|---|
| 144 | |
|---|
| 145 | image->readImageFromCurrentTexture(0,true); |
|---|
| 146 | |
|---|
| 147 | texture->setInternalFormatMode(osg::Texture::USE_IMAGE_DATA_FORMAT); |
|---|
| 148 | } |
|---|
| 149 | } |
|---|
| 150 | } |
|---|
| 151 | |
|---|
| 152 | typedef std::set< osg::ref_ptr<osg::Texture2D> > TextureSet; |
|---|
| 153 | TextureSet _textureSet; |
|---|
| 154 | |
|---|
| 155 | |
|---|
| 156 | }; |
|---|
| 157 | |
|---|
| 158 | |
|---|
| 159 | static void usage( const char *prog, const char *msg ) |
|---|
| 160 | { |
|---|
| 161 | if (msg) |
|---|
| 162 | { |
|---|
| 163 | osg::notify(osg::NOTICE)<< std::endl; |
|---|
| 164 | osg::notify(osg::NOTICE) << msg << std::endl; |
|---|
| 165 | } |
|---|
| 166 | osg::notify(osg::NOTICE)<< std::endl; |
|---|
| 167 | osg::notify(osg::NOTICE)<<"usage:"<< std::endl; |
|---|
| 168 | osg::notify(osg::NOTICE)<<" " << prog << " [options] infile1 [infile2 ...] outfile"<< std::endl; |
|---|
| 169 | osg::notify(osg::NOTICE)<< std::endl; |
|---|
| 170 | osg::notify(osg::NOTICE)<<"options:"<< std::endl; |
|---|
| 171 | osg::notify(osg::NOTICE)<<" -O option - ReaderWriter option"<< std::endl; |
|---|
| 172 | osg::notify(osg::NOTICE)<<" --compressed - Compress textures."<< std::endl; |
|---|
| 173 | osg::notify(osg::NOTICE)<<" -l libraryName - load plugin of name libraryName"<< std::endl; |
|---|
| 174 | osg::notify(osg::NOTICE)<<" i.e. -l osgdb_pfb"<< std::endl; |
|---|
| 175 | osg::notify(osg::NOTICE)<<" Useful for loading reader/writers which can load"<< std::endl; |
|---|
| 176 | osg::notify(osg::NOTICE)<<" other file formats in addition to its extension."<< std::endl; |
|---|
| 177 | osg::notify(osg::NOTICE)<<" -e extensionName - load reader/wrter plugin for file extension"<< std::endl; |
|---|
| 178 | osg::notify(osg::NOTICE)<<" i.e. -e pfb"<< std::endl; |
|---|
| 179 | osg::notify(osg::NOTICE)<<" Useful short hand for specifying full library name as"<< std::endl; |
|---|
| 180 | osg::notify(osg::NOTICE)<<" done with -l above, as it automatically expands to the"<< std::endl; |
|---|
| 181 | osg::notify(osg::NOTICE)<<" full library name appropriate for each platform."<< std::endl; |
|---|
| 182 | osg::notify(osg::NOTICE)<<" -o orientation - Convert geometry from input files to output files."<< std::endl; |
|---|
| 183 | osg::notify(osg::NOTICE)<< |
|---|
| 184 | " Format of orientation argument must be the following:\n" |
|---|
| 185 | "\n" |
|---|
| 186 | " X1,Y1,Z1-X2,Y2,Z2\n" |
|---|
| 187 | " or\n" |
|---|
| 188 | " degrees-A0,A1,A2\n" |
|---|
| 189 | "\n" |
|---|
| 190 | " where X1,Y1,Z1 represent the UP vector in the input\n" |
|---|
| 191 | " files and X2,Y2,Z2 represent the UP vector of the\n" |
|---|
| 192 | " output file, or degrees is the rotation angle in degrees\n" |
|---|
| 193 | " around axis (A0,A1,A2). For example, to convert a model\n" |
|---|
| 194 | " built in a Y-Up coordinate system to a model with a Z-up\n" |
|---|
| 195 | " coordinate system, the argument may look like\n" |
|---|
| 196 | "\n" |
|---|
| 197 | " 0,1,0-0,0,1" |
|---|
| 198 | "\n" |
|---|
| 199 | " or\n" |
|---|
| 200 | " -90-1,0,0\n" |
|---|
| 201 | "\n" << std::endl; |
|---|
| 202 | osg::notify(osg::NOTICE)<<" -t translation - Convert spatial position of output files. Format of\n" |
|---|
| 203 | " translation argument must be the following :\n" |
|---|
| 204 | "\n" |
|---|
| 205 | " X,Y,Z\n" |
|---|
| 206 | "\n" |
|---|
| 207 | " where X, Y, and Z represent the coordinates of the\n" |
|---|
| 208 | " absolute position in world space\n" |
|---|
| 209 | << std::endl; |
|---|
| 210 | osg::notify(osg::NOTICE)<<" -s scale - Scale size of model. Scale argument must be the \n" |
|---|
| 211 | " following :\n" |
|---|
| 212 | "\n" |
|---|
| 213 | " SX,SY,SZ\n" |
|---|
| 214 | "\n" |
|---|
| 215 | " where SX, SY, and SZ represent the scale factors\n" |
|---|
| 216 | " Caution: Scaling will be done in destination orientation\n" |
|---|
| 217 | << std::endl; |
|---|
| 218 | } |
|---|
| 219 | |
|---|
| 220 | |
|---|
| 221 | int main( int argc, char **argv ) |
|---|
| 222 | { |
|---|
| 223 | |
|---|
| 224 | osg::ArgumentParser arguments(&argc,argv); |
|---|
| 225 | |
|---|
| 226 | |
|---|
| 227 | arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName()); |
|---|
| 228 | arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the standard OpenSceneGraph example which loads and visualises 3d models."); |
|---|
| 229 | arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ..."); |
|---|
| 230 | |
|---|
| 231 | |
|---|
| 232 | if (arguments.read("-h") || arguments.read("--help")) |
|---|
| 233 | { |
|---|
| 234 | usage( arguments.getApplicationName().c_str(), 0 ); |
|---|
| 235 | |
|---|
| 236 | return 1; |
|---|
| 237 | } |
|---|
| 238 | |
|---|
| 239 | |
|---|
| 240 | if (arguments.argc()<=1) |
|---|
| 241 | { |
|---|
| 242 | arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION); |
|---|
| 243 | return 1; |
|---|
| 244 | } |
|---|
| 245 | |
|---|
| 246 | FileNameList fileNames; |
|---|
| 247 | OrientationConverter oc; |
|---|
| 248 | bool do_convert = false; |
|---|
| 249 | bool compressTextures = false; |
|---|
| 250 | |
|---|
| 251 | std::string str; |
|---|
| 252 | while (arguments.read("-O",str)) |
|---|
| 253 | { |
|---|
| 254 | osgDB::ReaderWriter::Options* options = new osgDB::ReaderWriter::Options; |
|---|
| 255 | options->setOptionString(str); |
|---|
| 256 | osgDB::Registry::instance()->setOptions(options); |
|---|
| 257 | } |
|---|
| 258 | |
|---|
| 259 | std::string ext; |
|---|
| 260 | while (arguments.read("-e",ext)) |
|---|
| 261 | { |
|---|
| 262 | std::string libName = osgDB::Registry::instance()->createLibraryNameForExtension(ext); |
|---|
| 263 | osgDB::Registry::instance()->loadLibrary(libName); |
|---|
| 264 | } |
|---|
| 265 | |
|---|
| 266 | std::string libName; |
|---|
| 267 | while (arguments.read("-l",libName)) |
|---|
| 268 | { |
|---|
| 269 | osgDB::Registry::instance()->loadLibrary(libName); |
|---|
| 270 | } |
|---|
| 271 | #if 0 |
|---|
| 272 | |
|---|
| 273 | if( nexti < argc ) |
|---|
| 274 | { |
|---|
| 275 | osg::Vec3 scale(0,0,0); |
|---|
| 276 | if( sscanf( argv[nexti++], "%f,%f,%f", |
|---|
| 277 | &scale[0], &scale[1], &scale[2] ) != 3 ) |
|---|
| 278 | { |
|---|
| 279 | usage( argv[0], "Scale argument format incorrect." ); |
|---|
| 280 | return false; |
|---|
| 281 | } |
|---|
| 282 | oc.setScale( scale ); |
|---|
| 283 | do_convert = true; |
|---|
| 284 | } |
|---|
| 285 | else |
|---|
| 286 | { |
|---|
| 287 | usage( argv[0], "Scale conversion option requires an argument." ); |
|---|
| 288 | return false; |
|---|
| 289 | } |
|---|
| 290 | break; |
|---|
| 291 | #endif |
|---|
| 292 | |
|---|
| 293 | while (arguments.read("-o",str)) |
|---|
| 294 | { |
|---|
| 295 | osg::Vec3 from, to; |
|---|
| 296 | if( sscanf( str.c_str(), "%f,%f,%f-%f,%f,%f", |
|---|
| 297 | &from[0], &from[1], &from[2], |
|---|
| 298 | &to[0], &to[1], &to[2] ) |
|---|
| 299 | != 6 ) |
|---|
| 300 | { |
|---|
| 301 | float degrees; |
|---|
| 302 | osg::Vec3 axis; |
|---|
| 303 | |
|---|
| 304 | if( sscanf( str.c_str(), "%f-%f,%f,%f", |
|---|
| 305 | °rees, &axis[0], &axis[1], &axis[2] ) != 4 ) |
|---|
| 306 | { |
|---|
| 307 | usage( argv[0], "Orientation argument format incorrect." ); |
|---|
| 308 | return 1; |
|---|
| 309 | } |
|---|
| 310 | else |
|---|
| 311 | { |
|---|
| 312 | oc.setRotation( degrees, axis ); |
|---|
| 313 | do_convert = true; |
|---|
| 314 | } |
|---|
| 315 | } |
|---|
| 316 | else |
|---|
| 317 | { |
|---|
| 318 | oc.setRotation( from, to ); |
|---|
| 319 | do_convert = true; |
|---|
| 320 | } |
|---|
| 321 | } |
|---|
| 322 | |
|---|
| 323 | while (arguments.read("-s",str)) |
|---|
| 324 | { |
|---|
| 325 | osg::Vec3 scale(0,0,0); |
|---|
| 326 | if( sscanf( str.c_str(), "%f,%f,%f", |
|---|
| 327 | &scale[0], &scale[1], &scale[2] ) != 3 ) |
|---|
| 328 | { |
|---|
| 329 | usage( argv[0], "Scale argument format incorrect." ); |
|---|
| 330 | return 1; |
|---|
| 331 | } |
|---|
| 332 | oc.setScale( scale ); |
|---|
| 333 | do_convert = true; |
|---|
| 334 | } |
|---|
| 335 | |
|---|
| 336 | while (arguments.read("-t",str)) |
|---|
| 337 | { |
|---|
| 338 | osg::Vec3 trans(0,0,0); |
|---|
| 339 | if( sscanf( str.c_str(), "%f,%f,%f", |
|---|
| 340 | &trans[0], &trans[1], &trans[2] ) != 3 ) |
|---|
| 341 | { |
|---|
| 342 | usage( argv[0], "Translation argument format incorrect." ); |
|---|
| 343 | return 1; |
|---|
| 344 | } |
|---|
| 345 | oc.setTranslation( trans ); |
|---|
| 346 | do_convert = true; |
|---|
| 347 | } |
|---|
| 348 | |
|---|
| 349 | |
|---|
| 350 | while (arguments.read("--compressed")) |
|---|
| 351 | { |
|---|
| 352 | compressTextures = true; |
|---|
| 353 | } |
|---|
| 354 | |
|---|
| 355 | |
|---|
| 356 | arguments.reportRemainingOptionsAsUnrecognized(); |
|---|
| 357 | |
|---|
| 358 | |
|---|
| 359 | if (arguments.errors()) |
|---|
| 360 | { |
|---|
| 361 | arguments.writeErrorMessages(std::cout); |
|---|
| 362 | return 1; |
|---|
| 363 | } |
|---|
| 364 | |
|---|
| 365 | for(int pos=1;pos<arguments.argc();++pos) |
|---|
| 366 | { |
|---|
| 367 | if (!arguments.isOption(pos)) |
|---|
| 368 | { |
|---|
| 369 | fileNames.push_back(arguments[pos]); |
|---|
| 370 | } |
|---|
| 371 | } |
|---|
| 372 | |
|---|
| 373 | |
|---|
| 374 | std::string fileNameOut("converted.osg"); |
|---|
| 375 | if (fileNames.size()>1) |
|---|
| 376 | { |
|---|
| 377 | fileNameOut = fileNames.back(); |
|---|
| 378 | fileNames.pop_back(); |
|---|
| 379 | } |
|---|
| 380 | |
|---|
| 381 | osg::ref_ptr<osg::Node> root = osgDB::readNodeFiles(fileNames); |
|---|
| 382 | |
|---|
| 383 | if ( root.valid() ) |
|---|
| 384 | { |
|---|
| 385 | |
|---|
| 386 | ConvertGeoSetsToGeometryVisitor cgtg; |
|---|
| 387 | if( root.valid() ) root->accept(cgtg); |
|---|
| 388 | |
|---|
| 389 | |
|---|
| 390 | osgUtil::Optimizer optimizer; |
|---|
| 391 | optimizer.optimize(root.get()); |
|---|
| 392 | |
|---|
| 393 | if( do_convert ) |
|---|
| 394 | root = oc.convert( root.get() ); |
|---|
| 395 | |
|---|
| 396 | if (compressTextures) |
|---|
| 397 | { |
|---|
| 398 | std::string ext = osgDB::getFileExtension(fileNameOut); |
|---|
| 399 | if (ext=="ive") |
|---|
| 400 | { |
|---|
| 401 | CompressTexturesVisitor ctv; |
|---|
| 402 | root->accept(ctv); |
|---|
| 403 | ctv.compress(); |
|---|
| 404 | } |
|---|
| 405 | else |
|---|
| 406 | { |
|---|
| 407 | std::cout<<"Warning: compressing texture only supported when outputing to .ive"<<std::endl; |
|---|
| 408 | } |
|---|
| 409 | } |
|---|
| 410 | |
|---|
| 411 | if (osgDB::writeNodeFile(*root,fileNameOut)) |
|---|
| 412 | { |
|---|
| 413 | osg::notify(osg::NOTICE)<<"Data written to '"<<fileNameOut<<"'."<< std::endl; |
|---|
| 414 | } |
|---|
| 415 | } |
|---|
| 416 | else |
|---|
| 417 | { |
|---|
| 418 | osg::notify(osg::NOTICE)<<"Error no data loaded."<< std::endl; |
|---|
| 419 | return 1; |
|---|
| 420 | } |
|---|
| 421 | |
|---|
| 422 | return 0; |
|---|
| 423 | } |
|---|