Updates to osgFX, from Marco Jez, to map Effect across to being derived
from osg::Group rather than from osg::Node.
This commit is contained in:
parent
5c3c0ed17c
commit
584f805327
@ -180,7 +180,8 @@ protected:
|
|||||||
root_->removeChild(0, root_->getNumChildren());
|
root_->removeChild(0, root_->getNumChildren());
|
||||||
osg::ref_ptr<osgFX::Effect> effect = effects_[selected_fx_].get();
|
osg::ref_ptr<osgFX::Effect> effect = effects_[selected_fx_].get();
|
||||||
effect->setEnabled(fxen_);
|
effect->setEnabled(fxen_);
|
||||||
effect->setChild(scene_.get());
|
effect->removeChild(0, effect->getNumChildren());
|
||||||
|
effect->addChild(scene_.get());
|
||||||
effect->setUpDemo();
|
effect->setUpDemo();
|
||||||
root_->addChild(effect.get());
|
root_->addChild(effect.get());
|
||||||
}
|
}
|
||||||
|
@ -25,11 +25,11 @@ namespace osgFX
|
|||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This effect makes surfaces appear bumpy. The child node must use two textures,
|
This effect makes surfaces appear bumpy. Children nodes must use two textures,
|
||||||
one for diffuse color and one for the normal map (which can be created
|
one for diffuse color and one for the normal map (which can be created
|
||||||
from a height map with tools like nVIDIA's normal map generator). Furthermore,
|
from a height map with tools like nVIDIA's normal map generator). Furthermore,
|
||||||
tangent-space basis vectors must be created and assigned to each Geometry; this
|
tangent-space basis vectors must be created and assigned to each Geometry; this
|
||||||
can be done quickly by calling BumpMapping::prepareChild(). Note that both
|
can be done quickly by calling BumpMapping::prepareChildren(). Note that both
|
||||||
diffuse and normal map textures must have corresponding UV maps defined in
|
diffuse and normal map textures must have corresponding UV maps defined in
|
||||||
Geometry objects.
|
Geometry objects.
|
||||||
This effect defines a preferred technique which uses ARB vertex & fragment
|
This effect defines a preferred technique which uses ARB vertex & fragment
|
||||||
@ -46,11 +46,11 @@ namespace osgFX
|
|||||||
|
|
||||||
"Bump Mapping",
|
"Bump Mapping",
|
||||||
|
|
||||||
"This effect makes surfaces appear bumpy. The child node must use two textures, "
|
"This effect makes surfaces appear bumpy. Children nodes must use two textures, "
|
||||||
"one for diffuse color and one for the normal map (which can be created "
|
"one for diffuse color and one for the normal map (which can be created "
|
||||||
"from a height map with tools like nVIDIA's normal map generator). Furthermore, "
|
"from a height map with tools like nVIDIA's normal map generator). Furthermore, "
|
||||||
"tangent-space basis vectors must be created and assigned to each Geometry; this "
|
"tangent-space basis vectors must be created and assigned to each Geometry; this "
|
||||||
"can be done quickly by calling BumpMapping::prepareChild(). Note that both "
|
"can be done quickly by calling BumpMapping::prepareChildren(). Note that both "
|
||||||
"diffuse and normal map textures must have corresponding UV maps defined in "
|
"diffuse and normal map textures must have corresponding UV maps defined in "
|
||||||
"Geometry objects.\n"
|
"Geometry objects.\n"
|
||||||
"This effect defines a preferred technique which uses ARB vertex & fragment "
|
"This effect defines a preferred technique which uses ARB vertex & fragment "
|
||||||
@ -79,22 +79,22 @@ namespace osgFX
|
|||||||
/** set the texture unit that contains normal map texture. Default is 0 */
|
/** set the texture unit that contains normal map texture. Default is 0 */
|
||||||
inline void setNormalMapTextureUnit(int n);
|
inline void setNormalMapTextureUnit(int n);
|
||||||
|
|
||||||
/** get the diffuse color texture that overrides the child's texture */
|
/** get the diffuse color texture that overrides children's texture */
|
||||||
inline osg::Texture2D *getOverrideDiffuseTexture();
|
inline osg::Texture2D *getOverrideDiffuseTexture();
|
||||||
|
|
||||||
/** get the const diffuse color texture that overrides the child's texture */
|
/** get the const diffuse color texture that overrides children's texture */
|
||||||
inline const osg::Texture2D *getOverrideDiffuseTexture() const;
|
inline const osg::Texture2D *getOverrideDiffuseTexture() const;
|
||||||
|
|
||||||
/** set the diffuse color texture that overrides the child's texture */
|
/** set the diffuse color texture that overrides children's texture */
|
||||||
inline void setOverrideDiffuseTexture(osg::Texture2D *texture);
|
inline void setOverrideDiffuseTexture(osg::Texture2D *texture);
|
||||||
|
|
||||||
/** get the normal map texture that overrides the child's texture */
|
/** get the normal map texture that overrides children's texture */
|
||||||
inline osg::Texture2D *getOverrideNormalMapTexture();
|
inline osg::Texture2D *getOverrideNormalMapTexture();
|
||||||
|
|
||||||
/** get the const normal map texture that overrides the child's texture */
|
/** get the const normal map texture that overrides children's texture */
|
||||||
inline const osg::Texture2D *getOverrideNormalMapTexture() const;
|
inline const osg::Texture2D *getOverrideNormalMapTexture() const;
|
||||||
|
|
||||||
/** set the normal map texture that overrides the child's texture */
|
/** set the normal map texture that overrides children's texture */
|
||||||
inline void setOverrideNormalMapTexture(osg::Texture2D *texture);
|
inline void setOverrideNormalMapTexture(osg::Texture2D *texture);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -106,8 +106,8 @@ namespace osgFX
|
|||||||
/** prepare a Node for bump lighting, calling prepareGeometry() for each Geometry */
|
/** prepare a Node for bump lighting, calling prepareGeometry() for each Geometry */
|
||||||
void prepareNode(osg::Node *node);
|
void prepareNode(osg::Node *node);
|
||||||
|
|
||||||
/** prepare the current child for bump lighting. Actually calls prepareNode(getChild()) */
|
/** prepare children for bump lighting. Actually calls prepareNode() for each child */
|
||||||
void prepareChild();
|
void prepareChildren();
|
||||||
|
|
||||||
/** set up a demo environment with predefined diffuse and normal maps, as well as texture coordinates */
|
/** set up a demo environment with predefined diffuse and normal maps, as well as texture coordinates */
|
||||||
void setUpDemo();
|
void setUpDemo();
|
||||||
|
@ -52,10 +52,9 @@ namespace osgFX
|
|||||||
selected either manually, with selectTechnique(), or automatically, in which
|
selected either manually, with selectTechnique(), or automatically, in which
|
||||||
case the first technique that is supported by all active rendering contexts
|
case the first technique that is supported by all active rendering contexts
|
||||||
is chosen.
|
is chosen.
|
||||||
If you are an Effect user, then simply use it as a single-child group.
|
If you are an Effect user, then simply use it as a node group. Create an
|
||||||
Create an instance of your desired effect, add it to your scene graph (it
|
instance of your desired effect, add it to your scene graph and call its
|
||||||
is a Node) and call its setChild() method to set its child node as you
|
addChild() method to add a child node as you would do with a Group.
|
||||||
would do with a Group.
|
|
||||||
If you are an Effect developer, you will have to implement the method
|
If you are an Effect developer, you will have to implement the method
|
||||||
define_techniques() to define the different techniques that can be used
|
define_techniques() to define the different techniques that can be used
|
||||||
for obtaining the desired effect. In define_techniques() you will usually
|
for obtaining the desired effect. In define_techniques() you will usually
|
||||||
@ -64,7 +63,7 @@ namespace osgFX
|
|||||||
techniques added first will have higher priority and will be used first as
|
techniques added first will have higher priority and will be used first as
|
||||||
soon as all rendering contexts support it.
|
soon as all rendering contexts support it.
|
||||||
*/
|
*/
|
||||||
class OSGFX_EXPORT Effect: public osg::Node {
|
class OSGFX_EXPORT Effect: public osg::Group {
|
||||||
public:
|
public:
|
||||||
Effect();
|
Effect();
|
||||||
Effect(const Effect ©, const osg::CopyOp ©op = osg::CopyOp::SHALLOW_COPY);
|
Effect(const Effect ©, const osg::CopyOp ©op = osg::CopyOp::SHALLOW_COPY);
|
||||||
@ -95,15 +94,6 @@ namespace osgFX
|
|||||||
*/
|
*/
|
||||||
inline virtual void setUpDemo() {}
|
inline virtual void setUpDemo() {}
|
||||||
|
|
||||||
/** get the const child node */
|
|
||||||
inline const osg::Node *getChild() const;
|
|
||||||
|
|
||||||
/** get the child node */
|
|
||||||
inline osg::Node *getChild();
|
|
||||||
|
|
||||||
/** set the child node */
|
|
||||||
inline void setChild(osg::Node *child);
|
|
||||||
|
|
||||||
/** get the number of techniques defined for this effect */
|
/** get the number of techniques defined for this effect */
|
||||||
inline int getNumTechniques() const;
|
inline int getNumTechniques() const;
|
||||||
|
|
||||||
@ -123,14 +113,16 @@ namespace osgFX
|
|||||||
/** select a technique or enable automatic detection */
|
/** select a technique or enable automatic detection */
|
||||||
inline void selectTechnique(int i = AUTO_DETECT);
|
inline void selectTechnique(int i = AUTO_DETECT);
|
||||||
|
|
||||||
virtual void traverse(osg::NodeVisitor &nv);
|
/** custom traversal */
|
||||||
|
virtual void traverse(osg::NodeVisitor &nv);
|
||||||
|
|
||||||
|
/** default traversal */
|
||||||
|
inline void inherited_traverse(osg::NodeVisitor &nv);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ~Effect() {}
|
virtual ~Effect();
|
||||||
Effect &operator=(const Effect &) { return *this; }
|
Effect &operator=(const Effect &) { return *this; }
|
||||||
|
|
||||||
virtual bool computeBound() const;
|
|
||||||
|
|
||||||
/** force rebuilding of techniques on next traversal */
|
/** force rebuilding of techniques on next traversal */
|
||||||
inline void dirtyTechniques();
|
inline void dirtyTechniques();
|
||||||
|
|
||||||
@ -144,7 +136,7 @@ namespace osgFX
|
|||||||
this method.
|
this method.
|
||||||
*/
|
*/
|
||||||
virtual bool define_techniques() = 0;
|
virtual bool define_techniques() = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class Validator;
|
friend class Validator;
|
||||||
|
|
||||||
@ -157,11 +149,11 @@ namespace osgFX
|
|||||||
|
|
||||||
// use int instead of bool to avoid errors
|
// use int instead of bool to avoid errors
|
||||||
mutable osg::buffered_value<int> tech_selected_;
|
mutable osg::buffered_value<int> tech_selected_;
|
||||||
|
|
||||||
int global_sel_tech_;
|
int global_sel_tech_;
|
||||||
|
|
||||||
bool techs_defined_;
|
bool techs_defined_;
|
||||||
|
|
||||||
osg::ref_ptr<osg::Node> child_;
|
|
||||||
osg::ref_ptr<osg::Geode> dummy_for_validation_;
|
osg::ref_ptr<osg::Geode> dummy_for_validation_;
|
||||||
|
|
||||||
void build_dummy_node();
|
void build_dummy_node();
|
||||||
@ -179,33 +171,6 @@ namespace osgFX
|
|||||||
enabled_ = v;
|
enabled_ = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const osg::Node *Effect::getChild() const
|
|
||||||
{
|
|
||||||
return child_.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline osg::Node *Effect::getChild()
|
|
||||||
{
|
|
||||||
return child_.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void Effect::setChild(osg::Node *child)
|
|
||||||
{
|
|
||||||
child_ = child;
|
|
||||||
setNumChildrenRequiringUpdateTraversal(0);
|
|
||||||
setNumChildrenWithCullingDisabled(0);
|
|
||||||
setNumChildrenWithOccluderNodes(0);
|
|
||||||
if (child) {
|
|
||||||
if (child->getNumChildrenRequiringUpdateTraversal() > 0 || child->getUpdateCallback())
|
|
||||||
setNumChildrenRequiringUpdateTraversal(1);
|
|
||||||
if (child->getNumChildrenWithCullingDisabled() > 0 || !child->getCullingActive())
|
|
||||||
setNumChildrenWithCullingDisabled(1);
|
|
||||||
if (child->getNumChildrenWithOccluderNodes() > 0 || dynamic_cast<osg::OccluderNode *>(child))
|
|
||||||
setNumChildrenWithOccluderNodes(1);
|
|
||||||
}
|
|
||||||
dirtyBound();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int Effect::getNumTechniques() const
|
inline int Effect::getNumTechniques() const
|
||||||
{
|
{
|
||||||
return static_cast<int>(techs_.size());
|
return static_cast<int>(techs_.size());
|
||||||
@ -240,6 +205,12 @@ namespace osgFX
|
|||||||
{
|
{
|
||||||
techs_defined_ = false;
|
techs_defined_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void Effect::inherited_traverse(osg::NodeVisitor &nv)
|
||||||
|
{
|
||||||
|
typedef osg::Group inherited;
|
||||||
|
inherited::traverse(nv);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,6 +37,8 @@
|
|||||||
namespace osgFX
|
namespace osgFX
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class Effect;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This is the base class for effect techniques. A technique represents one
|
This is the base class for effect techniques. A technique represents one
|
||||||
of the possible ways to implement a special effect. This base class is
|
of the possible ways to implement a special effect. This base class is
|
||||||
@ -79,12 +81,6 @@ namespace osgFX
|
|||||||
/** get the number of rendering passes defined in this technique */
|
/** get the number of rendering passes defined in this technique */
|
||||||
inline int getNumPasses() const;
|
inline int getNumPasses() const;
|
||||||
|
|
||||||
/** get the Group object associated to the i-th pass */
|
|
||||||
inline osg::Group *getPassGroup(int i);
|
|
||||||
|
|
||||||
/** get the const Group object associated to the i-th pass */
|
|
||||||
inline const osg::Group *getPassGroup(int i) const;
|
|
||||||
|
|
||||||
/** get the StateSet object associated to the i-th pass */
|
/** get the StateSet object associated to the i-th pass */
|
||||||
inline osg::StateSet *getPassStateSet(int i);
|
inline osg::StateSet *getPassStateSet(int i);
|
||||||
|
|
||||||
@ -92,11 +88,13 @@ namespace osgFX
|
|||||||
inline const osg::StateSet *getPassStateSet(int i) const;
|
inline const osg::StateSet *getPassStateSet(int i) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
traverses the child nodes with multipass if necessary.
|
traverse children with multipass if necessary. By default this method
|
||||||
|
simply calls the protected method traverse_implementation(); you can
|
||||||
|
override it to change the default behavior.
|
||||||
Don't call this method directly as it is called by osgFX::Effect
|
Don't call this method directly as it is called by osgFX::Effect
|
||||||
*/
|
*/
|
||||||
virtual void accept(osg::NodeVisitor &nv, osg::Node *child);
|
inline virtual void traverse(osg::NodeVisitor &nv, Effect *fx);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Technique(const Technique &): osg::Referenced() {} // copying is nonsense ;)
|
Technique(const Technique &): osg::Referenced() {} // copying is nonsense ;)
|
||||||
virtual ~Technique() {}
|
virtual ~Technique() {}
|
||||||
@ -105,82 +103,54 @@ namespace osgFX
|
|||||||
/** force rebuilding of pass nodes on next traversal */
|
/** force rebuilding of pass nodes on next traversal */
|
||||||
inline void dirtyPasses();
|
inline void dirtyPasses();
|
||||||
|
|
||||||
/** optional: return a node that overrides the child node on a specified pass */
|
|
||||||
inline virtual osg::Node *getOverrideChild(int) { return 0; }
|
|
||||||
|
|
||||||
/** create a new pass node, add it to the technique and associate a StateSet */
|
/** create a new pass node, add it to the technique and associate a StateSet */
|
||||||
void addPass(osg::StateSet *ss = 0);
|
void addPass(osg::StateSet *ss = 0);
|
||||||
|
|
||||||
/**
|
/** optional: return a node that overrides the child node on a specified pass */
|
||||||
add a new pass to the technique specifying an user-defined pass node.
|
inline virtual osg::Node *getOverrideChild(int) { return 0; }
|
||||||
You should call this version of addPass() only when you need to gain direct
|
|
||||||
control over the pass node (i.e. for setting up a cull callback); otherwise
|
|
||||||
please use addPass(StateSet*) and let the class create the pass node for you.
|
|
||||||
*/
|
|
||||||
void addPass(osg::Group *pass);
|
|
||||||
|
|
||||||
/**
|
|
||||||
get the control node which holds the user's subgraph.
|
|
||||||
You may want to do something on it like applying a cull callback.
|
|
||||||
*/
|
|
||||||
inline osg::Group *getControlNode();
|
|
||||||
|
|
||||||
/** get the const control node which holds the user's subgraph */
|
|
||||||
inline const osg::Group *getControlNode() const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
define the rendering passes that make up this technique. You must
|
define the rendering passes that make up this technique. You must
|
||||||
implement this method in derived classes to add the required passes.
|
implement this method in derived classes to add the required passes.
|
||||||
*/
|
*/
|
||||||
virtual void define_passes() = 0;
|
virtual void define_passes() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
traverse children with multipass if necessary. Don't call this method
|
||||||
|
directly unless you are in a customized version of traverse().
|
||||||
|
*/
|
||||||
|
void traverse_implementation(osg::NodeVisitor &nv, Effect *fx);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool passes_defined_;
|
typedef std::vector<osg::ref_ptr<osg::StateSet> > Pass_list;
|
||||||
|
Pass_list passes_;
|
||||||
osg::ref_ptr<osg::Group> control_node_;
|
|
||||||
osg::ref_ptr<osg::Node> prev_child_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// INLINE METHODS
|
// INLINE METHODS
|
||||||
|
|
||||||
inline int Technique::getNumPasses() const
|
inline int Technique::getNumPasses() const
|
||||||
{
|
{
|
||||||
return static_cast<int>(control_node_->getNumChildren());
|
return static_cast<int>(passes_.size());
|
||||||
}
|
|
||||||
|
|
||||||
inline osg::Group *Technique::getPassGroup(int i)
|
|
||||||
{
|
|
||||||
return static_cast<osg::Group *>(control_node_->getChild(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const osg::Group *Technique::getPassGroup(int i) const
|
|
||||||
{
|
|
||||||
return static_cast<const osg::Group *>(control_node_->getChild(i));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline osg::StateSet *Technique::getPassStateSet(int i)
|
inline osg::StateSet *Technique::getPassStateSet(int i)
|
||||||
{
|
{
|
||||||
return control_node_->getChild(i)->getStateSet();
|
return passes_[i].get();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const osg::StateSet *Technique::getPassStateSet(int i) const
|
inline const osg::StateSet *Technique::getPassStateSet(int i) const
|
||||||
{
|
{
|
||||||
return control_node_->getChild(i)->getStateSet();
|
return passes_[i].get();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline osg::Group *Technique::getControlNode()
|
|
||||||
{
|
|
||||||
return control_node_.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const osg::Group *Technique::getControlNode() const
|
|
||||||
{
|
|
||||||
return control_node_.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void Technique::dirtyPasses()
|
inline void Technique::dirtyPasses()
|
||||||
{
|
{
|
||||||
passes_defined_ = false;
|
passes_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Technique::traverse(osg::NodeVisitor &nv, Effect *fx)
|
||||||
|
{
|
||||||
|
traverse_implementation(nv, fx);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -34,22 +34,28 @@ namespace osgFX
|
|||||||
*/
|
*/
|
||||||
class OSGFX_EXPORT Validator: public osg::StateAttribute {
|
class OSGFX_EXPORT Validator: public osg::StateAttribute {
|
||||||
public:
|
public:
|
||||||
|
enum {
|
||||||
|
VALIDATOR = 0x56616C69
|
||||||
|
};
|
||||||
|
|
||||||
Validator();
|
Validator();
|
||||||
Validator(Effect *effect);
|
Validator(Effect *effect);
|
||||||
Validator(const Validator ©, const osg::CopyOp ©op = osg::CopyOp::SHALLOW_COPY);
|
Validator(const Validator ©, const osg::CopyOp ©op = osg::CopyOp::SHALLOW_COPY);
|
||||||
|
|
||||||
META_StateAttribute(osgFX, Validator, 0x56616C69);
|
META_StateAttribute(osgFX, Validator, VALIDATOR);
|
||||||
|
|
||||||
void apply(osg::State &state) const;
|
void apply(osg::State &state) const;
|
||||||
|
|
||||||
inline int compare(const osg::StateAttribute &sa) const;
|
inline int compare(const osg::StateAttribute &sa) const;
|
||||||
|
|
||||||
|
inline void disable() { effect_ = 0; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ~Validator() {}
|
virtual ~Validator() {}
|
||||||
Validator &operator=(const Validator &) { return *this; }
|
Validator &operator=(const Validator &) { return *this; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mutable osg::ref_ptr<Effect> effect_;
|
mutable Effect *effect_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// INLINE METHODS
|
// INLINE METHODS
|
||||||
@ -59,8 +65,8 @@ namespace osgFX
|
|||||||
const Validator *v = dynamic_cast<const Validator *>(&sa);
|
const Validator *v = dynamic_cast<const Validator *>(&sa);
|
||||||
if (!v) return -1;
|
if (!v) return -1;
|
||||||
|
|
||||||
if (effect_.get() < v->effect_.get()) return -1;
|
if (effect_ < v->effect_) return -1;
|
||||||
if (effect_.get() > v->effect_.get()) return 1;
|
if (effect_ > v->effect_) return 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -599,22 +599,23 @@ void BumpMapping::prepareNode(osg::Node *node)
|
|||||||
node->accept(tv);
|
node->accept(tv);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BumpMapping::prepareChild()
|
void BumpMapping::prepareChildren()
|
||||||
{
|
{
|
||||||
if (getChild())
|
for (unsigned i=0; i<getNumChildren(); ++i)
|
||||||
prepareNode(getChild());
|
prepareNode(getChild(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
void BumpMapping::setUpDemo()
|
void BumpMapping::setUpDemo()
|
||||||
{
|
{
|
||||||
// generate texture coordinates
|
// generate texture coordinates
|
||||||
TexCoordGenerator tcg(diffuseunit_, normalunit_);
|
TexCoordGenerator tcg(diffuseunit_, normalunit_);
|
||||||
getChild()->accept(tcg);
|
for (unsigned i=0; i<getNumChildren(); ++i)
|
||||||
|
getChild(i)->accept(tcg);
|
||||||
|
|
||||||
// set up diffuse texture
|
// set up diffuse texture
|
||||||
if (!diffuse_tex_.valid()) {
|
if (!diffuse_tex_.valid()) {
|
||||||
diffuse_tex_ = new osg::Texture2D;
|
diffuse_tex_ = new osg::Texture2D;
|
||||||
diffuse_tex_->setImage(osgDB::readImageFile("whitemetal_diffuse.jpg"));
|
diffuse_tex_->setImage(osgDB::readImageFile("Images/whitemetal_diffuse.jpg"));
|
||||||
diffuse_tex_->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR);
|
diffuse_tex_->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR);
|
||||||
diffuse_tex_->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
|
diffuse_tex_->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
|
||||||
diffuse_tex_->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
|
diffuse_tex_->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
|
||||||
@ -625,7 +626,7 @@ void BumpMapping::setUpDemo()
|
|||||||
// set up normal map texture
|
// set up normal map texture
|
||||||
if (!normal_tex_.valid()) {
|
if (!normal_tex_.valid()) {
|
||||||
normal_tex_ = new osg::Texture2D;
|
normal_tex_ = new osg::Texture2D;
|
||||||
normal_tex_->setImage(osgDB::readImageFile("whitemetal_normal.jpg"));
|
normal_tex_->setImage(osgDB::readImageFile("Images/whitemetal_normal.jpg"));
|
||||||
normal_tex_->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR);
|
normal_tex_->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR);
|
||||||
normal_tex_->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
|
normal_tex_->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
|
||||||
normal_tex_->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
|
normal_tex_->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
|
||||||
@ -634,7 +635,7 @@ void BumpMapping::setUpDemo()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// generate tangent-space basis vector
|
// generate tangent-space basis vector
|
||||||
prepareChild();
|
prepareChildren();
|
||||||
|
|
||||||
// recreate techniques on next step
|
// recreate techniques on next step
|
||||||
dirtyTechniques();
|
dirtyTechniques();
|
||||||
|
@ -6,10 +6,12 @@
|
|||||||
#include <osg/StateAttribute>
|
#include <osg/StateAttribute>
|
||||||
#include <osg/Geometry>
|
#include <osg/Geometry>
|
||||||
|
|
||||||
|
#include <osgUtil/CullVisitor>
|
||||||
|
|
||||||
using namespace osgFX;
|
using namespace osgFX;
|
||||||
|
|
||||||
Effect::Effect()
|
Effect::Effect()
|
||||||
: osg::Node(),
|
: osg::Group(),
|
||||||
enabled_(true),
|
enabled_(true),
|
||||||
global_sel_tech_(AUTO_DETECT),
|
global_sel_tech_(AUTO_DETECT),
|
||||||
techs_defined_(false)
|
techs_defined_(false)
|
||||||
@ -18,56 +20,59 @@ Effect::Effect()
|
|||||||
}
|
}
|
||||||
|
|
||||||
Effect::Effect(const Effect ©, const osg::CopyOp ©op)
|
Effect::Effect(const Effect ©, const osg::CopyOp ©op)
|
||||||
: osg::Node(copy, copyop),
|
: osg::Group(copy, copyop),
|
||||||
enabled_(copy.enabled_),
|
enabled_(copy.enabled_),
|
||||||
global_sel_tech_(copy.global_sel_tech_),
|
global_sel_tech_(copy.global_sel_tech_),
|
||||||
techs_defined_(false),
|
techs_defined_(false)
|
||||||
child_(static_cast<osg::Node *>(copyop(copy.child_.get())))
|
|
||||||
{
|
{
|
||||||
build_dummy_node();
|
build_dummy_node();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Effect::computeBound() const
|
Effect::~Effect()
|
||||||
{
|
{
|
||||||
_bsphere.init();
|
// disable the validator for safety, so it won't try to access us
|
||||||
_bsphere_computed = true;
|
// even if it stays alive for some reason
|
||||||
|
if (dummy_for_validation_.valid()) {
|
||||||
if (child_.valid()) {
|
osg::StateSet *ss = dummy_for_validation_->getStateSet();
|
||||||
_bsphere.expandBy(child_->getBound());
|
if (ss) {
|
||||||
}
|
Validator *validator = dynamic_cast<Validator *>(ss->getAttribute(Validator::VALIDATOR));
|
||||||
|
if (validator) {
|
||||||
return _bsphere.valid();
|
validator->disable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Effect::traverse(osg::NodeVisitor &nv)
|
void Effect::traverse(osg::NodeVisitor &nv)
|
||||||
{
|
{
|
||||||
typedef osg::Node Inherited;
|
// if this effect is not enabled, then go for default traversal
|
||||||
|
|
||||||
if (!child_.valid()) return;
|
|
||||||
|
|
||||||
// we are not a Group, so children will not notify us when their
|
|
||||||
// bounding box has changed. We need to recompute it at each traversal... :(
|
|
||||||
dirtyBound();
|
|
||||||
|
|
||||||
if (!enabled_) {
|
if (!enabled_) {
|
||||||
child_->accept(nv);
|
inherited_traverse(nv);
|
||||||
Inherited::traverse(nv);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ensure that at least one technique is defined
|
||||||
if (!techs_defined_) {
|
if (!techs_defined_) {
|
||||||
|
|
||||||
// clear existing techniques if necessary
|
// clear existing techniques
|
||||||
techs_.clear();
|
techs_.clear();
|
||||||
|
|
||||||
|
// clear technique selection indices
|
||||||
sel_tech_.clear();
|
sel_tech_.clear();
|
||||||
|
|
||||||
|
// clear technique selection flags
|
||||||
tech_selected_.clear();
|
tech_selected_.clear();
|
||||||
|
|
||||||
// define new techniques
|
// define new techniques
|
||||||
techs_defined_ = define_techniques();
|
techs_defined_ = define_techniques();
|
||||||
|
|
||||||
|
// check for errors, return on failure
|
||||||
if (!techs_defined_) {
|
if (!techs_defined_) {
|
||||||
osg::notify(osg::WARN) << "Warning: osgFX::Effect: could not define techniques for effect " << className() << std::endl;
|
osg::notify(osg::WARN) << "Warning: osgFX::Effect: could not define techniques for effect " << className() << std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ensure that at least one technique has been defined
|
||||||
if (techs_.empty()) {
|
if (techs_.empty()) {
|
||||||
osg::notify(osg::WARN) << "Warning: osgFX::Effect: no techniques defined for effect " << className() << std::endl;
|
osg::notify(osg::WARN) << "Warning: osgFX::Effect: no techniques defined for effect " << className() << std::endl;
|
||||||
return;
|
return;
|
||||||
@ -76,7 +81,11 @@ void Effect::traverse(osg::NodeVisitor &nv)
|
|||||||
|
|
||||||
Technique *tech = 0;
|
Technique *tech = 0;
|
||||||
|
|
||||||
if (global_sel_tech_ == AUTO_DETECT) {
|
// if the selection mode is set to AUTO_DETECT then we have to
|
||||||
|
// choose the active technique!
|
||||||
|
if (global_sel_tech_ == AUTO_DETECT) {
|
||||||
|
|
||||||
|
// test whether at least one technique has been selected
|
||||||
bool none_selected = true;
|
bool none_selected = true;
|
||||||
for (unsigned i=0; i<tech_selected_.size(); ++i) {
|
for (unsigned i=0; i<tech_selected_.size(); ++i) {
|
||||||
if (tech_selected_[i] != 0) {
|
if (tech_selected_[i] != 0) {
|
||||||
@ -85,11 +94,15 @@ void Effect::traverse(osg::NodeVisitor &nv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// no techniques selected, traverse a dummy node that
|
||||||
|
// contains the Validator (it will select a technique)
|
||||||
if (none_selected) {
|
if (none_selected) {
|
||||||
dummy_for_validation_->accept(nv);
|
dummy_for_validation_->accept(nv);
|
||||||
}
|
}
|
||||||
|
|
||||||
int max_index = -1;
|
// find the highest priority technique that could be validated
|
||||||
|
// in all active rendering contexts
|
||||||
|
int max_index = -1;
|
||||||
for (unsigned j=0; j<sel_tech_.size(); ++j) {
|
for (unsigned j=0; j<sel_tech_.size(); ++j) {
|
||||||
if (tech_selected_[j] != 0) {
|
if (tech_selected_[j] != 0) {
|
||||||
if (sel_tech_[j] > max_index) {
|
if (sel_tech_[j] > max_index) {
|
||||||
@ -98,26 +111,28 @@ void Effect::traverse(osg::NodeVisitor &nv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (max_index >= 0) {
|
// found a valid technique?
|
||||||
|
if (max_index >= 0) {
|
||||||
tech = techs_[max_index].get();
|
tech = techs_[max_index].get();
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
// the active technique was selected manually
|
||||||
tech = techs_[global_sel_tech_].get();
|
tech = techs_[global_sel_tech_].get();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tech) {
|
// if we could find an active technique, then continue with traversal
|
||||||
tech->accept(nv, child_.get());
|
if (tech) {
|
||||||
} else {
|
tech->traverse(nv, this);
|
||||||
child_->accept(nv);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Inherited::traverse(nv);
|
// wow, we're finished! :)
|
||||||
}
|
}
|
||||||
|
|
||||||
void Effect::build_dummy_node()
|
void Effect::build_dummy_node()
|
||||||
{
|
{
|
||||||
dummy_for_validation_ = new osg::Geode;
|
dummy_for_validation_ = new osg::Geode;
|
||||||
osg::ref_ptr<osg::Geometry> geo = new osg::Geometry;
|
osg::ref_ptr<osg::Geometry> geo = new osg::Geometry;
|
||||||
dummy_for_validation_->addDrawable(geo.get());
|
dummy_for_validation_->addDrawable(geo.get());
|
||||||
dummy_for_validation_->getOrCreateStateSet()->setAttribute(new Validator(this));
|
dummy_for_validation_->getOrCreateStateSet()->setAttribute(new Validator(this));
|
||||||
|
@ -1,30 +1,23 @@
|
|||||||
#include <osgFX/Technique>
|
#include <osgFX/Technique>
|
||||||
|
#include <osgFX/Effect>
|
||||||
|
|
||||||
#include <osg/GLExtensions>
|
#include <osg/GLExtensions>
|
||||||
|
|
||||||
|
#include <osgUtil/CullVisitor>
|
||||||
|
|
||||||
using namespace osgFX;
|
using namespace osgFX;
|
||||||
|
|
||||||
Technique::Technique()
|
Technique::Technique()
|
||||||
: osg::Referenced(),
|
: osg::Referenced()
|
||||||
passes_defined_(false),
|
|
||||||
control_node_(new osg::Group)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Technique::addPass(osg::StateSet *ss)
|
void Technique::addPass(osg::StateSet *ss)
|
||||||
{
|
{
|
||||||
osg::ref_ptr<osg::Group> pass = new osg::Group;
|
if (ss) {
|
||||||
control_node_->addChild(pass.get());
|
passes_.push_back(ss);
|
||||||
|
ss->setRenderBinDetails(static_cast<int>(passes_.size()), "RenderBin");
|
||||||
if (ss) {
|
}
|
||||||
ss->setRenderBinDetails(static_cast<int>(control_node_->getNumChildren()), "RenderBin");
|
|
||||||
pass->setStateSet(ss);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Technique::addPass(osg::Group *pass)
|
|
||||||
{
|
|
||||||
control_node_->addChild(pass);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Technique::validate(osg::State &) const
|
bool Technique::validate(osg::State &) const
|
||||||
@ -41,39 +34,36 @@ bool Technique::validate(osg::State &) const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Technique::accept(osg::NodeVisitor &nv, osg::Node *child)
|
void Technique::traverse_implementation(osg::NodeVisitor &nv, Effect *fx)
|
||||||
{
|
{
|
||||||
// define passes if necessary
|
// define passes if necessary
|
||||||
if (!passes_defined_) {
|
if (passes_.empty()) {
|
||||||
|
|
||||||
// clear existing pass nodes
|
|
||||||
if (control_node_->getNumChildren() > 0) {
|
|
||||||
control_node_->removeChild(0, control_node_->getNumChildren());
|
|
||||||
}
|
|
||||||
|
|
||||||
define_passes();
|
define_passes();
|
||||||
passes_defined_ = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// update pass children if necessary
|
// special actions must be taken if the node visitor is actually a CullVisitor
|
||||||
if (child != prev_child_.get()) {
|
osgUtil::CullVisitor *cv = dynamic_cast<osgUtil::CullVisitor *>(&nv);
|
||||||
for (unsigned i=0; i<control_node_->getNumChildren(); ++i) {
|
|
||||||
osg::Group *pass = dynamic_cast<osg::Group *>(control_node_->getChild(i));
|
|
||||||
if (pass) {
|
|
||||||
if (pass->getNumChildren() > 0) {
|
|
||||||
pass->removeChild(0, pass->getNumChildren());
|
|
||||||
}
|
|
||||||
osg::Node *oc = getOverrideChild(i);
|
|
||||||
if (oc) {
|
|
||||||
pass->addChild(oc);
|
|
||||||
} else {
|
|
||||||
pass->addChild(child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
prev_child_ = child;
|
|
||||||
}
|
|
||||||
|
|
||||||
// traverse the control node
|
// traverse all passes
|
||||||
control_node_->accept(nv);
|
for (int i=0; i<getNumPasses(); ++i) {
|
||||||
|
|
||||||
|
// push the i-th pass' StateSet if necessary
|
||||||
|
if (cv) {
|
||||||
|
cv->pushStateSet(passes_[i].get());
|
||||||
|
}
|
||||||
|
|
||||||
|
// traverse the override node if defined, otherwise
|
||||||
|
// traverse children as a Group would do
|
||||||
|
osg::Node *override = getOverrideChild(i);
|
||||||
|
if (override) {
|
||||||
|
override->accept(nv);
|
||||||
|
} else {
|
||||||
|
fx->inherited_traverse(nv);
|
||||||
|
}
|
||||||
|
|
||||||
|
// pop the StateSet if necessary
|
||||||
|
if (cv) {
|
||||||
|
cv->popStateSet();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,8 @@
|
|||||||
using namespace osgFX;
|
using namespace osgFX;
|
||||||
|
|
||||||
Validator::Validator()
|
Validator::Validator()
|
||||||
: osg::StateAttribute()
|
: osg::StateAttribute(),
|
||||||
|
effect_(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -18,13 +19,13 @@ Validator::Validator(Effect *effect)
|
|||||||
|
|
||||||
Validator::Validator(const Validator ©, const osg::CopyOp ©op)
|
Validator::Validator(const Validator ©, const osg::CopyOp ©op)
|
||||||
: osg::StateAttribute(copy, copyop),
|
: osg::StateAttribute(copy, copyop),
|
||||||
effect_(static_cast<Effect *>(copyop(copy.effect_.get())))
|
effect_(static_cast<Effect *>(copyop(copy.effect_)))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Validator::apply(osg::State &state) const
|
void Validator::apply(osg::State &state) const
|
||||||
{
|
{
|
||||||
if (!effect_.valid()) return;
|
if (!effect_) return;
|
||||||
|
|
||||||
if (effect_->tech_selected_[state.getContextID()] == 0) {
|
if (effect_->tech_selected_[state.getContextID()] == 0) {
|
||||||
Effect::Technique_list::iterator i;
|
Effect::Technique_list::iterator i;
|
||||||
|
@ -11,7 +11,7 @@ osgDB::RegisterDotOsgWrapperProxy AnisotropicLighting_Proxy
|
|||||||
(
|
(
|
||||||
new osgFX::AnisotropicLighting,
|
new osgFX::AnisotropicLighting,
|
||||||
"osgFX::AnisotropicLighting",
|
"osgFX::AnisotropicLighting",
|
||||||
"Object Node osgFX::Effect osgFX::AnisotropicLighting",
|
"Object Node Group osgFX::Effect osgFX::AnisotropicLighting",
|
||||||
AnisotropicLighting_readLocalData,
|
AnisotropicLighting_readLocalData,
|
||||||
AnisotropicLighting_writeLocalData
|
AnisotropicLighting_writeLocalData
|
||||||
);
|
);
|
||||||
|
@ -11,7 +11,7 @@ osgDB::RegisterDotOsgWrapperProxy BumpMapping_Proxy
|
|||||||
(
|
(
|
||||||
new osgFX::BumpMapping,
|
new osgFX::BumpMapping,
|
||||||
"osgFX::BumpMapping",
|
"osgFX::BumpMapping",
|
||||||
"Object Node osgFX::Effect osgFX::BumpMapping",
|
"Object Node Group osgFX::Effect osgFX::BumpMapping",
|
||||||
BumpMapping_readLocalData,
|
BumpMapping_readLocalData,
|
||||||
BumpMapping_writeLocalData
|
BumpMapping_writeLocalData
|
||||||
);
|
);
|
||||||
|
@ -11,7 +11,7 @@ osgDB::RegisterDotOsgWrapperProxy Cartoon_Proxy
|
|||||||
(
|
(
|
||||||
new osgFX::Cartoon,
|
new osgFX::Cartoon,
|
||||||
"osgFX::Cartoon",
|
"osgFX::Cartoon",
|
||||||
"Object Node osgFX::Effect osgFX::Cartoon",
|
"Object Node Group osgFX::Effect osgFX::Cartoon",
|
||||||
Cartoon_readLocalData,
|
Cartoon_readLocalData,
|
||||||
Cartoon_writeLocalData
|
Cartoon_writeLocalData
|
||||||
);
|
);
|
||||||
|
@ -11,7 +11,7 @@ osgDB::RegisterDotOsgWrapperProxy Effect_Proxy
|
|||||||
(
|
(
|
||||||
0,
|
0,
|
||||||
"osgFX::Effect",
|
"osgFX::Effect",
|
||||||
"Object Node osgFX::Effect",
|
"Object Node Group osgFX::Effect",
|
||||||
Effect_readLocalData,
|
Effect_readLocalData,
|
||||||
Effect_writeLocalData
|
Effect_writeLocalData
|
||||||
);
|
);
|
||||||
@ -46,11 +46,6 @@ bool Effect_readLocalData(osg::Object &obj, osgDB::Input &fr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::ref_ptr<osg::Node> node = static_cast<osg::Node *>(fr.readObjectOfType(osgDB::type_wrapper<osg::Node>()));
|
|
||||||
if (node.valid()) {
|
|
||||||
myobj.setChild(node.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
return itAdvanced;
|
return itAdvanced;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,7 +60,6 @@ bool Effect_writeLocalData(const osg::Object &obj, osgDB::Output &fw)
|
|||||||
} else {
|
} else {
|
||||||
fw << myobj.getSelectedTechnique() << "\n";
|
fw << myobj.getSelectedTechnique() << "\n";
|
||||||
}
|
}
|
||||||
fw.writeObject(*myobj.getChild());
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ osgDB::RegisterDotOsgWrapperProxy Scribe_Proxy
|
|||||||
(
|
(
|
||||||
new osgFX::Scribe,
|
new osgFX::Scribe,
|
||||||
"osgFX::Scribe",
|
"osgFX::Scribe",
|
||||||
"Object Node osgFX::Effect osgFX::Scribe",
|
"Object Node Group osgFX::Effect osgFX::Scribe",
|
||||||
Scribe_readLocalData,
|
Scribe_readLocalData,
|
||||||
Scribe_writeLocalData
|
Scribe_writeLocalData
|
||||||
);
|
);
|
||||||
|
@ -11,7 +11,7 @@ osgDB::RegisterDotOsgWrapperProxy SpecularHighlights_Proxy
|
|||||||
(
|
(
|
||||||
new osgFX::SpecularHighlights,
|
new osgFX::SpecularHighlights,
|
||||||
"osgFX::SpecularHighlights",
|
"osgFX::SpecularHighlights",
|
||||||
"Object Node osgFX::Effect osgFX::SpecularHighlights",
|
"Object Node Group osgFX::Effect osgFX::SpecularHighlights",
|
||||||
SpecularHighlights_readLocalData,
|
SpecularHighlights_readLocalData,
|
||||||
SpecularHighlights_writeLocalData
|
SpecularHighlights_writeLocalData
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user