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

Revision 13156, 57.7 kB (checked in by robert, 6 hours ago)

From Mattias Helsing, "Seems I was only half right given what you asked for. CMP0017 only
says that modules that are found and ran from cmake modules dir should
prefer cmake-provided modules. find_package() and include() still look
in CMAKE_MODULE_PATH first.

After some investigating I've come up with a proposal examplified in
the attached FindGDAL.cmake script. It simply calls the cmake provided
FindGDAL.cmake if it exists and returns if it succeeds in finding GDAL
using that, otherwise continue with our local cmake code.
Pro: Wont clutter our root CMakeLists.txt
Con: If we begin to write more advanced Findxxx modules (using
COMPONENTS, REQUIRED etc.) we may have to revise this scheme.
"

  • 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#include <memory>
37
38#include <stdlib.h>
39
40#if defined(__sgi)
41    #include <ctype.h>
42#elif defined(__GNUC__) || !defined(WIN32) || defined(__MWERKS__)
43    #include <cctype>
44    using std::tolower;
45#endif
46
47#ifdef OSG_LIBRARY_POSTFIX
48    #define OSG_LIBRARY_POSTFIX_WITH_QUOTES ADDQUOTES(OSG_LIBRARY_POSTFIX)
49#else
50    #define OSG_LIBRARY_POSTFIX_WITH_QUOTES ""
51#endif
52
53using namespace osg;
54using namespace osgDB;
55
56#if !defined(WIN32) || defined(__CYGWIN__)
57static osg::ApplicationUsageProxy Registry_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_FILE_PATH <path>[:path]..","Paths for locating datafiles");
58static osg::ApplicationUsageProxy Registry_e1(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_LIBRARY_PATH <path>[:path]..","Paths for locating libraries/ plugins");
59#else
60static osg::ApplicationUsageProxy Registry_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_FILE_PATH <path>[;path]..","Paths for locating datafiles");
61static osg::ApplicationUsageProxy Registry_e1(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_LIBRARY_PATH <path>[;path]..","Paths for locating libraries/ plugins");
62#endif
63
64static osg::ApplicationUsageProxy Registry_e2(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_BUILD_KDTREES on/off","Enable/disable the automatic building of KdTrees for each loaded Geometry.");
65
66
67// from MimeTypes.cpp
68extern const char* builtinMimeTypeExtMappings[];
69
70
71class Registry::AvailableReaderWriterIterator
72{
73public:
74    AvailableReaderWriterIterator(Registry::ReaderWriterList& rwList, OpenThreads::ReentrantMutex& pluginMutex):
75        _rwList(rwList),
76        _pluginMutex(pluginMutex) {}
77
78
79    ReaderWriter& operator * () { return *get(); }
80    ReaderWriter* operator -> () { return get(); }
81
82    bool valid() { return get()!=0; }
83
84    void operator ++()
85    {
86        _rwUsed.insert(get());
87    }
88
89
90protected:
91
92    AvailableReaderWriterIterator& operator = (const AvailableReaderWriterIterator&) { return *this; }
93
94    Registry::ReaderWriterList&     _rwList;
95    OpenThreads::ReentrantMutex&    _pluginMutex;
96
97    std::set<ReaderWriter*>         _rwUsed;
98
99    ReaderWriter* get()
100    {
101        OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
102        Registry::ReaderWriterList::iterator itr=_rwList.begin();
103        for(;itr!=_rwList.end();++itr)
104        {
105            if (_rwUsed.find(itr->get())==_rwUsed.end())
106            {
107                return itr->get();
108            }
109        }
110        return 0;
111    }
112
113};
114
115class Registry::AvailableArchiveIterator
116{
117public:
118    AvailableArchiveIterator(Registry::ArchiveCache& archives, OpenThreads::ReentrantMutex& mutex):
119        _archives(archives),
120        _mutex(mutex) {}
121
122
123    Archive& operator * () { return *get(); }
124    Archive* operator -> () { return get(); }
125
126    bool valid() { return get()!=0; }
127
128    void operator ++()
129    {
130        _archivesUsed.insert(get());
131    }
132
133
134protected:
135
136    AvailableArchiveIterator& operator = (const AvailableArchiveIterator&) { return *this; }
137
138    Registry::ArchiveCache&         _archives;
139    OpenThreads::ReentrantMutex&    _mutex;
140
141    std::set<Archive*>              _archivesUsed;
142
143    Archive* get()
144    {
145        OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_mutex);
146        Registry::ArchiveCache::iterator itr=_archives.begin();
147        for(;itr!=_archives.end();++itr)
148        {
149            if (_archivesUsed.find(itr->second.get())==_archivesUsed.end())
150            {
151                return itr->second.get();
152            }
153        }
154        return 0;
155    }
156
157};
158
159#if 0
160    // temporary test of autoregistering, not compiled by default.
161    enum Methods
162    {
163        SET_1,
164        SET_2,
165        END
166    };
167
168
169    typedef std::pair<Methods,std::string> MethodPair;
170
171    class Proxy
172    {
173    public:
174        Proxy(MethodPair* methods)
175        {
176            std::cout<<"methods "<<methods<<std::endl;
177            for(int i=0;methods[i].first!=END;++i)
178            {
179                std::cout<<"\t"<<methods[i].first<<"\t"<<methods[i].second<<std::endl;
180            }
181        }
182    };
183
184
185    static MethodPair methods[] =
186    {
187        MethodPair(SET_1,"SET_1"),
188        MethodPair(SET_2,"SET_2"),
189        MethodPair(END,"")
190    };
191
192    Proxy myproxy(methods);
193
194#endif
195
196void PrintFilePathList(std::ostream& stream,const FilePathList& filepath)
197{
198    for(FilePathList::const_iterator itr=filepath.begin();
199        itr!=filepath.end();
200        ++itr)
201    {
202        stream << "    "<< *itr<<std::endl;
203    }
204}
205
206Registry* Registry::instance(bool erase)
207{
208    static ref_ptr<Registry> s_registry = new Registry;
209    if (erase)
210    {
211        s_registry->destruct();
212        s_registry = 0;
213    }
214    return s_registry.get(); // will return NULL on erase
215}
216
217
218// definition of the Registry
219Registry::Registry()
220{
221    // comment out because it was causing problems under OSX - causing it to crash osgconv when constructing ostream in osg::notify().
222    // OSG_INFO << "Constructing osg::Registry"<<std::endl;
223
224    _buildKdTreesHint = Options::NO_PREFERENCE;
225    _kdTreeBuilder = new osg::KdTreeBuilder;
226
227    const char* kdtree_str = getenv("OSG_BUILD_KDTREES");
228    if (kdtree_str)
229    {
230        bool switchOff = (strcmp(kdtree_str, "off")==0 || strcmp(kdtree_str, "OFF")==0 || strcmp(kdtree_str, "Off")==0 );
231        if (switchOff) _buildKdTreesHint = Options::DO_NOT_BUILD_KDTREES;
232        else _buildKdTreesHint = Options::BUILD_KDTREES;
233    }
234
235    const char* ptr=0;
236
237    _expiryDelay = 10.0;
238    if( (ptr = getenv("OSG_EXPIRY_DELAY")) != 0)
239    {
240        _expiryDelay = osg::asciiToDouble(ptr);
241        OSG_INFO<<"Registry : Expiry delay = "<<_expiryDelay<<std::endl;
242    }
243
244    const char* fileCachePath = getenv("OSG_FILE_CACHE");
245    if (fileCachePath)
246    {
247        _fileCache = new FileCache(fileCachePath);
248    }
249
250    _createNodeFromImage = false;
251    _openingLibrary = false;
252
253    // add default osga archive extension
254    _archiveExtList.push_back("osga");
255    _archiveExtList.push_back("zip");
256
257    initFilePathLists();
258
259
260
261    // register file extension alias.
262    const char* flt_str = getenv("OSG_OPEN_FLIGHT_PLUGIN");
263    if (flt_str)
264    {
265        if (strcmp(flt_str, "new")==0)
266        {
267            addFileExtensionAlias("flt", "OpenFlight");
268        }
269    }
270    else
271    {
272    #ifndef COMPILE_WITH_OLD_OPENFLIGHT_PLUGIN_AS_DEFAULT
273        addFileExtensionAlias("flt", "OpenFlight");
274    #endif
275    }
276
277    addFileExtensionAlias("osgs", "osg");
278    addFileExtensionAlias("osgt", "osg");
279    addFileExtensionAlias("osgb", "osg");
280    addFileExtensionAlias("osgx", "osg");
281
282    addFileExtensionAlias("shadow""osgshadow");
283    addFileExtensionAlias("terrain", "osgterrain");
284    addFileExtensionAlias("view""osgviewer");
285
286    addFileExtensionAlias("sgi""rgb");
287    addFileExtensionAlias("rgba", "rgb");
288    addFileExtensionAlias("int""rgb");
289    addFileExtensionAlias("inta", "rgb");
290    addFileExtensionAlias("bw",   "rgb");
291
292    addFileExtensionAlias("ivz""gz");
293    addFileExtensionAlias("ozg""gz");
294
295    addFileExtensionAlias("mag""dicom");
296    addFileExtensionAlias("ph",   "dicom");
297    addFileExtensionAlias("ima""dicom");
298    addFileExtensionAlias("dcm""dicom");
299    addFileExtensionAlias("dic""dicom");
300
301    addFileExtensionAlias("gl",   "glsl");
302    addFileExtensionAlias("vert", "glsl");
303    addFileExtensionAlias("frag", "glsl");
304    addFileExtensionAlias("geom", "glsl");
305
306
307#if defined(DARWIN_IMAGEIO)
308    addFileExtensionAlias("jpg""imageio");
309    addFileExtensionAlias("jpe""imageio");
310    addFileExtensionAlias("jpeg", "imageio");
311    addFileExtensionAlias("tif""imageio");
312    addFileExtensionAlias("tiff", "imageio");
313    addFileExtensionAlias("gif""imageio");
314    addFileExtensionAlias("png""imageio");
315    addFileExtensionAlias("psd""imageio");
316    addFileExtensionAlias("tga""imageio");
317
318#endif
319
320#if defined(USE_QTKIT)
321    addFileExtensionAlias("mov""QTKit");
322    addFileExtensionAlias("mp4""QTKit");
323    addFileExtensionAlias("mov""QTKit");
324    addFileExtensionAlias("mpg""QTKit");
325    addFileExtensionAlias("mpeg""QTKit");
326    addFileExtensionAlias("mpv""QTKit");
327    addFileExtensionAlias("m4v""QTKit");
328    addFileExtensionAlias("3gp""QTKit");
329    // Requires Perian
330    addFileExtensionAlias("avi""QTKit");
331    addFileExtensionAlias("xvid""QTKit");
332    // Requires Flip4Mac
333    addFileExtensionAlias("wmv""QTKit");
334#endif
335
336#if defined(DARWIN_QUICKTIME)
337
338    addFileExtensionAlias("jpg""qt");
339    addFileExtensionAlias("jpe""qt");
340    addFileExtensionAlias("jpeg", "qt");
341    addFileExtensionAlias("tif""qt");
342    addFileExtensionAlias("tiff", "qt");
343    addFileExtensionAlias("gif""qt");
344    addFileExtensionAlias("png""qt");
345    addFileExtensionAlias("psd""qt");
346    addFileExtensionAlias("tga""qt");
347    addFileExtensionAlias("flv""qt");
348    addFileExtensionAlias("dv",   "qt");
349   
350    #if !defined(USE_QTKIT)
351        addFileExtensionAlias("mov""qt");
352        addFileExtensionAlias("avi""qt");
353        addFileExtensionAlias("mpg""qt");
354        addFileExtensionAlias("mpv""qt");
355        addFileExtensionAlias("mp4""qt");
356        addFileExtensionAlias("m4v""qt");
357        addFileExtensionAlias("3gp""qt");
358        // Add QuickTime live support for OSX
359        addFileExtensionAlias("live", "qt");
360    #endif
361#else
362    addFileExtensionAlias("jpg""jpeg");
363    addFileExtensionAlias("jpe""jpeg");
364    addFileExtensionAlias("tif""tiff");
365
366    // really need to decide this at runtime...
367    #if defined(USE_XINE)
368
369        addFileExtensionAlias("mov""xine");
370        addFileExtensionAlias("mpg""xine");
371        addFileExtensionAlias("ogv""xine");
372        addFileExtensionAlias("mpv""xine");
373        addFileExtensionAlias("dv",   "xine");
374        addFileExtensionAlias("avi""xine");
375        addFileExtensionAlias("wmv""xine");
376        addFileExtensionAlias("flv""xine");
377    #endif
378
379    // support QuickTime for Windows
380    // Logic error here. It is possible for Apple to not define Quicktime and end up in
381    // this Quicktime for Windows block. So add an extra check to avoid QTKit clashes.
382    #if defined(USE_QUICKTIME) && !defined(USE_QTKIT)
383
384        addFileExtensionAlias("mov""qt");
385        addFileExtensionAlias("live", "qt");
386        addFileExtensionAlias("mpg""qt");
387        addFileExtensionAlias("avi""qt");
388    #endif
389#endif
390
391    #if defined(USE_AV_FOUNDATION)
392        addFileExtensionAlias("mov""AVFoundation");
393        addFileExtensionAlias("mpg""AVFoundation");
394        addFileExtensionAlias("mpv""AVFoundation");
395        addFileExtensionAlias("mp4""AVFoundation");
396        addFileExtensionAlias("m4v""AVFoundation");
397    #endif
398
399    // remove geo to lwo alias as the new Carbon Graphics GEO format
400    // also uses the .geo. It is still possible to load light wave .geo
401    // files via loading the lwo plugin explicitly and then doing a readNodeFile.
402    //addFileExtensionAlias("geo",  "lwo");
403    addFileExtensionAlias("lw",   "lwo");
404
405    #if defined(USE_VRML)
406        addFileExtensionAlias("wrl",   "vrml");
407    #elif defined(USE_INVENTOR)
408        addFileExtensionAlias("wrl",   "iv");
409    #endif
410
411    // add alias for the text/freetype plugin.
412    addFileExtensionAlias("ttf",    "freetype");  // true type
413    addFileExtensionAlias("ttc",    "freetype");  // true type
414    addFileExtensionAlias("cid",    "freetype");  // Postscript CID-Fonts
415    addFileExtensionAlias("cff",    "freetype");  // OpenType
416    addFileExtensionAlias("cef",    "freetype");  // OpenType
417    addFileExtensionAlias("fon",    "freetype");  // Windows bitmap fonts
418    addFileExtensionAlias("fnt",    "freetype");  // Windows bitmap fonts
419    addFileExtensionAlias("text3d", "freetype"); // use 3D Font instead of 2D Font
420
421    // wont't add type1 and type2 until resolve extension collision with Performer binary and ascii files.
422    // addFileExtensionAlias("pfb",   "freetype");  // type1 binary
423    // addFileExtensionAlias("pfa",   "freetype");  // type2 ascii
424
425
426    // portable bitmap, greyscale and colour/pixmap image formats
427    addFileExtensionAlias("pbm", "pnm");
428    addFileExtensionAlias("pgm", "pnm");
429    addFileExtensionAlias("ppm", "pnm");
430
431
432    // add revision file mappings
433    addFileExtensionAlias("added",    "revisions");
434    addFileExtensionAlias("removed""revisions");
435    addFileExtensionAlias("modified", "revisions");
436
437
438
439
440    // add built-in mime-type extension mappings
441    for( int i=0; ; i+=2 )
442    {
443        std::string mimeType = builtinMimeTypeExtMappings[i];
444        if ( mimeType.length() == 0 )
445            break;
446        addMimeTypeExtensionMapping( mimeType, builtinMimeTypeExtMappings[i+1] );
447    }
448
449    // register server protocols, so the curl can handle it, if necessary
450    registerProtocol("http");
451    registerProtocol("https");
452    registerProtocol("ftp");
453    registerProtocol("ftps");
454
455    _objectWrapperManager = new ObjectWrapperManager;
456    _deprecatedDotOsgWrapperManager = new DeprecatedDotOsgWrapperManager;
457}
458
459
460Registry::~Registry()
461{
462    destruct();
463}
464
465void Registry::destruct()
466{
467    // OSG_NOTICE<<"Registry::destruct()"<<std::endl;
468
469    // clean up the SharedStateManager
470    _sharedStateManager = 0;
471
472
473    // clean up the FileCache
474    _fileCache = 0;
475
476
477    // object cache clear needed here to prevent crash in unref() of
478    // the objects it contains when running the TXP plugin.
479    // Not sure why, but perhaps there is is something in a TXP plugin
480    // which deletes the data before its ref count hits zero, perhaps
481    // even some issue with objects be allocated by a plugin that is
482    // maintained after that plugin is deleted...  Robert Osfield, Jan 2004.
483    clearObjectCache();
484    clearArchiveCache();
485
486
487    // unload all the plugin before we finally destruct.
488    closeAllLibraries();
489}
490
491#include <iostream>
492
493void Registry::initDataFilePathList()
494{
495    FilePathList filepath;
496    //
497    // set up data file paths
498    //
499    char *ptr;
500
501    if( (ptr = getenv( "OSG_FILE_PATH" )) )
502    {
503        //OSG_NOTIFY(DEBUG_INFO) << "OSG_FILE_PATH("<<ptr<<")"<<std::endl;
504        convertStringPathIntoFilePathList(ptr, filepath);
505    }
506    else if( (ptr = getenv( "OSGFILEPATH" )) )
507    {
508        //OSG_NOTIFY(DEBUG_INFO) << "OSGFILEPATH("<<ptr<<")"<<std::endl;
509        convertStringPathIntoFilePathList(ptr, filepath);
510    }
511
512    osgDB::appendPlatformSpecificResourceFilePaths(filepath);
513    setDataFilePathList(filepath);
514
515}
516
517void Registry::setDataFilePathList(const std::string& paths)
518{
519    _dataFilePath.clear();
520    convertStringPathIntoFilePathList(paths,_dataFilePath);
521}
522
523void Registry::setLibraryFilePathList(const std::string& paths) { _libraryFilePath.clear(); convertStringPathIntoFilePathList(paths,_libraryFilePath); }
524
525
526
527void Registry::initLibraryFilePathList()
528{
529    //
530    // set up library paths
531    //
532    char* ptr;
533    if( (ptr = getenv( "OSG_LIBRARY_PATH")) )
534    {
535        //OSG_NOTIFY(DEBUG_INFO) << "OSG_LIBRARY_PATH("<<ptr<<")"<<std::endl;
536        setLibraryFilePathList(ptr);
537    }
538    else if( (ptr = getenv( "OSG_LD_LIBRARY_PATH")) )
539    {
540        //OSG_NOTIFY(DEBUG_INFO) << "OSG_LD_LIBRARY_PATH("<<ptr<<")"<<std::endl;
541        setLibraryFilePathList(ptr);
542    }
543
544    appendPlatformSpecificLibraryFilePaths(_libraryFilePath);
545
546}
547
548
549void Registry::readCommandLine(osg::ArgumentParser& arguments)
550{
551    // report the usage options.
552    if (arguments.getApplicationUsage())
553    {
554        arguments.getApplicationUsage()->addCommandLineOption("-l <library>","Load the plugin");
555        arguments.getApplicationUsage()->addCommandLineOption("-e <extension>","Load the plugin associated with handling files with specified extension");
556        arguments.getApplicationUsage()->addCommandLineOption("-O <option_string>","Provide an option string to reader/writers used to load databases");
557    }
558
559    std::string value;
560    while(arguments.read("-l",value))
561    {
562        loadLibrary(value);
563    }
564
565    while(arguments.read("-e",value))
566    {
567        std::string libName = createLibraryNameForExtension(value);
568        loadLibrary(libName);
569    }
570
571    while(arguments.read("-O",value))
572    {
573        setOptions(new Options(value));
574    }
575}
576
577void Registry::addReaderWriter(ReaderWriter* rw)
578{
579    if (rw==0L) return;
580
581    // OSG_NOTIFY(INFO) << "osg::Registry::addReaderWriter("<<rw->className()<<")"<< std::endl;
582
583    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
584
585    _rwList.push_back(rw);
586
587}
588
589
590void Registry::removeReaderWriter(ReaderWriter* rw)
591{
592    if (rw==0L) return;
593
594//    OSG_NOTIFY(INFO) << "osg::Registry::removeReaderWriter();"<< std::endl;
595
596    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
597
598    ReaderWriterList::iterator rwitr = std::find(_rwList.begin(),_rwList.end(),rw);
599    if (rwitr!=_rwList.end())
600    {
601        _rwList.erase(rwitr);
602    }
603
604}
605
606ImageProcessor* Registry::getImageProcessor()
607{
608    {
609        OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
610        if (!_ipList.empty())
611        {
612            return _ipList.front().get();
613        }
614    }
615    return getImageProcessorForExtension("nvtt");
616}
617
618ImageProcessor* Registry::getImageProcessorForExtension(const std::string& ext)
619{
620    {
621        OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
622        if (!_ipList.empty())
623        {
624            return _ipList.front().get();
625        }
626    }
627
628    std::string libraryName = createLibraryNameForExtension(ext);
629    OSG_NOTICE << "Now checking for plug-in "<<libraryName<< std::endl;
630    if (loadLibrary(libraryName)==LOADED)
631    {
632        OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
633        if (!_ipList.empty())
634        {
635            OSG_NOTICE << "Loaded plug-in "<<libraryName<<" and located ImageProcessor"<< std::endl;
636            return _ipList.front().get();
637        }
638    }
639    return 0;
640}
641
642void Registry::addImageProcessor(ImageProcessor* ip)
643{
644    if (ip==0L) return;
645
646    OSG_NOTIFY(NOTICE) << "osg::Registry::addImageProcessor("<<ip->className()<<")"<< std::endl;
647
648    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
649
650    _ipList.push_back(ip);
651
652}
653
654
655void Registry::removeImageProcessor(ImageProcessor* ip)
656{
657    if (ip==0L) return;
658
659    OSG_NOTIFY(NOTICE) << "osg::Registry::removeImageProcessor();"<< std::endl;
660
661    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
662
663    ImageProcessorList::iterator ipitr = std::find(_ipList.begin(),_ipList.end(),ip);
664    if (ipitr!=_ipList.end())
665    {
666        _ipList.erase(ipitr);
667    }
668
669}
670
671
672void Registry::addFileExtensionAlias(const std::string mapExt, const std::string toExt)
673{
674    _extAliasMap[mapExt] = toExt;
675}
676
677void Registry::addMimeTypeExtensionMapping(const std::string fromMimeType, const std::string toExt)
678{
679    _mimeTypeExtMap[fromMimeType] = toExt;
680}
681
682bool Registry::readPluginAliasConfigurationFile( const std::string& file )
683{
684    std::string fileName = osgDB::findDataFile( file );
685    if (fileName.empty())
686    {
687        OSG_NOTIFY( osg::WARN) << "Can't find plugin alias config file \"" << file << "\"." << std::endl;
688        return false;
689    }
690
691    osgDB::ifstream ifs;
692    ifs.open( fileName.c_str() );
693    if (!ifs.good())
694    {
695        OSG_NOTIFY( osg::WARN) << "Can't open plugin alias config file \"" << fileName << "\"." << std::endl;
696        return false;
697    }
698
699    int lineNum( 0 );
700    while (ifs.good())
701    {
702        std::string raw;
703        ++lineNum;
704        std::getline( ifs, raw );
705        std::string ln = trim( raw );
706        if (ln.empty()) continue;
707        if (ln[0] == '#') continue;
708
709        std::string::size_type spIdx = ln.find_first_of( " \t" );
710        if (spIdx == ln.npos)
711        {
712            // mapExt and toExt must be on the same line, separated by a space.
713            OSG_NOTIFY( osg::WARN) << file << ", line " << lineNum << ": Syntax error: missing space in \"" << raw << "\"." << std::endl;
714            continue;
715        }
716
717        const std::string mapExt = trim( ln.substr( 0, spIdx ) );
718        const std::string toExt = trim( ln.substr( spIdx+1 ) );
719        addFileExtensionAlias( mapExt, toExt );
720    }
721    return true;
722}
723
724std::string Registry::trim( const std::string& str )
725{
726    if (!str.size()) return str;
727    std::string::size_type first = str.find_first_not_of( " \t" );
728    std::string::size_type last = str.find_last_not_of( "  \t\r\n" );
729    if ((first==str.npos) || (last==str.npos)) return std::string( "" );
730    return str.substr( first, last-first+1 );
731}
732
733
734std::string Registry::createLibraryNameForFile(const std::string& fileName)
735{
736    return createLibraryNameForExtension(getFileExtension(fileName));
737}
738
739std::string Registry::createLibraryNameForExtension(const std::string& ext)
740{
741    std::string lowercase_ext;
742    for(std::string::const_iterator sitr=ext.begin();
743        sitr!=ext.end();
744        ++sitr)
745    {
746        lowercase_ext.push_back(tolower(*sitr));
747    }
748
749    ExtensionAliasMap::iterator itr=_extAliasMap.find(lowercase_ext);
750    if (itr!=_extAliasMap.end() && ext != itr->second) return createLibraryNameForExtension(itr->second);
751
752#if defined(OSG_JAVA_BUILD)
753    static std::string prepend = std::string("osgPlugins-")+std::string(osgGetVersion())+std::string("/java");
754#else
755    static std::string prepend = std::string("osgPlugins-")+std::string(osgGetVersion())+std::string("/");
756#endif
757
758#if defined(__CYGWIN__)
759    return prepend+"cygwin_"+"osgdb_"+lowercase_ext+OSG_LIBRARY_POSTFIX_WITH_QUOTES+".dll";
760#elif defined(__MINGW32__)
761    return prepend+"mingw_"+"osgdb_"+lowercase_ext+OSG_LIBRARY_POSTFIX_WITH_QUOTES+".dll";
762#elif defined(WIN32)
763    return prepend+"osgdb_"+lowercase_ext+OSG_LIBRARY_POSTFIX_WITH_QUOTES+".dll";
764#elif macintosh
765    return prepend+"osgdb_"+lowercase_ext+OSG_LIBRARY_POSTFIX_WITH_QUOTES;
766#else
767    return prepend+"osgdb_"+lowercase_ext+OSG_LIBRARY_POSTFIX_WITH_QUOTES+ADDQUOTES(OSG_PLUGIN_EXTENSION);
768#endif
769
770}
771
772std::string Registry::createLibraryNameForNodeKit(const std::string& name)
773{
774#if defined(__CYGWIN__)
775    return "cyg"+name+OSG_LIBRARY_POSTFIX_WITH_QUOTES+".dll";
776#elif defined(__MINGW32__)
777    return "lib"+name+OSG_LIBRARY_POSTFIX_WITH_QUOTES+".dll";
778#elif defined(WIN32)
779    return name+OSG_LIBRARY_POSTFIX_WITH_QUOTES+".dll";
780#elif macintosh
781    return name+OSG_LIBRARY_POSTFIX_WITH_QUOTES;
782#else
783    return "lib"+name+OSG_LIBRARY_POSTFIX_WITH_QUOTES + ADDQUOTES(OSG_PLUGIN_EXTENSION);
784#endif
785}
786
787Registry::LoadStatus Registry::loadLibrary(const std::string& fileName)
788{
789    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
790
791    DynamicLibraryList::iterator ditr = getLibraryItr(fileName);
792    if (ditr!=_dlList.end()) return PREVIOUSLY_LOADED;
793
794    _openingLibrary=true;
795
796    DynamicLibrary* dl = DynamicLibrary::loadLibrary(fileName);
797    _openingLibrary=false;
798
799    if (dl)
800    {
801        _dlList.push_back(dl);
802        return LOADED;
803    }
804    return NOT_LOADED;
805}
806
807
808bool Registry::closeLibrary(const std::string& fileName)
809{
810    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
811    DynamicLibraryList::iterator ditr = getLibraryItr(fileName);
812    if (ditr!=_dlList.end())
813    {
814        _dlList.erase(ditr);
815        return true;
816    }
817    return false;
818}
819
820void Registry::closeAllLibraries()
821{
822    // OSG_NOTICE<<"Registry::closeAllLibraries()"<<std::endl;
823    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
824    _dlList.clear();
825}
826
827Registry::DynamicLibraryList::iterator Registry::getLibraryItr(const std::string& fileName)
828{
829    DynamicLibraryList::iterator ditr = _dlList.begin();
830    for(;ditr!=_dlList.end();++ditr)
831    {
832        if ((*ditr)->getName()==fileName) return ditr;
833    }
834    return _dlList.end();
835}
836
837DynamicLibrary* Registry::getLibrary(const std::string& fileName)
838{
839    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
840    DynamicLibraryList::iterator ditr = getLibraryItr(fileName);
841    if (ditr!=_dlList.end()) return ditr->get();
842    else return NULL;
843}
844
845ReaderWriter* Registry::getReaderWriterForExtension(const std::string& ext)
846{
847    // record the existing reader writer.
848    std::set<ReaderWriter*> rwOriginal;
849
850    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_pluginMutex);
851
852    // first attemt one of the installed loaders
853    for(ReaderWriterList::iterator itr=_rwList.begin();
854        itr!=_rwList.end();
855        ++itr)
856    {
857        rwOriginal.insert(itr->get());
858        if((*itr)->acceptsExtension(ext)) return (*itr).get();
859    }
860
861    // now look for a plug-in to load the file.
862    std::string libraryName = createLibraryNameForExtension(ext);
863    OSG_NOTIFY(INFO) << "Now checking for plug-in "<<libraryName<< std::endl;
864    if (loadLibrary(libraryName)==LOADED)
865    {
866        for(ReaderWriterList::iterator itr=_rwList.begin();
867            itr!=_rwList.end();
868            ++itr)
869        {
870            if (rwOriginal.find(itr->get())==rwOriginal.end())
871            {
872                if((*itr)->acceptsExtension(ext)) return (*itr).get();
873            }
874        }
875    }
876
877    return NULL;
878
879}
880
881ReaderWriter* Registry::getReaderWriterForMimeType(const std::string& mimeType)
882{
883    MimeTypeExtensionMap::const_iterator i = _mimeTypeExtMap.find( mimeType );
884    return i != _mimeTypeExtMap.end()?
885        getReaderWriterForExtension( i->second ) :
886        NULL;
887}
888
889#if 0
890struct concrete_wrapper: basic_type_wrapper
891{
892    virtual ~concrete_wrapper() {}
893    concrete_wrapper(const osg::Object *myobj) : myobj_(myobj) {}
894    bool matches(const osg::Object *proto) const
895    {
896        return myobj_->isSameKindAs(proto);
897    }
898    const osg::Object *myobj_;
899};
900#endif
901
902
903
904struct Registry::ReadObjectFunctor : public Registry::ReadFunctor
905{
906    ReadObjectFunctor(const std::string& filename, const Options* options):ReadFunctor(filename,options) {}
907
908    virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw) const { return rw.readObject(_filename, _options); }
909    virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validObject(); }
910    virtual bool isValid(osg::Object* object) const { return object!=0;  }
911
912    virtual ReadFunctor* cloneType(const std::string& filename, const Options* options) const { return new ReadObjectFunctor(filename, options); }
913};
914
915struct Registry::ReadImageFunctor : public Registry::ReadFunctor
916{
917    ReadImageFunctor(const std::string& filename, const Options* options):ReadFunctor(filename,options) {}
918
919    virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw)const  { return rw.readImage(_filename, _options); }
920    virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validImage(); }
921    virtual bool isValid(osg::Object* object) const { return dynamic_cast<osg::Image*>(object)!=0;  }
922
923    virtual ReadFunctor* cloneType(const std::string& filename, const Options* options) const { return new ReadImageFunctor(filename, options); }
924};
925
926struct Registry::ReadHeightFieldFunctor : public Registry::ReadFunctor
927{
928    ReadHeightFieldFunctor(const std::string& filename, const Options* options):ReadFunctor(filename,options) {}
929
930    virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw) const { return rw.readHeightField(_filename, _options); }
931    virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validHeightField(); }
932    virtual bool isValid(osg::Object* object) const { return dynamic_cast<osg::HeightField*>(object)!=0;  }
933
934    virtual ReadFunctor* cloneType(const std::string& filename, const Options* options) const { return new ReadHeightFieldFunctor(filename, options); }
935};
936
937struct Registry::ReadNodeFunctor : public Registry::ReadFunctor
938{
939    ReadNodeFunctor(const std::string& filename, const Options* options):ReadFunctor(filename,options) {}
940
941    virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw) const { return rw.readNode(_filename, _options); }
942    virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validNode(); }
943    virtual bool isValid(osg::Object* object) const { return dynamic_cast<osg::Node*>(object)!=0;  }
944
945    virtual ReadFunctor* cloneType(const std::string& filename, const Options* options) const { return new ReadNodeFunctor(filename, options); }
946};
947
948struct Registry::ReadArchiveFunctor : public Registry::ReadFunctor
949{
950    ReadArchiveFunctor(const std::string& filename, ReaderWriter::ArchiveStatus status, unsigned int indexBlockSizeHint, const Options* options):
951        ReadFunctor(filename,options),
952        _status(status),
953        _indexBlockSizeHint(indexBlockSizeHint) {}
954
955    ReaderWriter::ArchiveStatus _status;
956    unsigned int _indexBlockSizeHint;
957
958    virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw) const { return rw.openArchive(_filename, _status, _indexBlockSizeHint, _options); }
959    virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validArchive(); }
960    virtual bool isValid(osg::Object* object) const { return dynamic_cast<osgDB::Archive*>(object)!=0;  }
961
962    virtual ReadFunctor* cloneType(const std::string& filename, const Options* options) const { return new ReadArchiveFunctor(filename, _status, _indexBlockSizeHint, options); }
963};
964
965struct Registry::ReadShaderFunctor : public Registry::ReadFunctor
966{
967    ReadShaderFunctor(const std::string& filename, const Options* options):ReadFunctor(filename,options) {}
968
969    virtual ReaderWriter::ReadResult doRead(ReaderWriter& rw)const  { return rw.readShader(_filename, _options); }
970    virtual bool isValid(ReaderWriter::ReadResult& readResult) const { return readResult.validShader(); }
971    virtual bool isValid(osg::Object* object) const { return dynamic_cast<osg::Shader*>(object)!=0;  }
972
973    virtual ReadFunctor* cloneType(const std::string& filename, const Options* options) const { return new ReadShaderFunctor(filename, options); }
974};
975
976void Registry::addArchiveExtension(const std::string ext)
977{
978    for(ArchiveExtensionList::iterator aitr=_archiveExtList.begin();
979        aitr!=_archiveExtList.end();
980        ++aitr)
981    {
982        if ( (*aitr) == ext)   // extension already in archive extension list
983            return;
984    }
985    _archiveExtList.push_back(ext);
986}
987
988std::string Registry::findDataFileImplementation(const std::string& filename, const Options* options, CaseSensitivity caseSensitivity)
989{
990    if (filename.empty()) return filename;
991
992    // if data file contains a server address then we can't find it in local directories so return empty string.
993    if (containsServerAddress(filename)) return std::string();
994
995    bool absolutePath = osgDB::isAbsolutePath(filename);
996
997    if (absolutePath && fileExists(filename))
998    {
999        OSG_DEBUG << "FindFileInPath(" << filename << "): returning " << filename << std::endl;
1000        return filename;
1001    }
1002
1003    std::string fileFound;
1004    bool pathsContainsCurrentWorkingDirectory = false;
1005
1006    if (options && !options->getDatabasePathList().empty())
1007    {
1008        fileFound = findFileInPath(filename, options->getDatabasePathList(), caseSensitivity);
1009        if (!fileFound.empty()) return fileFound;
1010
1011        if (osgDB::containsCurrentWorkingDirectoryReference(options->getDatabasePathList()))
1012        {
1013            pathsContainsCurrentWorkingDirectory = true;
1014        }
1015
1016    }
1017
1018    const FilePathList& filepaths = Registry::instance()->getDataFilePathList();
1019    if (!filepaths.empty())
1020    {
1021        fileFound = findFileInPath(filename, filepaths, caseSensitivity);
1022        if (!fileFound.empty()) return fileFound;
1023
1024        if (!pathsContainsCurrentWorkingDirectory && osgDB::containsCurrentWorkingDirectoryReference(filepaths))
1025        {
1026            pathsContainsCurrentWorkingDirectory = true;
1027        }
1028    }
1029
1030    if (!absolutePath && !pathsContainsCurrentWorkingDirectory)
1031    {
1032        // check current working directory
1033        if (fileExists(filename))
1034        {
1035            return filename;
1036        }
1037    }
1038
1039
1040    // if a directory is included in the filename, get just the (simple) filename itself and try that
1041    std::string simpleFileName = getSimpleFileName(filename);
1042    if (simpleFileName!=filename)
1043    {
1044
1045        if(fileExists(simpleFileName))
1046        {
1047            OSG_DEBUG << "FindFileInPath(" << filename << "): returning " << filename << std::endl;
1048            return simpleFileName;
1049        }
1050
1051        if (options && !options->getDatabasePathList().empty())
1052        {
1053            fileFound = findFileInPath(simpleFileName, options->getDatabasePathList(), caseSensitivity);
1054            if (!fileFound.empty()) return fileFound;
1055        }
1056
1057        if (!filepaths.empty())
1058        {
1059            fileFound = findFileInPath(simpleFileName, filepaths,caseSensitivity);
1060            if (!fileFound.empty()) return fileFound;
1061        }
1062
1063    }
1064
1065    // return empty string.
1066    return std::string();
1067}
1068
1069std::string Registry::findLibraryFileImplementation(const std::string& filename, const Options* options, CaseSensitivity caseSensitivity)
1070{
1071    if (filename.empty())
1072        return filename;
1073
1074    const FilePathList& filepath = Registry::instance()->getLibraryFilePathList();
1075
1076    std::string fileFound = findFileInPath(filename, filepath,caseSensitivity);
1077    if (!fileFound.empty())
1078        return fileFound;
1079
1080    if(fileExists(filename))
1081    {
1082        OSG_DEBUG << "FindFileInPath(" << filename << "): returning " << filename << std::endl;
1083        return filename;
1084    }
1085
1086    // if a directory is included in the filename, get just the (simple) filename itself and try that
1087    std::string simpleFileName = getSimpleFileName(filename);
1088    if (simpleFileName!=filename)
1089    {
1090        std::string fileFound = findFileInPath(simpleFileName, filepath,caseSensitivity);
1091        if (!fileFound.empty()) return fileFound;
1092    }
1093
1094    // failed return empty string.
1095    return std::string();
1096}
1097
1098
1099
1100ReaderWriter::ReadResult Registry::read(const ReadFunctor& readFunctor)
1101{
1102    for(ArchiveExtensionList::iterator aitr=_archiveExtList.begin();
1103        aitr!=_archiveExtList.end();
1104        ++aitr)
1105    {
1106        std::string archiveExtension = "." + (*aitr);
1107
1108        std::string::size_type positionArchive = readFunctor._filename.find(archiveExtension+'/');
1109        if (positionArchive==std::string::npos) positionArchive = readFunctor._filename.find(archiveExtension+'\\');
1110        if (positionArchive!=std::string::npos)
1111        {
1112            std::string::size_type endArchive = positionArchive + archiveExtension.length();
1113            std::string archiveName( readFunctor._filename.substr(0,endArchive));
1114            std::string fileName(readFunctor._filename.substr(endArchive+1,std::string::npos));
1115            OSG_INFO<<"Contains archive : "<<readFunctor._filename<<std::endl;
1116            OSG_INFO<<"         archive : "<<archiveName<<std::endl;
1117            OSG_INFO<<"         filename : "<<fileName<<std::endl;
1118
1119            ReaderWriter::ReadResult result = openArchiveImplementation(archiveName,ReaderWriter::READ, 4096, readFunctor._options);
1120
1121            if (!result.validArchive()) return result;
1122
1123            osgDB::Archive* archive = result.getArchive();
1124
1125            //if valid options were passed through the read functor clone them
1126            //otherwise make new options
1127            osg::ref_ptr<osgDB::ReaderWriter::Options> options = readFunctor._options ?
1128                readFunctor._options->cloneOptions() :
1129                new osgDB::ReaderWriter::Options;
1130
1131            options->setDatabasePath(archiveName);
1132
1133            std::auto_ptr<ReadFunctor> rf(readFunctor.cloneType(fileName, options.get()));
1134
1135            result = rf->doRead(*archive);
1136
1137            if (rf->isValid(result))
1138            {
1139                OSG_INFO<<"Read object from archive"<<std::endl;
1140                return result;
1141            }
1142            OSG_INFO<<"Failed to read object from archive"<<std::endl;
1143        }
1144    }
1145
1146    // record the errors reported by readerwriters.
1147    typedef std::vector<ReaderWriter::ReadResult> Results;
1148    Results results;
1149
1150    // first attempt to load the file from existing ReaderWriter's
1151    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
1152    for(;itr.valid();++itr)
1153    {
1154        ReaderWriter::ReadResult rr = readFunctor.doRead(*itr);
1155        if (readFunctor.isValid(rr)) return rr;
1156        else results.push_back(rr);
1157    }
1158
1159    // check loaded archives.
1160    AvailableArchiveIterator aaitr(_archiveCache, _archiveCacheMutex);
1161    for(;aaitr.valid();++aaitr)
1162    {
1163        ReaderWriter::ReadResult rr = readFunctor.doRead(*aaitr);
1164        if (readFunctor.isValid(rr)) return rr;
1165        else
1166        {
1167            // don't pass on FILE_NOT_FOUND results as we don't want to prevent non archive plugins that haven't been
1168            // loaded yet from getting a chance to test for the presence of the file.
1169            if (rr.status()!=ReaderWriter::ReadResult::FILE_NOT_FOUND) results.push_back(rr);
1170        }
1171    }
1172
1173
1174    if (!results.empty())
1175    {
1176        unsigned int num_FILE_NOT_HANDLED = 0;
1177        unsigned int num_FILE_NOT_FOUND = 0;
1178        unsigned int num_ERROR_IN_READING_FILE = 0;
1179
1180        Results::iterator ritr;
1181        for(ritr=results.begin();
1182            ritr!=results.end();
1183            ++ritr)
1184        {
1185            if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_HANDLED) ++num_FILE_NOT_HANDLED;
1186            else if (ritr->status()==ReaderWriter::ReadResult::NOT_IMPLEMENTED) ++num_FILE_NOT_HANDLED;//Freetype and others
1187            else if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_FOUND) ++num_FILE_NOT_FOUND;
1188            else if (ritr->status()==ReaderWriter::ReadResult::ERROR_IN_READING_FILE) ++num_ERROR_IN_READING_FILE;
1189        }
1190
1191        if (num_FILE_NOT_HANDLED!=results.size())
1192        {
1193            for(ritr=results.begin(); ritr!=results.end(); ++ritr)
1194            {
1195                if (ritr->status()==ReaderWriter::ReadResult::ERROR_IN_READING_FILE)
1196                {
1197                    // OSG_NOTICE<<"Warning: error reading file \""<<readFunctor._filename<<"\""<<std::endl;
1198                    return *ritr;
1199                }
1200            }
1201
1202            //If the filename is a URL, don't return FILE_NOT_FOUND until the CURL plugin is given a chance
1203            if (!osgDB::containsServerAddress(readFunctor._filename))
1204            {
1205                for(ritr=results.begin(); ritr!=results.end(); ++ritr)
1206                {
1207                    if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_FOUND)
1208                    {
1209                        //OSG_NOTICE<<"Warning: could not find file \""<<readFunctor._filename<<"\""<<std::endl;
1210                        return *ritr;
1211                    }
1212                }
1213            }
1214        }
1215    }
1216
1217    results.clear();
1218
1219    // now look for a plug-in to load the file.
1220    std::string libraryName = createLibraryNameForFile(readFunctor._filename);
1221    if (loadLibrary(libraryName)!=NOT_LOADED)
1222    {
1223        for(;itr.valid();++itr)
1224        {
1225            ReaderWriter::ReadResult rr = readFunctor.doRead(*itr);
1226            if (readFunctor.isValid(rr)) return rr;
1227            else results.push_back(rr);
1228        }
1229    }
1230
1231    //If the filename contains a server address and wasn't loaded by any of the plugins, try to use the CURL plugin
1232    //to download the file and use the stream reading functionality of the plugins to load the file
1233    if (containsServerAddress(readFunctor._filename))
1234    {
1235        ReaderWriter* rw = getReaderWriterForExtension("curl");
1236        if (rw)
1237        {
1238            return readFunctor.doRead(*rw);
1239        }
1240        else
1241        {
1242            return  ReaderWriter::ReadResult("Warning: Could not find the .curl plugin to read from server.");
1243        }
1244    }
1245
1246    if (!results.empty())
1247    {
1248        unsigned int num_FILE_NOT_HANDLED = 0;
1249        unsigned int num_FILE_NOT_FOUND = 0;
1250        unsigned int num_ERROR_IN_READING_FILE = 0;
1251
1252        Results::iterator ritr;
1253        for(ritr=results.begin();
1254            ritr!=results.end();
1255            ++ritr)
1256        {
1257            if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_HANDLED) ++num_FILE_NOT_HANDLED;
1258            else if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_FOUND) ++num_FILE_NOT_FOUND;
1259            else if (ritr->status()==ReaderWriter::ReadResult::ERROR_IN_READING_FILE) ++num_ERROR_IN_READING_FILE;
1260        }
1261
1262        if (num_FILE_NOT_HANDLED!=results.size())
1263        {
1264            for(ritr=results.begin(); ritr!=results.end(); ++ritr)
1265            {
1266                if (ritr->status()==ReaderWriter::ReadResult::ERROR_IN_READING_FILE)
1267                {
1268                    // OSG_NOTICE<<"Warning: error reading file \""<<readFunctor._filename<<"\""<<std::endl;
1269                    return *ritr;
1270                }
1271            }
1272
1273            for(ritr=results.begin(); ritr!=results.end(); ++ritr)
1274            {
1275                if (ritr->status()==ReaderWriter::ReadResult::FILE_NOT_FOUND)
1276                {
1277                    // OSG_NOTICE<<"Warning: could not find file \""<<readFunctor._filename<<"\""<<std::endl;
1278                    return *ritr;
1279                }
1280            }
1281        }
1282    }
1283    else
1284    {
1285        return ReaderWriter::ReadResult("Warning: Could not find plugin to read objects from file \""+readFunctor._filename+"\".");
1286    }
1287
1288    return results.front();
1289}
1290
1291ReaderWriter::ReadResult Registry::readImplementation(const ReadFunctor& readFunctor,Options::CacheHintOptions cacheHint)
1292{
1293    std::string file(readFunctor._filename);
1294
1295    bool useObjectCache=false;
1296    //Note CACHE_ARCHIVES has a different object that it caches to so it will never be used here
1297    if (cacheHint!=Options::CACHE_ARCHIVES)
1298    {
1299        const Options* options=readFunctor._options;
1300        useObjectCache=options ? (options->getObjectCacheHint()&cacheHint)!=0: false;
1301    }
1302    if (useObjectCache)
1303    {
1304        // search for entry in the object cache.
1305        {
1306            OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
1307            ObjectCache::iterator oitr=_objectCache.find(file);
1308            if (oitr!=_objectCache.end())
1309            {
1310                OSG_NOTIFY(INFO)<<"returning cached instanced of "<<file<<std::endl;
1311                if (readFunctor.isValid(oitr->second.first.get())) return ReaderWriter::ReadResult(oitr->second.first.get(), ReaderWriter::ReadResult::FILE_LOADED_FROM_CACHE);
1312                else return ReaderWriter::ReadResult("Error file does not contain an osg::Object");
1313            }
1314        }
1315
1316        ReaderWriter::ReadResult rr = read(readFunctor);
1317        if (rr.validObject())
1318        {
1319            // update cache with new entry.
1320            OSG_NOTIFY(INFO)<<"Adding to object cache "<<file<<std::endl;
1321            addEntryToObjectCache(file,rr.getObject());
1322        }
1323        else
1324        {
1325            OSG_NOTIFY(INFO)<<"No valid object found for "<<file<<std::endl;
1326        }
1327
1328        return rr;
1329
1330    }
1331    else
1332    {
1333        ReaderWriter::ReadResult rr = read(readFunctor);
1334        return rr;
1335    }
1336}
1337
1338
1339ReaderWriter::ReadResult Registry::openArchiveImplementation(const std::string& fileName, ReaderWriter::ArchiveStatus status, unsigned int indexBlockSizeHint, const Options* options)
1340{
1341    osg::ref_ptr<osgDB::Archive> archive = getRefFromArchiveCache(fileName);
1342    if (archive.valid()) return archive.get();
1343
1344    ReaderWriter::ReadResult result = readImplementation(ReadArchiveFunctor(fileName, status, indexBlockSizeHint, options),Options::CACHE_ARCHIVES);
1345
1346    // default to using caching archive if no options structure provided, but if options are provided use archives
1347    // only if supplied.
1348    if (result.validArchive() &&
1349        (!options || (options->getObjectCacheHint() & Options::CACHE_ARCHIVES)) )
1350    {
1351        addToArchiveCache(fileName,result.getArchive());
1352    }
1353    return result;
1354}
1355
1356
1357ReaderWriter::ReadResult Registry::readObjectImplementation(const std::string& fileName,const Options* options)
1358{
1359    return readImplementation(ReadObjectFunctor(fileName, options),Options::CACHE_OBJECTS);
1360}
1361
1362ReaderWriter::WriteResult Registry::writeObjectImplementation(const Object& obj,const std::string& fileName,const Options* options)
1363{
1364    // record the errors reported by readerwriters.
1365    typedef std::vector<ReaderWriter::WriteResult> Results;
1366    Results results;
1367
1368    // first attempt to load the file from existing ReaderWriter's
1369    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
1370    for(;itr.valid();++itr)
1371    {
1372        ReaderWriter::WriteResult rr = itr->writeObject(obj,fileName,options);
1373        if (rr.success()) return rr;
1374        else results.push_back(rr);
1375    }
1376
1377    // now look for a plug-in to save the file.
1378    std::string libraryName = createLibraryNameForFile(fileName);
1379    if (loadLibrary(libraryName)==LOADED)
1380    {
1381        for(;itr.valid();++itr)
1382        {
1383            ReaderWriter::WriteResult rr = itr->writeObject(obj,fileName,options);
1384            if (rr.success()) return rr;
1385            else results.push_back(rr);
1386        }
1387    }
1388
1389    if (results.empty())
1390    {
1391        return ReaderWriter::WriteResult("Warning: Could not find plugin to write objects to file \""+fileName+"\".");
1392    }
1393
1394    if (results.front().message().empty())
1395    {
1396        switch(results.front().status())
1397        {
1398            case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): results.front().message() = "Warning: Write to \""+fileName+"\" not supported."; break;
1399            case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): results.front().message() = "Warning: Error in writing to \""+fileName+"\"."; break;
1400            default: break;
1401        }
1402    }
1403
1404    return results.front();
1405}
1406
1407
1408
1409ReaderWriter::ReadResult Registry::readImageImplementation(const std::string& fileName,const Options* options)
1410{
1411    return readImplementation(ReadImageFunctor(fileName, options),Options::CACHE_IMAGES);
1412}
1413
1414ReaderWriter::WriteResult Registry::writeImageImplementation(const Image& image,const std::string& fileName,const Options* options)
1415{
1416    // record the errors reported by readerwriters.
1417    typedef std::vector<ReaderWriter::WriteResult> Results;
1418    Results results;
1419
1420    // first attempt to load the file from existing ReaderWriter's
1421    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
1422    for(;itr.valid();++itr)
1423    {
1424        ReaderWriter::WriteResult rr = itr->writeImage(image,fileName,options);
1425        if (rr.success()) return rr;
1426        else results.push_back(rr);
1427    }
1428
1429    results.clear();
1430
1431    // now look for a plug-in to save the file.
1432    std::string libraryName = createLibraryNameForFile(fileName);
1433    if (loadLibrary(libraryName)==LOADED)
1434    {
1435        for(;itr.valid();++itr)
1436        {
1437            ReaderWriter::WriteResult rr = itr->writeImage(image,fileName,options);
1438            if (rr.success()) return rr;
1439            else results.push_back(rr);
1440        }
1441    }
1442
1443    if (results.empty())
1444    {
1445        return ReaderWriter::WriteResult("Warning: Could not find plugin to write image to file \""+fileName+"\".");
1446    }
1447
1448    if (results.front().message().empty())
1449    {
1450        switch(results.front().status())
1451        {
1452            case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): results.front().message() = "Warning: Write to \""+fileName+"\" not supported."; break;
1453            case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): results.front().message() = "Warning: Error in writing to \""+fileName+"\"."; break;
1454            default: break;
1455        }
1456    }
1457
1458    return results.front();
1459}
1460
1461
1462ReaderWriter::ReadResult Registry::readHeightFieldImplementation(const std::string& fileName,const Options* options)
1463{
1464    return readImplementation(ReadHeightFieldFunctor(fileName, options),Options::CACHE_HEIGHTFIELDS);
1465}
1466
1467ReaderWriter::WriteResult Registry::writeHeightFieldImplementation(const HeightField& HeightField,const std::string& fileName,const Options* options)
1468{
1469    // record the errors reported by readerwriters.
1470    typedef std::vector<ReaderWriter::WriteResult> Results;
1471    Results results;
1472
1473    // first attempt to load the file from existing ReaderWriter's
1474    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
1475    for(;itr.valid();++itr)
1476    {
1477        ReaderWriter::WriteResult rr = itr->writeHeightField(HeightField,fileName,options);
1478        if (rr.success()) return rr;
1479        else results.push_back(rr);
1480    }
1481
1482    results.clear();
1483
1484    // now look for a plug-in to save the file.
1485    std::string libraryName = createLibraryNameForFile(fileName);
1486    if (loadLibrary(libraryName)==LOADED)
1487    {
1488        for(;itr.valid();++itr)
1489        {
1490            ReaderWriter::WriteResult rr = itr->writeHeightField(HeightField,fileName,options);
1491            if (rr.success()) return rr;
1492            else results.push_back(rr);
1493        }
1494    }
1495
1496    if (results.empty())
1497    {
1498        return ReaderWriter::WriteResult("Warning: Could not find plugin to write HeightField to file \""+fileName+"\".");
1499    }
1500
1501    if (results.front().message().empty())
1502    {
1503        switch(results.front().status())
1504        {
1505            case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): results.front().message() = "Warning: Write to \""+fileName+"\" not supported."; break;
1506            case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): results.front().message() = "Warning: Error in writing to \""+fileName+"\"."; break;
1507            default: break;
1508        }
1509    }
1510
1511    return results.front();
1512}
1513
1514
1515ReaderWriter::ReadResult Registry::readNodeImplementation(const std::string& fileName,const Options* options)
1516{
1517#if 0
1518
1519    osg::Timer_t startTick = osg::Timer::instance()->tick();
1520    ReaderWriter::ReadResult result = readImplementation(ReadNodeFunctor(fileName, options),Options::CACHE_NODES);
1521    osg::Timer_t endTick = osg::Timer::instance()->tick();
1522    OSG_NOTICE<<"time to load "<<fileName<<" "<<osg::Timer::instance()->delta_m(startTick, endTick)<<"ms"<<std::endl;
1523    return result;
1524
1525#else
1526
1527    return readImplementation(ReadNodeFunctor(fileName, options),Options::CACHE_NODES);
1528
1529#endif
1530}
1531
1532ReaderWriter::WriteResult Registry::writeNodeImplementation(const Node& node,const std::string& fileName,const Options* options)
1533{
1534    // record the errors reported by readerwriters.
1535    typedef std::vector<ReaderWriter::WriteResult> Results;
1536    Results results;
1537
1538    // first attempt to write the file from existing ReaderWriter's
1539    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
1540    for(;itr.valid();++itr)
1541    {
1542        ReaderWriter::WriteResult rr = itr->writeNode(node,fileName,options);
1543        if (rr.success()) return rr;
1544        else results.push_back(rr);
1545    }
1546
1547    results.clear();
1548
1549    // now look for a plug-in to save the file.
1550    std::string libraryName = createLibraryNameForFile(fileName);
1551
1552
1553    if (loadLibrary(libraryName)==LOADED)
1554    {
1555        for(;itr.valid();++itr)
1556        {
1557            ReaderWriter::WriteResult rr = itr->writeNode(node,fileName,options);
1558
1559            if (rr.success()) return rr;
1560            else results.push_back(rr);
1561        }
1562    }
1563
1564    if (results.empty())
1565    {
1566        return ReaderWriter::WriteResult("Warning: Could not find plugin to write nodes to file \""+fileName+"\".");
1567    }
1568
1569    if (results.front().message().empty())
1570    {
1571        switch(results.front().status())
1572        {
1573            case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): results.front().message() = "Warning: Write to \""+fileName+"\" not supported."; break;
1574            case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): results.front().message() = "Warning: Error in writing to \""+fileName+"\"."; break;
1575            default: break;
1576        }
1577    }
1578
1579    return results.front();
1580}
1581
1582ReaderWriter::ReadResult Registry::readShaderImplementation(const std::string& fileName,const Options* options)
1583{
1584    return readImplementation(ReadShaderFunctor(fileName, options),Options::CACHE_SHADERS);
1585}
1586
1587ReaderWriter::WriteResult Registry::writeShaderImplementation(const Shader& shader,const std::string& fileName,const Options* options)
1588{
1589    // record the errors reported by readerwriters.
1590    typedef std::vector<ReaderWriter::WriteResult> Results;
1591    Results results;
1592
1593    // first attempt to load the file from existing ReaderWriter's
1594    AvailableReaderWriterIterator itr(_rwList, _pluginMutex);
1595    for(;itr.valid();++itr)
1596    {
1597        ReaderWriter::WriteResult rr = itr->writeShader(shader,fileName,options);
1598        if (rr.success()) return rr;
1599        else results.push_back(rr);
1600    }
1601
1602    results.clear();
1603
1604    // now look for a plug-in to save the file.
1605    std::string libraryName = createLibraryNameForFile(fileName);
1606    if (loadLibrary(libraryName)==LOADED)
1607    {
1608        for(;itr.valid();++itr)
1609        {
1610            ReaderWriter::WriteResult rr = itr->writeShader(shader,fileName,options);
1611            if (rr.success()) return rr;
1612            else results.push_back(rr);
1613        }
1614    }
1615
1616    if (results.empty())
1617    {
1618        return ReaderWriter::WriteResult("Warning: Could not find plugin to write shader to file \""+fileName+"\".");
1619    }
1620
1621    if (results.front().message().empty())
1622    {
1623        switch(results.front().status())
1624        {
1625            case(ReaderWriter::WriteResult::FILE_NOT_HANDLED): results.front().message() = "Warning: Write to \""+fileName+"\" not supported."; break;
1626            case(ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE): results.front().message() = "Warning: Error in writing to \""+fileName+"\"."; break;
1627            default: break;
1628        }
1629    }
1630
1631    return results.front();
1632}
1633
1634void Registry::addEntryToObjectCache(const std::string& filename, osg::Object* object, double timestamp)
1635{
1636    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
1637    _objectCache[filename]=ObjectTimeStampPair(object,timestamp);
1638}
1639
1640osg::Object* Registry::getFromObjectCache(const std::string& fileName)
1641{
1642    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
1643    ObjectCache::iterator itr = _objectCache.find(fileName);
1644    if (itr!=_objectCache.end()) return itr->second.first.get();
1645    else return 0;
1646}
1647
1648osg::ref_ptr<osg::Object> Registry::getRefFromObjectCache(const std::string& fileName)
1649{
1650    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
1651    ObjectCache::iterator itr = _objectCache.find(fileName);
1652    if (itr!=_objectCache.end()) return itr->second.first;
1653    else return 0;
1654}
1655
1656void Registry::updateTimeStampOfObjectsInCacheWithExternalReferences(const osg::FrameStamp& frameStamp)
1657{
1658    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
1659
1660    // look for objects with external references and update their time stamp.
1661    for(ObjectCache::iterator itr=_objectCache.begin();
1662        itr!=_objectCache.end();
1663        ++itr)
1664    {
1665        // if ref count is greater the 1 the object has an external reference.
1666        if (itr->second.first->referenceCount()>1)
1667        {
1668            // so update it time stamp.
1669            itr->second.second = frameStamp.getReferenceTime();
1670        }
1671    }
1672}
1673
1674void Registry::removeExpiredObjectsInCache(const osg::FrameStamp& frameStamp)
1675{
1676    double expiryTime = frameStamp.getReferenceTime() - _expiryDelay;
1677
1678    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
1679
1680    // Remove expired entries from object cache
1681    ObjectCache::iterator oitr = _objectCache.begin();
1682    while(oitr != _objectCache.end())
1683    {
1684        if (oitr->second.second<=expiryTime)
1685        {
1686            _objectCache.erase(oitr++);
1687        }
1688        else
1689        {
1690            ++oitr;
1691        }
1692    }
1693}
1694
1695void Registry::removeFromObjectCache(const std::string& fileName)
1696{
1697    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
1698    ObjectCache::iterator itr = _objectCache.find(fileName);
1699    if (itr!=_objectCache.end()) _objectCache.erase(itr);
1700}
1701
1702void Registry::clearObjectCache()
1703{
1704    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
1705    _objectCache.clear();
1706}
1707
1708void Registry::addToArchiveCache(const std::string& fileName, osgDB::Archive* archive)
1709{
1710    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_archiveCacheMutex);
1711    _archiveCache[fileName] = archive;
1712}
1713
1714/** Remove archive from cache.*/
1715void Registry::removeFromArchiveCache(const std::string& fileName)
1716{
1717    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_archiveCacheMutex);
1718    ArchiveCache::iterator itr = _archiveCache.find(fileName);
1719    if (itr!=_archiveCache.end())
1720    {
1721        _archiveCache.erase(itr);
1722    }
1723}
1724
1725osgDB::Archive* Registry::getFromArchiveCache(const std::string& fileName)
1726{
1727    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_archiveCacheMutex);
1728    ArchiveCache::iterator itr = _archiveCache.find(fileName);
1729    if (itr!=_archiveCache.end()) return itr->second.get();
1730    else return 0;
1731}
1732
1733osg::ref_ptr<osgDB::Archive> Registry::getRefFromArchiveCache(const std::string& fileName)
1734{
1735    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_archiveCacheMutex);
1736    ArchiveCache::iterator itr = _archiveCache.find(fileName);
1737    if (itr!=_archiveCache.end()) return itr->second;
1738    else return 0;
1739}
1740
1741void Registry::clearArchiveCache()
1742{
1743    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_archiveCacheMutex);
1744    _archiveCache.clear();
1745}
1746
1747void Registry::releaseGLObjects(osg::State* state)
1748{
1749    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
1750
1751    for(ObjectCache::iterator itr = _objectCache.begin();
1752        itr != _objectCache.end();
1753        ++itr)
1754    {
1755        osg::Object* object = itr->second.first.get();
1756        object->releaseGLObjects(state);
1757    }
1758
1759    if (_sharedStateManager.valid())
1760    {
1761      _sharedStateManager->releaseGLObjects( state );
1762    }
1763}
1764
1765SharedStateManager* Registry::getOrCreateSharedStateManager()
1766{
1767    if (!_sharedStateManager) _sharedStateManager = new SharedStateManager;
1768
1769    return _sharedStateManager.get();
1770}
1771
1772
1773void Registry::registerProtocol(const std::string& protocol)
1774{
1775    _registeredProtocols.insert( convertToLowerCase(protocol) );
1776}
1777
1778bool Registry::isProtocolRegistered(const std::string& protocol)
1779{
1780    return (_registeredProtocols.find( convertToLowerCase(protocol) ) != _registeredProtocols.end());
1781}
Note: See TracBrowser for help on using the browser.