Files
OpenSceneGraph/src/osgPlugins/Inventor/ReaderWriterIV.cpp
Robert Osfield c7bf98cca9 From Jan Peciva, "Improvements:
- Use OSG routines to load images instead of simage library (removes
dependency on 3rdParty simage library). Applies to Coin Inventor clone only.
"
2011-02-14 15:04:40 +00:00

270 lines
8.2 KiB
C++

// OSG headers
#include <osg/Notify>
#include <osgDB/FileUtils>
#include <osgDB/FileNameUtils>
// Inventor headers
#include <Inventor/SoDB.h>
#include <Inventor/SoInteraction.h>
#include <Inventor/nodekits/SoNodeKit.h>
#include <Inventor/nodes/SoSeparator.h>
#include <Inventor/actions/SoWriteAction.h>
#include <Inventor/actions/SoCallbackAction.h>
#ifdef __COIN__
# include <Inventor/VRMLnodes/SoVRMLImageTexture.h>
#endif
#include "ReaderWriterIV.h"
#include "ConvertFromInventor.h"
#include "ConvertToInventor.h"
// forward declarations of static functions
static void addSearchPaths(const osgDB::FilePathList *searchPaths);
static void removeSearchPaths(const osgDB::FilePathList *searchPaths);
// Register with Registry to instantiate the inventor reader.
REGISTER_OSGPLUGIN(Inventor, ReaderWriterIV)
/**
* Constructor.
* Initializes the ReaderWriterIV.
*/
ReaderWriterIV::ReaderWriterIV()
{
// Set supported extensions and options
supportsExtension("iv","Inventor format");
supportsExtension("wrl","VRML world file");
// Initialize Inventor
initInventor();
}
/**
* Initializes Open Inventor.
*/
void ReaderWriterIV::initInventor() const
{
// Initialize Inventor
SoDB::init();
SoNodeKit::init();
SoInteraction::init();
#ifdef __COIN__
// Disable delayed loading of VRML textures
SoVRMLImageTexture::setDelayFetchURL(FALSE);
// initialize convertor
ConvertFromInventor::init();
#endif
}
/**
* Read from SoInput and convert to OSG.
* This is a method used by readNode(string,options) and readNode(istream,options).
*/
osgDB::ReaderWriter::ReadResult
ReaderWriterIV::readNodeFromSoInput(SoInput &input,
std::string &fileName, const osgDB::ReaderWriter::Options *options) const
{
// Parse options and add search paths to SoInput
const osgDB::FilePathList *searchPaths = options ? &options->getDatabasePathList() : NULL;
if (options)
addSearchPaths(searchPaths);
// Create the inventor scenegraph by reading from SoInput
SoSeparator* rootIVNode = SoDB::readAll(&input);
// Remove recently appened search paths
if (options)
removeSearchPaths(searchPaths);
// Close the file
input.closeFile();
// Perform conversion
ReadResult result;
if (rootIVNode)
{
rootIVNode->ref();
// Convert the inventor scenegraph to an osg scenegraph
ConvertFromInventor convertIV;
convertIV.preprocess(rootIVNode);
result = convertIV.convert(rootIVNode);
rootIVNode->unref();
} else
result = ReadResult::FILE_NOT_HANDLED;
// Notify
if (result.success()) {
if (fileName.length())
{
OSG_NOTICE << "osgDB::ReaderWriterIV::readNode() "
<< "File " << fileName.data()
<< " loaded successfully." << std::endl;
}
else
{
OSG_NOTICE << "osgDB::ReaderWriterIV::readNode() "
<< "Stream loaded successfully." << std::endl;
}
} else {
if (fileName.length())
{
OSG_WARN << "osgDB::ReaderWriterIV::readNode() "
<< "Failed to load file " << fileName.data()
<< "." << std::endl;
}
else
{
OSG_WARN << "osgDB::ReaderWriterIV::readNode() "
<< "Failed to load stream." << std::endl;
}
}
return result;
}
// Read file and convert to OSG
osgDB::ReaderWriter::ReadResult
ReaderWriterIV::readNode(const std::string& file,
const osgDB::ReaderWriter::Options* options) const
{
// Accept extension
std::string ext = osgDB::getLowerCaseFileExtension(file);
if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
// Find file
std::string fileName = osgDB::findDataFile( file, options );
if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
// Notify
OSG_NOTICE << "osgDB::ReaderWriterIV::readNode() Reading file "
<< fileName.data() << std::endl;
OSG_INFO << "osgDB::ReaderWriterIV::readNode() Inventor version: "
<< SoDB::getVersion() << std::endl;
// Open the file
SoInput input;
if (!input.openFile(fileName.data()))
{
OSG_WARN << "osgDB::ReaderWriterIV::readIVFile() "
<< "Cannot open file " << fileName << std::endl;
return ReadResult::ERROR_IN_READING_FILE;
}
// Perform reading from SoInput
return readNodeFromSoInput(input, fileName, options);
}
osgDB::ReaderWriter::ReadResult
ReaderWriterIV::readNode(std::istream& fin,
const osgDB::ReaderWriter::Options* options) const
{
// Notify
OSG_NOTICE << "osgDB::ReaderWriterIV::readNode() "
"Reading from stream." << std::endl;
OSG_INFO << "osgDB::ReaderWriterIV::readNode() "
"Inventor version: " << SoDB::getVersion() << std::endl;
// Open the file
SoInput input;
// Assign istream to SoInput
// note: It seems there is no straightforward way to do that.
// SoInput accepts only FILE by setFilePointer or memory buffer
// by setBuffer. The FILE is dangerous on Windows, since it forces
// the plugin and Inventor DLL to use the same runtime library
// (otherwise there are app crashes).
// The memory buffer seems much better option here, even although
// there will not be a real streaming. However, the model data
// are usually much smaller than textures, so we should not worry
// about it and think how to stream textures instead.
// Get the data to the buffer
size_t bufSize = 126*1024; // let's make it something bellow 128KB
char *buf = (char*)malloc(bufSize);
size_t dataSize = 0;
while (!fin.eof() && fin.good()) {
fin.read(buf+dataSize, bufSize-dataSize);
dataSize += fin.gcount();
if (bufSize == dataSize) {
bufSize *= 2;
buf = (char*)realloc(buf, bufSize);
}
}
input.setBuffer(buf, dataSize);
OSG_INFO << "osgDB::ReaderWriterIV::readNode() "
"Stream size: " << dataSize << std::endl;
// Perform reading from SoInput
osgDB::ReaderWriter::ReadResult r;
std::string fileName("");
r = readNodeFromSoInput(input, fileName, options);
// clean up and return
free(buf);
return r;
}
osgDB::ReaderWriter::WriteResult
ReaderWriterIV::writeNode(const osg::Node& node, const std::string& fileName,
const osgDB::ReaderWriter::Options* options) const
{
// accept extension
std::string ext = osgDB::getLowerCaseFileExtension(fileName);
if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED;
bool useVRML1 = !isInventorExtension(osgDB::getFileExtension(fileName));
OSG_NOTICE << "osgDB::ReaderWriterIV::writeNode() Writing file "
<< fileName.data() << std::endl;
// Convert OSG graph to Inventor graph
ConvertToInventor osg2iv;
osg2iv.setVRML1Conversion(useVRML1);
(const_cast<osg::Node*>(&node))->accept(osg2iv);
SoNode *ivRoot = osg2iv.getIvSceneGraph();
if (ivRoot == NULL)
return WriteResult::ERROR_IN_WRITING_FILE;
ivRoot->ref();
// Change prefix according to VRML spec:
// Node names must not begin with a digit, and must not contain spaces or
// control characters, single or double quote characters, backslashes, curly braces,
// the sharp (#) character, the plus (+) character or the period character.
if (useVRML1)
SoBase::setInstancePrefix("_");
// Write Inventor graph to file
SoOutput out;
out.setHeaderString((useVRML1) ? "#VRML V1.0 ascii" : "#Inventor V2.1 ascii");
if (!out.openFile(fileName.c_str()))
return WriteResult::ERROR_IN_WRITING_FILE;
SoWriteAction wa(&out);
wa.apply(ivRoot);
ivRoot->unref();
return WriteResult::FILE_SAVED;
}
static void addSearchPaths(const osgDB::FilePathList *searchPaths)
{
for (int i=searchPaths->size()-1; i>=0; i--)
SoInput::addDirectoryFirst(searchPaths->operator[](i).c_str());
}
static void removeSearchPaths(const osgDB::FilePathList *searchPaths)
{
for (int i=0, c=searchPaths->size(); i<c; i++)
SoInput::addDirectoryFirst(searchPaths->operator[](i).c_str());
}