root/OpenSceneGraph/trunk/src/osgPlugins/Inventor/ReaderWriterIV.cpp @ 12912

Revision 12912, 9.8 kB (checked in by robert, 2 years ago)

Added support for using GL_UNPACK_ROW_LENGTH in conjunction with texture's + osg::Image via new RowLength?
parameter in osg::Image. To support this Image::setData(..) now has a new optional rowLength parameter which
defaults to 0, which provides the original behaviour, Image::setRowLength(int) and int Image::getRowLength() are also provided.

With the introduction of RowLength? support in osg::Image it is now possible to create a sub image where
the t size of the image are smaller than the row length, useful for when you have a large image on the CPU
and which to use a small portion of it on the GPU. However, when these sub images are created the data
within the image is no longer contiguous so data access can no longer assume that all the data is in
one block. The new method Image::isDataContiguous() enables the user to check whether the data is contiguous,
and if not one can either access the data row by row using Image::data(column,row,image) accessor, or use the
new Image::DataIterator? for stepping through each block on memory assocatied with the image.

To support the possibility of non contiguous osg::Image usage of image objects has had to be updated to
check DataContiguous? and handle the case or use access via the DataIerator? or by row by row. To achieve
this a relatively large number of files has had to be modified, in particular the texture classes and
image plugins that doing writing.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1// OSG headers
2#include <osg/Notify>
3#include <osgDB/FileUtils>
4#include <osgDB/FileNameUtils>
5
6// Inventor headers
7#include <Inventor/SoDB.h>
8#include <Inventor/SoInteraction.h>
9#include <Inventor/nodekits/SoNodeKit.h>
10#include <Inventor/errors/SoDebugError.h>
11#include <Inventor/errors/SoMemoryError.h>
12#include <Inventor/errors/SoReadError.h>
13#include <Inventor/nodes/SoSeparator.h>
14#include <Inventor/actions/SoWriteAction.h>
15#include <Inventor/actions/SoCallbackAction.h>
16#ifdef __COIN__
17# include <Inventor/VRMLnodes/SoVRMLImageTexture.h>
18#endif
19
20#include "ReaderWriterIV.h"
21#include "ConvertFromInventor.h"
22#include "ConvertToInventor.h"
23
24// forward declarations of static functions
25static void addSearchPaths(const osgDB::FilePathList *searchPaths);
26static void removeSearchPaths(const osgDB::FilePathList *searchPaths);
27static void errorCallback(const SoError *error, void * data);
28
29
30// Register with Registry to instantiate the inventor reader.
31REGISTER_OSGPLUGIN(Inventor, ReaderWriterIV)
32
33
34/**
35 * Constructor.
36 * Initializes the ReaderWriterIV.
37 */
38ReaderWriterIV::ReaderWriterIV()
39{
40    // Set supported extensions and options
41    supportsExtension("iv","Inventor format");
42    supportsExtension("wrl","VRML world file");
43
44    // Initialize Inventor
45    initInventor();
46}
47
48
49/**
50 * Initializes Open Inventor.
51 */
52void ReaderWriterIV::initInventor() const
53{
54    // Initialize Inventor
55    SoDB::init();
56    SoNodeKit::init();
57    SoInteraction::init();
58
59    // Redirect error messages to OSG notify
60    SoError::setHandlerCallback(errorCallback, NULL);
61    SoDebugError::setHandlerCallback(errorCallback, NULL);
62    SoMemoryError::setHandlerCallback(errorCallback, NULL);
63    SoReadError::setHandlerCallback(errorCallback, NULL);
64
65#ifdef __COIN__
66    // Disable delayed loading of VRML textures
67    SoVRMLImageTexture::setDelayFetchURL(FALSE);
68
69    // initialize convertor
70    ConvertFromInventor::init();
71#endif
72}
73
74
75static void errorCallback(const SoError *error, void *data)
76{
77    // note: Coin and SGI Inventor puts "Inventor read error..." or "Coin warning..."
78    // introduction string to the error message, so we do not prepend the error message
79    // by anything.
80
81    if (error->isOfType(SoDebugError::getClassTypeId()))
82    {
83        switch (((SoDebugError*)error)->getSeverity())
84        {
85            case SoDebugError::INFO:
86                OSG_INFO << error->getDebugString().getString() << std::endl;
87                break;
88            case SoDebugError::WARNING:
89                OSG_WARN << error->getDebugString().getString() << std::endl;
90                break;
91            case SoDebugError::ERROR:
92            default:
93                OSG_WARN << error->getDebugString().getString() << std::endl;
94                break;
95        }
96    }
97    else
98    {
99        OSG_WARN << error->getDebugString().getString() << std::endl;
100    }
101}
102
103
104/**
105 * Read from SoInput and convert to OSG.
106 * This is a method used by readNode(string,options) and readNode(istream,options).
107 */
108osgDB::ReaderWriter::ReadResult
109ReaderWriterIV::readNodeFromSoInput(SoInput &input,
110          std::string &fileName, const osgDB::ReaderWriter::Options *options) const
111{
112    // Parse options and add search paths to SoInput
113    const osgDB::FilePathList *searchPaths = options ? &options->getDatabasePathList() : NULL;
114    if (options)
115        addSearchPaths(searchPaths);
116
117    // Create the inventor scenegraph by reading from SoInput
118    SoSeparator* rootIVNode = SoDB::readAll(&input);
119
120    // Remove recently appened search paths
121    if (options)
122        removeSearchPaths(searchPaths);
123
124    // Close the file
125    input.closeFile();
126
127    // Perform conversion
128    ReadResult result;
129    if (rootIVNode)
130    {
131        rootIVNode->ref();
132        // Convert the inventor scenegraph to an osg scenegraph
133        ConvertFromInventor convertIV;
134        convertIV.preprocess(rootIVNode);
135        result = convertIV.convert(rootIVNode);
136        rootIVNode->unref();
137    } else
138        result = ReadResult::FILE_NOT_HANDLED;
139
140    // Notify
141    if (result.success()) {
142        if (fileName.length())
143        {
144            OSG_NOTICE << "osgDB::ReaderWriterIV::readNode() "
145                      << "File " << fileName
146                      << " loaded successfully." << std::endl;
147        }
148        else
149        {
150            OSG_NOTICE << "osgDB::ReaderWriterIV::readNode() "
151                      << "Stream loaded successfully." << std::endl;
152        }
153    } else {
154        if (fileName.length())
155        {
156            OSG_WARN << "osgDB::ReaderWriterIV::readNode() "
157                      << "Failed to load file " << fileName
158                      << "." << std::endl;
159        }
160        else
161        {
162            OSG_WARN << "osgDB::ReaderWriterIV::readNode() "
163                  << "Failed to load stream." << std::endl;
164        }
165    }
166
167    return result;
168}
169
170
171// Read file and convert to OSG
172osgDB::ReaderWriter::ReadResult
173ReaderWriterIV::readNode(const std::string& file,
174                         const osgDB::ReaderWriter::Options* options) const
175{
176    // Accept extension
177    std::string ext = osgDB::getLowerCaseFileExtension(file);
178    if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
179
180    // Find file
181    std::string fileName = osgDB::findDataFile( file, options );
182    if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
183
184    // Notify
185    OSG_NOTICE << "osgDB::ReaderWriterIV::readNode() Reading file "
186                             << fileName.data() << std::endl;
187    OSG_INFO << "osgDB::ReaderWriterIV::readNode() Inventor version: "
188                           << SoDB::getVersion() << std::endl;
189
190    // Open the file
191    SoInput input;
192    if (!input.openFile(fileName.data()))
193    {
194        OSG_WARN << "osgDB::ReaderWriterIV::readIVFile() "
195                               << "Cannot open file " << fileName << std::endl;
196        return ReadResult::ERROR_IN_READING_FILE;
197    }
198
199    // Perform reading from SoInput
200    return readNodeFromSoInput(input, fileName, options);
201}
202
203
204osgDB::ReaderWriter::ReadResult
205ReaderWriterIV::readNode(std::istream& fin,
206                         const osgDB::ReaderWriter::Options* options) const
207{
208    // Notify
209    OSG_NOTICE << "osgDB::ReaderWriterIV::readNode() "
210              "Reading from stream." << std::endl;
211    OSG_INFO << "osgDB::ReaderWriterIV::readNode() "
212              "Inventor version: " << SoDB::getVersion() << std::endl;
213
214    // Open the file
215    SoInput input;
216
217    // Assign istream to SoInput
218    // note: It seems there is no straightforward way to do that.
219    // SoInput accepts only FILE by setFilePointer or memory buffer
220    // by setBuffer. The FILE is dangerous on Windows, since it forces
221    // the plugin and Inventor DLL to use the same runtime library
222    // (otherwise there are app crashes).
223    // The memory buffer seems much better option here, even although
224    // there will not be a real streaming. However, the model data
225    // are usually much smaller than textures, so we should not worry
226    // about it and think how to stream textures instead.
227
228    // Get the data to the buffer
229    size_t bufSize = 126*1024; // let's make it something bellow 128KB
230    char *buf = (char*)malloc(bufSize);
231    size_t dataSize = 0;
232    while (!fin.eof() && fin.good()) {
233        fin.read(buf+dataSize, bufSize-dataSize);
234        dataSize += fin.gcount();
235        if (bufSize == dataSize) {
236           bufSize *= 2;
237           char* new_buf = (char*)realloc(buf, bufSize);
238           if (!new_buf)
239           {
240               free(buf);
241               return osgDB::ReaderWriter::ReadResult::INSUFFICIENT_MEMORY_TO_LOAD;
242           }
243           buf = new_buf;
244        }
245    }
246    input.setBuffer(buf, dataSize);
247    OSG_INFO << "osgDB::ReaderWriterIV::readNode() "
248              "Stream size: " << dataSize << std::endl;
249
250    // Perform reading from SoInput
251    osgDB::ReaderWriter::ReadResult r;
252    std::string fileName("");
253    r = readNodeFromSoInput(input, fileName, options);
254
255    // clean up and return
256    free(buf);
257    return r;
258}
259
260
261osgDB::ReaderWriter::WriteResult
262ReaderWriterIV::writeNode(const osg::Node& node, const std::string& fileName,
263                          const osgDB::ReaderWriter::Options* options) const
264{
265    // accept extension
266    std::string ext = osgDB::getLowerCaseFileExtension(fileName);
267    if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED;
268    bool useVRML1 = !isInventorExtension(osgDB::getFileExtension(fileName));
269
270    OSG_NOTICE << "osgDB::ReaderWriterIV::writeNode() Writing file "
271                             << fileName.data() << std::endl;
272
273    // Convert OSG graph to Inventor graph
274    ConvertToInventor osg2iv;
275    osg2iv.setVRML1Conversion(useVRML1);
276    (const_cast<osg::Node*>(&node))->accept(osg2iv);
277    SoNode *ivRoot = osg2iv.getIvSceneGraph();
278    if (ivRoot == NULL)
279        return WriteResult::ERROR_IN_WRITING_FILE;
280    ivRoot->ref();
281
282    // Change prefix according to VRML spec:
283    // Node names must not begin with a digit, and must not contain spaces or
284    // control characters, single or double quote characters, backslashes, curly braces,
285    // the sharp (#) character, the plus (+) character or the period character.
286    if (useVRML1)
287      SoBase::setInstancePrefix("_");
288
289    // Write Inventor graph to file
290    SoOutput out;
291    out.setHeaderString((useVRML1) ? "#VRML V1.0 ascii" : "#Inventor V2.1 ascii");
292    if (!out.openFile(fileName.c_str()))
293        return WriteResult::ERROR_IN_WRITING_FILE;
294    SoWriteAction wa(&out);
295    wa.apply(ivRoot);
296    ivRoot->unref();
297
298    return WriteResult::FILE_SAVED;
299}
300
301
302static void addSearchPaths(const osgDB::FilePathList *searchPaths)
303{
304    for (int i=searchPaths->size()-1; i>=0; i--)
305        SoInput::addDirectoryFirst(searchPaths->operator[](i).c_str());
306}
307
308
309static void removeSearchPaths(const osgDB::FilePathList *searchPaths)
310{
311    for (int i=0, c=searchPaths->size(); i<c; i++)
312        SoInput::addDirectoryFirst(searchPaths->operator[](i).c_str());
313}
Note: See TracBrowser for help on using the browser.