]> git.mxchange.org Git - simgear.git/blob - simgear/scene/material/makeEffect.cxx
Effects in models working for transparent materials and chrome animation
[simgear.git] / simgear / scene / material / makeEffect.cxx
1
2 #ifdef HAVE_CONFIG_H
3 #  include <simgear_config.h>
4 #endif
5
6 #include "Effect.hxx"
7 #include "Technique.hxx"
8 #include "Pass.hxx"
9
10 #include <algorithm>
11 #include <cstring>
12 #include <map>
13 #include <sstream>
14
15 #include <boost/lexical_cast.hpp>
16 #include <boost/tuple/tuple.hpp>
17 #include <boost/tuple/tuple_comparison.hpp>
18
19 #include <OpenThreads/ReentrantMutex>
20 #include <OpenThreads/ScopedLock>
21
22 #include <osg/Material>
23 #include <osg/Program>
24 #include <osg/Referenced>
25 #include <osg/Texture2D>
26 #include <osg/Vec4d>
27
28 #include <osgDB/FileUtils>
29 #include <osgDB/ReadFile>
30 #include <osgDB/Registry>
31
32 #include <simgear/debug/logstream.hxx>
33 #include <simgear/props/props_io.hxx>
34 #include <simgear/scene/util/SGSceneFeatures.hxx>
35 #include <simgear/scene/util/SplicingVisitor.hxx>
36 #include <simgear/structure/SGExpression.hxx>
37
38 namespace simgear
39 {
40 using namespace std;
41 using namespace osg;
42 using namespace effect;
43
44 typedef vector<const SGPropertyNode*> RawPropVector;
45 typedef map<const string, ref_ptr<Effect> > EffectMap;
46
47 namespace
48 {
49 EffectMap effectMap;
50 OpenThreads::ReentrantMutex effectMutex;
51 }
52
53 /** Merge two property trees, producing a new tree.
54  * If the nodes are both leaves, value comes from left leaf.
55  * Otherwise, The children are examined. If a left and right child are
56  * "identical," they are merged and the result placed in the children
57  * of the result. Otherwise the left children are placed after the
58  * right children in the result.
59  *
60  * Nodes are considered equal if their names and indexes are equal.
61  */
62
63 struct PropPredicate
64     : public unary_function<const SGPropertyNode*, bool>
65 {
66     PropPredicate(const SGPropertyNode* node_) : node(node_) {}
67     bool operator()(const SGPropertyNode* arg) const
68     {
69         if (strcmp(node->getName(), arg->getName()))
70             return false;
71         return node->getIndex() == arg->getIndex();
72     }
73     const SGPropertyNode* node;
74 };
75
76 namespace effect
77 {
78 void mergePropertyTrees(SGPropertyNode* resultNode,
79                         const SGPropertyNode* left, const SGPropertyNode* right)
80 {
81     if (left->nChildren() == 0) {
82         copyProperties(left, resultNode);
83         return;
84     }
85     resultNode->setAttributes(right->getAttributes());
86     RawPropVector leftChildren;
87     for (int i = 0; i < left->nChildren(); ++i)
88         leftChildren.push_back(left->getChild(i));
89     // Merge identical nodes
90     for (int i = 0; i < right->nChildren(); ++i) {
91         const SGPropertyNode* node = right->getChild(i);
92         RawPropVector::iterator litr
93             = find_if(leftChildren.begin(), leftChildren.end(),
94                       PropPredicate(node));
95         SGPropertyNode* newChild
96             = resultNode->getChild(node->getName(), node->getIndex(), true);
97         if (litr != leftChildren.end()) {
98             mergePropertyTrees(newChild, *litr, node);
99             leftChildren.erase(litr);
100         } else {
101             copyProperties(node, newChild);
102         }
103     }
104     // Now copy nodes remaining in the left tree
105     for (RawPropVector::iterator itr = leftChildren.begin(),
106              e = leftChildren.end();
107          itr != e;
108          ++itr) {
109         SGPropertyNode* newChild
110             = resultNode->getChild((*itr)->getName(), (*itr)->getIndex(), true);
111         copyProperties(*itr, newChild);
112     }
113 }
114 }
115
116 Effect* makeEffect(const string& name,
117                    bool realizeTechniques,
118                    const osgDB::ReaderWriter::Options* options)
119 {
120     OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(effectMutex);
121     EffectMap::iterator itr = effectMap.find(name);
122     if (itr != effectMap.end())
123         return itr->second.get();
124     string effectFileName(name);
125     effectFileName += ".eff";
126     string absFileName
127         = osgDB::findDataFile(effectFileName, options);
128     if (absFileName.empty()) {
129         SG_LOG(SG_INPUT, SG_WARN, "can't find \"" << effectFileName << "\"");
130         return 0;
131     }
132     SGPropertyNode_ptr effectProps = new SGPropertyNode();
133     readProperties(absFileName, effectProps.ptr(), 0, true);
134     Effect* result = makeEffect(effectProps.ptr(), realizeTechniques, options);
135     if (result)
136         effectMap.insert(make_pair(name, result));
137     return result;
138 }
139
140
141 Effect* makeEffect(SGPropertyNode* prop,
142                    bool realizeTechniques,
143                    const osgDB::ReaderWriter::Options* options)
144 {
145     // Give default names to techniques and passes
146     vector<SGPropertyNode_ptr> techniques = prop->getChildren("technique");
147     for (int i = 0; i < (int)techniques.size(); ++i) {
148         SGPropertyNode* tniqProp = techniques[i].ptr();
149         if (!tniqProp->hasChild("name"))
150             setValue(tniqProp->getChild("name", 0, true),
151                      boost::lexical_cast<string>(i));
152         vector<SGPropertyNode_ptr> passes = tniqProp->getChildren("pass");
153         for (int j = 0; j < (int)passes.size(); ++j) {
154             SGPropertyNode* passProp = passes[j].ptr();
155             if (!passProp->hasChild("name"))
156                 setValue(passProp->getChild("name", 0, true),
157                          boost::lexical_cast<string>(j));
158             vector<SGPropertyNode_ptr> texUnits
159                 = passProp->getChildren("texture-unit");
160             for (int k = 0; k < (int)texUnits.size(); ++k) {
161                 SGPropertyNode* texUnitProp = texUnits[k].ptr();
162                 if (!texUnitProp->hasChild("name"))
163                     setValue(texUnitProp->getChild("name", 0, true),
164                              boost::lexical_cast<string>(k));
165             }
166         }
167     }
168     Effect* effect = new Effect;
169     // Merge with the parent effect, if any
170     const SGPropertyNode* inheritProp = prop->getChild("inherits-from");
171     Effect* parent = 0;
172     if (inheritProp) {
173         parent = makeEffect(inheritProp->getStringValue(), false,
174                             options);
175         if(parent)
176         {
177             effect->root = new SGPropertyNode;
178             mergePropertyTrees(effect->root, prop, parent->root);
179             effect->root->removeChild("inherits-from");
180         } else {
181             effect->root = prop;
182             effect->root->removeChild("inherits-from");
183         }
184     } else {
185         effect->root = prop;
186     }
187     effect->parametersProp = effect->root->getChild("parameters");
188     if (realizeTechniques)
189         effect->realizeTechniques(options);
190     return effect;
191 }
192
193 }