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

Revision 11018, 21.5 kB (checked in by robert, 5 years ago)

From Wang Rui, "Changes:

1. Rewrite the reading/writing exception handlers to work like the ive
plugin exceptions.
2. Write a header writing/checking function in ReaderWriterOSG2.cpp,
which may help decide if the stream is ascii or binary. The
readInputIterator() function will return null pointer if the input
file is nither osgb nor osgt format, which indicates that the old .osg
format could be used here, in case we've merged the two plugins
together.
3. Add a new ForceReadingImage? option in the InputStream?, which will
allocate an empty image object with the filename if specifed external
image file is missed. It may be useful for format converting in some
cases.
4. Add new osgParticle wrappers, as well as some modification to the
osgParticle headers, for instance, change isEnabled() to getEnabled().
5. Some fixes to the osg serialization wrappers."

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