3 # include <simgear_config.h>
7 #include "EffectBuilder.hxx"
8 #include "Technique.hxx"
16 #include <boost/lexical_cast.hpp>
17 #include <boost/tuple/tuple.hpp>
18 #include <boost/tuple/tuple_comparison.hpp>
20 #include <OpenThreads/ReentrantMutex>
21 #include <OpenThreads/ScopedLock>
23 #include <osg/Material>
24 #include <osg/Program>
25 #include <osg/Referenced>
26 #include <osg/Texture2D>
29 #include <osgDB/FileUtils>
30 #include <osgDB/ReadFile>
31 #include <osgDB/Registry>
33 #include <simgear/debug/logstream.hxx>
34 #include <simgear/scene/util/SGReaderWriterOptions.hxx>
35 #include <simgear/props/props_io.hxx>
36 #include <simgear/scene/util/SGSceneFeatures.hxx>
37 #include <simgear/scene/util/SplicingVisitor.hxx>
38 #include <simgear/structure/SGExpression.hxx>
44 using namespace effect;
46 typedef vector<const SGPropertyNode*> RawPropVector;
47 typedef map<const string, ref_ptr<Effect> > EffectMap;
52 OpenThreads::ReentrantMutex effectMutex;
55 /** Merge two property trees, producing a new tree.
56 * If the nodes are both leaves, value comes from left leaf.
57 * Otherwise, The children are examined. If a left and right child are
58 * "identical," they are merged and the result placed in the children
59 * of the result. Otherwise the left children are placed after the
60 * right children in the result.
62 * Nodes are considered equal if their names and indexes are equal.
66 : public unary_function<const SGPropertyNode*, bool>
68 PropPredicate(const SGPropertyNode* node_) : node(node_) {}
69 bool operator()(const SGPropertyNode* arg) const
71 if (strcmp(node->getName(), arg->getName()))
73 return node->getIndex() == arg->getIndex();
75 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 // Merge identical nodes
92 for (int i = 0; i < right->nChildren(); ++i) {
93 const SGPropertyNode* node = right->getChild(i);
94 RawPropVector::iterator litr
95 = find_if(leftChildren.begin(), leftChildren.end(),
97 SGPropertyNode* newChild
98 = resultNode->getChild(node->getName(), node->getIndex(), true);
99 if (litr != leftChildren.end()) {
100 mergePropertyTrees(newChild, *litr, node);
101 leftChildren.erase(litr);
103 copyProperties(node, newChild);
106 // Now copy nodes remaining in the left tree
107 for (RawPropVector::iterator itr = leftChildren.begin(),
108 e = leftChildren.end();
111 SGPropertyNode* newChild
112 = resultNode->getChild((*itr)->getName(), (*itr)->getIndex(), true);
113 copyProperties(*itr, newChild);
118 Effect* makeEffect(const string& name,
119 bool realizeTechniques,
120 const SGReaderWriterOptions* options)
123 OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(effectMutex);
124 EffectMap::iterator itr = effectMap.find(name);
125 if ((itr != effectMap.end())&&
127 return itr->second.get();
129 string effectFileName(name);
130 effectFileName += ".eff";
132 = SGModelLib::findDataFile(effectFileName, options);
133 if (absFileName.empty()) {
134 SG_LOG(SG_INPUT, SG_ALERT, "can't find \"" << effectFileName << "\"");
137 SGPropertyNode_ptr effectProps = new SGPropertyNode();
139 readProperties(absFileName, effectProps.ptr(), 0, true);
141 catch (sg_io_exception& e) {
142 SG_LOG(SG_INPUT, SG_ALERT, "error reading \"" << absFileName << "\": "
143 << e.getFormattedMessage());
146 ref_ptr<Effect> result = makeEffect(effectProps.ptr(), realizeTechniques,
148 if (result.valid()) {
149 OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(effectMutex);
150 pair<EffectMap::iterator, bool> irslt
151 = effectMap.insert(make_pair(name, result));
153 // Another thread beat us to it!. Discard our newly
154 // constructed Effect and use the one in the cache.
155 result = irslt.first->second;
158 return result.release();
162 Effect* makeEffect(SGPropertyNode* prop,
163 bool realizeTechniques,
164 const SGReaderWriterOptions* options)
166 // Give default names to techniques and passes
167 vector<SGPropertyNode_ptr> techniques = prop->getChildren("technique");
168 for (int i = 0; i < (int)techniques.size(); ++i) {
169 SGPropertyNode* tniqProp = techniques[i].ptr();
170 if (!tniqProp->hasChild("name"))
171 setValue(tniqProp->getChild("name", 0, true),
172 boost::lexical_cast<string>(i));
173 vector<SGPropertyNode_ptr> passes = tniqProp->getChildren("pass");
174 for (int j = 0; j < (int)passes.size(); ++j) {
175 SGPropertyNode* passProp = passes[j].ptr();
176 if (!passProp->hasChild("name"))
177 setValue(passProp->getChild("name", 0, true),
178 boost::lexical_cast<string>(j));
179 vector<SGPropertyNode_ptr> texUnits
180 = passProp->getChildren("texture-unit");
181 for (int k = 0; k < (int)texUnits.size(); ++k) {
182 SGPropertyNode* texUnitProp = texUnits[k].ptr();
183 if (!texUnitProp->hasChild("name"))
184 setValue(texUnitProp->getChild("name", 0, true),
185 boost::lexical_cast<string>(k));
189 ref_ptr<Effect> effect;
190 if(!prop->hasChild("name")){
191 setValue(prop->getChild("name", 0, true), "noname");
193 SGPropertyNode_ptr nameProp = prop->getChild("name");
194 // Merge with the parent effect, if any
195 SGPropertyNode_ptr inheritProp = prop->getChild("inherits-from");
198 //prop->removeChild("inherits-from");
199 parent = makeEffect(inheritProp->getStringValue(), false, options);
204 key.paths = options->getDatabasePathList();
206 Effect::Cache* cache = 0;
207 Effect::Cache::iterator itr;
209 OpenThreads::ScopedLock<OpenThreads::ReentrantMutex>
211 cache = parent->getCache();
212 itr = cache->find(key);
213 if ((itr != cache->end())&&
214 itr->second.lock(effect))
216 effect->generator = parent->generator; // Copy the generators
219 if (!effect.valid()) {
221 effect->setName(nameProp->getStringValue());
222 effect->root = new SGPropertyNode;
223 mergePropertyTrees(effect->root, prop, parent->root);
224 effect->parametersProp = effect->root->getChild("parameters");
225 OpenThreads::ScopedLock<OpenThreads::ReentrantMutex>
227 pair<Effect::Cache::iterator, bool> irslt
228 = cache->insert(make_pair(key, effect));
231 if (irslt.first->second.lock(old))
232 effect = old; // Another thread beat us in creating it! Discard our own...
234 irslt.first->second = effect; // update existing, but empty observer
236 effect->generator = parent->generator; // Copy the generators
239 SG_LOG(SG_INPUT, SG_ALERT, "can't find base effect " <<
240 inheritProp->getStringValue());
245 effect->setName(nameProp->getStringValue());
247 effect->parametersProp = effect->root->getChild("parameters");
249 const SGPropertyNode *generateProp = prop->getChild("generate");
252 effect->generator.clear();
254 // Effect needs some generated properties, like tangent vectors
255 const SGPropertyNode *parameter = generateProp->getChild("normal");
256 if(parameter) effect->setGenerator(Effect::NORMAL, parameter->getIntValue());
258 parameter = generateProp->getChild("tangent");
259 if(parameter) effect->setGenerator(Effect::TANGENT, parameter->getIntValue());
261 parameter = generateProp->getChild("binormal");
262 if(parameter) effect->setGenerator(Effect::BINORMAL, parameter->getIntValue());
264 if (realizeTechniques) {
266 OpenThreads::ScopedLock<OpenThreads::ReentrantMutex>
268 effect->realizeTechniques(options);
270 catch (BuilderException& e) {
271 SG_LOG(SG_INPUT, SG_ALERT, "Error building technique: "
272 << e.getFormattedMessage());
276 return effect.release();
279 void clearEffectCache()
281 OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(effectMutex);