]> git.mxchange.org Git - simgear.git/blob - simgear/scene/model/ModelRegistry.hxx
0096315156c6cbdbd3e9c21033539aa82f874a03
[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 #include <simgear/structure/Singleton.hxx>
33
34 #include <string>
35 #include <map>
36
37 // Class to register per file extension read callbacks with the OSG
38 // registry, mostly to control caching and post load optimization /
39 // copying that happens above the level of the ReaderWriter.
40 namespace simgear
41 {
42
43 // Different caching and optimization strategies are needed for
44 // different file types. Most loaded files should be optimized and the
45 // optimized version should be cached. When an .osg file is
46 // substituted for another, it is assumed to be optimized already but
47 // it should be cached too (under the name of the original?). .stg
48 // files should not be cached (that's the pager's job) but the files
49 // it causes to be loaded should be. .btg files are already optimized
50 // and shouldn't be cached.
51 //
52 // Complicating this is the effect that removing CACHE_NODES has from
53 // the ReaderWriter options: it switches the object cache with an
54 // empty one, so that's not an option for the files that could be
55 // loaded from a .stg file. So, we'll let
56 // Registry::readNodeImplementation cache a loaded file and then add
57 // the optimized version to the cache ourselves, replacing the
58 // original subgraph.
59 //
60 // To support all these options with a minimum of duplication, the
61 // readNode function is specified as a template with a bunch of
62 // pluggable (and predefined) policies.
63 template <typename ProcessPolicy, typename CachePolicy, typename OptimizePolicy,
64           typename SubstitutePolicy, typename BVHPolicy>
65 class ModelRegistryCallback : public osgDB::Registry::ReadFileCallback {
66 public:
67     ModelRegistryCallback(const std::string& extension) :
68         _processPolicy(extension), _cachePolicy(extension),
69         _optimizePolicy(extension),
70         _substitutePolicy(extension), _bvhPolicy(extension)
71     {
72     }
73     virtual osgDB::ReaderWriter::ReadResult
74     readNode(const std::string& fileName,
75              const osgDB::ReaderWriter::Options* opt)
76     {
77         using namespace osg;
78         using namespace osgDB;
79         using osgDB::ReaderWriter;
80 //        Registry* registry = Registry::instance();
81         ref_ptr<osg::Node> optimizedNode = _cachePolicy.find(fileName, opt);
82         if (!optimizedNode.valid()) {
83             std::string otherFileName = _substitutePolicy.substitute(fileName,
84                                                                      opt);
85             ReaderWriter::ReadResult res;
86             if (!otherFileName.empty()) {
87                 res = loadUsingReaderWriter(otherFileName, opt);
88                 if (res.validNode())
89                     optimizedNode = res.getNode();
90             }
91             if (!optimizedNode.valid()) {
92                 res = loadUsingReaderWriter(fileName, opt);
93                 if (!res.validNode())
94                     return res;
95                 ref_ptr<osg::Node> processedNode
96                     = _processPolicy.process(res.getNode(), fileName, opt);
97                 optimizedNode = _optimizePolicy.optimize(processedNode.get(),
98                                                          fileName, opt);
99             }
100             _bvhPolicy.buildBVH(fileName, optimizedNode.get());
101             _cachePolicy.addToCache(fileName, optimizedNode.get());
102         }
103         return ReaderWriter::ReadResult(optimizedNode);
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     SubstitutePolicy _substitutePolicy;
122     BVHPolicy _bvhPolicy;
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
134 struct DefaultCachePolicy {
135     DefaultCachePolicy(const std::string& extension) {}
136     osg::Node* find(const std::string& fileName,
137                     const osgDB::ReaderWriter::Options* opt);
138     void addToCache(const std::string& filename, osg::Node* node);
139 };
140
141 struct NoCachePolicy {
142     NoCachePolicy(const std::string& extension) {}
143     osg::Node* find(const std::string& fileName,
144                     const osgDB::ReaderWriter::Options* opt)
145     {
146         return 0;
147     }
148     void addToCache(const std::string& filename, osg::Node* node) {}
149 };
150
151 class OptimizeModelPolicy {
152 public:
153     OptimizeModelPolicy(const std::string& extension);
154     osg::Node* optimize(osg::Node* node, const std::string& fileName,
155                         const osgDB::ReaderWriter::Options* opt);
156 protected:
157     unsigned _osgOptions;
158 };
159
160 struct NoOptimizePolicy {
161     NoOptimizePolicy(const std::string& extension) {}
162     osg::Node* optimize(osg::Node* node, const std::string& fileName,
163                         const osgDB::ReaderWriter::Options* opt)
164     {
165         return node;
166     }
167 };
168
169 struct OSGSubstitutePolicy {
170     OSGSubstitutePolicy(const std::string& extension) {}
171     std::string substitute(const std::string& name,
172                            const osgDB::ReaderWriter::Options* opt);
173 };
174
175 struct NoSubstitutePolicy {
176     NoSubstitutePolicy(const std::string& extension) {}
177     std::string substitute(const std::string& name,
178                            const osgDB::ReaderWriter::Options* opt)
179     {
180         return std::string();
181     }
182 };
183
184 struct BuildLeafBVHPolicy {
185     BuildLeafBVHPolicy(const std::string& extension) {}
186     void buildBVH(const std::string& fileName, osg::Node* node);
187 };
188
189 struct BuildGroupBVHPolicy {
190     BuildGroupBVHPolicy(const std::string& extension) {}
191     void buildBVH(const std::string& fileName, osg::Node* node);
192 };
193
194 struct NoBuildBVHPolicy {
195     NoBuildBVHPolicy(const std::string& extension) {}
196     void buildBVH(const std::string& fileName, osg::Node* node);
197 };
198
199 typedef ModelRegistryCallback<DefaultProcessPolicy, DefaultCachePolicy,
200                               OptimizeModelPolicy,
201                               OSGSubstitutePolicy, BuildLeafBVHPolicy>
202 DefaultCallback;
203
204 // The manager for the callbacks
205 class ModelRegistry : public osgDB::Registry::ReadFileCallback,
206                       public ReferencedSingleton<ModelRegistry> {
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     virtual ~ModelRegistry() {}
222 protected:
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     // Protect against simultaneous calls from main thread (MP models)
229     // and pager thread.
230     OpenThreads::ReentrantMutex readerMutex;
231 };
232
233 // Callback that only loads the file without any caching or
234 // postprocessing.
235 typedef ModelRegistryCallback<DefaultProcessPolicy, NoCachePolicy,
236                               NoOptimizePolicy,
237                               NoSubstitutePolicy, BuildLeafBVHPolicy>
238 LoadOnlyCallback;
239
240 // Proxy for registering extension-based callbacks
241
242 template<typename T>
243 class ModelRegistryCallbackProxy
244 {
245 public:
246     ModelRegistryCallbackProxy(std::string extension)
247     {
248         ModelRegistry::instance()
249             ->addNodeCallbackForExtension(extension, new T(extension));
250     }
251 };
252 }
253 #endif // _SG_MODELREGISTRY_HXX