Chris 'Xenon' Hanson wrote:
> I could refactor this so that recursive osgconv can move forward without
> pseudoloader
> suffix support. My latest suffix-support proposal in "PagedLOD/ProxyNode
> design
> discussion" would have a getCombinedFileName() method, so maybe we should
> decide that
> issue first, and osgconv would basically slide in right afterward.
Ok, here is an osgconv that incorporates the recursion feature and does not
require any
changes to PagedLOD/ProxyNode to function.
--
Chris 'Xenon' Hanson, omo sanza lettere Xenon AlphaPixel.com
PixelSense Landsat processing now available! http://www.alphapixel.com/demos/
"There is no Truth. There is only Perception. To Perceive is to Exist." - Xen
#include <stdio.h>
#include <queue>
#include <osg/ArgumentParser>
#include <osg/ApplicationUsage>
#include <osg/Group>
#include <osg/Notify>
#include <osg/Vec3>
#include <osg/ProxyNode>
#include <osg/Geometry>
#include <osg/Texture2D>
#include <osg/Texture3D>
#include <osg/BlendFunc>
#include <osg/Timer>
#include <osgDB/Registry>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osgDB/FileNameUtils>
#include <osgDB/FileUtils>
#include <osgDB/ReaderWriter>
#include <osgDB/PluginQuery>
#include <osgUtil/Optimizer>
#include <osgUtil/Simplifier>
#include <osgUtil/SmoothingVisitor>
#include <osgViewer/GraphicsWindow>
#include <osgViewer/Version>
#include <iostream>
#include "OrientationConverter.h"
typedef std::vector<std::string> FileNameList;
class ConvertBatch {
public:
void setInputBasePath(const std::string newInputBasePath)
{inputBasePath = newInputBasePath;}
void addInputFileName(const std::string newInputFileName)
{inputNames.push_back(newInputFileName);}
void setOutputPath(const std::string newOutputPath) {outputPath =
newOutputPath;}
void setOutputFileName(const std::string newOutputFileName, const
std::string optionalSuffix = "", bool stripAllExtensions = true)
{
std::string outNameWork = newOutputFileName; // make a
modifiable copy
// replace extension/suffix if needed
if(!optionalSuffix.empty())
{
outNameWork = osgDB::getNameLessExtension(outNameWork);
// take off the extension
if(stripAllExtensions)
{
while(!osgDB::getFileExtension(outNameWork).empty())
{
outNameWork =
osgDB::getNameLessExtension(outNameWork); // take off remaining extension
} // while
} // if
outNameWork += optionalSuffix; // append new
suffix/extension
} // if
outputFileName = outNameWork;
}
// ensure folder isn't already in set to simplify processing later
void addFolderToCreate(const std::string newFolderToCreate)
{
// is the new value NOT in the set yet?
if(find(foldersToCreate.begin(), foldersToCreate.end(),
newFolderToCreate) == foldersToCreate.end())
{
foldersToCreate.push_back(newFolderToCreate);
} // if not in set
}
std::string removeInputFromBack(void) {const std::string result =
inputNames.back(); inputNames.pop_back(); return(result);} // I don't think
this can be done any cleaner
std::string getOutputFileName(void) const {return(outputFileName);}
std::string getOutputPath(void) const {return(outputPath);}
std::string getInputBasePath(void) const {return(inputBasePath);}
std::string inputBasePath;
FileNameList inputNames;
std::string outputPath;
std::string outputFileName;
FileNameList foldersToCreate;
}; // ConvertBatch
typedef std::queue<ConvertBatch> ConvertQueue;
class MyGraphicsContext {
public:
MyGraphicsContext()
{
osg::ref_ptr<osg::GraphicsContext::Traits> traits = new
osg::GraphicsContext::Traits;
traits->x = 0;
traits->y = 0;
traits->width = 1;
traits->height = 1;
traits->windowDecoration = false;
traits->doubleBuffer = false;
traits->sharedContext = 0;
traits->pbuffer = true;
_gc = osg::GraphicsContext::createGraphicsContext(traits.get());
if (!_gc)
{
osg::notify(osg::NOTICE)<<"Failed to create pbuffer, failing
back to normal graphics window."<<std::endl;
traits->pbuffer = false;
_gc = osg::GraphicsContext::createGraphicsContext(traits.get());
}
if (_gc.valid())
{
_gc->realize();
_gc->makeCurrent();
if (dynamic_cast<osgViewer::GraphicsWindow*>(_gc.get()))
{
std::cout<<"Realized graphics window for OpenGL
operations."<<std::endl;
}
else
{
std::cout<<"Realized pbuffer for OpenGL
operations."<<std::endl;
}
}
}
bool valid() const { return _gc.valid() && _gc->isRealized(); }
private:
osg::ref_ptr<osg::GraphicsContext> _gc;
};
class RecursiveConversionVisitor
: public osg::NodeVisitor
{
public:
RecursiveConversionVisitor(ConvertQueue &masterConversionSet, std::string
parentFileInputFolderPath, std::string parentFileOutputFolderPath, std::string
baseNameSuffix)
: osg::NodeVisitor( osg::NodeVisitor::TRAVERSE_ALL_CHILDREN ),
_masterConversionSet(masterConversionSet),
_parentFileInputFolderPath(parentFileInputFolderPath),
_parentFileOutputFolderPath(parentFileOutputFolderPath),
_baseNameSuffix(baseNameSuffix) {
}
virtual void apply( osg::ProxyNode & Node )
{
osg::notify(osg::DEBUG_INFO) << "RecursiveConversionVisitor
ProxyNode DatabasePath=" << Node.getDatabasePath() << std::endl;
osg::notify(osg::DEBUG_INFO) << " Children=" <<
Node.getNumFileNames() << std::endl;
// The DatabasePath must be cleared during a recursive convert
otherwise
// it will embed a hard, fully-rooted path into the output
file, making it
// non-portable
Node.setDatabasePath("");
// we're not allowed to mess with the
FileNameDatabaseRequestList object so we iterate by subscript
for(unsigned int childLoop=0; childLoop<Node.getNumFileNames();
childLoop++)
{
const std::string childFileName =
Node.getFileName(childLoop);
if(!childFileName.empty())
{
osg::notify(osg::DEBUG_INFO) << " Adding child
" << childLoop << ": " << childFileName << std::endl;
// add this child file to the list of dependent
input filenames yet to convert
ConvertBatch dependentFileNameList;
dependentFileNameList.addInputFileName(childFileName); // only add one filename
to the convert batch
const std::string childBaseName =
osgDB::getSimpleFileName(childFileName); // just the filename, no path
// set input path
dependentFileNameList.setInputBasePath(_parentFileInputFolderPath); // load
dependents relative to their parent
// determine if input file had a path portion
std::string childFolderName =
osgDB::concatPaths(_parentFileOutputFolderPath,
osgDB::getFilePath(childFileName)); // combine parent-output path with child's
input path
// set output path
dependentFileNameList.setOutputPath(childFolderName);
// set output name
dependentFileNameList.setOutputFileName(childBaseName, _baseNameSuffix); //
apply suffix modification while adding output filename
// apply possible suffix name change to
original node here
const std::string originalNodePath =
osgDB::getFilePath(childFileName); // preserve original path
// combine original path and suffix-modified
output filename
Node.setFileName(childLoop,
osgDB::concatPaths(originalNodePath,
dependentFileNameList.getOutputFileName()));
// if this child is in a subfolder of some
sort, add the folder to the list of folders to create
osg::notify(osg::DEBUG_INFO) << " Adding child
folder: " << childFolderName << std::endl;
dependentFileNameList.addFolderToCreate(childFolderName);
_masterConversionSet.push(dependentFileNameList); // add the
dependentFileNameList to the queue-of-FileNameLists (which adds a copy)
} // if
} // for
} // apply proxyNode
virtual void apply( osg::PagedLOD & Node )
{
osg::notify(osg::DEBUG_INFO) << "RecursiveConversionVisitor
PagedLOD DatabasePath=" << Node.getDatabasePath() << std::endl;
osg::notify(osg::DEBUG_INFO) << " Children=" <<
Node.getNumFileNames() << std::endl;
// The DatabasePath must be cleared during a recursive convert
otherwise
// it will embed a hard, fully-rooted path into the output
file, making it
// non-portable
Node.setDatabasePath("");
// we're not allowed to mess with the PerRangeData object so we
iterate by subscript
// entire loop copied from Proxynode, above
for(unsigned int childLoop=0; childLoop<Node.getNumFileNames();
childLoop++)
{
const std::string childFileName =
Node.getFileName(childLoop);
if(!childFileName.empty())
{
osg::notify(osg::DEBUG_INFO) << " Adding child
" << childLoop << ": " << childFileName << std::endl;
// add this child file to the list of dependent
input filenames yet to convert
ConvertBatch dependentFileNameList;
dependentFileNameList.addInputFileName(childFileName); // only add one filename
to the convert batch
const std::string childBaseName =
osgDB::getSimpleFileName(childFileName); // just the filename, no path
// set input path
dependentFileNameList.setInputBasePath(_parentFileInputFolderPath); // load
dependents relative to their parent
// determine if input file had a path portion
std::string childFolderName =
osgDB::concatPaths(_parentFileOutputFolderPath,
osgDB::getFilePath(childFileName)); // combine parent-output path with child's
input path
// set output path
dependentFileNameList.setOutputPath(childFolderName);
// set output name
dependentFileNameList.setOutputFileName(childBaseName, _baseNameSuffix); //
apply suffix modification while adding output filename
// apply possible suffix name change to
original node here
const std::string originalNodePath =
osgDB::getFilePath(childFileName); // preserve original path
// combine original path and suffix-modified
output filename
Node.setFileName(childLoop,
osgDB::concatPaths(originalNodePath,
dependentFileNameList.getOutputFileName()));
// if this child is in a subfolder of some
sort, add the folder to the list of folders to create
osg::notify(osg::DEBUG_INFO) << " Adding child
folder: " << childFolderName << std::endl;
dependentFileNameList.addFolderToCreate(childFolderName);
_masterConversionSet.push(dependentFileNameList); // add the
dependentFileNameList to the queue-of-FileNameLists (which adds a copy)
} // if
} // for
} // apply pagedLOD
virtual void apply( osg::Node & node )
{
traverse( node );
}
private:
ConvertQueue &_masterConversionSet;
std::string _parentFileInputFolderPath, _parentFileOutputFolderPath;
std::string _baseNameSuffix;
}; // RecursiveConversionVisitor
class DefaultNormalsGeometryVisitor
: public osg::NodeVisitor
{
public:
DefaultNormalsGeometryVisitor()
: osg::NodeVisitor( osg::NodeVisitor::TRAVERSE_ALL_CHILDREN ) {
}
virtual void apply( osg::Geode & geode )
{
for( unsigned int ii = 0; ii < geode.getNumDrawables(); ++ii )
{
osg::ref_ptr< osg::Geometry > geometry = dynamic_cast<
osg::Geometry * >( geode.getDrawable( ii ) );
if( geometry.valid() )
{
osg::ref_ptr< osg::Vec3Array > newnormals = new osg::Vec3Array;
newnormals->push_back( osg::Z_AXIS );
geometry->setNormalArray( newnormals.get() );
geometry->setNormalBinding( osg::Geometry::BIND_OVERALL );
}
}
}
virtual void apply( osg::Node & node )
{
traverse( node );
}
};
class CompressTexturesVisitor : public osg::NodeVisitor
{
public:
CompressTexturesVisitor(osg::Texture::InternalFormatMode
internalFormatMode):
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
_internalFormatMode(internalFormatMode) {}
virtual void apply(osg::Node& node)
{
if (node.getStateSet()) apply(*node.getStateSet());
traverse(node);
}
virtual void apply(osg::Geode& node)
{
if (node.getStateSet()) apply(*node.getStateSet());
for(unsigned int i=0;i<node.getNumDrawables();++i)
{
osg::Drawable* drawable = node.getDrawable(i);
if (drawable && drawable->getStateSet())
apply(*drawable->getStateSet());
}
traverse(node);
}
virtual void apply(osg::StateSet& stateset)
{
// search for the existence of any texture object attributes
for(unsigned int i=0;i<stateset.getTextureAttributeList().size();++i)
{
osg::Texture* texture =
dynamic_cast<osg::Texture*>(stateset.getTextureAttribute(i,osg::StateAttribute::TEXTURE));
if (texture)
{
_textureSet.insert(texture);
}
}
}
void compress()
{
MyGraphicsContext context;
if (!context.valid())
{
osg::notify(osg::NOTICE)<<"Error: Unable to create graphics
context, problem with running osgViewer-"<<osgViewerGetVersion()<<", cannot run
compression."<<std::endl;
return;
}
osg::ref_ptr<osg::State> state = new osg::State;
for(TextureSet::iterator itr=_textureSet.begin();
itr!=_textureSet.end();
++itr)
{
osg::Texture* texture = const_cast<osg::Texture*>(itr->get());
osg::Texture2D* texture2D = dynamic_cast<osg::Texture2D*>(texture);
osg::Texture3D* texture3D = dynamic_cast<osg::Texture3D*>(texture);
osg::ref_ptr<osg::Image> image = texture2D ? texture2D->getImage()
: (texture3D ? texture3D->getImage() : 0);
if (image.valid() &&
(image->getPixelFormat()==GL_RGB ||
image->getPixelFormat()==GL_RGBA) &&
(image->s()>=32 && image->t()>=32))
{
texture->setInternalFormatMode(_internalFormatMode);
// need to disable the unref after apply, other the image could
go out of scope.
bool unrefImageDataAfterApply =
texture->getUnRefImageDataAfterApply();
texture->setUnRefImageDataAfterApply(false);
// get OpenGL driver to create texture from image.
texture->apply(*state);
// restore the original setting
texture->setUnRefImageDataAfterApply(unrefImageDataAfterApply);
image->readImageFromCurrentTexture(0,true);
texture->setInternalFormatMode(osg::Texture::USE_IMAGE_DATA_FORMAT);
}
}
}
void write(const std::string &dir)
{
for(TextureSet::iterator itr=_textureSet.begin();
itr!=_textureSet.end();
++itr)
{
osg::Texture* texture = const_cast<osg::Texture*>(itr->get());
osg::Texture2D* texture2D = dynamic_cast<osg::Texture2D*>(texture);
osg::Texture3D* texture3D = dynamic_cast<osg::Texture3D*>(texture);
osg::ref_ptr<osg::Image> image = texture2D ? texture2D->getImage()
: (texture3D ? texture3D->getImage() : 0);
if (image.valid())
{
std::string name = osgDB::getStrippedName(image->getFileName());
name += ".dds";
image->setFileName(name);
std::string path = dir.empty() ? name : osgDB::concatPaths(dir,
name);
osgDB::writeImageFile(*image, path);
osg::notify(osg::NOTICE) << "Image written to '" << path <<
"'." << std::endl;
}
}
}
typedef std::set< osg::ref_ptr<osg::Texture> > TextureSet;
TextureSet _textureSet;
osg::Texture::InternalFormatMode _internalFormatMode;
};
class FixTransparencyVisitor : public osg::NodeVisitor
{
public:
enum FixTransparencyMode
{
NO_TRANSPARANCY_FIXING,
MAKE_OPAQUE_TEXTURE_STATESET_OPAQUE,
MAKE_ALL_STATESET_OPAQUE
};
FixTransparencyVisitor(FixTransparencyMode
mode=MAKE_OPAQUE_TEXTURE_STATESET_OPAQUE):
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
_numTransparent(0),
_numOpaque(0),
_numTransparentMadeOpaque(0),
_mode(mode)
{
std::cout<<"Running FixTransparencyVisitor..."<<std::endl;
}
~FixTransparencyVisitor()
{
std::cout<<" Number of Transparent StateSet
"<<_numTransparent<<std::endl;
std::cout<<" Number of Opaque StateSet "<<_numOpaque<<std::endl;
std::cout<<" Number of Transparent State made Opaque
"<<_numTransparentMadeOpaque<<std::endl;
}
virtual void apply(osg::Node& node)
{
if (node.getStateSet()) isTransparent(*node.getStateSet());
traverse(node);
}
virtual void apply(osg::Geode& node)
{
if (node.getStateSet()) isTransparent(*node.getStateSet());
for(unsigned int i=0;i<node.getNumDrawables();++i)
{
osg::Drawable* drawable = node.getDrawable(i);
if (drawable && drawable->getStateSet())
isTransparent(*drawable->getStateSet());
}
traverse(node);
}
virtual bool isTransparent(osg::StateSet& stateset)
{
bool hasTranslucentTexture = false;
bool hasBlendFunc =
dynamic_cast<osg::BlendFunc*>(stateset.getAttribute(osg::StateAttribute::BLENDFUNC))!=0;
bool hasTransparentRenderingHint =
stateset.getRenderingHint()==osg::StateSet::TRANSPARENT_BIN;
bool hasDepthSortBin =
(stateset.getRenderBinMode()==osg::StateSet::USE_RENDERBIN_DETAILS)?(stateset.getBinName()=="DepthSortedBin"):false;
bool hasTexture = false;
// search for the existence of any texture object attributes
for(unsigned int i=0;i<stateset.getTextureAttributeList().size();++i)
{
osg::Texture* texture =
dynamic_cast<osg::Texture*>(stateset.getTextureAttribute(i,osg::StateAttribute::TEXTURE));
if (texture)
{
hasTexture = true;
for (unsigned int im=0;im<texture->getNumImages();++im)
{
osg::Image* image = texture->getImage(im);
if (image && image->isImageTranslucent())
hasTranslucentTexture = true;
}
}
}
if (hasTranslucentTexture || hasBlendFunc ||
hasTransparentRenderingHint || hasDepthSortBin)
{
++_numTransparent;
bool makeNonTransparent = false;
switch(_mode)
{
case(MAKE_OPAQUE_TEXTURE_STATESET_OPAQUE):
if (hasTexture && !hasTranslucentTexture)
{
makeNonTransparent = true;
}
break;
case(MAKE_ALL_STATESET_OPAQUE):
makeNonTransparent = true;
break;
default:
makeNonTransparent = false;
break;
}
if (makeNonTransparent)
{
stateset.removeAttribute(osg::StateAttribute::BLENDFUNC);
stateset.removeMode(GL_BLEND);
stateset.setRenderingHint(osg::StateSet::DEFAULT_BIN);
++_numTransparentMadeOpaque;
}
return true;
}
else
{
++_numOpaque;
return false;
}
}
unsigned int _numTransparent;
unsigned int _numOpaque;
unsigned int _numTransparentMadeOpaque;
FixTransparencyMode _mode;
};
class PruneStateSetVisitor : public osg::NodeVisitor
{
public:
PruneStateSetVisitor():
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
_numStateSetRemoved(0)
{
std::cout<<"Running PruneStateSet..."<<std::endl;
}
~PruneStateSetVisitor()
{
std::cout<<" Number of StateState removed
"<<_numStateSetRemoved<<std::endl;
}
virtual void apply(osg::Node& node)
{
if (node.getStateSet())
{
node.setStateSet(0);
++_numStateSetRemoved;
}
traverse(node);
}
virtual void apply(osg::Geode& node)
{
if (node.getStateSet())
{
node.setStateSet(0);
++_numStateSetRemoved;
}
for(unsigned int i=0;i<node.getNumDrawables();++i)
{
osg::Drawable* drawable = node.getDrawable(i);
if (drawable && drawable->getStateSet())
{
drawable->setStateSet(0);
++_numStateSetRemoved;
}
}
traverse(node);
}
unsigned int _numStateSetRemoved;
};
/** Add missing colours to osg::Geometry.*/
class AddMissingColoursToGeometryVisitor : public osg::NodeVisitor
{
public:
AddMissingColoursToGeometryVisitor():osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
{}
virtual void apply(osg::Geode& geode)
{
for(unsigned int i=0;i<geode.getNumDrawables();++i)
{
osg::Geometry* geometry =
dynamic_cast<osg::Geometry*>(geode.getDrawable(i));
if (geometry)
{
if (geometry->getColorArray()==0 ||
geometry->getColorArray()->getNumElements()==0)
{
osg::Vec4Array* colours = new osg::Vec4Array(1);
(*colours)[0].set(1.0f,1.0f,1.0f,1.0f);
geometry->setColorArray(colours);
geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
}
}
}
}
virtual void apply(osg::Node& node) { traverse(node); }
};
static void usage( const char *prog, const char *msg )
{
if (msg)
{
osg::notify(osg::NOTICE)<< std::endl;
osg::notify(osg::NOTICE) << msg << std::endl;
}
// basic usage
osg::notify(osg::NOTICE)<< std::endl;
osg::notify(osg::NOTICE)<<"usage:"<< std::endl;
osg::notify(osg::NOTICE)<<" " << prog << " [options] infile1 [infile2
...] outfile"<< std::endl;
osg::notify(osg::NOTICE)<< std::endl;
// print env options - especially since optimizer is always _on_
osg::notify(osg::NOTICE)<<"environment:" << std::endl;
osg::ApplicationUsage::UsageMap um =
osg::ApplicationUsage::instance()->getEnvironmentalVariables();
std::string envstring;
osg::ApplicationUsage::instance()->getFormattedString( envstring, um );
osg::notify(osg::NOTICE)<<envstring << std::endl;
// print tool options
osg::notify(osg::NOTICE)<<"options:"<< std::endl;
osg::notify(osg::NOTICE)<<" -R suffix - Recursively convert
files referred to by PagedLOD/ProxyNode, appending suffix to output name before
extension."<< std::endl;
osg::notify(osg::NOTICE)<< std::endl;
osg::notify(osg::NOTICE)<<" -O option - ReaderWriter option"<<
std::endl;
osg::notify(osg::NOTICE)<< std::endl;
osg::notify(osg::NOTICE)<<" --compressed - Enable the usage of
compressed textures,"<< std::endl;
osg::notify(osg::NOTICE)<<" defaults to OpenGL ARB
compressed textures."<< std::endl;
osg::notify(osg::NOTICE)<<" --compressed-arb - Enable the usage of
OpenGL ARB compressed textures"<< std::endl;
osg::notify(osg::NOTICE)<<" --compressed-dxt1 - Enable the usage of
S3TC DXT1 compressed textures"<< std::endl;
osg::notify(osg::NOTICE)<<" --compressed-dxt3 - Enable the usage of
S3TC DXT3 compressed textures"<< std::endl;
osg::notify(osg::NOTICE)<<" --compressed-dxt5 - Enable the usage of
S3TC DXT5 compressed textures"<< std::endl;
osg::notify(osg::NOTICE)<< std::endl;
osg::notify(osg::NOTICE)<<" --fix-transparency - fix stateset which are
curerntly declared as transprent,"<< std::endl;
osg::notify(osg::NOTICE)<<" but should be opaque.
Defaults to using the "<< std::endl;
osg::notify(osg::NOTICE)<<" fixTranspancyMode
MAKE_OPAQUE_TEXTURE_STATESET_OPAQUE."<< std::endl;
osg::notify(osg::NOTICE)<<" --fix-transparency-mode <mode_string> - fix
stateset which are curerntly declared as"<< std::endl;
osg::notify(osg::NOTICE)<<" transprent but should
be opaque. The mode_string determines"<< std::endl;
osg::notify(osg::NOTICE)<<" algorithm is used to
fix the transparency, options are: "<< std::endl;
osg::notify(osg::NOTICE)<<"
MAKE_OPAQUE_TEXTURE_STATESET_OPAQUE,"<<std::endl;
osg::notify(osg::NOTICE)<<"
MAKE_ALL_STATESET_OPAQUE."<<std::endl;
osg::notify(osg::NOTICE)<< std::endl;
osg::notify(osg::NOTICE)<<" -l libraryName - load plugin of name
libraryName"<< std::endl;
osg::notify(osg::NOTICE)<<" i.e. -l osgdb_pfb"<<
std::endl;
osg::notify(osg::NOTICE)<<" Useful for loading
reader/writers which can load"<< std::endl;
osg::notify(osg::NOTICE)<<" other file formats in
addition to its extension."<< std::endl;
osg::notify(osg::NOTICE)<<" -e extensionName - load reader/wrter
plugin for file extension"<< std::endl;
osg::notify(osg::NOTICE)<<" i.e. -e pfb"<<
std::endl;
osg::notify(osg::NOTICE)<<" Useful short hand for
specifying full library name as"<< std::endl;
osg::notify(osg::NOTICE)<<" done with -l above, as
it automatically expands to the"<< std::endl;
osg::notify(osg::NOTICE)<<" full library name
appropriate for each platform."<< std::endl;
osg::notify(osg::NOTICE)<<" -o orientation - Convert geometry from
input files to output files."<< std::endl;
osg::notify(osg::NOTICE)<<
" Format of orientation
argument must be the following:\n"
"\n"
" X1,Y1,Z1-X2,Y2,Z2\n"
" or\n"
" degrees-A0,A1,A2\n"
"\n"
" where X1,Y1,Z1
represent the UP vector in the input\n"
" files and X2,Y2,Z2
represent the UP vector of the\n"
" output file, or degrees
is the rotation angle in degrees\n"
" around axis (A0,A1,A2).
For example, to convert a model\n"
" built in a Y-Up
coordinate system to a model with a Z-up\n"
" coordinate system, the
argument may look like\n"
"\n"
" 0,1,0-0,0,1"
"\n"
" or\n"
" -90-1,0,0\n"
"\n" << std::endl;
osg::notify(osg::NOTICE)<<" -t translation - Convert spatial
position of output files. Format of\n"
" translation argument
must be the following :\n"
"\n"
" X,Y,Z\n"
"\n"
" where X, Y, and Z
represent the coordinates of the\n"
" absolute position in
world space\n"
<< std::endl;
osg::notify(osg::NOTICE)<<" --simplify n - Run simplifier on prior
to output. Argument must be a" << std::endl
<<" normalized value for
the resultant percentage reduction." << std::endl
<<" Example: --simplify .5
will produce an 50 reduced model." << std::endl
<< std::endl;
osg::notify(osg::NOTICE)<<" -s scale - Scale size of model.
Scale argument must be the \n"
" following :\n"
"\n"
" SX,SY,SZ\n"
"\n"
" where SX, SY, and SZ
represent the scale factors\n"
" Caution: Scaling will
be done in destination orientation\n"
<< std::endl;
osg::notify(osg::NOTICE)<<" --smooth - Smooth the surface by
regenerating surface normals on\n"
" all geometry"<<
std::endl;
osg::notify(osg::NOTICE)<<" --addMissingColors - Adding a white color
value to all geometry that don't have\n"
" their own color values
(--addMissingColours also accepted)."<< std::endl;
osg::notify(osg::NOTICE)<<" --overallNormal - Replace normals with a
single overall normal."<< std::endl;
osg::notify(osg::NOTICE)<<" --enable-object-cache - Enable caching of
objects, images, etc."<< std::endl;
osg::notify( osg::NOTICE ) << std::endl;
osg::notify( osg::NOTICE ) <<
" --formats - Lists all supported formats and their
supported options." << std::endl;
osg::notify( osg::NOTICE ) <<
" --format <format> - Displays information about the specified
<format>, where <format>\n"
" is the file extension, such as \"flt\"." <<
std::endl;
osg::notify( osg::NOTICE ) <<
" --plugins - Lists all supported plugin files." <<
std::endl;
osg::notify( osg::NOTICE ) <<
" --plugin >plugin> - Displays information about the specified
<plugin>, where <plugin>\n"
" is the plugin's full path and file name." <<
std::endl;
}
int main( int argc, char **argv )
{
// record original source directory
std::string originalCurrentWorkingDirectory;
originalCurrentWorkingDirectory = osgDB::getCurrentWorkingDirectory();
osg::notify(osg::DEBUG_INFO) << "osgconv
originalCurrentWorkingDirectory=" << originalCurrentWorkingDirectory <<
std::endl;
// use an ArgumentParser object to manage the program arguments.
osg::ArgumentParser arguments(&argc,argv);
// set up the usage document, in case we need to print out how to use this
program.
arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName());
arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+"
is a utility for converting between various input and output databases
formats.");
arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+"
[options] filename ...");
arguments.getApplicationUsage()->addCommandLineOption("-h or
--help","Display command line parameters");
arguments.getApplicationUsage()->addCommandLineOption("--help-env","Display
environmental variables available");
//arguments.getApplicationUsage()->addCommandLineOption("--formats","List
supported file formats");
//arguments.getApplicationUsage()->addCommandLineOption("--plugins","List
database olugins");
// if user request help write it out to cout.
if (arguments.read("-h") || arguments.read("--help"))
{
usage( arguments.getApplicationName().c_str(), 0 );
//arguments.getApplicationUsage()->write(std::cout);
return 1;
}
if (arguments.read("--help-env"))
{
arguments.getApplicationUsage()->write(std::cout,
osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE);
return 1;
}
if (arguments.read("--plugins"))
{
osgDB::FileNameList plugins = osgDB::listAllAvailablePlugins();
for(osgDB::FileNameList::iterator itr = plugins.begin();
itr != plugins.end();
++itr)
{
std::cout<<"Plugin "<<*itr<<std::endl;
}
return 0;
}
std::string plugin;
if (arguments.read("--plugin", plugin))
{
osgDB::outputPluginDetails(std::cout, plugin);
return 0;
}
std::string ext;
if (arguments.read("--format", ext))
{
plugin =
osgDB::Registry::instance()->createLibraryNameForExtension(ext);
osgDB::outputPluginDetails(std::cout, plugin);
return 0;
}
if (arguments.read("--formats"))
{
osgDB::FileNameList plugins = osgDB::listAllAvailablePlugins();
for(osgDB::FileNameList::iterator itr = plugins.begin();
itr != plugins.end();
++itr)
{
osgDB::outputPluginDetails(std::cout,*itr);
}
return 0;
}
if (arguments.argc()<=1)
{
arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION);
return 1;
}
ConvertQueue conversionSet;
ConvertBatch initialConversion;
OrientationConverter oc;
bool do_convert = false, do_recurse = false;
std::string str, baseSuffixString;
// parse recursion/suffix option
while(arguments.read("-R",baseSuffixString))
{
do_recurse = true;
};
while (arguments.read("-O",str))
{
osgDB::ReaderWriter::Options* options = new
osgDB::ReaderWriter::Options;
options->setOptionString(str);
osgDB::Registry::instance()->setOptions(options);
}
while (arguments.read("-e",ext))
{
std::string libName =
osgDB::Registry::instance()->createLibraryNameForExtension(ext);
osgDB::Registry::instance()->loadLibrary(libName);
}
std::string libName;
while (arguments.read("-l",libName))
{
osgDB::Registry::instance()->loadLibrary(libName);
}
while (arguments.read("-o",str))
{
osg::Vec3 from, to;
if( sscanf( str.c_str(), "%f,%f,%f-%f,%f,%f",
&from[0], &from[1], &from[2],
&to[0], &to[1], &to[2] )
!= 6 )
{
float degrees;
osg::Vec3 axis;
// Try deg-axis format
if( sscanf( str.c_str(), "%f-%f,%f,%f",
°rees, &axis[0], &axis[1], &axis[2] ) != 4 )
{
usage( argv[0], "Orientation argument format incorrect." );
return 1;
}
else
{
oc.setRotation( degrees, axis );
do_convert = true;
}
}
else
{
oc.setRotation( from, to );
do_convert = true;
}
}
while (arguments.read("-s",str))
{
osg::Vec3 scale(0,0,0);
if( sscanf( str.c_str(), "%f,%f,%f",
&scale[0], &scale[1], &scale[2] ) != 3 )
{
usage( argv[0], "Scale argument format incorrect." );
return 1;
}
oc.setScale( scale );
do_convert = true;
}
float simplifyPercent = 1.0;
bool do_simplify = false;
while ( arguments.read( "--simplify",str ) )
{
float nsimp = 1.0;
if( sscanf( str.c_str(), "%f",
&nsimp ) != 1 )
{
usage( argv[0], "Scale argument format incorrect." );
return 1;
}
std::cout << str << " " << nsimp << std::endl;
simplifyPercent = nsimp;
osg::notify( osg::INFO ) << "Simplifying with percentage: " <<
simplifyPercent << std::endl;
do_simplify = true;
}
while (arguments.read("-t",str))
{
osg::Vec3 trans(0,0,0);
if( sscanf( str.c_str(), "%f,%f,%f",
&trans[0], &trans[1], &trans[2] ) != 3 )
{
usage( argv[0], "Translation argument format incorrect." );
return 1;
}
oc.setTranslation( trans );
do_convert = true;
}
FixTransparencyVisitor::FixTransparencyMode fixTransparencyMode =
FixTransparencyVisitor::NO_TRANSPARANCY_FIXING;
std::string fixString;
while(arguments.read("--fix-transparency")) fixTransparencyMode =
FixTransparencyVisitor::MAKE_OPAQUE_TEXTURE_STATESET_OPAQUE;
while(arguments.read("--fix-transparency-mode",fixString))
{
if (fixString=="MAKE_OPAQUE_TEXTURE_STATESET_OPAQUE")
fixTransparencyMode =
FixTransparencyVisitor::MAKE_OPAQUE_TEXTURE_STATESET_OPAQUE;
if (fixString=="MAKE_ALL_STATESET_OPAQUE") fixTransparencyMode =
FixTransparencyVisitor::MAKE_ALL_STATESET_OPAQUE;
};
bool pruneStateSet = false;
while(arguments.read("--prune-StateSet")) pruneStateSet = true;
osg::Texture::InternalFormatMode internalFormatMode =
osg::Texture::USE_IMAGE_DATA_FORMAT;
while(arguments.read("--compressed") || arguments.read("--compressed-arb"))
{ internalFormatMode = osg::Texture::USE_ARB_COMPRESSION; }
while(arguments.read("--compressed-dxt1")) { internalFormatMode =
osg::Texture::USE_S3TC_DXT1_COMPRESSION; }
while(arguments.read("--compressed-dxt3")) { internalFormatMode =
osg::Texture::USE_S3TC_DXT3_COMPRESSION; }
while(arguments.read("--compressed-dxt5")) { internalFormatMode =
osg::Texture::USE_S3TC_DXT5_COMPRESSION; }
bool smooth = false;
while(arguments.read("--smooth")) { smooth = true; }
bool addMissingColours = false;
while(arguments.read("--addMissingColours") ||
arguments.read("--addMissingColors")) { addMissingColours = true; }
bool do_overallNormal = false;
while(arguments.read("--overallNormal") ||
arguments.read("--overallNormal")) { do_overallNormal = true; }
bool enableObjectCache = false;
while(arguments.read("--enable-object-cache")) { enableObjectCache = true; }
// any option left unread are converted into errors to write out later.
arguments.reportRemainingOptionsAsUnrecognized();
// report any errors if they have occurred when parsing the program
arguments.
if (arguments.errors())
{
arguments.writeErrorMessages(std::cout);
return 1;
}
// add all non-option arguments to the initialConversion container
for(int pos=1;pos<arguments.argc();++pos)
{
if (!arguments.isOption(pos))
{
initialConversion.addInputFileName(arguments[pos]);
initialConversion.setInputBasePath(originalCurrentWorkingDirectory);
}
} // for
// If more than one filename argument was provided, use last one as output
filename, otherwise use converted.osg
if (initialConversion.inputNames.size()>1) // was more than one
filename specified on the command line?
{
// remove the last-supplied filename from the initial filenames
const std::string initialFileNameOut =
initialConversion.removeInputFromBack();
// obtain destination path from it
initialConversion.setOutputPath(osgDB::getFilePath(initialFileNameOut));
// and get the path-less filename
initialConversion.setOutputFileName(osgDB::getSimpleFileName(initialFileNameOut));
} // if
else
{ // only one filename provided, use default output filename
initialConversion.setOutputFileName("converted.osg");
initialConversion.setOutputPath(originalCurrentWorkingDirectory);
} // else
// add the initialConversion batch to the set of ConvertBatches named
conversionSet
conversionSet.push(initialConversion);
if (enableObjectCache)
{
if (osgDB::Registry::instance()->getOptions()==0)
osgDB::Registry::instance()->setOptions(new osgDB::Options());
osgDB::Registry::instance()->getOptions()->setObjectCacheHint(osgDB::Options::CACHE_ALL);
}
osg::Timer_t conversionStartTick = osg::Timer::instance()->tick();
while(!conversionSet.empty())
{
osg::Timer_t startTick = osg::Timer::instance()->tick();
// get the first set of filenames in the queue
ConvertBatch &workingConvertBatch = conversionSet.front();
osg::notify(osg::DEBUG_INFO)<<"workingConvertBatch
("<<workingConvertBatch.inputNames.size() << " items)" <<std::endl;
osg::notify(osg::DEBUG_INFO)<<" inputBasePath " <<
workingConvertBatch.inputBasePath <<std::endl;
osg::notify(osg::DEBUG_INFO)<<" outputName " <<
workingConvertBatch.outputFileName <<std::endl;
osg::notify(osg::DEBUG_INFO)<<" outputPath " <<
workingConvertBatch.outputPath <<std::endl;
for(FileNameList::iterator FileNameListIterator =
workingConvertBatch.inputNames.begin(); FileNameListIterator !=
workingConvertBatch.inputNames.end(); FileNameListIterator++)
osg::notify(osg::INFO)<<" File:
"<<*FileNameListIterator <<std::endl;
// change to the specified base directory for loading
osg::notify(osg::DEBUG_INFO) << "Changing to folder " <<
workingConvertBatch.inputBasePath << std::endl;
osgDB::setCurrentWorkingDirectory(workingConvertBatch.inputBasePath);
// load all the input files in current set
osg::ref_ptr<osg::Node> root =
osgDB::readNodeFiles(workingConvertBatch.inputNames);
if (root.valid())
{
osg::Timer_t endTick = osg::Timer::instance()->tick();
osg::notify(osg::INFO)<<"Time to load files in set
"<<osg::Timer::instance()->delta_m(startTick, endTick)<<" ms"<<std::endl;
}
if (pruneStateSet)
{
PruneStateSetVisitor pssv;
root->accept(pssv);
}
if (fixTransparencyMode !=
FixTransparencyVisitor::NO_TRANSPARANCY_FIXING)
{
FixTransparencyVisitor atv(fixTransparencyMode);
root->accept(atv);
}
if ( root.valid() )
{
if (smooth)
{
osgUtil::SmoothingVisitor sv;
root->accept(sv);
}
if (addMissingColours)
{
AddMissingColoursToGeometryVisitor av;
root->accept(av);
}
// optimize the scene graph, remove rendundent nodes
and state etc.
osgUtil::Optimizer optimizer;
optimizer.optimize(root.get());
if( do_convert )
root = oc.convert( root.get() );
if (internalFormatMode !=
osg::Texture::USE_IMAGE_DATA_FORMAT)
{
std::string ext =
osgDB::getFileExtension(workingConvertBatch.outputFileName);
CompressTexturesVisitor ctv(internalFormatMode);
root->accept(ctv);
ctv.compress();
osgDB::ReaderWriter::Options *options =
osgDB::Registry::instance()->getOptions();
if (ext!="ive" || (options &&
options->getOptionString().find("noTexturesInIVEFile")!=std::string::npos))
{
ctv.write(osgDB::getFilePath(workingConvertBatch.outputFileName));
}
}
// scrub normals
if ( do_overallNormal )
{
DefaultNormalsGeometryVisitor dngv;
root->accept( dngv );
}
// apply any user-specified simplification
if ( do_simplify )
{
osgUtil::Simplifier simple;
simple.setSmoothing( smooth );
osg::notify( osg::ALWAYS ) << " smoothing: " <<
smooth << std::endl;
simple.setSampleRatio( simplifyPercent );
root->accept( simple );
}
// handle recursive conversion of external files
through PagedLOD/proxyNode
if ( do_recurse )
{
// gather the list of external filenames from
all PagedLOD/ProxyNode children's filenames
// and apply user-specified suffix to each
osg::notify( osg::ALWAYS ) << " Recursively
searching for dependent files to convert." << std::endl;
// since there are potentially multiple files
involved recursion paths only work with a single file processed at a time
// if we have loaded multiple nodes in
readNodeFiles, the name of the node may contain the path loaded from
std::string inputFileBasePath =
osgDB::getFilePath(osgDB::getRealPath(workingConvertBatch.inputNames.front()));
RecursiveConversionVisitor rcv(conversionSet,
inputFileBasePath, workingConvertBatch.outputPath, baseSuffixString);
root->accept(rcv);
}
// try to create destination directory if not present
if(!osgDB::fileExists(workingConvertBatch.outputPath))
{
osgDB::makeDirectory(workingConvertBatch.outputPath);
} // if
// change to destination directory
osg::notify(osg::DEBUG_INFO) << "Changing to folder "
<< workingConvertBatch.outputPath << std::endl;
osgDB::setCurrentWorkingDirectory(workingConvertBatch.outputPath);
// write the scenegraph
osg::notify(osg::DEBUG_INFO) << "writing output file "
<< workingConvertBatch.outputFileName << std::endl;
osgDB::ReaderWriter::WriteResult result =
osgDB::Registry::instance()->writeNode(*root,workingConvertBatch.outputFileName,osgDB::Registry::instance()->getOptions());
// change back to original current working directory
osg::notify(osg::DEBUG_INFO) << "Changing to original
folder " << originalCurrentWorkingDirectory << std::endl;
osgDB::setCurrentWorkingDirectory(originalCurrentWorkingDirectory);
if (result.success())
{
osg::notify(osg::NOTICE)<<"Data written to
'"<<workingConvertBatch.outputFileName<<"'."<< std::endl;
}
else if (result.message().empty())
{
osg::notify(osg::NOTICE)<<"Warning: file write
to '"<<workingConvertBatch.outputFileName<<"' no supported."<< std::endl;
}
else
{
osg::notify(osg::NOTICE)<<result.message()<<
std::endl;
}
}
else
{
osg::notify(osg::NOTICE)<<"Error no data loaded."<<
std::endl;
return 1;
}
conversionSet.pop(); // remove just-used set of filenames from
the queue
} // while any FileNameLists
osg::Timer_t conversionEndTick = osg::Timer::instance()->tick();
osg::notify(osg::INFO)<<"Time to convert all files
"<<osg::Timer::instance()->delta_s(conversionStartTick, conversionEndTick)<<"
seconds"<<std::endl;
return 0;
}
_______________________________________________
osg-submissions mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org