root/OpenSceneGraph/branches/osg-cocoa-dev/src/osgDB/Registry.cpp @ 9859

Revision 9859, 69.1 kB (checked in by shuber, 6 years ago)

new CMake-option OSG_DEFAULT_IMAGE_PLUGIN_FOR_OSX for switching between imageio and quicktime on OS X.

Note: both plugins get build, only the hardwiring in osgDB::Registry gets modified.

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