Use Effects in materials library, and therefore in scenery

This commit is contained in:
timoore 2009-07-15 23:09:31 +00:00 committed by Tim Moore
parent d320a6facb
commit c6b2124129
16 changed files with 348 additions and 57 deletions

View File

@ -1,5 +1,6 @@
#include "Effect.hxx"
#include "Technique.hxx"
#include "Pass.hxx"
#include <algorithm>
#include <functional>
@ -11,8 +12,10 @@
#include <osg/Drawable>
#include <osg/RenderInfo>
#include <osg/StateSet>
#include <osgUtil/CullVisitor>
#include <osgDB/Registry>
#include <osgDB/Input>
#include <osgDB/ParameterOutput>
#include <simgear/structure/OSGUtils.hxx>
@ -23,6 +26,10 @@ namespace simgear
using namespace osg;
using namespace osgUtil;
Effect::Effect()
{
}
Effect::Effect(const Effect& rhs, const CopyOp& copyop)
{
using namespace std;
@ -31,6 +38,19 @@ Effect::Effect(const Effect& rhs, const CopyOp& copyop)
backRefInsertIterator(techniques),
bind(simgear::clone_ref<Technique>, _1, copyop));
}
// Assume that the last technique is always valid.
StateSet* Effect::getDefaultStateSet()
{
Technique* tniq = techniques.back().get();
if (!tniq)
return 0;
Pass* pass = tniq->passes.front().get();
if (!pass)
return 0;
return pass->getStateSet();
}
// There should always be a valid technique in an effect.
Technique* Effect::chooseTechnique(RenderInfo* info)
@ -58,4 +78,32 @@ void Effect::releaseGLObjects(osg::State* state) const
technique->releaseGLObjects(state);
}
}
Effect::~Effect()
{
}
bool Effect_writeLocalData(const Object& obj, osgDB::Output& fw)
{
const Effect& effect = static_cast<const Effect&>(obj);
fw.indent() << "techniques " << effect.techniques.size() << "\n";
BOOST_FOREACH(const ref_ptr<Technique>& technique, effect.techniques) {
fw.writeObject(*technique);
}
return true;
}
namespace
{
osgDB::RegisterDotOsgWrapperProxy effectProxy
(
new Effect,
"simgear::Effect",
"Object simgear::Effect",
0,
&Effect_writeLocalData
);
}
}

View File

@ -42,7 +42,7 @@ class Effect : public osg::Object
{
public:
META_Object(simgear,Effect)
Effect() {}
Effect();
Effect(const Effect& rhs,
const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
osg::StateSet* getDefaultStateSet();
@ -51,7 +51,7 @@ public:
virtual void resizeGLObjectBuffers(unsigned int maxSize);
virtual void releaseGLObjects(osg::State* state = 0) const;
protected:
~Effect() {}
~Effect();
};
}
#endif

View File

@ -0,0 +1,63 @@
// Copyright (C) 2008 Timothy 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 program 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.
//
// 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 "EffectCullVisitor.hxx"
#include "EffectGeode.hxx"
#include "Effect.hxx"
#include "Technique.hxx"
namespace simgear
{
using osgUtil::CullVisitor;
EffectCullVisitor::EffectCullVisitor()
{
}
EffectCullVisitor::EffectCullVisitor(const EffectCullVisitor& rhs) :
CullVisitor(rhs)
{
}
CullVisitor* EffectCullVisitor::clone() const
{
return new EffectCullVisitor(*this);
}
void EffectCullVisitor::apply(osg::Geode& node)
{
if (isCulled(node))
return;
EffectGeode *eg = dynamic_cast<EffectGeode*>(&node);
if (!eg) {
CullVisitor::apply(node);
return;
}
Technique* technique = eg->getEffect()->chooseTechnique(&getRenderInfo());
if (!technique) {
CullVisitor::apply(node);
return;
}
for (EffectGeode::DrawablesIterator beginItr = eg->drawablesBegin(),
e = eg->drawablesEnd();
beginItr != e;
beginItr = technique->processDrawables(beginItr, e, this,
eg->isCullingActive()))
;
}
}

View File

@ -0,0 +1,39 @@
// Copyright (C) 2008 Timothy 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 program 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.
//
// 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_CULL_VISITOR_HXX
#define SIMGEAR_EFFECT_CULL_VISITOR_HXX 1
#include <osgUtil/CullVisitor>
namespace osg
{
class Geode;
}
namespace simgear
{
class EffectCullVisitor : public osgUtil::CullVisitor
{
public:
EffectCullVisitor();
EffectCullVisitor(const EffectCullVisitor&);
virtual osgUtil::CullVisitor* clone() const;
using osgUtil::CullVisitor::apply;
virtual void apply(osg::Geode& node);
};
}
#endif

View File

@ -20,29 +20,24 @@
#include <osgUtil/CullVisitor>
#include <osgDB/Registry>
#include <osgDB/Input>
#include <osgDB/ParameterOutput>
namespace simgear
{
using namespace osg;
using namespace osgUtil;
void EffectGeode::traverse(NodeVisitor& nv)
EffectGeode::EffectGeode()
{
CullVisitor* cv = dynamic_cast<CullVisitor*>(&nv);
if (!cv || !_effect.valid()) {
Geode::traverse(nv);
return;
}
Technique* technique = _effect->chooseTechnique(&cv->getRenderInfo());
if (!technique) {
Geode::traverse(nv);
return;
}
for (DrawablesIterator beginItr = _drawables.begin();
beginItr != _drawables.end();
beginItr = technique->processDrawables(beginItr, _drawables.end(), cv,
isCullingActive()))
;
}
EffectGeode::EffectGeode(const EffectGeode& rhs, const CopyOp& copyop) :
Geode(rhs, copyop)
{
_effect = static_cast<Effect*>(rhs._effect->clone(copyop));
}
void EffectGeode::resizeGLObjectBuffers(unsigned int maxSize)
@ -59,4 +54,24 @@ void EffectGeode::releaseGLObjects(osg::State* state) const
Geode::releaseGLObjects(state);
}
bool EffectGeode_writeLocalData(const Object& obj, osgDB::Output& fw)
{
const EffectGeode& eg = static_cast<const EffectGeode&>(obj);
fw.indent() << "effect\n";
fw.writeObject(*eg.getEffect());
return true;
}
namespace
{
osgDB::RegisterDotOsgWrapperProxy effectGeodeProxy
(
new EffectGeode,
"simgear::EffectGeode",
"Object Node Geode simgear::EffectGeode",
0,
&EffectGeode_writeLocalData
);
}
}

View File

@ -30,12 +30,13 @@ public:
EffectGeode(const EffectGeode& rhs,
const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
META_Node(simgear,EffectGeode);
virtual void traverse(osg::NodeVisitor& nv);
Effect* getEffect() const { return _effect.get(); }
void setEffect(Effect* effect);
void setEffect(Effect* effect) { _effect = effect; }
virtual void resizeGLObjectBuffers(unsigned int maxSize);
virtual void releaseGLObjects(osg::State* = 0) const;
typedef DrawableList::iterator DrawablesIterator;
DrawablesIterator drawablesBegin() { return _drawables.begin(); }
DrawablesIterator drawablesEnd() { return _drawables.end(); }
private:
osg::ref_ptr<Effect> _effect;
};

View File

@ -6,6 +6,7 @@ noinst_HEADERS =
include_HEADERS = \
Effect.hxx \
EffectCullVisitor.hxx \
EffectGeode.hxx \
Pass.hxx \
Technique.hxx \
@ -15,6 +16,7 @@ include_HEADERS = \
libsgmaterial_a_SOURCES = \
Effect.cxx \
EffectCullVisitor.cxx \
EffectGeode.cxx \
Pass.cxx \
Technique.cxx \

View File

@ -3,6 +3,9 @@
#include <simgear/structure/OSGUtils.hxx>
#include <osg/StateSet>
#include <osgDB/Registry>
#include <osgDB/Input>
#include <osgDB/ParameterOutput>
namespace simgear
{
@ -24,4 +27,24 @@ void Pass::releaseGLObjects(osg::State* state) const
_stateSet->releaseGLObjects(state);
}
bool Pass_writeLocalData(const osg::Object& obj, osgDB::Output& fw)
{
const Pass& pass = static_cast<const Pass&>(obj);
fw.indent() << "stateSet\n";
fw.writeObject(*pass.getStateSet());
return true;
}
namespace
{
osgDB::RegisterDotOsgWrapperProxy passProxy
(
new Pass,
"simgear::Pass",
"Object simgear::Pass",
0,
&Pass_writeLocalData
);
}
}

View File

@ -36,6 +36,7 @@ public:
Pass(const Pass& rhs,
const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
osg::StateSet* getStateSet() { return _stateSet.get(); }
const osg::StateSet* getStateSet() const { return _stateSet.get(); }
void setStateSet(osg::StateSet* stateSet) { _stateSet = stateSet; }
virtual void resizeGLObjectBuffers(unsigned int maxSize);
virtual void releaseGLObjects(osg::State* state = 0) const;

View File

@ -10,6 +10,10 @@
#include <osg/Math>
#include <osgUtil/CullVisitor>
#include <osgDB/Registry>
#include <osgDB/Input>
#include <osgDB/ParameterOutput>
#include <simgear/structure/OSGUtils.hxx>
namespace simgear
@ -40,13 +44,14 @@ void ValidateOperation::operator() (GraphicsContext* gc)
}
}
Technique::Technique() : _glVersion(1.1f)
Technique::Technique(bool alwaysValid)
: _alwaysValid(alwaysValid), _glVersion(1.1f)
{
}
Technique::Technique(const Technique& rhs, const osg::CopyOp& copyop) :
_contextMap(rhs._contextMap), _shadowingStateSet(rhs._shadowingStateSet),
_glVersion(rhs._glVersion)
_contextMap(rhs._contextMap), _alwaysValid(rhs._alwaysValid),
_shadowingStateSet(rhs._shadowingStateSet), _glVersion(rhs._glVersion)
{
using namespace std;
using namespace boost;
@ -62,6 +67,8 @@ Technique::~Technique()
Technique::Status Technique::valid(osg::RenderInfo* renderInfo)
{
if (_alwaysValid)
return VALID;
unsigned contextID = renderInfo->getContextID();
ContextInfo& contextInfo = _contextMap[contextID];
Status status = contextInfo.valid();
@ -81,6 +88,8 @@ Technique::Status Technique::valid(osg::RenderInfo* renderInfo)
Technique::Status Technique::getValidStatus(const RenderInfo* renderInfo) const
{
if (_alwaysValid)
return VALID;
ContextInfo& contextInfo = _contextMap[renderInfo->getContextID()];
return contextInfo.valid();
}
@ -177,4 +186,33 @@ void Technique::releaseGLObjects(osg::State* state) const
info.valid.compareAndSwap(oldVal, UNKNOWN);
}
}
bool Technique_writeLocalData(const Object& obj, osgDB::Output& fw)
{
const Technique& tniq = static_cast<const Technique&>(obj);
fw.indent() << "alwaysValid "
<< (tniq.getAlwaysValid() ? "TRUE\n" : "FALSE\n");
fw.indent() << "glVersion " << tniq.getGLVersion() << "\n";
if (tniq.getShadowingStateSet()) {
fw.indent() << "shadowingStateSet\n";
fw.writeObject(*tniq.getShadowingStateSet());
}
fw.indent() << "passes\n";
BOOST_FOREACH(const ref_ptr<Pass>& pass, tniq.passes) {
fw.writeObject(*pass);
}
return true;
}
namespace
{
osgDB::RegisterDotOsgWrapperProxy TechniqueProxy
(
new Technique,
"simgear::Technique",
"Object simgear::Technique",
0,
&Technique_writeLocalData
);
}
}

View File

@ -52,7 +52,7 @@ class Technique : public osg::Object
{
public:
META_Object(simgear,Technique);
Technique();
Technique(bool alwaysValid = false);
Technique(const Technique& rhs,
const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
virtual ~Technique();
@ -83,14 +83,20 @@ public:
bool isCullingActive);
std::vector<osg::ref_ptr<Pass> > passes;
osg::StateSet* getShadowingStateSet() { return _shadowingStateSet.get(); }
const osg::StateSet* getShadowingStateSet() const
{
return _shadowingStateSet.get();
}
void setShadowingStateSet(osg::StateSet* ss) { _shadowingStateSet = ss; }
virtual void resizeGLObjectBuffers(unsigned int maxSize);
virtual void releaseGLObjects(osg::State* state = 0) const;
// Initial validity testing. Either the minimum OpenGL version
// must be supported, or the list of extensions must be supported.
float getGLVersion() { return _glVersion; }
float getGLVersion() const { return _glVersion; }
void setGLVersion(float glVersion) { _glVersion = glVersion; }
std::vector<std::string> glExtensions;
bool getAlwaysValid() const { return _alwaysValid; }
void setAlwaysValid(bool val) { _alwaysValid = val; }
protected:
// Validity of technique in a graphics context.
struct ContextInfo : public osg::Referenced
@ -105,6 +111,7 @@ protected:
};
typedef osg::buffered_object<ContextInfo> ContextMap;
mutable ContextMap _contextMap;
bool _alwaysValid;
osg::ref_ptr<osg::StateSet> _shadowingStateSet;
float _glVersion;
};

View File

@ -30,9 +30,12 @@
#include <string.h>
#include <map>
#include "mat.hxx"
#include <osg/CullFace>
#include <osg/Material>
#include <osg/ShadeModel>
#include <osg/StateSet>
#include <osg/TexEnv>
#include <osg/Texture2D>
#include <osgDB/ReadFile>
@ -45,7 +48,9 @@
#include <simgear/scene/model/model.hxx>
#include <simgear/scene/util/StateAttributeFactory.hxx>
#include "mat.hxx"
#include "Effect.hxx"
#include "Technique.hxx"
#include "Pass.hxx"
using std::map;
using namespace simgear;
@ -55,6 +60,11 @@ 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::SGMaterial( const string &fg_root, const SGPropertyNode *props )
{
@ -244,15 +254,34 @@ SGMaterial::get_state (int n)
return st;
}
Effect* SGMaterial::get_effect(int n)
{
if (_status.size() == 0) {
SG_LOG( SG_GENERAL, SG_WARN, "No effect available.");
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;
}
// XXX This business of returning a "random" alternate texture is
// really bogus. It means that the appearance of the terrain
// depends on the order in which it is paged in!
_current_ptr = (_current_ptr + 1) % _status.size();
return _status[i].effect.get();
}
void
SGMaterial::build_state( bool defer_tex_load )
{
StateAttributeFactory *attrFact = StateAttributeFactory::instance();
SGMaterialUserData* user = new SGMaterialUserData(this);
for (unsigned int i = 0; i < _status.size(); i++)
{
osg::StateSet *stateSet = new osg::StateSet;
stateSet->setUserData(new SGMaterialUserData(this));
stateSet->setUserData(user);
// Set up the textured state
stateSet->setAttribute(attrFact->getSmoothShadeModel());
@ -283,6 +312,14 @@ SGMaterial::build_state( bool defer_tex_load )
}
_status[i].state = stateSet;
Pass* pass = new Pass;
pass->setStateSet(_status[i].state.get());
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;
}
}

View File

@ -39,7 +39,11 @@
#include <simgear/math/SGMath.hxx>
#include <osg/ref_ptr>
#include <osg/StateSet>
namespace osg
{
class StateSet;
}
#include <simgear/props/props.hxx>
#include <simgear/structure/SGSharedPtr.hxx>
@ -47,10 +51,10 @@
#include "matmodel.hxx"
using std::string;
using std::vector;
using std::map;
namespace simgear
{
class Effect;
}
class SGMaterialGlyph;
@ -79,7 +83,7 @@ public:
* state information for the material. This node is usually
* loaded from the $FG_ROOT/materials.xml file.
*/
SGMaterial( const string &fg_root, const SGPropertyNode *props);
SGMaterial( const std::string &fg_root, const SGPropertyNode *props);
/**
@ -88,7 +92,7 @@ public:
* @param texture_path A string containing an absolute path
* to a texture file (usually RGB).
*/
SGMaterial( const string &texpath );
SGMaterial( const std::string &texpath );
/**
@ -117,7 +121,7 @@ public:
* Get the textured state.
*/
osg::StateSet *get_state (int n = -1);
simgear::Effect *get_effect(int n = -1);
/**
* Get the number of textures assigned to this material.
@ -188,7 +192,7 @@ public:
*
* @return the texture to use for trees.
*/
inline string get_tree_texture () const { return tree_texture; }
inline std::string get_tree_texture () const { return tree_texture; }
/**
* Return if the surface material is solid, if it is not solid, a fluid
@ -219,12 +223,12 @@ public:
/**
* Get the list of names for this material
*/
const vector<string>& get_names() const { return _names; }
const std::vector<std::string>& get_names() const { return _names; }
/**
* add the given name to the list of names this material is known
*/
void add_name(const string& name) { _names.push_back(name); }
void add_name(const std::string& name) { _names.push_back(name); }
/**
* Get the number of randomly-placed objects defined for this material.
@ -241,7 +245,7 @@ public:
/**
* Return pointer to glyph class, or 0 if it doesn't exist.
*/
SGMaterialGlyph * get_glyph (const string& name) const;
SGMaterialGlyph * get_glyph (const std::string& name) const;
void set_light_color(const SGVec4f& color)
{ emission = color; }
@ -272,10 +276,10 @@ protected:
protected:
struct _internal_state {
_internal_state( osg::StateSet *s, const string &t, bool l )
: state(s), texture_path(t), texture_loaded(l) {}
_internal_state( osg::StateSet *s, const std::string &t, bool l );
osg::ref_ptr<osg::StateSet> state;
string texture_path;
osg::ref_ptr<simgear::Effect> effect;
std::string texture_path;
bool texture_loaded;
};
@ -287,7 +291,7 @@ private:
////////////////////////////////////////////////////////////////////
// texture status
vector<_internal_state> _status;
std::vector<_internal_state> _status;
// Round-robin counter
mutable unsigned int _current_ptr;
@ -339,23 +343,23 @@ private:
double shininess;
// the list of names for this material. May be empty.
vector<string> _names;
std::vector<std::string> _names;
vector<SGSharedPtr<SGMatModelGroup> > object_groups;
std::vector<SGSharedPtr<SGMatModelGroup> > object_groups;
// taxiway-/runway-sign texture elements
map<string, SGSharedPtr<SGMaterialGlyph> > glyphs;
std::map<std::string, SGSharedPtr<SGMaterialGlyph> > glyphs;
// Tree texture, typically a strip of applicable tree textures
string tree_texture;
std::string tree_texture;
////////////////////////////////////////////////////////////////////
// Internal constructors and methods.
////////////////////////////////////////////////////////////////////
SGMaterial( const string &fg_root, const SGMaterial &mat ); // unimplemented
SGMaterial( const std::string &fg_root, const SGMaterial &mat ); // unimplemented
void read_properties( const string &fg_root, const SGPropertyNode *props );
void read_properties( const std::string &fg_root, const SGPropertyNode *props );
void build_state( bool defer_tex_load );
void set_state( osg::StateSet *s );

View File

@ -58,6 +58,8 @@
#include "mat.hxx"
#include "Effect.hxx"
#include "Technique.hxx"
#include "matlib.hxx"
using std::string;

View File

@ -485,6 +485,9 @@ SGCloudLayer::rebuild()
layer_states[SG_CLOUD_CLEAR] = 0;
layer_states2[SG_CLOUD_CLEAR] = 0;
#if 0
// experimental optimization that may not make any difference
// at all :/
osg::CopyOp copyOp;
for (int i = 0; i < SG_MAX_CLOUD_COVERAGES; ++i) {
StateAttributeFactory *saf = StateAttributeFactory::instance();
@ -495,9 +498,7 @@ SGCloudLayer::rebuild()
layer_states2[i]->setAttribute(saf ->getCullFaceBack());
}
}
// OSGFIXME
// SGNewCloud::loadTextures(texture_path.str());
// layer3D->buildTestLayer();
#endif
}
scale = 4000.0;

View File

@ -44,6 +44,8 @@
#include <simgear/io/sg_binobj.hxx>
#include <simgear/math/sg_geodesy.hxx>
#include <simgear/math/sg_random.h>
#include <simgear/scene/material/Effect.hxx>
#include <simgear/scene/material/EffectGeode.hxx>
#include <simgear/scene/material/mat.hxx>
#include <simgear/scene/material/matlib.hxx>
#include <simgear/scene/model/SGOffsetTransform.hxx>
@ -367,18 +369,26 @@ struct SGTileGeometryBin {
if (materialTriangleMap.empty())
return 0;
osg::Geode* geode = new osg::Geode;
EffectGeode* eg = 0;
osg::Group* group = (materialTriangleMap.size() > 1 ? new osg::Group : 0);
//osg::Geode* geode = new osg::Geode;
SGMaterialTriangleMap::const_iterator i;
for (i = materialTriangleMap.begin(); i != materialTriangleMap.end(); ++i) {
osg::Geometry* geometry = i->second.buildGeometry();
SGMaterial *mat = 0;
if (matlib)
mat = matlib->find(i->first);
eg = new EffectGeode;
if (mat)
geometry->setStateSet(mat->get_state());
geode->addDrawable(geometry);
eg->setEffect(mat->get_effect());
eg->addDrawable(geometry);
if (group)
group->addChild(eg);
}
return geode;
if (group)
return group;
else
return eg;
}
void computeRandomSurfaceLights(SGMaterialLib* matlib)