/*
 * Copyright (C) 1997-2009, R3vis Corporation.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * 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 GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA, or visit http://www.gnu.org/copyleft/lgpl.html.
 *
 * Original Contributor:
 *   Wes Bethel, R3vis Corporation, Marin County, California
 *   http://www.r3vis.com/
 * Additional Contributor(s):
 *
 * The OpenRM project is located at http://openrm.sourceforge.net/.
 */

/*
 * $Id: rmstats.c,v 1.7 2005/06/06 02:04:29 wes Exp $
 * Version: $Name: v180-alpha-02 $
 * $Revision: 1.7 $
 * $Log: rmstats.c,v $
 * Revision 1.7  2005/06/06 02:04:29  wes
 * Lots of small additions to clean up compiler warnings.
 *
 * Revision 1.6  2005/02/19 16:22:50  wes
 * Distro sync and consolidation.
 *
 * Revision 1.5  2005/01/23 17:00:22  wes
 * Copyright updated to 2005.
 *
 * Revision 1.4  2004/01/16 16:48:35  wes
 * Updated copyright line for 2004.
 *
 * Revision 1.3  2003/11/05 15:31:06  wes
 * Updated to use new rmTime() routines introduced in 1.5.1.
 *
 * Revision 1.2  2003/02/02 02:07:16  wes
 * Updated copyright to 2003.
 *
 * Revision 1.1.1.1  2003/01/28 02:15:23  wes
 * Manual rebuild of rm150 repository.
 *
 * Revision 1.4  2003/01/16 22:21:17  wes
 * Updated all source files to reflect new organization of header files:
 * all header files formerly located in include/rmaux, include/rmi, include/rmv
 * are now located in include/rm.
 *
 * Revision 1.3  2002/04/30 19:33:49  wes
 * Updated copyright dates.
 *
 * Revision 1.2  2001/06/03 20:50:31  wes
 * No significant differences.
 *
 * Revision 1.1  2001/03/31 17:29:14  wes
 * Initial entry.
 *
 */

#include <rm/rm.h>
#include "rmprivat.h"
#include "rmstats.h"

static RMstats ss;

void
statsNodeFunc(RMnode *n,
	      const RMstate *state,
	      void *clientData)
{
    RMstats *s = (RMstats *)clientData;
    s->nNodes += 1;

    /* in the future, we may want to use information in the RMstate */
    state = NULL; 		/* foil compiler warning */

    if (n->nprims != 0)
    {
	int i;
	s->nPrims += n->nprims;
	for (i=0;i<n->nprims;i++)
	{
	    RMprimitive *p;
	    int nverts, vstride, vveclen;
	    RMvertex3D *v=NULL;

	    p = (RMprimitive *)(n->prims[i]);

	    private_rmGetBlobData(BLOB_VERTEX_INDEX, p, &vstride, &nverts, (void **)&v, &vveclen);
	    switch (p->type)
	    {
		/* code to count up stuff depending upon prim type */
	    case RM_LINES:
		s->nVectors += (nverts/2);
		break;
	    case RM_LINE_STRIP:
		s->nVectors += (nverts - 1);
		break;
	    case RM_TRIANGLES:
		s->nTriangles += (nverts/3);
		break;
	    case RM_TRIANGLE_STRIP:
		s->nTriangles += (nverts-2);
		break;
	    case RM_TRIANGLE_FAN:
		s->nTriangles += (nverts-2);
		break;

	    case RM_QUADMESH:
		{
		    int *dims;
		    private_rmGetBlobData(BLOB_QMESHDIMS_INDEX, p, NULL, NULL, (void *)&dims, NULL);
		    s->nQuads += ((dims[0]-1) * (dims[1]-1));
		}
		break;
	    case RM_POINTS:
		s->nPoints += (nverts);
		break;

	    case RM_INDEXED_TFAN:
		break;

	    case RM_POLYS:
		break;

	    case RM_SPHERES:
		{
		    /* spheres are made from disjoint triangles */
		    int modelFlag = rmPrimitiveGetModelFlag(p);
		    if (modelFlag == RM_SPHERES_8)
			s->nTriangles += (nverts * 8);
		    else if (modelFlag == RM_SPHERES_32)
			s->nTriangles += (nverts * 32);
		    else if (modelFlag == RM_SPHERES_128)
			s->nTriangles += (nverts * 128);
		    else if (modelFlag == RM_SPHERES_512)
			s->nTriangles += (nverts * 512);
		}
		break;

	    case RM_BOX3D:
		s->nQuads = (nverts/2 * 6);
		break;

	    case RM_BOX3D_WIRE:
		break;

	    case RM_CONES:
		{
		    /* cones are built from tstrips. the bottom of the
		     cone is built from a t-fan. 2 verts per cone. */
		    
		    int modelFlag = rmPrimitiveGetModelFlag(p);
		    
		    if (modelFlag == RM_CONES_4)
			s->nTriangles += (nverts/2 * 8);
		    else if (modelFlag == RM_CONES_8)
			s->nTriangles += (nverts/2 * 16);
		    else if (modelFlag == RM_CONES_12)
			s->nTriangles += (nverts/2 * 24);
		    else if (modelFlag == RM_CONES_16)
			s->nTriangles += (nverts/2 * 32);
		    else if (modelFlag == RM_CONES_32)
			s->nTriangles += (nverts/2 * 64);
		    else if (modelFlag == RM_CONES_64)
			s->nTriangles += (nverts/2 * 128);
		    else if (modelFlag == RM_CONES_128)
			s->nTriangles += (nverts/2 * 256);
		}
		break;

	    case RM_CYLINDERS:
		{
		    /* cylinders are built from tstrips. 2 verts per cylinder*/
		    
		    int modelFlag = rmPrimitiveGetModelFlag(p);
		    
		    if (modelFlag == RM_CYLINDERS_4)
			s->nTriangles += (nverts/2 * 8);
		    else if (modelFlag == RM_CYLINDERS_8)
			s->nTriangles += (nverts/2 * 16);
		    else if (modelFlag == RM_CYLINDERS_12)
			s->nTriangles += (nverts/2 * 24);
		    else if (modelFlag == RM_CYLINDERS_16)
			s->nTriangles += (nverts/2 * 32);
		    else if (modelFlag == RM_CYLINDERS_32)
			s->nTriangles += (nverts/2 * 64);
		    else if (modelFlag == RM_CYLINDERS_64)
			s->nTriangles += (nverts/2 * 128);
		    else if (modelFlag == RM_CYLINDERS_128)
			s->nTriangles += (nverts/2 * 256);
		}
		break;

	    case RM_OCTMESH:
		break;

	    case RM_TEXT:
		break;

	    case RM_INDEXED_TEXT:
		break;

	    case RM_QUADS:
		s->nQuads += (nverts/4);
		break;

	    case RM_MARKERS2D:
		break;

	    case RM_CIRCLE2D:
		break;

	    case RM_BOX2D:
		break;

	    case RM_ELLIPSE2D:
		break;

	    case RM_SPRITE:
		break;

	    case RM_BITMAP:
		break;

	    case RM_INDEXED_BITMAP:
		break;

	    case RM_USERDEFINED_PRIM:
	    default:
		break;
	    }
	}
    }
}

RMenum
rmStatsComputeDemography (RMnode *r)
{
    memset(&ss, 0,sizeof(RMstats));
    
    /* count things in scene graph */
    rmSceneGraphWalk(NULL, r, statsNodeFunc, (void *)&ss);
    return(RM_CHILL);
}

RMenum
rmStatsStartTime(void)
{
    /* initialize time entries in static RMstats structure */
    rmTimeCurrent(&ss.renderStageTime[0]);
    return(RM_CHILL);
}

RMenum
rmStatsEndTime(void)
{
    /* make sure all rendering has been completed. note that glFinish()
       will block execution until all rendering has been complete. It is
       an expensive operation that will slow down applications. Use calls
       to rmStatsEndTime sparingly!! */
/*    glFinish(); */
    
    /* get end times */
    rmTimeCurrent(&ss.renderStageTime[1]);
    return(RM_CHILL);
}

RMenum
rmStatsPrint(void)
{
    char buf1[256], buf2[256];
    float msec;

    memset(buf1,0,256);
    memset(buf2,0,256);

#if 0
    printf(" rmStatsPrint start=(%ld,%ld) end=(%ld,%ld) \n",ss.renderStageTime[0].sec, ss.renderStageTime[0].usec, ss.renderStageTime[1].sec, ss.renderStageTime[1].usec);
#endif

    msec = rmTimeDifferenceMS(&(ss.renderStageTime[0]), &(ss.renderStageTime[1]));
    
    /* print count of scene graph demography */
    sprintf(buf1,"nodes\tprims\ttris\tquads\tvectors\ttex\tpbytes\tnpoints\ttime(ms)\n");
    sprintf(buf2,"%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%g\n",ss.nNodes, ss.nPrims, ss.nTriangles, ss.nQuads, ss.nVectors, ss.nTextures, ss.nPixelBytes, ss.nPoints, msec);
    /* print elapsed time */
    fprintf(stderr,"%s", buf1);
    fprintf(stderr,"%s", buf2);
    return(RM_CHILL);
}

/* EOF */
