root/OpenSceneGraph/trunk/src/osgDB/OutputStream.cpp @ 10986

Revision 10986, 20.9 kB (checked in by robert, 5 years ago)

From Wang Rui, refactored the InputStream/OutputStream? operations so that the binar/ascii foramts are implemented via subclasses.

Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2010 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13// Written by Wang Rui, (C) 2010
14
15#include <osg/Version>
16#include <osg/Notify>
17#include <osgDB/FileUtils>
18#include <osgDB/WriteFile>
19#include <osgDB/ObjectWrapper>
20#include <fstream>
21
22using namespace osgDB;
23
24OutputStream::OutputStream( const osgDB::Options* options )
25:   _writeImageHint(WRITE_USE_IMAGE_HINT),
26    _out(0)
27{
28    if ( !options ) return;
29   
30    StringList optionList;
31    split( options->getOptionString(), optionList );
32    for ( StringList::iterator itr=optionList.begin(); itr!=optionList.end(); ++itr )
33    {
34        const std::string& option = *itr;
35        if ( option=="Ascii" )
36        {
37            // Omit this
38        }
39        else
40        {
41            StringList keyAndValues;
42            split( option, keyAndValues, '=' );
43            if ( keyAndValues.size()<2 ) continue;
44           
45            if ( keyAndValues[0]=="SchemaFile" )
46            {
47                osgDB::ofstream schemaStream( keyAndValues[1].c_str(), std::ios::out );
48                if ( !schemaStream.fail() ) writeSchema( schemaStream );
49                schemaStream.close();
50            }
51            else if ( keyAndValues[0]=="Compressor" )
52                _compressorName = keyAndValues[1];
53            else if ( keyAndValues[0]=="WriteImageHint" )
54            {
55                if ( keyAndValues[1]=="IncludeData" ) _writeImageHint = WRITE_INLINE_DATA;
56                else if ( keyAndValues[1]=="IncludeFile" ) _writeImageHint = WRITE_INLINE_FILE;
57                else if ( keyAndValues[1]=="UseExternal" ) _writeImageHint = WRITE_USE_EXTERNAL;
58                else if ( keyAndValues[1]=="WriteOut" ) _writeImageHint = WRITE_EXTERNAL_FILE;
59            }
60            else
61                osg::notify(osg::WARN) << "OutputStream: Unknown option " << option << std::endl;
62        }
63    }
64}
65
66OutputStream::~OutputStream()
67{
68}
69
70OutputStream& OutputStream::operator<<( const osg::Vec2b& v )
71{ *this << v.x() << v.y(); return *this; }
72
73OutputStream& OutputStream::operator<<( const osg::Vec3b& v )
74{ *this << v.x() << v.y() << v.z(); return *this; }
75
76OutputStream& OutputStream::operator<<( const osg::Vec4b& v )
77{ *this << v.x() << v.y() << v.z() << v.w(); return *this; }
78
79OutputStream& OutputStream::operator<<( const osg::Vec4ub& v )
80{ *this << v.r() << v.g() << v.b() << v.a(); return *this; }
81
82OutputStream& OutputStream::operator<<( const osg::Vec2s& v )
83{ *this << v.x() << v.y(); return *this; }
84
85OutputStream& OutputStream::operator<<( const osg::Vec3s& v )
86{ *this << v.x() << v.y() << v.z(); return *this; }
87
88OutputStream& OutputStream::operator<<( const osg::Vec4s& v )
89{ *this << v.x() << v.y() << v.z() << v.w(); return *this; }
90
91OutputStream& OutputStream::operator<<( const osg::Vec2f& v )
92{ *this << v.x() << v.y(); return *this; }
93
94OutputStream& OutputStream::operator<<( const osg::Vec3f& v )
95{ *this << v.x() << v.y() << v.z(); return *this; }
96
97OutputStream& OutputStream::operator<<( const osg::Vec4f& v )
98{ *this << v.x() << v.y() << v.z() << v.w(); return *this; }
99
100OutputStream& OutputStream::operator<<( const osg::Vec2d& v )
101{ *this << v.x() << v.y(); return *this; }
102
103OutputStream& OutputStream::operator<<( const osg::Vec3d& v )
104{ *this << v.x() << v.y() << v.z(); return *this; }
105
106OutputStream& OutputStream::operator<<( const osg::Vec4d& v )
107{ *this << v.x() << v.y() << v.z() << v.w(); return *this; }
108
109OutputStream& OutputStream::operator<<( const osg::Quat& q )
110{ *this << q.x() << q.y() << q.z() << q.w(); return *this; }
111
112OutputStream& OutputStream::operator<<( const osg::Plane& p )
113{ *this << (double)p[0] << (double)p[1] << (double)p[2] << (double)p[3]; return *this; }
114
115OutputStream& OutputStream::operator<<( const osg::Matrixf& mat )
116{
117    *this << PROPERTY("Matrixf") << BEGIN_BRACKET << std::endl;
118    for ( int r=0; r<4; ++r )
119    {
120        *this << mat(r, 0) << mat(r, 1)
121              << mat(r, 2) << mat(r, 3) << std::endl;
122    }
123    *this << END_BRACKET << std::endl;
124    return *this;
125}
126
127OutputStream& OutputStream::operator<<( const osg::Matrixd& mat )
128{
129    *this << PROPERTY("Matrixd") << BEGIN_BRACKET << std::endl;
130    for ( int r=0; r<4; ++r )
131    {
132        *this << mat(r, 0) << mat(r, 1)
133              << mat(r, 2) << mat(r, 3) << std::endl;
134    }
135    *this << END_BRACKET << std::endl;
136    return *this;
137}
138
139void OutputStream::writeArray( const osg::Array* a )
140{
141    if ( !a ) return;
142   
143    unsigned int id = findOrCreateArrayID( a );
144    *this << PROPERTY("ArrayID") << id;
145    if ( id<_arrayMap.size() )  // Shared array
146    {
147        *this << std::endl;
148        return;
149    }
150   
151    switch ( a->getType() )
152    {
153    case osg::Array::ByteArrayType:
154        *this << MAPPEE(ArrayType, ID_BYTE_ARRAY);
155        writeArrayImplementation( static_cast<const osg::ByteArray*>(a), a->getNumElements(), 4 );
156        break;
157    case osg::Array::UByteArrayType:
158        *this << MAPPEE(ArrayType, ID_UBYTE_ARRAY);
159        writeArrayImplementation( static_cast<const osg::UByteArray*>(a), a->getNumElements(), 4 );
160        break;
161    case osg::Array::ShortArrayType:
162        *this << MAPPEE(ArrayType, ID_SHORT_ARRAY);
163        writeArrayImplementation( static_cast<const osg::ShortArray*>(a), a->getNumElements(), 4 );
164        break;
165    case osg::Array::UShortArrayType:
166        *this << MAPPEE(ArrayType, ID_USHORT_ARRAY);
167        writeArrayImplementation( static_cast<const osg::UShortArray*>(a), a->getNumElements(), 4 );
168        break;
169    case osg::Array::IntArrayType:
170        *this << MAPPEE(ArrayType, ID_INT_ARRAY);
171        writeArrayImplementation( static_cast<const osg::IntArray*>(a), a->getNumElements(), 4 );
172        break;
173    case osg::Array::UIntArrayType:
174        *this << MAPPEE(ArrayType, ID_UINT_ARRAY);
175        writeArrayImplementation( static_cast<const osg::UIntArray*>(a), a->getNumElements(), 4 );
176        break;
177    case osg::Array::FloatArrayType:
178        *this << MAPPEE(ArrayType, ID_FLOAT_ARRAY);
179        writeArrayImplementation( static_cast<const osg::FloatArray*>(a), a->getNumElements(), 4 );
180        break;
181    case osg::Array::DoubleArrayType:
182        *this << MAPPEE(ArrayType, ID_DOUBLE_ARRAY);
183        writeArrayImplementation( static_cast<const osg::DoubleArray*>(a), a->getNumElements(), 4 );
184        break;
185    case osg::Array::Vec2bArrayType:
186        *this << MAPPEE(ArrayType, ID_VEC2B_ARRAY);
187        writeArrayImplementation( static_cast<const osg::Vec2bArray*>(a), a->getNumElements() );
188        break;
189    case osg::Array::Vec3bArrayType:
190        *this << MAPPEE(ArrayType, ID_VEC3B_ARRAY);
191        writeArrayImplementation( static_cast<const osg::Vec3bArray*>(a), a->getNumElements() );
192        break;
193    case osg::Array::Vec4bArrayType:
194        *this << MAPPEE(ArrayType, ID_VEC4B_ARRAY);
195        writeArrayImplementation( static_cast<const osg::Vec4bArray*>(a), a->getNumElements() );
196        break;
197    case osg::Array::Vec4ubArrayType:
198        *this << MAPPEE(ArrayType, ID_VEC4UB_ARRAY);
199        writeArrayImplementation( static_cast<const osg::Vec4ubArray*>(a), a->getNumElements() );
200        break;
201    case osg::Array::Vec2sArrayType:
202        *this << MAPPEE(ArrayType, ID_VEC2S_ARRAY);
203        writeArrayImplementation( static_cast<const osg::Vec2sArray*>(a), a->getNumElements() );
204        break;
205    case osg::Array::Vec3sArrayType:
206        *this << MAPPEE(ArrayType, ID_VEC3S_ARRAY);
207        writeArrayImplementation( static_cast<const osg::Vec3sArray*>(a), a->getNumElements() );
208        break;
209    case osg::Array::Vec4sArrayType:
210        *this << MAPPEE(ArrayType, ID_VEC4S_ARRAY);
211        writeArrayImplementation( static_cast<const osg::Vec4sArray*>(a), a->getNumElements() );
212        break;
213    case osg::Array::Vec2ArrayType:
214        *this << MAPPEE(ArrayType, ID_VEC2_ARRAY);
215        writeArrayImplementation( static_cast<const osg::Vec2Array*>(a), a->getNumElements() );
216        break;
217    case osg::Array::Vec3ArrayType:
218        *this << MAPPEE(ArrayType, ID_VEC3_ARRAY);
219        writeArrayImplementation( static_cast<const osg::Vec3Array*>(a), a->getNumElements() );
220        break;
221    case osg::Array::Vec4ArrayType:
222        *this << MAPPEE(ArrayType, ID_VEC4_ARRAY);
223        writeArrayImplementation( static_cast<const osg::Vec4Array*>(a), a->getNumElements() );
224        break;
225    case osg::Array::Vec2dArrayType:
226        *this << MAPPEE(ArrayType, ID_VEC4D_ARRAY);
227        writeArrayImplementation( static_cast<const osg::Vec2dArray*>(a), a->getNumElements() );
228        break;
229    case osg::Array::Vec3dArrayType:
230        *this << MAPPEE(ArrayType, ID_VEC4D_ARRAY);
231        writeArrayImplementation( static_cast<const osg::Vec3dArray*>(a), a->getNumElements() );
232        break;
233    case osg::Array::Vec4dArrayType:
234        *this << MAPPEE(ArrayType, ID_VEC4D_ARRAY);
235        writeArrayImplementation( static_cast<const osg::Vec4dArray*>(a), a->getNumElements() );
236        break;
237    default:
238        throw OutputException(_currentField, "OutputStream::writeArray(): Unsupported array type.");
239    }
240}
241
242void OutputStream::writePrimitiveSet( const osg::PrimitiveSet* p )
243{
244    if ( !p ) return;
245   
246    switch ( p->getType() )
247    {
248    case osg::PrimitiveSet::DrawArraysPrimitiveType:
249        *this << MAPPEE(PrimitiveType, ID_DRAWARRAYS);
250        {
251            const osg::DrawArrays* da = static_cast<const osg::DrawArrays*>(p);
252            *this << MAPPEE(PrimitiveType, da->getMode())
253                  << da->getFirst() << da->getCount() << std::endl;
254        }
255        break;
256    case osg::PrimitiveSet::DrawArrayLengthsPrimitiveType:
257        *this << MAPPEE(PrimitiveType, ID_DRAWARRAY_LENGTH);
258        {
259            const osg::DrawArrayLengths* dl = static_cast<const osg::DrawArrayLengths*>(p);
260            *this << MAPPEE(PrimitiveType, dl->getMode()) << dl->getFirst();
261            writeArrayImplementation( dl, dl->size(), 4 );
262        }
263        break;
264    case osg::PrimitiveSet::DrawElementsUBytePrimitiveType:
265        *this << MAPPEE(PrimitiveType, ID_DRAWELEMENTS_UBYTE);
266        {
267            const osg::DrawElementsUByte* de = static_cast<const osg::DrawElementsUByte*>(p);
268            *this << MAPPEE(PrimitiveType, de->getMode());
269            writeArrayImplementation( de, de->size(), 4 );
270        }
271        break;
272    case osg::PrimitiveSet::DrawElementsUShortPrimitiveType:
273        *this << MAPPEE(PrimitiveType, ID_DRAWELEMENTS_USHORT);
274        {
275            const osg::DrawElementsUShort* de = static_cast<const osg::DrawElementsUShort*>(p);
276            *this << MAPPEE(PrimitiveType, de->getMode());
277            writeArrayImplementation( de, de->size(), 4 );
278        }
279        break;
280    case osg::PrimitiveSet::DrawElementsUIntPrimitiveType:
281        *this << MAPPEE(PrimitiveType, ID_DRAWELEMENTS_UINT);
282        {
283            const osg::DrawElementsUInt* de = static_cast<const osg::DrawElementsUInt*>(p);
284            *this << MAPPEE(PrimitiveType, de->getMode());
285            writeArrayImplementation( de, de->size(), 4 );
286        }
287        break;
288    default:
289        throw OutputException(_currentField, "OutputStream::writePrimitiveSet(): Unsupported primitive type.");
290    }
291}
292
293void OutputStream::writeImage( const osg::Image* img )
294{
295    if ( !img ) return;
296   
297    *this << PROPERTY("FileName"); writeWrappedString(img->getFileName()); *this << std::endl;
298    *this << PROPERTY("WriteHint") << (int)img->getWriteHint();
299   
300    int decision = IMAGE_EXTERNAL;
301    switch ( _writeImageHint )
302    {
303    case OutputStream::WRITE_INLINE_DATA: decision = IMAGE_INLINE_DATA; break;
304    case OutputStream::WRITE_INLINE_FILE: decision = IMAGE_INLINE_FILE; break;
305    case OutputStream::WRITE_EXTERNAL_FILE: decision = IMAGE_EXTERNAL; break;
306    case OutputStream::WRITE_USE_EXTERNAL: decision = IMAGE_WRITE_OUT; break;
307    default:
308        if ( img->getWriteHint()==osg::Image::STORE_INLINE && isBinary() )
309            decision = IMAGE_INLINE_DATA;
310        else if ( img->getWriteHint()==osg::Image::EXTERNAL_FILE )
311            decision = IMAGE_WRITE_OUT;
312        break;
313    }
314   
315    *this << decision << std::endl;
316    if ( decision==IMAGE_WRITE_OUT || _writeImageHint==WRITE_EXTERNAL_FILE )
317    {
318        bool result = osgDB::writeImageFile( *img, img->getFileName() );
319        osg::notify(osg::NOTICE) << "OutputStream::writeImage(): Write image data to external file "
320                                 << img->getFileName() << std::endl;
321        if ( !result )
322        {
323            osg::notify(osg::WARN) << "OutputStream::writeImage(): Failed to write "
324                                   << img->getFileName() << std::endl;
325        }
326    }
327   
328    switch ( decision )
329    {
330    case IMAGE_INLINE_DATA:
331        if ( isBinary() )
332        {
333            *this << img->getOrigin();  // _origin
334            *this << img->s() << img->t() << img->r(); // _s & _t & _r
335            *this << img->getInternalTextureFormat();  // _internalTextureFormat
336            *this << img->getPixelFormat();  // _pixelFormat
337            *this << img->getDataType();  // _dataType
338            *this << img->getPacking();  // _packing
339            *this << img->getAllocationMode();  // _allocationMode
340           
341            // _data
342            unsigned int size = img->getTotalSizeInBytesIncludingMipmaps();
343            *this << size; writeCharArray( (char*)img->data(), size );
344           
345            // _mipmapData
346            const osg::Image::MipmapDataType& levels = img->getMipmapLevels();
347            *this << levels.size();
348            for ( osg::Image::MipmapDataType::const_iterator itr=levels.begin();
349                  itr!=levels.end(); ++itr )
350            {
351                *this << *itr;
352            }
353        }
354        break;
355    case IMAGE_INLINE_FILE:
356        if ( isBinary() )
357        {
358            std::string fullPath = osgDB::findDataFile( img->getFileName() );
359            std::ifstream infile( fullPath.c_str(), std::ios::in|std::ios::binary );
360            if ( infile )
361            {
362                infile.seekg( 0, std::ios::end );
363                unsigned int size = infile.tellg();
364                *this << size;
365               
366                if ( size>0 )
367                {
368                    char* data = new char[size];
369                    if ( !data )
370                        throw OutputException(_currentField, "OutputStream::writeImage(): Out of memory.");
371                    infile.seekg( 0, std::ios::beg );
372                    infile.read( data, size );
373                    writeCharArray( data, size );
374                    delete[] data;
375                }
376                infile.close();
377            }
378            else
379            {
380                osg::notify(osg::WARN) << "OutputStream::writeImage(): Failed to open image file "
381                                       << img->getFileName() << std::endl;
382                *this << (unsigned int)0;
383            }
384        }
385        break;
386    case IMAGE_EXTERNAL:
387        break;
388    default:
389        break;
390    }
391   
392    writeObject( img );
393}
394
395void OutputStream::writeObject( const osg::Object* obj )
396{
397    if ( !obj ) return;
398   
399    std::string name = obj->libraryName();
400    name += std::string("::") + obj->className();
401    unsigned int id = findOrCreateObjectID( obj );
402   
403    *this << name << BEGIN_BRACKET << std::endl;       // Write object name
404    *this << PROPERTY("UniqueID") << id << std::endl;  // Write object ID
405   
406    // Check whether this is a shared object or not
407    if ( id>=_objectMap.size() )
408    {
409        ObjectWrapper* wrapper = Registry::instance()->getObjectWrapperManager()->findWrapper( name );
410        if ( !wrapper )
411        {
412            osg::notify(osg::WARN) << "OutputStream::writeObject(): Unsupported wrapper class "
413                                   << name << std::endl;
414            *this << END_BRACKET << std::endl;
415            return;
416        }
417       
418        const StringList& associates = wrapper->getAssociates();
419        for ( StringList::const_iterator itr=associates.begin(); itr!=associates.end(); ++itr )
420        {
421            ObjectWrapper* assocWrapper = Registry::instance()->getObjectWrapperManager()->findWrapper(*itr);
422            if ( !assocWrapper )
423            {
424                osg::notify(osg::WARN) << "OutputStream::writeObject(): Unsupported associated class "
425                                       << *itr << std::endl;
426                continue;
427            }
428           
429            _currentField = assocWrapper->getName();
430            assocWrapper->write( *this, *obj );
431        }
432    }
433    *this << END_BRACKET << std::endl;
434}
435
436void OutputStream::start( OutputIterator* outIterator, OutputStream::WriteType type )
437{
438    _currentField = "Header";
439    _out = outIterator;
440    if ( !_out )
441        throw OutputException(_currentField, "OutputStream: Null stream specified.");
442   
443    if ( isBinary() )
444    {
445        *this << (unsigned int)OSG_HEADER_LOW << (unsigned int)OSG_HEADER_HIGH
446              << (unsigned int)type << (unsigned int)PLUGIN_VERSION;
447       
448        if ( sizeof(osg::Matrix::value_type)==FLOAT_SIZE ) *this << (unsigned int)0;
449        else *this << (unsigned int)1;  // Record matrix value type of current built OSG
450       
451        if ( !_compressorName.empty() )
452        {
453            BaseCompressor* compressor = Registry::instance()->getObjectWrapperManager()->findCompressor(_compressorName);
454            if ( !compressor )
455            {
456                osg::notify(osg::WARN) << "OutputStream::start(): No such compressor "
457                                       << _compressorName << std::endl;
458            }
459            else
460            {
461                *this << _compressorName;
462                _out->getStream()->flush();
463                _out->setStream( &_compressSource );
464                return;
465            }
466        }
467        *this << std::string("0");
468    }
469    else
470    {
471        std::string typeString("Unknown");
472        switch ( type )
473        {
474        case WRITE_SCENE: typeString = "Scene"; break;
475        case WRITE_IMAGE: typeString = "Image"; break;
476        default: break;
477        }
478       
479        *this << PROPERTY("#Ascii") << typeString << std::endl;
480        *this << PROPERTY("#Version") << (unsigned int)PLUGIN_VERSION << std::endl;
481        *this << PROPERTY("#Generator") << std::string("OpenSceneGraph")
482              << std::string(osgGetVersion()) << std::endl;
483        *this << std::endl;
484    }
485}
486
487void OutputStream::compress( std::ostream* ostream )
488{
489    _currentField = "Compression";
490    if ( _compressorName.empty() || !isBinary() ) return;
491   
492    BaseCompressor* compressor = Registry::instance()->getObjectWrapperManager()->findCompressor(_compressorName);
493    if ( !compressor || !ostream ) return;
494   
495    if ( !compressor->compress(*ostream, _compressSource.str()) )
496        throw OutputException(_currentField, "OutputStream: Failed to compress stream.");
497}
498
499// PROTECTED METHODS
500
501void OutputStream::writeSchema( std::ostream& fout )
502{
503    // Write to external ascii stream
504    const ObjectWrapperManager::WrapperMap& wrappers = Registry::instance()->getObjectWrapperManager()->getWrapperMap();
505    for ( ObjectWrapperManager::WrapperMap::const_iterator itr=wrappers.begin();
506          itr!=wrappers.end(); ++itr )
507    {
508        ObjectWrapper* wrapper = itr->second.get();
509        fout << itr->first << " =";
510       
511        StringList properties;
512        wrapper->writeSchema( properties );
513        if ( properties.size()>0 )
514        {
515            for ( StringList::iterator sitr=properties.begin(); sitr!=properties.end(); ++sitr )
516            {
517                fout << ' ' << *sitr;
518            }
519        }
520        fout << std::endl;
521    }
522}
523
524template<typename T>
525void OutputStream::writeArrayImplementation( const T* a, int writeSize, unsigned int numInRow )
526{
527    *this << writeSize << BEGIN_BRACKET;
528    if ( numInRow>1 )
529    {
530        for ( int i=0; i<writeSize; ++i )
531        {
532            if ( !(i%numInRow) )
533            {
534                *this << std::endl << (*a)[i];
535            }
536            else
537                *this << (*a)[i];
538        }
539        *this << std::endl;
540    }
541    else
542    {
543        *this << std::endl;
544        for ( int i=0; i<writeSize; ++i )
545            *this << (*a)[i] << std::endl;
546    }
547    *this << END_BRACKET << std::endl;
548}
549
550unsigned int OutputStream::findOrCreateArrayID( const osg::Array* array )
551{
552    ArrayMap::iterator itr = _arrayMap.find( array );
553    if ( itr==_arrayMap.end() )
554    {
555        unsigned int id = _arrayMap.size()+1;
556        _arrayMap[array] = id;
557        return id;
558    }
559    return itr->second;
560}
561
562unsigned int OutputStream::findOrCreateObjectID( const osg::Object* obj )
563{
564    ObjectMap::iterator itr = _objectMap.find( obj );
565    if ( itr==_objectMap.end() )
566    {
567        unsigned int id = _objectMap.size()+1;
568        _objectMap[obj] = id;
569        return id;
570    }
571    return itr->second;
572}
Note: See TracBrowser for help on using the browser.