]> git.mxchange.org Git - simgear.git/blob - simgear/scene/material/makeEffect.cxx
Compile latest SimGear under MSVC9
[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/structure/SGExpression.hxx>
36
37 namespace simgear
38 {
39 using namespace std;
40 using namespace osg;
41
42 typedef vector<const SGPropertyNode*> RawPropVector;
43 typedef map<const string, ref_ptr<Effect> > EffectMap;
44
45 namespace
46 {
47 EffectMap effectMap;
48 OpenThreads::ReentrantMutex effectMutex;
49 }
50
51 /** Merge two property trees, producing a new tree.
52  * If the nodes are both leaves, value comes from left leaf.
53  * Otherwise, The children are examined. If a left and right child are
54  * "identical," they are merged and the result placed in the children
55  * of the result. Otherwise the left children are placed after the
56  * right children in the result.
57  *
58  * Nodes are considered identical if:
59  * Their names are equal;
60  * Either they both have "name" children and their values are equal;
61  * or their indexes are equal.
62  */
63
64 struct PropPredicate
65     : public unary_function<const SGPropertyNode*, bool>
66 {
67     PropPredicate(const SGPropertyNode* node_) : node(node_) {}
68     bool operator()(const SGPropertyNode* arg) const
69     {
70         if (strcmp(node->getName(), arg->getName()))
71             return false;
72         const SGPropertyNode* nodeName = node->getChild("name");
73         const SGPropertyNode* argName = arg->getChild("name");
74         if (nodeName && argName)
75             return !strcmp(nodeName->getStringValue(),
76                            argName->getStringValue());
77         else if (!(nodeName || argName))
78             return node->getIndex() == arg->getIndex();
79         else
80             return false;
81     }
82     const SGPropertyNode* node;
83 };
84
85 void mergePropertyTrees(SGPropertyNode* resultNode,
86                         const SGPropertyNode* left, const SGPropertyNode* right)
87 {
88     if (left->nChildren() == 0) {
89         copyProperties(left, resultNode);
90         return;
91     }
92     resultNode->setAttributes(right->getAttributes());
93     RawPropVector leftChildren;
94     for (int i = 0; i < left->nChildren(); ++i)
95         leftChildren.push_back(left->getChild(i));
96     // Maximum index of nodes (with same names) we've created.
97     map<string, int> nodeIndex;
98     // Merge identical nodes
99     for (int i = 0; i < right->nChildren(); ++i) {
100         const SGPropertyNode* node = right->getChild(i);
101         RawPropVector::iterator litr
102             = find_if(leftChildren.begin(), leftChildren.end(),
103                       PropPredicate(node));
104         SGPropertyNode* newChild
105             = resultNode->getChild(node->getName(),
106                                    nodeIndex[node->getName()]++, true);
107         if (litr != leftChildren.end()) {
108             mergePropertyTrees(newChild, *litr, node);
109             leftChildren.erase(litr);
110         } else {
111             copyProperties(node, newChild);
112         }
113     }
114     for (RawPropVector::iterator itr = leftChildren.begin(),
115              e = leftChildren.end();
116          itr != e;
117          ++itr) {
118         SGPropertyNode* newChild
119             = resultNode->getChild((*itr)->getName(),
120                                    nodeIndex[(*itr)->getName()]++, true);
121         copyProperties(*itr, newChild);
122     }
123 }
124
125 Effect* makeEffect(const string& name,
126                    bool realizeTechniques,
127                    const osgDB::ReaderWriter::Options* options)
128 {
129     OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(effectMutex);
130     EffectMap::iterator itr = effectMap.find(name);
131     if (itr != effectMap.end())
132         return itr->second.get();
133     string effectFileName(name);
134     effectFileName += ".eff";
135     string absFileName
136         = osgDB::findDataFile(effectFileName, options);
137     if (absFileName.empty())
138         return 0;
139     SGPropertyNode_ptr effectProps = new SGPropertyNode();
140     readProperties(absFileName, effectProps.ptr(), 0, true);
141     Effect* result = makeEffect(effectProps.ptr(), realizeTechniques, options);
142     if (result)
143         effectMap.insert(make_pair(name, result));
144     return result;
145 }
146
147
148 Effect* makeEffect(SGPropertyNode* prop,
149                    bool realizeTechniques,
150                    const osgDB::ReaderWriter::Options* options)
151 {
152     // Give default names to techniques and passes
153     vector<SGPropertyNode_ptr> techniques = prop->getChildren("technique");
154     for (int i = 0; i < techniques.size(); ++i) {
155         SGPropertyNode* tniqProp = techniques[i].ptr();
156         if (!tniqProp->hasChild("name"))
157             setValue(tniqProp->getChild("name", 0, true),
158                      boost::lexical_cast<string>(i));
159         vector<SGPropertyNode_ptr> passes = tniqProp->getChildren("pass");
160         for (int j = 0; j < passes.size(); ++j) {
161             SGPropertyNode* passProp = passes[j].ptr();
162             if (!passProp->hasChild("name"))
163                 setValue(passProp->getChild("name", 0, true),
164                          boost::lexical_cast<string>(j));
165             vector<SGPropertyNode_ptr> texUnits
166                 = passProp->getChildren("texture-unit");
167             for (int k = 0; k < texUnits.size(); ++k) {
168                 SGPropertyNode* texUnitProp = texUnits[k].ptr();
169                 if (!texUnitProp->hasChild("name"))
170                     setValue(texUnitProp->getChild("name", 0, true),
171                              boost::lexical_cast<string>(k));
172             }
173         }
174     }
175     Effect* effect = new Effect;
176     // Merge with the parent effect, if any
177     const SGPropertyNode* inheritProp = prop->getChild("inherits-from");
178     Effect* parent = 0;
179     if (inheritProp) {
180         parent = makeEffect(inheritProp->getStringValue(), realizeTechniques,
181                             options);
182         effect->root = new SGPropertyNode;
183         mergePropertyTrees(effect->root, prop, parent->root);
184         effect->root->removeChild("inherits-from");
185     } else {
186         effect->root = prop;
187     }
188     effect->parametersProp = effect->root->getChild("parameters");
189     if (realizeTechniques)
190         effect->realizeTechniques(options);
191     return effect;
192 }
193
194 }