Files
OpenSceneGraph/src/osgPlugins/osgjs/ReaderWriterJSON.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

244 lines
8.9 KiB
C++

// copyright: 'Cedric Pinson cedric@plopbyte.com'
#include <osg/Image>
#include <osg/Notify>
#include <osg/Geode>
#include <osg/GL>
#include <osg/Version>
#include <osg/Endian>
#include <osg/Projection>
#include <osg/MatrixTransform>
#include <osg/PositionAttitudeTransform>
#include <osgUtil/UpdateVisitor>
#include <osgDB/ReaderWriter>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osgDB/Registry>
#include <osgDB/FileUtils>
#include <osgDB/FileNameUtils>
#include <osgAnimation/UpdateMatrixTransform>
#include <osgAnimation/AnimationManagerBase>
#include <osgAnimation/BasicAnimationManager>
#include <vector>
#include "json_stream"
#include "JSON_Objects"
#include "Animation"
#include "CompactBufferVisitor"
#include "WriteVisitor"
using namespace osg;
class ReaderWriterJSON : public osgDB::ReaderWriter
{
public:
struct OptionsStruct {
int resizeTextureUpToPowerOf2;
bool useExternalBinaryArray;
bool mergeAllBinaryFiles;
bool disableCompactBuffer;
bool inlineImages;
bool varint;
bool strictJson;
std::vector<std::string> useSpecificBuffer;
OptionsStruct() {
resizeTextureUpToPowerOf2 = 0;
useExternalBinaryArray = false;
mergeAllBinaryFiles = false;
disableCompactBuffer = false;
inlineImages = false;
varint = false;
strictJson = true;
}
};
ReaderWriterJSON()
{
supportsExtension("osgjs","OpenSceneGraph Javascript implementation format");
supportsOption("resizeTextureUpToPowerOf2=<int>","Specify the maximum power of 2 allowed dimension for texture. Using 0 will disable the functionality and no image resizing will occur.");
supportsOption("useExternalBinaryArray","create binary files for vertex arrays");
supportsOption("mergeAllBinaryFiles","merge all binary files into one to avoid multi request on a server");
supportsOption("inlineImages","insert base64 encoded images instead of referring to them");
supportsOption("varint","Use varint encoding to serialize integer buffers");
supportsOption("useSpecificBuffer=uservalue1,uservalue2","uses specific buffers for unshared buffers attached to geometries having a specified user value");
supportsOption("disableCompactBuffer","keep source types and do not try to optimize buffers size");
supportsOption("disableStrictJson","do not clean string (to utf8) or floating point (should be finite) values");
}
virtual const char* className() const { return "OSGJS json Writer"; }
virtual ReadResult readNode(const std::string& fileName, const Options* options) const;
virtual WriteResult writeNode(const Node& node,
const std::string& fileName,
const osgDB::ReaderWriter::Options* options) const
{
std::string ext = osgDB::getFileExtension(fileName);
if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED;
OptionsStruct _options = parseOptions(options);
json_stream fout(fileName, _options.strictJson);
if(fout) {
WriteResult res = writeNodeModel(node, fout, osgDB::getNameLessExtension(fileName), _options);
return res;
}
return WriteResult("Unable to open file for output");
}
virtual WriteResult writeNode(const Node& node,
json_stream& fout,
const osgDB::ReaderWriter::Options* options) const
{
if (!fout) {
return WriteResult("Unable to write to output stream");
}
OptionsStruct _options;
_options = parseOptions(options);
return writeNodeModel(node, fout, "stream", _options);
}
virtual WriteResult writeNodeModel(const Node& node, json_stream& fout, const std::string& basename, const OptionsStruct& options) const
{
// process regular model
osg::ref_ptr<osg::Node> model = osg::clone(&node);
if(!options.disableCompactBuffer) {
CompactBufferVisitor compact;
model->accept(compact);
}
WriteVisitor writer;
try {
//osgDB::writeNodeFile(*model, "/tmp/debug_osgjs.osg");
writer.setBaseName(basename);
writer.useExternalBinaryArray(options.useExternalBinaryArray);
writer.mergeAllBinaryFiles(options.mergeAllBinaryFiles);
writer.inlineImages(options.inlineImages);
writer.setMaxTextureDimension(options.resizeTextureUpToPowerOf2);
writer.setVarint(options.varint);
for(std::vector<std::string>::const_iterator specificBuffer = options.useSpecificBuffer.begin() ;
specificBuffer != options.useSpecificBuffer.end() ; ++ specificBuffer) {
writer.addSpecificBuffer(*specificBuffer);
}
model->accept(writer);
if (writer._root.valid()) {
writer.write(fout);
return WriteResult::FILE_SAVED;
}
} catch (...) {
osg::notify(osg::FATAL) << "can't save osgjs file" << std::endl;
return WriteResult("Unable to write to output stream");
}
return WriteResult("Unable to write to output stream");
}
ReaderWriterJSON::OptionsStruct parseOptions(const osgDB::ReaderWriter::Options* options) const
{
OptionsStruct localOptions;
if (options)
{
osg::notify(NOTICE) << "options " << options->getOptionString() << std::endl;
std::istringstream iss(options->getOptionString());
std::string opt;
while (iss >> opt)
{
// split opt into pre= and post=
std::string pre_equals;
std::string post_equals;
size_t found = opt.find("=");
if(found!=std::string::npos)
{
pre_equals = opt.substr(0,found);
post_equals = opt.substr(found+1);
}
else
{
pre_equals = opt;
}
if (pre_equals == "useExternalBinaryArray")
{
localOptions.useExternalBinaryArray = true;
}
if (pre_equals == "mergeAllBinaryFiles")
{
localOptions.mergeAllBinaryFiles = true;
}
if (pre_equals == "disableCompactBuffer")
{
localOptions.disableCompactBuffer = true;
}
if (pre_equals == "disableStrictJson")
{
localOptions.strictJson = false;
}
if (pre_equals == "inlineImages")
{
localOptions.inlineImages = true;
}
if (pre_equals == "varint")
{
localOptions.varint = true;
}
if (pre_equals == "resizeTextureUpToPowerOf2" && post_equals.length() > 0)
{
int value = atoi(post_equals.c_str());
localOptions.resizeTextureUpToPowerOf2 = osg::Image::computeNearestPowerOfTwo(value);
}
if (pre_equals == "useSpecificBuffer" && !post_equals.empty())
{
size_t stop_pos = 0, start_pos = 0;
while((stop_pos = post_equals.find(",", start_pos)) != std::string::npos) {
localOptions.useSpecificBuffer.push_back(post_equals.substr(start_pos,
stop_pos - start_pos));
start_pos = stop_pos + 1;
++ stop_pos;
}
localOptions.useSpecificBuffer.push_back(post_equals.substr(start_pos,
post_equals.length() - start_pos));
}
}
}
return localOptions;
}
};
osgDB::ReaderWriter::ReadResult ReaderWriterJSON::readNode(const std::string& file, const Options* options) const
{
std::string ext = osgDB::getLowerCaseFileExtension(file);
if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
// strip the pseudo-loader extension
std::string fileName = osgDB::getNameLessExtension( file );
fileName = osgDB::findDataFile( fileName, options );
if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
osg::ref_ptr<osg::Node> node = osgDB::readRefNodeFile( fileName, options );
if (!node)
return ReadResult::FILE_NOT_HANDLED;
return ReadResult::FILE_NOT_HANDLED;
}
// now register with Registry to instantiate the above
// reader/writer.
REGISTER_OSGPLUGIN(osgjs, ReaderWriterJSON)