/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ //osgFX - Copyright (C) 2003 Marco Jez #ifndef OSGFX_EFFECT_ #define OSGFX_EFFECT_ #include #include #include #include #include #include #include #include #include /** An helper macro that defines the methods like effectName() and effectDescription() making them return the strings passed as parameters, after the usual library name and class name. */ #define META_Effect(library, classname, effectname, effectdescription, effectauthor) \ META_Node(library, classname) \ virtual const char *effectName() const { return effectname; } \ virtual const char *effectDescription() const { return effectdescription; } \ virtual const char *effectAuthor() const { return effectauthor; } namespace osgFX { /** The base class for special effects. An effect is basically a collection of state attributes and an interface for configuring them in a predefined fashion. The Effect class does more however, as it handles multipass rendering transparently and it allows more than one "technique" to be defined. Each technique tries to implement the effect in a different way, often using different OpenGL extensions. The active technique can be selected either manually, with selectTechnique(), or automatically, in which case the first technique that is supported by all active rendering contexts is chosen. If you are an Effect user, then simply use it as a single-child group. Create an instance of your desired effect, add it to your scene graph (it is a Node) and call its setChild() method to set its child node as you would do with a Group. If you are an Effect developer, you will have to implement the method define_techniques() to define the different techniques that can be used for obtaining the desired effect. In define_techniques() you will usually create one or more instances of custom classes derived from Technique and you will add them to the effect with addTechnique(). The order is important: techniques added first will have higher priority and will be used first as soon as all rendering contexts support it. */ class OSGFX_EXPORT Effect: public osg::Node { public: Effect(); Effect(const Effect ©, const osg::CopyOp ©op = osg::CopyOp::SHALLOW_COPY); virtual inline bool isSameKindAs(const osg::Object *obj) const { return dynamic_cast(obj) != NULL; } virtual inline const char *libraryName() const { return "osgFX"; } virtual inline const char *className() const { return "Effect"; } /** get the name of this effect */ virtual const char *effectName() const = 0; /** get a brief description of this effect */ virtual const char *effectDescription() const = 0; /** get the effect author's name */ virtual const char *effectAuthor() const = 0; /** get whether the effect is enabled or not */ inline bool getEnabled() const; /** set whether the effect is enabled or not */ inline void setEnabled(bool v); /** optional: set effect parameters to produce a visually significant result to be used in demo applications like osgfxbrowser. Default is to do nothing. */ 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 */ inline int getNumTechniques() const; /** get the i-th technique */ inline Technique *getTechnique(int i); /** get the i-th const technique */ inline const Technique *getTechnique(int i) const; /** get the index of the currently selected technique */ inline int getSelectedTechnique() const; enum TechniqueSelection { AUTO_DETECT = -1 }; /** select a technique or enable automatic detection */ inline void selectTechnique(int i = AUTO_DETECT); virtual void traverse(osg::NodeVisitor &nv); protected: virtual ~Effect() {} Effect &operator=(const Effect &) { return *this; } virtual bool computeBound() const; /** force rebuilding of techniques on next traversal */ inline void dirtyTechniques(); /** add a technique to the effect */ inline void addTechnique(Technique *tech); /** abstract method to be implemented in derived classes; its purpose if to create the techniques that can be used for obtaining the desired effect. You will usually call addTechnique() inside this method. */ virtual bool define_techniques() = 0; private: friend class Validator; bool enabled_; typedef std::vector > Technique_list; Technique_list techs_; mutable osg::buffered_value sel_tech_; // use int instead of bool to avoid errors mutable osg::buffered_value tech_selected_; int global_sel_tech_; bool techs_defined_; osg::ref_ptr child_; osg::ref_ptr dummy_for_validation_; void build_dummy_node(); }; // INLINE METHODS inline bool Effect::getEnabled() const { return enabled_; } inline void Effect::setEnabled(bool 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(child)) setNumChildrenWithOccluderNodes(1); } dirtyBound(); } inline int Effect::getNumTechniques() const { return static_cast(techs_.size()); } inline Technique *Effect::getTechnique(int i) { return techs_[i].get(); } inline const Technique *Effect::getTechnique(int i) const { return techs_[i].get(); } inline int Effect::getSelectedTechnique() const { return global_sel_tech_; } inline void Effect::selectTechnique(int i) { global_sel_tech_ = i; } inline void Effect::addTechnique(Technique *tech) { techs_.push_back(tech); } inline void Effect::dirtyTechniques() { techs_defined_ = false; } } #endif