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>
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.
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.
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
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 {
64 ModelRegistryCallback(const std::string& extension) :
65 _processPolicy(extension), _cachePolicy(extension),
66 _optimizePolicy(extension), _copyPolicy(extension),
67 _substitutePolicy(extension)
70 virtual osgDB::ReaderWriter::ReadResult
71 readNode(const std::string& fileName,
72 const osgDB::ReaderWriter::Options* opt)
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));
85 return ReaderWriter::ReadResult(); // FILE_NOT_HANDLED
86 ReaderWriter::ReadResult res = rw->readNode(usedFileName, opt);
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,
94 _cachePolicy.addToCache(usedFileName, optimizedNode.get());
95 loadedNode = optimizedNode;
97 return ReaderWriter::ReadResult(_copyPolicy.copy(loadedNode.get(),
102 ProcessPolicy _processPolicy;
103 CachePolicy _cachePolicy;
104 OptimizePolicy _optimizePolicy;
105 CopyPolicy _copyPolicy;
106 SubstitutePolicy _substitutePolicy;
107 virtual ~ModelRegistryCallback() {}
110 // Predefined policies
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)
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);
128 struct NoCachePolicy {
129 NoCachePolicy(const std::string& extension) {}
130 osg::Node* find(const std::string& fileName,
131 const osgDB::ReaderWriter::Options* opt)
135 void addToCache(const std::string& filename, osg::Node* node) {}
138 class OptimizeModelPolicy {
140 OptimizeModelPolicy(const std::string& extension);
141 osg::Node* optimize(osg::Node* node, const std::string& fileName,
142 const osgDB::ReaderWriter::Options* opt);
144 unsigned _osgOptions;
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)
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);
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)
171 struct OSGSubstitutePolicy {
172 OSGSubstitutePolicy(const std::string& extension) {}
173 std::string substitute(const std::string& name,
174 const osgDB::ReaderWriter::Options* opt);
177 struct NoSubstitutePolicy {
178 NoSubstitutePolicy(const std::string& extension) {}
179 std::string substitute(const std::string& name,
180 const osgDB::ReaderWriter::Options* opt)
182 return std::string();
185 typedef ModelRegistryCallback<DefaultProcessPolicy, DefaultCachePolicy,
186 OptimizeModelPolicy, DefaultCopyPolicy,
187 OSGSubstitutePolicy> DefaultCallback;
189 // The manager for the callbacks
190 class ModelRegistry : public osgDB::Registry::ReadFileCallback {
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*
202 void addNodeCallbackForExtension(const std::string& extension,
203 osgDB::Registry::ReadFileCallback*
205 static ModelRegistry* getInstance();
206 virtual ~ModelRegistry() {}
208 static osg::ref_ptr<ModelRegistry> instance;
209 typedef std::map<std::string, osg::ref_ptr<osgDB::Registry::ReadFileCallback> >
211 CallbackMap imageCallbackMap;
212 CallbackMap nodeCallbackMap;
213 osg::ref_ptr<DefaultCallback> _defaultCallback;
216 // Callback that only loads the file without any caching or
218 typedef ModelRegistryCallback<DefaultProcessPolicy, NoCachePolicy,
219 NoOptimizePolicy, NoCopyPolicy,
220 NoSubstitutePolicy> LoadOnlyCallback;
222 // Proxy for registering extension-based callbacks
225 class ModelRegistryCallbackProxy
228 ModelRegistryCallbackProxy(std::string extension)
230 ModelRegistry::getInstance()
231 ->addNodeCallbackForExtension(extension, new T(extension));
235 // Callback for file extensions that load files using the default OSG
238 class OSGFileCallback : public osgDB::Registry::ReadFileCallback {
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);
249 #endif // _SG_MODELREGISTRY_HXX