/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2005 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.
*/

#ifndef OSGUTIL_RENDERSTAGE
#define OSGUTIL_RENDERSTAGE 1

#include <osg/ColorMask>
#include <osg/Viewport>

#include <osgUtil/RenderBin>
#include <osgUtil/RenderStageLighting>

namespace osgUtil {

/**
 * RenderStage base class. Used for encapsulate a complete stage in
 * rendering - setting up of viewport, the projection and model
 * matrices and rendering the RenderBin's enclosed with this RenderStage.
 * RenderStage also has a dependency list of other RenderStages, each
 * of which must be called before the rendering of this stage.  These
 * 'pre' rendering stages are used for advanced rendering techniques
 * like multistage pixel shading or impostors.
 */
class OSGUTIL_EXPORT RenderStage : public RenderBin
{
    public:
    

        RenderStage();
        RenderStage(SortMode mode);
        
        RenderStage(const RenderStage& rhs,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY);
        
        virtual osg::Object* cloneType() const { return new RenderStage(); }
        virtual osg::Object* clone(const osg::CopyOp& copyop) const { return new RenderStage(*this,copyop); } // note only implements a clone of type.
        virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast<const RenderStage*>(obj)!=0L; }
        virtual const char* className() const { return "RenderStage"; }

        virtual void reset();
        
        
        /** Set the viewport.*/
        void setViewport(osg::Viewport* viewport) { _viewport = viewport; }

        /** Get the const viewport. */
        const osg::Viewport* getViewport() const { return _viewport.get(); }

        /** Get the viewport. */
        osg::Viewport* getViewport() { return _viewport.get(); }



        /** Set the clear mask used in glClear(..).
          * Defaults to GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT. */
        void setClearMask(GLbitfield mask) { _clearMask = mask; }

        /** Get the clear mask.*/
        GLbitfield getClearMask() const { return _clearMask; }


        void setColorMask(osg::ColorMask* cm) { _colorMask = cm; }
        osg::ColorMask* getColorMask() { return _colorMask.get(); }
        const osg::ColorMask* getColorMask() const { return _colorMask.get(); }


        /** Set the clear color used in glClearColor(..). 
          * glClearColor is only called if mask & GL_COLOR_BUFFER_BIT is true*/
        void setClearColor(const osg::Vec4& color) { _clearColor=color; }
        
        /** Get the clear color.*/
        const osg::Vec4& getClearColor() const { return _clearColor; }
        

        /** Set the clear accum used in glClearAccum(..). 
          * glClearAcumm is only called if mask & GL_ACCUM_BUFFER_BIT is true. */
        void setClearAccum(const osg::Vec4& color) { _clearAccum=color; }
        
        /** Get the clear accum.*/
        const osg::Vec4& getClearAccum() const { return _clearAccum; }
        

        
        /** Set the clear depth used in glClearDepth(..). Defaults to 1.0
          * glClearDepth is only called if mask & GL_DEPTH_BUFFER_BIT is true. */
        void setClearDepth(double depth) { _clearDepth=depth; }
        
        /** Get the clear depth.*/
        double getClearDepth() const { return _clearDepth; }

        
        /** Set the clear stencil value used in glClearStencil(). Defaults to 0;
          * glClearStencil is only called if mask & GL_STENCIL_BUFFER_BIT is true*/
        void setClearStencil(int stencil) { _clearStencil=stencil; }
        
        /** Get the clear color.*/
        int getClearStencil() const { return _clearStencil; }

        void setRenderStageLighting(RenderStageLighting* rsl) { _renderStageLighting = rsl; }

        RenderStageLighting* getRenderStageLighting() const
        {
            if (!_renderStageLighting.valid()) _renderStageLighting = new RenderStageLighting;
            return _renderStageLighting.get();
        }

        virtual void addPositionedAttribute(osg::RefMatrix* matrix,const osg::StateAttribute* attr)
        {
            getRenderStageLighting()->addPositionedAttribute(matrix,attr);
        }
        
        virtual void addPositionedTextureAttribute(unsigned int textureUnit, osg::RefMatrix* matrix,const osg::StateAttribute* attr)
        {
            getRenderStageLighting()->addPositionedTextureAttribute(textureUnit, matrix,attr);
        }

        virtual void drawPreRenderStages(osg::State& state,RenderLeaf*& previous);

        virtual void draw(osg::State& state,RenderLeaf*& previous);
    
        virtual void drawImplementation(osg::State& state,RenderLeaf*& previous);

        void addToDependencyList(RenderStage* rs);

        /** Extract stats for current draw list. */
        bool getStats(Statistics* primStats); 
        
    protected:
        
        virtual ~RenderStage();

        typedef std::vector< osg::ref_ptr<RenderStage> > DependencyList;

        bool                                _stageDrawnThisFrame;
        DependencyList                      _dependencyList;

        // viewport x,y,width,height.
        osg::ref_ptr<osg::Viewport>         _viewport;
        
        GLbitfield                          _clearMask;
        osg::ref_ptr<osg::ColorMask>        _colorMask;
        osg::Vec4                           _clearColor;
        osg::Vec4                           _clearAccum;
        double                              _clearDepth;
        int                                 _clearStencil;

        mutable osg::ref_ptr<RenderStageLighting>   _renderStageLighting;
        
    

};

}

#endif

