/* -*-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.
*/

#ifndef OSGUTIL_STATISTICS
#define OSGUTIL_STATISTICS 1

#include <osg/Referenced>
#include <osg/Drawable>

#include <map>

namespace osg {

/**
 * Statistics base class. Used to extract primitive information from 
 * the renderBin(s).  Add a case of getStats(osgUtil::Statistics *stat)
 * for any new drawable (or drawable derived class) that you generate 
 * (eg see Geometry.cpp).  There are 20 types of drawable counted - actually only
 * 14 cases can occur in reality.  these represent sets of GL_POINTS, GL_LINES
 * GL_LINESTRIPS, LOOPS, TRIANGLES, TRI-fans, tristrips, quads, quadstrips etc
 * The number of triangles rendered is inferred:
 * each triangle = 1 triangle (number of vertices/3)
 * each quad = 2 triangles (nverts/2)
 * each trifan or tristrip = (length-2) triangles and so on.
 */

class Statistics : public osg::Drawable::PrimitiveFunctor{
    public:

        typedef std::pair<unsigned int,unsigned int>    PrimitivePair;
        typedef std::map<GLenum,PrimitivePair>          PrimtiveValueMap;


        Statistics()
        {
            reset();
        };

        enum statsType
        {
            STAT_NONE, // default
            STAT_FRAMERATE, 
            STAT_GRAPHS,
            STAT_PRIMS, 
            STAT_PRIMSPERVIEW, 
            STAT_PRIMSPERBIN,
            STAT_DC,
            STAT_RESTART // hint to restart the stats
        };
        
        void reset()
        {
            numDrawables=0, nummat=0; depth=0; stattype=STAT_NONE;
            nlights=0; nbins=0; nimpostor=0;
            
            _vertexCount=0;
            _primitiveCount.clear();            
            
            _currentPrimtiveFunctorMode=0;
        }

        void setType(statsType t) {stattype=t;}
        
        virtual void setVertexArray(unsigned int count,const Vec3*) { _vertexCount += count; }

        virtual void drawArrays(GLenum mode,GLint,GLsizei count) { PrimitivePair& prim = _primitiveCount[mode]; ++prim.first; prim.second+=count; } 
        virtual void drawElements(GLenum mode,GLsizei count,const GLubyte*) { PrimitivePair& prim = _primitiveCount[mode]; ++prim.first; prim.second+=count; } 
        virtual void drawElements(GLenum mode,GLsizei count,const GLushort*) { PrimitivePair& prim = _primitiveCount[mode]; ++prim.first; prim.second+=count; } 
        virtual void drawElements(GLenum mode,GLsizei count,const GLuint*) { PrimitivePair& prim = _primitiveCount[mode]; ++prim.first; prim.second+=count; } 

        virtual void begin(GLenum mode) { _currentPrimtiveFunctorMode=mode; PrimitivePair& prim = _primitiveCount[mode]; ++prim.first; }
        virtual void vertex(const Vec3&) { PrimitivePair& prim = _primitiveCount[_currentPrimtiveFunctorMode]; ++prim.second; }
        virtual void vertex(float,float,float) {  PrimitivePair& prim = _primitiveCount[_currentPrimtiveFunctorMode]; ++prim.second; }
        virtual void end() {}
        
        void addDrawable() { numDrawables++;}
        void addMatrix() { nummat++;}
        void addLight(int np) { nlights+=np;}
        void addImpostor(int np) { nimpostor+= np; }
        inline int getBins() { return nbins;}
        void setDepth(int d) { depth=d; }
        void addBins(int np) { nbins+= np; }

        void setBinNo(int n) { _binNo=n;}       
                
    public:
                
        int numDrawables, nummat, nbins;
        int nlights;
        int depth; // depth into bins - eg 1.1,1.2,1.3 etc
        int _binNo;
        statsType stattype;
        int nimpostor; // number of impostors rendered
        
        unsigned int        _vertexCount;
        PrimtiveValueMap    _primitiveCount;
        GLenum              _currentPrimtiveFunctorMode;
        

};

}

#endif
