Effects for models

Basically working, at last. Among other things, create effects in
 models loaded directly from .ac files; this can happen, for example,
with the random models from the materials library.
This commit is contained in:
Tim Moore
2009-09-08 13:09:05 +02:00
parent 63ce675914
commit 3e40d624a8
15 changed files with 411 additions and 66 deletions

View File

@@ -1171,6 +1171,12 @@
<Filter
Name="Lib_sgutil"
Filter="">
<File
RelativePath="..\..\simgear\scene\util\CopyOp.cxx">
</File>
<File
RelativePath="..\..\simgear\scene\util\CopyOp.hxx">
</File>
<File
RelativePath="..\..\simgear\scene\util\NodeAndDrawableVisitor.cxx">
</File>

View File

@@ -1705,6 +1705,14 @@
<Filter
Name="Lib_sgutil"
>
<File
RelativePath="..\..\simgear\scene\util\CopyOp.cxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\util\CopyOp.hxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\util\NodeAndDrawableVisitor.cxx"
>

View File

@@ -30,7 +30,6 @@
#include <map>
#include <utility>
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/tuple/tuple.hpp>
@@ -85,10 +84,12 @@ Effect::Effect()
Effect::Effect(const Effect& rhs, const CopyOp& copyop)
: root(rhs.root), parametersProp(rhs.parametersProp)
{
using namespace boost;
transform(rhs.techniques.begin(), rhs.techniques.end(),
back_inserter(techniques),
bind(simgear::clone_ref<Technique>, _1, copyop));
typedef vector<ref_ptr<Technique> > TechniqueList;
for (TechniqueList::const_iterator itr = rhs.techniques.begin(),
end = rhs.techniques.end();
itr != end;
++itr)
techniques.push_back(static_cast<Technique*>(copyop(itr->get())));
}
// Assume that the last technique is always valid.
@@ -196,6 +197,19 @@ osg::Vec4f getColor(const SGPropertyNode* prop)
}
}
// The description of an attribute may exist in a pass' XML, but a
// derived effect might want to disable the attribute altogether. So,
// some attributes have an "active" property; if it exists and is
// false, the OSG attribute is not built at all. This is different
// from any OSG mode settings that might be around.
bool isAttributeActive(Effect* effect, const SGPropertyNode* prop)
{
const SGPropertyNode* activeProp
= getEffectPropertyChild(effect, prop, "active");
return !activeProp || activeProp->getValue<bool>();
}
struct LightingBuilder : public PassAttributeBuilder
{
void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
@@ -265,6 +279,15 @@ struct CullFaceBuilder : PassAttributeBuilder
InstallAttributeBuilder<CullFaceBuilder> installCullFace("cull-face");
EffectNameValue<StateSet::RenderingHint> renderingHintInit[] =
{
{ "default", StateSet::DEFAULT_BIN },
{ "opaque", StateSet::OPAQUE_BIN },
{ "transparent", StateSet::TRANSPARENT_BIN }
};
EffectPropertyMap<StateSet::RenderingHint> renderingHints(renderingHintInit);
struct HintBuilder : public PassAttributeBuilder
{
void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
@@ -273,11 +296,9 @@ struct HintBuilder : public PassAttributeBuilder
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);
StateSet::RenderingHint renderingHint = StateSet::DEFAULT_BIN;
findAttr(renderingHints, realProp, renderingHint);
pass->setRenderingHint(renderingHint);
}
};
@@ -288,6 +309,8 @@ struct RenderBinBuilder : public PassAttributeBuilder
void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
const osgDB::ReaderWriter::Options* options)
{
if (!isAttributeActive(effect, prop))
return;
const SGPropertyNode* binProp = prop->getChild("bin-number");
binProp = getEffectPropertyNode(effect, binProp);
const SGPropertyNode* nameProp = prop->getChild("bin-name");
@@ -329,6 +352,8 @@ void MaterialBuilder::buildAttribute(Effect* effect, Pass* pass,
const SGPropertyNode* prop,
const osgDB::ReaderWriter::Options* options)
{
if (!isAttributeActive(effect, prop))
return;
Material* mat = new Material;
const SGPropertyNode* color = 0;
if ((color = getEffectPropertyChild(effect, prop, "ambient")))
@@ -397,6 +422,8 @@ struct BlendBuilder : public PassAttributeBuilder
void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
const osgDB::ReaderWriter::Options* options)
{
if (!isAttributeActive(effect, prop))
return;
// XXX Compatibility with early <blend> syntax; should go away
// before a release
const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop);
@@ -417,8 +444,8 @@ struct BlendBuilder : public PassAttributeBuilder
pass->setMode(GL_BLEND, StateAttribute::OFF);
return;
}
const SGPropertyNode* psource = getEffectPropertyChild(effect, prop,
"source");
const SGPropertyNode* psource
= getEffectPropertyChild(effect, prop, "source");
const SGPropertyNode* pdestination
= getEffectPropertyChild(effect, prop, "destination");
const SGPropertyNode* psourceRGB
@@ -493,6 +520,8 @@ struct AlphaTestBuilder : public PassAttributeBuilder
void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
const osgDB::ReaderWriter::Options* options)
{
if (!isAttributeActive(effect, prop))
return;
// XXX Compatibility with early <alpha-test> syntax; should go away
// before a release
const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop);
@@ -577,7 +606,8 @@ void TextureUnitBuilder::buildAttribute(Effect* effect, Pass* pass,
const SGPropertyNode* prop,
const osgDB::ReaderWriter::Options* options)
{
if (!isAttributeActive(effect, prop))
return;
// Decode the texture unit
int unit = 0;
const SGPropertyNode* pUnit = prop->getChild("unit");
@@ -593,7 +623,7 @@ void TextureUnitBuilder::buildAttribute(Effect* effect, Pass* pass,
<< lex.what());
}
}
const SGPropertyNode* pType = prop->getChild("type");
const SGPropertyNode* pType = getEffectPropertyChild(effect, prop, "type");
string type;
if (!pType)
type = "2d";
@@ -650,6 +680,8 @@ void ShaderProgramBuilder::buildAttribute(Effect* effect, Pass* pass,
const osgDB::ReaderWriter::Options*
options)
{
if (!isAttributeActive(effect, prop))
return;
PropertyList pVertShaders = prop->getChildren("vertex-shader");
PropertyList pFragShaders = prop->getChildren("fragment-shader");
string programKey;
@@ -724,6 +756,8 @@ struct UniformBuilder :public PassAttributeBuilder
void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
const osgDB::ReaderWriter::Options* options)
{
if (!isAttributeActive(effect, prop))
return;
const SGPropertyNode* nameProp = prop->getChild("name");
const SGPropertyNode* typeProp = prop->getChild("type");
const SGPropertyNode* valProp
@@ -818,6 +852,8 @@ struct PolygonModeBuilder : public PassAttributeBuilder
void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
const osgDB::ReaderWriter::Options* options)
{
if (!isAttributeActive(effect, prop))
return;
const SGPropertyNode* frontProp
= getEffectPropertyChild(effect, prop, "front");
const SGPropertyNode* backProp
@@ -876,8 +912,9 @@ void buildTechnique(Effect* effect, const SGPropertyNode* prop,
}
// Specifically for .ac files...
bool makeParametersFromStateSet(SGPropertyNode* paramRoot, const StateSet* ss)
bool makeParametersFromStateSet(SGPropertyNode* effectRoot, const StateSet* ss)
{
SGPropertyNode* paramRoot = makeChild(effectRoot, "parameters");
SGPropertyNode* matNode = paramRoot->getChild("material", 0, true);
Vec4f ambVal, difVal, specVal, emisVal;
float shininess = 0.0f;
@@ -888,13 +925,16 @@ bool makeParametersFromStateSet(SGPropertyNode* paramRoot, const StateSet* ss)
specVal = mat->getSpecular(Material::FRONT_AND_BACK);
emisVal = mat->getEmission(Material::FRONT_AND_BACK);
shininess = mat->getShininess(Material::FRONT_AND_BACK);
makeChild(matNode, "active")->setValue(true);
makeChild(matNode, "ambient")->setValue(toVec4d(toSG(ambVal)));
makeChild(matNode, "diffuse")->setValue(toVec4d(toSG(difVal)));
makeChild(matNode, "specular")->setValue(toVec4d(toSG(specVal)));
makeChild(matNode, "emissive")->setValue(toVec4d(toSG(emisVal)));
makeChild(matNode, "shininess")->setValue(shininess);
matNode->getChild("color-mode", 0, true)->setStringValue("diffuse");
} else {
makeChild(matNode, "active")->setValue(false);
}
matNode->getChild("ambient", 0, true)->setValue(toVec4d(toSG(ambVal)));
matNode->getChild("diffuse", 0, true)->setValue(toVec4d(toSG(difVal)));
matNode->getChild("specular", 0, true)->setValue(toVec4d(toSG(specVal)));
matNode->getChild("emissive", 0, true)->setValue(toVec4d(toSG(emisVal)));
matNode->getChild("shininess", 0, true)->setValue(shininess);
matNode->getChild("color-mode", 0, true)->setStringValue("diffuse");
const ShadeModel* sm = getStateAttribute<ShadeModel>(ss);
string shadeModelString("smooth");
if (sm) {
@@ -902,8 +942,7 @@ bool makeParametersFromStateSet(SGPropertyNode* paramRoot, const StateSet* ss)
if (smMode == ShadeModel::FLAT)
shadeModelString = "flat";
}
paramRoot->getChild("shade-model", 0, true)
->setStringValue(shadeModelString);
makeChild(paramRoot, "shade-model")->setStringValue(shadeModelString);
string cullFaceString("off");
const CullFace* cullFace = getStateAttribute<CullFace>(ss);
if (cullFace) {
@@ -921,15 +960,18 @@ bool makeParametersFromStateSet(SGPropertyNode* paramRoot, const StateSet* ss)
break;
}
}
paramRoot->getChild("cull-face", 0, true)->setStringValue(cullFaceString);
makeChild(paramRoot, "cull-face")->setStringValue(cullFaceString);
const BlendFunc* blendFunc = getStateAttribute<BlendFunc>(ss);
SGPropertyNode* blendNode = makeChild(paramRoot, "blend");
if (blendFunc) {
string sourceMode = findName(blendFuncModes, blendFunc->getSource());
string destMode = findName(blendFuncModes, blendFunc->getDestination());
SGPropertyNode* blendNode = paramRoot->getChild("blend", 0, true);
blendNode->getChild("source", 0, true)->setStringValue(sourceMode);
blendNode->getChild("destination", 0, true)->setStringValue(destMode);
blendNode->getChild("mode", 0, true)->setValue(true);
makeChild(blendNode, "active")->setValue(true);
makeChild(blendNode, "source")->setStringValue(sourceMode);
makeChild(blendNode, "destination")->setStringValue(destMode);
makeChild(blendNode, "mode")->setValue(true);
} else {
makeChild(blendNode, "active")->setValue(false);
}
makeTextureParameters(paramRoot, ss);
return true;

View File

@@ -74,5 +74,15 @@ Effect* makeEffect(SGPropertyNode* prop,
bool makeParametersFromStateSet(SGPropertyNode* paramRoot,
const osg::StateSet* ss);
namespace effect
{
/**
* The function that implements effect property tree inheritance.
*/
void mergePropertyTrees(SGPropertyNode* resultNode,
const SGPropertyNode* left,
const SGPropertyNode* right);
}
}
#endif

View File

@@ -38,10 +38,10 @@ EffectGeode::EffectGeode()
{
}
EffectGeode::EffectGeode(const EffectGeode& rhs, const CopyOp& copyop) :
Geode(rhs, copyop)
EffectGeode::EffectGeode(const EffectGeode& rhs, const osg::CopyOp& copyop) :
Geode(rhs, copyop),
_effect(static_cast<Effect*>(copyop(rhs._effect.get())))
{
_effect = static_cast<Effect*>(rhs._effect->clone(copyop));
}
void EffectGeode::resizeGLObjectBuffers(unsigned int maxSize)

View File

@@ -6,7 +6,6 @@
#include "Technique.hxx"
#include "Pass.hxx"
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#include <iterator>
@@ -59,16 +58,15 @@ Technique::Technique(bool alwaysValid)
Technique::Technique(const Technique& rhs, const osg::CopyOp& copyop) :
_contextMap(rhs._contextMap), _alwaysValid(rhs._alwaysValid),
_shadowingStateSet(rhs._shadowingStateSet),
_shadowingStateSet(copyop(rhs._shadowingStateSet)),
_validExpression(rhs._validExpression),
_contextIdLocation(rhs._contextIdLocation)
{
using namespace std;
using namespace boost;
transform(rhs.passes.begin(), rhs.passes.end(),
back_inserter(passes),
bind(simgear::clone_ref<Pass>, _1, copyop));
for (std::vector<ref_ptr<Pass> >::const_iterator itr = rhs.passes.begin(),
end = rhs.passes.end();
itr != end;
++itr)
passes.push_back(static_cast<Pass*>(copyop(itr->get())));
}
Technique::~Technique()

View File

@@ -285,19 +285,29 @@ TextureBuilder::Registrar installNoise("noise", new NoiseBuilder);
bool makeTextureParameters(SGPropertyNode* paramRoot, const StateSet* ss)
{
SGPropertyNode* texUnit = makeChild(paramRoot, "texture");
const Texture* tex = getStateAttribute<Texture>(0, ss);
const Texture2D* texture = dynamic_cast<const Texture2D*>(tex);
if (!tex)
makeChild(texUnit, "unit")->setValue(0);
if (!tex) {
makeChild(texUnit, "active")->setValue(false);
makeChild(texUnit, "type")->setValue("white");
return false;
}
const Image* image = texture->getImage();
string imageName;
if (image)
if (image) {
imageName = image->getFileName();
} else {
makeChild(texUnit, "active")->setValue(false);
makeChild(texUnit, "type")->setValue("white");
return false;
}
makeChild(texUnit, "active")->setValue(true);
makeChild(texUnit, "type")->setValue("2d");
string wrapS = findName(wrapModes, texture->getWrap(Texture::WRAP_S));
string wrapT = findName(wrapModes, texture->getWrap(Texture::WRAP_T));
string wrapR = findName(wrapModes, texture->getWrap(Texture::WRAP_R));
SGPropertyNode* texUnit = makeChild(paramRoot, "texture-unit");
makeChild(texUnit, "unit")->setValue(0);
makeChild(texUnit, "image")->setStringValue(imageName);
makeChild(texUnit, "wrap-s")->setStringValue(wrapS);
makeChild(texUnit, "wrap-t")->setStringValue(wrapT);

View File

@@ -39,6 +39,7 @@ namespace simgear
{
using namespace std;
using namespace osg;
using namespace effect;
typedef vector<const SGPropertyNode*> RawPropVector;
typedef map<const string, ref_ptr<Effect> > EffectMap;
@@ -72,6 +73,8 @@ struct PropPredicate
const SGPropertyNode* node;
};
namespace effect
{
void mergePropertyTrees(SGPropertyNode* resultNode,
const SGPropertyNode* left, const SGPropertyNode* right)
{
@@ -108,6 +111,7 @@ void mergePropertyTrees(SGPropertyNode* resultNode,
copyProperties(*itr, newChild);
}
}
}
Effect* makeEffect(const string& name,
bool realizeTechniques,

View File

@@ -20,6 +20,7 @@
# include <simgear_config.h>
#endif
#include <osg/Geode>
#include <osg/MatrixTransform>
#include <osgDB/WriteFile>
#include <osgDB/Registry>
@@ -43,7 +44,9 @@
#include "model.hxx"
#include "SGText.hxx"
using namespace std;
using namespace simgear;
using namespace osg;
static osg::Node *
sgLoad3DModel_internal(const std::string& path,
@@ -210,13 +213,13 @@ sgLoad3DModel_internal(const string &path,
texturepath = texturepath.dir();
options->setDatabasePath(texturepath.str());
osg::Node* origModel
= osgDB::readNodeFile(modelpath.str(), options.get());
if (!origModel)
osgDB::ReaderWriter::ReadResult modelResult
= osgDB::Registry::instance()->readNode(modelpath.str(),
options.get());
if (!modelResult.validNode())
throw sg_io_exception("Failed to load 3D model",
sg_location(modelpath.str()));
model = copyModel(origModel);
model = copyModel(modelResult.getNode());
// Add an extra reference to the model stored in the database.
// That is to avoid expiring the object from the cache even if
// it is still in use. Note that the object cache will think
@@ -224,7 +227,7 @@ sgLoad3DModel_internal(const string &path,
// clone all structural nodes here we need that extra
// reference to the original object
SGDatabaseReference* databaseReference;
databaseReference = new SGDatabaseReference(origModel);
databaseReference = new SGDatabaseReference(modelResult.getNode());
model->addObserver(databaseReference);
// Update liveries
@@ -274,7 +277,8 @@ sgLoad3DModel_internal(const string &path,
SGPath submodelpath;
osg::ref_ptr<osg::Node> submodel;
string submodelFileName = sub_props->getStringValue("path");
if ( submodelFileName.size() > 2 && submodelFileName.substr( 0, 2 ) == "./" ) {
if (submodelFileName.size() > 2
&& !submodelFileName.compare(0, 2, "./" )) {
submodelpath = modelpath.dir();
submodelpath.append( submodelFileName.substr( 2 ) );
} else {
@@ -292,7 +296,7 @@ sgLoad3DModel_internal(const string &path,
throw;
}
osg::ref_ptr<osg::Node> submodel_final=submodel.get();
osg::ref_ptr<osg::Node> submodel_final = submodel;
SGPropertyNode *offs = sub_props->getNode("offsets", false);
if (offs) {
osg::Matrix res_matrix;
@@ -314,7 +318,7 @@ sgLoad3DModel_internal(const string &path,
offs->getDoubleValue("z-m", 0));
align->setMatrix(res_matrix*tmat);
align->addChild(submodel.get());
submodel_final=align.get();
submodel_final = align;
}
submodel_final->setName(sub_props->getStringValue("name", ""));
@@ -363,7 +367,12 @@ sgLoad3DModel_internal(const string &path,
prop_root,
options.get()));
}
PropertyList effect_nodes = props->getChildren("effect");
{
ref_ptr<Node> modelWithEffects
= instantiateEffects(group.get(), effect_nodes, options.get());
group = static_cast<Group*>(modelWithEffects.get());
}
std::vector<SGPropertyNode_ptr> animation_nodes;
animation_nodes = props->getChildren("animation");
for (unsigned i = 0; i < animation_nodes.size(); ++i)

View File

@@ -9,6 +9,8 @@
#include <utility>
#include <boost/foreach.hpp>
#include <osg/ref_ptr>
#include <osgDB/FileNameUtils>
#include <osgDB/FileUtils>
@@ -16,10 +18,16 @@
#include <osgDB/ReadFile>
#include <osgDB/SharedStateManager>
#include <simgear/scene/material/Effect.hxx>
#include <simgear/scene/material/EffectGeode.hxx>
#include <simgear/scene/util/SGSceneFeatures.hxx>
#include <simgear/scene/util/SGSceneUserData.hxx>
#include <simgear/scene/util/CopyOp.hxx>
#include <simgear/scene/util/SplicingVisitor.hxx>
#include <simgear/structure/exception.hxx>
#include <simgear/structure/Singleton.hxx>
#include <simgear/props/props.hxx>
#include <simgear/props/props_io.hxx>
#include <simgear/props/condition.hxx>
@@ -67,21 +75,23 @@ SGLoadTexture2D(bool staticTexture, const std::string& path,
namespace simgear
{
using namespace std;
using namespace osg;
using simgear::CopyOp;
Node* copyModel(Node* model)
{
CopyOp::CopyFlags flags = CopyOp::DEEP_COPY_ALL;
flags &= ~CopyOp::DEEP_COPY_TEXTURES;
flags &= ~CopyOp::DEEP_COPY_IMAGES;
flags &= ~CopyOp::DEEP_COPY_STATESETS;
flags &= ~CopyOp::DEEP_COPY_STATEATTRIBUTES;
flags &= ~CopyOp::DEEP_COPY_ARRAYS;
flags &= ~CopyOp::DEEP_COPY_PRIMITIVES;
// This will preserve display lists ...
flags &= ~CopyOp::DEEP_COPY_DRAWABLES;
flags &= ~CopyOp::DEEP_COPY_SHAPES;
return static_cast<Node*>(model->clone(CopyOp(flags)));
const CopyOp::CopyFlags flags = (CopyOp::DEEP_COPY_ALL
& ~CopyOp::DEEP_COPY_TEXTURES
& ~CopyOp::DEEP_COPY_IMAGES
& ~CopyOp::DEEP_COPY_STATESETS
& ~CopyOp::DEEP_COPY_STATEATTRIBUTES
& ~CopyOp::DEEP_COPY_ARRAYS
& ~CopyOp::DEEP_COPY_PRIMITIVES
// This will preserve display lists ...
& ~CopyOp::DEEP_COPY_DRAWABLES
& ~CopyOp::DEEP_COPY_SHAPES);
return (CopyOp(flags))(model);
}
TextureUpdateVisitor::TextureUpdateVisitor(const osgDB::FilePathList& pathList) :
@@ -191,5 +201,127 @@ void UserDataCopyVisitor::apply(Node& node)
node.traverse(*this);
}
namespace
{
class MakeEffectVisitor : public SplicingVisitor
{
public:
typedef std::map<string, SGPropertyNode_ptr> EffectMap;
using SplicingVisitor::apply;
MakeEffectVisitor(const osgDB::ReaderWriter::Options* options = 0)
: _options(options)
{
}
virtual void apply(osg::Node& node);
virtual void apply(osg::Geode& geode);
EffectMap& getEffectMap() { return _effectMap; }
const EffectMap& getEffectMap() const { return _effectMap; }
void setDefaultEffect(SGPropertyNode* effect)
{
_currentEffectParent = effect;
}
SGPropertyNode* getDefaultEffect() { return _currentEffectParent; }
protected:
EffectMap _effectMap;
SGPropertyNode_ptr _currentEffectParent;
osg::ref_ptr<const osgDB::ReaderWriter::Options> _options;
};
void MakeEffectVisitor::apply(osg::Node& node)
{
SGPropertyNode_ptr savedEffectRoot;
const string& nodeName = node.getName();
bool restoreEffect = false;
if (!nodeName.empty()) {
EffectMap::iterator eitr = _effectMap.find(nodeName);
if (eitr != _effectMap.end()) {
savedEffectRoot = _currentEffectParent;
_currentEffectParent = eitr->second;
restoreEffect = true;
}
}
SplicingVisitor::apply(node);
if (restoreEffect)
_currentEffectParent = savedEffectRoot;
}
void MakeEffectVisitor::apply(osg::Geode& geode)
{
if (pushNode(getNewNode(geode)))
return;
osg::StateSet* ss = geode.getStateSet();
if (!ss) {
pushNode(&geode);
return;
}
SGPropertyNode_ptr ssRoot = new SGPropertyNode;
makeParametersFromStateSet(ssRoot, ss);
SGPropertyNode_ptr effectRoot = new SGPropertyNode;
effect::mergePropertyTrees(effectRoot, ssRoot, _currentEffectParent);
Effect* effect = makeEffect(effectRoot, true, _options);
EffectGeode* eg = dynamic_cast<EffectGeode*>(&geode);
if (eg) {
eg->setEffect(effect);
} else {
eg = new EffectGeode;
eg->setEffect(effect);
for (int i = 0; i < geode.getNumDrawables(); ++i)
eg->addDrawable(geode.getDrawable(i));
}
pushResultNode(&geode, eg);
}
}
namespace
{
class DefaultEffect : public simgear::Singleton<DefaultEffect>
{
public:
DefaultEffect()
{
_effect = new SGPropertyNode;
makeChild(_effect.ptr(), "inherits-from")
->setStringValue("Effects/model-default");
}
virtual ~DefaultEffect() {}
SGPropertyNode* getEffect() { return _effect.ptr(); }
protected:
SGPropertyNode_ptr _effect;
};
}
ref_ptr<Node> instantiateEffects(osg::Node* modelGroup,
PropertyList& effectProps,
const osgDB::ReaderWriter::Options* options)
{
SGPropertyNode_ptr defaultEffectPropRoot;
MakeEffectVisitor visitor(options);
MakeEffectVisitor::EffectMap& emap = visitor.getEffectMap();
for (PropertyList::iterator itr = effectProps.begin(),
end = effectProps.end();
itr != end;
++itr)
{
SGPropertyNode_ptr configNode = *itr;
std::vector<SGPropertyNode_ptr> objectNames =
configNode->getChildren("object-name");
SGPropertyNode* defaultNode = configNode->getChild("default");
if (defaultNode && defaultNode->getValue<bool>())
defaultEffectPropRoot = configNode;
BOOST_FOREACH(SGPropertyNode_ptr objNameNode, objectNames) {
emap.insert(make_pair(objNameNode->getStringValue(), configNode));
}
configNode->removeChild("default");
configNode->removeChildren("object-name");
}
if (!defaultEffectPropRoot)
defaultEffectPropRoot = DefaultEffect::instance()->getEffect();
visitor.setDefaultEffect(defaultEffectPropRoot.ptr());
modelGroup->accept(visitor);
osg::NodeList& result = visitor.getResults();
return ref_ptr<Node>(result[0].get());
}
}
// end of model.cxx

View File

@@ -20,6 +20,7 @@
#include <osgDB/ReaderWriter>
#include <simgear/misc/sg_path.hxx>
#include <simgear/props/props.hxx>
#include <simgear/scene/util/NodeAndDrawableVisitor.hxx>
osg::Texture2D*
@@ -86,5 +87,33 @@ public:
virtual void apply(osg::Node& node);
};
/**
* Transform an OSG subgraph by substituting Effects and EffectGeodes
* for osg::Geodes with osg::StateSets. This is only guaranteed to
* work for models prouced by the .ac loader.
*
* returns a copy if any nodes are changed
*/
osg::ref_ptr<osg::Node>
instantiateEffects(osg::Node* model,
PropertyList& effectProps,
const osgDB::ReaderWriter::Options* options);
/**
* Transform an OSG subgraph by substituting the Effects and
* EffectGeodes for osg::Geodes with osg::StateSets, inheriting from
* the default model effect. This is only guaranteed to work for
* models prouced by the .ac loader.
*
* returns a copy if any nodes are changed
*/
inline osg::ref_ptr<osg::Node>
instantiateEffects(osg::Node* model,
const osgDB::ReaderWriter::Options* options)
{
PropertyList effectProps;
return instantiateEffects(model, effectProps, options);
}
}
#endif // __MODEL_HXX

View File

@@ -19,6 +19,8 @@
# include <simgear_config.h>
#endif
#include <boost/algorithm/string.hpp>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osgDB/Registry>
@@ -26,6 +28,7 @@
#include <simgear/constants.h>
#include <simgear/props/props.hxx>
#include <simgear/props/props_io.hxx>
#include <simgear/scene/model/model.hxx>
#include <simgear/scene/model/ModelRegistry.hxx>
#include "SGPagedLOD.hxx"
@@ -59,6 +62,21 @@ SGModelLib::~SGModelLib()
{
}
namespace
{
osg::Node* loadFile(const string& path, osgDB::ReaderWriter::Options* options)
{
using namespace osg;
using namespace osgDB;
ref_ptr<Node> model = readRefNodeFile(path, options);
if (!model)
return 0;
if (boost::iends_with(path, ".ac"))
model = instantiateEffects(model.get(), options);
return model.release();
}
}
osg::Node*
SGModelLib::loadModel(const string &path,
SGPropertyNode *prop_root,
@@ -67,7 +85,7 @@ SGModelLib::loadModel(const string &path,
osg::ref_ptr<SGReaderWriterXMLOptions> opt = new SGReaderWriterXMLOptions(*(osgDB::Registry::instance()->getOptions()));
opt->setPropRoot(prop_root);
opt->setModelData(data);
osg::Node *n = readNodeFile(path, opt.get());
osg::Node *n = loadFile(path, opt.get());
if (n && n->getName().empty())
n->setName("Direct loaded model \"" + path + "\"");
return n;
@@ -82,7 +100,7 @@ SGModelLib::loadModel(const string &path,
osg::ref_ptr<SGReaderWriterXMLOptions> opt = new SGReaderWriterXMLOptions(*(osgDB::Registry::instance()->getOptions()));
opt->setPropRoot(prop_root);
opt->setLoadPanel(pf);
return readNodeFile(path, opt.get());
return loadFile(path, opt.get());
}
osg::Node*

View File

@@ -0,0 +1,40 @@
// CopyOp.cxx - Simgear CopyOp for copying our own classes
//
// Copyright (C) 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 Library General Public
// License along with this library; if not, write to the
// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
// Boston, MA 02111-1307, USA.
#include "CopyOp.hxx"
#include <simgear/scene/material/Effect.hxx>
#include <simgear/scene/material/Technique.hxx>
namespace simgear
{
osg::Object* CopyOp::operator()(const osg::Object* obj) const
{
if (dynamic_cast<const Effect*>(obj)
|| dynamic_cast<const Technique*>(obj)) {
if (_flags & DEEP_COPY_STATESETS)
return obj->clone(*this);
else
return const_cast<osg::Object*>(obj);
}
else {
return osg::CopyOp::operator()(obj);
}
}
}

View File

@@ -0,0 +1,37 @@
// CopyOp.hxx - Simgear CopyOp for copying our own classes
//
// Copyright (C) 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 Library General Public
// License along with this library; if not, write to the
// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
// Boston, MA 02111-1307, USA.
#ifndef SIMGEAR_COPYOP_HXX
#define SIMGEAR_COPYOP_HXX 1
#include <osg/CopyOp>
namespace simgear
{
class CopyOp : public osg::CopyOp
{
public:
CopyOp(osg::CopyOp::CopyFlags flags = osg::CopyOp::SHALLOW_COPY)
: osg::CopyOp(flags)
{
}
using osg::CopyOp::operator();
virtual osg::Object* operator()(const osg::Object* obj) const;
};
}
#endif

View File

@@ -14,6 +14,7 @@ include_HEADERS = \
SGStateAttributeVisitor.hxx \
SGTextureStateAttributeVisitor.hxx \
SGUpdateVisitor.hxx \
CopyOp.hxx \
NodeAndDrawableVisitor.hxx \
PrimitiveUtils.hxx \
QuadTreeBuilder.hxx \
@@ -29,6 +30,7 @@ libsgutil_a_SOURCES = \
SGSceneUserData.cxx \
SGStateAttributeVisitor.cxx \
SGTextureStateAttributeVisitor.cxx \
CopyOp.cxx \
NodeAndDrawableVisitor.cxx \
PrimitiveUtils.cxx \
SplicingVisitor.cxx \