#pragma ident "@(#)cgputil.c	1.7 98/09/28 SMI"

/*
 * Copyright (c) 1997 by Sun Microsystems, Inc.
 * All Rights Reserved
 */


/******************************************************************************
 * cgputil.c
 *
 * This file contains all the compressed geometry utility routines.
 *
 *  List of functions in this file:
 *      cgpUtilPrintApiBuff
 *	cgpUtilRenderApiBuff
 *	cgpUtilPrimStats
 *
 *****************************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <GL/gl.h>

#include "cgpi.h"

extern CGPprimlist	*Prims;


/*******************
 * cgpUtilPrintApiBuff
 *
 *  Utility routine to print out the buffers generated from
 *  the user's API calls.
 *
 *  Input:
 *    CGPprimlist*  prims - pointer to the primList structure holding the data
 *                       obtained from the user.
 *
 *  Output:
 *    Prints to stderr all data in the primList structure.
 */
void
cgpUtilPrintApiBuff(CGPprimlist *prims)
{
    CGPprimlist*   primlist;
    CGPprimitive*  curPrim;
    CGPptbuffer*   curPtBuff;
    CGPpoint*    curPt;
    CGuint      i, j;

    fprintf(stderr, "\n\n**** cgPrintApiBuff ****\n\n");

    primlist = prims;
    while (primlist != NULL)
    {
        curPrim = &primlist->primitive;

        fprintf(stderr, "\n\nPrimitive Type (%x): ", curPrim->primType);
        switch (curPrim->primType)
        {
            case CG_TRIANGLES:
                fprintf(stderr, "CG_TRIANGLES\n");
                break;

            case CG_TRIANGLE_STRIP:
                fprintf(stderr, "CG_TRIANGLE_STRIP\n");
                break;

            case CG_TRIANGLE_FAN:
                fprintf(stderr, "CG_TRIANGLE_FAN\n");
                break;

            case CG_QUADS:
                fprintf(stderr, "CG_QUADS\n");
                break;

            case CG_QUAD_STRIP:
                fprintf(stderr, "CG_QUAD_STRIP\n");
                break;

            case CG_POLYGON:
                fprintf(stderr, "CG_POLYGON\n");
                break;

            default:
                fprintf(stderr, " ** UNKNOWN **\n");
        }

        fprintf(stderr, "\nFront Face: ");
        if (curPrim->primFlags & CGP_FRONT_FACE_CW)
            fprintf(stderr, "CW\n");
        else
            fprintf(stderr, "CCW\n");

        fprintf(stderr, "\nGlobal Normal:\n");
        if (curPrim->primFlags & CGP_GLOBAL_NORMAL_VALID)
        {
            fprintf(stderr, "  X: %f\n", curPrim->globalNormalX);
            fprintf(stderr, "  Y: %f\n", curPrim->globalNormalY);
            fprintf(stderr, "  Z: %f\n", curPrim->globalNormalZ);
        }
        else
            fprintf(stderr, "  Not Valid\n");

        fprintf(stderr, "\nGlobal Color:\n");
        if (curPrim->primFlags & CGP_GLOBAL_COLOR_VALID)
        {
            fprintf(stderr, "  Red:   %f\n", curPrim->globalColorR);
            fprintf(stderr, "  Green: %f\n", curPrim->globalColorG);
            fprintf(stderr, "  Blue:  %f\n", curPrim->globalColorB);

            if (curPrim->primFlags & CGP_GLOBAL_ALPHA_VALID)
                fprintf(stderr, "  Alpha: %f\n", curPrim->globalAlpha);
        }
        else
            fprintf(stderr, "  Not Valid\n");

        fprintf(stderr, "\nPoint Type (%x): ", curPrim->primFlags & 0x7);
        if (curPrim->primFlags & CGP_PT_TYPE_VTX_NORMAL)
            fprintf(stderr, "Normal ");
        if (curPrim->primFlags & CGP_PT_TYPE_VTX_COLOR)
            fprintf(stderr, "Color ");
        if (curPrim->primFlags & CGP_PT_TYPE_VTX_COLOR_ALPHA)
            fprintf(stderr, "Alpha ");
        fprintf(stderr, "Vertex3d\n");

        curPtBuff = &curPrim->ptBuff;
        curPt = &curPtBuff->pts[0];
        fprintf(stderr, "\n Number of Points: %d\n", curPrim->numPts);

        /* use i = 1 so points are numbered correctly */
        for (j = 0, i = 1; i <= curPrim->numPts; i++)
        {
            fprintf(stderr, "  %d:\n", i);

            if (curPrim->primFlags & CGP_PT_TYPE_VTX_NORMAL)
                fprintf(stderr, "\tNormal:\t%f\t%f\t%f\n",
                        curPt->nX, curPt->nY, curPt->nZ);

            if (curPrim->primFlags & CGP_PT_TYPE_VTX_COLOR)
            {
                fprintf(stderr, "\tColor:\t%f\t%f\t%f",
                        curPt->r, curPt->g, curPt->b);

                if (curPrim->primFlags & CGP_PT_TYPE_VTX_COLOR_ALPHA)
                    fprintf(stderr, "\t%f", curPt->a);

                fprintf(stderr, "\n");
            }

            /* do we have header info (only if data has been through the */
            /*  mesher.                                                  */
            if (curPt->header != 0)
            {
                CGuint hdr = curPt->header;

                fprintf(stderr, "\tHdr:\t");

                /* check restart bits */
                if (hdr & CGP_POINT_HDR_RESTART_CW)
                    fprintf(stderr, "RESTART_CW");
                if (hdr & CGP_POINT_HDR_RESTART_CCW)
                    fprintf(stderr, "RESTART_CCW");
                if (hdr & CGP_POINT_HDR_REPLACE_MIDDLE)
                    fprintf(stderr, "REPLACE_MIDDLE");
                if (hdr & CGP_POINT_HDR_REPLACE_OLDEST)
                    fprintf(stderr, "REPLACE_OLDEST");

                /* check mesh buffer push bits */
                if (hdr & CGP_POINT_HDR_PUSH)
                    fprintf(stderr, ", PUSH");
                if (hdr & CGP_POINT_HDR_REF)
                    fprintf(stderr, ", REF: %d",
                      CGP_GET_POINT_HDR_REF_NUMBER(hdr));

                fprintf(stderr, "\n");
            }

            fprintf(stderr, "\tGeom:\t%f\t%f\t%f\n",
                    curPt->x, curPt->y, curPt->z);

            /* see if points continue onto next ptBuffer structure */
            /* TODO: rename j */
            if (++j == CGP_PT_BUFFER_SIZE)
            {
                 curPtBuff = curPtBuff->nextPtBuffer;
                 curPt = &curPtBuff->pts[0];
                 j = 0;
             }
             else
                 curPt++;
        }

        primlist = primlist->nextPrimitive;

    }  /* while (curPrim != NULL) */
}

/*******************
 * cgpUtilRenderApiBuff
 *
 *  Utility routine to render the buffers generated from
 *  the user's API calls using BP calls (these may be displayed or put into
 *  a display list depending on the OGL state)
 *
 *  Input:
 *    CGPprimlist*  prims - pointer to the primList structure holding the data
 *                       obtained from the user.
 *
 *  Output:
 *    None (OGL calls are made for each prim)
 */
void
cgpUtilRenderApiBuff()
{
    CGPprimlist*   primlist;
    CGPprimitive*  curPrim;
    CGPptbuffer*   curPtBuff;
    CGPpoint*    curPt;
    CGuint      i, j;


    primlist = Prims;
    while (primlist != NULL)
    {
        curPrim = &primlist->primitive;

	/* TODO: Does this translate into any GL calls? 
        fprintf(stderr, "\nFront Face: ");
        if (curPrim->primFlags & CGP_FRONT_FACE_CW)
            fprintf(stderr, "CW\n");
        else
            fprintf(stderr, "CCW\n");
	*/

        if (curPrim->primFlags & CGP_GLOBAL_NORMAL_VALID) {
	    glNormal3f(curPrim->globalNormalX, curPrim->globalNormalY,
		curPrim->globalNormalZ);
        }

        if (curPrim->primFlags & CGP_GLOBAL_COLOR_VALID) {
            if (curPrim->primFlags & CGP_GLOBAL_ALPHA_VALID) {
		glColor4f(curPrim->globalColorR, curPrim->globalColorG,
		    curPrim->globalColorB, curPrim->globalAlpha);
	    } else {
		glColor3f(curPrim->globalColorR, curPrim->globalColorG,
		    curPrim->globalColorB);
	    }
        }

        switch (curPrim->primType) {
	  case CG_TRIANGLES:
	    glBegin(GL_TRIANGLES);
	    break;
	  case CG_TRIANGLE_STRIP:
	    glBegin(GL_TRIANGLE_STRIP);
	    break;
	  case CG_TRIANGLE_FAN:
	    glBegin(GL_TRIANGLE_FAN);
	    break;
	  case CG_QUADS:
	    glBegin(GL_QUADS);
	    break;
	  case CG_QUAD_STRIP:
	    glBegin(GL_QUAD_STRIP);
	    break;
	  case CG_POLYGON:
	    glBegin(GL_POLYGON);
	    break;
	  default:
	    fprintf(stderr, "Unknown primitive type in cgpUtilRenderApiBuff\n");
	    exit(1);
        }


        curPtBuff = &curPrim->ptBuff;
        curPt = &curPtBuff->pts[0];

        for (i = 0, j = 0; i < curPrim->numPts; i++) {
            if (curPrim->primFlags & CGP_PT_TYPE_VTX_NORMAL) {
	       glNormal3f(curPt->nX, curPt->nY, curPt->nZ);
	    }

            if (curPrim->primFlags & CGP_PT_TYPE_VTX_COLOR) {
                if (curPrim->primFlags & CGP_PT_TYPE_VTX_COLOR_ALPHA) {
                   glColor4f(curPt->r, curPt->g, curPt->b, curPt->a);
		} else {
                   glColor3f(curPt->r, curPt->g, curPt->b);
		}
            }

            glVertex3f(curPt->x, curPt->y, curPt->z);

            /* see if points continue onto next ptBuffer structure */
            if (++j == CGP_PT_BUFFER_SIZE) {
                 curPtBuff = curPtBuff->nextPtBuffer;
                 curPt = &curPtBuff->pts[0];
                 j = 0;
            } else {
                 curPt++;
	    }
        }

	glEnd();

        primlist = primlist->nextPrimitive;

    }  /* while (curPrim != NULL) */
}

/*******************
 * cgpUtilPrimStats
 *
 *  Utility routine to compute stats about the primitives from
 *  the user's API calls.
 *
 *  Input/Output:
 *    Pointers to variables to hold the number of prims, number of vertices,
 *    and total vertex size.
 */
void
cgUtilPrimStats(CGint *numPrims, CGint *numVtx, CGint *vtxSize)
{
    CGPprimlist*   primlist;
    CGPprimitive*  curPrim;
    CGPptbuffer*   curPtBuff;
    CGPpoint*    curPt;
    CGuint      i, j;
    int		curPtSize;

    *numPrims = 0;
    *numVtx = 0;
    *vtxSize = 0;

    primlist = Prims;
    while (primlist != NULL)
    {
        curPrim = &primlist->primitive;

	(*numPrims)++;

	curPtSize = 12; /* coords */
        if (curPrim->primFlags & CGP_PT_TYPE_VTX_NORMAL)
            curPtSize += 12; 
        if (curPrim->primFlags & CGP_PT_TYPE_VTX_COLOR)
            curPtSize += 12; 
        if (curPrim->primFlags & CGP_PT_TYPE_VTX_COLOR_ALPHA)
            curPtSize += 16; 

        curPtBuff = &curPrim->ptBuff;
        curPt = &curPtBuff->pts[0];
	*numVtx += curPrim->numPts;
	*vtxSize += curPrim->numPts * curPtSize;

        primlist = primlist->nextPrimitive;

    }  /* while (curPrim != NULL) */
}
