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::Registry::instance()->findDataFile(effectFileName, options,
132 osgDB::CASE_SENSITIVE);
133 if (absFileName.empty())
135 SGPropertyNode_ptr effectProps = new SGPropertyNode();
136 readProperties(absFileName, effectProps.ptr(), 0, true);
137 Effect* result = makeEffect(effectProps.ptr(), realizeTechniques, options);
139 effectMap.insert(make_pair(name, result));
144 Effect* makeEffect(SGPropertyNode* prop,
145 bool realizeTechniques,
146 const osgDB::ReaderWriter::Options* options)
148 // Give default names to techniques and passes
149 vector<SGPropertyNode_ptr> techniques = prop->getChildren("technique");
150 for (int i = 0; i < techniques.size(); ++i) {
151 SGPropertyNode* tniqProp = techniques[i].ptr();
152 if (!tniqProp->hasChild("name"))
153 setValue(tniqProp->getChild("name", 0, true),
154 boost::lexical_cast<string>(i));
155 vector<SGPropertyNode_ptr> passes = tniqProp->getChildren("pass");
156 for (int j = 0; j < passes.size(); ++j) {
157 SGPropertyNode* passProp = passes[j].ptr();
158 if (!passProp->hasChild("name"))
159 setValue(passProp->getChild("name", 0, true),
160 boost::lexical_cast<string>(j));
161 vector<SGPropertyNode_ptr> texUnits
162 = passProp->getChildren("texture-unit");
163 for (int k = 0; k < texUnits.size(); ++k) {
164 SGPropertyNode* texUnitProp = texUnits[k].ptr();
165 if (!texUnitProp->hasChild("name"))
166 setValue(texUnitProp->getChild("name", 0, true),
167 boost::lexical_cast<string>(k));
171 Effect* effect = new Effect;
172 // Merge with the parent effect, if any
173 const SGPropertyNode* inheritProp = prop->getChild("inherits-from");
176 parent = makeEffect(inheritProp->getStringValue(), realizeTechniques,
178 effect->root = new SGPropertyNode;
179 mergePropertyTrees(effect->root, prop, parent->root);
180 effect->root->removeChild("inherits-from");
184 effect->parametersProp = effect->root->getChild("parameters");
185 if (realizeTechniques)
186 effect->realizeTechniques(options);