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

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

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

  • 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.