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>
42 using namespace effect;
44 typedef vector<const SGPropertyNode*> RawPropVector;
45 typedef map<const string, ref_ptr<Effect> > EffectMap;
50 OpenThreads::ReentrantMutex effectMutex;
53 /** Merge two property trees, producing a new tree.
54 * If the nodes are both leaves, value comes from left leaf.
55 * Otherwise, The children are examined. If a left and right child are
56 * "identical," they are merged and the result placed in the children
57 * of the result. Otherwise the left children are placed after the
58 * right children in the result.
60 * Nodes are considered equal if their names and indexes are equal.
64 : public unary_function<const SGPropertyNode*, bool>
66 PropPredicate(const SGPropertyNode* node_) : node(node_) {}
67 bool operator()(const SGPropertyNode* arg) const
69 if (strcmp(node->getName(), arg->getName()))
71 return node->getIndex() == arg->getIndex();
73 const SGPropertyNode* node;
78 void mergePropertyTrees(SGPropertyNode* resultNode,
79 const SGPropertyNode* left, const SGPropertyNode* right)
81 if (left->nChildren() == 0) {
82 copyProperties(left, resultNode);
85 resultNode->setAttributes(right->getAttributes());
86 RawPropVector leftChildren;
87 for (int i = 0; i < left->nChildren(); ++i)
88 leftChildren.push_back(left->getChild(i));
89 // Merge identical nodes
90 for (int i = 0; i < right->nChildren(); ++i) {
91 const SGPropertyNode* node = right->getChild(i);
92 RawPropVector::iterator litr
93 = find_if(leftChildren.begin(), leftChildren.end(),
95 SGPropertyNode* newChild
96 = resultNode->getChild(node->getName(), node->getIndex(), true);
97 if (litr != leftChildren.end()) {
98 mergePropertyTrees(newChild, *litr, node);
99 leftChildren.erase(litr);
101 copyProperties(node, newChild);
104 // Now copy nodes remaining in the left tree
105 for (RawPropVector::iterator itr = leftChildren.begin(),
106 e = leftChildren.end();
109 SGPropertyNode* newChild
110 = resultNode->getChild((*itr)->getName(), (*itr)->getIndex(), true);
111 copyProperties(*itr, newChild);
116 Effect* makeEffect(const string& name,
117 bool realizeTechniques,
118 const osgDB::ReaderWriter::Options* options)
120 OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(effectMutex);
121 EffectMap::iterator itr = effectMap.find(name);
122 if (itr != effectMap.end())
123 return itr->second.get();
124 string effectFileName(name);
125 effectFileName += ".eff";
127 = osgDB::findDataFile(effectFileName, options);
128 if (absFileName.empty()) {
129 SG_LOG(SG_INPUT, SG_WARN, "can't find \"" << effectFileName << "\"");
132 SGPropertyNode_ptr effectProps = new SGPropertyNode();
133 readProperties(absFileName, effectProps.ptr(), 0, true);
134 Effect* result = makeEffect(effectProps.ptr(), realizeTechniques, options);
136 effectMap.insert(make_pair(name, result));
141 Effect* makeEffect(SGPropertyNode* prop,
142 bool realizeTechniques,
143 const osgDB::ReaderWriter::Options* options)
145 // Give default names to techniques and passes
146 vector<SGPropertyNode_ptr> techniques = prop->getChildren("technique");
147 for (int i = 0; i < (int)techniques.size(); ++i) {
148 SGPropertyNode* tniqProp = techniques[i].ptr();
149 if (!tniqProp->hasChild("name"))
150 setValue(tniqProp->getChild("name", 0, true),
151 boost::lexical_cast<string>(i));
152 vector<SGPropertyNode_ptr> passes = tniqProp->getChildren("pass");
153 for (int j = 0; j < (int)passes.size(); ++j) {
154 SGPropertyNode* passProp = passes[j].ptr();
155 if (!passProp->hasChild("name"))
156 setValue(passProp->getChild("name", 0, true),
157 boost::lexical_cast<string>(j));
158 vector<SGPropertyNode_ptr> texUnits
159 = passProp->getChildren("texture-unit");
160 for (int k = 0; k < (int)texUnits.size(); ++k) {
161 SGPropertyNode* texUnitProp = texUnits[k].ptr();
162 if (!texUnitProp->hasChild("name"))
163 setValue(texUnitProp->getChild("name", 0, true),
164 boost::lexical_cast<string>(k));
169 // Merge with the parent effect, if any
170 SGPropertyNode_ptr inheritProp = prop->getChild("inherits-from");
173 //prop->removeChild("inherits-from");
174 parent = makeEffect(inheritProp->getStringValue(), false, options);
176 Effect::Cache* cache = parent->getCache();
179 key = Effect::Key(prop, options->getDatabasePathList());
181 osgDB::FilePathList dummy;
182 key = Effect::Key(prop, dummy);
184 Effect::Cache::iterator itr = cache->find(key);
185 if (itr != cache->end()) {
186 effect = itr->second.get();
189 effect->root = new SGPropertyNode;
190 mergePropertyTrees(effect->root, prop, parent->root);
191 cache->insert(make_pair(key, effect));
194 SG_LOG(SG_INPUT, SG_WARN, "can't find base effect " <<
195 inheritProp->getStringValue());
202 effect->parametersProp = effect->root->getChild("parameters");
203 if (realizeTechniques)
204 effect->realizeTechniques(options);