2 #include "Technique.hxx"
10 #include <boost/lexical_cast.hpp>
11 #include <boost/tuple/tuple.hpp>
12 #include <boost/tuple/tuple_comparison.hpp>
14 #include <OpenThreads/ReentrantMutex>
15 #include <OpenThreads/ScopedLock>
17 #include <osg/Material>
18 #include <osg/Program>
19 #include <osg/Referenced>
20 #include <osg/Texture2D>
23 #include <osgDB/FileUtils>
24 #include <osgDB/ReadFile>
25 #include <osgDB/Registry>
27 #include <simgear/debug/logstream.hxx>
28 #include <simgear/props/props_io.hxx>
29 #include <simgear/scene/util/SGSceneFeatures.hxx>
30 #include <simgear/structure/SGExpression.hxx>
37 typedef vector<const SGPropertyNode*> RawPropVector;
38 typedef map<const string, ref_ptr<Effect> > EffectMap;
43 OpenThreads::ReentrantMutex effectMutex;
46 /** Merge two property trees, producing a new tree.
47 * If the nodes are both leaves, value comes from left leaf.
48 * Otherwise, The children are examined. If a left and right child are
49 * "identical," they are merged and the result placed in the children
50 * of the result. Otherwise the left children are placed after the
51 * right children in the result.
53 * Nodes are considered identical if:
54 * Their names are equal;
55 * Either they both have "name" children and their values are equal;
56 * or their indexes are equal.
60 : public unary_function<const SGPropertyNode*, bool>
62 PropPredicate(const SGPropertyNode* node_) : node(node_) {}
63 bool operator()(const SGPropertyNode* arg) const
65 if (strcmp(node->getName(), arg->getName()))
67 const SGPropertyNode* nodeName = node->getChild("name");
68 const SGPropertyNode* argName = arg->getChild("name");
69 if (nodeName && argName)
70 return !strcmp(nodeName->getStringValue(),
71 argName->getStringValue());
72 else if (!(nodeName || argName))
73 return node->getIndex() == arg->getIndex();
77 const SGPropertyNode* node;
80 void mergePropertyTrees(SGPropertyNode* resultNode,
81 const SGPropertyNode* left, const SGPropertyNode* right)
83 if (left->nChildren() == 0) {
84 copyProperties(left, resultNode);
87 resultNode->setAttributes(right->getAttributes());
88 RawPropVector leftChildren;
89 for (int i = 0; i < left->nChildren(); ++i)
90 leftChildren.push_back(left->getChild(i));
91 // Maximum index of nodes (with same names) we've created.
92 map<string, int> nodeIndex;
93 // Merge identical nodes
94 for (int i = 0; i < right->nChildren(); ++i) {
95 const SGPropertyNode* node = right->getChild(i);
96 RawPropVector::iterator litr
97 = find_if(leftChildren.begin(), leftChildren.end(),
99 SGPropertyNode* newChild
100 = resultNode->getChild(node->getName(),
101 nodeIndex[node->getName()]++, true);
102 if (litr != leftChildren.end()) {
103 mergePropertyTrees(newChild, *litr, node);
104 leftChildren.erase(litr);
106 copyProperties(node, newChild);
109 for (RawPropVector::iterator itr = leftChildren.begin(),
110 e = leftChildren.end();
113 SGPropertyNode* newChild
114 = resultNode->getChild((*itr)->getName(),
115 nodeIndex[(*itr)->getName()]++, true);
116 copyProperties(*itr, newChild);
120 Effect* makeEffect(const string& name,
121 bool realizeTechniques,
122 const osgDB::ReaderWriter::Options* options)
124 OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(effectMutex);
125 EffectMap::iterator itr = effectMap.find(name);
126 if (itr != effectMap.end())
127 return itr->second.get();
128 string effectFileName(name);
129 effectFileName += ".eff";
131 = osgDB::findDataFile(effectFileName, options);
132 if (absFileName.empty())
134 SGPropertyNode_ptr effectProps = new SGPropertyNode();
135 readProperties(absFileName, effectProps.ptr(), 0, true);
136 Effect* result = makeEffect(effectProps.ptr(), realizeTechniques, options);
138 effectMap.insert(make_pair(name, result));
143 Effect* makeEffect(SGPropertyNode* prop,
144 bool realizeTechniques,
145 const osgDB::ReaderWriter::Options* options)
147 // Give default names to techniques and passes
148 vector<SGPropertyNode_ptr> techniques = prop->getChildren("technique");
149 for (int i = 0; i < techniques.size(); ++i) {
150 SGPropertyNode* tniqProp = techniques[i].ptr();
151 if (!tniqProp->hasChild("name"))
152 setValue(tniqProp->getChild("name", 0, true),
153 boost::lexical_cast<string>(i));
154 vector<SGPropertyNode_ptr> passes = tniqProp->getChildren("pass");
155 for (int j = 0; j < passes.size(); ++j) {
156 SGPropertyNode* passProp = passes[j].ptr();
157 if (!passProp->hasChild("name"))
158 setValue(passProp->getChild("name", 0, true),
159 boost::lexical_cast<string>(j));
160 vector<SGPropertyNode_ptr> texUnits
161 = passProp->getChildren("texture-unit");
162 for (int k = 0; k < texUnits.size(); ++k) {
163 SGPropertyNode* texUnitProp = texUnits[k].ptr();
164 if (!texUnitProp->hasChild("name"))
165 setValue(texUnitProp->getChild("name", 0, true),
166 boost::lexical_cast<string>(k));
170 Effect* effect = new Effect;
171 // Merge with the parent effect, if any
172 const SGPropertyNode* inheritProp = prop->getChild("inherits-from");
175 parent = makeEffect(inheritProp->getStringValue(), realizeTechniques,
177 effect->root = new SGPropertyNode;
178 mergePropertyTrees(effect->root, prop, parent->root);
179 effect->root->removeChild("inherits-from");
183 effect->parametersProp = effect->root->getChild("parameters");
184 if (realizeTechniques)
185 effect->realizeTechniques(options);