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 "Technique.hxx"
27 #include <boost/bind.hpp>
28 #include <boost/foreach.hpp>
29 #include <boost/lexical_cast.hpp>
30 #include <boost/tuple/tuple.hpp>
31 #include <boost/tuple/tuple_comparison.hpp>
33 #include <osg/CullFace>
34 #include <osg/Drawable>
35 #include <osg/Material>
36 #include <osg/PolygonMode>
37 #include <osg/Program>
38 #include <osg/Referenced>
39 #include <osg/RenderInfo>
40 #include <osg/ShadeModel>
41 #include <osg/StateSet>
43 #include <osg/Texture2D>
44 #include <osg/Uniform>
46 #include <osgUtil/CullVisitor>
47 #include <osgDB/FileUtils>
48 #include <osgDB/Input>
49 #include <osgDB/ParameterOutput>
50 #include <osgDB/ReadFile>
51 #include <osgDB/Registry>
53 #include <simgear/scene/util/SGSceneFeatures.hxx>
54 #include <simgear/scene/util/StateAttributeFactory.hxx>
55 #include <simgear/structure/OSGUtils.hxx>
56 #include <simgear/structure/SGExpression.hxx>
64 using namespace osgUtil;
70 Effect::Effect(const Effect& rhs, const CopyOp& copyop)
71 : root(rhs.root), parametersProp(rhs.parametersProp)
73 using namespace boost;
74 transform(rhs.techniques.begin(), rhs.techniques.end(),
75 backRefInsertIterator(techniques),
76 bind(simgear::clone_ref<Technique>, _1, copyop));
79 // Assume that the last technique is always valid.
80 StateSet* Effect::getDefaultStateSet()
82 Technique* tniq = techniques.back().get();
85 Pass* pass = tniq->passes.front().get();
89 // There should always be a valid technique in an effect.
91 Technique* Effect::chooseTechnique(RenderInfo* info)
93 BOOST_FOREACH(ref_ptr<Technique>& technique, techniques)
95 if (technique->valid(info) == Technique::VALID)
96 return technique.get();
101 void Effect::resizeGLObjectBuffers(unsigned int maxSize)
103 BOOST_FOREACH(const ref_ptr<Technique>& technique, techniques)
105 technique->resizeGLObjectBuffers(maxSize);
109 void Effect::releaseGLObjects(osg::State* state) const
111 BOOST_FOREACH(const ref_ptr<Technique>& technique, techniques)
113 technique->releaseGLObjects(state);
121 class PassAttributeBuilder : public Referenced
124 virtual void buildAttribute(Effect* effect, Pass* pass,
125 const SGPropertyNode* prop,
126 const osgDB::ReaderWriter::Options* options)
130 typedef map<const string, ref_ptr<PassAttributeBuilder> > PassAttrMap;
131 PassAttrMap passAttrMap;
134 struct InstallAttributeBuilder
136 InstallAttributeBuilder(const string& name)
138 passAttrMap.insert(make_pair(name, new T));
141 // Simple tables of strings and OSG constants. The table intialization
142 // *must* be in alphabetical order.
143 template <typename T>
144 struct EffectNameValue
146 // Don't use std::pair because we want to use aggregate intialization.
153 static bool compare(const char* lhs, const char* rhs)
155 return strcmp(lhs, rhs) < 0;
158 bool operator()(const EffectNameValue& lhs,
159 const EffectNameValue& rhs) const
161 return compare(lhs.first, rhs.first);
163 bool operator()(const char* lhs, const EffectNameValue& rhs) const
165 return compare(lhs, rhs.first);
167 bool operator()(const EffectNameValue& lhs, const char* rhs) const
169 return compare (lhs.first, rhs);
174 template<typename ENV, typename T, int N>
175 bool findAttr(const ENV (&attrs)[N], const SGPropertyNode* prop, T& result)
179 const char* name = prop->getStringValue();
182 std::pair<const ENV*, const ENV*> itrs
183 = std::equal_range(&attrs[0], &attrs[N], name, typename ENV::Compare());
184 if (itrs.first == itrs.second) {
187 result = itrs.first->second;
192 void buildPass(Effect* effect, Technique* tniq, const SGPropertyNode* prop,
193 const osgDB::ReaderWriter::Options* options)
195 Pass* pass = new Pass;
196 tniq->passes.push_back(pass);
197 for (int i = 0; i < prop->nChildren(); ++i) {
198 const SGPropertyNode* attrProp = prop->getChild(i);
199 PassAttrMap::iterator itr = passAttrMap.find(attrProp->getName());
200 if (itr != passAttrMap.end())
201 itr->second->buildAttribute(effect, pass, attrProp, options);
203 SG_LOG(SG_INPUT, SG_ALERT,
204 "skipping unknown pass attribute " << attrProp->getName());
208 osg::Vec4f getColor(const SGPropertyNode* prop)
210 if (prop->nChildren() == 0) {
211 if (prop->getType() == props::VEC4D) {
212 return osg::Vec4f(prop->getValue<SGVec4d>().osg());
213 } else if (prop->getType() == props::VEC3D) {
214 return osg::Vec4f(prop->getValue<SGVec3d>().osg(), 1.0f);
216 SG_LOG(SG_INPUT, SG_ALERT,
217 "invalid color property " << prop->getName() << " "
218 << prop->getStringValue());
219 return osg::Vec4f(0.0f, 0.0f, 0.0f, 1.0f);
223 static const char* colors[] = {"r", "g", "b"};
224 for (int i = 0; i < 3; ++i) {
225 const SGPropertyNode* componentProp = prop->getChild(colors[i]);
226 result[i] = componentProp ? componentProp->getValue<float>() : 0.0f;
228 const SGPropertyNode* alphaProp = prop->getChild("a");
229 result[3] = alphaProp ? alphaProp->getValue<float>() : 1.0f;
234 // Given a property node from a pass, get its value either from it or
235 // from the effect parameters.
236 const SGPropertyNode* getEffectPropertyNode(Effect* effect,
237 const SGPropertyNode* prop)
241 if (prop->nChildren() > 0) {
242 const SGPropertyNode* useProp = prop->getChild("use");
243 if (!useProp || !effect->parametersProp)
245 return effect->parametersProp->getNode(useProp->getStringValue());
250 // Get a named child property from pass parameters or effect
252 const SGPropertyNode* getEffectPropertyChild(Effect* effect,
253 const SGPropertyNode* prop,
256 const SGPropertyNode* child = prop->getChild(name);
260 return getEffectPropertyNode(effect, child);
263 struct LightingBuilder : public PassAttributeBuilder
265 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
266 const osgDB::ReaderWriter::Options* options);
269 void LightingBuilder::buildAttribute(Effect* effect, Pass* pass,
270 const SGPropertyNode* prop,
271 const osgDB::ReaderWriter::Options* options)
273 const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop);
276 pass->setMode(GL_LIGHTING, (realProp->getValue<bool>() ? StateAttribute::ON
277 : StateAttribute::OFF));
280 InstallAttributeBuilder<LightingBuilder> installLighting("lighting");
282 struct ShadeModelBuilder : public PassAttributeBuilder
284 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
285 const osgDB::ReaderWriter::Options* options)
287 const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop);
290 StateAttributeFactory *attrFact = StateAttributeFactory::instance();
291 string propVal = realProp->getStringValue();
292 if (propVal == "flat")
293 pass->setAttribute(attrFact->getFlatShadeModel());
294 else if (propVal == "smooth")
295 pass->setAttribute(attrFact->getSmoothShadeModel());
297 SG_LOG(SG_INPUT, SG_ALERT,
298 "invalid shade model property " << propVal);
302 InstallAttributeBuilder<ShadeModelBuilder> installShadeModel("shade-model");
304 struct CullFaceBuilder : PassAttributeBuilder
306 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
307 const osgDB::ReaderWriter::Options* options)
309 const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop);
312 StateAttributeFactory *attrFact = StateAttributeFactory::instance();
313 string propVal = realProp->getStringValue();
314 if (propVal == "front")
315 pass->setAttributeAndModes(attrFact->getCullFaceFront());
316 else if (propVal == "back")
317 pass->setAttributeAndModes(attrFact->getCullFaceBack());
318 else if (propVal == "front-back")
319 pass->setAttributeAndModes(new CullFace(CullFace::FRONT_AND_BACK));
321 SG_LOG(SG_INPUT, SG_ALERT,
322 "invalid cull face property " << propVal);
326 InstallAttributeBuilder<CullFaceBuilder> installCullFace("cull-face");
328 struct HintBuilder : public PassAttributeBuilder
330 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
331 const osgDB::ReaderWriter::Options* options)
333 const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop);
336 string propVal = realProp->getStringValue();
337 if (propVal == "opaque")
338 pass->setRenderingHint(StateSet::OPAQUE_BIN);
339 else if (propVal == "transparent")
340 pass->setRenderingHint(StateSet::TRANSPARENT_BIN);
344 InstallAttributeBuilder<HintBuilder> installHint("rendering-hint");
346 struct RenderBinBuilder : public PassAttributeBuilder
348 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
349 const osgDB::ReaderWriter::Options* options)
351 const SGPropertyNode* binProp = prop->getChild("bin-number");
352 binProp = getEffectPropertyNode(effect, binProp);
353 const SGPropertyNode* nameProp = prop->getChild("bin-name");
354 nameProp = getEffectPropertyNode(effect, nameProp);
355 if (binProp && nameProp) {
356 pass->setRenderBinDetails(binProp->getIntValue(),
357 nameProp->getStringValue());
360 SG_LOG(SG_INPUT, SG_ALERT,
361 "No render bin number specified in render bin section");
363 SG_LOG(SG_INPUT, SG_ALERT,
364 "No render bin name specified in render bin section");
369 InstallAttributeBuilder<RenderBinBuilder> installRenderBin("render-bin");
371 struct MaterialBuilder : public PassAttributeBuilder
373 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
374 const osgDB::ReaderWriter::Options* options);
377 EffectNameValue<Material::ColorMode> colorModes[] =
379 { "ambient", Material::AMBIENT },
380 { "ambient-and-diffuse", Material::AMBIENT_AND_DIFFUSE },
381 { "diffuse", Material::DIFFUSE },
382 { "emissive", Material::EMISSION },
383 { "specular", Material::SPECULAR },
384 { "off", Material::OFF }
387 void MaterialBuilder::buildAttribute(Effect* effect, Pass* pass,
388 const SGPropertyNode* prop,
389 const osgDB::ReaderWriter::Options* options)
391 Material* mat = new Material;
392 const SGPropertyNode* color = 0;
393 if ((color = getEffectPropertyChild(effect, prop, "ambient")))
394 mat->setAmbient(Material::FRONT_AND_BACK, getColor(color));
395 if ((color = getEffectPropertyChild(effect, prop, "ambient-front")))
396 mat->setAmbient(Material::FRONT, getColor(color));
397 if ((color = getEffectPropertyChild(effect, prop, "ambient-back")))
398 mat->setAmbient(Material::BACK, getColor(color));
399 if ((color = getEffectPropertyChild(effect, prop, "diffuse")))
400 mat->setDiffuse(Material::FRONT_AND_BACK, getColor(color));
401 if ((color = getEffectPropertyChild(effect, prop, "diffuse-front")))
402 mat->setDiffuse(Material::FRONT, getColor(color));
403 if ((color = getEffectPropertyChild(effect, prop, "diffuse-back")))
404 mat->setDiffuse(Material::BACK, getColor(color));
405 if ((color = getEffectPropertyChild(effect, prop, "specular")))
406 mat->setSpecular(Material::FRONT_AND_BACK, getColor(color));
407 if ((color = getEffectPropertyChild(effect, prop, "specular-front")))
408 mat->setSpecular(Material::FRONT, getColor(color));
409 if ((color = getEffectPropertyChild(effect, prop, "specular-back")))
410 mat->setSpecular(Material::BACK, getColor(color));
411 if ((color = getEffectPropertyChild(effect, prop, "emissive")))
412 mat->setEmission(Material::FRONT_AND_BACK, getColor(color));
413 if ((color = getEffectPropertyChild(effect, prop, "emissive-front")))
414 mat->setEmission(Material::FRONT, getColor(color));
415 if ((color = getEffectPropertyChild(effect, prop, "emissive-back")))
416 mat->setEmission(Material::BACK, getColor(color));
417 const SGPropertyNode* shininess = 0;
418 if ((shininess = getEffectPropertyChild(effect, prop, "shininess")))
419 mat->setShininess(Material::FRONT_AND_BACK, shininess->getFloatValue());
420 if ((shininess = getEffectPropertyChild(effect, prop, "shininess-front")))
421 mat->setShininess(Material::FRONT, shininess->getFloatValue());
422 if ((shininess = getEffectPropertyChild(effect, prop, "shininess-back")))
423 mat->setShininess(Material::BACK, shininess->getFloatValue());
424 Material::ColorMode colorMode = Material::OFF;
425 findAttr(colorModes, getEffectPropertyChild(effect, prop, "color-mode"),
427 mat->setColorMode(colorMode);
428 pass->setAttribute(mat);
431 InstallAttributeBuilder<MaterialBuilder> installMaterial("material");
433 struct BlendBuilder : public PassAttributeBuilder
435 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
436 const osgDB::ReaderWriter::Options* options)
438 const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop);
441 pass->setMode(GL_BLEND, (realProp->getBoolValue()
443 : StateAttribute::OFF));
447 InstallAttributeBuilder<BlendBuilder> installBlend("blend");
449 struct AlphaTestBuilder : public PassAttributeBuilder
451 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
452 const osgDB::ReaderWriter::Options* options)
454 const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop);
457 pass->setMode(GL_ALPHA_TEST, (realProp->getBoolValue()
459 : StateAttribute::OFF));
463 InstallAttributeBuilder<AlphaTestBuilder> installAlphaTest("alpha-test");
465 EffectNameValue<Texture::FilterMode> filterModes[] =
467 { "linear", Texture::LINEAR },
468 { "linear-mipmap-linear", Texture::LINEAR_MIPMAP_LINEAR},
469 { "linear-mipmap-nearest", Texture::LINEAR_MIPMAP_NEAREST},
470 { "nearest", Texture::NEAREST},
471 { "nearest-mipmap-linear", Texture::NEAREST_MIPMAP_LINEAR},
472 { "nearest-mipmap-nearest", Texture::NEAREST_MIPMAP_NEAREST}
475 EffectNameValue<Texture::WrapMode> wrapModes[] =
477 {"clamp", Texture::CLAMP},
478 {"clamp-to-border", Texture::CLAMP_TO_BORDER},
479 {"clamp-to-edge", Texture::CLAMP_TO_EDGE},
480 {"mirror", Texture::MIRROR},
481 {"repeat", Texture::REPEAT}
484 EffectNameValue<TexEnv::Mode> texEnvModes[] =
486 {"add", TexEnv::ADD},
487 {"blend", TexEnv::BLEND},
488 {"decal", TexEnv::DECAL},
489 {"modulate", TexEnv::MODULATE},
490 {"replace", TexEnv::REPLACE}
493 TexEnv* buildTexEnv(Effect* effect, const SGPropertyNode* prop)
495 const SGPropertyNode* modeProp = getEffectPropertyChild(effect, prop,
497 const SGPropertyNode* colorProp = getEffectPropertyChild(effect, prop,
501 TexEnv::Mode mode = TexEnv::MODULATE;
502 findAttr(texEnvModes, modeProp, mode);
503 if (mode == TexEnv::MODULATE) {
504 return StateAttributeFactory::instance()->getStandardTexEnv();
506 TexEnv* env = new TexEnv(mode);
508 env->setColor(colorProp->getValue<SGVec4d>().osg());
512 typedef boost::tuple<string, Texture::FilterMode, Texture::FilterMode,
513 Texture::WrapMode, Texture::WrapMode,
514 Texture::WrapMode> TexTuple;
516 typedef map<TexTuple, ref_ptr<Texture2D> > TexMap;
520 struct TextureUnitBuilder : PassAttributeBuilder
522 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
523 const osgDB::ReaderWriter::Options* options);
526 void TextureUnitBuilder::buildAttribute(Effect* effect, Pass* pass,
527 const SGPropertyNode* prop,
528 const osgDB::ReaderWriter::Options* options)
530 // First, all the texture properties
531 const SGPropertyNode* pTexture2d = prop->getChild("texture2d");
534 const SGPropertyNode* pImage
535 = getEffectPropertyChild(effect, pTexture2d, "image");
538 const char* imageName = pImage->getStringValue();
539 Texture::FilterMode minFilter = Texture::LINEAR_MIPMAP_LINEAR;
540 findAttr(filterModes, getEffectPropertyChild(effect, pTexture2d, "filter"),
542 Texture::FilterMode magFilter = Texture::LINEAR;
543 findAttr(filterModes, getEffectPropertyChild(effect, pTexture2d,
546 const SGPropertyNode* pWrapS
547 = getEffectPropertyChild(effect, pTexture2d, "wrap-s");
548 Texture::WrapMode sWrap = Texture::CLAMP;
549 findAttr(wrapModes, pWrapS, sWrap);
550 const SGPropertyNode* pWrapT
551 = getEffectPropertyChild(effect, pTexture2d, "wrap-t");
552 Texture::WrapMode tWrap = Texture::CLAMP;
553 findAttr(wrapModes, pWrapT, tWrap);
554 const SGPropertyNode* pWrapR
555 = getEffectPropertyChild(effect, pTexture2d, "wrap-r");
556 Texture::WrapMode rWrap = Texture::CLAMP;
557 findAttr(wrapModes, pWrapR, rWrap);
558 TexTuple tuple(imageName, minFilter, magFilter, sWrap, tWrap, rWrap);
559 TexMap::iterator texIter = texMap.find(tuple);
560 Texture2D* texture = 0;
561 if (texIter != texMap.end()) {
562 texture = texIter->second.get();
564 texture = new Texture2D;
565 osgDB::ReaderWriter::ReadResult result
566 = osgDB::Registry::instance()->readImage(imageName, options);
567 if (result.success()) {
568 osg::Image* image = result.getImage();
569 texture->setImage(image);
573 if (s <= t && 32 <= s) {
574 SGSceneFeatures::instance()->setTextureCompression(texture);
575 } else if (t < s && 32 <= t) {
576 SGSceneFeatures::instance()->setTextureCompression(texture);
578 texture->setMaxAnisotropy(SGSceneFeatures::instance()
579 ->getTextureFilter());
581 SG_LOG(SG_INPUT, SG_ALERT, "failed to load effect texture file "
584 // texture->setDataVariance(osg::Object::STATIC);
585 texture->setFilter(Texture::MIN_FILTER, minFilter);
586 texture->setFilter(Texture::MAG_FILTER, magFilter);
587 texture->setWrap(Texture::WRAP_S, sWrap);
588 texture->setWrap(Texture::WRAP_T, tWrap);
589 texture->setWrap(Texture::WRAP_R, rWrap);
590 texMap.insert(make_pair(tuple, texture));
592 // Decode the texture unit
594 const SGPropertyNode* pUnit = prop->getChild("unit");
596 unit = pUnit->getValue<int>();
598 const SGPropertyNode* pName = prop->getChild("name");
601 unit = boost::lexical_cast<int>(pName->getStringValue());
602 } catch (boost::bad_lexical_cast& lex) {
603 SG_LOG(SG_INPUT, SG_ALERT, "can't decode name as texture unit "
607 pass->setTextureAttributeAndModes(unit, texture);
608 const SGPropertyNode* envProp = prop->getChild("environment");
610 TexEnv* env = buildTexEnv(effect, envProp);
612 pass->setTextureAttributeAndModes(unit, env);
616 InstallAttributeBuilder<TextureUnitBuilder> textureUnitBuilder("texture-unit");
618 typedef map<string, ref_ptr<Program> > ProgramMap;
619 ProgramMap programMap;
621 typedef map<string, ref_ptr<Shader> > ShaderMap;
624 struct ShaderProgramBuilder : PassAttributeBuilder
626 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
627 const osgDB::ReaderWriter::Options* options);
630 void ShaderProgramBuilder::buildAttribute(Effect* effect, Pass* pass,
631 const SGPropertyNode* prop,
632 const osgDB::ReaderWriter::Options*
635 PropertyList pVertShaders = prop->getChildren("vertex-shader");
636 PropertyList pFragShaders = prop->getChildren("fragment-shader");
638 for (PropertyList::iterator itr = pVertShaders.begin(),
639 e = pVertShaders.end();
643 programKey += (*itr)->getStringValue();
646 for (PropertyList::iterator itr = pFragShaders.begin(),
647 e = pFragShaders.end();
651 programKey += (*itr)->getStringValue();
654 Program* program = 0;
655 ProgramMap::iterator pitr = programMap.find(programKey);
656 if (pitr != programMap.end()) {
657 program = pitr->second.get();
659 program = new Program;
660 // Add vertex shaders, then fragment shaders
661 PropertyList& pvec = pVertShaders;
662 Shader::Type stype = Shader::VERTEX;
663 for (int i = 0; i < 2; ++i) {
664 for (PropertyList::iterator nameItr = pvec.begin(), e = pvec.end();
667 string shaderName = (*nameItr)->getStringValue();
668 ShaderMap::iterator sitr = shaderMap.find(shaderName);
669 if (sitr != shaderMap.end()) {
670 program->addShader(sitr->second.get());
672 string fileName = osgDB::Registry::instance()
673 ->findDataFile(shaderName, options,
674 osgDB::CASE_SENSITIVE);
675 if (!fileName.empty()) {
676 ref_ptr<Shader> shader = new Shader(stype);
677 if (shader->loadShaderSourceFromFile(fileName)) {
678 shaderMap.insert(make_pair(shaderName, shader));
679 program->addShader(shader.get());
685 stype = Shader::FRAGMENT;
687 programMap.insert(make_pair(programKey, program));
689 pass->setAttributeAndModes(program);
692 InstallAttributeBuilder<ShaderProgramBuilder> installShaderProgram("program");
694 EffectNameValue<Uniform::Type> uniformTypes[] =
696 {"float", Uniform::FLOAT},
697 {"float-vec3", Uniform::FLOAT_VEC3},
698 {"float-vec4", Uniform::FLOAT_VEC4},
699 {"sampler-1d", Uniform::SAMPLER_1D},
700 {"sampler-2d", Uniform::SAMPLER_2D},
701 {"sampler-3d", Uniform::SAMPLER_3D}
704 struct UniformBuilder :public PassAttributeBuilder
706 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
707 const osgDB::ReaderWriter::Options* options)
709 using namespace simgear::props;
710 const SGPropertyNode* nameProp = prop->getChild("name");
711 const SGPropertyNode* typeProp = prop->getChild("type");
712 const SGPropertyNode* valProp
713 = getEffectPropertyChild(effect, prop, "value");
715 Uniform::Type uniformType = Uniform::FLOAT;
717 name = nameProp->getStringValue();
719 SG_LOG(SG_INPUT, SG_ALERT, "No name for uniform property ");
723 SG_LOG(SG_INPUT, SG_ALERT, "No value for uniform property "
728 props::Type propType = valProp->getType();
732 break; // default float type;
734 uniformType = Uniform::FLOAT_VEC3;
737 uniformType = Uniform::FLOAT_VEC4;
740 SG_LOG(SG_INPUT, SG_ALERT, "Can't deduce type of uniform "
745 findAttr(uniformTypes, typeProp, uniformType);
747 ref_ptr<Uniform> uniform = new Uniform;
748 uniform->setName(name);
749 uniform->setType(uniformType);
750 switch (uniformType) {
752 uniform->set(valProp->getValue<float>());
754 case Uniform::FLOAT_VEC3:
755 uniform->set(Vec3f(valProp->getValue<SGVec3d>().osg()));
757 case Uniform::FLOAT_VEC4:
758 uniform->set(Vec4f(valProp->getValue<SGVec4d>().osg()));
760 case Uniform::SAMPLER_1D:
761 case Uniform::SAMPLER_2D:
762 case Uniform::SAMPLER_3D:
763 uniform->set(valProp->getValue<int>());
766 pass->addUniform(uniform.get());
770 InstallAttributeBuilder<UniformBuilder> installUniform("uniform");
772 // Not sure what to do with "name". At one point I wanted to use it to
773 // order the passes, but I do support render bin and stuff too...
775 struct NameBuilder : public PassAttributeBuilder
777 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
778 const osgDB::ReaderWriter::Options* options)
780 // name can't use <use>
781 string name = prop->getStringValue();
787 InstallAttributeBuilder<NameBuilder> installName("name");
789 EffectNameValue<PolygonMode::Mode> polygonModeModes[] =
791 {"fill", PolygonMode::FILL},
792 {"line", PolygonMode::LINE},
793 {"point", PolygonMode::POINT}
796 struct PolygonModeBuilder : public PassAttributeBuilder
798 void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
799 const osgDB::ReaderWriter::Options* options)
801 const SGPropertyNode* frontProp
802 = getEffectPropertyChild(effect, prop, "front");
803 const SGPropertyNode* backProp
804 = getEffectPropertyChild(effect, prop, "back");
805 ref_ptr<PolygonMode> pmode = new PolygonMode;
806 PolygonMode::Mode frontMode = PolygonMode::FILL;
807 PolygonMode::Mode backMode = PolygonMode::FILL;
809 findAttr(polygonModeModes, frontProp, frontMode);
810 pmode->setMode(PolygonMode::FRONT, frontMode);
813 findAttr(polygonModeModes, backProp, backMode);
814 pmode->setMode(PolygonMode::BACK, backMode);
816 pass->setAttribute(pmode.get());
820 InstallAttributeBuilder<PolygonModeBuilder> installPolygonMode("polygon-mode");
821 void buildTechnique(Effect* effect, const SGPropertyNode* prop,
822 const osgDB::ReaderWriter::Options* options)
824 Technique* tniq = new Technique;
825 effect->techniques.push_back(tniq);
826 const SGPropertyNode* predProp = prop->getChild("predicate");
828 tniq->setAlwaysValid(true);
831 expression::BindingLayout layout;
832 int contextLoc = layout.addBinding("__contextId", expression::INT);
833 SGExpressionb* validExp
834 = dynamic_cast<SGExpressionb*>(expression::read(predProp
837 tniq->setValidExpression(validExp, layout);
839 throw expression::ParseError("technique predicate is not a boolean expression");
841 catch (expression::ParseError& except)
843 SG_LOG(SG_INPUT, SG_ALERT,
844 "parsing technique predicate " << except.getMessage());
845 tniq->setAlwaysValid(false);
848 PropertyList passProps = prop->getChildren("pass");
849 for (PropertyList::iterator itr = passProps.begin(), e = passProps.end();
852 buildPass(effect, tniq, itr->ptr(), options);
856 // Walk the techniques property tree, building techniques and
858 bool Effect::realizeTechniques(const osgDB::ReaderWriter::Options* options)
860 PropertyList tniqList = root->getChildren("technique");
861 for (PropertyList::iterator itr = tniqList.begin(), e = tniqList.end();
864 buildTechnique(this, *itr, options);
867 bool Effect_writeLocalData(const Object& obj, osgDB::Output& fw)
869 const Effect& effect = static_cast<const Effect&>(obj);
871 fw.indent() << "techniques " << effect.techniques.size() << "\n";
872 BOOST_FOREACH(const ref_ptr<Technique>& technique, effect.techniques) {
873 fw.writeObject(*technique);
880 osgDB::RegisterDotOsgWrapperProxy effectProxy
884 "Object simgear::Effect",
886 &Effect_writeLocalData