]> git.mxchange.org Git - simgear.git/commitdiff
Construct effects from property lists
authortimoore <timoore>
Wed, 15 Jul 2009 23:10:44 +0000 (23:10 +0000)
committerTim Moore <timoore@redhat.com>
Thu, 16 Jul 2009 10:09:44 +0000 (12:09 +0200)
The material code constructs a property list from its input parameters.

Enable dumping of Pass and Technique objects to a file.

Default effect now uses texture node instead of texture0

simgear/scene/material/Effect.cxx
simgear/scene/material/Effect.hxx
simgear/scene/material/Makefile.am
simgear/scene/material/Pass.cxx
simgear/scene/material/Technique.cxx
simgear/scene/material/makeEffect.cxx [new file with mode: 0644]
simgear/scene/material/mat.cxx
simgear/scene/material/mat.hxx
simgear/scene/material/matlib.cxx

index 6e8fd9317181a5919180c39858adbc16e106cf27..c1db1d73e59a300328f4fa4a0b0b6059847d500a 100644 (file)
@@ -1,3 +1,19 @@
+// Copyright (C) 2008 - 2009  Tim Moore timoore@redhat.com
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
 #include "Effect.hxx"
 #include "Technique.hxx"
 #include "Pass.hxx"
 #include <algorithm>
 #include <functional>
 #include <iterator>
+#include <map>
+#include <utility>
 
 #include <boost/bind.hpp>
 #include <boost/foreach.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/tuple/tuple.hpp>
+#include <boost/tuple/tuple_comparison.hpp>
 
+#include <osg/CullFace>
 #include <osg/Drawable>
+#include <osg/Material>
+#include <osg/Program>
+#include <osg/Referenced>
 #include <osg/RenderInfo>
+#include <osg/ShadeModel>
 #include <osg/StateSet>
+#include <osg/TexEnv>
+#include <osg/Texture2D>
+#include <osg/Vec4d>
 #include <osgUtil/CullVisitor>
-#include <osgDB/Registry>
+#include <osgDB/FileUtils>
 #include <osgDB/Input>
 #include <osgDB/ParameterOutput>
+#include <osgDB/ReadFile>
+#include <osgDB/Registry>
 
+#include <simgear/scene/util/SGSceneFeatures.hxx>
+#include <simgear/scene/util/StateAttributeFactory.hxx>
 #include <simgear/structure/OSGUtils.hxx>
+#include <simgear/structure/SGExpression.hxx>
 
 
 
 namespace simgear
 {
+using namespace std;
 using namespace osg;
 using namespace osgUtil;
 
@@ -31,8 +66,8 @@ Effect::Effect()
 }
 
 Effect::Effect(const Effect& rhs, const CopyOp& copyop)
+    : root(rhs.root), parametersProp(rhs.parametersProp)
 {
-    using namespace std;
     using namespace boost;
     transform(rhs.techniques.begin(), rhs.techniques.end(),
               backRefInsertIterator(techniques),
@@ -81,6 +116,638 @@ Effect::~Effect()
 {
 }
 
+class PassAttributeBuilder : public Referenced
+{
+public:
+    virtual void buildAttribute(Effect* effect, Pass* pass,
+                                const SGPropertyNode* prop,
+                                const osgDB::ReaderWriter::Options* options)
+    = 0;
+};
+
+typedef map<const string, ref_ptr<PassAttributeBuilder> > PassAttrMap;
+PassAttrMap passAttrMap;
+
+template<typename T>
+struct InstallAttributeBuilder
+{
+    InstallAttributeBuilder(const string& name)
+    {
+        passAttrMap.insert(make_pair(name, new T));
+    }
+};
+// Simple tables of strings and OSG constants. The table intialization
+// *must* be in alphabetical order.
+template <typename T>
+struct EffectNameValue
+{
+    // Don't use std::pair because we want to use aggregate intialization.
+
+    const char* first;
+    T second;
+    class Compare
+    {
+    private:
+        static bool compare(const char* lhs, const char* rhs)
+        {
+            return strcmp(lhs, rhs) < 0;
+        }
+    public:
+        bool operator()(const EffectNameValue& lhs,
+                        const EffectNameValue& rhs) const
+        {
+            return compare(lhs.first, rhs.first);
+        }
+        bool operator()(const char* lhs, const EffectNameValue& rhs) const
+        {
+            return compare(lhs, rhs.first);
+        }
+        bool operator()(const EffectNameValue& lhs, const char* rhs) const
+        {
+            return compare (lhs.first, rhs);
+        }
+    };
+};
+
+template<typename ENV, typename T, int N>
+bool findAttr(const ENV (&attrs)[N], const SGPropertyNode* prop, T& result)
+{
+    if (!prop)
+        return false;
+    const char* name = prop->getStringValue();
+    if (!name)
+        return false;
+    std::pair<const ENV*, const ENV*> itrs
+        = std::equal_range(&attrs[0], &attrs[N], name, typename ENV::Compare());
+    if (itrs.first == itrs.second) {
+        return false;
+    } else {
+        result = itrs.first->second;
+        return true;
+    }
+}
+
+void buildPass(Effect* effect, Technique* tniq, const SGPropertyNode* prop,
+               const osgDB::ReaderWriter::Options* options)
+{
+    Pass* pass = new Pass;
+    tniq->passes.push_back(pass);
+    for (int i = 0; i < prop->nChildren(); ++i) {
+        const SGPropertyNode* attrProp = prop->getChild(i);
+        PassAttrMap::iterator itr = passAttrMap.find(attrProp->getName());
+        if (itr != passAttrMap.end())
+            itr->second->buildAttribute(effect, pass, attrProp, options);
+        else
+            SG_LOG(SG_INPUT, SG_ALERT,
+                   "skipping unknown pass attribute " << attrProp->getName());
+    }
+}
+
+osg::Vec4f getColor(const SGPropertyNode* prop)
+{
+    if (prop->nChildren() == 0) {
+        if (prop->getType() == props::VEC4D) {
+            return osg::Vec4f(prop->getValue<SGVec4d>().osg());
+        } else if (prop->getType() == props::VEC3D) {
+            return osg::Vec4f(prop->getValue<SGVec3d>().osg(), 1.0f);
+        } else {
+            SG_LOG(SG_INPUT, SG_ALERT,
+                   "invalid color property " << prop->getName() << " "
+                   << prop->getStringValue());
+            return osg::Vec4f(0.0f, 0.0f, 0.0f, 1.0f);
+        }
+    } else {
+        osg::Vec4f result;
+        static const char* colors[] = {"r", "g", "b"};
+        for (int i = 0; i < 3; ++i) {
+            const SGPropertyNode* componentProp = prop->getChild(colors[i]);
+            result[i] = componentProp ? componentProp->getValue<float>() : 0.0f;
+        }
+        const SGPropertyNode* alphaProp = prop->getChild("a");
+        result[3] = alphaProp ? alphaProp->getValue<float>() : 1.0f;
+        return result;
+    }
+}
+
+// Given a property node from a pass, get its value either from it or
+// from the effect parameters.
+const SGPropertyNode* getEffectPropertyNode(Effect* effect,
+                                            const SGPropertyNode* prop)
+{
+    if (!prop)
+        return 0;
+    if (prop->nChildren() > 0) {
+        const SGPropertyNode* useProp = prop->getChild("use");
+        if (!useProp || !effect->parametersProp)
+            return prop;
+        return effect->parametersProp->getNode(useProp->getStringValue());
+    }
+    return prop;
+}
+
+// Get a named child property from pass parameters or effect
+// parameters.
+const SGPropertyNode* getEffectPropertyChild(Effect* effect,
+                                             const SGPropertyNode* prop,
+                                             const char* name)
+{
+    const SGPropertyNode* child = prop->getChild(name);
+    if (!child)
+        return 0;
+    else
+        return getEffectPropertyNode(effect, child);
+}
+
+struct LightingBuilder : public PassAttributeBuilder
+{
+    void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
+                        const osgDB::ReaderWriter::Options* options);
+};
+
+void LightingBuilder::buildAttribute(Effect* effect, Pass* pass,
+                                     const SGPropertyNode* prop,
+                                     const osgDB::ReaderWriter::Options* options)
+{
+    const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop);
+    if (!realProp)
+        return;
+    pass->setMode(GL_LIGHTING, (realProp->getValue<bool>() ? StateAttribute::ON
+                                : StateAttribute::OFF));
+}
+
+InstallAttributeBuilder<LightingBuilder> installLighting("lighting");
+
+struct ShadeModelBuilder : public PassAttributeBuilder
+{
+    void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
+                        const osgDB::ReaderWriter::Options* options)
+    {
+        const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop);
+        if (!realProp)
+            return;
+        StateAttributeFactory *attrFact = StateAttributeFactory::instance();
+        string propVal = realProp->getStringValue();
+        if (propVal == "flat")
+            pass->setAttribute(attrFact->getFlatShadeModel());
+        else if (propVal == "smooth")
+            pass->setAttribute(attrFact->getSmoothShadeModel());
+        else
+            SG_LOG(SG_INPUT, SG_ALERT,
+                   "invalid shade model property " << propVal);
+    }
+};
+
+InstallAttributeBuilder<ShadeModelBuilder> installShadeModel("shade-model");
+
+struct CullFaceBuilder : PassAttributeBuilder
+{
+    void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
+                        const osgDB::ReaderWriter::Options* options)
+    {
+        const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop);
+        if (!realProp)
+            return;
+        StateAttributeFactory *attrFact = StateAttributeFactory::instance();
+        string propVal = realProp->getStringValue();
+        if (propVal == "front")
+            pass->setAttributeAndModes(attrFact->getCullFaceFront());
+        else if (propVal == "back")
+            pass->setAttributeAndModes(attrFact->getCullFaceBack());
+        else if (propVal == "front-back")
+            pass->setAttributeAndModes(new CullFace(CullFace::FRONT_AND_BACK));
+        else
+            SG_LOG(SG_INPUT, SG_ALERT,
+                   "invalid cull face property " << propVal);            
+    }    
+};
+
+InstallAttributeBuilder<CullFaceBuilder> installCullFace("cull-face");
+
+struct HintBuilder : public PassAttributeBuilder
+{
+    void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
+                        const osgDB::ReaderWriter::Options* options)
+    {
+        const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop);
+        if (!realProp)
+            return;
+        string propVal = realProp->getStringValue();
+        if (propVal == "opaque")
+            pass->setRenderingHint(StateSet::OPAQUE_BIN);
+        else if (propVal == "transparent")
+            pass->setRenderingHint(StateSet::TRANSPARENT_BIN);
+    }    
+};
+
+InstallAttributeBuilder<HintBuilder> installHint("rendering-hint");
+
+struct RenderBinBuilder : public PassAttributeBuilder
+{
+    void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
+                        const osgDB::ReaderWriter::Options* options)
+    {
+        const SGPropertyNode* binProp = prop->getChild("bin-number");
+        binProp = getEffectPropertyNode(effect, binProp);
+        const SGPropertyNode* nameProp = prop->getChild("bin-name");
+        nameProp = getEffectPropertyNode(effect, nameProp);
+        if (binProp && nameProp) {
+            pass->setRenderBinDetails(binProp->getIntValue(),
+                                      nameProp->getStringValue());
+        } else {
+            if (!binProp)
+                SG_LOG(SG_INPUT, SG_ALERT,
+                       "No render bin number specified in render bin section");
+            if (!nameProp)
+                SG_LOG(SG_INPUT, SG_ALERT,
+                       "No render bin name specified in render bin section");
+        }
+    }
+};
+
+InstallAttributeBuilder<RenderBinBuilder> installRenderBin("render-bin");
+
+struct MaterialBuilder : public PassAttributeBuilder
+{
+    void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
+                        const osgDB::ReaderWriter::Options* options);
+};
+
+EffectNameValue<Material::ColorMode> colorModes[] =
+{
+    { "ambient", Material::AMBIENT },
+    { "ambient-and-diffuse", Material::AMBIENT_AND_DIFFUSE },
+    { "diffuse", Material::DIFFUSE },
+    { "emissive", Material::EMISSION },
+    { "specular", Material::SPECULAR },
+    { "off", Material::OFF }
+};
+
+void MaterialBuilder::buildAttribute(Effect* effect, Pass* pass,
+                                     const SGPropertyNode* prop,
+                                     const osgDB::ReaderWriter::Options* options)
+{
+    Material* mat = new Material;
+    const SGPropertyNode* color = 0;
+    if ((color = getEffectPropertyChild(effect, prop, "ambient")))
+        mat->setAmbient(Material::FRONT_AND_BACK, getColor(color));
+    if ((color = getEffectPropertyChild(effect, prop, "ambient-front")))
+        mat->setAmbient(Material::FRONT, getColor(color));
+    if ((color = getEffectPropertyChild(effect, prop, "ambient-back")))
+        mat->setAmbient(Material::BACK, getColor(color));
+    if ((color = getEffectPropertyChild(effect, prop, "diffuse")))
+        mat->setDiffuse(Material::FRONT_AND_BACK, getColor(color));
+    if ((color = getEffectPropertyChild(effect, prop, "diffuse-front")))
+        mat->setDiffuse(Material::FRONT, getColor(color));
+    if ((color = getEffectPropertyChild(effect, prop, "diffuse-back")))
+        mat->setDiffuse(Material::BACK, getColor(color));
+    if ((color = getEffectPropertyChild(effect, prop, "specular")))
+        mat->setSpecular(Material::FRONT_AND_BACK, getColor(color));
+    if ((color = getEffectPropertyChild(effect, prop, "specular-front")))
+        mat->setSpecular(Material::FRONT, getColor(color));
+    if ((color = getEffectPropertyChild(effect, prop, "specular-back")))
+        mat->setSpecular(Material::BACK, getColor(color));
+    if ((color = getEffectPropertyChild(effect, prop, "emissive")))
+        mat->setEmission(Material::FRONT_AND_BACK, getColor(color));
+    if ((color = getEffectPropertyChild(effect, prop, "emissive-front")))
+        mat->setEmission(Material::FRONT, getColor(color));        
+    if ((color = getEffectPropertyChild(effect, prop, "emissive-back")))
+        mat->setEmission(Material::BACK, getColor(color));        
+    const SGPropertyNode* shininess = 0;
+    if ((shininess = getEffectPropertyChild(effect, prop, "shininess")))
+        mat->setShininess(Material::FRONT_AND_BACK, shininess->getFloatValue());
+    if ((shininess = getEffectPropertyChild(effect, prop, "shininess-front")))
+        mat->setShininess(Material::FRONT, shininess->getFloatValue());
+    if ((shininess = getEffectPropertyChild(effect, prop, "shininess-back")))
+        mat->setShininess(Material::BACK, shininess->getFloatValue());
+    Material::ColorMode colorMode = Material::OFF;
+    findAttr(colorModes, getEffectPropertyChild(effect, prop, "color-mode"),
+             colorMode);
+    mat->setColorMode(colorMode);
+    pass->setAttribute(mat);
+}
+
+InstallAttributeBuilder<MaterialBuilder> installMaterial("material");
+
+struct BlendBuilder : public PassAttributeBuilder
+{
+    void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
+                        const osgDB::ReaderWriter::Options* options)
+    {
+        const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop);
+        if (!realProp)
+            return;
+        pass->setMode(GL_BLEND, (realProp->getBoolValue()
+                                 ? StateAttribute::ON
+                                 : StateAttribute::OFF));
+    }
+};
+
+InstallAttributeBuilder<BlendBuilder> installBlend("blend");
+
+struct AlphaTestBuilder : public PassAttributeBuilder
+{
+    void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
+                        const osgDB::ReaderWriter::Options* options)
+    {
+        const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop);
+        if (!realProp)
+            return;
+        pass->setMode(GL_ALPHA_TEST, (realProp->getBoolValue()
+                                      ? StateAttribute::ON
+                                      : StateAttribute::OFF));
+    }
+};
+
+InstallAttributeBuilder<AlphaTestBuilder> installAlphaTest("alpha-test");
+
+EffectNameValue<Texture::FilterMode> filterModes[] =
+{
+    { "linear", Texture::LINEAR },
+    { "linear-mipmap-linear", Texture::LINEAR_MIPMAP_LINEAR},
+    { "linear-mipmap-nearest", Texture::LINEAR_MIPMAP_NEAREST},
+    { "nearest", Texture::NEAREST},
+    { "nearest-mipmap-linear", Texture::NEAREST_MIPMAP_LINEAR},
+    { "nearest-mipmap-nearest", Texture::NEAREST_MIPMAP_NEAREST}
+};
+
+EffectNameValue<Texture::WrapMode> wrapModes[] =
+{
+    {"clamp", Texture::CLAMP},
+    {"clamp-to-border", Texture::CLAMP_TO_BORDER},
+    {"clamp-to-edge", Texture::CLAMP_TO_EDGE},
+    {"mirror", Texture::MIRROR},
+    {"repeat", Texture::REPEAT}
+};
+
+EffectNameValue<TexEnv::Mode> texEnvModes[] =
+{
+    {"add", TexEnv::ADD},
+    {"blend", TexEnv::BLEND},
+    {"decal", TexEnv::DECAL},
+    {"modulate", TexEnv::MODULATE},
+    {"replace", TexEnv::REPLACE}
+};
+
+TexEnv* buildTexEnv(Effect* effect, const SGPropertyNode* prop)
+{
+    const SGPropertyNode* modeProp = getEffectPropertyChild(effect, prop,
+                                                            "mode");
+    const SGPropertyNode* colorProp = getEffectPropertyChild(effect, prop,
+                                                             "color");
+    if (!modeProp)
+        return 0;
+    TexEnv::Mode mode = TexEnv::MODULATE;
+    findAttr(texEnvModes, modeProp, mode);
+    if (mode == TexEnv::MODULATE) {
+        return StateAttributeFactory::instance()->getStandardTexEnv();
+    }
+    TexEnv* env = new TexEnv(mode);
+    if (colorProp)
+        env->setColor(colorProp->getValue<SGVec4d>().osg());
+    return env;
+ }
+
+typedef boost::tuple<string, Texture::FilterMode, Texture::FilterMode,
+                     Texture::WrapMode, Texture::WrapMode,
+                     Texture::WrapMode> TexTuple;
+
+typedef map<TexTuple, ref_ptr<Texture2D> > TexMap;
+
+TexMap texMap;
+
+struct TextureUnitBuilder : PassAttributeBuilder
+{
+    void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
+                        const osgDB::ReaderWriter::Options* options);
+};
+
+void TextureUnitBuilder::buildAttribute(Effect* effect, Pass* pass,
+                                        const SGPropertyNode* prop,
+                                        const osgDB::ReaderWriter::Options* options)
+{
+    // First, all the texture properties
+    const SGPropertyNode* pTexture2d = prop->getChild("texture2d");
+    if (!pTexture2d)
+        return;
+    const SGPropertyNode* pImage
+        = getEffectPropertyChild(effect, pTexture2d, "image");
+    if (!pImage)
+        return;
+    const char* imageName = pImage->getStringValue();
+    Texture::FilterMode minFilter = Texture::LINEAR_MIPMAP_LINEAR;
+    findAttr(filterModes, getEffectPropertyChild(effect, pTexture2d, "filter"),
+             minFilter);
+    Texture::FilterMode magFilter = Texture::LINEAR;
+    findAttr(filterModes, getEffectPropertyChild(effect, pTexture2d,
+                                                 "mag-filter"),
+             magFilter);
+    const SGPropertyNode* pWrapS
+        = getEffectPropertyChild(effect, pTexture2d, "wrap-s");
+    Texture::WrapMode sWrap = Texture::CLAMP;
+    findAttr(wrapModes, pWrapS, sWrap);
+    const SGPropertyNode* pWrapT
+        = getEffectPropertyChild(effect, pTexture2d, "wrap-t");
+    Texture::WrapMode tWrap = Texture::CLAMP;
+    findAttr(wrapModes, pWrapT, tWrap);
+    const SGPropertyNode* pWrapR
+        = getEffectPropertyChild(effect, pTexture2d, "wrap-r");
+    Texture::WrapMode rWrap = Texture::CLAMP;
+    findAttr(wrapModes, pWrapR, rWrap);
+    TexTuple tuple(imageName, minFilter, magFilter, sWrap, tWrap, rWrap);
+    TexMap::iterator texIter = texMap.find(tuple);
+    Texture2D* texture = 0;
+    if (texIter != texMap.end()) {
+        texture = texIter->second.get();
+    } else {
+        texture = new Texture2D;
+        osgDB::ReaderWriter::ReadResult result
+            = osgDB::Registry::instance()->readImage(imageName, options);
+        if (result.success()) {
+            osg::Image* image = result.getImage();
+            texture->setImage(image);
+            int s = image->s();
+            int t = image->t();
+
+            if (s <= t && 32 <= s) {
+                SGSceneFeatures::instance()->setTextureCompression(texture);
+            } else if (t < s && 32 <= t) {
+                SGSceneFeatures::instance()->setTextureCompression(texture);
+            }
+            texture->setMaxAnisotropy(SGSceneFeatures::instance()
+                                      ->getTextureFilter());
+        } else {
+            SG_LOG(SG_INPUT, SG_ALERT, "failed to load effect texture file "
+                   << imageName);
+        }
+        // texture->setDataVariance(osg::Object::STATIC);
+        texture->setFilter(Texture::MIN_FILTER, minFilter);
+        texture->setFilter(Texture::MAG_FILTER, magFilter);
+        texture->setWrap(Texture::WRAP_S, sWrap);
+        texture->setWrap(Texture::WRAP_T, tWrap);
+        texture->setWrap(Texture::WRAP_R, rWrap);
+        texMap.insert(make_pair(tuple, texture));
+    }
+    // Decode the texture unit
+    int unit = 0;
+    const SGPropertyNode* pUnit = prop->getChild("unit");
+    if (pUnit) {
+        unit = pUnit->getValue<int>();
+    } else {
+        const SGPropertyNode* pName = prop->getChild("name");
+        if (pName)
+            try {
+                unit = boost::lexical_cast<int>(pName->getStringValue());
+            } catch (boost::bad_lexical_cast& lex) {
+                SG_LOG(SG_INPUT, SG_ALERT, "can't decode name as texture unit "
+                       << lex.what());
+            }
+    }
+    pass->setTextureAttributeAndModes(unit, texture);
+    const SGPropertyNode* envProp = prop->getChild("environment");
+    if (envProp) {
+        TexEnv* env = buildTexEnv(effect, envProp);
+        if (env)
+            pass->setTextureAttributeAndModes(unit, env);
+    }
+}
+
+InstallAttributeBuilder<TextureUnitBuilder> textureUnitBuilder("texture-unit");
+
+typedef map<string, ref_ptr<Program> > ProgramMap;
+ProgramMap programMap;
+
+typedef map<string, ref_ptr<Shader> > ShaderMap;
+ShaderMap shaderMap;
+
+struct ShaderProgramBuilder : PassAttributeBuilder
+{
+    void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
+                        const osgDB::ReaderWriter::Options* options);
+};
+
+void ShaderProgramBuilder::buildAttribute(Effect* effect, Pass* pass,
+                                          const SGPropertyNode* prop,
+                                          const osgDB::ReaderWriter::Options*
+                                          options)
+{
+    PropertyList pVertShaders = prop->getChildren("vertex-shader");
+    PropertyList pFragShaders = prop->getChildren("fragment-shader");
+    string programKey;
+    for (PropertyList::iterator itr = pVertShaders.begin(),
+             e = pVertShaders.end();
+         itr != e;
+         ++itr)
+    {
+        programKey += (*itr)->getStringValue();
+        programKey += ";";
+    }
+    for (PropertyList::iterator itr = pFragShaders.begin(),
+             e = pFragShaders.end();
+         itr != e;
+         ++itr)
+    {
+        programKey += (*itr)->getStringValue();
+        programKey += ";";
+    }
+    Program* program = 0;
+    ProgramMap::iterator pitr = programMap.find(programKey);
+    if (pitr != programMap.end()) {
+        program = pitr->second.get();
+    } else {
+        program = new Program;
+        // Add vertex shaders, then fragment shaders
+        PropertyList& pvec = pVertShaders;
+        Shader::Type stype = Shader::VERTEX;
+        for (int i = 0; i < 2; ++i) {
+            for (PropertyList::iterator nameItr = pvec.begin(), e = pvec.end();
+                 nameItr != e;
+                 ++nameItr) {
+                string shaderName = (*nameItr)->getStringValue();
+                ShaderMap::iterator sitr = shaderMap.find(shaderName);
+                if (sitr != shaderMap.end()) {
+                    program->addShader(sitr->second.get());
+                } else {
+                    string fileName = osgDB::findDataFile(shaderName, options);
+                    if (!fileName.empty()) {
+                        ref_ptr<Shader> shader = new Shader(stype);
+                        if (shader->loadShaderSourceFromFile(fileName)) {
+                            shaderMap.insert(make_pair(shaderName, shader));
+                            program->addShader(shader.get());
+                        }
+                    }
+                }
+            }
+            pvec = pFragShaders;
+            stype = Shader::FRAGMENT;
+        }
+        programMap.insert(make_pair(programKey, program));
+    }
+    pass->setAttributeAndModes(program);
+}
+
+// Not sure what to do with "name". At one point I wanted to use it to
+// order the passes, but I do support render bin and stuff too...
+
+struct NameBuilder : public PassAttributeBuilder
+{
+    void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
+                        const osgDB::ReaderWriter::Options* options)
+    {
+        // name can't use <use>
+        string name = prop->getStringValue();
+        if (!name.empty())
+            pass->setName(name);
+    }
+};
+
+InstallAttributeBuilder<NameBuilder> installName("name");
+
+void buildTechnique(Effect* effect, const SGPropertyNode* prop,
+                    const osgDB::ReaderWriter::Options* options)
+{
+    Technique* tniq = new Technique;
+    effect->techniques.push_back(tniq);
+    const SGPropertyNode* predProp = prop->getChild("predicate");
+    if (!predProp) {
+        tniq->setAlwaysValid(true);
+    } else {
+        try {
+            expression::BindingLayout layout;
+            int contextLoc = layout.addBinding("__contextId", expression::INT);
+            SGExpressionb* validExp
+                = dynamic_cast<SGExpressionb*>(expression::read(predProp
+                                                                ->getChild(0)));
+            if (validExp)
+                tniq->setValidExpression(validExp, layout);
+            else
+                throw expression::ParseError("technique predicate is not a boolean expression");
+        }
+        catch (expression::ParseError& except)
+        {
+            SG_LOG(SG_INPUT, SG_ALERT,
+                   "parsing technique predicate " << except.getMessage());
+            tniq->setAlwaysValid(false);
+        }
+    }
+    PropertyList passProps = prop->getChildren("pass");
+    for (PropertyList::iterator itr = passProps.begin(), e = passProps.end();
+         itr != e;
+         ++itr) {
+        buildPass(effect, tniq, itr->ptr(), options);
+    }
+}
+
+// Walk the techniques property tree, building techniques and
+// passes.
+bool Effect::realizeTechniques(const osgDB::ReaderWriter::Options* options)
+{
+    PropertyList tniqList = root->getChildren("technique");
+    for (PropertyList::iterator itr = tniqList.begin(), e = tniqList.end();
+         itr != e;
+         ++itr)
+        buildTechnique(this, *itr, options);
+}
+
 bool Effect_writeLocalData(const Object& obj, osgDB::Output& fw)
 {
     const Effect& effect = static_cast<const Effect&>(obj);
index 8c86d945df2a25f514042efa958b464122ac5824..2a3c896ec58d2a9b8c59f5f8318245cbee902318 100644 (file)
@@ -1,26 +1,29 @@
-// Copyright (C) 2008  Timothy Moore timoore@redhat.com
+// Copyright (C) 2008 - 2009  Tim Moore timoore@redhat.com
 //
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
 //
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// General Public License for more details.
+// Library General Public License for more details.
 //
 // You should have received a copy of the GNU General Public License
 // along with this program; if not, write to the Free Software
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
-
 #ifndef SIMGEAR_EFFECT_HXX
 #define SIMGEAR_EFFECT_HXX 1
 
 #include <vector>
+#include <string>
 
 #include <osg/Object>
+#include <osgDB/ReaderWriter>
+
+#include <simgear/props/props.hxx>
 
 namespace osg
 {
@@ -47,11 +50,26 @@ public:
            const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
     osg::StateSet* getDefaultStateSet();
     std::vector<osg::ref_ptr<Technique> > techniques;
+    SGPropertyNode_ptr root;
+    // Pointer to the parameters node, if it exists
+    SGPropertyNode_ptr parametersProp;
     Technique* chooseTechnique(osg::RenderInfo* renderInfo);
     virtual void resizeGLObjectBuffers(unsigned int maxSize);
     virtual void releaseGLObjects(osg::State* state = 0) const;
+    /*
+     * Build the techniques from the effect properties.
+     */
+    bool realizeTechniques(const osgDB::ReaderWriter::Options* options = 0);
+    
 protected:
     ~Effect();
 };
+Effect* makeEffect(const std::string& name,
+                   bool realizeTechniques,
+                   const osgDB::ReaderWriter::Options* options = 0);
+
+Effect* makeEffect(SGPropertyNode* prop,
+                   bool realizeTechniques,
+                   const osgDB::ReaderWriter::Options* options = 0);
 }
 #endif
index eca5aa479c0956676fd447ef493ec3dca937d36a..aee10b42ebdfabf3df8b42198b3d83f3782fb4cc 100644 (file)
@@ -22,6 +22,7 @@ libsgmaterial_a_SOURCES = \
        GLPredicate.cxx \
        Pass.cxx \
        Technique.cxx \
+       makeEffect.cxx \
        mat.cxx \
        matlib.cxx \
        matmodel.cxx
index 9c1aafcea1882cc869e267a5bb4441a07b7ebc51..2a47ea39644f2561ac73e64c7e92e6d23dba961f 100644 (file)
@@ -1,5 +1,7 @@
 #include "Pass.hxx"
 
+#include <osgDB/Registry>
+
 namespace simgear
 {
 
@@ -7,4 +9,16 @@ Pass::Pass(const Pass& rhs, const osg::CopyOp& copyop) :
     osg::StateSet(rhs, copyop)
 {
 }
+
+namespace
+{
+osgDB::RegisterDotOsgWrapperProxy PassProxy
+(
+    new Pass,
+    "simgear::Pass",
+    "Object simgear::Pass StateSet ",
+    0,
+    0
+    );
+}
 }
index 5c1d835b683e075a5506b0a8b9d1ba7670862012..19699607c9a4415df051e4ac97fd73afbd07abbe 100644 (file)
@@ -15,6 +15,7 @@
 #include <osgDB/Input>
 #include <osgDB/ParameterOutput>
 
+#include <simgear/props/props.hxx>
 #include <simgear/structure/OSGUtils.hxx>
 
 namespace simgear
@@ -217,6 +218,14 @@ public:
     }
 };
 
+Expression* glVersionParser(const SGPropertyNode* exp,
+                            expression::Parser* parser)
+{
+    return new GLVersionExpression();
+}
+
+expression::ExpParserRegistrar glVersionRegistrar("glversion", glVersionParser);
+
 class ExtensionSupportedExpression
     : public GeneralNaryExpression<bool, int>
 {
@@ -237,6 +246,18 @@ protected:
     string _extString;
 };
 
+Expression* extensionSupportedParser(const SGPropertyNode* exp,
+                                     expression::Parser* parser)
+{
+    if (exp->getType() == props::STRING
+        || exp->getType() == props::UNSPECIFIED)
+        return new ExtensionSupportedExpression(exp->getStringValue());
+    throw expression::ParseError("extension-supported expression has wrong type");
+}
+
+expression::ExpParserRegistrar
+extensionSupportedRegistrar("extension-supported", extensionSupportedParser);
+
 void Technique::setGLExtensionsPred(float glVersion,
                                     const std::vector<std::string>& extensions)
 {
@@ -246,9 +267,14 @@ void Technique::setGLExtensionsPred(float glVersion,
     int contextLoc = layout.addBinding("__contextId", INT);
     VariableExpression<int>* contextExp
         = new VariableExpression<int>(contextLoc);
+    SGExpression<bool>* versionTest
+        = makePredicate<std::less_equal>(new SGConstExpression<float>(glVersion),
+                        new GLVersionExpression);
+#if 0
     LessEqualExpression<float>* versionTest
         = new LessEqualExpression<float>(new SGConstExpression<float>(glVersion),
                                          new GLVersionExpression);
+#endif
     AndExpression* extensionsExp = 0;
     for (vector<string>::const_iterator itr = extensions.begin(),
              e = extensions.end();
@@ -285,7 +311,7 @@ bool Technique_writeLocalData(const Object& obj, osgDB::Output& fw)
         fw.indent() << "shadowingStateSet\n";
         fw.writeObject(*tniq.getShadowingStateSet());
     }
-    fw.indent() << "passes\n";
+    fw.indent() << "num_passes " << tniq.passes.size() << "\n";
     BOOST_FOREACH(const ref_ptr<Pass>& pass, tniq.passes) {
         fw.writeObject(*pass);
     }
diff --git a/simgear/scene/material/makeEffect.cxx b/simgear/scene/material/makeEffect.cxx
new file mode 100644 (file)
index 0000000..7745cd9
--- /dev/null
@@ -0,0 +1,190 @@
+#include "Effect.hxx"
+#include "Technique.hxx"
+#include "Pass.hxx"
+
+#include <algorithm>
+#include <cstring>
+#include <map>
+#include <sstream>
+
+#include <boost/lexical_cast.hpp>
+#include <boost/tuple/tuple.hpp>
+#include <boost/tuple/tuple_comparison.hpp>
+
+#include <OpenThreads/ReentrantMutex>
+#include <OpenThreads/ScopedLock>
+
+#include <osg/Material>
+#include <osg/Program>
+#include <osg/Referenced>
+#include <osg/Texture2D>
+#include <osg/Vec4d>
+
+#include <osgDB/FileUtils>
+#include <osgDB/ReadFile>
+#include <osgDB/Registry>
+
+#include <simgear/debug/logstream.hxx>
+#include <simgear/props/props_io.hxx>
+#include <simgear/scene/util/SGSceneFeatures.hxx>
+#include <simgear/structure/SGExpression.hxx>
+
+namespace simgear
+{
+using namespace std;
+using namespace osg;
+
+typedef vector<const SGPropertyNode*> RawPropVector;
+typedef map<const string, ref_ptr<Effect> > EffectMap;
+
+namespace
+{
+EffectMap effectMap;
+OpenThreads::ReentrantMutex effectMutex;
+}
+
+/** Merge two property trees, producing a new tree.
+ * If the nodes are both leaves, value comes from left leaf.
+ * Otherwise, The children are examined. If a left and right child are
+ * "identical," they are merged and the result placed in the children
+ * of the result. Otherwise the left children are placed after the
+ * right children in the result.
+ *
+ * Nodes are considered identical if:
+ * Their names are equal;
+ * Either they both have "name" children and their values are equal;
+ * or their indexes are equal.
+ */
+
+struct PropPredicate
+    : public unary_function<const SGPropertyNode*, bool>
+{
+    PropPredicate(const SGPropertyNode* node_) : node(node_) {}
+    bool operator()(const SGPropertyNode* arg) const
+    {
+        if (strcmp(node->getName(), arg->getName()))
+            return false;
+        const SGPropertyNode* nodeName = node->getChild("name");
+        const SGPropertyNode* argName = arg->getChild("name");
+        if (nodeName && argName)
+            return !strcmp(nodeName->getStringValue(),
+                           argName->getStringValue());
+        else if (!(nodeName || argName))
+            return node->getIndex() == arg->getIndex();
+        else
+            return false;
+    }
+    const SGPropertyNode* node;
+};
+
+void mergePropertyTrees(SGPropertyNode* resultNode,
+                        const SGPropertyNode* left, const SGPropertyNode* right)
+{
+    if (left->nChildren() == 0) {
+        copyProperties(left, resultNode);
+        return;
+    }
+    resultNode->setAttributes(right->getAttributes());
+    RawPropVector leftChildren;
+    for (int i = 0; i < left->nChildren(); ++i)
+        leftChildren.push_back(left->getChild(i));
+    // Maximum index of nodes (with same names) we've created.
+    map<string, int> nodeIndex;
+    // Merge identical nodes
+    for (int i = 0; i < right->nChildren(); ++i) {
+        const SGPropertyNode* node = right->getChild(i);
+        RawPropVector::iterator litr
+            = find_if(leftChildren.begin(), leftChildren.end(),
+                      PropPredicate(node));
+        SGPropertyNode* newChild
+            = resultNode->getChild(node->getName(),
+                                   nodeIndex[node->getName()]++, true);
+        if (litr != leftChildren.end()) {
+            mergePropertyTrees(newChild, *litr, node);
+            leftChildren.erase(litr);
+        } else {
+            copyProperties(node, newChild);
+        }
+    }
+    for (RawPropVector::iterator itr = leftChildren.begin(),
+             e = leftChildren.end();
+         itr != e;
+         ++itr) {
+        SGPropertyNode* newChild
+            = resultNode->getChild((*itr)->getName(),
+                                   nodeIndex[(*itr)->getName()]++, true);
+        copyProperties(*itr, newChild);
+    }
+}
+
+Effect* makeEffect(const string& name,
+                   bool realizeTechniques,
+                   const osgDB::ReaderWriter::Options* options)
+{
+    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(effectMutex);
+    EffectMap::iterator itr = effectMap.find(name);
+    if (itr != effectMap.end())
+        return itr->second.get();
+    string effectFileName(name);
+    effectFileName += ".eff";
+    string absFileName
+        = osgDB::Registry::instance()->findDataFile(effectFileName, options,
+                                                    osgDB::CASE_SENSITIVE);
+    if (absFileName.empty())
+        return 0;
+    SGPropertyNode_ptr effectProps = new SGPropertyNode();
+    readProperties(absFileName, effectProps.ptr(), 0, true);
+    Effect* result = makeEffect(effectProps.ptr(), realizeTechniques, options);
+    if (result)
+        effectMap.insert(make_pair(name, result));
+    return result;
+}
+
+
+Effect* makeEffect(SGPropertyNode* prop,
+                   bool realizeTechniques,
+                   const osgDB::ReaderWriter::Options* options)
+{
+    // Give default names to techniques and passes
+    vector<SGPropertyNode_ptr> techniques = prop->getChildren("technique");
+    for (int i = 0; i < techniques.size(); ++i) {
+        SGPropertyNode* tniqProp = techniques[i].ptr();
+        if (!tniqProp->hasChild("name"))
+            setValue(tniqProp->getChild("name", 0, true),
+                     boost::lexical_cast<string>(i));
+        vector<SGPropertyNode_ptr> passes = tniqProp->getChildren("pass");
+        for (int j = 0; j < passes.size(); ++j) {
+            SGPropertyNode* passProp = passes[j].ptr();
+            if (!passProp->hasChild("name"))
+                setValue(passProp->getChild("name", 0, true),
+                         boost::lexical_cast<string>(j));
+            vector<SGPropertyNode_ptr> texUnits
+                = passProp->getChildren("texture-unit");
+            for (int k = 0; k < texUnits.size(); ++k) {
+                SGPropertyNode* texUnitProp = texUnits[k].ptr();
+                if (!texUnitProp->hasChild("name"))
+                    setValue(texUnitProp->getChild("name", 0, true),
+                             boost::lexical_cast<string>(k));
+            }
+        }
+    }
+    Effect* effect = new Effect;
+    // Merge with the parent effect, if any
+    const SGPropertyNode* inheritProp = prop->getChild("inherits-from");
+    Effect* parent = 0;
+    if (inheritProp) {
+        parent = makeEffect(inheritProp->getStringValue(), realizeTechniques,
+                            options);
+        effect->root = new SGPropertyNode;
+        mergePropertyTrees(effect->root, prop, parent->root);
+        effect->root->removeChild("inherits-from");
+    } else {
+        effect->root = prop;
+    }
+    effect->parametersProp = effect->root->getChild("parameters");
+    if (realizeTechniques)
+        effect->realizeTechniques(options);
+    return effect;
+}
+
+}
index 7a0628f0dec1463e0fe1d7caf4428f5d9aa2b18b..1484c4208e04d8a5f88882e35cfc884378334222 100644 (file)
@@ -32,6 +32,7 @@
 #include <vector>
 #include<string>
 
+#include <boost/foreach.hpp>
 #include "mat.hxx"
 
 #include <osg/CullFace>
 #include <osg/StateSet>
 #include <osg/TexEnv>
 #include <osg/Texture2D>
+#include <osgDB/Options>
 #include <osgDB/ReadFile>
+#include <osgDB/Registry>
 #include <osgDB/FileUtils>
 
 #include <simgear/debug/logstream.hxx>
 #include <simgear/misc/sg_path.hxx>
 #include <simgear/misc/sgstream.hxx>
-
+#include <simgear/props/props_io.hxx>
 #include <simgear/scene/model/model.hxx>
+#include <simgear/scene/util/RenderConstants.hxx>
 #include <simgear/scene/util/StateAttributeFactory.hxx>
 
 #include "Effect.hxx"
@@ -55,6 +59,7 @@
 #include "Pass.hxx"
 
 using std::map;
+using std::string;
 using namespace simgear;
 
 \f
@@ -62,33 +67,18 @@ using namespace simgear;
 // Constructors and destructor.
 ////////////////////////////////////////////////////////////////////////
 
-SGMaterial::_internal_state::_internal_state(osg::StateSet *s,
-                                             const std::string &t, bool l ) :
-    state(s), texture_path(t), texture_loaded(l)
+SGMaterial::_internal_state::_internal_state(Effect *e, const string &t, bool l,
+                                             const osgDB::Options* o ) :
+  effect(e), texture_path(t), effect_realized(l), options(o)
 {
 }
 
-SGMaterial::SGMaterial( const string &fg_root, const SGPropertyNode *props )
+SGMaterial::SGMaterial( const osgDB::Options* options,
+                        const SGPropertyNode *props )
 {
     init();
-    read_properties( fg_root, props );
-    build_state( false );
-}
-
-SGMaterial::SGMaterial( const string &texpath )
-{
-    init();
-
-    _internal_state st( NULL, texpath, false );
-    _status.push_back( st );
-
-    build_state( true );
-}
-
-SGMaterial::SGMaterial( osg::StateSet *s )
-{
-    init();
-    set_state( s );
+    read_properties( options, props );
+    buildEffectProperties(options);
 }
 
 SGMaterial::~SGMaterial (void)
@@ -101,7 +91,8 @@ SGMaterial::~SGMaterial (void)
 ////////////////////////////////////////////////////////////////////////
 
 void
-SGMaterial::read_properties( const string &fg_root, const SGPropertyNode *props)
+SGMaterial::read_properties(const osgDB::Options* options,
+                            const SGPropertyNode *props)
 {
                                // Gather the path(s) to the texture(s)
   vector<SGPropertyNode_ptr> textures = props->getChildren("texture");
@@ -111,29 +102,29 @@ SGMaterial::read_properties( const string &fg_root, const SGPropertyNode *props)
     if (tname.empty()) {
         tname = "unknown.rgb";
     }
-
-    SGPath tpath( fg_root );
-    tpath.append("Textures.high");
+    SGPath tpath("Textures.high");
     tpath.append(tname);
-    if ( !osgDB::fileExists(tpath.str()) ) {
-      tpath = SGPath( fg_root );
-      tpath.append("Textures");
+    osgDB::Registry* reg = osgDB::Registry::instance();
+    string fullTexPath = reg->findDataFile(tpath.str(), options,
+                                           osgDB::CASE_SENSITIVE);
+    if (fullTexPath.empty()) {
+      tpath = SGPath("Textures");
       tpath.append(tname);
+      fullTexPath = reg->findDataFile(tpath.str(), options,
+                                      osgDB::CASE_SENSITIVE);
     }
 
-    if ( osgDB::fileExists(tpath.str()) ) {
-      _internal_state st( NULL, tpath.str(), false );
+    if (!fullTexPath.empty() ) {
+      _internal_state st( NULL, fullTexPath, false, options );
       _status.push_back( st );
     }
   }
 
   if (textures.size() == 0) {
-    string tname = "unknown.rgb";
-    SGPath tpath( fg_root );
-    tpath.append("Textures");
+    SGPath tpath("Textures");
     tpath.append("Terrain");
-    tpath.append(tname);
-    _internal_state st( NULL, tpath.str(), true );
+    tpath.append("unknown.rgb");
+    _internal_state st( NULL, tpath.str(), true, options );
     _status.push_back( st );
   }
 
@@ -148,10 +139,12 @@ SGMaterial::read_properties( const string &fg_root, const SGPropertyNode *props)
   tree_width = props->getDoubleValue("tree-width-m", 0.0);
   tree_range = props->getDoubleValue("tree-range-m", 0.0);
   tree_varieties = props->getIntValue("tree-varieties", 1);
-
-  SGPath tpath( fg_root );
-  tpath.append(props->getStringValue("tree-texture"));
-  tree_texture = tpath.str();
+  const SGPropertyNode* treeTexNode = props->getChild("tree-texture");
+  if (treeTexNode) {
+    string treeTexPath = props->getStringValue("tree-texture");
+    tree_texture = osgDB::Registry::instance()
+      ->findDataFile(treeTexPath, options, osgDB::CASE_SENSITIVE);
+  }
 
   // surface values for use with ground reactions
   solid = props->getBoolValue("solid", true);
@@ -238,10 +231,9 @@ Effect* SGMaterial::get_effect(int n)
         return 0;
     }
     int i = n >= 0 ? n : _current_ptr;
-    if(!_status[i].texture_loaded) {
-        assignTexture(_status[i].state.get(), _status[i].texture_path,
-                      wrapu, wrapv, mipmap);
-        _status[i].texture_loaded = true;
+    if(!_status[i].effect_realized) {
+        _status[i].effect->realizeTechniques(_status[i].options.get());
+        _status[i].effect_realized = true;
     }
     // XXX This business of returning a "random" alternate texture is
     // really bogus. It means that the appearance of the terrain
@@ -250,72 +242,44 @@ Effect* SGMaterial::get_effect(int n)
     return _status[i].effect.get();
 }
 
-void 
-SGMaterial::build_state( bool defer_tex_load )
+void SGMaterial::buildEffectProperties(const osgDB::Options* options)
 {
-    StateAttributeFactory *attrFact = StateAttributeFactory::instance();
-    SGMaterialUserData* user = new SGMaterialUserData(this);
-    for (unsigned int i = 0; i < _status.size(); i++)
+    using namespace osg;
+    SGPropertyNode_ptr propRoot = new SGPropertyNode();
+    makeChild(propRoot, "inherits-from")
+        ->setStringValue("Effects/terrain-default");
+    SGPropertyNode* paramProp = makeChild(propRoot, "parameters");
+    SGPropertyNode* materialProp = makeChild(paramProp, "material");
+    makeChild(materialProp, "ambient")->setValue(SGVec4d(ambient));    
+    makeChild(materialProp, "diffuse")->setValue(SGVec4d(diffuse));
+    makeChild(materialProp, "specular")->setValue(SGVec4d(specular));
+    makeChild(materialProp, "emissive")->setValue(SGVec4d(emission));
+    makeChild(materialProp, "shininess")->setFloatValue(shininess);
+    if (ambient[3] < 1 || diffuse[3] < 1 ||
+        specular[3] < 1 || emission[3] < 1) {
+        makeChild(paramProp, "transparent")->setBoolValue(true);
+        SGPropertyNode* binProp = makeChild(paramProp, "render-bin");
+        makeChild(binProp, "bin-number")->setIntValue(TRANSPARENT_BIN);
+        makeChild(binProp, "bin-name")->setStringValue("DepthSortedBin");
+    }
+    BOOST_FOREACH(_internal_state& matState, _status)
     {
-        Pass *pass = new Pass;
-        pass->setUserData(user);
-
-        // Set up the textured state
-        pass->setAttribute(attrFact->getSmoothShadeModel());
-        pass->setAttributeAndModes(attrFact->getCullFaceBack());
-
-        pass->setMode(GL_LIGHTING, osg::StateAttribute::ON);
-
-        _status[i].texture_loaded = false;
-
-        osg::Material* material = new osg::Material;
-        material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
-        material->setAmbient(osg::Material::FRONT_AND_BACK, ambient.osg());
-        material->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse.osg());
-        material->setSpecular(osg::Material::FRONT_AND_BACK, specular.osg());
-        material->setEmission(osg::Material::FRONT_AND_BACK, emission.osg());
-        material->setShininess(osg::Material::FRONT_AND_BACK, shininess );
-        pass->setAttribute(material);
-
-        if (ambient[3] < 1 || diffuse[3] < 1 ||
-            specular[3] < 1 || emission[3] < 1) {
-          pass->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
-          pass->setMode(GL_BLEND, osg::StateAttribute::ON);
-          pass->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON);
-        } else {
-          pass->setRenderingHint(osg::StateSet::OPAQUE_BIN);
-          pass->setMode(GL_BLEND, osg::StateAttribute::OFF);
-          pass->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF);
-        }
-
-        _status[i].state = pass;
-        Technique* tniq = new Technique(true);
-        tniq->passes.push_back(pass);
-        Effect* effect = new Effect;
-        effect->techniques.push_back(tniq);
-        effect->setUserData(user);
-        _status[i].effect = effect;
+        SGPropertyNode_ptr effectProp = new SGPropertyNode();
+        copyProperties(propRoot, effectProp);
+        SGPropertyNode* effectParamProp = effectProp->getChild("parameters", 0);
+        SGPropertyNode* texProp = makeChild(effectParamProp, "texture");
+        SGPropertyNode* tex2dProp = makeChild(texProp, "texture2d");
+        makeChild(tex2dProp, "image")->setStringValue(matState.texture_path);
+        makeChild(tex2dProp, "filter")
+            ->setStringValue(mipmap ? "linear-mipmap-linear" : "nearest");
+        makeChild(tex2dProp, "wrap-s")
+            ->setStringValue(wrapu ? "repeat" : "clamp");
+        makeChild(tex2dProp, "wrap-t")
+            ->setStringValue(wrapv ? "repeat" : "clamp");
+        matState.effect = makeEffect(effectProp, false, options);
     }
 }
 
-
-void SGMaterial::set_state( osg::StateSet *s )
-{
-    _status.push_back( _internal_state( s, "", true ) );
-}
-
-void SGMaterial::assignTexture( osg::StateSet *state, const std::string &fname,
-                 bool _wrapu, bool _wrapv, bool _mipmap )
-{
-   osg::Texture2D* texture = SGLoadTexture2D(fname, 0, _wrapu, _wrapv,
-                                             mipmap ? -1 : 0);
-   texture->setMaxAnisotropy( SGGetTextureFilter());
-   state->setTextureAttributeAndModes(0, texture);
-
-   StateAttributeFactory *attrFact = StateAttributeFactory::instance();
-   state->setTextureAttributeAndModes(0, attrFact->getStandardTexEnv());
-}
-
 SGMaterialGlyph* SGMaterial::get_glyph (const string& name) const
 {
   map<string, SGSharedPtr<SGMaterialGlyph> >::const_iterator it;
index e041b6987a97dd8972c2f27eec44d30065a61265..1317072a6d9737b3398c29ad0a57fcc3e5fa6f44 100644 (file)
@@ -45,6 +45,11 @@ namespace osg
 class StateSet;
 }
 
+namespace osgDB
+{
+class Options;
+}
+
 #include <simgear/props/props.hxx>
 #include <simgear/structure/SGSharedPtr.hxx>
 #include <simgear/scene/util/SGSceneFeatures.hxx>
@@ -83,28 +88,7 @@ public:
    * state information for the material.  This node is usually
    * loaded from the $FG_ROOT/materials.xml file.
    */
-  SGMaterial( const std::string &fg_root, const SGPropertyNode *props);
-
-
-  /**
-   * Construct a material from an absolute texture path.
-   *
-   * @param texture_path A string containing an absolute path
-   * to a texture file (usually RGB).
-   */
-  SGMaterial( const std::string &texpath );
-
-
-  /**
-   * Construct a material around an existing state.
-   *
-   * This constructor allows the application to create a custom,
-   * low-level state for the scene graph and wrap a material around
-   * it.  Note: the pointer ownership is transferred to the material.
-   *
-   * @param s The state for this material.
-   */
-  SGMaterial( osg::StateSet *s );
+  SGMaterial( const osgDB::Options*, const SGPropertyNode *props);
 
   /**
    * Destructor.
@@ -275,11 +259,12 @@ protected:
 protected:
 
   struct _internal_state {
-      _internal_state( osg::StateSet *s, const std::string &t, bool l );
-      osg::ref_ptr<osg::StateSet> state;
+      _internal_state(simgear::Effect *e, const std::string &t, bool l,
+                      const osgDB::Options *o);
       osg::ref_ptr<simgear::Effect> effect;
       std::string texture_path;
-      bool texture_loaded;
+      bool effect_realized;
+      osg::ref_ptr<const osgDB::Options> options;
   };
 
 private:
@@ -356,14 +341,9 @@ private:
   // Internal constructors and methods.
   ////////////////////////////////////////////////////////////////////
 
-  SGMaterial( const std::string &fg_root, const SGMaterial &mat ); // unimplemented
-
-  void read_properties( const std::string &fg_root, const SGPropertyNode *props );
-  void build_state( bool defer_tex_load );
-  void set_state( osg::StateSet *s );
-
-  void assignTexture( osg::StateSet *state, const std::string &fname, bool _wrapu = true, bool _wrapv = true, bool _mipmap = true );
-
+  void read_properties(const osgDB::Options* options,
+                        const SGPropertyNode *props);
+  void buildEffectProperties(const osgDB::Options* options);
 };
 
 
index 4f1357707479c24d555c6437ca5485329402194f..c4aa8a8fb89bfbc6e28242e4e7e7498336cb2a36 100644 (file)
 #include <string.h>
 #include <string>
 
-#include <osg/AlphaFunc>
-#include <osg/BlendFunc>
-#include <osg/CullFace>
-#include <osg/Material>
-#include <osg/Point>
-#include <osg/PointSprite>
-#include <osg/PolygonMode>
-#include <osg/PolygonOffset>
-#include <osg/StateSet>
-#include <osg/TexEnv>
-#include <osg/TexGen>
-#include <osg/Texture2D>
+#include <osgDB/Options>
 
 #include <simgear/debug/logstream.hxx>
 #include <simgear/misc/sg_path.hxx>
@@ -82,7 +71,9 @@ bool SGMaterialLib::load( const string &fg_root, const string& mpath,
                 << ex.getMessage() );
         throw;
     }
-
+    osg::ref_ptr<osgDB::Options> options = new osgDB::Options;
+    options->setObjectCacheHint(osgDB::Options::CACHE_ALL);
+    options->setDatabasePath(fg_root);
     int nMaterials = materials.nChildren();
     for (int i = 0; i < nMaterials; i++) {
         const SGPropertyNode *node = materials.getChild(i);
@@ -97,7 +88,7 @@ bool SGMaterialLib::load( const string &fg_root, const string& mpath,
                 }
             }
 
-            SGSharedPtr<SGMaterial> m = new SGMaterial(fg_root, node);
+            SGSharedPtr<SGMaterial> m = new SGMaterial(options.get(), node);
 
             vector<SGPropertyNode_ptr>names = node->getChildren("name");
             for ( unsigned int j = 0; j < names.size(); j++ ) {