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

Revision 13788, 30.4 kB (checked in by robert, 4 days ago)

Added shaders to support experimental shader based displacement mapping technique osgTerrain::ShaderTerrain?.

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