00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #ifdef HAVE_CONFIG_H
00018 # include <simgear_config.h>
00019 #endif
00020
00021 #include "Effect.hxx"
00022 #include "EffectBuilder.hxx"
00023 #include "EffectGeode.hxx"
00024 #include "Technique.hxx"
00025 #include "Pass.hxx"
00026 #include "TextureBuilder.hxx"
00027
00028 #include <algorithm>
00029 #include <functional>
00030 #include <iterator>
00031 #include <map>
00032 #include <utility>
00033 #include <boost/tr1/unordered_map.hpp>
00034
00035 #include <boost/bind.hpp>
00036 #include <boost/foreach.hpp>
00037 #include <boost/functional/hash.hpp>
00038 #include <boost/tuple/tuple.hpp>
00039 #include <boost/tuple/tuple_comparison.hpp>
00040
00041 #include <osg/AlphaFunc>
00042 #include <osg/BlendFunc>
00043 #include <osg/CullFace>
00044 #include <osg/Depth>
00045 #include <osg/Drawable>
00046 #include <osg/Material>
00047 #include <osg/Math>
00048 #include <osg/PolygonMode>
00049 #include <osg/Program>
00050 #include <osg/Referenced>
00051 #include <osg/RenderInfo>
00052 #include <osg/ShadeModel>
00053 #include <osg/StateSet>
00054 #include <osg/Stencil>
00055 #include <osg/TexEnv>
00056 #include <osg/Texture1D>
00057 #include <osg/Texture2D>
00058 #include <osg/Texture3D>
00059 #include <osg/TextureRectangle>
00060 #include <osg/Uniform>
00061 #include <osg/Vec4d>
00062 #include <osgUtil/CullVisitor>
00063 #include <osgDB/FileUtils>
00064 #include <osgDB/Input>
00065 #include <osgDB/ParameterOutput>
00066 #include <osgDB/ReadFile>
00067 #include <osgDB/Registry>
00068
00069 #include <simgear/scene/tgdb/userdata.hxx>
00070 #include <simgear/scene/util/SGSceneFeatures.hxx>
00071 #include <simgear/scene/util/StateAttributeFactory.hxx>
00072 #include <simgear/structure/OSGUtils.hxx>
00073 #include <simgear/structure/SGExpression.hxx>
00074
00075
00076
00077 namespace simgear
00078 {
00079 using namespace std;
00080 using namespace osg;
00081 using namespace osgUtil;
00082
00083 using namespace effect;
00084
00085 Effect::Effect()
00086 : _cache(0), _isRealized(false)
00087 {
00088 }
00089
00090 Effect::Effect(const Effect& rhs, const CopyOp& copyop)
00091 : root(rhs.root), parametersProp(rhs.parametersProp), _cache(0),
00092 _isRealized(rhs._isRealized)
00093 {
00094 typedef vector<ref_ptr<Technique> > TechniqueList;
00095 for (TechniqueList::const_iterator itr = rhs.techniques.begin(),
00096 end = rhs.techniques.end();
00097 itr != end;
00098 ++itr)
00099 techniques.push_back(static_cast<Technique*>(copyop(itr->get())));
00100 }
00101
00102
00103 StateSet* Effect::getDefaultStateSet()
00104 {
00105 Technique* tniq = techniques.back().get();
00106 if (!tniq)
00107 return 0;
00108 Pass* pass = tniq->passes.front().get();
00109 return pass;
00110 }
00111
00112
00113
00114 Technique* Effect::chooseTechnique(RenderInfo* info)
00115 {
00116 BOOST_FOREACH(ref_ptr<Technique>& technique, techniques)
00117 {
00118 if (technique->valid(info) == Technique::VALID)
00119 return technique.get();
00120 }
00121 return 0;
00122 }
00123
00124 void Effect::resizeGLObjectBuffers(unsigned int maxSize)
00125 {
00126 BOOST_FOREACH(const ref_ptr<Technique>& technique, techniques)
00127 {
00128 technique->resizeGLObjectBuffers(maxSize);
00129 }
00130 }
00131
00132 void Effect::releaseGLObjects(osg::State* state) const
00133 {
00134 BOOST_FOREACH(const ref_ptr<Technique>& technique, techniques)
00135 {
00136 technique->releaseGLObjects(state);
00137 }
00138 }
00139
00140 Effect::~Effect()
00141 {
00142 delete _cache;
00143 }
00144
00145 void buildPass(Effect* effect, Technique* tniq, const SGPropertyNode* prop,
00146 const osgDB::ReaderWriter::Options* options)
00147 {
00148 Pass* pass = new Pass;
00149 tniq->passes.push_back(pass);
00150 for (int i = 0; i < prop->nChildren(); ++i) {
00151 const SGPropertyNode* attrProp = prop->getChild(i);
00152 PassAttributeBuilder* builder
00153 = PassAttributeBuilder::find(attrProp->getNameString());
00154 if (builder)
00155 builder->buildAttribute(effect, pass, attrProp, options);
00156 else
00157 SG_LOG(SG_INPUT, SG_ALERT,
00158 "skipping unknown pass attribute " << attrProp->getName());
00159 }
00160 }
00161
00162 osg::Vec4f getColor(const SGPropertyNode* prop)
00163 {
00164 if (prop->nChildren() == 0) {
00165 if (prop->getType() == props::VEC4D) {
00166 return osg::Vec4f(toOsg(prop->getValue<SGVec4d>()));
00167 } else if (prop->getType() == props::VEC3D) {
00168 return osg::Vec4f(toOsg(prop->getValue<SGVec3d>()), 1.0f);
00169 } else {
00170 SG_LOG(SG_INPUT, SG_ALERT,
00171 "invalid color property " << prop->getName() << " "
00172 << prop->getStringValue());
00173 return osg::Vec4f(0.0f, 0.0f, 0.0f, 1.0f);
00174 }
00175 } else {
00176 osg::Vec4f result;
00177 static const char* colors[] = {"r", "g", "b"};
00178 for (int i = 0; i < 3; ++i) {
00179 const SGPropertyNode* componentProp = prop->getChild(colors[i]);
00180 result[i] = componentProp ? componentProp->getValue<float>() : 0.0f;
00181 }
00182 const SGPropertyNode* alphaProp = prop->getChild("a");
00183 result[3] = alphaProp ? alphaProp->getValue<float>() : 1.0f;
00184 return result;
00185 }
00186 }
00187
00188 struct LightingBuilder : public PassAttributeBuilder
00189 {
00190 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
00191 const osgDB::ReaderWriter::Options* options);
00192 };
00193
00194 void LightingBuilder::buildAttribute(Effect* effect, Pass* pass,
00195 const SGPropertyNode* prop,
00196 const osgDB::ReaderWriter::Options* options)
00197 {
00198 const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop);
00199 if (!realProp)
00200 return;
00201 pass->setMode(GL_LIGHTING, (realProp->getValue<bool>() ? StateAttribute::ON
00202 : StateAttribute::OFF));
00203 }
00204
00205 InstallAttributeBuilder<LightingBuilder> installLighting("lighting");
00206
00207 struct ShadeModelBuilder : public PassAttributeBuilder
00208 {
00209 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
00210 const osgDB::ReaderWriter::Options* options)
00211 {
00212 const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop);
00213 if (!realProp)
00214 return;
00215 StateAttributeFactory *attrFact = StateAttributeFactory::instance();
00216 string propVal = realProp->getStringValue();
00217 if (propVal == "flat")
00218 pass->setAttribute(attrFact->getFlatShadeModel());
00219 else if (propVal == "smooth")
00220 pass->setAttribute(attrFact->getSmoothShadeModel());
00221 else
00222 SG_LOG(SG_INPUT, SG_ALERT,
00223 "invalid shade model property " << propVal);
00224 }
00225 };
00226
00227 InstallAttributeBuilder<ShadeModelBuilder> installShadeModel("shade-model");
00228
00229 struct CullFaceBuilder : PassAttributeBuilder
00230 {
00231 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
00232 const osgDB::ReaderWriter::Options* options)
00233 {
00234 const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop);
00235 if (!realProp) {
00236 pass->setMode(GL_CULL_FACE, StateAttribute::OFF);
00237 return;
00238 }
00239 StateAttributeFactory *attrFact = StateAttributeFactory::instance();
00240 string propVal = realProp->getStringValue();
00241 if (propVal == "front")
00242 pass->setAttributeAndModes(attrFact->getCullFaceFront());
00243 else if (propVal == "back")
00244 pass->setAttributeAndModes(attrFact->getCullFaceBack());
00245 else if (propVal == "front-back")
00246 pass->setAttributeAndModes(new CullFace(CullFace::FRONT_AND_BACK));
00247 else if (propVal == "off")
00248 pass->setMode(GL_CULL_FACE, StateAttribute::OFF);
00249 else
00250 SG_LOG(SG_INPUT, SG_ALERT,
00251 "invalid cull face property " << propVal);
00252 }
00253 };
00254
00255 InstallAttributeBuilder<CullFaceBuilder> installCullFace("cull-face");
00256
00257 struct ColorMaskBuilder : PassAttributeBuilder
00258 {
00259 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
00260 const osgDB::ReaderWriter::Options* options)
00261 {
00262 const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop);
00263 if (!realProp)
00264 return;
00265
00266 ColorMask *mask = new ColorMask;
00267 Vec4 m = getColor(realProp);
00268 mask->setMask(m.r(), m.g(), m.b(), m.a());
00269 pass->setAttributeAndModes(mask);
00270 }
00271 };
00272
00273 InstallAttributeBuilder<ColorMaskBuilder> installColorMask("color-mask");
00274
00275 EffectNameValue<StateSet::RenderingHint> renderingHintInit[] =
00276 {
00277 { "default", StateSet::DEFAULT_BIN },
00278 { "opaque", StateSet::OPAQUE_BIN },
00279 { "transparent", StateSet::TRANSPARENT_BIN }
00280 };
00281
00282 EffectPropertyMap<StateSet::RenderingHint> renderingHints(renderingHintInit);
00283
00284 struct HintBuilder : public PassAttributeBuilder
00285 {
00286 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
00287 const osgDB::ReaderWriter::Options* options)
00288 {
00289 const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop);
00290 if (!realProp)
00291 return;
00292 StateSet::RenderingHint renderingHint = StateSet::DEFAULT_BIN;
00293 findAttr(renderingHints, realProp, renderingHint);
00294 pass->setRenderingHint(renderingHint);
00295 }
00296 };
00297
00298 InstallAttributeBuilder<HintBuilder> installHint("rendering-hint");
00299
00300 struct RenderBinBuilder : public PassAttributeBuilder
00301 {
00302 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
00303 const osgDB::ReaderWriter::Options* options)
00304 {
00305 if (!isAttributeActive(effect, prop))
00306 return;
00307 const SGPropertyNode* binProp = prop->getChild("bin-number");
00308 binProp = getEffectPropertyNode(effect, binProp);
00309 const SGPropertyNode* nameProp = prop->getChild("bin-name");
00310 nameProp = getEffectPropertyNode(effect, nameProp);
00311 if (binProp && nameProp) {
00312 pass->setRenderBinDetails(binProp->getIntValue(),
00313 nameProp->getStringValue());
00314 } else {
00315 if (!binProp)
00316 SG_LOG(SG_INPUT, SG_ALERT,
00317 "No render bin number specified in render bin section");
00318 if (!nameProp)
00319 SG_LOG(SG_INPUT, SG_ALERT,
00320 "No render bin name specified in render bin section");
00321 }
00322 }
00323 };
00324
00325 InstallAttributeBuilder<RenderBinBuilder> installRenderBin("render-bin");
00326
00327 struct MaterialBuilder : public PassAttributeBuilder
00328 {
00329 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
00330 const osgDB::ReaderWriter::Options* options);
00331 };
00332
00333 EffectNameValue<Material::ColorMode> colorModeInit[] =
00334 {
00335 { "ambient", Material::AMBIENT },
00336 { "ambient-and-diffuse", Material::AMBIENT_AND_DIFFUSE },
00337 { "diffuse", Material::DIFFUSE },
00338 { "emissive", Material::EMISSION },
00339 { "specular", Material::SPECULAR },
00340 { "off", Material::OFF }
00341 };
00342 EffectPropertyMap<Material::ColorMode> colorModes(colorModeInit);
00343
00344 void MaterialBuilder::buildAttribute(Effect* effect, Pass* pass,
00345 const SGPropertyNode* prop,
00346 const osgDB::ReaderWriter::Options* options)
00347 {
00348 if (!isAttributeActive(effect, prop))
00349 return;
00350 Material* mat = new Material;
00351 const SGPropertyNode* color = 0;
00352 if ((color = getEffectPropertyChild(effect, prop, "ambient")))
00353 mat->setAmbient(Material::FRONT_AND_BACK, getColor(color));
00354 if ((color = getEffectPropertyChild(effect, prop, "ambient-front")))
00355 mat->setAmbient(Material::FRONT, getColor(color));
00356 if ((color = getEffectPropertyChild(effect, prop, "ambient-back")))
00357 mat->setAmbient(Material::BACK, getColor(color));
00358 if ((color = getEffectPropertyChild(effect, prop, "diffuse")))
00359 mat->setDiffuse(Material::FRONT_AND_BACK, getColor(color));
00360 if ((color = getEffectPropertyChild(effect, prop, "diffuse-front")))
00361 mat->setDiffuse(Material::FRONT, getColor(color));
00362 if ((color = getEffectPropertyChild(effect, prop, "diffuse-back")))
00363 mat->setDiffuse(Material::BACK, getColor(color));
00364 if ((color = getEffectPropertyChild(effect, prop, "specular")))
00365 mat->setSpecular(Material::FRONT_AND_BACK, getColor(color));
00366 if ((color = getEffectPropertyChild(effect, prop, "specular-front")))
00367 mat->setSpecular(Material::FRONT, getColor(color));
00368 if ((color = getEffectPropertyChild(effect, prop, "specular-back")))
00369 mat->setSpecular(Material::BACK, getColor(color));
00370 if ((color = getEffectPropertyChild(effect, prop, "emissive")))
00371 mat->setEmission(Material::FRONT_AND_BACK, getColor(color));
00372 if ((color = getEffectPropertyChild(effect, prop, "emissive-front")))
00373 mat->setEmission(Material::FRONT, getColor(color));
00374 if ((color = getEffectPropertyChild(effect, prop, "emissive-back")))
00375 mat->setEmission(Material::BACK, getColor(color));
00376 const SGPropertyNode* shininess = 0;
00377 mat->setShininess(Material::FRONT_AND_BACK, 0.0f);
00378 if ((shininess = getEffectPropertyChild(effect, prop, "shininess")))
00379 mat->setShininess(Material::FRONT_AND_BACK, shininess->getFloatValue());
00380 if ((shininess = getEffectPropertyChild(effect, prop, "shininess-front")))
00381 mat->setShininess(Material::FRONT, shininess->getFloatValue());
00382 if ((shininess = getEffectPropertyChild(effect, prop, "shininess-back")))
00383 mat->setShininess(Material::BACK, shininess->getFloatValue());
00384 Material::ColorMode colorMode = Material::OFF;
00385 findAttr(colorModes, getEffectPropertyChild(effect, prop, "color-mode"),
00386 colorMode);
00387 mat->setColorMode(colorMode);
00388 pass->setAttribute(mat);
00389 }
00390
00391 InstallAttributeBuilder<MaterialBuilder> installMaterial("material");
00392
00393 EffectNameValue<BlendFunc::BlendFuncMode> blendFuncModesInit[] =
00394 {
00395 {"dst-alpha", BlendFunc::DST_ALPHA},
00396 {"dst-color", BlendFunc::DST_COLOR},
00397 {"one", BlendFunc::ONE},
00398 {"one-minus-dst-alpha", BlendFunc::ONE_MINUS_DST_ALPHA},
00399 {"one-minus-dst-color", BlendFunc::ONE_MINUS_DST_COLOR},
00400 {"one-minus-src-alpha", BlendFunc::ONE_MINUS_SRC_ALPHA},
00401 {"one-minus-src-color", BlendFunc::ONE_MINUS_SRC_COLOR},
00402 {"src-alpha", BlendFunc::SRC_ALPHA},
00403 {"src-alpha-saturate", BlendFunc::SRC_ALPHA_SATURATE},
00404 {"src-color", BlendFunc::SRC_COLOR},
00405 {"constant-color", BlendFunc::CONSTANT_COLOR},
00406 {"one-minus-constant-color", BlendFunc::ONE_MINUS_CONSTANT_COLOR},
00407 {"constant-alpha", BlendFunc::CONSTANT_ALPHA},
00408 {"one-minus-constant-alpha", BlendFunc::ONE_MINUS_CONSTANT_ALPHA},
00409 {"zero", BlendFunc::ZERO}
00410 };
00411 EffectPropertyMap<BlendFunc::BlendFuncMode> blendFuncModes(blendFuncModesInit);
00412
00413 struct BlendBuilder : public PassAttributeBuilder
00414 {
00415 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
00416 const osgDB::ReaderWriter::Options* options)
00417 {
00418 if (!isAttributeActive(effect, prop))
00419 return;
00420
00421
00422 const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop);
00423 if (!realProp)
00424 return;
00425 if (realProp->nChildren() == 0) {
00426 pass->setMode(GL_BLEND, (realProp->getBoolValue()
00427 ? StateAttribute::ON
00428 : StateAttribute::OFF));
00429 return;
00430 }
00431
00432 const SGPropertyNode* pmode = getEffectPropertyChild(effect, prop,
00433 "mode");
00434
00435
00436 if (pmode && !pmode->getValue<bool>()) {
00437 pass->setMode(GL_BLEND, StateAttribute::OFF);
00438 return;
00439 }
00440 const SGPropertyNode* psource
00441 = getEffectPropertyChild(effect, prop, "source");
00442 const SGPropertyNode* pdestination
00443 = getEffectPropertyChild(effect, prop, "destination");
00444 const SGPropertyNode* psourceRGB
00445 = getEffectPropertyChild(effect, prop, "source-rgb");
00446 const SGPropertyNode* psourceAlpha
00447 = getEffectPropertyChild(effect, prop, "source-alpha");
00448 const SGPropertyNode* pdestRGB
00449 = getEffectPropertyChild(effect, prop, "destination-rgb");
00450 const SGPropertyNode* pdestAlpha
00451 = getEffectPropertyChild(effect, prop, "destination-alpha");
00452 BlendFunc::BlendFuncMode sourceMode = BlendFunc::ONE;
00453 BlendFunc::BlendFuncMode destMode = BlendFunc::ZERO;
00454 if (psource)
00455 findAttr(blendFuncModes, psource, sourceMode);
00456 if (pdestination)
00457 findAttr(blendFuncModes, pdestination, destMode);
00458 if (psource && pdestination
00459 && !(psourceRGB || psourceAlpha || pdestRGB || pdestAlpha)
00460 && sourceMode == BlendFunc::SRC_ALPHA
00461 && destMode == BlendFunc::ONE_MINUS_SRC_ALPHA) {
00462 pass->setAttributeAndModes(StateAttributeFactory::instance()
00463 ->getStandardBlendFunc());
00464 return;
00465 }
00466 BlendFunc* blendFunc = new BlendFunc;
00467 if (psource)
00468 blendFunc->setSource(sourceMode);
00469 if (pdestination)
00470 blendFunc->setDestination(destMode);
00471 if (psourceRGB) {
00472 BlendFunc::BlendFuncMode sourceRGBMode;
00473 findAttr(blendFuncModes, psourceRGB, sourceRGBMode);
00474 blendFunc->setSourceRGB(sourceRGBMode);
00475 }
00476 if (pdestRGB) {
00477 BlendFunc::BlendFuncMode destRGBMode;
00478 findAttr(blendFuncModes, pdestRGB, destRGBMode);
00479 blendFunc->setDestinationRGB(destRGBMode);
00480 }
00481 if (psourceAlpha) {
00482 BlendFunc::BlendFuncMode sourceAlphaMode;
00483 findAttr(blendFuncModes, psourceAlpha, sourceAlphaMode);
00484 blendFunc->setSourceAlpha(sourceAlphaMode);
00485 }
00486 if (pdestAlpha) {
00487 BlendFunc::BlendFuncMode destAlphaMode;
00488 findAttr(blendFuncModes, pdestAlpha, destAlphaMode);
00489 blendFunc->setDestinationAlpha(destAlphaMode);
00490 }
00491 pass->setAttributeAndModes(blendFunc);
00492 }
00493 };
00494
00495 InstallAttributeBuilder<BlendBuilder> installBlend("blend");
00496
00497
00498 EffectNameValue<Stencil::Function> stencilFunctionInit[] =
00499 {
00500 {"never", Stencil::NEVER },
00501 {"less", Stencil::LESS},
00502 {"equal", Stencil::EQUAL},
00503 {"less-or-equal", Stencil::LEQUAL},
00504 {"greater", Stencil::GREATER},
00505 {"not-equal", Stencil::NOTEQUAL},
00506 {"greater-or-equal", Stencil::GEQUAL},
00507 {"always", Stencil::ALWAYS}
00508 };
00509
00510 EffectPropertyMap<Stencil::Function> stencilFunction(stencilFunctionInit);
00511
00512 EffectNameValue<Stencil::Operation> stencilOperationInit[] =
00513 {
00514 {"keep", Stencil::KEEP},
00515 {"zero", Stencil::ZERO},
00516 {"replace", Stencil::REPLACE},
00517 {"increase", Stencil::INCR},
00518 {"decrease", Stencil::DECR},
00519 {"invert", Stencil::INVERT},
00520 {"increase-wrap", Stencil::INCR_WRAP},
00521 {"decrease-wrap", Stencil::DECR_WRAP}
00522 };
00523
00524 EffectPropertyMap<Stencil::Operation> stencilOperation(stencilOperationInit);
00525
00526 struct StencilBuilder : public PassAttributeBuilder
00527 {
00528 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
00529 const osgDB::ReaderWriter::Options* options)
00530 {
00531 if (!isAttributeActive(effect, prop))
00532 return;
00533
00534 const SGPropertyNode* pmode = getEffectPropertyChild(effect, prop,
00535 "mode");
00536 if (pmode && !pmode->getValue<bool>()) {
00537 pass->setMode(GL_STENCIL, StateAttribute::OFF);
00538 return;
00539 }
00540 const SGPropertyNode* pfunction
00541 = getEffectPropertyChild(effect, prop, "function");
00542 const SGPropertyNode* pvalue
00543 = getEffectPropertyChild(effect, prop, "value");
00544 const SGPropertyNode* pmask
00545 = getEffectPropertyChild(effect, prop, "mask");
00546 const SGPropertyNode* psfail
00547 = getEffectPropertyChild(effect, prop, "stencil-fail");
00548 const SGPropertyNode* pzfail
00549 = getEffectPropertyChild(effect, prop, "z-fail");
00550 const SGPropertyNode* ppass
00551 = getEffectPropertyChild(effect, prop, "pass");
00552
00553 Stencil::Function func = Stencil::ALWAYS;
00554 int ref = 0;
00555 unsigned int mask = ~0u;
00556 Stencil::Operation sfailop = Stencil::KEEP;
00557 Stencil::Operation zfailop = Stencil::KEEP;
00558 Stencil::Operation passop = Stencil::KEEP;
00559
00560 ref_ptr<Stencil> stencilFunc = new Stencil;
00561
00562 if (pfunction)
00563 findAttr(stencilFunction, pfunction, func);
00564 if (pvalue)
00565 ref = pvalue->getIntValue();
00566 if (pmask)
00567 mask = pmask->getIntValue();
00568
00569 if (psfail)
00570 findAttr(stencilOperation, psfail, sfailop);
00571 if (pzfail)
00572 findAttr(stencilOperation, pzfail, zfailop);
00573 if (ppass)
00574 findAttr(stencilOperation, ppass, passop);
00575
00576
00577 stencilFunc->setFunction(func, ref, mask);
00578
00579
00580 stencilFunc->setOperation(sfailop, zfailop, passop);
00581
00582
00583 pass->setAttributeAndModes(stencilFunc.get());
00584 }
00585 };
00586
00587 InstallAttributeBuilder<StencilBuilder> installStencil("stencil");
00588
00589
00590 EffectNameValue<AlphaFunc::ComparisonFunction> alphaComparisonInit[] =
00591 {
00592 {"never", AlphaFunc::NEVER},
00593 {"less", AlphaFunc::LESS},
00594 {"equal", AlphaFunc::EQUAL},
00595 {"lequal", AlphaFunc::LEQUAL},
00596 {"greater", AlphaFunc::GREATER},
00597 {"notequal", AlphaFunc::NOTEQUAL},
00598 {"gequal", AlphaFunc::GEQUAL},
00599 {"always", AlphaFunc::ALWAYS}
00600 };
00601 EffectPropertyMap<AlphaFunc::ComparisonFunction>
00602 alphaComparison(alphaComparisonInit);
00603
00604 struct AlphaTestBuilder : public PassAttributeBuilder
00605 {
00606 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
00607 const osgDB::ReaderWriter::Options* options)
00608 {
00609 if (!isAttributeActive(effect, prop))
00610 return;
00611
00612
00613 const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop);
00614 if (!realProp)
00615 return;
00616 if (realProp->nChildren() == 0) {
00617 pass->setMode(GL_ALPHA_TEST, (realProp->getBoolValue()
00618 ? StateAttribute::ON
00619 : StateAttribute::OFF));
00620 return;
00621 }
00622
00623 const SGPropertyNode* pmode = getEffectPropertyChild(effect, prop,
00624 "mode");
00625
00626
00627 if (pmode && !pmode->getValue<bool>()) {
00628 pass->setMode(GL_ALPHA_TEST, StateAttribute::OFF);
00629 return;
00630 }
00631 const SGPropertyNode* pComp = getEffectPropertyChild(effect, prop,
00632 "comparison");
00633 const SGPropertyNode* pRef = getEffectPropertyChild(effect, prop,
00634 "reference");
00635 AlphaFunc::ComparisonFunction func = AlphaFunc::ALWAYS;
00636 float refValue = 1.0f;
00637 if (pComp)
00638 findAttr(alphaComparison, pComp, func);
00639 if (pRef)
00640 refValue = pRef->getValue<float>();
00641 if (func == AlphaFunc::GREATER && osg::equivalent(refValue, 1.0f)) {
00642 pass->setAttributeAndModes(StateAttributeFactory::instance()
00643 ->getStandardAlphaFunc());
00644 } else {
00645 AlphaFunc* alphaFunc = new AlphaFunc;
00646 alphaFunc->setFunction(func);
00647 alphaFunc->setReferenceValue(refValue);
00648 pass->setAttributeAndModes(alphaFunc);
00649 }
00650 }
00651 };
00652
00653 InstallAttributeBuilder<AlphaTestBuilder> installAlphaTest("alpha-test");
00654
00655 InstallAttributeBuilder<TextureUnitBuilder> textureUnitBuilder("texture-unit");
00656
00657
00658 typedef pair<string, Shader::Type> ShaderKey;
00659
00660 struct ProgramKey
00661 {
00662 typedef pair<string, int> AttribKey;
00663 osgDB::FilePathList paths;
00664 vector<ShaderKey> shaders;
00665 vector<AttribKey> attributes;
00666 struct EqualTo
00667 {
00668 bool operator()(const ProgramKey& lhs, const ProgramKey& rhs) const
00669 {
00670 return (lhs.paths.size() == rhs.paths.size()
00671 && equal(lhs.paths.begin(), lhs.paths.end(),
00672 rhs.paths.begin())
00673 && lhs.shaders.size() == rhs.shaders.size()
00674 && equal (lhs.shaders.begin(), lhs.shaders.end(),
00675 rhs.shaders.begin())
00676 && lhs.attributes.size() == rhs.attributes.size()
00677 && equal(lhs.attributes.begin(), lhs.attributes.end(),
00678 rhs.attributes.begin()));
00679 }
00680 };
00681 };
00682
00683 size_t hash_value(const ProgramKey& key)
00684 {
00685 size_t seed = 0;
00686 boost::hash_range(seed, key.paths.begin(), key.paths.end());
00687 boost::hash_range(seed, key.shaders.begin(), key.shaders.end());
00688 boost::hash_range(seed, key.attributes.begin(), key.attributes.end());
00689 return seed;
00690 }
00691
00692
00693
00694 typedef tr1::unordered_map<ProgramKey, ref_ptr<Program>,
00695 boost::hash<ProgramKey>, ProgramKey::EqualTo>
00696 ProgramMap;
00697 ProgramMap programMap;
00698
00699 typedef tr1::unordered_map<ShaderKey, ref_ptr<Shader>, boost::hash<ShaderKey> >
00700 ShaderMap;
00701 ShaderMap shaderMap;
00702
00703 void reload_shaders()
00704 {
00705 for(ShaderMap::iterator sitr = shaderMap.begin(); sitr != shaderMap.end(); ++sitr)
00706 {
00707 Shader *shader = sitr->second.get();
00708 string fileName = osgDB::findDataFile(sitr->first.first);
00709 if (!fileName.empty()) {
00710 shader->loadShaderSourceFromFile(fileName);
00711 }
00712 }
00713 }
00714
00715 struct ShaderProgramBuilder : PassAttributeBuilder
00716 {
00717 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
00718 const osgDB::ReaderWriter::Options* options);
00719 };
00720
00721 void ShaderProgramBuilder::buildAttribute(Effect* effect, Pass* pass,
00722 const SGPropertyNode* prop,
00723 const osgDB::ReaderWriter::Options*
00724 options)
00725 {
00726 using namespace boost;
00727 if (!isAttributeActive(effect, prop))
00728 return;
00729 PropertyList pVertShaders = prop->getChildren("vertex-shader");
00730 PropertyList pFragShaders = prop->getChildren("fragment-shader");
00731 PropertyList pAttributes = prop->getChildren("attribute");
00732 ProgramKey prgKey;
00733 for (PropertyList::iterator itr = pVertShaders.begin(),
00734 e = pVertShaders.end();
00735 itr != e;
00736 ++itr)
00737 prgKey.shaders.push_back(ShaderKey((*itr)->getStringValue(),
00738 Shader::VERTEX));
00739 for (PropertyList::iterator itr = pFragShaders.begin(),
00740 e = pFragShaders.end();
00741 itr != e;
00742 ++itr)
00743 prgKey.shaders.push_back(ShaderKey((*itr)->getStringValue(),
00744 Shader::FRAGMENT));
00745 for (PropertyList::iterator itr = pAttributes.begin(),
00746 e = pAttributes.end();
00747 itr != e;
00748 ++itr) {
00749 const SGPropertyNode* pName = getEffectPropertyChild(effect, *itr,
00750 "name");
00751 const SGPropertyNode* pIndex = getEffectPropertyChild(effect, *itr,
00752 "index");
00753 if (!pName || ! pIndex)
00754 throw BuilderException("malformed attribute property");
00755 prgKey.attributes
00756 .push_back(ProgramKey::AttribKey(pName->getStringValue(),
00757 pIndex->getValue<int>()));
00758 }
00759 if (options)
00760 prgKey.paths = options->getDatabasePathList();
00761 Program* program = 0;
00762 ProgramMap::iterator pitr = programMap.find(prgKey);
00763 if (pitr != programMap.end()) {
00764 program = pitr->second.get();
00765 } else {
00766 program = new Program;
00767
00768 PropertyList& pvec = pVertShaders;
00769 Shader::Type stype = Shader::VERTEX;
00770 for (int i = 0; i < 2; ++i) {
00771 for (PropertyList::iterator nameItr = pvec.begin(), e = pvec.end();
00772 nameItr != e;
00773 ++nameItr) {
00774 string shaderName = (*nameItr)->getStringValue();
00775 string fileName = osgDB::findDataFile(shaderName, options);
00776 if (fileName.empty())
00777 throw BuilderException(string("couldn't find shader ") +
00778 shaderName);
00779 ShaderKey skey(fileName, stype);
00780 ShaderMap::iterator sitr = shaderMap.find(skey);
00781 if (sitr != shaderMap.end()) {
00782 program->addShader(sitr->second.get());
00783 } else {
00784 ref_ptr<Shader> shader = new Shader(stype);
00785 if (shader->loadShaderSourceFromFile(fileName)) {
00786 program->addShader(shader.get());
00787 shaderMap.insert(ShaderMap::value_type(skey, shader));
00788 }
00789 }
00790 }
00791 pvec = pFragShaders;
00792 stype = Shader::FRAGMENT;
00793 }
00794 BOOST_FOREACH(const ProgramKey::AttribKey& key, prgKey.attributes) {
00795 program->addBindAttribLocation(key.first, key.second);
00796 }
00797 programMap.insert(ProgramMap::value_type(prgKey, program));
00798 }
00799 pass->setAttributeAndModes(program);
00800 }
00801
00802 InstallAttributeBuilder<ShaderProgramBuilder> installShaderProgram("program");
00803
00804 EffectNameValue<Uniform::Type> uniformTypesInit[] =
00805 {
00806 {"float", Uniform::FLOAT},
00807 {"float-vec3", Uniform::FLOAT_VEC3},
00808 {"float-vec4", Uniform::FLOAT_VEC4},
00809 {"sampler-1d", Uniform::SAMPLER_1D},
00810 {"sampler-2d", Uniform::SAMPLER_2D},
00811 {"sampler-3d", Uniform::SAMPLER_3D}
00812 };
00813 EffectPropertyMap<Uniform::Type> uniformTypes(uniformTypesInit);
00814
00815 struct UniformBuilder :public PassAttributeBuilder
00816 {
00817 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
00818 const osgDB::ReaderWriter::Options* options)
00819 {
00820 if (!isAttributeActive(effect, prop))
00821 return;
00822 const SGPropertyNode* nameProp = prop->getChild("name");
00823 const SGPropertyNode* typeProp = prop->getChild("type");
00824 const SGPropertyNode* valProp
00825 = getEffectPropertyChild(effect, prop, "value");
00826 string name;
00827 Uniform::Type uniformType = Uniform::FLOAT;
00828 if (nameProp) {
00829 name = nameProp->getStringValue();
00830 } else {
00831 SG_LOG(SG_INPUT, SG_ALERT, "No name for uniform property ");
00832 return;
00833 }
00834 if (!valProp) {
00835 SG_LOG(SG_INPUT, SG_ALERT, "No value for uniform property "
00836 << name);
00837 return;
00838 }
00839 if (!typeProp) {
00840 props::Type propType = valProp->getType();
00841 switch (propType) {
00842 case props::FLOAT:
00843 case props::DOUBLE:
00844 break;
00845 case props::VEC3D:
00846 uniformType = Uniform::FLOAT_VEC3;
00847 break;
00848 case props::VEC4D:
00849 uniformType = Uniform::FLOAT_VEC4;
00850 break;
00851 default:
00852 SG_LOG(SG_INPUT, SG_ALERT, "Can't deduce type of uniform "
00853 << name);
00854 return;
00855 }
00856 } else {
00857 findAttr(uniformTypes, typeProp, uniformType);
00858 }
00859 ref_ptr<Uniform> uniform = new Uniform;
00860 uniform->setName(name);
00861 uniform->setType(uniformType);
00862 switch (uniformType) {
00863 case Uniform::FLOAT:
00864 uniform->set(valProp->getValue<float>());
00865 break;
00866 case Uniform::FLOAT_VEC3:
00867 uniform->set(toOsg(valProp->getValue<SGVec3d>()));
00868 break;
00869 case Uniform::FLOAT_VEC4:
00870 uniform->set(toOsg(valProp->getValue<SGVec4d>()));
00871 break;
00872 case Uniform::SAMPLER_1D:
00873 case Uniform::SAMPLER_2D:
00874 case Uniform::SAMPLER_3D:
00875 uniform->set(valProp->getValue<int>());
00876 break;
00877 default:
00878 break;
00879 }
00880 pass->addUniform(uniform.get());
00881 }
00882 };
00883
00884 InstallAttributeBuilder<UniformBuilder> installUniform("uniform");
00885
00886
00887
00888
00889 struct NameBuilder : public PassAttributeBuilder
00890 {
00891 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
00892 const osgDB::ReaderWriter::Options* options)
00893 {
00894
00895 string name = prop->getStringValue();
00896 if (!name.empty())
00897 pass->setName(name);
00898 }
00899 };
00900
00901 InstallAttributeBuilder<NameBuilder> installName("name");
00902
00903 EffectNameValue<PolygonMode::Mode> polygonModeModesInit[] =
00904 {
00905 {"fill", PolygonMode::FILL},
00906 {"line", PolygonMode::LINE},
00907 {"point", PolygonMode::POINT}
00908 };
00909 EffectPropertyMap<PolygonMode::Mode> polygonModeModes(polygonModeModesInit);
00910
00911 struct PolygonModeBuilder : public PassAttributeBuilder
00912 {
00913 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
00914 const osgDB::ReaderWriter::Options* options)
00915 {
00916 if (!isAttributeActive(effect, prop))
00917 return;
00918 const SGPropertyNode* frontProp
00919 = getEffectPropertyChild(effect, prop, "front");
00920 const SGPropertyNode* backProp
00921 = getEffectPropertyChild(effect, prop, "back");
00922 ref_ptr<PolygonMode> pmode = new PolygonMode;
00923 PolygonMode::Mode frontMode = PolygonMode::FILL;
00924 PolygonMode::Mode backMode = PolygonMode::FILL;
00925 if (frontProp) {
00926 findAttr(polygonModeModes, frontProp, frontMode);
00927 pmode->setMode(PolygonMode::FRONT, frontMode);
00928 }
00929 if (backProp) {
00930 findAttr(polygonModeModes, backProp, backMode);
00931 pmode->setMode(PolygonMode::BACK, backMode);
00932 }
00933 pass->setAttribute(pmode.get());
00934 }
00935 };
00936
00937 InstallAttributeBuilder<PolygonModeBuilder> installPolygonMode("polygon-mode");
00938
00939 struct VertexProgramTwoSideBuilder : public PassAttributeBuilder
00940 {
00941 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
00942 const osgDB::ReaderWriter::Options* options)
00943 {
00944 const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop);
00945 if (!realProp)
00946 return;
00947 pass->setMode(GL_VERTEX_PROGRAM_TWO_SIDE,
00948 (realProp->getValue<bool>()
00949 ? StateAttribute::ON : StateAttribute::OFF));
00950 }
00951 };
00952
00953 InstallAttributeBuilder<VertexProgramTwoSideBuilder>
00954 installTwoSide("vertex-program-two-side");
00955
00956 struct VertexProgramPointSizeBuilder : public PassAttributeBuilder
00957 {
00958 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
00959 const osgDB::ReaderWriter::Options* options)
00960 {
00961 const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop);
00962 if (!realProp)
00963 return;
00964 pass->setMode(GL_VERTEX_PROGRAM_POINT_SIZE,
00965 (realProp->getValue<bool>()
00966 ? StateAttribute::ON : StateAttribute::OFF));
00967 }
00968 };
00969
00970 InstallAttributeBuilder<VertexProgramPointSizeBuilder>
00971 installPointSize("vertex-program-point-size");
00972
00973 EffectNameValue<Depth::Function> depthFunctionInit[] =
00974 {
00975 {"never", Depth::NEVER},
00976 {"less", Depth::LESS},
00977 {"equal", Depth::EQUAL},
00978 {"lequal", Depth::LEQUAL},
00979 {"greater", Depth::GREATER},
00980 {"notequal", Depth::NOTEQUAL},
00981 {"gequal", Depth::GEQUAL},
00982 {"always", Depth::ALWAYS}
00983 };
00984 EffectPropertyMap<Depth::Function> depthFunction(depthFunctionInit);
00985
00986 struct DepthBuilder : public PassAttributeBuilder
00987 {
00988 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
00989 const osgDB::ReaderWriter::Options* options)
00990 {
00991 if (!isAttributeActive(effect, prop))
00992 return;
00993 ref_ptr<Depth> depth = new Depth;
00994 const SGPropertyNode* pfunc
00995 = getEffectPropertyChild(effect, prop, "function");
00996 if (pfunc) {
00997 Depth::Function func = Depth::LESS;
00998 findAttr(depthFunction, pfunc, func);
00999 depth->setFunction(func);
01000 }
01001 const SGPropertyNode* pnear
01002 = getEffectPropertyChild(effect, prop, "near");
01003 if (pnear)
01004 depth->setZNear(pnear->getValue<double>());
01005 const SGPropertyNode* pfar
01006 = getEffectPropertyChild(effect, prop, "far");
01007 if (pfar)
01008 depth->setZFar(pnear->getValue<double>());
01009 const SGPropertyNode* pmask
01010 = getEffectPropertyChild(effect, prop, "write-mask");
01011 if (pmask)
01012 depth->setWriteMask(pmask->getValue<bool>());
01013 pass->setAttribute(depth.get());
01014 }
01015 };
01016
01017 InstallAttributeBuilder<DepthBuilder> installDepth("depth");
01018
01019 void buildTechnique(Effect* effect, const SGPropertyNode* prop,
01020 const osgDB::ReaderWriter::Options* options)
01021 {
01022 Technique* tniq = new Technique;
01023 effect->techniques.push_back(tniq);
01024 const SGPropertyNode* predProp = prop->getChild("predicate");
01025 if (!predProp) {
01026 tniq->setAlwaysValid(true);
01027 } else {
01028 try {
01029 TechniquePredParser parser;
01030 parser.setTechnique(tniq);
01031 expression::BindingLayout& layout = parser.getBindingLayout();
01032 layout.addBinding("__contextId", expression::INT);
01033 SGExpressionb* validExp
01034 = dynamic_cast<SGExpressionb*>(parser.read(predProp
01035 ->getChild(0)));
01036 if (validExp)
01037 tniq->setValidExpression(validExp, layout);
01038 else
01039 throw expression::ParseError("technique predicate is not a boolean expression");
01040 }
01041 catch (expression::ParseError& except)
01042 {
01043 SG_LOG(SG_INPUT, SG_ALERT,
01044 "parsing technique predicate " << except.getMessage());
01045 tniq->setAlwaysValid(false);
01046 }
01047 }
01048 PropertyList passProps = prop->getChildren("pass");
01049 for (PropertyList::iterator itr = passProps.begin(), e = passProps.end();
01050 itr != e;
01051 ++itr) {
01052 buildPass(effect, tniq, itr->ptr(), options);
01053 }
01054 }
01055
01056
01057 bool makeParametersFromStateSet(SGPropertyNode* effectRoot, const StateSet* ss)
01058 {
01059 SGPropertyNode* paramRoot = makeChild(effectRoot, "parameters");
01060 SGPropertyNode* matNode = paramRoot->getChild("material", 0, true);
01061 Vec4f ambVal, difVal, specVal, emisVal;
01062 float shininess = 0.0f;
01063 const Material* mat = getStateAttribute<Material>(ss);
01064 if (mat) {
01065 ambVal = mat->getAmbient(Material::FRONT_AND_BACK);
01066 difVal = mat->getDiffuse(Material::FRONT_AND_BACK);
01067 specVal = mat->getSpecular(Material::FRONT_AND_BACK);
01068 emisVal = mat->getEmission(Material::FRONT_AND_BACK);
01069 shininess = mat->getShininess(Material::FRONT_AND_BACK);
01070 makeChild(matNode, "active")->setValue(true);
01071 makeChild(matNode, "ambient")->setValue(toVec4d(toSG(ambVal)));
01072 makeChild(matNode, "diffuse")->setValue(toVec4d(toSG(difVal)));
01073 makeChild(matNode, "specular")->setValue(toVec4d(toSG(specVal)));
01074 makeChild(matNode, "emissive")->setValue(toVec4d(toSG(emisVal)));
01075 makeChild(matNode, "shininess")->setValue(shininess);
01076 matNode->getChild("color-mode", 0, true)->setStringValue("diffuse");
01077 } else {
01078 makeChild(matNode, "active")->setValue(false);
01079 }
01080 const ShadeModel* sm = getStateAttribute<ShadeModel>(ss);
01081 string shadeModelString("smooth");
01082 if (sm) {
01083 ShadeModel::Mode smMode = sm->getMode();
01084 if (smMode == ShadeModel::FLAT)
01085 shadeModelString = "flat";
01086 }
01087 makeChild(paramRoot, "shade-model")->setStringValue(shadeModelString);
01088 string cullFaceString("off");
01089 const CullFace* cullFace = getStateAttribute<CullFace>(ss);
01090 if (cullFace) {
01091 switch (cullFace->getMode()) {
01092 case CullFace::FRONT:
01093 cullFaceString = "front";
01094 break;
01095 case CullFace::BACK:
01096 cullFaceString = "back";
01097 break;
01098 case CullFace::FRONT_AND_BACK:
01099 cullFaceString = "front-back";
01100 break;
01101 default:
01102 break;
01103 }
01104 }
01105 makeChild(paramRoot, "cull-face")->setStringValue(cullFaceString);
01106 const BlendFunc* blendFunc = getStateAttribute<BlendFunc>(ss);
01107 SGPropertyNode* blendNode = makeChild(paramRoot, "blend");
01108 if (blendFunc) {
01109 string sourceMode = findName(blendFuncModes, blendFunc->getSource());
01110 string destMode = findName(blendFuncModes, blendFunc->getDestination());
01111 makeChild(blendNode, "active")->setValue(true);
01112 makeChild(blendNode, "source")->setStringValue(sourceMode);
01113 makeChild(blendNode, "destination")->setStringValue(destMode);
01114 makeChild(blendNode, "mode")->setValue(true);
01115 } else {
01116 makeChild(blendNode, "active")->setValue(false);
01117 }
01118 string renderingHint = findName(renderingHints, ss->getRenderingHint());
01119 makeChild(paramRoot, "rendering-hint")->setStringValue(renderingHint);
01120 makeTextureParameters(paramRoot, ss);
01121 return true;
01122 }
01123
01124
01125
01126 bool Effect::realizeTechniques(const osgDB::ReaderWriter::Options* options)
01127 {
01128 if (_isRealized)
01129 return true;
01130 PropertyList tniqList = root->getChildren("technique");
01131 for (PropertyList::iterator itr = tniqList.begin(), e = tniqList.end();
01132 itr != e;
01133 ++itr)
01134 buildTechnique(this, *itr, options);
01135 _isRealized = true;
01136 return true;
01137 }
01138
01139 void Effect::InitializeCallback::doUpdate(osg::Node* node, osg::NodeVisitor* nv)
01140 {
01141 EffectGeode* eg = dynamic_cast<EffectGeode*>(node);
01142 if (!eg)
01143 return;
01144 Effect* effect = eg->getEffect();
01145 if (!effect)
01146 return;
01147 SGPropertyNode* root = getPropertyRoot();
01148 for (vector<SGSharedPtr<Updater> >::iterator itr = effect->_extraData.begin(),
01149 end = effect->_extraData.end();
01150 itr != end;
01151 ++itr) {
01152 InitializeWhenAdded* adder
01153 = dynamic_cast<InitializeWhenAdded*>(itr->ptr());
01154 if (adder)
01155 adder->initOnAdd(effect, root);
01156 }
01157 }
01158
01159 bool Effect::Key::EqualTo::operator()(const Effect::Key& lhs,
01160 const Effect::Key& rhs) const
01161 {
01162 if (lhs.paths.size() != rhs.paths.size()
01163 || !equal(lhs.paths.begin(), lhs.paths.end(), rhs.paths.begin()))
01164 return false;
01165 if (lhs.unmerged.valid() && rhs.unmerged.valid())
01166 return props::Compare()(lhs.unmerged, rhs.unmerged);
01167 else
01168 return lhs.unmerged == rhs.unmerged;
01169 }
01170
01171 size_t hash_value(const Effect::Key& key)
01172 {
01173 size_t seed = 0;
01174 if (key.unmerged.valid())
01175 boost::hash_combine(seed, *key.unmerged);
01176 boost::hash_range(seed, key.paths.begin(), key.paths.end());
01177 return seed;
01178 }
01179
01180 bool Effect_writeLocalData(const Object& obj, osgDB::Output& fw)
01181 {
01182 const Effect& effect = static_cast<const Effect&>(obj);
01183
01184 fw.indent() << "techniques " << effect.techniques.size() << "\n";
01185 BOOST_FOREACH(const ref_ptr<Technique>& technique, effect.techniques) {
01186 fw.writeObject(*technique);
01187 }
01188 return true;
01189 }
01190
01191 namespace
01192 {
01193 osgDB::RegisterDotOsgWrapperProxy effectProxy
01194 (
01195 new Effect,
01196 "simgear::Effect",
01197 "Object simgear::Effect",
01198 0,
01199 &Effect_writeLocalData
01200 );
01201 }
01202
01203
01204 class PropertyExpression : public SGExpression<bool>
01205 {
01206 public:
01207 PropertyExpression(SGPropertyNode* pnode) : _pnode(pnode) {}
01208
01209 void eval(bool& value, const expression::Binding*) const
01210 {
01211 value = _pnode->getValue<bool>();
01212 }
01213 protected:
01214 SGPropertyNode_ptr _pnode;
01215 };
01216
01217 class EffectPropertyListener : public SGPropertyChangeListener
01218 {
01219 public:
01220 EffectPropertyListener(Technique* tniq) : _tniq(tniq) {}
01221
01222 void valueChanged(SGPropertyNode* node)
01223 {
01224 _tniq->refreshValidity();
01225 }
01226 protected:
01227 osg::ref_ptr<Technique> _tniq;
01228 };
01229
01230 Expression* propertyExpressionParser(const SGPropertyNode* exp,
01231 expression::Parser* parser)
01232 {
01233 SGPropertyNode_ptr pnode = getPropertyRoot()->getNode(exp->getStringValue(),
01234 true);
01235 PropertyExpression* pexp = new PropertyExpression(pnode);
01236 TechniquePredParser* predParser
01237 = dynamic_cast<TechniquePredParser*>(parser);
01238 if (predParser)
01239 pnode->addChangeListener(new EffectPropertyListener(predParser
01240 ->getTechnique()));
01241 return pexp;
01242 }
01243
01244 expression::ExpParserRegistrar propertyRegistrar("property",
01245 propertyExpressionParser);
01246
01247 }