3 # include <simgear_config.h>
7 #include "Technique.hxx"
15 #include <boost/lexical_cast.hpp>
16 #include <boost/tuple/tuple.hpp>
17 #include <boost/tuple/tuple_comparison.hpp>
19 #include <OpenThreads/ReentrantMutex>
20 #include <OpenThreads/ScopedLock>
22 #include <osg/Material>
23 #include <osg/Program>
24 #include <osg/Referenced>
25 #include <osg/Texture2D>
28 #include <osgDB/FileUtils>
29 #include <osgDB/ReadFile>
30 #include <osgDB/Registry>
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>
42 typedef vector<const SGPropertyNode*> RawPropVector;
43 typedef map<const string, ref_ptr<Effect> > EffectMap;
48 OpenThreads::ReentrantMutex effectMutex;
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.
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.
65 : public unary_function<const SGPropertyNode*, bool>
67 PropPredicate(const SGPropertyNode* node_) : node(node_) {}
68 bool operator()(const SGPropertyNode* arg) const
70 if (strcmp(node->getName(), arg->getName()))
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();
82 const SGPropertyNode* node;
85 void mergePropertyTrees(SGPropertyNode* resultNode,
86 const SGPropertyNode* left, const SGPropertyNode* right)
88 if (left->nChildren() == 0) {
89 copyProperties(left, resultNode);
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);
111 copyProperties(node, newChild);
114 for (RawPropVector::iterator itr = leftChildren.begin(),
115 e = leftChildren.end();
118 SGPropertyNode* newChild
119 = resultNode->getChild((*itr)->getName(),
120 nodeIndex[(*itr)->getName()]++, true);
121 copyProperties(*itr, newChild);
125 Effect* makeEffect(const string& name,
126 bool realizeTechniques,
127 const osgDB::ReaderWriter::Options* options)
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";
136 = osgDB::findDataFile(effectFileName, options);
137 if (absFileName.empty())
139 SGPropertyNode_ptr effectProps = new SGPropertyNode();
140 readProperties(absFileName, effectProps.ptr(), 0, true);
141 Effect* result = makeEffect(effectProps.ptr(), realizeTechniques, options);
143 effectMap.insert(make_pair(name, result));
148 Effect* makeEffect(SGPropertyNode* prop,
149 bool realizeTechniques,
150 const osgDB::ReaderWriter::Options* options)
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));
175 Effect* effect = new Effect;
176 // Merge with the parent effect, if any
177 const SGPropertyNode* inheritProp = prop->getChild("inherits-from");
180 parent = makeEffect(inheritProp->getStringValue(), realizeTechniques,
182 effect->root = new SGPropertyNode;
183 mergePropertyTrees(effect->root, prop, parent->root);
184 effect->root->removeChild("inherits-from");
188 effect->parametersProp = effect->root->getChild("parameters");
189 if (realizeTechniques)
190 effect->realizeTechniques(options);