1 // ModelRegistry.hxx -- interface to the OSG model registry
3 // Copyright (C) 2005-2007 Mathias Froehlich
4 // Copyright (C) 2007 Tim Moore <timoore@redhat.com>
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.
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.
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
22 #include <OpenThreads/ReentrantMutex>
24 #include <osg/ref_ptr>
26 #include <osgDB/FileUtils>
27 #include <osgDB/FileNameUtils>
28 #include <osgDB/ReaderWriter>
29 #include <osgDB/Registry>
31 #include <simgear/compiler.h>
32 #include <simgear/structure/Singleton.hxx>
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.
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.
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
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 CopyPolicy, typename SubstitutePolicy, typename BVHPolicy>
65 class ModelRegistryCallback : public osgDB::Registry::ReadFileCallback {
67 ModelRegistryCallback(const std::string& extension) :
68 _processPolicy(extension), _cachePolicy(extension),
69 _optimizePolicy(extension), _copyPolicy(extension),
70 _substitutePolicy(extension), _bvhPolicy(extension)
73 virtual osgDB::ReaderWriter::ReadResult
74 readNode(const std::string& fileName,
75 const osgDB::ReaderWriter::Options* opt)
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,
85 ReaderWriter::ReadResult res;
86 if (!otherFileName.empty()) {
87 res = loadUsingReaderWriter(otherFileName, opt);
89 optimizedNode = res.getNode();
91 if (!optimizedNode.valid()) {
92 res = loadUsingReaderWriter(fileName, opt);
95 ref_ptr<osg::Node> processedNode
96 = _processPolicy.process(res.getNode(), fileName, opt);
97 optimizedNode = _optimizePolicy.optimize(processedNode.get(),
100 _bvhPolicy.buildBVH(fileName, optimizedNode.get());
101 _cachePolicy.addToCache(fileName, optimizedNode.get());
103 osg::ref_ptr<osg::Node> copyNode;
104 copyNode = _copyPolicy.copy(optimizedNode.get(), fileName, opt);
105 return ReaderWriter::ReadResult(copyNode);
108 static osgDB::ReaderWriter::ReadResult
109 loadUsingReaderWriter(const std::string& fileName,
110 const osgDB::ReaderWriter::Options* opt)
112 using namespace osgDB;
113 ReaderWriter* rw = Registry::instance()
114 ->getReaderWriterForExtension(osgDB::getFileExtension(fileName));
116 return ReaderWriter::ReadResult(); // FILE_NOT_HANDLED
117 return rw->readNode(fileName, opt);
120 ProcessPolicy _processPolicy;
121 CachePolicy _cachePolicy;
122 OptimizePolicy _optimizePolicy;
123 CopyPolicy _copyPolicy;
124 SubstitutePolicy _substitutePolicy;
125 BVHPolicy _bvhPolicy;
126 virtual ~ModelRegistryCallback() {}
129 // Predefined policies
131 struct DefaultProcessPolicy {
132 DefaultProcessPolicy(const std::string& extension) {}
133 osg::Node* process(osg::Node* node, const std::string& filename,
134 const osgDB::ReaderWriter::Options* opt);
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);
144 struct NoCachePolicy {
145 NoCachePolicy(const std::string& extension) {}
146 osg::Node* find(const std::string& fileName,
147 const osgDB::ReaderWriter::Options* opt)
151 void addToCache(const std::string& filename, osg::Node* node) {}
154 class OptimizeModelPolicy {
156 OptimizeModelPolicy(const std::string& extension);
157 osg::Node* optimize(osg::Node* node, const std::string& fileName,
158 const osgDB::ReaderWriter::Options* opt);
160 unsigned _osgOptions;
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)
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);
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)
187 struct OSGSubstitutePolicy {
188 OSGSubstitutePolicy(const std::string& extension) {}
189 std::string substitute(const std::string& name,
190 const osgDB::ReaderWriter::Options* opt);
193 struct NoSubstitutePolicy {
194 NoSubstitutePolicy(const std::string& extension) {}
195 std::string substitute(const std::string& name,
196 const osgDB::ReaderWriter::Options* opt)
198 return std::string();
202 struct BuildLeafBVHPolicy {
203 BuildLeafBVHPolicy(const std::string& extension) {}
204 void buildBVH(const std::string& fileName, osg::Node* node);
207 struct BuildGroupBVHPolicy {
208 BuildGroupBVHPolicy(const std::string& extension) {}
209 void buildBVH(const std::string& fileName, osg::Node* node);
212 struct NoBuildBVHPolicy {
213 NoBuildBVHPolicy(const std::string& extension) {}
214 void buildBVH(const std::string& fileName, osg::Node* node);
217 typedef ModelRegistryCallback<DefaultProcessPolicy, DefaultCachePolicy,
218 OptimizeModelPolicy, DefaultCopyPolicy,
219 OSGSubstitutePolicy, BuildLeafBVHPolicy>
222 // The manager for the callbacks
223 class ModelRegistry : public osgDB::Registry::ReadFileCallback,
224 public ReferencedSingleton<ModelRegistry> {
227 virtual osgDB::ReaderWriter::ReadResult
228 readImage(const std::string& fileName,
229 const osgDB::ReaderWriter::Options* opt);
230 virtual osgDB::ReaderWriter::ReadResult
231 readNode(const std::string& fileName,
232 const osgDB::ReaderWriter::Options* opt);
233 void addImageCallbackForExtension(const std::string& extension,
234 osgDB::Registry::ReadFileCallback*
236 void addNodeCallbackForExtension(const std::string& extension,
237 osgDB::Registry::ReadFileCallback*
239 virtual ~ModelRegistry() {}
241 typedef std::map<std::string, osg::ref_ptr<osgDB::Registry::ReadFileCallback> >
243 CallbackMap imageCallbackMap;
244 CallbackMap nodeCallbackMap;
245 osg::ref_ptr<DefaultCallback> _defaultCallback;
246 // Protect against simultaneous calls from main thread (MP models)
248 OpenThreads::ReentrantMutex readerMutex;
251 // Callback that only loads the file without any caching or
253 typedef ModelRegistryCallback<DefaultProcessPolicy, NoCachePolicy,
254 NoOptimizePolicy, NoCopyPolicy,
255 NoSubstitutePolicy, BuildLeafBVHPolicy>
258 // Proxy for registering extension-based callbacks
261 class ModelRegistryCallbackProxy
264 ModelRegistryCallbackProxy(std::string extension)
266 ModelRegistry::instance()
267 ->addNodeCallbackForExtension(extension, new T(extension));
271 #endif // _SG_MODELREGISTRY_HXX