root/OpenSceneGraph/trunk/src/osgDB/Registry.cpp @ 9881

Revision 9881, 68.8 kB (checked in by robert, 5 years ago)

From David Callu, "Problem:

osgText::Text and osgText::Text3D use the same font file.
The first really load the file and obtain an osgText::Font object,
the second use the cache created during the first load of the
font file, and so obtain an osgText::Font object instead of
osgText::Font3D object. To obtain an osgText::Font3D object,
osgText::Text3D call osgDB::readObjectFile(...) with an option
to specify the plugin we want an osgText::Font3D instead of
osgText::Font.

Generalised Problem:

In osgDB::Registry, loaded file cache is referenced by the name
of this file, so if I load a file with some options, and the cache
already contain object for this filename, I obtain an object
potentially not loaded with my options.

Behaviours:

Cache management is delegate to osgDB::Registry, but cache
coherence (load a file with option then reuse it, deactivate the
cache when load a specific file or don't cached the loaded file)
is user's responsibility.

Text3D solution:

Postfix the font file name by .text3d or something similar and then have the freetype plugin return
osgText::Font3D when it detects this.
This operation is done by osgText::readFont3DFile() which unsure the filename have .text3d as extension.
This is totaly transparent for user, and backward compatible.

BTW, I fix the bug about the Normal of 3D text. Currently, the front and wall face have
the same normal (0,0,1) in the Text3D object coordinate. Now the wall face have its own
normal array computed by the plugin.

BTW 2, I implement
- void Text3D::accept(osg::Drawable::ConstAttributeFunctor?& af) const
- void Text3D::accept(osg::PrimitiveFunctor?& pf) const
so now statistics are well reported.
"

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 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
14#include <stdio.h>
15#include <string.h>
16
17#include <osg/Notify>
18#include <osg/Object>
19#include <osg/Image>
20#include <osg/Shader>
21#include <osg/Node>
22#include <osg/Group>
23#include <osg/Geode>
24#include <osg/ApplicationUsage>
25#include <osg/Version>
26#include <osg/Timer>
27
28#include <osgDB/Registry>
29#include <osgDB/FileUtils>
30#include <osgDB/FileNameUtils>
31#include <osgDB/fstream>
32#include <osgDB/Archive>
33
34#include <algorithm>
35#include <set>
36
37#include <stdlib.h>
38
39#if defined(__sgi)
40    #include <ctype.h>
41#elif defined(__GNUC__) || !defined(WIN32) || defined(__MWERKS__)
42    #include <cctype>
43    using std::tolower;
44#endif
45
46#ifdef OSG_DEBUG_POSTFIX
47    #define OSG_DEBUG_POSTFIX_WITH_QUOTES ADDQUOTES(OSG_DEBUG_POSTFIX)
48#else
49    #define OSG_DEBUG_POSTFIX_WITH_QUOTES "d"
50#endif
51
52using namespace osg;
53using namespace osgDB;
54
55#if !defined(WIN32) || defined(__CYGWIN__)
56static osg::ApplicationUsageProxy Registry_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_FILE_PATH <path>[:path]..","Paths for locating datafiles");
57static osg::ApplicationUsageProxy Registry_e1(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_LIBRARY_PATH <path>[:path]..","Paths for locating libraries/ plugins");
58#else
59static osg::ApplicationUsageProxy Registry_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_FILE_PATH <path>[;path]..","Paths for locating datafiles");
60static osg::ApplicationUsageProxy Registry_e1(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_LIBRARY_PATH <path>[;path]..","Paths for locating libraries/ plugins");
61#endif
62
63static osg::ApplicationUsageProxy Registry_e2(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_BUILD_KDTREES on/off","Enable/disable the automatic building of KdTrees for each loaded Geometry.");
64
65
66class Registry::AvailableReaderWriterIterator
67{
68public:
69    AvailableReaderWriterIterator(Registry::ReaderWriterList& rwList, OpenThreads::ReentrantMutex& pluginMutex):
70        _rwList(rwList),
71        _pluginMutex(pluginMutex) {}
72
73
74    ReaderWriter& operator * () { return *get(); }
75    ReaderWriter* operator -> () { return get(); }
76   
77    bool valid() { return get()!=0; }
78   
79    void operator ++()
80    {
81        _rwUsed.insert(get());
82    }
83   
84
85protected:
86
87    AvailableReaderWriterIterator& operator = (const AvailableReaderWriterIterator&) { return *this; }
88
89    Registry::ReaderWriterList&     _rwList;
90    OpenThreads::ReentrantMutex&    _pluginMutex;
91   
92    std::set<ReaderWriter*>         _rwUsed;
93
94    ReaderWriter* get()
95    {
96        OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
97        Registry::ReaderWriterList::iterator itr=_rwList.begin();
98        for(;itr!=_rwList.end();++itr)
99        {
100            if (_rwUsed.find(itr->get())==_rwUsed.end())
101            {
102                return itr->get();
103            }
104        }
105        return 0;
106    }
107
108};
109
110#if 0
111    // temporary test of autoregistering, not compiled by default.
112    enum Methods
113    {
114        SET_1,
115        SET_2,
116        END
117    };
118
119
120    typedef std::pair<Methods,std::string> MethodPair;
121
122    class Proxy
123    {
124    public:
125        Proxy(MethodPair* methods)
126        {
127            std::cout<<"methods "<<methods<<std::endl;
128            for(int i=0;methods[i].first!=END;++i)
129            {
130                std::cout<<"\t"<<methods[i].first<<"\t"<<methods[i].second<<std::endl;
131            }
132        }
133    };
134
135
136    static MethodPair methods[] =
137    {
138        MethodPair(SET_1,"SET_1"),
139        MethodPair(SET_2,"SET_2"),
140        MethodPair(END,"")
141    };
142
143    Proxy myproxy(methods);
144
145#endif
146
147void PrintFilePathList(std::ostream& stream,const FilePathList& filepath)
148{
149    for(FilePathList::const_iterator itr=filepath.begin();
150        itr!=filepath.end();
151        ++itr)
152    {
153        stream << "    "<< *itr<<std::endl;
154    }
155}
156
157Registry* Registry::instance(bool erase)
158{
159    static ref_ptr<Registry> s_registry = new Registry;
160    if (erase)
161    {   
162        s_registry->destruct();
163        s_registry = 0;
164    }
165    return s_registry.get(); // will return NULL on erase
166}
167
168
169// definition of the Registry
170Registry::Registry()
171{
172    // comment out because it was causing problems under OSX - causing it to crash osgconv when constructing ostream in osg::notify().
173    // notify(INFO) << "Constructing osg::Registry"<<std::endl;
174
175    _buildKdTreesHint = ReaderWriter::Options::NO_PREFERENCE;
176    _kdTreeBuilder = new osg::KdTreeBuilder;
177   
178    const char* kdtree_str = getenv("OSG_BUILD_KDTREES");
179    if (kdtree_str)
180    {
181        bool switchOff = (strcmp(kdtree_str, "off")==0 || strcmp(kdtree_str, "OFF")==0 || strcmp(kdtree_str, "Off")==0 );
182        if (switchOff) _buildKdTreesHint = ReaderWriter::Options::DO_NOT_BUILD_KDTREES;
183        else _buildKdTreesHint = ReaderWriter::Options::BUILD_KDTREES;
184    }
185
186    const char* fileCachePath = getenv("OSG_FILE_CACHE");
187    if (fileCachePath)
188    {
189        _fileCache = new FileCache(fileCachePath);   
190    }
191
192    _createNodeFromImage = false;
193    _openingLibrary = false;
194
195    // add default osga archive extension
196    _archiveExtList.push_back("osga");
197   
198    initFilePathLists();
199
200
201
202    // register file extension alias.
203    const char* flt_str = getenv("OSG_OPEN_FLIGHT_PLUGIN");
204    if (flt_str)
205    {
206        if (strcmp(flt_str, "new")==0)
207        {
208            addFileExtensionAlias("flt", "OpenFlight");
209        }
210    }
211    else
212    {
213    #ifndef COMPILE_WITH_OLD_OPENFLIGHT_PLUGIN_AS_DEFAULT
214        addFileExtensionAlias("flt", "OpenFlight");
215    #endif
216    }
217
218    addFileExtensionAlias("osgs", "osg");
219    addFileExtensionAlias("shadow""osgShadow");
220    addFileExtensionAlias("terrain", "osgTerrain");
221    addFileExtensionAlias("view""osgViewer");
222
223    addFileExtensionAlias("sgi""rgb");
224    addFileExtensionAlias("rgba", "rgb");
225    addFileExtensionAlias("int""rgb");
226    addFileExtensionAlias("inta", "rgb");
227    addFileExtensionAlias("bw",   "rgb");
228
229    addFileExtensionAlias("ivz",   "gz");
230    addFileExtensionAlias("ozg",   "gz");
231   
232    addFileExtensionAlias("mag",   "dicom");
233    addFileExtensionAlias("ph",   "dicom");
234    addFileExtensionAlias("ima",   "dicom");
235    addFileExtensionAlias("dcm",   "dicom");
236    addFileExtensionAlias("dic",   "dicom");
237
238    addFileExtensionAlias("gl",   "glsl");
239    addFileExtensionAlias("vert",   "glsl");
240    addFileExtensionAlias("frag",   "glsl");
241
242
243#if defined(DARWIN_IMAGEIO)
244    addFileExtensionAlias("jpg""imageio");
245    addFileExtensionAlias("jpe""imageio");
246    addFileExtensionAlias("jpeg", "imageio");
247    addFileExtensionAlias("tif""imageio");
248    addFileExtensionAlias("tiff", "imageio");
249    addFileExtensionAlias("gif""imageio");
250    addFileExtensionAlias("png""imageio");
251    addFileExtensionAlias("psd""imageio");
252    addFileExtensionAlias("tga""imageio");
253#endif
254
255#if defined(DARWIN_QUICKTIME)
256    addFileExtensionAlias("jpg""qt");
257    addFileExtensionAlias("jpe""qt");
258    addFileExtensionAlias("jpeg", "qt");
259    addFileExtensionAlias("tif""qt");
260    addFileExtensionAlias("tiff", "qt");
261    addFileExtensionAlias("gif""qt");
262    addFileExtensionAlias("png""qt");
263    addFileExtensionAlias("psd""qt");
264    addFileExtensionAlias("tga""qt");
265    addFileExtensionAlias("mov""qt");
266    addFileExtensionAlias("avi""qt");
267    addFileExtensionAlias("mpg""qt");
268    addFileExtensionAlias("flv""qt");
269    addFileExtensionAlias("mpv""qt");
270    addFileExtensionAlias("dv",   "qt");
271    addFileExtensionAlias("mp4""qt");
272    addFileExtensionAlias("m4v""qt");
273    addFileExtensionAlias("3gp""qt");
274    // Add QuickTime live support for OSX
275    addFileExtensionAlias("live", "qt");
276#else
277    addFileExtensionAlias("jpg""jpeg");
278    addFileExtensionAlias("jpe""jpeg");
279    addFileExtensionAlias("tif""tiff");
280
281    // really need to decide this at runtime...
282    #if defined(USE_XINE)
283        addFileExtensionAlias("mov""xine");
284        addFileExtensionAlias("mpg""xine");
285        addFileExtensionAlias("ogv""xine");
286        addFileExtensionAlias("mpv""xine");
287        addFileExtensionAlias("dv",   "xine");
288        addFileExtensionAlias("avi""xine");
289        addFileExtensionAlias("wmv""xine");
290        addFileExtensionAlias("flv""xine");
291    #endif
292
293    // support QuickTime for Windows
294    #if defined(USE_QUICKTIME)
295        addFileExtensionAlias("mov", "qt");
296        addFileExtensionAlias("live", "qt");
297        addFileExtensionAlias("mpg", "qt");
298        addFileExtensionAlias("avi", "qt");
299    #endif
300#endif
301
302    // remove geo to lwo alias as the new Carbon Graphics GEO format
303    // also uses the .geo. It is still possible to load light wave .geo
304    // files via loading the lwo plugin explicitly and then doing a readNodeFile.
305    //addFileExtensionAlias("geo",  "lwo");
306    addFileExtensionAlias("lw",   "lwo");
307
308    #if defined(USE_VRML)
309        addFileExtensionAlias("wrl",   "vrml");   
310    #elif defined(USE_INVENTOR)
311        addFileExtensionAlias("wrl",   "iv");
312    #endif
313   
314    // add alias for the text/freetype plugin.
315    addFileExtensionAlias("ttf",   "freetype");  // true type
316    addFileExtensionAlias("ttc",   "freetype");  // true type
317    addFileExtensionAlias("cid",   "freetype");  // Postscript CID-Fonts
318    addFileExtensionAlias("cff",   "freetype");  // OpenType
319    addFileExtensionAlias("cef",   "freetype");  // OpenType
320    addFileExtensionAlias("fon",   "freetype");  // Windows bitmap fonts
321    addFileExtensionAlias("fnt",   "freetype");  // Windows bitmap fonts
322    addFileExtensionAlias("text3d", "freetype"); // use 3D Font instead of 2D Font
323
324    // wont't add type1 and type2 until resolve extension collision with Performer binary and ascii files.
325    // addFileExtensionAlias("pfb",   "freetype");  // type1 binary
326    // addFileExtensionAlias("pfa",   "freetype");  // type2 ascii
327
328
329    // portable bitmap, greyscale and colour/pixmap image formats
330    addFileExtensionAlias("pbm", "pnm");
331    addFileExtensionAlias("pgm", "pnm");
332    addFileExtensionAlias("ppm", "pnm");
333   
334}
335
336
337Registry::~Registry()
338{
339    destruct();
340}
341
342void Registry::destruct()
343{
344    // osg::notify(osg::NOTICE)<<"Registry::destruct()"<<std::endl;
345
346    // clean up the SharedStateManager
347    _sharedStateManager = 0;
348   
349
350    // clean up the FileCache
351    _fileCache = 0;
352   
353
354    // object cache clear needed here to prevent crash in unref() of
355    // the objects it contains when running the TXP plugin.
356    // Not sure why, but perhaps there is is something in a TXP plugin
357    // which deletes the data before its ref count hits zero, perhaps
358    // even some issue with objects be allocated by a plugin that is
359    // maintained after that plugin is deleted...  Robert Osfield, Jan 2004.
360    clearObjectCache();
361    clearArchiveCache();
362   
363
364    // unload all the plugin before we finally destruct.
365    closeAllLibraries();
366}
367
368#include <iostream>
369
370void Registry::initDataFilePathList()
371{
372    FilePathList filepath;
373    //
374    // set up data file paths
375    //
376    char *ptr;
377 
378    if( (ptr = getenv( "OSG_FILE_PATH" )) )
379    {
380        //notify(DEBUG_INFO) << "OSG_FILE_PATH("<<ptr<<")"<<std::endl;
381        convertStringPathIntoFilePathList(ptr, filepath);
382    }
383    else if( (ptr = getenv( "OSGFILEPATH" )) )
384    {
385        //notify(DEBUG_INFO) << "OSGFILEPATH("<<ptr<<")"<<std::endl;
386        convertStringPathIntoFilePathList(ptr, filepath);
387    }
388
389    osgDB::appendPlatformSpecificResourceFilePaths(filepath);
390    setDataFilePathList(filepath);
391   
392}
393
394void Registry::setDataFilePathList(const std::string& paths)
395{
396    _dataFilePath.clear();
397    convertStringPathIntoFilePathList(paths,_dataFilePath);
398}
399
400void Registry::setLibraryFilePathList(const std::string& paths) { _libraryFilePath.clear(); convertStringPathIntoFilePathList(paths,_libraryFilePath); }
401
402
403
404void Registry::initLibraryFilePathList()
405{
406    //
407    // set up library paths
408    //
409    char* ptr;
410    if( (ptr = getenv( "OSG_LIBRARY_PATH")) )
411    {
412        //notify(DEBUG_INFO) << "OSG_LIBRARY_PATH("<<ptr<<")"<<std::endl;
413        setLibraryFilePathList(ptr);
414    }
415    else if( (ptr = getenv( "OSG_LD_LIBRARY_PATH")) )
416    {
417        //notify(DEBUG_INFO) << "OSG_LD_LIBRARY_PATH("<<ptr<<")"<<std::endl;
418        setLibraryFilePathList(ptr);
419    }
420   
421    appendPlatformSpecificLibraryFilePaths(_libraryFilePath);
422
423}
424
425
426void Registry::readCommandLine(osg::ArgumentParser& arguments)
427{
428    // report the usage options.
429    if (arguments.getApplicationUsage())
430    {
431        arguments.getApplicationUsage()->addCommandLineOption("-l <library>","Load the plugin");
432        arguments.getApplicationUsage()->addCommandLineOption("-e <extension>","Load the plugin associated with handling files with specified extension");
433        arguments.getApplicationUsage()->addCommandLineOption("-O <option_string>","Provide an option string to reader/writers used to load databases");
434    }
435
436    std::string value;
437    while(arguments.read("-l",value))
438    {
439        loadLibrary(value);
440    }
441       
442    while(arguments.read("-e",value))
443    {
444        std::string libName = createLibraryNameForExtension(value);
445        loadLibrary(libName);
446    }
447
448    while(arguments.read("-O",value))
449    {
450        setOptions(new ReaderWriter::Options(value));
451    }
452}
453
454void Registry::addDotOsgWrapper(DotOsgWrapper* wrapper)
455{
456    if (wrapper==0L) return;
457
458    //notify(INFO) << "osg::Registry::addDotOsgWrapper("<<wrapper->getName()<<")"<< std::endl;
459    const DotOsgWrapper::Associates& assoc = wrapper->getAssociates();
460   
461    for(DotOsgWrapper::Associates::const_iterator itr=assoc.begin();
462                                                  itr!=assoc.end();
463                                                  ++itr)
464    {
465        //notify(INFO) << "    ("<<*itr<<")"<< std::endl;
466    }
467
468    const std::string& name = wrapper->getName();
469    const osg::Object* proto = wrapper->getPrototype();
470
471    _objectWrapperMap[name] = wrapper;
472    if (wrapper->getReadWriteMode()==DotOsgWrapper::READ_AND_WRITE) _classNameWrapperMap[name] = wrapper;
473   
474    if (proto)
475    {
476        std::string libraryName = proto->libraryName();
477        std::string compositeName = libraryName + "::" + name;
478
479        _objectWrapperMap[compositeName] = wrapper;
480        if (wrapper->getReadWriteMode()==DotOsgWrapper::READ_AND_WRITE) _classNameWrapperMap[compositeName] = wrapper;
481
482        if (dynamic_cast<const Image*>(proto))
483        {
484            _imageWrapperMap[name] = wrapper;
485            _imageWrapperMap[compositeName] = wrapper;
486        }
487        if (dynamic_cast<const Drawable*>(proto))
488        {
489              _drawableWrapperMap[name] = wrapper;
490              _drawableWrapperMap[compositeName] = wrapper;
491        }
492        if (dynamic_cast<const StateAttribute*>(proto))
493        {
494            _stateAttrWrapperMap[name] = wrapper;
495            _stateAttrWrapperMap[compositeName] = wrapper;
496        }
497        if (dynamic_cast<const Uniform*>(proto))
498        {
499            _uniformWrapperMap[name] = wrapper;
500            _uniformWrapperMap[compositeName] = wrapper;
501        }
502        if (dynamic_cast<const Node*>(proto))
503        {
504            _nodeWrapperMap[name] = wrapper;
505            _nodeWrapperMap[compositeName] = wrapper;
506        }
507        if (dynamic_cast<const Shader*>(proto))
508        {
509            _shaderWrapperMap[name] = wrapper;
510            _shaderWrapperMap[compositeName] = wrapper;
511        }
512
513
514    }
515}
516
517// need to change to delete all instances of wrapper, since we
518// now can have a wrapper entered twice with the addition of the
519// library::class composite name.
520void Registry::eraseWrapper(DotOsgWrapperMap& wrappermap,DotOsgWrapper* wrapper)
521{
522    typedef std::vector<DotOsgWrapperMap::iterator> EraseList;
523    EraseList eraseList;
524    for(DotOsgWrapperMap::iterator witr=wrappermap.begin();
525        witr!=wrappermap.end();
526        ++witr)
527    {
528        if (witr->second==wrapper) eraseList.push_back(witr);
529    }
530    for(EraseList::iterator eitr=eraseList.begin();
531        eitr!=eraseList.end();
532        ++eitr)
533    {
534        wrappermap.erase(*eitr);
535    }
536}
537
538void Registry::removeDotOsgWrapper(DotOsgWrapper* wrapper)
539{
540    if (wrapper==0L) return;
541
542    eraseWrapper(_objectWrapperMap,wrapper);
543    eraseWrapper(_classNameWrapperMap,wrapper);
544    eraseWrapper(_imageWrapperMap,wrapper);
545    eraseWrapper(_drawableWrapperMap,wrapper);
546    eraseWrapper(_uniformWrapperMap,wrapper);
547    eraseWrapper(_stateAttrWrapperMap,wrapper);
548    eraseWrapper(_nodeWrapperMap,wrapper);
549    eraseWrapper(_shaderWrapperMap,wrapper);
550}
551
552void Registry::addReaderWriter(ReaderWriter* rw)
553{
554    if (rw==0L) return;
555
556    // notify(INFO) << "osg::Registry::addReaderWriter("<<rw->className()<<")"<< std::endl;
557
558    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
559
560    _rwList.push_back(rw);
561
562}
563
564
565void Registry::removeReaderWriter(ReaderWriter* rw)
566{
567    if (rw==0L) return;
568
569//    notify(INFO) << "osg::Registry::removeReaderWriter();"<< std::endl;
570
571    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
572
573    ReaderWriterList::iterator rwitr = std::find(_rwList.begin(),_rwList.end(),rw);
574    if (rwitr!=_rwList.end())
575    {
576        _rwList.erase(rwitr);
577    }
578
579}
580
581
582void Registry::addFileExtensionAlias(const std::string mapExt, const std::string toExt)
583{
584    _extAliasMap[mapExt] = toExt;
585}
586
587bool Registry::readPluginAliasConfigurationFile( const std::string& file )
588{
589    std::string fileName = osgDB::findDataFile( file );
590    if (fileName.empty())
591    {
592        osg::notify( osg::WARN) << "Can't find plugin alias config file \"" << file << "\"." << std::endl;
593        return false;
594    }
595
596    osgDB::ifstream ifs;
597    ifs.open( fileName.c_str() );
598    if (!ifs.good())
599    {
600        osg::notify( osg::WARN) << "Can't open plugin alias config file \"" << fileName << "\"." << std::endl;
601        return false;
602    }
603
604    int lineNum( 0 );
605    while (ifs.good())
606    {
607        std::string raw;
608        ++lineNum;
609        std::getline( ifs, raw );
610        std::string ln = trim( raw );
611        if (ln.empty()) continue;
612        if (ln[0] == '#') continue;
613
614        std::string::size_type spIdx = ln.find_first_of( " \t" );
615        if (spIdx == ln.npos)
616        {
617            // mapExt and toExt must be on the same line, separated by a space.
618            osg::notify( osg::WARN) << file << ", line " << lineNum << ": Syntax error: missing space in \"" << raw << "\"." << std::endl;
619            continue;
620        }
621
622        const std::string mapExt = trim( ln.substr( 0, spIdx ) );
623        const std::string toExt = trim( ln.substr( spIdx+1 ) );
624        addFileExtensionAlias( mapExt, toExt );
625    }
626    return true;
627}
628
629std::string Registry::trim( const std::string& str )
630{
631    if (!str.size()) return str;
632    std::string::size_type first = str.find_first_not_of( " \t" );
633    std::string::size_type last = str.find_last_not_of( "  \t\r\n" );
634    if ((first==str.npos) || (last==str.npos)) return std::string( "" );
635    return str.substr( first, last-first+1 );
636}
637
638
639std::string Registry::createLibraryNameForFile(const std::string& fileName)
640{
641    return createLibraryNameForExtension(getFileExtension(fileName));
642}
643
644std::string Registry::createLibraryNameForExtension(const std::string& ext)
645{
646    std::string lowercase_ext;
647    for(std::string::const_iterator sitr=ext.begin();
648        sitr!=ext.end();
649        ++sitr)
650    {
651        lowercase_ext.push_back(tolower(*sitr));
652    }
653
654    ExtensionAliasMap::iterator itr=_extAliasMap.find(lowercase_ext);
655    if (itr!=_extAliasMap.end() && ext != itr->second) return createLibraryNameForExtension(itr->second);
656
657#ifdef OSG_JAVA_BUILD
658    static std::string prepend = std::string("osgPlugins-")+std::string(osgGetVersion())+std::string("/java");
659#elseif defined(__APPLE__)
660    // OSX is rather a mess in FileUtils.cpp w.r.t its appendPlatformSpecificLibraryFilePaths implementation
661    // as it hardwires the plugin name to PlugIns.  This *needs* fixing to use the naming convention as all
662    // other platforms.
663    static std::string prepend = "";
664#else
665    static std::string prepend = std::string("osgPlugins-")+std::string(osgGetVersion())+std::string("/");
666#endif
667
668#if defined(__CYGWIN__)
669    #ifdef _DEBUG
670        return prepend+"cygwin_"+"osgdb_"+lowercase_ext+OSG_DEBUG_POSTFIX_WITH_QUOTES+".dll";
671    #else
672        return prepend+"cygwin_"+"osgdb_"+lowercase_ext+".dll";
673    #endif
674#elif defined(__MINGW32__)
675    return prepend+"mingw_"+"osgdb_"+lowercase_ext+".dll";
676#elif defined(WIN32)
677    #ifdef _DEBUG
678        return prepend+"osgdb_"+lowercase_ext+ OSG_DEBUG_POSTFIX_WITH_QUOTES +".dll";
679    #else
680        return prepend+"osgdb_"+lowercase_ext+".dll";
681    #endif
682#elif macintosh
683    return prepend+"osgdb_"+lowercase_ext;
684#elif defined(__hpux__)
685    // why don't we use PLUGIN_EXT from the makefiles here?
686    return prepend+"osgdb_"+lowercase_ext+".sl";
687#else
688    #ifdef _DEBUG
689         return prepend+"osgdb_"+lowercase_ext+ OSG_DEBUG_POSTFIX_WITH_QUOTES + ".so";
690    #else
691         return prepend+"osgdb_"+lowercase_ext+".so";
692    #endif
693#endif
694
695}
696
697std::string Registry::createLibraryNameForNodeKit(const std::string& name)
698{
699#if defined(__CYGWIN__)
700    return "cyg"+name+".dll";
701#elif defined(__MINGW32__)
702    return "lib"+name+".dll";
703#elif defined(WIN32)
704    #ifdef _DEBUG
705        return name+OSG_DEBUG_POSTFIX_WITH_QUOTES +".dll";
706    #else
707        return name+".dll";
708    #endif
709#elif macintosh
710    return name;
711#elif defined(__hpux__)
712    // why don't we use PLUGIN_EXT from the makefiles here?
713    return "lib"+name+".sl";
714#else
715    #ifdef _DEBUG
716        return "lib"+name+OSG_DEBUG_POSTFIX_WITH_QUOTES +".so";
717    #else
718        return "lib"+name+".so";
719    #endif
720#endif
721}
722
723Registry::LoadStatus Registry::loadLibrary(const std::string& fileName)
724{
725    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
726
727    DynamicLibraryList::iterator ditr = getLibraryItr(fileName);
728    if (ditr!=_dlList.end()) return PREVIOUSLY_LOADED;
729
730    _openingLibrary=true;
731
732    DynamicLibrary* dl = DynamicLibrary::loadLibrary(fileName);
733    _openingLibrary=false;
734
735    if (dl)
736    {
737        _dlList.push_back(dl);
738        return LOADED;
739    }
740    return NOT_LOADED;
741}
742
743
744bool Registry::closeLibrary(const std::string& fileName)
745{
746    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
747    DynamicLibraryList::iterator ditr = getLibraryItr(fileName);
748    if (ditr!=_dlList.end())
749    {
750        _dlList.erase(ditr);
751        return true;
752    }
753    return false;
754}
755
756void Registry::closeAllLibraries()
757{
758    // osg::notify(osg::NOTICE)<<"Registry::closeAllLibraries()"<<std::endl;
759    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
760    _dlList.clear();
761}
762
763Registry::DynamicLibraryList::iterator Registry::getLibraryItr(const std::string& fileName)
764{
765    DynamicLibraryList::iterator ditr = _dlList.begin();
766    for(;ditr!=_dlList.end();++ditr)
767    {
768        if ((*ditr)->getName()==fileName) return ditr;
769    }
770    return _dlList.end();
771}
772
773DynamicLibrary* Registry::getLibrary(const std::string& fileName)
774{
775    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
776    DynamicLibraryList::iterator ditr = getLibraryItr(fileName);
777    if (ditr!=_dlList.end()) return ditr->get();
778    else return NULL;
779}
780
781ReaderWriter* Registry::getReaderWriterForExtension(const std::string& ext)
782{
783    // record the existing reader writer.
784    std::set<ReaderWriter*> rwOriginal;
785
786    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
787
788    // first attemt one of the installed loaders
789    for(ReaderWriterList::iterator itr=_rwList.begin();
790        itr!=_rwList.end();
791        ++itr)
792    {
793        rwOriginal.insert(itr->get());
794        if((*itr)->acceptsExtension(ext)) return (*itr).get();
795    }
796   
797    // now look for a plug-in to load the file.
798    std::string libraryName = createLibraryNameForExtension(ext);
799    notify(INFO) << "Now checking for plug-in "<<libraryName<< std::endl;
800    if (loadLibrary(libraryName)==LOADED)
801    {
802        for(ReaderWriterList::iterator itr=_rwList.begin();
803            itr!=_rwList.end();
804            ++itr)
805        {
806            if (rwOriginal.find(itr->get())==rwOriginal.end())
807            {
808                if((*itr)->acceptsExtension(ext)) return (*itr).get();
809            }
810        }
811    }
812
813    return NULL;
814
815}
816
817struct concrete_wrapper: basic_type_wrapper
818{
819    virtual ~concrete_wrapper() {}
820    concrete_wrapper(const osg::Object *myobj) : myobj_(myobj) {}
821    bool matches(const osg::Object *proto) const
822    {
823        return myobj_->isSameKindAs(proto);
824    }
825    const osg::Object *myobj_;
826};
827
828osg::Object* Registry::readObjectOfType(const osg::Object& compObj,Input& fr)
829{
830    return readObjectOfType(concrete_wrapper(&compObj), fr);
831}
832
833osg::Object* Registry::readObjectOfType(const basic_type_wrapper &btw,Input& fr)
834{
835    const char *str = fr[0].getStr();
836    if (str==NULL) return NULL;
837
838    if (fr[0].matchWord("Use"))
839    {
840        if (fr[1].isString())
841        {
842            Object* obj = fr.getObjectForUniqueID(fr[1].getStr());
843            if (obj && btw.matches(obj))
844            {
845                fr+=2;
846                return obj;
847            }
848        }
849        else return NULL;
850
851    }
852
853    std::string name = str;
854    DotOsgWrapperMap::iterator itr = _objectWrapperMap.find(name);
855    if (itr==_objectWrapperMap.end())
856    {
857        // not found so check if a library::class composite name.
858        std::string token = fr[0].getStr();
859        std::string::size_type posDoubleColon = token.rfind("::");
860        if (posDoubleColon != std::string::npos)
861        {
862            // we have a composite name so now strip off the library name
863            // are try to load it, and then retry the readObject to see
864            // if we can recognize the objects.
865            std::string libraryName = std::string(token,0,posDoubleColon);
866
867            // first try the standard nodekit library.
868            std::string nodeKitLibraryName = createLibraryNameForNodeKit(libraryName);
869            if (loadLibrary(nodeKitLibraryName)==LOADED) return readObjectOfType(btw,fr);
870           
871            // otherwise try the osgdb_ plugin library.
872            std::string pluginLibraryName = createLibraryNameForExtension(libraryName);
873            if (loadLibrary(pluginLibraryName)==LOADED) return readObjectOfType(btw,fr);
874        }
875    }
876    else if (fr[1].isOpenBracket())
877    {
878        DotOsgWrapper* wrapper = itr->second.get();
879        const osg::Object* proto = wrapper->getPrototype();
880        if (proto==NULL)
881        {
882            osg::notify(osg::WARN)<<"Token "<<fr[0].getStr()<<" read, but has no prototype, cannot load."<< std::endl;
883            return NULL;
884        }
885       
886        if (!btw.matches(proto))
887        {
888            return NULL;
889        }
890
891        // record the number of nested brackets move the input iterator
892        // over the name { tokens.
893        int entry = fr[0].getNoNestedBrackets();
894        fr+=2;
895
896        const DotOsgWrapper::Associates& assoc = wrapper->getAssociates();
897        osg::Object* obj = proto->cloneType();
898
899        while(!fr.eof() && fr[0].getNoNestedBrackets()>entry)
900        {
901            bool iteratorAdvanced = false;
902            if (fr[0].matchWord("UniqueID") && fr[1].isString())
903            {
904                fr.registerUniqueIDForObject(fr[1].getStr(),obj);
905                fr += 2;
906                iteratorAdvanced = true;
907            }
908
909            // read the local data by iterating through the associate
910            // list, mapping the associate names to DotOsgWrapper's which
911            // in turn have the appropriate functions.
912            for(DotOsgWrapper::Associates::const_iterator aitr=assoc.begin();
913                                                          aitr!=assoc.end();
914                                                          ++aitr)
915            {
916                DotOsgWrapperMap::iterator mitr = _objectWrapperMap.find(*aitr);
917                if (mitr==_objectWrapperMap.end())
918                {
919                    // not found so check if a library::class composite name.
920                    std::string token = *aitr;
921                    std::string::size_type posDoubleColon = token.rfind("::");
922                    if (posDoubleColon != std::string::npos)
923                    {
924                        // we have a composite name so now strip off the library name
925                        // and try to load it, and then retry the find to see
926                        // if we can recognize the objects.
927                        std::string libraryName = std::string(token,0,posDoubleColon);
928
929                        // first try the standard nodekit library.
930                        std::string nodeKitLibraryName = createLibraryNameForNodeKit(libraryName);
931                        if (loadLibrary(nodeKitLibraryName)==LOADED)
932                        {
933                            mitr = _objectWrapperMap.find(*aitr);
934                            if (mitr==_objectWrapperMap.end())
935                            {
936                                // otherwise try the osgdb_ plugin library.
937                                std::string pluginLibraryName = createLibraryNameForExtension(libraryName);
938                                if (loadLibrary(pluginLibraryName)==LOADED)
939                                {
940                                    mitr = _objectWrapperMap.find(*aitr);
941                                }
942                            }
943                        }
944                    }
945                }
946
947                if (mitr!=_objectWrapperMap.end())
948                {
949                    // get the function to read the data...
950                    DotOsgWrapper::ReadFunc rf = mitr->second->getReadFunc();
951                    if (rf && (*rf)(*obj,fr)) iteratorAdvanced = true;
952                }
953
954            }
955
956            if (!iteratorAdvanced) fr.advanceOverCurrentFieldOrBlock();
957        }
958        ++fr;                        // step over trailing '}'
959       
960        return obj;
961       
962    }
963    return 0L;
964}
965
966//
967// read object from input iterator.
968//
969osg::Object* Registry::readObject(DotOsgWrapperMap& dowMap,Input& fr)
970{
971    const char *str = fr[0].getStr();
972    if (str==NULL) return NULL;
973
974    std::string name = str;
975    DotOsgWrapperMap::iterator itr = dowMap.find(name);
976    if (itr==dowMap.end())
977    {
978        // not found so check if a library::class composite name.
979        std::string token = fr[0].getStr();
980        std::string::size_type posDoubleColon = token.rfind("::");
981        if (posDoubleColon != std::string::npos)
982        {
983            // we have a composite name so now strip off the library name
984            // are try to load it, and then retry the readObject to see
985            // if we can recognize the objects.
986       
987            std::string libraryName = std::string(token,0,posDoubleColon);
988
989            // first try the standard nodekit library.
990            std::string nodeKitLibraryName = createLibraryNameForNodeKit(libraryName);
991            if (loadLibrary(nodeKitLibraryName)==LOADED) return readObject(dowMap,fr);
992           
993            // otherwise try the osgdb_ plugin library.
994            std::string pluginLibraryName = createLibraryNameForExtension(libraryName);
995            if (loadLibrary(pluginLibraryName)==LOADED) return readObject(dowMap,fr);
996        }
997    }
998    else if (fr[1].isOpenBracket())
999    {
1000   
1001        DotOsgWrapper* wrapper = itr->second.get();
1002        const osg::Object* proto = wrapper->getPrototype();
1003        if (proto==NULL)
1004        {
1005            osg::notify(osg::WARN)<<"Token "<<fr[0].getStr()<<" read, but has no prototype, cannot load."<< std::endl;
1006            return NULL;
1007        }
1008
1009        // record the number of nested brackets move the input iterator
1010        // over the name { tokens.
1011        int entry = fr[0].getNoNestedBrackets();
1012        fr+=2;
1013
1014        const DotOsgWrapper::Associates& assoc = wrapper->getAssociates();
1015        osg::Object* obj = proto->cloneType();
1016
1017        while(!fr.eof() && fr[0].getNoNestedBrackets()>entry)
1018        {
1019            bool iteratorAdvanced = false;
1020            if (fr[0].matchWord("UniqueID") && fr[1].isString())
1021            {
1022                fr.registerUniqueIDForObject(fr[1].getStr(),obj);
1023                fr += 2;
1024                iteratorAdvanced = true;
1025            }
1026
1027            // read the local data by iterating through the associate
1028            // list, mapping the associate names to DotOsgWrapper's which
1029            // in turn have the appropriate functions.
1030            for(DotOsgWrapper::Associates::const_iterator aitr=assoc.begin();
1031                                                          aitr!=assoc.end();
1032                                                          ++aitr)
1033            {
1034                DotOsgWrapperMap::iterator mitr = _objectWrapperMap.find(*aitr);
1035                if (mitr==_objectWrapperMap.end())
1036                {
1037                    // not found so check if a library::class composite name.
1038                    std::string token = *aitr;
1039                    std::string::size_type posDoubleColon = token.rfind("::");
1040                    if (posDoubleColon != std::string::npos)
1041                    {
1042
1043                        // we have a composite name so now strip off the library name
1044                        // are try to load it, and then retry the find to see
1045                        // if we can recognize the objects.
1046
1047                        std::string libraryName = std::string(token,0,posDoubleColon);
1048
1049                        // first try the standard nodekit library.
1050                        std::string nodeKitLibraryName = createLibraryNameForNodeKit(libraryName);
1051                        if (loadLibrary(nodeKitLibraryName)==LOADED)
1052                        {
1053                            mitr = _objectWrapperMap.find(*aitr);
1054                        }
1055
1056                        if (mitr==_objectWrapperMap.end())
1057                        {
1058                            // otherwise try the osgdb_ plugin library.
1059                            std::string pluginLibraryName = createLibraryNameForExtension(libraryName);
1060                            if (loadLibrary(pluginLibraryName)==LOADED)
1061                            {
1062                                mitr = _objectWrapperMap.find(*aitr);
1063                            }
1064                        }
1065
1066                    }
1067                }
1068
1069                if (mitr!=_objectWrapperMap.end())
1070                {
1071                    // get the function to read the data...
1072                    DotOsgWrapper::ReadFunc rf = mitr->second->getReadFunc();
1073                    if (rf && (*rf)(*obj,fr)) iteratorAdvanced = true;
1074                }
1075
1076            }
1077
1078            if (!iteratorAdvanced) fr.advanceOverCurrentFieldOrBlock();
1079        }
1080        ++fr;                        // step over trailing '}'
1081       
1082        return obj;
1083       
1084    }
1085
1086    return 0L;
1087}
1088
1089//
1090// read object from input iterator.
1091//
1092Object* Registry::readObject(Input& fr)
1093{
1094    if (fr[0].matchWord("Use"))
1095    {
1096        if (fr[1].isString())
1097        {
1098            Object* obj = fr.getObjectForUniqueID(fr[1].getStr());
1099            if (obj) fr+=2;
1100            return obj;
1101        }
1102        else return NULL;
1103
1104    }
1105
1106    return readObject(_objectWrapperMap,fr);
1107}
1108
1109
1110//
1111// read image from input iterator.
1112//
1113Image* Registry::readImage(Input& fr)
1114{
1115    if (fr[0].matchWord("Use"))
1116    {
1117        if (fr[1].isString())
1118        {
1119            Image* image = dynamic_cast<Image*>(fr.getObjectForUniqueID(fr[1].getStr()));
1120            if (image) fr+=2;
1121            return image;
1122        }
1123        else return NULL;
1124
1125    }
1126
1127    osg::Object* obj = readObject(_imageWrapperMap,fr);
1128    osg::Image* image = dynamic_cast<Image*>(obj);
1129    if (image) return image;
1130    else if (obj) obj->unref();
1131   
1132    return NULL;
1133}
1134
1135
1136//
1137// read drawable from input iterator.
1138//
1139Drawable* Registry::readDrawable(Input& fr)
1140{
1141    if (fr[0].matchWord("Use"))
1142    {
1143        if (fr[1].isString())
1144        {
1145            Drawable* drawable = dynamic_cast<Drawable*>(fr.getObjectForUniqueID(fr[1].getStr()));
1146            if (drawable) fr+=2;
1147            return drawable;
1148        }
1149        else return NULL;
1150
1151    }
1152
1153    osg::Object* obj = readObject(_drawableWrapperMap,fr);
1154    osg::Drawable* drawable = dynamic_cast<Drawable*>(obj);
1155    if (drawable) return drawable;
1156    else if (obj) obj->unref();
1157   
1158    return NULL;
1159}
1160
1161//
1162// read drawable from input iterator.
1163//
1164StateAttribute* Registry::readStateAttribute(Input& fr)
1165{
1166
1167    if (fr[0].matchWord("Use"))
1168    {
1169        if (fr[1].isString())
1170        {
1171            StateAttribute* attribute = dynamic_cast<StateAttribute*>(fr.getObjectForUniqueID(fr[1].getStr()));
1172            if (attribute) fr+=2;
1173            return attribute;
1174        }
1175        else return NULL;
1176
1177    }
1178
1179    return dynamic_cast<StateAttribute*>(readObject(_stateAttrWrapperMap,fr));
1180}
1181
1182//
1183// read drawable from input iterator.
1184//
1185Uniform* Registry::readUniform(Input& fr)
1186{
1187
1188    if (fr[0].matchWord("Use"))
1189    {
1190        if (fr[1].isString())
1191        {
1192            Uniform* attribute = dynamic_cast<Uniform*>(fr.getObjectForUniqueID(fr[1].getStr()));
1193            if (attribute) fr+=2;
1194            return attribute;
1195        }
1196        else return NULL;
1197
1198    }
1199
1200    return dynamic_cast<Uniform*>(readObject(_uniformWrapperMap,fr));
1201}
1202
1203//
1204// read node from input iterator.
1205//
1206Node* Registry::readNode(Input& fr)
1207{
1208    if (fr[0].matchWord("Use"))
1209    {
1210        if (fr[1].isString())
1211        {
1212            Node* node = dynamic_cast<Node*>(fr.getObjectForUniqueID(fr[1].getStr()));
1213            if (node) fr+=2;
1214            return node;
1215        }
1216        else return NULL;
1217
1218    }
1219
1220    osg::Object* obj = readObject(_nodeWrapperMap,fr);
1221    osg::Node* node = dynamic_cast<Node*>(obj);
1222    if (node) return node;
1223    else if (obj) obj->unref();
1224   
1225    return NULL;
1226}
1227
1228//
1229// read image from input iterator.
1230//
1231Shader* Registry::readShader(Input& fr)
1232{
1233    if (fr[0].matchWord("Use"))
1234    {
1235        if (fr[1].isString())
1236        {
1237            Shader* shader = dynamic_cast<Shader*>(fr.getObjectForUniqueID(fr[1].getStr()));
1238            if (shader) fr+=2;
1239            return shader;
1240        }
1241        else return NULL;
1242
1243    }
1244
1245    osg::Object* obj = readObject(_shaderWrapperMap,fr);
1246    osg::Shader* shader = dynamic_cast<Shader*>(obj);
1247    if (shader) return shader;
1248    else if (obj) obj->unref();
1249   
1250    return NULL;
1251}
1252
1253//
1254// Write object to output
1255//
1256bool Registry::writeObject(const osg::Object& obj,Output& fw)
1257{
1258
1259    if (obj.referenceCount()>1)
1260    {
1261        std::string uniqueID;
1262        if (fw.getUniqueIDForObject(&obj,uniqueID))
1263        {
1264            fw.writeUseID( uniqueID );
1265            return true;
1266        }
1267    }
1268
1269    const std::string classname( obj.className() );
1270    const std::string libraryName( obj.libraryName() );
1271    const std::string compositeName( libraryName + "::" + classname );
1272
1273    // try composite name first
1274    DotOsgWrapperMap::iterator itr = _classNameWrapperMap.find(compositeName);
1275
1276    if (itr==_classNameWrapperMap.end())
1277    {
1278        // first try the standard nodekit library.
1279        std::string nodeKitLibraryName = createLibraryNameForNodeKit(libraryName);
1280        if (loadLibrary(nodeKitLibraryName)==LOADED) return writeObject(obj,fw);
1281
1282        // otherwise try the osgdb_ plugin library.
1283        std::string pluginLibraryName = createLibraryNameForExtension(libraryName);
1284        if (loadLibrary(pluginLibraryName)==LOADED) return writeObject(obj,fw);
1285
1286        // otherwise try simple class name
1287        if (itr == _classNameWrapperMap.end())
1288            itr = _classNameWrapperMap.find(classname);
1289    }
1290
1291    if (itr!=_classNameWrapperMap.end())
1292    {
1293        DotOsgWrapper* wrapper = itr->second.get();
1294        const DotOsgWrapper::Associates& assoc = wrapper->getAssociates();
1295
1296        if (libraryName=="osg")
1297        {
1298            // member of the core osg, so no need to have composite library::class name.
1299            fw.writeBeginObject( wrapper->getName() );
1300        }
1301        else
1302        {
1303            // member of the node kit so must use composite library::class name.
1304            std::string::size_type posDoubleColon = wrapper->getName().find("::");
1305            if (posDoubleColon != std::string::npos)
1306            {
1307                fw.writeBeginObject( wrapper->getName() );
1308            }
1309            else
1310            {
1311                fw.writeBeginObject( libraryName + "::" + wrapper->getName() );
1312            }
1313        }
1314        fw.moveIn();
1315
1316
1317        // write out the unique ID if required.
1318        if (obj.referenceCount()>1)
1319        {
1320            std::string uniqueID;
1321            fw.createUniqueIDForObject(&obj,uniqueID);
1322            fw.registerUniqueIDForObject(&obj,uniqueID);
1323            fw.writeUniqueID( uniqueID );
1324        }
1325
1326        // read the local data by iterating through the associate
1327        // list, mapping the associate names to DotOsgWrapper's which
1328        // in turn have the appropriate functions.
1329        for(DotOsgWrapper::Associates::const_iterator aitr=assoc.begin();
1330                                                      aitr!=assoc.end();
1331                                                      ++aitr)
1332        {
1333            DotOsgWrapperMap::iterator mitr = _objectWrapperMap.find(*aitr);
1334            if (mitr==_objectWrapperMap.end())
1335            {
1336                // not found so check if a library::class composite name.
1337                std::string token = *aitr;
1338                std::string::size_type posDoubleColon = token.rfind("::");
1339                if (posDoubleColon != std::string::npos)
1340                {
1341
1342                    // we have a composite name so now strip off the library name
1343                    // are try to load it, and then retry the find to see
1344                    // if we can recognize the objects.
1345
1346                    std::string libraryName = std::string(token,0,posDoubleColon);
1347
1348                    // first try the standard nodekit library.
1349                    std::string nodeKitLibraryName = createLibraryNameForNodeKit(libraryName);
1350                    if (loadLibrary(nodeKitLibraryName)==LOADED)
1351                    {
1352                        mitr = _objectWrapperMap.find(*aitr);
1353                    }
1354
1355                    if (mitr==_objectWrapperMap.end())
1356                    {
1357                        // otherwise try the osgdb_ plugin library.
1358                        std::string pluginLibraryName = createLibraryNameForExtension(libraryName);
1359                        if (loadLibrary(pluginLibraryName)==LOADED)
1360                        {
1361                            mitr = _objectWrapperMap.find(*aitr);
1362                        }
1363                    }
1364
1365                }
1366            }
1367            if (mitr!=_objectWrapperMap.end())
1368            {
1369                // get the function to read the data...
1370                DotOsgWrapper::WriteFunc wf = mitr->second->getWriteFunc();
1371                if (wf) (*wf)(obj,fw);
1372            }
1373
1374        }
1375
1376        fw.moveOut();
1377        fw.writeEndObject();
1378
1379        return true;
1380    }
1381   
1382    return false;
1383}
1384
1385
1386
1387struct Registry::ReadObjectFunctor : public Registry::ReadFunctor
1388{
1389    ReadObjectFunctor(const std::string& filename, const ReaderWriter::Options* options):ReadFunctor(filename,options) {}
1390
1391    virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw) const { return rw.readObject(_filename, _options); }   
1392    virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validObject(); }
1393    virtual bool isValid(osg::Object* object) const { return object!=0;  }
1394};
1395
1396struct Registry::ReadImageFunctor : public Registry::ReadFunctor
1397{
1398    ReadImageFunctor(const std::string& filename, const ReaderWriter::Options* options):ReadFunctor(filename,options) {}
1399
1400    virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw)const  { return rw.readImage(_filename, _options); }   
1401    virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validImage(); }
1402    virtual bool isValid(osg::Object* object) const { return dynamic_cast<osg::Image*>(object)!=0;  }
1403};
1404
1405struct Registry::ReadHeightFieldFunctor : public Registry::ReadFunctor
1406{
1407    ReadHeightFieldFunctor(const std::string& filename, const ReaderWriter::Options* options):ReadFunctor(filename,options) {}
1408
1409    virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw) const { return rw.readHeightField(_filename, _options); }   
1410    virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validHeightField(); }
1411    virtual bool isValid(osg::Object* object) const { return dynamic_cast<osg::HeightField*>(object)!=0;  }
1412};
1413
1414struct Registry::ReadNodeFunctor : public Registry::ReadFunctor
1415{
1416    ReadNodeFunctor(const std::string& filename, const ReaderWriter::Options* options):ReadFunctor(filename,options) {}
1417
1418    virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw) const { return rw.readNode(_filename, _options); }   
1419    virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validNode(); }
1420    virtual bool isValid(osg::Object* object) const { return dynamic_cast<osg::Node*>(object)!=0;  }
1421
1422};
1423
1424struct Registry::ReadArchiveFunctor : public Registry::ReadFunctor
1425{
1426    ReadArchiveFunctor(const std::string& filename, ReaderWriter::ArchiveStatus status, unsigned int indexBlockSizeHint, const ReaderWriter::Options* options):
1427        ReadFunctor(filename,options),
1428        _status(status),
1429        _indexBlockSizeHint(indexBlockSizeHint) {}
1430       
1431    ReaderWriter::ArchiveStatus _status;
1432    unsigned int _indexBlockSizeHint;
1433
1434    virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw) const { return rw.openArchive(_filename, _status, _indexBlockSizeHint, _options); }
1435    virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validArchive(); }
1436    virtual bool isValid(osg::Object* object) const { return dynamic_cast<osgDB::Archive*>(object)!=0;  }
1437
1438};
1439
1440struct Registry::ReadShaderFunctor : public Registry::ReadFunctor
1441{
1442    ReadShaderFunctor(const std::string& filename, const ReaderWriter::Options* options):ReadFunctor(filename,options) {}
1443
1444    virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw)const  { return rw.readShader(_filename, _options); }   
1445    virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validShader(); }
1446    virtual bool isValid(osg::Object* object) const { return dynamic_cast<osg::Shader*>(object)!=0;  }
1447};
1448
1449void Registry::addArchiveExtension(const std::string ext)
1450{
1451    for(ArchiveExtensionList::iterator aitr=_archiveExtList.begin();
1452        aitr!=_archiveExtList.end();
1453        ++aitr)
1454    {
1455        if ( (*aitr) == ext)   // extension already in archive extension list
1456            return;
1457    }
1458    _archiveExtList.push_back(ext);
1459}
1460
1461ReaderWriter::ReadResult Registry::read(const ReadFunctor& readFunctor)
1462{
1463    for(ArchiveExtensionList::iterator aitr=_archiveExtList.begin();
1464        aitr!=_archiveExtList.end();
1465        ++aitr)
1466    {
1467        std::string archiveExtension = "." + (*aitr);
1468
1469        std::string::size_type positionArchive = readFunctor._filename.find(archiveExtension+'/');
1470        if (positionArchive==std::string::npos) positionArchive = readFunctor._filename.find(archiveExtension+'\\');
1471        if (positionArchive!=std::string::npos)
1472        {
1473            std::string::size_type endArchive = positionArchive + archiveExtension.length();
1474            std::string archiveName( readFunctor._filename.substr(0,endArchive));
1475            std::string fileName(readFunctor._filename.substr(endArchive+1,std::string::npos));
1476            osg::notify(osg::INFO)<<"Contains archive : "<<readFunctor._filename<<std::endl;
1477            osg::notify(osg::INFO)<<"         archive : "<<archiveName<<std::endl;
1478            osg::notify(osg::INFO)<<"         filename : "<<fileName<<std::endl;
1479       
1480            ReaderWriter::ReadResult result = openArchiveImplementation(archiveName,ReaderWriter::READ, 4096, readFunctor._options);
1481       
1482            if (!result.validArchive()) return result;
1483
1484            osgDB::Archive* archive = result.getArchive();
1485       
1486            osg::ref_ptr<ReaderWriter::Options> options = new ReaderWriter::Options;
1487            options->setDatabasePath(archiveName);
1488
1489            return archive->readObject(fileName,options.get());
1490        }
1491    }
1492 
1493    // record the errors reported by readerwriters.
1494    typedef std::vector<ReaderWriter::ReadResult> Results;
1495    Results results;
1496
1497    // first attempt to load the file from existing ReaderWriter's
1498    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
1499    for(;itr.valid();++itr)
1500    {
1501        ReaderWriter::ReadResult rr = readFunctor.doRead(*itr);
1502        if (readFunctor.isValid(rr)) return rr;
1503        else results.push_back(rr);
1504    }
1505
1506    if (!results.empty())
1507    {
1508        unsigned int num_FILE_NOT_HANDLED = 0;
1509        unsigned int num_FILE_NOT_FOUND = 0;
1510        unsigned int num_ERROR_IN_READING_FILE = 0;
1511
1512        Results::iterator ritr;
1513        for(ritr=results.begin();
1514            ritr!=results.end();
1515            ++ritr)
1516        {
1517            if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_HANDLED) ++num_FILE_NOT_HANDLED;
1518            else if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_FOUND) ++num_FILE_NOT_FOUND;
1519            else if (ritr->status()==ReaderWriter::ReadResult::ERROR_IN_READING_FILE) ++num_ERROR_IN_READING_FILE;
1520        }
1521       
1522        if (num_FILE_NOT_HANDLED!=results.size())
1523        {
1524            for(ritr=results.begin(); ritr!=results.end(); ++ritr)
1525            {
1526                if (ritr->status()==ReaderWriter::ReadResult::ERROR_IN_READING_FILE)
1527                {
1528                    // osg::notify(osg::NOTICE)<<"Warning: error reading file \""<<readFunctor._filename<<"\""<<std::endl;
1529                    return *ritr;
1530                }
1531            }
1532
1533            //If the filename is a URL, don't return FILE_NOT_FOUND until the CURL plugin is given a chance
1534            if (!osgDB::containsServerAddress(readFunctor._filename))
1535            {
1536                for(ritr=results.begin(); ritr!=results.end(); ++ritr)
1537                {
1538                    if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_FOUND)
1539                    {
1540                        //osg::notify(osg::NOTICE)<<"Warning: could not find file \""<<readFunctor._filename<<"\""<<std::endl;
1541                        return *ritr;
1542                    }
1543                }
1544            }
1545        }
1546    }
1547
1548    results.clear();
1549
1550    // now look for a plug-in to load the file.
1551    std::string libraryName = createLibraryNameForFile(readFunctor._filename);
1552    if (loadLibrary(libraryName)!=NOT_LOADED)
1553    {
1554        for(;itr.valid();++itr)
1555        {
1556            ReaderWriter::ReadResult rr = readFunctor.doRead(*itr);
1557            if (readFunctor.isValid(rr)) return rr;
1558            else results.push_back(rr);
1559        }
1560    }
1561
1562    //If the filename contains a server address and wasn't loaded by any of the plugins, try to use the CURL plugin
1563    //to download the file and use the stream reading functionality of the plugins to load the file
1564    if (containsServerAddress(readFunctor._filename))
1565    {
1566        ReaderWriter* rw = getReaderWriterForExtension("curl");
1567        if (rw)
1568        {
1569            return readFunctor.doRead(*rw);
1570        }
1571        else
1572        {
1573            return  ReaderWriter::ReadResult("Warning: Could not find the .curl plugin to read from server.");
1574        }
1575    }
1576   
1577    if (!results.empty())
1578    {
1579        unsigned int num_FILE_NOT_HANDLED = 0;
1580        unsigned int num_FILE_NOT_FOUND = 0;
1581        unsigned int num_ERROR_IN_READING_FILE = 0;
1582
1583        Results::iterator ritr;
1584        for(ritr=results.begin();
1585            ritr!=results.end();
1586            ++ritr)
1587        {
1588            if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_HANDLED) ++num_FILE_NOT_HANDLED;
1589            else if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_FOUND) ++num_FILE_NOT_FOUND;
1590            else if (ritr->status()==ReaderWriter::ReadResult::ERROR_IN_READING_FILE) ++num_ERROR_IN_READING_FILE;
1591        }
1592       
1593        if (num_FILE_NOT_HANDLED!=results.size())
1594        {
1595            for(ritr=results.begin(); ritr!=results.end(); ++ritr)
1596            {
1597                if (ritr->status()==ReaderWriter::ReadResult::ERROR_IN_READING_FILE)
1598                {
1599                    // osg::notify(osg::NOTICE)<<"Warning: error reading file \""<<readFunctor._filename<<"\""<<std::endl;
1600                    return *ritr;
1601                }
1602            }
1603
1604            for(ritr=results.begin(); ritr!=results.end(); ++ritr)
1605            {
1606                if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_FOUND)
1607                {
1608                    // osg::notify(osg::NOTICE)<<"Warning: could not find file \""<<readFunctor._filename<<"\""<<std::endl;
1609                    return *ritr;
1610                }
1611            }
1612        }
1613    }
1614    else
1615    {
1616        return ReaderWriter::ReadResult("Warning: Could not find plugin to read objects from file \""+readFunctor._filename+"\".");
1617    }
1618
1619    return results.front();
1620}
1621
1622ReaderWriter::ReadResult Registry::readImplementation(const ReadFunctor& readFunctor, bool useObjectCache)
1623{
1624    std::string file(readFunctor._filename);
1625
1626    if (useObjectCache)
1627    {
1628        // search for entry in the object cache.
1629        {
1630            OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
1631            ObjectCache::iterator oitr=_objectCache.find(file);
1632            if (oitr!=_objectCache.end())
1633            {
1634                notify(INFO)<<"returning cached instanced of "<<file<<std::endl;
1635                if (readFunctor.isValid(oitr->second.first.get())) return ReaderWriter::ReadResult(oitr->second.first.get(), ReaderWriter::ReadResult::FILE_LOADED_FROM_CACHE);
1636                else return ReaderWriter::ReadResult("Error file does not contain an osg::Object");
1637            }
1638        }
1639       
1640        ReaderWriter::ReadResult rr = read(readFunctor);
1641        if (rr.validObject())
1642        {
1643            // update cache with new entry.
1644            notify(INFO)<<"Adding to object cache "<<file<<std::endl;
1645            addEntryToObjectCache(file,rr.getObject());
1646        }
1647        else
1648        {
1649            notify(INFO)<<"No valid object found for "<<file<<std::endl;
1650        }
1651
1652        return rr;
1653
1654    }
1655    else
1656    {
1657        ObjectCache tmpObjectCache;
1658       
1659        {
1660            OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
1661            tmpObjectCache.swap(_objectCache);
1662        }
1663       
1664        ReaderWriter::ReadResult rr = read(readFunctor);
1665
1666        {
1667            OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
1668            tmpObjectCache.swap(_objectCache);
1669        }
1670       
1671        return rr;
1672    }
1673}
1674
1675
1676ReaderWriter::ReadResult Registry::openArchiveImplementation(const std::string& fileName, ReaderWriter::ArchiveStatus status, unsigned int indexBlockSizeHint, const ReaderWriter::Options* options)
1677{
1678    osgDB::Archive* archive = getFromArchiveCache(fileName);
1679    if (archive) return archive;
1680
1681    ReaderWriter::ReadResult result = readImplementation(ReadArchiveFunctor(fileName, status, indexBlockSizeHint, options),false);
1682
1683    // default to using caching archive if no options structure provided, but if options are provided use archives
1684    // only if supplied.
1685    if (result.validArchive() &&
1686        (!options || (options->getObjectCacheHint() & ReaderWriter::Options::CACHE_ARCHIVES)) )
1687    {
1688        addToArchiveCache(fileName,result.getArchive());
1689    }
1690    return result;
1691}
1692
1693
1694ReaderWriter::ReadResult Registry::readObjectImplementation(const std::string& fileName,const ReaderWriter::Options* options)
1695{
1696    return readImplementation(ReadObjectFunctor(fileName, options),
1697                              options ? (options->getObjectCacheHint()&ReaderWriter::Options::CACHE_OBJECTS)!=0: false);
1698}
1699
1700ReaderWriter::WriteResult Registry::writeObjectImplementation(const Object& obj,const std::string& fileName,const ReaderWriter::Options* options)
1701{
1702    // record the errors reported by readerwriters.
1703    typedef std::vector<ReaderWriter::WriteResult> Results;
1704    Results results;
1705
1706    // first attempt to load the file from existing ReaderWriter's
1707    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
1708    for(;itr.valid();++itr)
1709    {
1710        ReaderWriter::WriteResult rr = itr->writeObject(obj,fileName,options);
1711        if (rr.success()) return rr;
1712        else results.push_back(rr);
1713    }
1714
1715    // now look for a plug-in to save the file.
1716    std::string libraryName = createLibraryNameForFile(fileName);
1717    if (loadLibrary(libraryName)==LOADED)
1718    {
1719        for(;itr.valid();++itr)
1720        {
1721            ReaderWriter::WriteResult rr = itr->writeObject(obj,fileName,options);
1722            if (rr.success()) return rr;
1723            else results.push_back(rr);
1724        }
1725    }
1726
1727    if (results.empty())
1728    {
1729        return ReaderWriter::WriteResult("Warning: Could not find plugin to write objects to file \""+fileName+"\".");
1730    }
1731
1732    if (results.front().message().empty())
1733    {
1734        switch(results.front().status())
1735        {
1736            case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): results.front().message() = "Warning: Write to \""+fileName+"\" not supported."; break;
1737            case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): results.front().message() = "Warning: Error in writing to \""+fileName+"\"."; break;
1738            default: break;
1739        }
1740    }
1741
1742    return results.front();
1743}
1744
1745
1746
1747ReaderWriter::ReadResult Registry::readImageImplementation(const std::string& fileName,const ReaderWriter::Options* options)
1748{
1749    return readImplementation(ReadImageFunctor(fileName, options),
1750                              options ? (options->getObjectCacheHint()&ReaderWriter::Options::CACHE_IMAGES)!=0: false);
1751}
1752
1753ReaderWriter::WriteResult Registry::writeImageImplementation(const Image& image,const std::string& fileName,const ReaderWriter::Options* options)
1754{
1755    // record the errors reported by readerwriters.
1756    typedef std::vector<ReaderWriter::WriteResult> Results;
1757    Results results;
1758
1759    // first attempt to load the file from existing ReaderWriter's
1760    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
1761    for(;itr.valid();++itr)
1762    {
1763        ReaderWriter::WriteResult rr = itr->writeImage(image,fileName,options);
1764        if (rr.success()) return rr;
1765        else results.push_back(rr);
1766    }
1767
1768    results.clear();
1769
1770    // now look for a plug-in to save the file.
1771    std::string libraryName = createLibraryNameForFile(fileName);
1772    if (loadLibrary(libraryName)==LOADED)
1773    {
1774        for(;itr.valid();++itr)
1775        {
1776            ReaderWriter::WriteResult rr = itr->writeImage(image,fileName,options);
1777            if (rr.success()) return rr;
1778            else results.push_back(rr);
1779        }
1780    }
1781
1782    if (results.empty())
1783    {
1784        return ReaderWriter::WriteResult("Warning: Could not find plugin to write image to file \""+fileName+"\".");
1785    }
1786   
1787    if (results.front().message().empty())
1788    {
1789        switch(results.front().status())
1790        {
1791            case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): results.front().message() = "Warning: Write to \""+fileName+"\" not supported."; break;
1792            case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): results.front().message() = "Warning: Error in writing to \""+fileName+"\"."; break;
1793            default: break;
1794        }
1795    }
1796
1797    return results.front();
1798}
1799
1800
1801ReaderWriter::ReadResult Registry::readHeightFieldImplementation(const std::string& fileName,const ReaderWriter::Options* options)
1802{
1803    return readImplementation(ReadHeightFieldFunctor(fileName, options),
1804                              options ? (options->getObjectCacheHint()&ReaderWriter::Options::CACHE_HEIGHTFIELDS)!=0: false);
1805}
1806
1807ReaderWriter::WriteResult Registry::writeHeightFieldImplementation(const HeightField& HeightField,const std::string& fileName,const ReaderWriter::Options* options)
1808{
1809    // record the errors reported by readerwriters.
1810    typedef std::vector<ReaderWriter::WriteResult> Results;
1811    Results results;
1812
1813    // first attempt to load the file from existing ReaderWriter's
1814    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
1815    for(;itr.valid();++itr)
1816    {
1817        ReaderWriter::WriteResult rr = itr->writeHeightField(HeightField,fileName,options);
1818        if (rr.success()) return rr;
1819        else results.push_back(rr);
1820    }
1821
1822    results.clear();
1823
1824    // now look for a plug-in to save the file.
1825    std::string libraryName = createLibraryNameForFile(fileName);
1826    if (loadLibrary(libraryName)==LOADED)
1827    {
1828        for(;itr.valid();++itr)
1829        {
1830            ReaderWriter::WriteResult rr = itr->writeHeightField(HeightField,fileName,options);
1831            if (rr.success()) return rr;
1832            else results.push_back(rr);
1833        }
1834    }
1835
1836    if (results.empty())
1837    {
1838        return ReaderWriter::WriteResult("Warning: Could not find plugin to write HeightField to file \""+fileName+"\".");
1839    }
1840
1841    if (results.front().message().empty())
1842    {
1843        switch(results.front().status())
1844        {
1845            case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): results.front().message() = "Warning: Write to \""+fileName+"\" not supported."; break;
1846            case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): results.front().message() = "Warning: Error in writing to \""+fileName+"\"."; break;
1847            default: break;
1848        }
1849    }
1850   
1851    return results.front();
1852}
1853
1854
1855ReaderWriter::ReadResult Registry::readNodeImplementation(const std::string& fileName,const ReaderWriter::Options* options)
1856{
1857#if 0
1858
1859    osg::Timer_t startTick = osg::Timer::instance()->tick();
1860    ReaderWriter::ReadResult result = readImplementation(ReadNodeFunctor(fileName, options),
1861                              options ? (options->getObjectCacheHint()&ReaderWriter::Options::CACHE_NODES)!=0: false);
1862    osg::Timer_t endTick = osg::Timer::instance()->tick();
1863    osg::notify(osg::NOTICE)<<"time to load "<<fileName<<" "<<osg::Timer::instance()->delta_m(startTick, endTick)<<"ms"<<std::endl;
1864    return result;
1865
1866#else
1867
1868    return readImplementation(ReadNodeFunctor(fileName, options),
1869                              options ? (options->getObjectCacheHint()&ReaderWriter::Options::CACHE_NODES)!=0: false);
1870                             
1871#endif
1872}
1873
1874ReaderWriter::WriteResult Registry::writeNodeImplementation(const Node& node,const std::string& fileName,const ReaderWriter::Options* options)
1875{
1876    // record the errors reported by readerwriters.
1877    typedef std::vector<ReaderWriter::WriteResult> Results;
1878    Results results;
1879
1880    // first attempt to write the file from existing ReaderWriter's
1881    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
1882    for(;itr.valid();++itr)
1883    {
1884        ReaderWriter::WriteResult rr = itr->writeNode(node,fileName,options);
1885        if (rr.success()) return rr;
1886        else results.push_back(rr);
1887    }
1888
1889    results.clear();
1890
1891    // now look for a plug-in to save the file.
1892    std::string libraryName = createLibraryNameForFile(fileName);
1893
1894
1895    if (loadLibrary(libraryName)==LOADED)
1896    {
1897        for(;itr.valid();++itr)
1898        {
1899            ReaderWriter::WriteResult rr = itr->writeNode(node,fileName,options);
1900   
1901            if (rr.success()) return rr;
1902            else results.push_back(rr);
1903        }
1904    }
1905
1906    if (results.empty())
1907    {
1908        return ReaderWriter::WriteResult("Warning: Could not find plugin to write nodes to file \""+fileName+"\".");
1909    }
1910
1911    if (results.front().message().empty())
1912    {
1913        switch(results.front().status())
1914        {
1915            case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): results.front().message() = "Warning: Write to \""+fileName+"\" not supported."; break;
1916            case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): results.front().message() = "Warning: Error in writing to \""+fileName+"\"."; break;
1917            default: break;
1918        }
1919    }
1920
1921    return results.front();
1922}
1923
1924ReaderWriter::ReadResult Registry::readShaderImplementation(const std::string& fileName,const ReaderWriter::Options* options)
1925{
1926    return readImplementation(ReadShaderFunctor(fileName, options),
1927                              options ? (options->getObjectCacheHint()&ReaderWriter::Options::CACHE_SHADERS)!=0: false);
1928}
1929
1930ReaderWriter::WriteResult Registry::writeShaderImplementation(const Shader& shader,const std::string& fileName,const ReaderWriter::Options* options)
1931{
1932    // record the errors reported by readerwriters.
1933    typedef std::vector<ReaderWriter::WriteResult> Results;
1934    Results results;
1935
1936    // first attempt to load the file from existing ReaderWriter's
1937    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
1938    for(;itr.valid();++itr)
1939    {
1940        ReaderWriter::WriteResult rr = itr->writeShader(shader,fileName,options);
1941        if (rr.success()) return rr;
1942        else results.push_back(rr);
1943    }
1944
1945    results.clear();
1946
1947    // now look for a plug-in to save the file.
1948    std::string libraryName = createLibraryNameForFile(fileName);
1949    if (loadLibrary(libraryName)==LOADED)
1950    {
1951        for(;itr.valid();++itr)
1952        {
1953            ReaderWriter::WriteResult rr = itr->writeShader(shader,fileName,options);
1954            if (rr.success()) return rr;
1955            else results.push_back(rr);
1956        }
1957    }
1958
1959    if (results.empty())
1960    {
1961        return ReaderWriter::WriteResult("Warning: Could not find plugin to write shader to file \""+fileName+"\".");
1962    }
1963   
1964    if (results.front().message().empty())
1965    {
1966        switch(results.front().status())
1967        {
1968            case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): results.front().message() = "Warning: Write to \""+fileName+"\" not supported."; break;
1969            case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): results.front().message() = "Warning: Error in writing to \""+fileName+"\"."; break;
1970            default: break;
1971        }
1972    }
1973
1974    return results.front();
1975}
1976
1977void Registry::addEntryToObjectCache(const std::string& filename, osg::Object* object, double timestamp)
1978{
1979    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
1980    _objectCache[filename]=ObjectTimeStampPair(object,timestamp);
1981}
1982osg::Object* Registry::getFromObjectCache(const std::string& fileName)
1983{
1984    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
1985    ObjectCache::iterator itr = _objectCache.find(fileName);
1986    if (itr!=_objectCache.end()) return itr->second.first.get();
1987    else return 0;
1988}
1989
1990void Registry::updateTimeStampOfObjectsInCacheWithExternalReferences(double currentTime)
1991{
1992    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
1993
1994    // look for objects with external references and update their time stamp.
1995    for(ObjectCache::iterator itr=_objectCache.begin();
1996        itr!=_objectCache.end();
1997        ++itr)
1998    {
1999        // if ref count is greater the 1 the object has an external reference.
2000        if (itr->second.first->referenceCount()>1)
2001        {
2002            // so update it time stamp.
2003            itr->second.second = currentTime;
2004        }
2005    }
2006}
2007
2008void Registry::removeExpiredObjectsInCache(double expiryTime)
2009{
2010    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
2011
2012    typedef std::vector<std::string> ObjectsToRemove;
2013    ObjectsToRemove objectsToRemove;
2014
2015    // first collect all the expired entries in the ObjectToRemove list.
2016    for(ObjectCache::iterator oitr=_objectCache.begin();
2017        oitr!=_objectCache.end();
2018        ++oitr)
2019    {
2020        if (oitr->second.second<=expiryTime)
2021        {
2022            // record the filename of the entry to use as key for deleting
2023            // afterwards/
2024            objectsToRemove.push_back(oitr->first);
2025        }
2026    }
2027   
2028    // remove the entries from the _objectCaache.
2029    for(ObjectsToRemove::iterator ritr=objectsToRemove.begin();
2030        ritr!=objectsToRemove.end();
2031        ++ritr)
2032    {
2033        // std::cout<<"Removing from Registry object cache '"<<*ritr<<"'"<<std::endl;
2034        _objectCache.erase(*ritr);
2035    }
2036       
2037}
2038
2039void Registry::clearObjectCache()
2040{
2041    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
2042    _objectCache.clear();
2043}
2044
2045void Registry::addToArchiveCache(const std::string& fileName, osgDB::Archive* archive)
2046{
2047    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_archiveCacheMutex);
2048    _archiveCache[fileName] = archive;
2049}
2050
2051/** Remove archive from cache.*/
2052void Registry::removeFromArchiveCache(const std::string& fileName)
2053{
2054    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_archiveCacheMutex);
2055    ArchiveCache::iterator itr = _archiveCache.find(fileName);
2056    if (itr!=_archiveCache.end())
2057    {
2058        _archiveCache.erase(itr);
2059    }
2060}
2061
2062osgDB::Archive* Registry::getFromArchiveCache(const std::string& fileName)
2063{
2064    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_archiveCacheMutex);
2065    ArchiveCache::iterator itr = _archiveCache.find(fileName);
2066    if (itr!=_archiveCache.end()) return itr->second.get();
2067    else return 0;
2068}
2069
2070void Registry::clearArchiveCache()
2071{
2072    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_archiveCacheMutex);
2073    _archiveCache.clear();
2074}
2075
2076void Registry::releaseGLObjects(osg::State* state)
2077{
2078    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
2079
2080    for(ObjectCache::iterator itr = _objectCache.begin();
2081        itr != _objectCache.end();
2082        ++itr)
2083    {
2084        osg::Object* object = itr->second.first.get();
2085        object->releaseGLObjects(state);
2086    }
2087}
2088
2089SharedStateManager* Registry::getOrCreateSharedStateManager()
2090{
2091    if (!_sharedStateManager) _sharedStateManager = new SharedStateManager;
2092   
2093    return _sharedStateManager.get();
2094}
Note: See TracBrowser for help on using the browser.