]> git.mxchange.org Git - simgear.git/blob - simgear/scene/model/ModelRegistry.hxx
2c0102976c2815096a09a880ceecd99bc4137e39
[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 <osg/ref_ptr>
23 #include <osg/Node>
24 #include <osgDB/FileUtils>
25 #include <osgDB/FileNameUtils>
26 #include <osgDB/ReaderWriter>
27 #include <osgDB/Registry>
28
29 #include <simgear/compiler.h>
30
31 #include STL_STRING
32 #include <map>
33
34 // Class to register per file extension read callbacks with the OSG
35 // registry, mostly to control caching and post load optimization /
36 // copying that happens above the level of the ReaderWriter.
37 namespace simgear
38 {
39
40 // Different caching and optimization strategies are needed for
41 // different file types. Most loaded files should be optimized and the
42 // optimized version should be cached. When an .osg file is
43 // substituted for another, it is assumed to be optimized already but
44 // it should be cached too (under the name of the original?). .stg
45 // files should not be cached (that's the pager's job) but the files
46 // it causes to be loaded should be. .btg files are already optimized
47 // and shouldn't be cached.
48 //
49 // Complicating this is the effect that removing CACHE_NODES has from
50 // the ReaderWriter options: it switches the object cache with an
51 // empty one, so that's not an option for the files that could be
52 // loaded from a .stg file. So, we'll let
53 // Registry::readNodeImplementation cache a loaded file and then add
54 // the optimized version to the cache ourselves, replacing the
55 // original subgraph.
56 //
57 // To support all these options with a minimum of duplication, the
58 // readNode function is specified as a template with a bunch of
59 // pluggable (and predefined) policies.
60 template <typename ProcessPolicy, typename CachePolicy, typename OptimizePolicy,
61           typename CopyPolicy, typename SubstitutePolicy>
62 class ModelRegistryCallback : public osgDB::Registry::ReadFileCallback {
63 public:
64     ModelRegistryCallback(const std::string& extension) :
65         _processPolicy(extension), _cachePolicy(extension),
66         _optimizePolicy(extension), _copyPolicy(extension),
67         _substitutePolicy(extension)
68     {
69     }
70     virtual osgDB::ReaderWriter::ReadResult
71     readNode(const std::string& fileName,
72              const osgDB::ReaderWriter::Options* opt)
73     {
74         using namespace osg;
75         using namespace osgDB;
76         using osgDB::ReaderWriter;
77         Registry* registry = Registry::instance();
78         ref_ptr<osg::Node> optimizedNode = _cachePolicy.find(fileName, opt);
79         if (!optimizedNode.valid()) {
80             std::string otherFileName = _substitutePolicy.substitute(fileName,
81                                                                      opt);
82             ReaderWriter::ReadResult res;
83             if (!otherFileName.empty()) {
84                 res = loadUsingReaderWriter(otherFileName, opt);
85                 if (res.validNode())
86                     optimizedNode = res.getNode();
87             }
88             if (!optimizedNode.valid()) {
89                 res = loadUsingReaderWriter(fileName, opt);
90                 if (!res.validNode())
91                     return res;
92                 ref_ptr<osg::Node> processedNode
93                     = _processPolicy.process(res.getNode(), fileName, opt);
94                 optimizedNode = _optimizePolicy.optimize(processedNode.get(),
95                                                          fileName, opt);
96             }
97             _cachePolicy.addToCache(fileName, optimizedNode.get());
98         }
99         return ReaderWriter::ReadResult(_copyPolicy.copy(optimizedNode.get(),
100                                                          fileName,
101                                                          opt));
102     }
103 protected:
104     static osgDB::ReaderWriter::ReadResult
105     loadUsingReaderWriter(const std::string& fileName,
106                           const osgDB::ReaderWriter::Options* opt)
107     {
108         using namespace osgDB;
109         ReaderWriter* rw = Registry::instance()
110             ->getReaderWriterForExtension(osgDB::getFileExtension(fileName));
111         if (!rw)
112             return ReaderWriter::ReadResult(); // FILE_NOT_HANDLED
113         return rw->readNode(fileName, opt);
114     }
115     
116     ProcessPolicy _processPolicy;
117     CachePolicy _cachePolicy;
118     OptimizePolicy _optimizePolicy;
119     CopyPolicy _copyPolicy;
120     SubstitutePolicy _substitutePolicy;
121     virtual ~ModelRegistryCallback() {}
122 };
123
124 // Predefined policies
125
126 struct DefaultProcessPolicy {
127     DefaultProcessPolicy(const std::string& extension) {}
128     osg::Node* process(osg::Node* node, const std::string& filename,
129                        const osgDB::ReaderWriter::Options* opt)
130     {
131         return node;
132     }
133 };
134
135 struct DefaultCachePolicy {
136     DefaultCachePolicy(const std::string& extension) {}
137     osg::Node* find(const std::string& fileName,
138                     const osgDB::ReaderWriter::Options* opt);
139     void addToCache(const std::string& filename, osg::Node* node);
140 };
141
142 struct NoCachePolicy {
143     NoCachePolicy(const std::string& extension) {}
144     osg::Node* find(const std::string& fileName,
145                     const osgDB::ReaderWriter::Options* opt)
146     {
147         return 0;
148     }
149     void addToCache(const std::string& filename, osg::Node* node) {}
150 };
151
152 class OptimizeModelPolicy {
153 public:
154     OptimizeModelPolicy(const std::string& extension);
155     osg::Node* optimize(osg::Node* node, const std::string& fileName,
156                         const osgDB::ReaderWriter::Options* opt);
157 protected:
158     unsigned _osgOptions;
159 };
160
161 struct NoOptimizePolicy {
162     NoOptimizePolicy(const std::string& extension) {}
163     osg::Node* optimize(osg::Node* node, const std::string& fileName,
164                         const osgDB::ReaderWriter::Options* opt)
165     {
166         return node;
167     }
168 };
169
170 struct DefaultCopyPolicy {
171     DefaultCopyPolicy(const std::string& extension) {}
172     osg::Node* copy(osg::Node* node, const std::string& fileName,
173                     const osgDB::ReaderWriter::Options* opt);
174 };
175
176 struct NoCopyPolicy {
177     NoCopyPolicy(const std::string& extension) {}
178     osg::Node* copy(osg::Node* node, const std::string& fileName,
179                     const osgDB::ReaderWriter::Options* opt)
180     {
181         return node;
182     }
183 };
184
185 struct OSGSubstitutePolicy {
186     OSGSubstitutePolicy(const std::string& extension) {}
187     std::string substitute(const std::string& name,
188                            const osgDB::ReaderWriter::Options* opt);
189 };
190
191 struct NoSubstitutePolicy {
192     NoSubstitutePolicy(const std::string& extension) {}
193     std::string substitute(const std::string& name,
194                            const osgDB::ReaderWriter::Options* opt)
195     {
196         return std::string();
197     }
198 };
199 typedef ModelRegistryCallback<DefaultProcessPolicy, DefaultCachePolicy,
200                               OptimizeModelPolicy, DefaultCopyPolicy,
201                               OSGSubstitutePolicy> DefaultCallback;
202
203 // The manager for the callbacks
204 class ModelRegistry : public osgDB::Registry::ReadFileCallback {
205 public:
206     ModelRegistry();
207     virtual osgDB::ReaderWriter::ReadResult
208     readImage(const std::string& fileName,
209               const osgDB::ReaderWriter::Options* opt);
210     virtual osgDB::ReaderWriter::ReadResult
211     readNode(const std::string& fileName,
212              const osgDB::ReaderWriter::Options* opt);
213     void addImageCallbackForExtension(const std::string& extension,
214                                       osgDB::Registry::ReadFileCallback*
215                                       callback);
216     void addNodeCallbackForExtension(const std::string& extension,
217                                      osgDB::Registry::ReadFileCallback*
218                                      callback);
219     static ModelRegistry* getInstance();
220     virtual ~ModelRegistry() {}
221 protected:
222     static osg::ref_ptr<ModelRegistry> instance;
223     typedef std::map<std::string, osg::ref_ptr<osgDB::Registry::ReadFileCallback> >
224     CallbackMap;
225     CallbackMap imageCallbackMap;
226     CallbackMap nodeCallbackMap;
227     osg::ref_ptr<DefaultCallback> _defaultCallback;
228 };
229
230 // Callback that only loads the file without any caching or
231 // postprocessing.
232 typedef ModelRegistryCallback<DefaultProcessPolicy, NoCachePolicy,
233                               NoOptimizePolicy, NoCopyPolicy,
234                               NoSubstitutePolicy> LoadOnlyCallback;
235
236 // Proxy for registering extension-based callbacks
237
238 template<typename T>
239 class ModelRegistryCallbackProxy
240 {
241 public:
242     ModelRegistryCallbackProxy(std::string extension)
243     {
244         ModelRegistry::getInstance()
245             ->addNodeCallbackForExtension(extension, new T(extension));
246     }
247 };
248
249 // Callback for file extensions that load files using the default OSG
250 // implementation.
251
252 class OSGFileCallback : public osgDB::Registry::ReadFileCallback {
253 public:
254     virtual osgDB::ReaderWriter::ReadResult
255     readImage(const std::string& fileName,
256               const osgDB::ReaderWriter::Options* opt);
257     virtual osgDB::ReaderWriter::ReadResult
258     readNode(const std::string& fileName,
259              const osgDB::ReaderWriter::Options* opt);
260 };
261
262 }
263 #endif // _SG_MODELREGISTRY_HXX