]> git.mxchange.org Git - simgear.git/blob - simgear/scene/material/makeEffect.cxx
wip for effects in models
[simgear.git] / simgear / scene / material / makeEffect.cxx
1
2 #ifdef HAVE_CONFIG_H
3 #  include <simgear_config.h>
4 #endif
5
6 #include "Effect.hxx"
7 #include "Technique.hxx"
8 #include "Pass.hxx"
9
10 #include <algorithm>
11 #include <cstring>
12 #include <map>
13 #include <sstream>
14
15 #include <boost/lexical_cast.hpp>
16 #include <boost/tuple/tuple.hpp>
17 #include <boost/tuple/tuple_comparison.hpp>
18
19 #include <OpenThreads/ReentrantMutex>
20 #include <OpenThreads/ScopedLock>
21
22 #include <osg/Material>
23 #include <osg/Program>
24 #include <osg/Referenced>
25 #include <osg/Texture2D>
26 #include <osg/Vec4d>
27
28 #include <osgDB/FileUtils>
29 #include <osgDB/ReadFile>
30 #include <osgDB/Registry>
31
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>
37
38 namespace simgear
39 {
40 using namespace std;
41 using namespace osg;
42
43 typedef vector<const SGPropertyNode*> RawPropVector;
44 typedef map<const string, ref_ptr<Effect> > EffectMap;
45
46 namespace
47 {
48 EffectMap effectMap;
49 OpenThreads::ReentrantMutex effectMutex;
50 }
51
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.
58  *
59  * Nodes are considered equal if their names and indexes are equal.
60  */
61
62 struct PropPredicate
63     : public unary_function<const SGPropertyNode*, bool>
64 {
65     PropPredicate(const SGPropertyNode* node_) : node(node_) {}
66     bool operator()(const SGPropertyNode* arg) const
67     {
68         if (strcmp(node->getName(), arg->getName()))
69             return false;
70         return node->getIndex() == arg->getIndex();
71     }
72     const SGPropertyNode* node;
73 };
74
75 void mergePropertyTrees(SGPropertyNode* resultNode,
76                         const SGPropertyNode* left, const SGPropertyNode* right)
77 {
78     if (left->nChildren() == 0) {
79         copyProperties(left, resultNode);
80         return;
81     }
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(),
91                       PropPredicate(node));
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);
97         } else {
98             copyProperties(node, newChild);
99         }
100     }
101     // Now copy nodes remaining in the left tree
102     for (RawPropVector::iterator itr = leftChildren.begin(),
103              e = leftChildren.end();
104          itr != e;
105          ++itr) {
106         SGPropertyNode* newChild
107             = resultNode->getChild((*itr)->getName(), (*itr)->getIndex(), true);
108         copyProperties(*itr, newChild);
109     }
110 }
111
112 Effect* makeEffect(const string& name,
113                    bool realizeTechniques,
114                    const osgDB::ReaderWriter::Options* options)
115 {
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";
122     string absFileName
123         = osgDB::findDataFile(effectFileName, options);
124     if (absFileName.empty()) {
125         SG_LOG(SG_INPUT, SG_WARN, "can't find \"" << effectFileName << "\"");
126         return 0;
127     }
128     SGPropertyNode_ptr effectProps = new SGPropertyNode();
129     readProperties(absFileName, effectProps.ptr(), 0, true);
130     Effect* result = makeEffect(effectProps.ptr(), realizeTechniques, options);
131     if (result)
132         effectMap.insert(make_pair(name, result));
133     return result;
134 }
135
136
137 Effect* makeEffect(SGPropertyNode* prop,
138                    bool realizeTechniques,
139                    const osgDB::ReaderWriter::Options* options)
140 {
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));
161             }
162         }
163     }
164     Effect* effect = new Effect;
165     // Merge with the parent effect, if any
166     const SGPropertyNode* inheritProp = prop->getChild("inherits-from");
167     Effect* parent = 0;
168     if (inheritProp) {
169         parent = makeEffect(inheritProp->getStringValue(), realizeTechniques,
170                             options);
171         if(parent)
172         {
173             effect->root = new SGPropertyNode;
174             mergePropertyTrees(effect->root, prop, parent->root);
175             effect->root->removeChild("inherits-from");
176         } else {
177             effect->root = prop;
178             effect->root->removeChild("inherits-from");
179         }
180     } else {
181         effect->root = prop;
182     }
183     effect->parametersProp = effect->root->getChild("parameters");
184     if (realizeTechniques)
185         effect->realizeTechniques(options);
186     return effect;
187 }
188
189 }