OpenSceneGraph/applications/present3D/ReadShowFile.cpp
Robert Osfield dd996a3289 Introduced CMake option OSG_PROVIDE_READFILE option that defaults to ON, but when switched to OFF disables the building of the osgDB::read*File() methods,
forcing users to use osgDB::readRef*File() methods.  The later is preferable as it closes a potential threading bug when using paging databases in conjunction
with the osgDB::Registry Object Cache.  This threading bug occurs when one thread gets an object from the Cache via an osgDB::read*File() call where only
a pointer to the object is passed back, so taking a reference to the object is delayed till it gets reassigned to a ref_ptr<>, but at the same time another
thread calls a flush of the Object Cache deleting this object as it's referenceCount is now zero.  Using osgDB::readREf*File() makes sure the a ref_ptr<> is
passed back and the referenceCount never goes to zero.

To ensure the OSG builds when OSG_PROVIDE_READFILE is to OFF the many cases of osgDB::read*File() usage had to be replaced with a ref_ptr<> osgDB::readRef*File()
usage.  The avoid this change causing lots of other client code to be rewritten to handle the use of ref_ptr<> in place of C pointer I introduced a serious of
templte methods in various class to adapt ref_ptr<> to the underly C pointer to be passed to old OSG API's, example of this is found in include/osg/Group:

    bool addChild(Node* child); // old method which can only be used with a Node*

    tempalte<class T> bool addChild(const osg::ref_ptr<T>& child) { return addChild(child.get()); } // adapter template method

These changes together cover 149 modified files, so it's a large submission. This extent of changes are warrent to make use of the Object Cache
and multi-threaded loaded more robust.



git-svn-id: http://svn.openscenegraph.org/osg/OpenSceneGraph/trunk@15164 16af8721-9629-0410-8352-f15c8da7e697
2015-10-22 13:42:19 +00:00

302 lines
8.6 KiB
C++

/* -*-c++-*- Present3D - Copyright (C) 1999-2006 Robert Osfield
*
* This software is open source and may be redistributed and/or modified under
* the terms of the GNU General Public License (GPL) version 2.0.
* The full license is in LICENSE.txt file included with this distribution,.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* include LICENSE.txt for more details.
*/
#include "ReadShowFile.h"
#include "ShowEventHandler.h"
#include <osgPresentation/SlideEventHandler>
#include <osg/ImageStream>
#include <osg/Shape>
#include <osg/ShapeDrawable>
#include <osg/Switch>
#include <osgDB/ReadFile>
#include <osgDB/FileNameUtils>
#include <osgDB/FileUtils>
#include <osgVolume/VolumeTile>
#include <osgDB/XmlParser>
#include <string.h>
class AddVolumeEditingCallbackVisitor : public osg::NodeVisitor
{
public:
AddVolumeEditingCallbackVisitor():
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}
void apply(osg::Group& group)
{
osgVolume::VolumeTile* volumeTile = dynamic_cast<osgVolume::VolumeTile*>(&group);
if (volumeTile)
{
if (dynamic_cast<osgVolume::PropertyAdjustmentCallback*>(volumeTile->getEventCallback())==0)
{
volumeTile->addEventCallback(new osgVolume::PropertyAdjustmentCallback());
}
}
else
{
traverse(group);
}
}
};
bool p3d::getFileNames(osg::ArgumentParser& arguments, FileNameList& xmlFiles, FileNameList& normalFiles)
{
// note currently doesn't delete the loaded file entries from the command line yet...
for(int pos=1;pos<arguments.argc();++pos)
{
if (!arguments.isOption(pos))
{
std::string ext = osgDB::getFileExtension(arguments[pos]);
if (osgDB::equalCaseInsensitive(ext,"xml") || osgDB::equalCaseInsensitive(ext,"p3d"))
{
xmlFiles.push_back(arguments[pos]);
}
else
{
normalFiles.push_back(arguments[pos]);
}
}
}
return (!xmlFiles.empty() || !normalFiles.empty());
}
bool p3d::readEnvVars(osg::ArgumentParser& arguments)
{
bool readVars = false;
for(int i=1; i<arguments.argc(); ++i)
{
if (!arguments.isOption(i))
{
std::string ext = osgDB::getLowerCaseFileExtension(arguments[i]);
if (ext=="xml" || ext=="p3d")
{
std::string file = osgDB::findDataFile(arguments[i]);
if (!file.empty())
{
std::string path = osgDB::getFilePath(file);
if (!path.empty())
{
osgDB::getDataFilePathList().push_front(path);
}
if (p3d::readEnvVars(file)) readVars = true;
}
}
}
}
return readVars;
}
bool p3d::readEnvVars(const std::string& fileName)
{
std::string ext = osgDB::getFileExtension(fileName);
if (!osgDB::equalCaseInsensitive(ext,"xml") &&
!osgDB::equalCaseInsensitive(ext,"p3d")) return false;
osg::ref_ptr<osgDB::XmlNode> doc = new osgDB::XmlNode;
osgDB::XmlNode* root = 0;
osgDB::XmlNode::Input input;
input.open(fileName);
input.readAllDataIntoBuffer();
doc->read(input);
if (doc == NULL )
{
fprintf(stderr,"Document not parsed successfully. \n");
return false;
}
for(osgDB::XmlNode::Children::iterator itr = doc->children.begin();
itr != doc->children.end() && !root;
++itr)
{
if ((*itr)->name=="presentation") root = itr->get();
}
if (root == NULL)
{
fprintf(stderr,"empty document\n");
return false;
}
if (root->name!="presentation")
{
fprintf(stderr,"document of the wrong type, root node != presentation");
return false;
}
bool readVars = false;
for(osgDB::XmlNode::Children::iterator itr = root->children.begin();
itr != root->children.end();
++itr)
{
osgDB::XmlNode* cur = itr->get();
if (cur->name=="env")
{
char* str = strdup(cur->contents.c_str());
osg::notify(osg::INFO)<<"putenv("<<str<<")"<<std::endl;
putenv(str);
readVars = true;
}
}
return readVars;
}
osgDB::Options* createOptions(const osgDB::ReaderWriter::Options* options)
{
osg::ref_ptr<osgDB::Options> local_options = options ? options->cloneOptions() : 0;
if (!local_options)
{
local_options = osgDB::Registry::instance()->getOptions() ?
osgDB::Registry::instance()->getOptions()->cloneOptions() :
new osgDB::Options;
}
local_options->setPluginStringData("P3D_EVENTHANDLER","none");
return local_options.release();
}
osg::ref_ptr<osg::Node> p3d::readHoldingSlide(const std::string& filename)
{
std::string ext = osgDB::getFileExtension(filename);
if (!osgDB::equalCaseInsensitive(ext,"xml") &&
!osgDB::equalCaseInsensitive(ext,"p3d")) return 0;
osg::ref_ptr<osgDB::ReaderWriter::Options> options = createOptions(0);
options->setObjectCacheHint(osgDB::ReaderWriter::Options::CACHE_NONE);
options->setOptionString("preview");
return osgDB::readRefNodeFile(filename, options.get());
}
osg::ref_ptr<osg::Node> p3d::readPresentation(const std::string& filename,const osgDB::ReaderWriter::Options* options)
{
std::string ext = osgDB::getFileExtension(filename);
if (!osgDB::equalCaseInsensitive(ext,"xml") &&
!osgDB::equalCaseInsensitive(ext,"p3d")) return 0;
osg::ref_ptr<osgDB::Options> local_options = createOptions(options);
local_options->setOptionString("main");
return osgDB::readRefNodeFile(filename, local_options.get());
}
osg::ref_ptr<osg::Node> p3d::readShowFiles(osg::ArgumentParser& arguments,const osgDB::ReaderWriter::Options* options)
{
osg::ref_ptr<osgDB::Options> local_options = createOptions(options);
local_options->setOptionString("main");
typedef std::vector< osg::ref_ptr<osg::Node> > NodeList;
NodeList nodeList;
std::string filename;
while (arguments.read("--image",filename))
{
osg::ref_ptr<osg::Image> image = readRefImageFile(filename.c_str(), local_options.get());
if (image.valid()) nodeList.push_back(osg::createGeodeForImage(image));
}
while (arguments.read("--movie",filename))
{
osg::ref_ptr<osg::Image> image = readRefImageFile(filename.c_str(), local_options.get());
osg::ref_ptr<osg::ImageStream> imageStream = dynamic_cast<osg::ImageStream*>(image.get());
if (image.valid())
{
imageStream->play();
nodeList.push_back(osg::createGeodeForImage(imageStream));
}
}
while (arguments.read("--dem",filename))
{
osg::ref_ptr<osg::HeightField> hf = readRefHeightFieldFile(filename.c_str(), local_options.get());
if (hf)
{
osg::Geode* geode = new osg::Geode;
geode->addDrawable(new osg::ShapeDrawable(hf));
nodeList.push_back(geode);
}
}
// note currently doesn't delete the loaded file entries from the command line yet...
for(int pos=1;pos<arguments.argc();++pos)
{
if (!arguments.isOption(pos))
{
// not an option so assume string is a filename.
osg::ref_ptr<osg::Node> node = osgDB::readRefNodeFile( arguments[pos], local_options.get());
if(node)
{
if (node->getName().empty()) node->setName( arguments[pos] );
nodeList.push_back(node);
// make sure that this presentation isn't cached
osgDB::Registry::instance()->removeFromObjectCache( arguments[pos] );
}
}
}
if (nodeList.empty())
{
return NULL;
}
osg::ref_ptr<osg::Node> root;
if (nodeList.size()==1)
{
root = nodeList.front().get();
}
else // size >1
{
osg::Switch* sw = new osg::Switch;
for(NodeList::iterator itr=nodeList.begin();
itr!=nodeList.end();
++itr)
{
sw->addChild((*itr).get());
}
sw->setSingleChildOn(0);
sw->setEventCallback(new p3d::ShowEventHandler());
root = sw;
}
if (root.valid())
{
osg::notify(osg::INFO)<<"Got node now adding callback"<<std::endl;
AddVolumeEditingCallbackVisitor avecv;
root->accept(avecv);
}
return root;
}