//C++ header - Open Scene Graph - Copyright (C) 1998-2001 Robert Osfield
//Distributed under the terms of the GNU Library General Public License (LGPL)
//as published by the Free Software Foundation.

#ifndef OSGUTIL_STATISTICS
#define OSGUTIL_STATISTICS 1

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

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 GeoSet.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::Referenced, public osg::Drawable::AttributeFunctor
{
    public:
    
        Statistics():
            osg::Drawable::AttributeFunctor(osg::Drawable::COORDS)
        {
            reset();
        };
        
        enum PrimitiveType
        {
            NO_TYPE,
            POINTS,
            LINES,
            LINE_STRIP,
            FLAT_LINE_STRIP,
            LINE_LOOP,
            TRIANGLES,
            TRIANGLE_STRIP,
            FLAT_TRIANGLE_STRIP,
            TRIANGLE_FAN,
            FLAT_TRIANGLE_FAN,
            QUADS,
            QUAD_STRIP,
            POLYGON,
            IMPOSTOR
        };


        ~Statistics() {}; // no dynamic allocations, so no need to free
        
        enum statsType
        {
            STAT_NONE, // default
            STAT_FRAMERATE, STAT_GRAPHS,
            STAT_VIEWPARMS,  // descrbe the view parameters (FOV, near/far...)
            STAT_PRIMS, STAT_PRIMSPERVIEW, STAT_PRIMSPERBIN,
            STAT_DC,
            STAT_RESTART // hint to restart the stats
        };
        void reset()
        {
            numOpaque=0, nummat=0; depth=0; stattype=STAT_NONE;
            nprims=0, nlights=0; nbins=0; nimpostor=0;
            for (int i=0; i<=POLYGON; i++) primverts[i]=numprimtypes[i]=primlens[i]=primtypes[i]=0;
        }

        void setType(statsType t) {stattype=t;}

        virtual bool apply(osg::Drawable::AttributeBitMask abm,osg::Vec3* begin,osg::Vec3* end)
        {
            if (abm == osg::Drawable::COORDS)
            {
                primverts[0] += (end-begin);
                return true;
            }
            return false;
        }

        void addNumPrims(const int typ, const int nprimlen, const int numprimtype, const int primvert)
        {
            if (typ>NO_TYPE && typ<=POLYGON) {
                primtypes[0]++;
                primtypes[typ]++;
                numprimtypes[0]+=numprimtype;
                numprimtypes[typ]+=numprimtype;
                primlens[0]+=nprimlen;
                primlens[typ]+=nprimlen;
                //primverts[0]+=primvert;
                primverts[typ]+=primvert;
            }
        }
        
        void addOpaque() { numOpaque++;}
        void addMatrix() { nummat++;}
        void addLight(const int np) { nlights+=np;}
        void addNumPrims(const int np) { nprims += np; }
        void addImpostor(const int np) { nimpostor+= np; }
        inline const int getBins() { return nbins;}
        void setDepth(const int d) { depth=d; }
        void addBins(const int np) { nbins+= np; }

        void setBinNo(const int n) { _binNo=n;}       
                
public:
                
        int numOpaque, nummat, nbins;
        int nprims, nlights;
        int depth; // depth into bins - eg 1.1,1.2,1.3 etc
        int _binNo;
        statsType stattype;
        int nimpostor; // number of impostors rendered
        int numprimtypes[16]; // histogram of number of each type of prim
        int primtypes[16]; // histogram of number of each type of prim
        int primlens[16]; // histogram of lengths of each type of prim
        int primverts[16]; // histogram of number of vertices to be transformed
        
};

}

#endif
