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 <osg/ref_ptr>
24 #include <osgDB/FileUtils>
25 #include <osgDB/FileNameUtils>
26 #include <osgDB/ReaderWriter>
27 #include <osgDB/Registry>
29 #include <simgear/compiler.h>
30 #include <simgear/structure/Singleton.hxx>
35 // Class to register per file extension read callbacks with the OSG
36 // registry, mostly to control caching and post load optimization /
37 // copying that happens above the level of the ReaderWriter.
41 // Different caching and optimization strategies are needed for
42 // different file types. Most loaded files should be optimized and the
43 // optimized version should be cached. When an .osg file is
44 // substituted for another, it is assumed to be optimized already but
45 // it should be cached too (under the name of the original?). .stg
46 // files should not be cached (that's the pager's job) but the files
47 // it causes to be loaded should be. .btg files are already optimized
48 // and shouldn't be cached.
50 // Complicating this is the effect that removing CACHE_NODES has from
51 // the ReaderWriter options: it switches the object cache with an
52 // empty one, so that's not an option for the files that could be
53 // loaded from a .stg file. So, we'll let
54 // Registry::readNodeImplementation cache a loaded file and then add
55 // the optimized version to the cache ourselves, replacing the
58 // To support all these options with a minimum of duplication, the
59 // readNode function is specified as a template with a bunch of
60 // pluggable (and predefined) policies.
61 template <typename ProcessPolicy, typename CachePolicy, typename OptimizePolicy,
62 typename SubstitutePolicy, typename BVHPolicy>
63 class ModelRegistryCallback : public osgDB::Registry::ReadFileCallback {
65 ModelRegistryCallback(const std::string& extension) :
66 _processPolicy(extension), _cachePolicy(extension),
67 _optimizePolicy(extension),
68 _substitutePolicy(extension), _bvhPolicy(extension)
71 virtual osgDB::ReaderWriter::ReadResult
72 readNode(const std::string& fileName,
73 const osgDB::ReaderWriter::Options* opt)
76 using namespace osgDB;
77 using osgDB::ReaderWriter;
78 // Registry* registry = Registry::instance();
79 ref_ptr<osg::Node> optimizedNode = _cachePolicy.find(fileName, opt);
80 if (!optimizedNode.valid()) {
81 std::string otherFileName = _substitutePolicy.substitute(fileName,
83 ReaderWriter::ReadResult res;
84 if (!otherFileName.empty()) {
85 res = loadUsingReaderWriter(otherFileName, opt);
87 optimizedNode = res.getNode();
89 if (!optimizedNode.valid()) {
90 res = loadUsingReaderWriter(fileName, opt);
93 ref_ptr<osg::Node> processedNode
94 = _processPolicy.process(res.getNode(), fileName, opt);
95 optimizedNode = _optimizePolicy.optimize(processedNode.get(),
98 _bvhPolicy.buildBVH(fileName, optimizedNode.get());
99 _cachePolicy.addToCache(fileName, optimizedNode.get());
101 return ReaderWriter::ReadResult(optimizedNode.get());
104 static osgDB::ReaderWriter::ReadResult
105 loadUsingReaderWriter(const std::string& fileName,
106 const osgDB::ReaderWriter::Options* opt)
108 using namespace osgDB;
109 ReaderWriter* rw = Registry::instance()
110 ->getReaderWriterForExtension(osgDB::getFileExtension(fileName));
112 return ReaderWriter::ReadResult(); // FILE_NOT_HANDLED
113 return rw->readNode(fileName, opt);
116 ProcessPolicy _processPolicy;
117 CachePolicy _cachePolicy;
118 OptimizePolicy _optimizePolicy;
119 SubstitutePolicy _substitutePolicy;
120 BVHPolicy _bvhPolicy;
121 virtual ~ModelRegistryCallback() {}
124 // Predefined policies
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);
132 struct DefaultCachePolicy {
133 DefaultCachePolicy(const std::string& extension) {}
134 osg::Node* find(const std::string& fileName,
135 const osgDB::ReaderWriter::Options* opt);
136 void addToCache(const std::string& filename, osg::Node* node);
139 struct NoCachePolicy {
140 NoCachePolicy(const std::string& extension) {}
141 osg::Node* find(const std::string& fileName,
142 const osgDB::ReaderWriter::Options* opt)
146 void addToCache(const std::string& filename, osg::Node* node) {}
149 class OptimizeModelPolicy {
151 OptimizeModelPolicy(const std::string& extension);
152 osg::Node* optimize(osg::Node* node, const std::string& fileName,
153 const osgDB::ReaderWriter::Options* opt);
155 unsigned _osgOptions;
158 struct NoOptimizePolicy {
159 NoOptimizePolicy(const std::string& extension) {}
160 osg::Node* optimize(osg::Node* node, const std::string& fileName,
161 const osgDB::ReaderWriter::Options* opt)
167 struct OSGSubstitutePolicy {
168 OSGSubstitutePolicy(const std::string& extension) {}
169 std::string substitute(const std::string& name,
170 const osgDB::ReaderWriter::Options* opt);
173 struct NoSubstitutePolicy {
174 NoSubstitutePolicy(const std::string& extension) {}
175 std::string substitute(const std::string& name,
176 const osgDB::ReaderWriter::Options* opt)
178 return std::string();
182 struct BuildLeafBVHPolicy {
183 BuildLeafBVHPolicy(const std::string& extension) {}
184 void buildBVH(const std::string& fileName, osg::Node* node);
187 struct BuildGroupBVHPolicy {
188 BuildGroupBVHPolicy(const std::string& extension) {}
189 void buildBVH(const std::string& fileName, osg::Node* node);
192 struct NoBuildBVHPolicy {
193 NoBuildBVHPolicy(const std::string& extension) {}
194 void buildBVH(const std::string& fileName, osg::Node* node);
197 typedef ModelRegistryCallback<DefaultProcessPolicy, DefaultCachePolicy,
199 OSGSubstitutePolicy, BuildLeafBVHPolicy>
202 // The manager for the callbacks
203 class ModelRegistry : public osgDB::Registry::ReadFileCallback,
204 public ReferencedSingleton<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*
216 void addNodeCallbackForExtension(const std::string& extension,
217 osgDB::Registry::ReadFileCallback*
219 virtual ~ModelRegistry() {}
221 typedef std::map<std::string, osg::ref_ptr<osgDB::Registry::ReadFileCallback> >
223 CallbackMap imageCallbackMap;
224 CallbackMap nodeCallbackMap;
225 osg::ref_ptr<DefaultCallback> _defaultCallback;
228 // Callback that only loads the file without any caching or
230 typedef ModelRegistryCallback<DefaultProcessPolicy, NoCachePolicy,
232 NoSubstitutePolicy, BuildLeafBVHPolicy>
235 // Proxy for registering extension-based callbacks
238 class ModelRegistryCallbackProxy
241 ModelRegistryCallbackProxy(std::string extension)
243 ModelRegistry::instance()
244 ->addNodeCallbackForExtension(extension, new T(extension));
248 #endif // _SG_MODELREGISTRY_HXX