]> git.mxchange.org Git - simgear.git/blob - simgear/scene/model/ModelRegistry.hxx
e65c78b86cb94a287b358d3759e701d280e559e7
[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         std::string usedFileName = _substitutePolicy.substitute(fileName, opt);
79         if (usedFileName.empty())
80             usedFileName = fileName;
81         ref_ptr<osg::Node> loadedNode = _cachePolicy.find(usedFileName, opt);
82         if (!loadedNode.valid()) {
83             ReaderWriter* rw = registry ->getReaderWriterForExtension(osgDB::getFileExtension(usedFileName));
84             if (!rw)
85                 return ReaderWriter::ReadResult(); // FILE_NOT_HANDLED
86             ReaderWriter::ReadResult res = rw->readNode(usedFileName, opt);
87             if (!res.validNode())
88                 return res;
89             ref_ptr<osg::Node> processedNode
90                 = _processPolicy.process(res.getNode(), usedFileName, opt);
91             ref_ptr<osg::Node> optimizedNode
92                 = _optimizePolicy.optimize(processedNode.get(), usedFileName,
93                                            opt);
94             _cachePolicy.addToCache(usedFileName, optimizedNode.get());
95             loadedNode = optimizedNode;
96         }
97         return ReaderWriter::ReadResult(_copyPolicy.copy(loadedNode.get(),
98                                                          usedFileName,
99                                                          opt));
100     }
101 protected:
102     ProcessPolicy _processPolicy;
103     CachePolicy _cachePolicy;
104     OptimizePolicy _optimizePolicy;
105     CopyPolicy _copyPolicy;
106     SubstitutePolicy _substitutePolicy;
107     virtual ~ModelRegistryCallback() {}
108 };
109
110 // Predefined policies
111
112 struct DefaultProcessPolicy {
113     DefaultProcessPolicy(const std::string& extension) {}
114     osg::Node* process(osg::Node* node, const std::string& filename,
115                        const osgDB::ReaderWriter::Options* opt)
116     {
117         return node;
118     }
119 };
120
121 struct DefaultCachePolicy {
122     DefaultCachePolicy(const std::string& extension) {}
123     osg::Node* find(const std::string& fileName,
124                     const osgDB::ReaderWriter::Options* opt);
125     void addToCache(const std::string& filename, osg::Node* node);
126 };
127
128 struct NoCachePolicy {
129     NoCachePolicy(const std::string& extension) {}
130     osg::Node* find(const std::string& fileName,
131                     const osgDB::ReaderWriter::Options* opt)
132     {
133         return 0;
134     }
135     void addToCache(const std::string& filename, osg::Node* node) {}
136 };
137
138 class OptimizeModelPolicy {
139 public:
140     OptimizeModelPolicy(const std::string& extension);
141     osg::Node* optimize(osg::Node* node, const std::string& fileName,
142                         const osgDB::ReaderWriter::Options* opt);
143 protected:
144     unsigned _osgOptions;
145 };
146
147 struct NoOptimizePolicy {
148     NoOptimizePolicy(const std::string& extension) {}
149     osg::Node* optimize(osg::Node* node, const std::string& fileName,
150                         const osgDB::ReaderWriter::Options* opt)
151     {
152         return node;
153     }
154 };
155
156 struct DefaultCopyPolicy {
157     DefaultCopyPolicy(const std::string& extension) {}
158     osg::Node* copy(osg::Node* node, const std::string& fileName,
159                     const osgDB::ReaderWriter::Options* opt);
160 };
161
162 struct NoCopyPolicy {
163     NoCopyPolicy(const std::string& extension) {}
164     osg::Node* copy(osg::Node* node, const std::string& fileName,
165                     const osgDB::ReaderWriter::Options* opt)
166     {
167         return node;
168     }
169 };
170
171 struct OSGSubstitutePolicy {
172     OSGSubstitutePolicy(const std::string& extension) {}
173     std::string substitute(const std::string& name,
174                            const osgDB::ReaderWriter::Options* opt);
175 };
176
177 struct NoSubstitutePolicy {
178     NoSubstitutePolicy(const std::string& extension) {}
179     std::string substitute(const std::string& name,
180                            const osgDB::ReaderWriter::Options* opt)
181     {
182         return std::string();
183     }
184 };
185 typedef ModelRegistryCallback<DefaultProcessPolicy, DefaultCachePolicy,
186                               OptimizeModelPolicy, DefaultCopyPolicy,
187                               OSGSubstitutePolicy> DefaultCallback;
188
189 // The manager for the callbacks
190 class ModelRegistry : public osgDB::Registry::ReadFileCallback {
191 public:
192     ModelRegistry();
193     virtual osgDB::ReaderWriter::ReadResult
194     readImage(const std::string& fileName,
195               const osgDB::ReaderWriter::Options* opt);
196     virtual osgDB::ReaderWriter::ReadResult
197     readNode(const std::string& fileName,
198              const osgDB::ReaderWriter::Options* opt);
199     void addImageCallbackForExtension(const std::string& extension,
200                                       osgDB::Registry::ReadFileCallback*
201                                       callback);
202     void addNodeCallbackForExtension(const std::string& extension,
203                                      osgDB::Registry::ReadFileCallback*
204                                      callback);
205     static ModelRegistry* getInstance();
206     virtual ~ModelRegistry() {}
207 protected:
208     static osg::ref_ptr<ModelRegistry> instance;
209     typedef std::map<std::string, osg::ref_ptr<osgDB::Registry::ReadFileCallback> >
210     CallbackMap;
211     CallbackMap imageCallbackMap;
212     CallbackMap nodeCallbackMap;
213     osg::ref_ptr<DefaultCallback> _defaultCallback;
214 };
215
216 // Callback that only loads the file without any caching or
217 // postprocessing.
218 typedef ModelRegistryCallback<DefaultProcessPolicy, NoCachePolicy,
219                               NoOptimizePolicy, NoCopyPolicy,
220                               NoSubstitutePolicy> LoadOnlyCallback;
221
222 // Proxy for registering extension-based callbacks
223
224 template<typename T>
225 class ModelRegistryCallbackProxy
226 {
227 public:
228     ModelRegistryCallbackProxy(std::string extension)
229     {
230         ModelRegistry::getInstance()
231             ->addNodeCallbackForExtension(extension, new T(extension));
232     }
233 };
234
235 // Callback for file extensions that load files using the default OSG
236 // implementation.
237
238 class OSGFileCallback : public osgDB::Registry::ReadFileCallback {
239 public:
240     virtual osgDB::ReaderWriter::ReadResult
241     readImage(const std::string& fileName,
242               const osgDB::ReaderWriter::Options* opt);
243     virtual osgDB::ReaderWriter::ReadResult
244     readNode(const std::string& fileName,
245              const osgDB::ReaderWriter::Options* opt);
246 };
247
248 }
249 #endif // _SG_MODELREGISTRY_HXX