]> git.mxchange.org Git - simgear.git/blob - simgear/scene/model/ModelRegistry.hxx
e14292680f9d4808c58eaf9db4b8a183874d5994
[simgear.git] / simgear / scene / model / ModelRegistry.hxx
1 // ModelRegistry.hxx -- interface to the OSG model registry
2 //
3 // Copyright (C) 2005-2007 Mathias Froehlich 
4 // Copyright (C) 2007  Tim Moore <timoore@redhat.com>
5 //
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License as
8 // published by the Free Software Foundation; either version 2 of the
9 // License, or (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful, but
12 // WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 #ifndef _SG_MODELREGISTRY_HXX
20 #define _SG_MODELREGISTRY_HXX 1
21
22 #include <OpenThreads/ReentrantMutex>
23
24 #include <osg/ref_ptr>
25 #include <osg/Node>
26 #include <osgDB/FileUtils>
27 #include <osgDB/FileNameUtils>
28 #include <osgDB/ReaderWriter>
29 #include <osgDB/Registry>
30
31 #include <simgear/compiler.h>
32
33 #include STL_STRING
34 #include <map>
35
36 // Class to register per file extension read callbacks with the OSG
37 // registry, mostly to control caching and post load optimization /
38 // copying that happens above the level of the ReaderWriter.
39 namespace simgear
40 {
41
42 // Different caching and optimization strategies are needed for
43 // different file types. Most loaded files should be optimized and the
44 // optimized version should be cached. When an .osg file is
45 // substituted for another, it is assumed to be optimized already but
46 // it should be cached too (under the name of the original?). .stg
47 // files should not be cached (that's the pager's job) but the files
48 // it causes to be loaded should be. .btg files are already optimized
49 // and shouldn't be cached.
50 //
51 // Complicating this is the effect that removing CACHE_NODES has from
52 // the ReaderWriter options: it switches the object cache with an
53 // empty one, so that's not an option for the files that could be
54 // loaded from a .stg file. So, we'll let
55 // Registry::readNodeImplementation cache a loaded file and then add
56 // the optimized version to the cache ourselves, replacing the
57 // original subgraph.
58 //
59 // To support all these options with a minimum of duplication, the
60 // readNode function is specified as a template with a bunch of
61 // pluggable (and predefined) policies.
62 template <typename ProcessPolicy, typename CachePolicy, typename OptimizePolicy,
63           typename CopyPolicy, typename SubstitutePolicy>
64 class ModelRegistryCallback : public osgDB::Registry::ReadFileCallback {
65 public:
66     ModelRegistryCallback(const std::string& extension) :
67         _processPolicy(extension), _cachePolicy(extension),
68         _optimizePolicy(extension), _copyPolicy(extension),
69         _substitutePolicy(extension)
70     {
71     }
72     virtual osgDB::ReaderWriter::ReadResult
73     readNode(const std::string& fileName,
74              const osgDB::ReaderWriter::Options* opt)
75     {
76         using namespace osg;
77         using namespace osgDB;
78         using osgDB::ReaderWriter;
79         Registry* registry = Registry::instance();
80         ref_ptr<osg::Node> optimizedNode = _cachePolicy.find(fileName, opt);
81         if (!optimizedNode.valid()) {
82             std::string otherFileName = _substitutePolicy.substitute(fileName,
83                                                                      opt);
84             ReaderWriter::ReadResult res;
85             if (!otherFileName.empty()) {
86                 res = loadUsingReaderWriter(otherFileName, opt);
87                 if (res.validNode())
88                     optimizedNode = res.getNode();
89             }
90             if (!optimizedNode.valid()) {
91                 res = loadUsingReaderWriter(fileName, opt);
92                 if (!res.validNode())
93                     return res;
94                 ref_ptr<osg::Node> processedNode
95                     = _processPolicy.process(res.getNode(), fileName, opt);
96                 optimizedNode = _optimizePolicy.optimize(processedNode.get(),
97                                                          fileName, opt);
98             }
99             _cachePolicy.addToCache(fileName, optimizedNode.get());
100         }
101         return ReaderWriter::ReadResult(_copyPolicy.copy(optimizedNode.get(),
102                                                          fileName,
103                                                          opt));
104     }
105 protected:
106     static osgDB::ReaderWriter::ReadResult
107     loadUsingReaderWriter(const std::string& fileName,
108                           const osgDB::ReaderWriter::Options* opt)
109     {
110         using namespace osgDB;
111         ReaderWriter* rw = Registry::instance()
112             ->getReaderWriterForExtension(osgDB::getFileExtension(fileName));
113         if (!rw)
114             return ReaderWriter::ReadResult(); // FILE_NOT_HANDLED
115         return rw->readNode(fileName, opt);
116     }
117     
118     ProcessPolicy _processPolicy;
119     CachePolicy _cachePolicy;
120     OptimizePolicy _optimizePolicy;
121     CopyPolicy _copyPolicy;
122     SubstitutePolicy _substitutePolicy;
123     virtual ~ModelRegistryCallback() {}
124 };
125
126 // Predefined policies
127
128 struct DefaultProcessPolicy {
129     DefaultProcessPolicy(const std::string& extension) {}
130     osg::Node* process(osg::Node* node, const std::string& filename,
131                        const osgDB::ReaderWriter::Options* opt)
132     {
133         return node;
134     }
135 };
136
137 struct DefaultCachePolicy {
138     DefaultCachePolicy(const std::string& extension) {}
139     osg::Node* find(const std::string& fileName,
140                     const osgDB::ReaderWriter::Options* opt);
141     void addToCache(const std::string& filename, osg::Node* node);
142 };
143
144 struct NoCachePolicy {
145     NoCachePolicy(const std::string& extension) {}
146     osg::Node* find(const std::string& fileName,
147                     const osgDB::ReaderWriter::Options* opt)
148     {
149         return 0;
150     }
151     void addToCache(const std::string& filename, osg::Node* node) {}
152 };
153
154 class OptimizeModelPolicy {
155 public:
156     OptimizeModelPolicy(const std::string& extension);
157     osg::Node* optimize(osg::Node* node, const std::string& fileName,
158                         const osgDB::ReaderWriter::Options* opt);
159 protected:
160     unsigned _osgOptions;
161 };
162
163 struct NoOptimizePolicy {
164     NoOptimizePolicy(const std::string& extension) {}
165     osg::Node* optimize(osg::Node* node, const std::string& fileName,
166                         const osgDB::ReaderWriter::Options* opt)
167     {
168         return node;
169     }
170 };
171
172 struct DefaultCopyPolicy {
173     DefaultCopyPolicy(const std::string& extension) {}
174     osg::Node* copy(osg::Node* node, const std::string& fileName,
175                     const osgDB::ReaderWriter::Options* opt);
176 };
177
178 struct NoCopyPolicy {
179     NoCopyPolicy(const std::string& extension) {}
180     osg::Node* copy(osg::Node* node, const std::string& fileName,
181                     const osgDB::ReaderWriter::Options* opt)
182     {
183         return node;
184     }
185 };
186
187 struct OSGSubstitutePolicy {
188     OSGSubstitutePolicy(const std::string& extension) {}
189     std::string substitute(const std::string& name,
190                            const osgDB::ReaderWriter::Options* opt);
191 };
192
193 struct NoSubstitutePolicy {
194     NoSubstitutePolicy(const std::string& extension) {}
195     std::string substitute(const std::string& name,
196                            const osgDB::ReaderWriter::Options* opt)
197     {
198         return std::string();
199     }
200 };
201 typedef ModelRegistryCallback<DefaultProcessPolicy, DefaultCachePolicy,
202                               OptimizeModelPolicy, DefaultCopyPolicy,
203                               OSGSubstitutePolicy> DefaultCallback;
204
205 // The manager for the callbacks
206 class ModelRegistry : public osgDB::Registry::ReadFileCallback {
207 public:
208     ModelRegistry();
209     virtual osgDB::ReaderWriter::ReadResult
210     readImage(const std::string& fileName,
211               const osgDB::ReaderWriter::Options* opt);
212     virtual osgDB::ReaderWriter::ReadResult
213     readNode(const std::string& fileName,
214              const osgDB::ReaderWriter::Options* opt);
215     void addImageCallbackForExtension(const std::string& extension,
216                                       osgDB::Registry::ReadFileCallback*
217                                       callback);
218     void addNodeCallbackForExtension(const std::string& extension,
219                                      osgDB::Registry::ReadFileCallback*
220                                      callback);
221     static ModelRegistry* getInstance();
222     virtual ~ModelRegistry() {}
223 protected:
224     static osg::ref_ptr<ModelRegistry> instance;
225     typedef std::map<std::string, osg::ref_ptr<osgDB::Registry::ReadFileCallback> >
226     CallbackMap;
227     CallbackMap imageCallbackMap;
228     CallbackMap nodeCallbackMap;
229     osg::ref_ptr<DefaultCallback> _defaultCallback;
230     // Protect against simultaneous calls from main thread (MP models)
231     // and pager thread.
232     OpenThreads::ReentrantMutex readerMutex;
233 };
234
235 // Callback that only loads the file without any caching or
236 // postprocessing.
237 typedef ModelRegistryCallback<DefaultProcessPolicy, NoCachePolicy,
238                               NoOptimizePolicy, NoCopyPolicy,
239                               NoSubstitutePolicy> LoadOnlyCallback;
240
241 // Proxy for registering extension-based callbacks
242
243 template<typename T>
244 class ModelRegistryCallbackProxy
245 {
246 public:
247     ModelRegistryCallbackProxy(std::string extension)
248     {
249         ModelRegistry::getInstance()
250             ->addNodeCallbackForExtension(extension, new T(extension));
251     }
252 };
253 }
254 #endif // _SG_MODELREGISTRY_HXX