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
244 lines
8.9 KiB
C++
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)
|