00001
00002 #ifdef HAVE_CONFIG_H
00003 # include <simgear_config.h>
00004 #endif
00005
00006 #include "Effect.hxx"
00007 #include "EffectBuilder.hxx"
00008 #include "Technique.hxx"
00009 #include "Pass.hxx"
00010
00011 #include <algorithm>
00012 #include <cstring>
00013 #include <map>
00014 #include <sstream>
00015
00016 #include <boost/lexical_cast.hpp>
00017 #include <boost/tuple/tuple.hpp>
00018 #include <boost/tuple/tuple_comparison.hpp>
00019
00020 #include <OpenThreads/ReentrantMutex>
00021 #include <OpenThreads/ScopedLock>
00022
00023 #include <osg/Material>
00024 #include <osg/Program>
00025 #include <osg/Referenced>
00026 #include <osg/Texture2D>
00027 #include <osg/Vec4d>
00028
00029 #include <osgDB/FileUtils>
00030 #include <osgDB/ReadFile>
00031 #include <osgDB/Registry>
00032
00033 #include <simgear/debug/logstream.hxx>
00034 #include <simgear/props/props_io.hxx>
00035 #include <simgear/scene/util/SGSceneFeatures.hxx>
00036 #include <simgear/scene/util/SplicingVisitor.hxx>
00037 #include <simgear/structure/SGExpression.hxx>
00038
00039 namespace simgear
00040 {
00041 using namespace std;
00042 using namespace osg;
00043 using namespace effect;
00044
00045 typedef vector<const SGPropertyNode*> RawPropVector;
00046 typedef map<const string, ref_ptr<Effect> > EffectMap;
00047
00048 namespace
00049 {
00050 EffectMap effectMap;
00051 OpenThreads::ReentrantMutex effectMutex;
00052 }
00053
00064 struct PropPredicate
00065 : public unary_function<const SGPropertyNode*, bool>
00066 {
00067 PropPredicate(const SGPropertyNode* node_) : node(node_) {}
00068 bool operator()(const SGPropertyNode* arg) const
00069 {
00070 if (strcmp(node->getName(), arg->getName()))
00071 return false;
00072 return node->getIndex() == arg->getIndex();
00073 }
00074 const SGPropertyNode* node;
00075 };
00076
00077 namespace effect
00078 {
00079 void mergePropertyTrees(SGPropertyNode* resultNode,
00080 const SGPropertyNode* left, const SGPropertyNode* right)
00081 {
00082 if (left->nChildren() == 0) {
00083 copyProperties(left, resultNode);
00084 return;
00085 }
00086 resultNode->setAttributes(right->getAttributes());
00087 RawPropVector leftChildren;
00088 for (int i = 0; i < left->nChildren(); ++i)
00089 leftChildren.push_back(left->getChild(i));
00090
00091 for (int i = 0; i < right->nChildren(); ++i) {
00092 const SGPropertyNode* node = right->getChild(i);
00093 RawPropVector::iterator litr
00094 = find_if(leftChildren.begin(), leftChildren.end(),
00095 PropPredicate(node));
00096 SGPropertyNode* newChild
00097 = resultNode->getChild(node->getName(), node->getIndex(), true);
00098 if (litr != leftChildren.end()) {
00099 mergePropertyTrees(newChild, *litr, node);
00100 leftChildren.erase(litr);
00101 } else {
00102 copyProperties(node, newChild);
00103 }
00104 }
00105
00106 for (RawPropVector::iterator itr = leftChildren.begin(),
00107 e = leftChildren.end();
00108 itr != e;
00109 ++itr) {
00110 SGPropertyNode* newChild
00111 = resultNode->getChild((*itr)->getName(), (*itr)->getIndex(), true);
00112 copyProperties(*itr, newChild);
00113 }
00114 }
00115 }
00116
00117 Effect* makeEffect(const string& name,
00118 bool realizeTechniques,
00119 const osgDB::ReaderWriter::Options* options)
00120 {
00121 {
00122 OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(effectMutex);
00123 EffectMap::iterator itr = effectMap.find(name);
00124 if (itr != effectMap.end())
00125 return itr->second.get();
00126 }
00127 string effectFileName(name);
00128 effectFileName += ".eff";
00129 string absFileName
00130 = osgDB::findDataFile(effectFileName, options);
00131 if (absFileName.empty()) {
00132 SG_LOG(SG_INPUT, SG_ALERT, "can't find \"" << effectFileName << "\"");
00133 return 0;
00134 }
00135 SGPropertyNode_ptr effectProps = new SGPropertyNode();
00136 try {
00137 readProperties(absFileName, effectProps.ptr(), 0, true);
00138 }
00139 catch (sg_io_exception& e) {
00140 SG_LOG(SG_INPUT, SG_ALERT, "error reading \"" << absFileName << "\": "
00141 << e.getFormattedMessage());
00142 return 0;
00143 }
00144 ref_ptr<Effect> result = makeEffect(effectProps.ptr(), realizeTechniques,
00145 options);
00146 if (result.valid()) {
00147 OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(effectMutex);
00148 pair<EffectMap::iterator, bool> irslt
00149 = effectMap.insert(make_pair(name, result));
00150 if (!irslt.second) {
00151
00152
00153 result = irslt.first->second;
00154 }
00155 }
00156 return result.release();
00157 }
00158
00159
00160 Effect* makeEffect(SGPropertyNode* prop,
00161 bool realizeTechniques,
00162 const osgDB::ReaderWriter::Options* options)
00163 {
00164
00165 vector<SGPropertyNode_ptr> techniques = prop->getChildren("technique");
00166 for (int i = 0; i < (int)techniques.size(); ++i) {
00167 SGPropertyNode* tniqProp = techniques[i].ptr();
00168 if (!tniqProp->hasChild("name"))
00169 setValue(tniqProp->getChild("name", 0, true),
00170 boost::lexical_cast<string>(i));
00171 vector<SGPropertyNode_ptr> passes = tniqProp->getChildren("pass");
00172 for (int j = 0; j < (int)passes.size(); ++j) {
00173 SGPropertyNode* passProp = passes[j].ptr();
00174 if (!passProp->hasChild("name"))
00175 setValue(passProp->getChild("name", 0, true),
00176 boost::lexical_cast<string>(j));
00177 vector<SGPropertyNode_ptr> texUnits
00178 = passProp->getChildren("texture-unit");
00179 for (int k = 0; k < (int)texUnits.size(); ++k) {
00180 SGPropertyNode* texUnitProp = texUnits[k].ptr();
00181 if (!texUnitProp->hasChild("name"))
00182 setValue(texUnitProp->getChild("name", 0, true),
00183 boost::lexical_cast<string>(k));
00184 }
00185 }
00186 }
00187 ref_ptr<Effect> effect;
00188
00189 SGPropertyNode_ptr inheritProp = prop->getChild("inherits-from");
00190 Effect* parent = 0;
00191 if (inheritProp) {
00192
00193 parent = makeEffect(inheritProp->getStringValue(), false, options);
00194 if (parent) {
00195 Effect::Key key;
00196 key.unmerged = prop;
00197 if (options) {
00198 key.paths = options->getDatabasePathList();
00199 }
00200 Effect::Cache* cache = 0;
00201 Effect::Cache::iterator itr;
00202 {
00203 OpenThreads::ScopedLock<OpenThreads::ReentrantMutex>
00204 lock(effectMutex);
00205 cache = parent->getCache();
00206 itr = cache->find(key);
00207 if (itr != cache->end())
00208 effect = itr->second.get();
00209 }
00210 if (!effect.valid()) {
00211 effect = new Effect;
00212 effect->root = new SGPropertyNode;
00213 mergePropertyTrees(effect->root, prop, parent->root);
00214 effect->parametersProp = effect->root->getChild("parameters");
00215 OpenThreads::ScopedLock<OpenThreads::ReentrantMutex>
00216 lock(effectMutex);
00217 pair<Effect::Cache::iterator, bool> irslt
00218 = cache->insert(make_pair(key, effect));
00219 if (!irslt.second)
00220 effect = irslt.first->second;
00221 }
00222 } else {
00223 SG_LOG(SG_INPUT, SG_ALERT, "can't find base effect " <<
00224 inheritProp->getStringValue());
00225 return 0;
00226 }
00227 } else {
00228 effect = new Effect;
00229 effect->root = prop;
00230 effect->parametersProp = effect->root->getChild("parameters");
00231 }
00232 if (realizeTechniques) {
00233 try {
00234 OpenThreads::ScopedLock<OpenThreads::ReentrantMutex>
00235 lock(effectMutex);
00236 effect->realizeTechniques(options);
00237 }
00238 catch (BuilderException& e) {
00239 SG_LOG(SG_INPUT, SG_ALERT, "Error building technique: "
00240 << e.getFormattedMessage());
00241 return 0;
00242 }
00243 }
00244 return effect.release();
00245 }
00246
00247 }