1 // Copyright (C) 2008 - 2009 Tim Moore timoore@redhat.com
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Library General Public
5 // License as published by the Free Software Foundation; either
6 // version 2 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Library General Public License for more details.
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 # include <simgear_config.h>
22 #include "EffectBuilder.hxx"
23 #include "Technique.hxx"
25 #include "TextureBuilder.hxx"
33 #include <boost/bind.hpp>
34 #include <boost/foreach.hpp>
35 #include <boost/lexical_cast.hpp>
36 #include <boost/tuple/tuple.hpp>
37 #include <boost/tuple/tuple_comparison.hpp>
39 #include <osg/CullFace>
40 #include <osg/Drawable>
41 #include <osg/Material>
42 #include <osg/PolygonMode>
43 #include <osg/Program>
44 #include <osg/Referenced>
45 #include <osg/RenderInfo>
46 #include <osg/ShadeModel>
47 #include <osg/StateSet>
49 #include <osg/Texture1D>
50 #include <osg/Texture2D>
51 #include <osg/Texture3D>
52 #include <osg/TextureRectangle>
53 #include <osg/Uniform>
55 #include <osgUtil/CullVisitor>
56 #include <osgDB/FileUtils>
57 #include <osgDB/Input>
58 #include <osgDB/ParameterOutput>
59 #include <osgDB/ReadFile>
60 #include <osgDB/Registry>
62 #include <simgear/scene/tgdb/userdata.hxx>
63 #include <simgear/scene/util/SGSceneFeatures.hxx>
64 #include <simgear/scene/util/StateAttributeFactory.hxx>
65 #include <simgear/structure/OSGUtils.hxx>
66 #include <simgear/structure/SGExpression.hxx>
74 using namespace osgUtil;
76 using namespace effect;
82 Effect::Effect(const Effect& rhs, const CopyOp& copyop)
83 : root(rhs.root), parametersProp(rhs.parametersProp)
85 using namespace boost;
86 transform(rhs.techniques.begin(), rhs.techniques.end(),
87 back_inserter(techniques),
88 bind(simgear::clone_ref<Technique>, _1, copyop));
91 // Assume that the last technique is always valid.
92 StateSet* Effect::getDefaultStateSet()
94 Technique* tniq = techniques.back().get();
97 Pass* pass = tniq->passes.front().get();
101 // There should always be a valid technique in an effect.
103 Technique* Effect::chooseTechnique(RenderInfo* info)
105 BOOST_FOREACH(ref_ptr<Technique>& technique, techniques)
107 if (technique->valid(info) == Technique::VALID)
108 return technique.get();
113 void Effect::resizeGLObjectBuffers(unsigned int maxSize)
115 BOOST_FOREACH(const ref_ptr<Technique>& technique, techniques)
117 technique->resizeGLObjectBuffers(maxSize);
121 void Effect::releaseGLObjects(osg::State* state) const
123 BOOST_FOREACH(const ref_ptr<Technique>& technique, techniques)
125 technique->releaseGLObjects(state);
133 class PassAttributeBuilder : public Referenced
136 virtual void buildAttribute(Effect* effect, Pass* pass,
137 const SGPropertyNode* prop,
138 const osgDB::ReaderWriter::Options* options)
142 typedef map<const string, ref_ptr<PassAttributeBuilder> > PassAttrMap;
143 PassAttrMap passAttrMap;
146 struct InstallAttributeBuilder
148 InstallAttributeBuilder(const string& name)
150 passAttrMap.insert(make_pair(name, new T));
154 void buildPass(Effect* effect, Technique* tniq, const SGPropertyNode* prop,
155 const osgDB::ReaderWriter::Options* options)
157 Pass* pass = new Pass;
158 tniq->passes.push_back(pass);
159 for (int i = 0; i < prop->nChildren(); ++i) {
160 const SGPropertyNode* attrProp = prop->getChild(i);
161 PassAttrMap::iterator itr = passAttrMap.find(attrProp->getName());
162 if (itr != passAttrMap.end())
163 itr->second->buildAttribute(effect, pass, attrProp, options);
165 SG_LOG(SG_INPUT, SG_ALERT,
166 "skipping unknown pass attribute " << attrProp->getName());
170 osg::Vec4f getColor(const SGPropertyNode* prop)
172 if (prop->nChildren() == 0) {
173 if (prop->getType() == props::VEC4D) {
174 return osg::Vec4f(toOsg(prop->getValue<SGVec4d>()));
175 } else if (prop->getType() == props::VEC3D) {
176 return osg::Vec4f(toOsg(prop->getValue<SGVec3d>()), 1.0f);
178 SG_LOG(SG_INPUT, SG_ALERT,
179 "invalid color property " << prop->getName() << " "
180 << prop->getStringValue());
181 return osg::Vec4f(0.0f, 0.0f, 0.0f, 1.0f);
185 static const char* colors[] = {"r", "g", "b"};
186 for (int i = 0; i < 3; ++i) {
187 const SGPropertyNode* componentProp = prop->getChild(colors[i]);
188 result[i] = componentProp ? componentProp->getValue<float>() : 0.0f;
190 const SGPropertyNode* alphaProp = prop->getChild("a");
191 result[3] = alphaProp ? alphaProp->getValue<float>() : 1.0f;
196 struct LightingBuilder : public PassAttributeBuilder
198 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
199 const osgDB::ReaderWriter::Options* options);
202 void LightingBuilder::buildAttribute(Effect* effect, Pass* pass,
203 const SGPropertyNode* prop,
204 const osgDB::ReaderWriter::Options* options)
206 const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop);
209 pass->setMode(GL_LIGHTING, (realProp->getValue<bool>() ? StateAttribute::ON
210 : StateAttribute::OFF));
213 InstallAttributeBuilder<LightingBuilder> installLighting("lighting");
215 struct ShadeModelBuilder : public PassAttributeBuilder
217 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
218 const osgDB::ReaderWriter::Options* options)
220 const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop);
223 StateAttributeFactory *attrFact = StateAttributeFactory::instance();
224 string propVal = realProp->getStringValue();
225 if (propVal == "flat")
226 pass->setAttribute(attrFact->getFlatShadeModel());
227 else if (propVal == "smooth")
228 pass->setAttribute(attrFact->getSmoothShadeModel());
230 SG_LOG(SG_INPUT, SG_ALERT,
231 "invalid shade model property " << propVal);
235 InstallAttributeBuilder<ShadeModelBuilder> installShadeModel("shade-model");
237 struct CullFaceBuilder : PassAttributeBuilder
239 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
240 const osgDB::ReaderWriter::Options* options)
242 const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop);
245 StateAttributeFactory *attrFact = StateAttributeFactory::instance();
246 string propVal = realProp->getStringValue();
247 if (propVal == "front")
248 pass->setAttributeAndModes(attrFact->getCullFaceFront());
249 else if (propVal == "back")
250 pass->setAttributeAndModes(attrFact->getCullFaceBack());
251 else if (propVal == "front-back")
252 pass->setAttributeAndModes(new CullFace(CullFace::FRONT_AND_BACK));
254 SG_LOG(SG_INPUT, SG_ALERT,
255 "invalid cull face property " << propVal);
259 InstallAttributeBuilder<CullFaceBuilder> installCullFace("cull-face");
261 struct HintBuilder : public PassAttributeBuilder
263 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
264 const osgDB::ReaderWriter::Options* options)
266 const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop);
269 string propVal = realProp->getStringValue();
270 if (propVal == "opaque")
271 pass->setRenderingHint(StateSet::OPAQUE_BIN);
272 else if (propVal == "transparent")
273 pass->setRenderingHint(StateSet::TRANSPARENT_BIN);
277 InstallAttributeBuilder<HintBuilder> installHint("rendering-hint");
279 struct RenderBinBuilder : public PassAttributeBuilder
281 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
282 const osgDB::ReaderWriter::Options* options)
284 const SGPropertyNode* binProp = prop->getChild("bin-number");
285 binProp = getEffectPropertyNode(effect, binProp);
286 const SGPropertyNode* nameProp = prop->getChild("bin-name");
287 nameProp = getEffectPropertyNode(effect, nameProp);
288 if (binProp && nameProp) {
289 pass->setRenderBinDetails(binProp->getIntValue(),
290 nameProp->getStringValue());
293 SG_LOG(SG_INPUT, SG_ALERT,
294 "No render bin number specified in render bin section");
296 SG_LOG(SG_INPUT, SG_ALERT,
297 "No render bin name specified in render bin section");
302 InstallAttributeBuilder<RenderBinBuilder> installRenderBin("render-bin");
304 struct MaterialBuilder : public PassAttributeBuilder
306 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
307 const osgDB::ReaderWriter::Options* options);
310 EffectNameValue<Material::ColorMode> colorModeInit[] =
312 { "ambient", Material::AMBIENT },
313 { "ambient-and-diffuse", Material::AMBIENT_AND_DIFFUSE },
314 { "diffuse", Material::DIFFUSE },
315 { "emissive", Material::EMISSION },
316 { "specular", Material::SPECULAR },
317 { "off", Material::OFF }
319 EffectPropertyMap<Material::ColorMode> colorModes(colorModeInit);
321 void MaterialBuilder::buildAttribute(Effect* effect, Pass* pass,
322 const SGPropertyNode* prop,
323 const osgDB::ReaderWriter::Options* options)
325 Material* mat = new Material;
326 const SGPropertyNode* color = 0;
327 if ((color = getEffectPropertyChild(effect, prop, "ambient")))
328 mat->setAmbient(Material::FRONT_AND_BACK, getColor(color));
329 if ((color = getEffectPropertyChild(effect, prop, "ambient-front")))
330 mat->setAmbient(Material::FRONT, getColor(color));
331 if ((color = getEffectPropertyChild(effect, prop, "ambient-back")))
332 mat->setAmbient(Material::BACK, getColor(color));
333 if ((color = getEffectPropertyChild(effect, prop, "diffuse")))
334 mat->setDiffuse(Material::FRONT_AND_BACK, getColor(color));
335 if ((color = getEffectPropertyChild(effect, prop, "diffuse-front")))
336 mat->setDiffuse(Material::FRONT, getColor(color));
337 if ((color = getEffectPropertyChild(effect, prop, "diffuse-back")))
338 mat->setDiffuse(Material::BACK, getColor(color));
339 if ((color = getEffectPropertyChild(effect, prop, "specular")))
340 mat->setSpecular(Material::FRONT_AND_BACK, getColor(color));
341 if ((color = getEffectPropertyChild(effect, prop, "specular-front")))
342 mat->setSpecular(Material::FRONT, getColor(color));
343 if ((color = getEffectPropertyChild(effect, prop, "specular-back")))
344 mat->setSpecular(Material::BACK, getColor(color));
345 if ((color = getEffectPropertyChild(effect, prop, "emissive")))
346 mat->setEmission(Material::FRONT_AND_BACK, getColor(color));
347 if ((color = getEffectPropertyChild(effect, prop, "emissive-front")))
348 mat->setEmission(Material::FRONT, getColor(color));
349 if ((color = getEffectPropertyChild(effect, prop, "emissive-back")))
350 mat->setEmission(Material::BACK, getColor(color));
351 const SGPropertyNode* shininess = 0;
352 mat->setShininess(Material::FRONT_AND_BACK, 0.0f);
353 if ((shininess = getEffectPropertyChild(effect, prop, "shininess")))
354 mat->setShininess(Material::FRONT_AND_BACK, shininess->getFloatValue());
355 if ((shininess = getEffectPropertyChild(effect, prop, "shininess-front")))
356 mat->setShininess(Material::FRONT, shininess->getFloatValue());
357 if ((shininess = getEffectPropertyChild(effect, prop, "shininess-back")))
358 mat->setShininess(Material::BACK, shininess->getFloatValue());
359 Material::ColorMode colorMode = Material::OFF;
360 findAttr(colorModes, getEffectPropertyChild(effect, prop, "color-mode"),
362 mat->setColorMode(colorMode);
363 pass->setAttribute(mat);
366 InstallAttributeBuilder<MaterialBuilder> installMaterial("material");
368 struct BlendBuilder : public PassAttributeBuilder
370 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
371 const osgDB::ReaderWriter::Options* options)
373 const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop);
376 pass->setMode(GL_BLEND, (realProp->getBoolValue()
378 : StateAttribute::OFF));
382 InstallAttributeBuilder<BlendBuilder> installBlend("blend");
384 struct AlphaTestBuilder : public PassAttributeBuilder
386 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
387 const osgDB::ReaderWriter::Options* options)
389 const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop);
392 pass->setMode(GL_ALPHA_TEST, (realProp->getBoolValue()
394 : StateAttribute::OFF));
398 InstallAttributeBuilder<AlphaTestBuilder> installAlphaTest("alpha-test");
400 EffectNameValue<TexEnv::Mode> texEnvModesInit[] =
402 {"add", TexEnv::ADD},
403 {"blend", TexEnv::BLEND},
404 {"decal", TexEnv::DECAL},
405 {"modulate", TexEnv::MODULATE},
406 {"replace", TexEnv::REPLACE}
408 EffectPropertyMap<TexEnv::Mode> texEnvModes(texEnvModesInit);
410 TexEnv* buildTexEnv(Effect* effect, const SGPropertyNode* prop)
412 const SGPropertyNode* modeProp = getEffectPropertyChild(effect, prop,
414 const SGPropertyNode* colorProp = getEffectPropertyChild(effect, prop,
418 TexEnv::Mode mode = TexEnv::MODULATE;
419 findAttr(texEnvModes, modeProp, mode);
420 if (mode == TexEnv::MODULATE) {
421 return StateAttributeFactory::instance()->getStandardTexEnv();
423 TexEnv* env = new TexEnv(mode);
425 env->setColor(toOsg(colorProp->getValue<SGVec4d>()));
430 struct TextureUnitBuilder : PassAttributeBuilder
432 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
433 const osgDB::ReaderWriter::Options* options);
436 void TextureUnitBuilder::buildAttribute(Effect* effect, Pass* pass,
437 const SGPropertyNode* prop,
438 const osgDB::ReaderWriter::Options* options)
441 // Decode the texture unit
443 const SGPropertyNode* pUnit = prop->getChild("unit");
445 unit = pUnit->getValue<int>();
447 const SGPropertyNode* pName = prop->getChild("name");
450 unit = boost::lexical_cast<int>(pName->getStringValue());
451 } catch (boost::bad_lexical_cast& lex) {
452 SG_LOG(SG_INPUT, SG_ALERT, "can't decode name as texture unit "
456 const SGPropertyNode* pType = prop->getChild("type");
461 type = pType->getStringValue();
462 Texture* texture = 0;
464 texture = TextureBuilder::buildFromType(effect, type, prop,
467 catch (BuilderException& e) {
468 SG_LOG(SG_INPUT, SG_ALERT, "No image file for texture, using white ");
469 texture = StateAttributeFactory::instance()->getWhiteTexture();
471 pass->setTextureAttributeAndModes(unit, texture);
472 const SGPropertyNode* envProp = prop->getChild("environment");
474 TexEnv* env = buildTexEnv(effect, envProp);
476 pass->setTextureAttributeAndModes(unit, env);
482 InstallAttributeBuilder<TextureUnitBuilder> textureUnitBuilder("texture-unit");
484 typedef map<string, ref_ptr<Program> > ProgramMap;
485 ProgramMap programMap;
487 typedef map<string, ref_ptr<Shader> > ShaderMap;
490 void reload_shaders()
492 for(ShaderMap::iterator sitr = shaderMap.begin(); sitr != shaderMap.end(); ++sitr)
494 Shader *shader = sitr->second.get();
495 string fileName = osgDB::findDataFile(sitr->first);
496 if (!fileName.empty()) {
497 shader->loadShaderSourceFromFile(fileName);
502 struct ShaderProgramBuilder : PassAttributeBuilder
504 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
505 const osgDB::ReaderWriter::Options* options);
508 void ShaderProgramBuilder::buildAttribute(Effect* effect, Pass* pass,
509 const SGPropertyNode* prop,
510 const osgDB::ReaderWriter::Options*
513 PropertyList pVertShaders = prop->getChildren("vertex-shader");
514 PropertyList pFragShaders = prop->getChildren("fragment-shader");
516 for (PropertyList::iterator itr = pVertShaders.begin(),
517 e = pVertShaders.end();
521 programKey += (*itr)->getStringValue();
524 for (PropertyList::iterator itr = pFragShaders.begin(),
525 e = pFragShaders.end();
529 programKey += (*itr)->getStringValue();
532 Program* program = 0;
533 ProgramMap::iterator pitr = programMap.find(programKey);
534 if (pitr != programMap.end()) {
535 program = pitr->second.get();
537 program = new Program;
538 program->setName(programKey);
539 // Add vertex shaders, then fragment shaders
540 PropertyList& pvec = pVertShaders;
541 Shader::Type stype = Shader::VERTEX;
542 for (int i = 0; i < 2; ++i) {
543 for (PropertyList::iterator nameItr = pvec.begin(), e = pvec.end();
546 string shaderName = (*nameItr)->getStringValue();
547 ShaderMap::iterator sitr = shaderMap.find(shaderName);
548 if (sitr != shaderMap.end()) {
549 program->addShader(sitr->second.get());
551 string fileName = osgDB::findDataFile(shaderName, options);
552 if (!fileName.empty()) {
553 ref_ptr<Shader> shader = new Shader(stype);
554 if (shader->loadShaderSourceFromFile(fileName)) {
555 program->addShader(shader.get());
556 shaderMap.insert(make_pair(shaderName, shader));
562 stype = Shader::FRAGMENT;
564 programMap.insert(make_pair(programKey, program));
566 pass->setAttributeAndModes(program);
569 InstallAttributeBuilder<ShaderProgramBuilder> installShaderProgram("program");
571 EffectNameValue<Uniform::Type> uniformTypesInit[] =
573 {"float", Uniform::FLOAT},
574 {"float-vec3", Uniform::FLOAT_VEC3},
575 {"float-vec4", Uniform::FLOAT_VEC4},
576 {"sampler-1d", Uniform::SAMPLER_1D},
577 {"sampler-2d", Uniform::SAMPLER_2D},
578 {"sampler-3d", Uniform::SAMPLER_3D}
580 EffectPropertyMap<Uniform::Type> uniformTypes(uniformTypesInit);
582 struct UniformBuilder :public PassAttributeBuilder
584 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
585 const osgDB::ReaderWriter::Options* options)
587 const SGPropertyNode* nameProp = prop->getChild("name");
588 const SGPropertyNode* typeProp = prop->getChild("type");
589 const SGPropertyNode* valProp
590 = getEffectPropertyChild(effect, prop, "value");
592 Uniform::Type uniformType = Uniform::FLOAT;
594 name = nameProp->getStringValue();
596 SG_LOG(SG_INPUT, SG_ALERT, "No name for uniform property ");
600 SG_LOG(SG_INPUT, SG_ALERT, "No value for uniform property "
605 props::Type propType = valProp->getType();
609 break; // default float type;
611 uniformType = Uniform::FLOAT_VEC3;
614 uniformType = Uniform::FLOAT_VEC4;
617 SG_LOG(SG_INPUT, SG_ALERT, "Can't deduce type of uniform "
622 findAttr(uniformTypes, typeProp, uniformType);
624 ref_ptr<Uniform> uniform = new Uniform;
625 uniform->setName(name);
626 uniform->setType(uniformType);
627 switch (uniformType) {
629 uniform->set(valProp->getValue<float>());
631 case Uniform::FLOAT_VEC3:
632 uniform->set(toOsg(valProp->getValue<SGVec3d>()));
634 case Uniform::FLOAT_VEC4:
635 uniform->set(toOsg(valProp->getValue<SGVec4d>()));
637 case Uniform::SAMPLER_1D:
638 case Uniform::SAMPLER_2D:
639 case Uniform::SAMPLER_3D:
640 uniform->set(valProp->getValue<int>());
642 default: // avoid compiler warning
645 pass->addUniform(uniform.get());
649 InstallAttributeBuilder<UniformBuilder> installUniform("uniform");
651 // Not sure what to do with "name". At one point I wanted to use it to
652 // order the passes, but I do support render bin and stuff too...
654 struct NameBuilder : public PassAttributeBuilder
656 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
657 const osgDB::ReaderWriter::Options* options)
659 // name can't use <use>
660 string name = prop->getStringValue();
666 InstallAttributeBuilder<NameBuilder> installName("name");
668 EffectNameValue<PolygonMode::Mode> polygonModeModesInit[] =
670 {"fill", PolygonMode::FILL},
671 {"line", PolygonMode::LINE},
672 {"point", PolygonMode::POINT}
674 EffectPropertyMap<PolygonMode::Mode> polygonModeModes(polygonModeModesInit);
676 struct PolygonModeBuilder : public PassAttributeBuilder
678 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
679 const osgDB::ReaderWriter::Options* options)
681 const SGPropertyNode* frontProp
682 = getEffectPropertyChild(effect, prop, "front");
683 const SGPropertyNode* backProp
684 = getEffectPropertyChild(effect, prop, "back");
685 ref_ptr<PolygonMode> pmode = new PolygonMode;
686 PolygonMode::Mode frontMode = PolygonMode::FILL;
687 PolygonMode::Mode backMode = PolygonMode::FILL;
689 findAttr(polygonModeModes, frontProp, frontMode);
690 pmode->setMode(PolygonMode::FRONT, frontMode);
693 findAttr(polygonModeModes, backProp, backMode);
694 pmode->setMode(PolygonMode::BACK, backMode);
696 pass->setAttribute(pmode.get());
700 InstallAttributeBuilder<PolygonModeBuilder> installPolygonMode("polygon-mode");
701 void buildTechnique(Effect* effect, const SGPropertyNode* prop,
702 const osgDB::ReaderWriter::Options* options)
704 Technique* tniq = new Technique;
705 effect->techniques.push_back(tniq);
706 const SGPropertyNode* predProp = prop->getChild("predicate");
708 tniq->setAlwaysValid(true);
711 TechniquePredParser parser;
712 parser.setTechnique(tniq);
713 expression::BindingLayout& layout = parser.getBindingLayout();
714 /*int contextLoc = */layout.addBinding("__contextId", expression::INT);
715 SGExpressionb* validExp
716 = dynamic_cast<SGExpressionb*>(parser.read(predProp
719 tniq->setValidExpression(validExp, layout);
721 throw expression::ParseError("technique predicate is not a boolean expression");
723 catch (expression::ParseError& except)
725 SG_LOG(SG_INPUT, SG_ALERT,
726 "parsing technique predicate " << except.getMessage());
727 tniq->setAlwaysValid(false);
730 PropertyList passProps = prop->getChildren("pass");
731 for (PropertyList::iterator itr = passProps.begin(), e = passProps.end();
734 buildPass(effect, tniq, itr->ptr(), options);
738 // Walk the techniques property tree, building techniques and
740 bool Effect::realizeTechniques(const osgDB::ReaderWriter::Options* options)
742 PropertyList tniqList = root->getChildren("technique");
743 for (PropertyList::iterator itr = tniqList.begin(), e = tniqList.end();
746 buildTechnique(this, *itr, options);
750 bool Effect_writeLocalData(const Object& obj, osgDB::Output& fw)
752 const Effect& effect = static_cast<const Effect&>(obj);
754 fw.indent() << "techniques " << effect.techniques.size() << "\n";
755 BOOST_FOREACH(const ref_ptr<Technique>& technique, effect.techniques) {
756 fw.writeObject(*technique);
763 osgDB::RegisterDotOsgWrapperProxy effectProxy
767 "Object simgear::Effect",
769 &Effect_writeLocalData
773 // Property expressions for technique predicates
774 class PropertyExpression : public SGExpression<bool>
777 PropertyExpression(SGPropertyNode* pnode) : _pnode(pnode) {}
779 void eval(bool& value, const expression::Binding*) const
781 value = _pnode->getValue<bool>();
784 SGPropertyNode_ptr _pnode;
787 class EffectPropertyListener : public SGPropertyChangeListener
790 EffectPropertyListener(Technique* tniq) : _tniq(tniq) {}
792 void valueChanged(SGPropertyNode* node)
794 _tniq->refreshValidity();
797 osg::ref_ptr<Technique> _tniq;
800 Expression* propertyExpressionParser(const SGPropertyNode* exp,
801 expression::Parser* parser)
803 SGPropertyNode_ptr pnode = getPropertyRoot()->getNode(exp->getStringValue(),
805 PropertyExpression* pexp = new PropertyExpression(pnode);
806 TechniquePredParser* predParser
807 = dynamic_cast<TechniquePredParser*>(parser);
809 pnode->addChangeListener(new EffectPropertyListener(predParser
814 expression::ExpParserRegistrar propertyRegistrar("property",
815 propertyExpressionParser);