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:
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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*
|
||||
|
||||
40
simgear/scene/util/CopyOp.cxx
Normal file
40
simgear/scene/util/CopyOp.cxx
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
37
simgear/scene/util/CopyOp.hxx
Normal file
37
simgear/scene/util/CopyOp.hxx
Normal 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
|
||||
@@ -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 \
|
||||
|
||||
Reference in New Issue
Block a user