]> git.mxchange.org Git - simgear.git/blobdiff - simgear/scene/material/makeEffect.cxx
Random buildings - initial commit.
[simgear.git] / simgear / scene / material / makeEffect.cxx
index 7745cd976cc9a716bd1722b410b0dc71b0a2d516..06bf47b229b1d8d118816f85a3c60a2f63e41e53 100644 (file)
@@ -1,4 +1,10 @@
+
+#ifdef HAVE_CONFIG_H
+#  include <simgear_config.h>
+#endif
+
 #include "Effect.hxx"
+#include "EffectBuilder.hxx"
 #include "Technique.hxx"
 #include "Pass.hxx"
 
 #include <osgDB/Registry>
 
 #include <simgear/debug/logstream.hxx>
+#include <simgear/scene/util/SGReaderWriterOptions.hxx>
 #include <simgear/props/props_io.hxx>
 #include <simgear/scene/util/SGSceneFeatures.hxx>
+#include <simgear/scene/util/SplicingVisitor.hxx>
 #include <simgear/structure/SGExpression.hxx>
 
 namespace simgear
 {
 using namespace std;
 using namespace osg;
+using namespace effect;
 
 typedef vector<const SGPropertyNode*> RawPropVector;
 typedef map<const string, ref_ptr<Effect> > EffectMap;
@@ -50,10 +59,7 @@ OpenThreads::ReentrantMutex effectMutex;
  * of the result. Otherwise the left children are placed after the
  * right children in the result.
  *
- * Nodes are considered identical if:
- * Their names are equal;
- * Either they both have "name" children and their values are equal;
- * or their indexes are equal.
+ * Nodes are considered equal if their names and indexes are equal.
  */
 
 struct PropPredicate
@@ -64,19 +70,13 @@ struct PropPredicate
     {
         if (strcmp(node->getName(), arg->getName()))
             return false;
-        const SGPropertyNode* nodeName = node->getChild("name");
-        const SGPropertyNode* argName = arg->getChild("name");
-        if (nodeName && argName)
-            return !strcmp(nodeName->getStringValue(),
-                           argName->getStringValue());
-        else if (!(nodeName || argName))
-            return node->getIndex() == arg->getIndex();
-        else
-            return false;
+        return node->getIndex() == arg->getIndex();
     }
     const SGPropertyNode* node;
 };
 
+namespace effect
+{
 void mergePropertyTrees(SGPropertyNode* resultNode,
                         const SGPropertyNode* left, const SGPropertyNode* right)
 {
@@ -88,8 +88,6 @@ void mergePropertyTrees(SGPropertyNode* resultNode,
     RawPropVector leftChildren;
     for (int i = 0; i < left->nChildren(); ++i)
         leftChildren.push_back(left->getChild(i));
-    // Maximum index of nodes (with same names) we've created.
-    map<string, int> nodeIndex;
     // Merge identical nodes
     for (int i = 0; i < right->nChildren(); ++i) {
         const SGPropertyNode* node = right->getChild(i);
@@ -97,8 +95,7 @@ void mergePropertyTrees(SGPropertyNode* resultNode,
             = find_if(leftChildren.begin(), leftChildren.end(),
                       PropPredicate(node));
         SGPropertyNode* newChild
-            = resultNode->getChild(node->getName(),
-                                   nodeIndex[node->getName()]++, true);
+            = resultNode->getChild(node->getName(), node->getIndex(), true);
         if (litr != leftChildren.end()) {
             mergePropertyTrees(newChild, *litr, node);
             leftChildren.erase(litr);
@@ -106,61 +103,82 @@ void mergePropertyTrees(SGPropertyNode* resultNode,
             copyProperties(node, newChild);
         }
     }
+    // Now copy nodes remaining in the left tree
     for (RawPropVector::iterator itr = leftChildren.begin(),
              e = leftChildren.end();
          itr != e;
          ++itr) {
         SGPropertyNode* newChild
-            = resultNode->getChild((*itr)->getName(),
-                                   nodeIndex[(*itr)->getName()]++, true);
+            = resultNode->getChild((*itr)->getName(), (*itr)->getIndex(), true);
         copyProperties(*itr, newChild);
     }
 }
+}
 
 Effect* makeEffect(const string& name,
                    bool realizeTechniques,
-                   const osgDB::ReaderWriter::Options* options)
+                   const SGReaderWriterOptions* options)
 {
-    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(effectMutex);
-    EffectMap::iterator itr = effectMap.find(name);
-    if (itr != effectMap.end())
-        return itr->second.get();
+    {
+        OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(effectMutex);
+        EffectMap::iterator itr = effectMap.find(name);
+        if ((itr != effectMap.end())&&
+            itr->second.valid())
+            return itr->second.get();
+    }
     string effectFileName(name);
     effectFileName += ".eff";
     string absFileName
-        = osgDB::Registry::instance()->findDataFile(effectFileName, options,
-                                                    osgDB::CASE_SENSITIVE);
-    if (absFileName.empty())
+        = SGModelLib::findDataFile(effectFileName, options);
+    if (absFileName.empty()) {
+        SG_LOG(SG_INPUT, SG_ALERT, "can't find \"" << effectFileName << "\"");
         return 0;
+    }
     SGPropertyNode_ptr effectProps = new SGPropertyNode();
-    readProperties(absFileName, effectProps.ptr(), 0, true);
-    Effect* result = makeEffect(effectProps.ptr(), realizeTechniques, options);
-    if (result)
-        effectMap.insert(make_pair(name, result));
-    return result;
+    try {
+        readProperties(absFileName, effectProps.ptr(), 0, true);
+    }
+    catch (sg_io_exception& e) {
+        SG_LOG(SG_INPUT, SG_ALERT, "error reading \"" << absFileName << "\": "
+               << e.getFormattedMessage());
+        return 0;
+    }
+    ref_ptr<Effect> result = makeEffect(effectProps.ptr(), realizeTechniques,
+                                        options);
+    if (result.valid()) {
+        OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(effectMutex);
+        pair<EffectMap::iterator, bool> irslt
+            = effectMap.insert(make_pair(name, result));
+        if (!irslt.second) {
+            // Another thread beat us to it!. Discard our newly
+            // constructed Effect and use the one in the cache.
+            result = irslt.first->second;
+        }
+    }
+    return result.release();
 }
 
 
 Effect* makeEffect(SGPropertyNode* prop,
                    bool realizeTechniques,
-                   const osgDB::ReaderWriter::Options* options)
+                   const SGReaderWriterOptions* options)
 {
     // Give default names to techniques and passes
     vector<SGPropertyNode_ptr> techniques = prop->getChildren("technique");
-    for (int i = 0; i < techniques.size(); ++i) {
+    for (int i = 0; i < (int)techniques.size(); ++i) {
         SGPropertyNode* tniqProp = techniques[i].ptr();
         if (!tniqProp->hasChild("name"))
             setValue(tniqProp->getChild("name", 0, true),
                      boost::lexical_cast<string>(i));
         vector<SGPropertyNode_ptr> passes = tniqProp->getChildren("pass");
-        for (int j = 0; j < passes.size(); ++j) {
+        for (int j = 0; j < (int)passes.size(); ++j) {
             SGPropertyNode* passProp = passes[j].ptr();
             if (!passProp->hasChild("name"))
                 setValue(passProp->getChild("name", 0, true),
                          boost::lexical_cast<string>(j));
             vector<SGPropertyNode_ptr> texUnits
                 = passProp->getChildren("texture-unit");
-            for (int k = 0; k < texUnits.size(); ++k) {
+            for (int k = 0; k < (int)texUnits.size(); ++k) {
                 SGPropertyNode* texUnitProp = texUnits[k].ptr();
                 if (!texUnitProp->hasChild("name"))
                     setValue(texUnitProp->getChild("name", 0, true),
@@ -168,23 +186,88 @@ Effect* makeEffect(SGPropertyNode* prop,
             }
         }
     }
-    Effect* effect = new Effect;
+    ref_ptr<Effect> effect;
     // Merge with the parent effect, if any
-    const SGPropertyNode* inheritProp = prop->getChild("inherits-from");
+    SGPropertyNode_ptr inheritProp = prop->getChild("inherits-from");
     Effect* parent = 0;
     if (inheritProp) {
-        parent = makeEffect(inheritProp->getStringValue(), realizeTechniques,
-                            options);
-        effect->root = new SGPropertyNode;
-        mergePropertyTrees(effect->root, prop, parent->root);
-        effect->root->removeChild("inherits-from");
+        //prop->removeChild("inherits-from");
+        parent = makeEffect(inheritProp->getStringValue(), false, options);
+        if (parent) {
+            Effect::Key key;
+            key.unmerged = prop;
+            if (options) {
+                key.paths = options->getDatabasePathList();
+            }
+            Effect::Cache* cache = 0;
+            Effect::Cache::iterator itr;
+            {
+                OpenThreads::ScopedLock<OpenThreads::ReentrantMutex>
+                    lock(effectMutex);
+                cache = parent->getCache();
+                itr = cache->find(key);
+                if ((itr != cache->end())&&
+                    itr->second.lock(effect))
+                {
+                    effect->generator = parent->generator;  // Copy the generators
+                }
+            }
+            if (!effect.valid()) {
+                effect = new Effect;
+                effect->root = new SGPropertyNode;
+                mergePropertyTrees(effect->root, prop, parent->root);
+                effect->parametersProp = effect->root->getChild("parameters");
+                OpenThreads::ScopedLock<OpenThreads::ReentrantMutex>
+                    lock(effectMutex);
+                pair<Effect::Cache::iterator, bool> irslt
+                    = cache->insert(make_pair(key, effect));
+                if (!irslt.second) {
+                    ref_ptr<Effect> old;
+                    if (irslt.first->second.lock(old))
+                        effect = old; // Another thread beat us in creating it! Discard our own...
+                    else
+                        irslt.first->second = effect; // update existing, but empty observer
+                }
+                effect->generator = parent->generator;  // Copy the generators
+            }
+        } else {
+            SG_LOG(SG_INPUT, SG_ALERT, "can't find base effect " <<
+                   inheritProp->getStringValue());
+            return 0;
+        }
     } else {
+        effect = new Effect;
         effect->root = prop;
+        effect->parametersProp = effect->root->getChild("parameters");
+    }
+    const SGPropertyNode *generateProp = prop->getChild("generate");
+    if(generateProp)
+    {
+        effect->generator.clear();
+
+        // Effect needs some generated properties, like tangent vectors
+        const SGPropertyNode *parameter = generateProp->getChild("normal");
+        if(parameter) effect->setGenerator(Effect::NORMAL, parameter->getIntValue());
+
+        parameter = generateProp->getChild("tangent");
+        if(parameter) effect->setGenerator(Effect::TANGENT, parameter->getIntValue());
+
+        parameter = generateProp->getChild("binormal");
+        if(parameter) effect->setGenerator(Effect::BINORMAL, parameter->getIntValue());
+    }
+    if (realizeTechniques) {
+        try {
+            OpenThreads::ScopedLock<OpenThreads::ReentrantMutex>
+                lock(effectMutex);
+            effect->realizeTechniques(options);
+        }
+        catch (BuilderException& e) {
+            SG_LOG(SG_INPUT, SG_ALERT, "Error building technique: "
+                   << e.getFormattedMessage());
+            return 0;
+        }
     }
-    effect->parametersProp = effect->root->getChild("parameters");
-    if (realizeTechniques)
-        effect->realizeTechniques(options);
-    return effect;
+    return effect.release();
 }
 
 }