]> git.mxchange.org Git - simgear.git/blobdiff - simgear/scene/model/model.cxx
Improove texture sharing.
[simgear.git] / simgear / scene / model / model.cxx
index 1d278f7ee63faeb0647185340c8f7c057a6a6bd4..749b45c3f7d2a023a85f9b908f01a0c0c00e8db8 100644 (file)
@@ -136,6 +136,9 @@ public:
     if (!texture)
       return;
     
+    // Hmm, true??
+    texture->setDataVariance(osg::Object::STATIC);
+
     osg::Image* image = texture->getImage(0);
     if (!image)
       return;
@@ -207,28 +210,47 @@ public:
   readNode(const std::string& fileName,
            const osgDB::ReaderWriter::Options* opt)
   {
-    std::string absFileName = osgDB::findDataFile(fileName);
+    osgDB::Registry* registry = osgDB::Registry::instance();
+    osgDB::ReaderWriter::ReadResult res;
+    osg::Node* cached = 0;
+    // The BTG loader automatically looks for ".btg.gz" if a file with
+    // the .btg extension doesn't exist. Also, we don't want to add
+    // nodes, run the optimizer, etc. on the btg model.So, let it do
+    // its thing.
+    if (osgDB::equalCaseInsensitive(osgDB::getFileExtension(fileName), "btg")) {
+      return registry->readNodeImplementation(fileName, opt);
+    }
+    // First, look for a file with the same name, and the extension
+    // ".osg" and, if it exists, load it instead. This allows for
+    // substitution of optimized models for ones named in the scenery.
+    bool optimizeModel = true;
+    std::string fileSansExtension = osgDB::getNameLessExtension(fileName);
+    std::string osgFileName = fileSansExtension + ".osg";
+    std::string absFileName = osgDB::findDataFile(osgFileName);
+    if (osgDB::fileExists(absFileName)) {
+      optimizeModel = false;
+    } else {
+      absFileName = osgDB::findDataFile(fileName);
+    }
     if (!osgDB::fileExists(absFileName)) {
       SG_LOG(SG_IO, SG_ALERT, "Cannot find model file \""
              << fileName << "\"");
       return osgDB::ReaderWriter::ReadResult::FILE_NOT_FOUND;
     }
-
-    osgDB::Registry* registry = osgDB::Registry::instance();
-    osgDB::ReaderWriter::ReadResult res;
-    res = registry->readNodeImplementation(absFileName, opt);
-    if (!res.validNode())
-      return res;
-
-    if (res.loadedFromCache()) {
-      SG_LOG(SG_IO, SG_INFO, "Returning cached model \""
+    cached
+        = dynamic_cast<osg::Node*>(registry->getFromObjectCache(absFileName));
+    if (cached) {
+      SG_LOG(SG_IO, SG_INFO, "Got cached model \""
              << absFileName << "\"");
     } else {
       SG_LOG(SG_IO, SG_INFO, "Reading model \""
              << absFileName << "\"");
+      res = registry->readNodeImplementation(absFileName, opt);
+      if (!res.validNode())
+        return res;
 
       bool needTristrip = true;
-      if (osgDB::getLowerCaseFileExtension(absFileName) == "ac") {
+      if (osgDB::getLowerCaseFileExtension(fileName) == "ac") {
         // we get optimal geometry from the loader.
         needTristrip = false;
         osg::Matrix m(1, 0, 0, 0,
@@ -245,10 +267,12 @@ public:
         transform->addChild(res.getNode());
         
         res = osgDB::ReaderWriter::ReadResult(0);
-        
-        osgUtil::Optimizer optimizer;
-        unsigned opts = osgUtil::Optimizer::FLATTEN_STATIC_TRANSFORMS;
-        optimizer.optimize(root.get(), opts);
+
+        if (optimizeModel) {
+          osgUtil::Optimizer optimizer;
+          unsigned opts = osgUtil::Optimizer::FLATTEN_STATIC_TRANSFORMS;
+          optimizer.optimize(root.get(), opts);
+        }
 
         // strip away unneeded groups
         if (root->getNumChildren() == 1 && root->getName().empty()) {
@@ -267,26 +291,27 @@ public:
         SGAcMaterialCrippleVisitor matCriple;
         res.getNode()->accept(matCriple);
       }
-      
-      osgUtil::Optimizer optimizer;
-      unsigned opts = 0;
-      // Don't use this one. It will break animation names ...
-      // opts |= osgUtil::Optimizer::REMOVE_REDUNDANT_NODES;
-
-      // opts |= osgUtil::Optimizer::REMOVE_LOADED_PROXY_NODES;
-      // opts |= osgUtil::Optimizer::COMBINE_ADJACENT_LODS;
-      // opts |= osgUtil::Optimizer::SHARE_DUPLICATE_STATE;
-      opts |= osgUtil::Optimizer::MERGE_GEOMETRY;
-      // opts |= osgUtil::Optimizer::CHECK_GEOMETRY;
-      // opts |= osgUtil::Optimizer::SPATIALIZE_GROUPS;
-      // opts |= osgUtil::Optimizer::COPY_SHARED_NODES;
-      opts |= osgUtil::Optimizer::FLATTEN_STATIC_TRANSFORMS;
-      if (needTristrip)
-        opts |= osgUtil::Optimizer::TRISTRIP_GEOMETRY;
-      // opts |= osgUtil::Optimizer::TESSELATE_GEOMETRY;
-      // opts |= osgUtil::Optimizer::OPTIMIZE_TEXTURE_SETTINGS;
-      optimizer.optimize(res.getNode(), opts);
 
+      if (optimizeModel) {
+        osgUtil::Optimizer optimizer;
+        unsigned opts = 0;
+        // Don't use this one. It will break animation names ...
+        // opts |= osgUtil::Optimizer::REMOVE_REDUNDANT_NODES;
+
+        // opts |= osgUtil::Optimizer::REMOVE_LOADED_PROXY_NODES;
+        // opts |= osgUtil::Optimizer::COMBINE_ADJACENT_LODS;
+        // opts |= osgUtil::Optimizer::SHARE_DUPLICATE_STATE;
+        opts |= osgUtil::Optimizer::MERGE_GEOMETRY;
+        // opts |= osgUtil::Optimizer::CHECK_GEOMETRY;
+        // opts |= osgUtil::Optimizer::SPATIALIZE_GROUPS;
+        // opts |= osgUtil::Optimizer::COPY_SHARED_NODES;
+        opts |= osgUtil::Optimizer::FLATTEN_STATIC_TRANSFORMS;
+        if (needTristrip)
+          opts |= osgUtil::Optimizer::TRISTRIP_GEOMETRY;
+        // opts |= osgUtil::Optimizer::TESSELATE_GEOMETRY;
+        // opts |= osgUtil::Optimizer::OPTIMIZE_TEXTURE_SETTINGS;
+        optimizer.optimize(res.getNode(), opts);
+      }
       // Make sure the data variance of sharable objects is set to STATIC ...
       SGTexDataVarianceVisitor dataVarianceVisitor;
       res.getNode()->accept(dataVarianceVisitor);
@@ -295,15 +320,16 @@ public:
       
       SGTexCompressionVisitor texComp;
       res.getNode()->accept(texComp);
+      cached = res.getNode();
+      registry->addEntryToObjectCache(absFileName, cached);
     }
-
     // Add an extra reference to the model stored in the database.
     // That it to avoid expiring the object from the cache even if it is still
     // in use. Note that the object cache will think that a model is unused
     // if the reference count is 1. If we clone all structural nodes here
     // we need that extra reference to the original object
     SGDatabaseReference* databaseReference;
-    databaseReference = new SGDatabaseReference(res.getNode());
+    databaseReference = new SGDatabaseReference(cached);
     osg::CopyOp::CopyFlags flags = osg::CopyOp::DEEP_COPY_ALL;
     flags &= ~osg::CopyOp::DEEP_COPY_TEXTURES;
     flags &= ~osg::CopyOp::DEEP_COPY_IMAGES;
@@ -312,7 +338,7 @@ public:
     // This will safe display lists ...
     flags &= ~osg::CopyOp::DEEP_COPY_DRAWABLES;
     flags &= ~osg::CopyOp::DEEP_COPY_SHAPES;
-    res = osgDB::ReaderWriter::ReadResult(osg::CopyOp(flags)(res.getNode()));
+    res = osgDB::ReaderWriter::ReadResult(osg::CopyOp(flags)(cached));
     res.getNode()->addObserver(databaseReference);
 
     // Update liveries
@@ -337,7 +363,11 @@ public:
 
     osgDB::Registry* registry = osgDB::Registry::instance();
     osgDB::ReaderWriter::Options* options = new osgDB::ReaderWriter::Options;
-    options->setObjectCacheHint(osgDB::ReaderWriter::Options::CACHE_ALL);
+    // We manage node caching ourselves
+    int cacheOptions = osgDB::ReaderWriter::Options::CACHE_ALL
+      & ~osgDB::ReaderWriter::Options::CACHE_NODES;
+    options->
+      setObjectCacheHint((osgDB::ReaderWriter::Options::CacheHintOptions)cacheOptions);
     registry->setOptions(options);
     registry->getOrCreateSharedStateManager()->setShareMode(osgDB::SharedStateManager::SHARE_TEXTURES);
     registry->setReadFileCallback(new SGReadFileCallback);
@@ -352,6 +382,7 @@ SGLoadTexture2D(const std::string& path, bool wrapu, bool wrapv, int)
   osg::Image* image = osgDB::readImageFile(path);
   osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
   texture->setImage(image);
+  texture->setDataVariance(osg::Object::STATIC);
   if (wrapu)
     texture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
   else
@@ -381,7 +412,7 @@ SGLoadTexture2D(const std::string& path, bool wrapu, bool wrapv, int)
 
     // OSGFIXME: don't forget that mutex here
     osgDB::Registry* registry = osgDB::Registry::instance();
-    registry->getOrCreateSharedStateManager()->share(tmpNode.get(), 0);
+    registry->getSharedStateManager()->share(tmpNode.get(), 0);
 
     // should be the same, but be paranoid ...
     stateSet = tmpNode->getStateSet();