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

Revision 13769, 28.6 kB (checked in by robert, 3 days ago)

Release OpenSceneGraph-3.3.3

  • Property svn:eol-style set to native
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#include <sstream>
22#include <stdlib.h>
23
24using namespace osgDB;
25
26OutputStream::OutputStream( const osgDB::Options* options )
27:   _writeImageHint(WRITE_USE_IMAGE_HINT), _useSchemaData(false), _useRobustBinaryFormat(true)
28{
29    BEGIN_BRACKET.set( "{", +INDENT_VALUE );
30    END_BRACKET.set( "}", -INDENT_VALUE );
31
32    if ( !options ) return;
33    _options = options;
34
35    if ( options->getPluginStringData("RobustBinaryFormat")=="false" )
36        _useRobustBinaryFormat = false;
37    if ( options->getPluginStringData("SchemaData")=="true" )
38        _useSchemaData = true;
39    if ( !options->getPluginStringData("SchemaFile").empty() )
40        _schemaName = options->getPluginStringData("SchemaFile");
41    if ( !options->getPluginStringData("Compressor").empty() )
42        _compressorName = options->getPluginStringData("Compressor");
43    if ( !options->getPluginStringData("WriteImageHint").empty() )
44    {
45        std::string hintString = options->getPluginStringData("WriteImageHint");
46        if ( hintString=="IncludeData" ) _writeImageHint = WRITE_INLINE_DATA;
47        else if ( hintString=="IncludeFile" ) _writeImageHint = WRITE_INLINE_FILE;
48        else if ( hintString=="UseExternal" ) _writeImageHint = WRITE_USE_EXTERNAL;
49        else if ( hintString=="WriteOut" ) _writeImageHint = WRITE_EXTERNAL_FILE;
50    }
51
52    if ( !options->getPluginStringData("CustomDomains").empty() )
53    {
54        StringList domains, keyAndValue;
55        split( options->getPluginStringData("CustomDomains"), domains, ';' );
56        for ( unsigned int i=0; i<domains.size(); ++i )
57        {
58            split( domains[i], keyAndValue, ':' );
59            if ( keyAndValue.size()>1 )
60                _domainVersionMap[keyAndValue.front()] = atoi(keyAndValue.back().c_str());
61        }
62    }
63}
64
65OutputStream::~OutputStream()
66{
67}
68
69int OutputStream::getFileVersion( const std::string& d ) const
70{
71    if ( d.empty() ) return OPENSCENEGRAPH_SOVERSION;
72    VersionMap::const_iterator itr = _domainVersionMap.find(d);
73    return itr==_domainVersionMap.end() ? 0 : itr->second;
74}
75
76OutputStream& OutputStream::operator<<( const osg::Vec2b& v )
77{ *this << v.x() << v.y(); return *this; }
78
79OutputStream& OutputStream::operator<<( const osg::Vec3b& v )
80{ *this << v.x() << v.y() << v.z(); return *this; }
81
82OutputStream& OutputStream::operator<<( const osg::Vec4b& v )
83{ *this << v.x() << v.y() << v.z() << v.w(); return *this; }
84
85OutputStream& OutputStream::operator<<( const osg::Vec2ub& v )
86{ *this << v.x() << v.y(); return *this; }
87
88OutputStream& OutputStream::operator<<( const osg::Vec3ub& v )
89{ *this << v.x() << v.y() << v.z(); return *this; }
90
91OutputStream& OutputStream::operator<<( const osg::Vec4ub& v )
92{ *this << v.r() << v.g() << v.b() << v.a(); return *this; }
93
94OutputStream& OutputStream::operator<<( const osg::Vec2s& v )
95{ *this << v.x() << v.y(); return *this; }
96
97OutputStream& OutputStream::operator<<( const osg::Vec3s& v )
98{ *this << v.x() << v.y() << v.z(); return *this; }
99
100OutputStream& OutputStream::operator<<( const osg::Vec4s& v )
101{ *this << v.x() << v.y() << v.z() << v.w(); return *this; }
102
103OutputStream& OutputStream::operator<<( const osg::Vec2us& v )
104{ *this << v.x() << v.y(); return *this; }
105
106OutputStream& OutputStream::operator<<( const osg::Vec3us& v )
107{ *this << v.x() << v.y() << v.z(); return *this; }
108
109OutputStream& OutputStream::operator<<( const osg::Vec4us& v )
110{ *this << v.x() << v.y() << v.z() << v.w(); return *this; }
111
112OutputStream& OutputStream::operator<<( const osg::Vec2f& v )
113{ *this << v.x() << v.y(); return *this; }
114
115OutputStream& OutputStream::operator<<( const osg::Vec3f& v )
116{ *this << v.x() << v.y() << v.z(); return *this; }
117
118OutputStream& OutputStream::operator<<( const osg::Vec4f& v )
119{ *this << v.x() << v.y() << v.z() << v.w(); return *this; }
120
121OutputStream& OutputStream::operator<<( const osg::Vec2d& v )
122{ *this << v.x() << v.y(); return *this; }
123
124OutputStream& OutputStream::operator<<( const osg::Vec3d& v )
125{ *this << v.x() << v.y() << v.z(); return *this; }
126
127OutputStream& OutputStream::operator<<( const osg::Vec4d& v )
128{ *this << v.x() << v.y() << v.z() << v.w(); return *this; }
129
130OutputStream& OutputStream::operator<<( const osg::Quat& q )
131{ *this << q.x() << q.y() << q.z() << q.w(); return *this; }
132
133OutputStream& OutputStream::operator<<( const osg::Plane& p )
134{ *this << (double)p[0] << (double)p[1] << (double)p[2] << (double)p[3]; return *this; }
135
136
137#if 0
138OutputStream& OutputStream::operator<<( const osg::Matrixf& mat )
139{
140    *this << PROPERTY("Matrixf")<<BEGIN_BRACKET << std::endl;
141    for ( int r=0; r<4; ++r )
142    {
143        *this << mat(r, 0) << mat(r, 1)
144              << mat(r, 2) << mat(r, 3) << std::endl;
145    }
146    *this << END_BRACKET << std::endl;
147    return *this;
148}
149
150OutputStream& OutputStream::operator<<( const osg::Matrixd& mat )
151{
152    *this << PROPERTY("Matrixd")<<BEGIN_BRACKET << std::endl;
153    for ( int r=0; r<4; ++r )
154    {
155        *this << mat(r, 0) << mat(r, 1)
156              << mat(r, 2) << mat(r, 3) << std::endl;
157    }
158    *this << END_BRACKET << std::endl;
159    return *this;
160}
161#else
162OutputStream& OutputStream::operator<<( const osg::Matrixf& mat )
163{
164    *this << BEGIN_BRACKET << std::endl;
165    for ( int r=0; r<4; ++r )
166    {
167        *this << (double)mat(r, 0) << (double)mat(r, 1)
168              << (double)mat(r, 2) << (double)mat(r, 3) << std::endl;
169    }
170    *this << END_BRACKET << std::endl;
171    return *this;
172}
173
174OutputStream& OutputStream::operator<<( const osg::Matrixd& mat )
175{
176    *this << BEGIN_BRACKET << std::endl;
177    for ( int r=0; r<4; ++r )
178    {
179        *this << mat(r, 0) << mat(r, 1)
180              << mat(r, 2) << mat(r, 3) << std::endl;
181    }
182    *this << END_BRACKET << std::endl;
183    return *this;
184}
185#endif
186
187void OutputStream::writeArray( const osg::Array* a )
188{
189    if ( !a ) return;
190
191    bool newID = false;
192    unsigned int id = findOrCreateArrayID( a, newID );
193    *this << PROPERTY("ArrayID") << id;
194    if ( !newID )  // Shared array
195    {
196        *this << std::endl;
197        return;
198    }
199
200    switch ( a->getType() )
201    {
202    case osg::Array::ByteArrayType:
203        *this << MAPPEE(ArrayType, ID_BYTE_ARRAY);
204        writeArrayImplementation( static_cast<const osg::ByteArray*>(a), a->getNumElements(), 4 );
205        break;
206    case osg::Array::UByteArrayType:
207        *this << MAPPEE(ArrayType, ID_UBYTE_ARRAY);
208        writeArrayImplementation( static_cast<const osg::UByteArray*>(a), a->getNumElements(), 4 );
209        break;
210    case osg::Array::ShortArrayType:
211        *this << MAPPEE(ArrayType, ID_SHORT_ARRAY);
212        writeArrayImplementation( static_cast<const osg::ShortArray*>(a), a->getNumElements(), 4 );
213        break;
214    case osg::Array::UShortArrayType:
215        *this << MAPPEE(ArrayType, ID_USHORT_ARRAY);
216        writeArrayImplementation( static_cast<const osg::UShortArray*>(a), a->getNumElements(), 4 );
217        break;
218    case osg::Array::IntArrayType:
219        *this << MAPPEE(ArrayType, ID_INT_ARRAY);
220        writeArrayImplementation( static_cast<const osg::IntArray*>(a), a->getNumElements(), 4 );
221        break;
222    case osg::Array::UIntArrayType:
223        *this << MAPPEE(ArrayType, ID_UINT_ARRAY);
224        writeArrayImplementation( static_cast<const osg::UIntArray*>(a), a->getNumElements(), 4 );
225        break;
226    case osg::Array::FloatArrayType:
227        *this << MAPPEE(ArrayType, ID_FLOAT_ARRAY);
228        writeArrayImplementation( static_cast<const osg::FloatArray*>(a), a->getNumElements(), 4 );
229        break;
230    case osg::Array::DoubleArrayType:
231        *this << MAPPEE(ArrayType, ID_DOUBLE_ARRAY);
232        writeArrayImplementation( static_cast<const osg::DoubleArray*>(a), a->getNumElements(), 4 );
233        break;
234    case osg::Array::Vec2bArrayType:
235        *this << MAPPEE(ArrayType, ID_VEC2B_ARRAY);
236        writeArrayImplementation( static_cast<const osg::Vec2bArray*>(a), a->getNumElements() );
237        break;
238    case osg::Array::Vec3bArrayType:
239        *this << MAPPEE(ArrayType, ID_VEC3B_ARRAY);
240        writeArrayImplementation( static_cast<const osg::Vec3bArray*>(a), a->getNumElements() );
241        break;
242    case osg::Array::Vec4bArrayType:
243        *this << MAPPEE(ArrayType, ID_VEC4B_ARRAY);
244        writeArrayImplementation( static_cast<const osg::Vec4bArray*>(a), a->getNumElements() );
245        break;
246    case osg::Array::Vec2ubArrayType:
247        *this << MAPPEE(ArrayType, ID_VEC2UB_ARRAY);
248        writeArrayImplementation( static_cast<const osg::Vec2ubArray*>(a), a->getNumElements() );
249        break;
250    case osg::Array::Vec3ubArrayType:
251        *this << MAPPEE(ArrayType, ID_VEC3UB_ARRAY);
252        writeArrayImplementation( static_cast<const osg::Vec3ubArray*>(a), a->getNumElements() );
253        break;
254    case osg::Array::Vec4ubArrayType:
255        *this << MAPPEE(ArrayType, ID_VEC4UB_ARRAY);
256        writeArrayImplementation( static_cast<const osg::Vec4ubArray*>(a), a->getNumElements() );
257        break;
258    case osg::Array::Vec2sArrayType:
259        *this << MAPPEE(ArrayType, ID_VEC2S_ARRAY);
260        writeArrayImplementation( static_cast<const osg::Vec2sArray*>(a), a->getNumElements() );
261        break;
262    case osg::Array::Vec3sArrayType:
263        *this << MAPPEE(ArrayType, ID_VEC3S_ARRAY);
264        writeArrayImplementation( static_cast<const osg::Vec3sArray*>(a), a->getNumElements() );
265        break;
266    case osg::Array::Vec4sArrayType:
267        *this << MAPPEE(ArrayType, ID_VEC4S_ARRAY);
268        writeArrayImplementation( static_cast<const osg::Vec4sArray*>(a), a->getNumElements() );
269        break;
270    case osg::Array::Vec2usArrayType:
271        *this << MAPPEE(ArrayType, ID_VEC2US_ARRAY);
272        writeArrayImplementation( static_cast<const osg::Vec2usArray*>(a), a->getNumElements() );
273        break;
274    case osg::Array::Vec3usArrayType:
275        *this << MAPPEE(ArrayType, ID_VEC3US_ARRAY);
276        writeArrayImplementation( static_cast<const osg::Vec3usArray*>(a), a->getNumElements() );
277        break;
278    case osg::Array::Vec4usArrayType:
279        *this << MAPPEE(ArrayType, ID_VEC4US_ARRAY);
280        writeArrayImplementation( static_cast<const osg::Vec4usArray*>(a), a->getNumElements() );
281        break;
282    case osg::Array::Vec2ArrayType:
283        *this << MAPPEE(ArrayType, ID_VEC2_ARRAY);
284        writeArrayImplementation( static_cast<const osg::Vec2Array*>(a), a->getNumElements() );
285        break;
286    case osg::Array::Vec3ArrayType:
287        *this << MAPPEE(ArrayType, ID_VEC3_ARRAY);
288        writeArrayImplementation( static_cast<const osg::Vec3Array*>(a), a->getNumElements() );
289        break;
290    case osg::Array::Vec4ArrayType:
291        *this << MAPPEE(ArrayType, ID_VEC4_ARRAY);
292        writeArrayImplementation( static_cast<const osg::Vec4Array*>(a), a->getNumElements() );
293        break;
294    case osg::Array::Vec2dArrayType:
295        *this << MAPPEE(ArrayType, ID_VEC2D_ARRAY);
296        writeArrayImplementation( static_cast<const osg::Vec2dArray*>(a), a->getNumElements() );
297        break;
298    case osg::Array::Vec3dArrayType:
299        *this << MAPPEE(ArrayType, ID_VEC3D_ARRAY);
300        writeArrayImplementation( static_cast<const osg::Vec3dArray*>(a), a->getNumElements() );
301        break;
302    case osg::Array::Vec4dArrayType:
303        *this << MAPPEE(ArrayType, ID_VEC4D_ARRAY);
304        writeArrayImplementation( static_cast<const osg::Vec4dArray*>(a), a->getNumElements() );
305        break;
306    default:
307        throwException( "OutputStream::writeArray(): Unsupported array type." );
308    }
309}
310
311void OutputStream::writePrimitiveSet( const osg::PrimitiveSet* p )
312{
313    if ( !p ) return;
314
315    switch ( p->getType() )
316    {
317    case osg::PrimitiveSet::DrawArraysPrimitiveType:
318        *this << MAPPEE(PrimitiveType, ID_DRAWARRAYS);
319        {
320            const osg::DrawArrays* da = static_cast<const osg::DrawArrays*>(p);
321            *this << MAPPEE(PrimitiveType, da->getMode()) << da->getNumInstances()
322                  << da->getFirst() << da->getCount() << std::endl;
323        }
324        break;
325    case osg::PrimitiveSet::DrawArrayLengthsPrimitiveType:
326        *this << MAPPEE(PrimitiveType, ID_DRAWARRAY_LENGTH);
327        {
328            const osg::DrawArrayLengths* dl = static_cast<const osg::DrawArrayLengths*>(p);
329            *this << MAPPEE(PrimitiveType, dl->getMode()) << dl->getNumInstances() << dl->getFirst();
330            writeArrayImplementation( dl, dl->size(), 4 );
331        }
332        break;
333    case osg::PrimitiveSet::DrawElementsUBytePrimitiveType:
334        *this << MAPPEE(PrimitiveType, ID_DRAWELEMENTS_UBYTE);
335        {
336            const osg::DrawElementsUByte* de = static_cast<const osg::DrawElementsUByte*>(p);
337            *this << MAPPEE(PrimitiveType, de->getMode()) << de->getNumInstances();
338            writeArrayImplementation( de, de->size(), 4 );
339        }
340        break;
341    case osg::PrimitiveSet::DrawElementsUShortPrimitiveType:
342        *this << MAPPEE(PrimitiveType, ID_DRAWELEMENTS_USHORT);
343        {
344            const osg::DrawElementsUShort* de = static_cast<const osg::DrawElementsUShort*>(p);
345            *this << MAPPEE(PrimitiveType, de->getMode()) << de->getNumInstances();
346            writeArrayImplementation( de, de->size(), 4 );
347        }
348        break;
349    case osg::PrimitiveSet::DrawElementsUIntPrimitiveType:
350        *this << MAPPEE(PrimitiveType, ID_DRAWELEMENTS_UINT);
351        {
352            const osg::DrawElementsUInt* de = static_cast<const osg::DrawElementsUInt*>(p);
353            *this << MAPPEE(PrimitiveType, de->getMode()) << de->getNumInstances();
354            writeArrayImplementation( de, de->size(), 4 );
355        }
356        break;
357    default:
358        throwException( "OutputStream::writePrimitiveSet(): Unsupported primitive type." );
359    }
360}
361
362void OutputStream::writeImage( const osg::Image* img )
363{
364    if ( !img ) return;
365
366    std::string name = img->libraryName();
367    name += std::string("::") + img->className();
368
369    bool newID = false;
370    unsigned int id = findOrCreateObjectID( img, newID );
371
372    *this << PROPERTY("ClassName") << name << std::endl;   // Write object name
373    *this << PROPERTY("UniqueID") << id << std::endl;      // Write image ID
374    if ( getException() ) return;
375
376    if (newID)
377    {
378        int decision = IMAGE_EXTERNAL;
379        switch ( _writeImageHint )
380        {
381        case OutputStream::WRITE_INLINE_DATA: decision = IMAGE_INLINE_DATA; break;
382        case OutputStream::WRITE_INLINE_FILE: decision = IMAGE_INLINE_FILE; break;
383        case OutputStream::WRITE_EXTERNAL_FILE: decision = IMAGE_WRITE_OUT; break;
384        case OutputStream::WRITE_USE_EXTERNAL: decision = IMAGE_EXTERNAL; break;
385        default:
386            if ( img->getWriteHint()==osg::Image::EXTERNAL_FILE )
387                decision = IMAGE_EXTERNAL;
388            else if ( isBinary() )
389                decision = IMAGE_INLINE_DATA;
390            break;
391        }
392
393
394        std::string imageFileName = img->getFileName();
395        if ( decision==IMAGE_WRITE_OUT || _writeImageHint==WRITE_EXTERNAL_FILE )
396        {
397            if (imageFileName.empty())
398            {
399                OSG_NOTICE<<"Empty Image::FileName resetting to image.dds"<<std::endl;
400                imageFileName = "image.dds";
401            }
402
403            bool result = osgDB::writeImageFile( *img, imageFileName );
404            OSG_NOTICE << "OutputStream::writeImage(): Write image data to external file " << imageFileName << std::endl;
405            if ( !result )
406            {
407                OSG_WARN << "OutputStream::writeImage(): Failed to write " << img->getFileName() << std::endl;
408            }
409        }
410
411        *this << PROPERTY("FileName"); writeWrappedString(imageFileName); *this << std::endl;
412        *this << PROPERTY("WriteHint") << (int)img->getWriteHint();
413        if ( getException() ) return;
414
415        *this << decision << std::endl;
416
417        switch ( decision )
418        {
419        case IMAGE_INLINE_DATA:
420            if ( isBinary() )
421            {
422                *this << img->getOrigin();  // _origin
423                *this << img->s() << img->t() << img->r(); // _s & _t & _r
424                *this << img->getInternalTextureFormat();  // _internalTextureFormat
425                *this << img->getPixelFormat();  // _pixelFormat
426                *this << img->getDataType();  // _dataType
427                *this << img->getPacking();  // _packing
428                *this << img->getAllocationMode();  // _allocationMode
429
430                // _data
431                unsigned int size = img->getTotalSizeInBytesIncludingMipmaps();
432                writeSize(size);
433
434                for(osg::Image::DataIterator img_itr(img); img_itr.valid(); ++img_itr)
435                {
436                    writeCharArray( (char*)img_itr.data(), img_itr.size() );
437                }
438
439                // _mipmapData
440                unsigned int numMipmaps = img->getNumMipmapLevels()-1;
441                writeSize(numMipmaps);
442                int s = img->s();
443                int t = img->t();
444                int r = img->r();
445                unsigned int offset = 0;
446                for (unsigned int i=0; i<numMipmaps; ++i)
447                {
448                    unsigned int size = osg::Image::computeImageSizeInBytes(s,t,r,img->getPixelFormat(),img->getDataType(),img->getPacking());
449                    offset += size;
450
451                    *this << offset;
452
453                    s >>= 1;
454                    t >>= 1;
455                    r >>= 1;
456                    if (s<1) s=1;
457                    if (t<1) t=1;
458                    if (r<1) r=1;
459                }
460            }
461            break;
462        case IMAGE_INLINE_FILE:
463            if ( isBinary() )
464            {
465                std::string fullPath = osgDB::findDataFile( img->getFileName() );
466                std::ifstream infile( fullPath.c_str(), std::ios::in|std::ios::binary );
467                if ( infile )
468                {
469                    infile.seekg( 0, std::ios::end );
470                    unsigned int size = infile.tellg();
471                    writeSize(size);
472
473                    if ( size>0 )
474                    {
475                        char* data = new char[size];
476                        if ( !data )
477                        {
478                            throwException( "OutputStream::writeImage(): Out of memory." );
479                            if ( getException() ) return;
480                        }
481
482                        infile.seekg( 0, std::ios::beg );
483                        infile.read( data, size );
484                        writeCharArray( data, size );
485                        delete[] data;
486                    }
487                    infile.close();
488                }
489                else
490                {
491                    OSG_WARN << "OutputStream::writeImage(): Failed to open image file "
492                                        << img->getFileName() << std::endl;
493                    *this << (unsigned int)0;
494                }
495            }
496            break;
497        case IMAGE_EXTERNAL:
498            break;
499        default:
500            break;
501        }
502
503        writeObjectFields( img );
504    }
505
506    // *this << END_BRACKET << std::endl;
507}
508
509void OutputStream::writeObject( const osg::Object* obj )
510{
511    if ( !obj ) return;
512
513    std::string name = obj->libraryName();
514    name += std::string("::") + obj->className();
515
516    bool newID = false;
517    unsigned int id = findOrCreateObjectID( obj, newID );
518
519    *this << name << BEGIN_BRACKET << std::endl;       // Write object name
520    *this << PROPERTY("UniqueID") << id << std::endl;  // Write object ID
521    if ( getException() ) return;
522
523    if (newID)
524    {
525        writeObjectFields(obj);
526    }
527
528    *this << END_BRACKET << std::endl;
529}
530
531void OutputStream::writeObjectFields( const osg::Object* obj )
532{
533    std::string name = obj->libraryName();
534    name += std::string("::") + obj->className();
535
536    ObjectWrapper* wrapper = Registry::instance()->getObjectWrapperManager()->findWrapper( name );
537    if ( !wrapper )
538    {
539        OSG_WARN << "OutputStream::writeObject(): Unsupported wrapper class "
540                                << name << std::endl;
541        return;
542    }
543
544    const StringList& associates = wrapper->getAssociates();
545    for ( StringList::const_iterator itr=associates.begin(); itr!=associates.end(); ++itr )
546    {
547        const std::string& assocName = *itr;
548        ObjectWrapper* assocWrapper = Registry::instance()->getObjectWrapperManager()->findWrapper(assocName);
549        if ( !assocWrapper )
550        {
551            OSG_WARN << "OutputStream::writeObject(): Unsupported associated class "
552                                    << assocName << std::endl;
553            continue;
554        }
555        else if ( _useSchemaData )
556        {
557            if ( _inbuiltSchemaMap.find(assocName)==_inbuiltSchemaMap.end() )
558            {
559                StringList properties;
560                std::vector<int> types;
561                assocWrapper->writeSchema( properties, types );
562
563                unsigned int size = osg::minimum( properties.size(), types.size() );
564                if ( size>0 )
565                {
566                    std::stringstream propertiesStream;
567                    for ( unsigned int i=0; i<size; ++i )
568                    {
569                        propertiesStream << properties[i] << ":" << types[i] << " ";
570                    }
571                    _inbuiltSchemaMap[assocName] = propertiesStream.str();
572                }
573            }
574        }
575        _fields.push_back( assocWrapper->getName() );
576
577        assocWrapper->write( *this, *obj );
578        if ( getException() ) return;
579
580        _fields.pop_back();
581    }
582}
583
584void OutputStream::start( OutputIterator* outIterator, OutputStream::WriteType type )
585{
586    _fields.clear();
587    _fields.push_back( "Start" );
588
589    _out = outIterator;
590    if ( !_out )
591        throwException( "OutputStream: Null stream specified." );
592    if ( getException() ) return;
593
594    if ( isBinary() )
595    {
596        *this << (unsigned int)type << (unsigned int)OPENSCENEGRAPH_SOVERSION;
597
598        bool useCompressSource = false;
599        unsigned int attributes = 0;
600
601        // From SOVERSION 98, start to support custom wrapper domains, enabling the attribute bit
602        if ( _domainVersionMap.size()>0 ) attributes |= 0x1;
603
604        if ( _useSchemaData )
605        {
606            attributes |= 0x2;  // Record if we use inbuilt schema data or not
607            useCompressSource = true;
608        }
609
610        // From SOVERSION 98, start to support binary begin/end brackets so we can easily ignore
611        // errors and unsupport classes, enabling the attribute bit
612        if ( _useRobustBinaryFormat )
613        {
614            outIterator->setSupportBinaryBrackets( true );
615            attributes |= 0x4;
616        }
617        *this << attributes;
618
619        // Record all custom versions
620        if ( _domainVersionMap.size()>0 )
621        {
622            unsigned int numDomains = _domainVersionMap.size();
623            *this << numDomains;
624            for ( VersionMap::iterator itr=_domainVersionMap.begin();
625                  itr!=_domainVersionMap.end(); ++itr )
626            {
627                *this << itr->first << itr->second;
628            }
629        }
630
631        if ( !_compressorName.empty() )
632        {
633            BaseCompressor* compressor = Registry::instance()->getObjectWrapperManager()->findCompressor(_compressorName);
634            if ( !compressor )
635            {
636                OSG_WARN << "OutputStream::start(): No such compressor "
637                                       << _compressorName << std::endl;
638                _compressorName.clear();
639            }
640            else
641            {
642                useCompressSource = true;
643            }
644        }
645        if ( !_compressorName.empty() ) *this << _compressorName;
646        else *this << std::string("0");  // No compressor
647
648        // Compressors and inbuilt schema use a new stream, which will be merged with the original one at the end.
649        if ( useCompressSource )
650        {
651            _out->flush();
652            _out->setStream( &_compressSource );
653        }
654    }
655    else
656    {
657        std::string typeString("Unknown");
658        switch ( type )
659        {
660        case WRITE_SCENE: typeString = "Scene"; break;
661        case WRITE_IMAGE: typeString = "Image"; break;
662        case WRITE_OBJECT: typeString = "Object"; break;
663        default: break;
664        }
665
666        *this << typeString << std::endl;
667        *this << PROPERTY("#Version") << (unsigned int)OPENSCENEGRAPH_SOVERSION << std::endl;
668        *this << PROPERTY("#Generator") << std::string("OpenSceneGraph")
669              << std::string(osgGetVersion()) << std::endl;
670        if ( _domainVersionMap.size()>0 )
671        {
672            for ( VersionMap::iterator itr=_domainVersionMap.begin();
673                  itr!=_domainVersionMap.end(); ++itr )
674            {
675                *this << PROPERTY("#CustomDomain") << itr->first << itr->second << std::endl;
676            }
677        }
678        *this << std::endl;
679    }
680    _fields.pop_back();
681}
682
683void OutputStream::compress( std::ostream* ostream )
684{
685    _fields.clear();
686    if ( !isBinary() ) return;
687
688    std::stringstream schemaSource;
689    if ( _useSchemaData )
690    {
691        _fields.push_back( "SchemaData" );
692
693        std::string schemaData;
694        for ( SchemaMap::iterator itr=_inbuiltSchemaMap.begin();
695              itr!=_inbuiltSchemaMap.end(); ++itr )
696        {
697            schemaData += itr->first + '=';
698            schemaData += itr->second;
699            schemaData += '\n';
700        }
701
702        int size = schemaData.size();
703        schemaSource.write( (char*)&size, INT_SIZE );
704        schemaSource.write( schemaData.c_str(), size );
705
706        _inbuiltSchemaMap.clear();
707        _fields.pop_back();
708    }
709
710    if ( !_compressorName.empty() )
711    {
712        _fields.push_back( "Compression" );
713        BaseCompressor* compressor = Registry::instance()->getObjectWrapperManager()->findCompressor(_compressorName);
714        if ( !compressor || !ostream )
715        {
716            _fields.pop_back();
717            return;
718        }
719
720        if ( !compressor->compress(*ostream, schemaSource.str() + _compressSource.str()) )
721            throwException( "OutputStream: Failed to compress stream." );
722        if ( getException() ) return;
723        _fields.pop_back();
724    }
725    else if ( _useSchemaData )
726    {
727        std::string str = schemaSource.str() + _compressSource.str();
728        ostream->write( str.c_str(), str.size() );
729    }
730}
731
732void OutputStream::writeSchema( std::ostream& fout )
733{
734    // Write to external ascii stream
735    const ObjectWrapperManager::WrapperMap& wrappers = Registry::instance()->getObjectWrapperManager()->getWrapperMap();
736    for ( ObjectWrapperManager::WrapperMap::const_iterator itr=wrappers.begin();
737          itr!=wrappers.end(); ++itr )
738    {
739        ObjectWrapper* wrapper = itr->second.get();
740        fout << itr->first << " =";
741
742        StringList properties;
743        std::vector<int> types;
744        wrapper->writeSchema( properties, types );
745
746        std::string propertiesString;
747        unsigned int size = osg::minimum( properties.size(), types.size() );
748        for ( unsigned int i=0; i<size; ++i )
749        {
750            fout << " " << properties[i] << ":" << types[i];
751        }
752        fout << std::endl;
753    }
754}
755
756// PROTECTED METHODS
757
758template<typename T>
759void OutputStream::writeArrayImplementation( const T* a, int write_size, unsigned int numInRow )
760{
761    *this << write_size << BEGIN_BRACKET;
762    if ( numInRow>1 )
763    {
764        for ( int i=0; i<write_size; ++i )
765        {
766            if ( !(i%numInRow) )
767            {
768                *this << std::endl << (*a)[i];
769            }
770            else
771                *this << (*a)[i];
772        }
773        *this << std::endl;
774    }
775    else
776    {
777        *this << std::endl;
778        for ( int i=0; i<write_size; ++i )
779            *this << (*a)[i] << std::endl;
780    }
781    *this << END_BRACKET << std::endl;
782}
783
784unsigned int OutputStream::findOrCreateArrayID( const osg::Array* array, bool& newID )
785{
786    ArrayMap::iterator itr = _arrayMap.find( array );
787    if ( itr==_arrayMap.end() )
788    {
789        unsigned int id = _arrayMap.size()+1;
790        _arrayMap[array] = id;
791        newID = true;
792        return id;
793    }
794    newID = false;
795    return itr->second;
796}
797
798unsigned int OutputStream::findOrCreateObjectID( const osg::Object* obj, bool& newID )
799{
800    ObjectMap::iterator itr = _objectMap.find( obj );
801    if ( itr==_objectMap.end() )
802    {
803        unsigned int id = _objectMap.size()+1;
804        _objectMap[obj] = id;
805        newID = true;
806        return id;
807    }
808    newID = false;
809    return itr->second;
810}
Note: See TracBrowser for help on using the browser.