]> git.mxchange.org Git - simgear.git/blobdiff - simgear/scene/model/ModelRegistry.hxx
Make return type from loadPagedModel explicit.
[simgear.git] / simgear / scene / model / ModelRegistry.hxx
index 770d4ee4f5ed45a135a3e5d0c3dc6c46bf0b1b95..8c8e7467386cd6c7bda347f6678cdb89147f9445 100644 (file)
@@ -1,5 +1,6 @@
 // ModelRegistry.hxx -- interface to the OSG model registry
 //
+// Copyright (C) 2005-2007 Mathias Froehlich 
 // Copyright (C) 2007  Tim Moore <timoore@redhat.com>
 //
 // This program is free software; you can redistribute it and/or
 #define _SG_MODELREGISTRY_HXX 1
 
 #include <osg/ref_ptr>
+#include <osg/Node>
+#include <osgDB/FileUtils>
+#include <osgDB/FileNameUtils>
 #include <osgDB/ReaderWriter>
 #include <osgDB/Registry>
 
 #include <simgear/compiler.h>
+#include <simgear/scene/util/OsgSingleton.hxx>
 
-#include STL_STRING
+#include <string>
 #include <map>
 
+// Class to register per file extension read callbacks with the OSG
+// registry, mostly to control caching and post load optimization /
+// copying that happens above the level of the ReaderWriter.
 namespace simgear
 {
-class ModelRegistry : public osgDB::Registry::ReadFileCallback {
+
+// Different caching and optimization strategies are needed for
+// different file types. Most loaded files should be optimized and the
+// optimized version should be cached. When an .osg file is
+// substituted for another, it is assumed to be optimized already but
+// it should be cached too (under the name of the original?). .stg
+// files should not be cached (that's the pager's job) but the files
+// it causes to be loaded should be. .btg files are already optimized
+// and shouldn't be cached.
+//
+// Complicating this is the effect that removing CACHE_NODES has from
+// the ReaderWriter options: it switches the object cache with an
+// empty one, so that's not an option for the files that could be
+// loaded from a .stg file. So, we'll let
+// Registry::readNodeImplementation cache a loaded file and then add
+// the optimized version to the cache ourselves, replacing the
+// original subgraph.
+//
+// To support all these options with a minimum of duplication, the
+// readNode function is specified as a template with a bunch of
+// pluggable (and predefined) policies.
+template <typename ProcessPolicy, typename CachePolicy, typename OptimizePolicy,
+          typename SubstitutePolicy, typename BVHPolicy>
+class ModelRegistryCallback : public osgDB::Registry::ReadFileCallback {
 public:
+    ModelRegistryCallback(const std::string& extension) :
+        _processPolicy(extension), _cachePolicy(extension),
+        _optimizePolicy(extension),
+        _substitutePolicy(extension), _bvhPolicy(extension)
+    {
+    }
+    virtual osgDB::ReaderWriter::ReadResult
+    readNode(const std::string& fileName,
+             const osgDB::Options* opt)
+    {
+        using namespace osg;
+        using namespace osgDB;
+        using osgDB::ReaderWriter;
+//        Registry* registry = Registry::instance();
+        ref_ptr<osg::Node> optimizedNode = _cachePolicy.find(fileName, opt);
+        if (!optimizedNode.valid()) {
+            std::string otherFileName = _substitutePolicy.substitute(fileName,
+                                                                     opt);
+            ReaderWriter::ReadResult res;
+            if (!otherFileName.empty()) {
+                res = loadUsingReaderWriter(otherFileName, opt);
+                if (res.validNode())
+                    optimizedNode = res.getNode();
+            }
+            if (!optimizedNode.valid()) {
+                res = loadUsingReaderWriter(fileName, opt);
+                if (!res.validNode())
+                    return res;
+                ref_ptr<osg::Node> processedNode
+                    = _processPolicy.process(res.getNode(), fileName, opt);
+                optimizedNode = _optimizePolicy.optimize(processedNode.get(),
+                                                         fileName, opt);
+            }
+            if (opt->getPluginStringData("SimGear::BOUNDINGVOLUMES") != "OFF")
+                _bvhPolicy.buildBVH(fileName, optimizedNode.get());
+            _cachePolicy.addToCache(fileName, optimizedNode.get());
+        }
+        return ReaderWriter::ReadResult(optimizedNode.get());
+    }
+protected:
+    static osgDB::ReaderWriter::ReadResult
+    loadUsingReaderWriter(const std::string& fileName,
+                          const osgDB::Options* opt)
+    {
+        using namespace osgDB;
+        ReaderWriter* rw = Registry::instance()
+            ->getReaderWriterForExtension(osgDB::getFileExtension(fileName));
+        if (!rw)
+            return ReaderWriter::ReadResult(); // FILE_NOT_HANDLED
+        return rw->readNode(fileName, opt);
+    }
+    
+    ProcessPolicy _processPolicy;
+    CachePolicy _cachePolicy;
+    OptimizePolicy _optimizePolicy;
+    SubstitutePolicy _substitutePolicy;
+    BVHPolicy _bvhPolicy;
+    virtual ~ModelRegistryCallback() {}
+};
+
+// Predefined policies
+
+struct DefaultProcessPolicy {
+    DefaultProcessPolicy(const std::string& extension) {}
+    osg::Node* process(osg::Node* node, const std::string& filename,
+                       const osgDB::Options* opt);
+};
+
+struct DefaultCachePolicy {
+    DefaultCachePolicy(const std::string& extension) {}
+    osg::Node* find(const std::string& fileName,
+                    const osgDB::Options* opt);
+    void addToCache(const std::string& filename, osg::Node* node);
+};
+
+struct NoCachePolicy {
+    NoCachePolicy(const std::string& extension) {}
+    osg::Node* find(const std::string& fileName,
+                    const osgDB::Options* opt)
+    {
+        return 0;
+    }
+    void addToCache(const std::string& filename, osg::Node* node) {}
+};
+
+class OptimizeModelPolicy {
+public:
+    OptimizeModelPolicy(const std::string& extension);
+    osg::Node* optimize(osg::Node* node, const std::string& fileName,
+                        const osgDB::Options* opt);
+protected:
+    unsigned _osgOptions;
+};
+
+struct NoOptimizePolicy {
+    NoOptimizePolicy(const std::string& extension) {}
+    osg::Node* optimize(osg::Node* node, const std::string& fileName,
+                        const osgDB::Options* opt)
+    {
+        return node;
+    }
+};
+
+struct OSGSubstitutePolicy {
+    OSGSubstitutePolicy(const std::string& extension) {}
+    std::string substitute(const std::string& name,
+                           const osgDB::Options* opt);
+};
+
+struct NoSubstitutePolicy {
+    NoSubstitutePolicy(const std::string& extension) {}
+    std::string substitute(const std::string& name,
+                           const osgDB::Options* opt)
+    {
+        return std::string();
+    }
+};
+
+struct BuildLeafBVHPolicy {
+    BuildLeafBVHPolicy(const std::string& extension) {}
+    void buildBVH(const std::string& fileName, osg::Node* node);
+};
+
+struct BuildGroupBVHPolicy {
+    BuildGroupBVHPolicy(const std::string& extension) {}
+    void buildBVH(const std::string& fileName, osg::Node* node);
+};
+
+struct NoBuildBVHPolicy {
+    NoBuildBVHPolicy(const std::string& extension) {}
+    void buildBVH(const std::string& fileName, osg::Node* node);
+};
+
+typedef ModelRegistryCallback<DefaultProcessPolicy, DefaultCachePolicy,
+                              OptimizeModelPolicy,
+                              OSGSubstitutePolicy, BuildLeafBVHPolicy>
+DefaultCallback;
+
+// The manager for the callbacks
+class ModelRegistry : public osgDB::Registry::ReadFileCallback,
+                      public ReferencedSingleton<ModelRegistry> {
+public:
+    ModelRegistry();
     virtual osgDB::ReaderWriter::ReadResult
     readImage(const std::string& fileName,
-              const osgDB::ReaderWriter::Options* opt);
+              const osgDB::Options* opt);
     virtual osgDB::ReaderWriter::ReadResult
     readNode(const std::string& fileName,
-             const osgDB::ReaderWriter::Options* opt);
+             const osgDB::Options* opt);
     void addImageCallbackForExtension(const std::string& extension,
                                       osgDB::Registry::ReadFileCallback*
                                       callback);
     void addNodeCallbackForExtension(const std::string& extension,
                                      osgDB::Registry::ReadFileCallback*
                                      callback);
-    static ModelRegistry* getInstance();
+    virtual ~ModelRegistry() {}
 protected:
-    static osg::ref_ptr<ModelRegistry> instance;
     typedef std::map<std::string, osg::ref_ptr<osgDB::Registry::ReadFileCallback> >
     CallbackMap;
     CallbackMap imageCallbackMap;
     CallbackMap nodeCallbackMap;
+    osg::ref_ptr<DefaultCallback> _defaultCallback;
 };
 
+// Callback that only loads the file without any caching or
+// postprocessing.
+typedef ModelRegistryCallback<DefaultProcessPolicy, NoCachePolicy,
+                              NoOptimizePolicy,
+                              NoSubstitutePolicy, BuildLeafBVHPolicy>
+LoadOnlyCallback;
+
 // Proxy for registering extension-based callbacks
 
 template<typename T>
@@ -60,23 +241,9 @@ class ModelRegistryCallbackProxy
 public:
     ModelRegistryCallbackProxy(std::string extension)
     {
-        ModelRegistry::getInstance()->addNodeCallbackForExtension(extension,
-                                                                  new T);
+        ModelRegistry::instance()
+            ->addNodeCallbackForExtension(extension, new T(extension));
     }
 };
-
-// Callback for file extensions that load files using the default OSG
-// implementation.
-
-class OSGFileCallback : public osgDB::Registry::ReadFileCallback {
-public:
-    virtual osgDB::ReaderWriter::ReadResult
-    readImage(const std::string& fileName,
-              const osgDB::ReaderWriter::Options* opt);
-    virtual osgDB::ReaderWriter::ReadResult
-    readNode(const std::string& fileName,
-             const osgDB::ReaderWriter::Options* opt);
-};
-
 }
 #endif // _SG_MODELREGISTRY_HXX