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/scene/util/SplicingVisitor.hxx>
36 #include <simgear/structure/SGExpression.hxx>
43 typedef vector<const SGPropertyNode*> RawPropVector;
44 typedef map<const string, ref_ptr<Effect> > EffectMap;
49 OpenThreads::ReentrantMutex effectMutex;
52 /** Merge two property trees, producing a new tree.
53 * If the nodes are both leaves, value comes from left leaf.
54 * Otherwise, The children are examined. If a left and right child are
55 * "identical," they are merged and the result placed in the children
56 * of the result. Otherwise the left children are placed after the
57 * right children in the result.
59 * Nodes are considered equal if their names and indexes are equal.
63 : public unary_function<const SGPropertyNode*, bool>
65 PropPredicate(const SGPropertyNode* node_) : node(node_) {}
66 bool operator()(const SGPropertyNode* arg) const
68 if (strcmp(node->getName(), arg->getName()))
70 return node->getIndex() == arg->getIndex();
72 const SGPropertyNode* node;
75 void mergePropertyTrees(SGPropertyNode* resultNode,
76 const SGPropertyNode* left, const SGPropertyNode* right)
78 if (left->nChildren() == 0) {
79 copyProperties(left, resultNode);
82 resultNode->setAttributes(right->getAttributes());
83 RawPropVector leftChildren;
84 for (int i = 0; i < left->nChildren(); ++i)
85 leftChildren.push_back(left->getChild(i));
86 // Merge identical nodes
87 for (int i = 0; i < right->nChildren(); ++i) {
88 const SGPropertyNode* node = right->getChild(i);
89 RawPropVector::iterator litr
90 = find_if(leftChildren.begin(), leftChildren.end(),
92 SGPropertyNode* newChild
93 = resultNode->getChild(node->getName(), node->getIndex(), true);
94 if (litr != leftChildren.end()) {
95 mergePropertyTrees(newChild, *litr, node);
96 leftChildren.erase(litr);
98 copyProperties(node, newChild);
101 // Now copy nodes remaining in the left tree
102 for (RawPropVector::iterator itr = leftChildren.begin(),
103 e = leftChildren.end();
106 SGPropertyNode* newChild
107 = resultNode->getChild((*itr)->getName(), (*itr)->getIndex(), true);
108 copyProperties(*itr, newChild);
112 Effect* makeEffect(const string& name,
113 bool realizeTechniques,
114 const osgDB::ReaderWriter::Options* options)
116 OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(effectMutex);
117 EffectMap::iterator itr = effectMap.find(name);
118 if (itr != effectMap.end())
119 return itr->second.get();
120 string effectFileName(name);
121 effectFileName += ".eff";
123 = osgDB::findDataFile(effectFileName, options);
124 if (absFileName.empty()) {
125 SG_LOG(SG_INPUT, SG_WARN, "can't find \"" << effectFileName << "\"");
128 SGPropertyNode_ptr effectProps = new SGPropertyNode();
129 readProperties(absFileName, effectProps.ptr(), 0, true);
130 Effect* result = makeEffect(effectProps.ptr(), realizeTechniques, options);
132 effectMap.insert(make_pair(name, result));
137 Effect* makeEffect(SGPropertyNode* prop,
138 bool realizeTechniques,
139 const osgDB::ReaderWriter::Options* options)
141 // Give default names to techniques and passes
142 vector<SGPropertyNode_ptr> techniques = prop->getChildren("technique");
143 for (int i = 0; i < (int)techniques.size(); ++i) {
144 SGPropertyNode* tniqProp = techniques[i].ptr();
145 if (!tniqProp->hasChild("name"))
146 setValue(tniqProp->getChild("name", 0, true),
147 boost::lexical_cast<string>(i));
148 vector<SGPropertyNode_ptr> passes = tniqProp->getChildren("pass");
149 for (int j = 0; j < (int)passes.size(); ++j) {
150 SGPropertyNode* passProp = passes[j].ptr();
151 if (!passProp->hasChild("name"))
152 setValue(passProp->getChild("name", 0, true),
153 boost::lexical_cast<string>(j));
154 vector<SGPropertyNode_ptr> texUnits
155 = passProp->getChildren("texture-unit");
156 for (int k = 0; k < (int)texUnits.size(); ++k) {
157 SGPropertyNode* texUnitProp = texUnits[k].ptr();
158 if (!texUnitProp->hasChild("name"))
159 setValue(texUnitProp->getChild("name", 0, true),
160 boost::lexical_cast<string>(k));
164 Effect* effect = new Effect;
165 // Merge with the parent effect, if any
166 const SGPropertyNode* inheritProp = prop->getChild("inherits-from");
169 parent = makeEffect(inheritProp->getStringValue(), realizeTechniques,
173 effect->root = new SGPropertyNode;
174 mergePropertyTrees(effect->root, prop, parent->root);
175 effect->root->removeChild("inherits-from");
178 effect->root->removeChild("inherits-from");
183 effect->parametersProp = effect->root->getChild("parameters");
184 if (realizeTechniques)
185 effect->realizeTechniques(options);