/*
 * 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: rmdraw1.c,v 1.17 2005/06/26 16:28:49 wes Exp $
 * Version: $Name: v180-alpha-02 $
 * $Revision: 1.17 $
 * $Log: rmdraw1.c,v $
 * Revision 1.17  2005/06/26 16:28:49  wes
 * Repaired buglet in rmTrianglesDisjoint to accommodate per-face colors or norms.
 *
 * Revision 1.16  2005/06/12 21:48:44  wes
 * Minor tweaks to avoid compiler warnings.
 *
 * Revision 1.15  2005/06/06 02:04:29  wes
 * Lots of small additions to clean up compiler warnings.
 *
 * Revision 1.14  2005/05/16 01:01:37  wes
 * Update some primitive draw routines to use private_rmSetGLTexCoordFunc
 * to obtain the correct OpenGL texture coordinate function.
 *
 * Revision 1.13  2005/05/07 15:39:49  wes
 * To the rmLinesDisjoint draw code: (1) add support for texture coords,
 * (2) add support for normals, (3) refactor code to be cleaner about
 * handling the case where there is per-segment data, (4) general code
 * clean-up.
 *
 * Revision 1.12  2005/05/06 16:34:40  wes
 * Minor code cleanup in rmLineStrip draw code. rmLineStrip only supports
 * per-vertex everything.
 *
 * Revision 1.11  2005/05/06 15:43:46  wes
 * Add support for normals data in linestrip primitives.
 *
 * Revision 1.10  2005/02/19 16:23:56  wes
 * Distro sync and consolidation.
 * Added support for multitexturing.
 *
 * Revision 1.9  2005/02/12 00:54:50  wes
 * Preliminary multitexturing support for RMprimitives: qmesh, quads, tstrip,
 * triangles, and indexed triangles.
 *
 * Revision 1.8  2005/01/23 17:00:22  wes
 * Copyright updated to 2005.
 *
 * Revision 1.7  2004/09/28 00:44:07  wes
 * Modified rmQuads to support per-face colors and/or normals. When per-face
 * data is present, we don't use vertex arrays.
 *
 * Revision 1.6  2004/04/09 14:48:03  wes
 * Fix some compile warnings about unused variables.
 *
 * Revision 1.5  2004/02/23 03:04:32  wes
 * New primitives: RM_QUAD_STRIP, RM_INDEXED_TRIANGLES, RM_INDEXED_QUADS,
 * RM_INDEXED_TRIANGLE_STRIP.
 *
 * Revision 1.4  2004/01/16 16:44:05  wes
 * Updated copyright line for 2004.
 *
 * Revision 1.3  2003/07/20 14:44:09  wes
 * Enabled per-line color data in rmLinesDisjoint rendering function.
 *
 * Revision 1.2  2003/02/02 02:07:15  wes
 * Updated copyright to 2003.
 *
 * Revision 1.1.1.1  2003/01/28 02:15:23  wes
 * Manual rebuild of rm150 repository.
 *
 * Revision 1.14  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.13  2002/06/02 15:14:18  wes
 *
 * Added RMstateCache code to help eliminate the number of state changes
 * made during the render traversal. The RMstateCache tracks
 * the actual OpenGL rendering state w/o the need for querying OpenGL
 * directly, and  is queried by draw code that then decides if any
 * real state changes are required given the configuration of data
 * within an RMprimitive.
 *
 * Revision 1.12  2002/04/30 19:29:18  wes
 * Updated copyright dates.
 *
 * Revision 1.11  2001/03/31 17:12:38  wes
 * v1.4.0-alpha-2 checkin.
 *
 * Revision 1.10  2000/12/03 22:34:37  wes
 * Mods for thread safety- RMpipe added as parm to display list
 * calls.
 *
 * Revision 1.9  2000/08/31 02:06:57  wes
 * No significant changes.
 *
 * Revision 1.8  2000/08/28 01:36:18  wes
 * In rmLinesDisjoint, ifdef'ed out the display list code. On some
 * platforms (nVidia 0.9-4 drivers, to be specific), there appear
 * to be some combinations of render state changes combined with
 * vertex arrays that cause the driver to barf when encapsulated
 * into an OpenGL display list.
 *
 * Revision 1.7  2000/08/23 23:24:20  wes
 * DO_LISTS define moved from rmogl.c to rmprivat.h. All display
 * list code removed from rmBitmap (will be reinserted later).
 *
 * Revision 1.6  2000/08/19 14:58:28  wes
 * Culled unused code.
 *
 * Revision 1.5  2000/05/17 14:22:06  wes
 * Added rmPolys draw routine (thanks to Matt & Todd from VRCO).
 *
 * Revision 1.4  2000/04/27 03:13:34  wes
 * rmPoints state management tweaks.
 *
 * Revision 1.3  2000/04/20 16:29:47  wes
 * Documentation additions/enhancements, some code rearragement.
 *
 * Revision 1.2  2000/02/29 23:43:53  wes
 * Compile warning cleanups.
 *
 * Revision 1.1.1.1  2000/02/28 21:29:40  wes
 * OpenRM 1.2 Checkin
 *
 * Revision 1.1.1.1  2000/02/28 17:18:48  wes
 * Initial entry - pre-RM120 release, source base for OpenRM 1.2.
 *
 */

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


/*
 * this file contains RMprimitive "draw" routines for those
 * primitives that easily map to OpenGL vertex arrays.
 */

/*#define Z_ADJUST_VALUE .0005F */
#define Z_ADJUST_VALUE 0.0F

static float lzadjust;

/* macros */
#define LINE_Z_ADJUST_BEGIN(a) \
{ \
    lzadjust = ((a) == 2) ? (-1.0 * Z_ADJUST_VALUE) : Z_ADJUST_VALUE; \
    glMatrixMode(GL_PROJECTION); \
    glTranslatef(0.0F, 0.0F, ((s->focal_length) * lzadjust)); \
    glMatrixMode(GL_MODELVIEW); \
}

#define LINE_Z_ADJUST_END() \
{ \
    glMatrixMode(GL_PROJECTION); \
    glTranslatef(0.0F, 0.0, (-1.0 * (s->focal_length) * lzadjust)); \
    glMatrixMode(GL_MODELVIEW); \
}

/* PRIVATE */
void
private_rmGetBlobData (int tag,
		       RMprimitive *p,
		       int *stride,
		       int *nverts,
		       void **data,
		       int *veclen)
{
    RMprimitiveDataBlob *blob;
    void *blobData;

    blob = private_rmBlobFromIndex(p, tag);
    blobData = (void *)private_rmBlobGetData(blob);

    if (blobData != NULL)
    {
	if (stride != NULL)
	    *stride = private_rmBlobGetStride(blob) / sizeof(float);
	if (nverts != NULL)
	    *nverts = private_rmBlobGetNthings(blob);
	if (veclen != NULL)
	    *veclen = private_rmBlobGetVeclen(blob);
	if (data != NULL)
	    *data = blobData;
    }
    else
    {
	if (stride != NULL)
	    *stride = 0;
	
	if (nverts != NULL)
	    *nverts = 0;

	if (veclen != NULL)
	    *veclen = 0;

	if (data != NULL)
	    *data = NULL;
    }
}


/* PRIVATE */
void
private_rmEnableVertexArrays (int verts,
			      int colors,
			      int normals,
			      int textureCoords,
			      int indices,
			      int edgeFlags)
{
    if (verts != 0)
	glEnableClientState(GL_VERTEX_ARRAY);
    else
	glDisableClientState(GL_VERTEX_ARRAY);
    
    if (colors != 0)
	glEnableClientState(GL_COLOR_ARRAY);
    else
	glDisableClientState(GL_COLOR_ARRAY);
    
    if (normals != 0)
	glEnableClientState(GL_NORMAL_ARRAY);
    else
	glDisableClientState(GL_NORMAL_ARRAY);
    
    if (textureCoords != 0)
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    else
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    
    if (indices != 0)
	glEnableClientState(GL_INDEX_ARRAY);
    else
	glDisableClientState(GL_INDEX_ARRAY);
	
    if (edgeFlags != 0)
	glEnableClientState(GL_EDGE_FLAG_ARRAY);
    else
	glDisableClientState(GL_EDGE_FLAG_ARRAY);
}


/* PRIVATE */
void
rmLineStrip OGLPRIMPARMLIST()
{
    /*
     * for linestrip primitives, we enforce per-vertex data.
     */
    int dataError=0;

    /* for verts */
    int    vstride, nverts, vveclen;
    float *v;

    /* color data */
    float *c=NULL;
    int cstride, ncolors, cveclen;

    /* normals */
    int nstride, nnormals, nveclen;
    float *n=NULL;

    /* texture coord data */
    float *tc=NULL;
    int tcstride;
    int ntc,tcveclen;
    
    int listStat=1;

    private_colorMaterialStateManip(p, s, rsc);
    private_lightingStateManip(p, s, rsc, RM_FALSE);
    
    if (s->rendermode != GL_FEEDBACK)
    {
	listStat = private_rmPrimitiveDisplayListBegin(renderPipe, p);
	if (listStat == 0)
	    return;
    }
    else
    {
	listStat = 0;
	r = NULL; 		/* foil compiler warning */
    }

    /* get vertex data */
    private_rmGetBlobData(BLOB_VERTEX_INDEX, p, &vstride, &nverts, (void **)&v, &vveclen);

    /* get color data */
    private_rmGetBlobData(BLOB_COLOR_INDEX, p, &cstride, &ncolors, (void **)&c, &cveclen);
    if ((ncolors != 0) && (ncolors != nverts))
    {
	rmWarning("rmLineStrip error: your RM_LINES primitive contains color data, but the number of color data values that is not equal to the number of geometric vertices. This primitive will not be rendered. ");
	dataError = 1;
    }

    /* get normals info */
    private_rmGetBlobData(BLOB_NORMAL_INDEX, p, &nstride, &nnormals, (void **)&n, &nveclen);
    if ((nnormals != 0) && (nnormals != nverts))
    {
	rmWarning("rmLineStrip error: your RM_LINES primitive contains normals data, but the number of normals data values that is not equal to the number of geometric vertices. This primitive will not be rendered. ");
	dataError = 1;
    }

    /* get texture coord data */
    private_rmGetBlobData(BLOB_TC_INDEX, p, &tcstride, &ntc, (void **)&tc, &tcveclen);
    if ((ntc != 0) && (ntc != nverts))
    {
	rmWarning("rmLineStrip error: your RM_LINES primitive contains texture coordinates data, but the number of texture coordinate data values that is not equal to the number of geometric vertices. This primitive will not be rendered. ");
	dataError = 1;
    }


    /* for now, use different loops depending upon color layout. we may
     want to do something more sophisticated later on...*/

    LINE_Z_ADJUST_BEGIN(vveclen);

    if (dataError == 0) /* assume per-vertex everything */
    {
	/* when we have per-vertex everything, then use vertex arrays */
	private_rmEnableVertexArrays(nverts, ncolors, nnormals, ntc, 0, 0);

	glVertexPointer(vveclen, GL_FLOAT, (sizeof(float) * vstride), (const GLvoid *)v);
	if (ncolors != 0)
	    glColorPointer(cveclen, GL_FLOAT, sizeof(float) * cstride, (const GLvoid *)c);

	if (nnormals != 0)
	    glNormalPointer(GL_FLOAT, sizeof(float)*nstride, (const GLvoid *)n);
	if (ntc != 0)
	    glTexCoordPointer(tcveclen, GL_FLOAT, sizeof(float) * tcstride, (const GLvoid *)tc);
	
	glDrawArrays(GL_LINE_STRIP, 0, nverts);
    }
    
    LINE_Z_ADJUST_END();

    private_rmPrimitiveDisplayListEnd(renderPipe, p, listStat);

}


/* PRIVATE */
void
rmLinesDisjoint OGLPRIMPARMLIST()
{
    int i;

    /* for verts */
    float *v;
    int vstride=0, nverts=0, vveclen=0;

    /* color data */
    float *c=NULL;
    int cstride=0, ncolors=0, cveclen=0;
    int perVertexColors=1;

    /* normals */
    int nstride=0, nnormals=0, nveclen=0;
    int perVertexNormals=1;
    float *n=NULL;

    /* texture coord data */
    float *tc=NULL;
    int tcstride=0;
    int ntc=0,tcveclen=0;
    int perVertexTCs=1;

    int perVertexData=1;
    
    int listStat=0;

    private_colorMaterialStateManip(p, s, rsc);  
    private_lightingStateManip(p, s, rsc, RM_FALSE); 

    if (s->rendermode != GL_FEEDBACK)
    {
	listStat = private_rmPrimitiveDisplayListBegin(renderPipe,p);
	if (listStat == 0)
	    return;
    }
    else
    {
	r = NULL; 		/* foil compiler warning */
	listStat = 0;
    }

    /* get vertex data */
    private_rmGetBlobData(BLOB_VERTEX_INDEX, p, &vstride, &nverts, (void **)&v, &vveclen);

    /* get color data */
    private_rmGetBlobData(BLOB_COLOR_INDEX, p, &cstride, &ncolors, (void **)&c, &cveclen);
    if ((ncolors != 0) && (ncolors != nverts))
    {
	perVertexData = 0;
	perVertexColors = 0;
    }

    /* get texture coord data */
    private_rmGetBlobData(BLOB_TC_INDEX, p, &tcstride, &ntc, (void **)&tc, &tcveclen);
    if ((ntc != 0) && (ntc != nverts))
    {
	perVertexData = 0;
	perVertexTCs = 0;
    }

    /* get normals info */
    private_rmGetBlobData(BLOB_NORMAL_INDEX, p, &nstride, &nnormals, (void **)&n, &nveclen);
    if ((nnormals != 0) && (nnormals != nverts))
    {
	perVertexData = 0;
	perVertexNormals = 0;
    }

    /* for now, use different loops depending upon color layout. we may
     want to do something more sophisticated later on...*/

    i = vveclen;
    LINE_Z_ADJUST_BEGIN(i);

    /*
     * we don't want to use display listing if we're in feedback
     * mode (PS generation) because we generate additional tokens
     * for PS that say something about linestyle & width.
     */

    if (perVertexData == 1) 	/* have per-vertex everything */
    {
	/* when we have per-vertex everything, then use vertex arrays. */
	private_rmEnableVertexArrays(nverts, ncolors, nnormals, ntc, 0, 0);

	glVertexPointer(vveclen, GL_FLOAT, sizeof(float) * vstride, (const GLvoid *)v);
	if (ncolors != 0)
	    glColorPointer(cveclen, GL_FLOAT, sizeof(float) * cstride, (const GLvoid *)c);

	if (nnormals != 0)
	    glNormalPointer(GL_FLOAT, sizeof(float)*nstride, (const GLvoid *)n);
	if (ntc != 0)
	    glTexCoordPointer(tcveclen, GL_FLOAT, sizeof(float) * tcstride, (const GLvoid *)tc);
	
	glDrawArrays(GL_LINES, 0, nverts);
    }
    else /* assume per-segment data for one or more data items */
    {
	void (*vertexfunc)(const float *);
	void (*colorfunc)(const float *);
	void (*normalfunc)(const float *); 
	void (*tcfunc)(const float *); 

	if (nnormals != 0)
	    normalfunc = rmglNormal3fv;
	else
	    normalfunc = glNoOp;
	
	if (vveclen == 3)
	    vertexfunc = rmglVertex3fv;
	else
	    vertexfunc = rmglVertex2fv;

	if (ncolors == 0)
	    colorfunc = glNoOp;
	else
	    private_rmSetGLColorFunc(cveclen, ncolors, &colorfunc);

	if (ntc == 0)
	    tcfunc = glNoOp;
	else
	    private_rmSetGLTexCoordFunc(tcveclen, ntc, &tcfunc);
	
        glBegin(GL_LINES);
	for (i = 0; i < (nverts / 2); i++, v += vstride, c += cstride, tc += tcstride, n += nstride)
	{
	    /* do the first segment vertex */
	    (*colorfunc)(c);
	    (*tcfunc)(tc);
	    (*normalfunc)(n);
	    (*vertexfunc)(v);

	    v += vstride;

	    /* do the second segment vertex */
	    if ((c != NULL) && (perVertexColors == 1))
	    {
		c += cstride;
		(*colorfunc)(c);
	    }

	    if ((tc != NULL) && (perVertexTCs == 1))
	    {
		tc += tcstride;
		(*tcfunc)(tc);
	    }
	    
	    if ((n != NULL) && (perVertexNormals == 1))
	    {
		n += nstride;
		(*normalfunc)(n);
	    }
	    
	    (*vertexfunc)(v);
	}
	glEnd();

    }

    LINE_Z_ADJUST_END();

    private_rmPrimitiveDisplayListEnd(renderPipe, p, listStat);
    
}


/* PRIVATE */
void
rmPoints OGLPRIMPARMLIST()
{
    /* for verts */
    float *v;
    int    vstride, nverts, vveclen;

    /* color data */
    float *c = NULL;
    int    cstride, ncolors, cveclen;

    /* texture coord data */
    float *tc = NULL;
    int    tcstride;
    int    ntc, tcveclen;

    /* normals */
    float *n;
    int    nstride, nveclen, nnormals;
    
    int listStat;

    private_colorMaterialStateManip(p, s, rsc);
    private_lightingStateManip(p, s, rsc, RM_FALSE);

    listStat = private_rmPrimitiveDisplayListBegin(renderPipe,p);

    if (listStat == 0)
	return;

    r = NULL; 		/* foil compiler warning */
    
    /* get vertex data */
    private_rmGetBlobData(BLOB_VERTEX_INDEX, p, &vstride, &nverts, (void **)&v, &vveclen);

    /* get color data */
    private_rmGetBlobData(BLOB_COLOR_INDEX, p, &cstride, &ncolors, (void **)&c, &cveclen);

    /* get texture coord data - NOTE: (2/2000) tc's & points not tested */
    private_rmGetBlobData(BLOB_TC_INDEX, p, &tcstride, &ntc, (void **)&tc, &tcveclen);

    /* get normals info */
    private_rmGetBlobData(BLOB_NORMAL_INDEX, p, &nstride, &nnormals, (void **)&n, &nveclen);

    private_rmEnableVertexArrays(nverts, ncolors, nnormals, ntc, 0, 0);
    
    glVertexPointer(vveclen, GL_FLOAT, sizeof(float) * vstride, (const GLvoid *)v);
    
    if (ncolors != 0)
	glColorPointer(cveclen, GL_FLOAT, sizeof(float) * cstride, (const GLvoid *)c);

    if (ntc != 0)
	glTexCoordPointer(tcveclen, GL_FLOAT, sizeof(float) * tcstride, (const GLvoid *)tc);

    if (nnormals != 0)
	glNormalPointer(GL_FLOAT, sizeof(float) * nstride, (const GLvoid *)n);
	
    glDrawArrays(GL_POINTS, 0, nverts);

    private_rmPrimitiveDisplayListEnd(renderPipe, p, listStat);

}


/* PRIVATE */
void
rmTrianglesDisjoint OGLPRIMPARMLIST()
{
    /* this code is written assuming per-vertex everything */
    
    /* for verts */
    float *v;
    int    vstride, nverts, vveclen;

    /* color data */
    float *c = NULL;
    int    cstride, ncolors, cveclen;

    /* texture coord data */
    float *tc = NULL;
    int    tcstride;
    int    ntc, tcveclen;

    /* normals */
    float *n;
    int    nstride, nveclen, nnormals;

    int    haveMTCs = 0;
    int    useVertexArrays = 1;
    int    perVertexColor=0, perFaceColor=0;
    int    perFaceNormals=0;
    
    int listStat;

    private_lightingStateManip(p,s, rsc, RM_FALSE); 
    private_colorMaterialStateManip(p,s, rsc); 
    
    listStat = private_rmPrimitiveDisplayListBegin(renderPipe,p);

    if (listStat == 0)
	return;

    r = NULL; 			/* foil compiler warning */
    
    /* get vertex data */
    private_rmGetBlobData(BLOB_VERTEX_INDEX, p, &vstride, &nverts, (void **)&v, &vveclen);

    /* get color data */
    private_rmGetBlobData(BLOB_COLOR_INDEX, p, &cstride, &ncolors, (void **)&c, &cveclen);
    if (ncolors != 0)
    {
	if  (ncolors == nverts)
	    perVertexColor = 1;
	else if (ncolors == nverts / 3)
	{
	    perFaceColor = 1;
	    useVertexArrays = 0;
	}
    }

    private_rmGetBlobData(BLOB_TC_INDEX, p, &tcstride, &ntc, (void **)&tc, &tcveclen);
    if ((ntc != 0) && (ntc != nverts))
	rmWarning("rmTrianglesDisjoint() warning - the number of input texture coordinates is not the same as the number of vertices. ");

    /* get normals info */
    private_rmGetBlobData(BLOB_NORMAL_INDEX, p, &nstride, &nnormals, (void **)&n, &nveclen);
    if (nnormals != 0)
    {
	if (nnormals == nverts / 3)
	{
	    perFaceNormals = 1;
	    useVertexArrays = 0;
	}
	/* else assume per vertex normals */
    }

    if (p->multiTextureCoordBlobsMask != 0)
    {
	useVertexArrays = 0; 	/* slow path until we figure out how to
				   use vertex arrays with MTCs. */
	haveMTCs = 1;
    }
    
    if (useVertexArrays == 0)
    {
        /* vertex, normal, color, tc functions */
        void (*vertexfunc)(const float *);
	void (*normalfunc)(const float *);
	void (*colorfunc)(const float *);
	void (*tcfunc)(const float *);
	int i;

	if (vveclen == 3)
	    vertexfunc = rmglVertex3fv;
	else
	    vertexfunc = rmglVertex2fv;
    
	if (nnormals != 0)
	    normalfunc = rmglNormal3fv;
	else
	    normalfunc = glNoOp;

	if (ncolors != 0)
	    private_rmSetGLColorFunc(cveclen, ncolors, &colorfunc);
	else
 	    colorfunc = glNoOp;
	
	if (ntc == 0)
	    tcfunc = glNoOp;
	else
	    private_rmSetGLTexCoordFunc(tcveclen, ntc, &tcfunc);
	
	glBegin(GL_TRIANGLES);

	for (i=0; i < nverts; )
	{
	    if (nnormals != 0)
	        (*normalfunc)(n), n += nstride;
	    if (ncolors != 0)
	        (*colorfunc)(c), c += cstride;
	    if (ntc != 0)
		(*tcfunc)(tc), tc += tcstride;
	    if (haveMTCs)
		private_dispatchMTCs(renderPipe, p, i);
	    
  	    (*vertexfunc)(v);
	    i++;
	    v += vstride;

	    if ((nnormals != 0) && (perFaceNormals == 0))
	        (*normalfunc)(n), n += nstride;
	    if ((perVertexColor) && (perFaceColor == 0))
	        (*colorfunc)(c), c += cstride;
	    if (ntc != 0)
		(*tcfunc)(tc), tc += tcstride;
	    if (haveMTCs)
		private_dispatchMTCs(renderPipe, p, i);
	    
  	    (*vertexfunc)(v);
	    i++;
	    v += vstride;
	    
	    if ((nnormals != 0) && (perFaceNormals == 0))
	        (*normalfunc)(n), n += nstride;
	    if ((perVertexColor) && (perFaceColor == 0))
	        (*colorfunc)(c), c += cstride;
	    if (ntc != 0)
		(*tcfunc)(tc), tc += tcstride;
	    if (haveMTCs)
		private_dispatchMTCs(renderPipe, p, i);
	    
  	    (*vertexfunc)(v);
	    i++;
	    v += vstride;
	}
	glEnd();
    }
    else
    {

	private_rmEnableVertexArrays(nverts, ncolors, nnormals, ntc, 0, 0);
        glVertexPointer(vveclen, GL_FLOAT, sizeof(float) * vstride, (const GLvoid *)v);
    
	if (ncolors != 0)
	    glColorPointer(cveclen, GL_FLOAT, sizeof(float) * cstride, (const GLvoid *)c);

	if (ntc != 0)
	    glTexCoordPointer(tcveclen, GL_FLOAT,sizeof(float) * tcstride, (const GLvoid *)tc);

	if (nnormals != 0)
	    glNormalPointer(GL_FLOAT, sizeof(float)*nstride, (const GLvoid *)n);
	glDrawArrays(GL_TRIANGLES, 0, nverts);
    }

    private_rmPrimitiveDisplayListEnd(renderPipe, p, listStat);
}


/* PRIVATE */
void
rmTrianglesConnected OGLPRIMPARMLIST()
{
    /* this code is written assuming per-vertex everything */
    /* for verts */
    float *v;
    int    vstride, nverts, vveclen;

    /* color data */
    float *c = NULL;
    int    cstride, ncolors, cveclen;

    /* texture coord data */
    float *tc = NULL;
    int tcstride;
    int ntc, tcveclen;

    /* normals */
    float *n;
    int    nstride, nveclen, nnormals;

    /* multitexture coords */
    int haveMTCs = 0;

    int listStat;

    private_lightingStateManip(p,s, rsc, RM_FALSE); 
    private_colorMaterialStateManip(p,s, rsc); 
    
    listStat = private_rmPrimitiveDisplayListBegin(renderPipe,p);

    if (listStat == 0)
	return;

    r = NULL; 			/* foil compiler warning */

    /* get vertex data */
    private_rmGetBlobData(BLOB_VERTEX_INDEX, p, &vstride, &nverts, (void **)&v, &vveclen);

    /* get color data */
    private_rmGetBlobData(BLOB_COLOR_INDEX, p, &cstride, &ncolors, (void **)&c, &cveclen);

    /* get texture coord data - NOTE: (2/2000) tc's & points not tested */
    private_rmGetBlobData(BLOB_TC_INDEX, p, &tcstride, &ntc, (void **)&tc, &tcveclen);

    /* get normals info */
    private_rmGetBlobData(BLOB_NORMAL_INDEX, p, &nstride, &nnormals, (void **)&n, &nveclen);

    if (p->multiTextureCoordBlobsMask != 0)
	haveMTCs = 1;

    if (haveMTCs == 1) 		/* slow path until MTCs are supported in vertex arrays*/
    {
        /* vertex, normal, color, tc functions */
        void (*vertexfunc)(const float *);
	void (*normalfunc)(const float *);
	void (*colorfunc)(const float *);
	void (*tcfunc)(const float *);
	int i;

	if (vveclen == 3)
	    vertexfunc = rmglVertex3fv;
	else
	    vertexfunc = rmglVertex2fv;
    
	if (nnormals != 0)
	    normalfunc = rmglNormal3fv;
	else
	    normalfunc = glNoOp;

	if (ncolors != 0)
	    private_rmSetGLColorFunc(cveclen, ncolors, &colorfunc);
	else
 	    colorfunc = glNoOp;
	
	if (ntc == 0)
	    tcfunc = glNoOp;
	else
	    private_rmSetGLTexCoordFunc(tcveclen, ntc, &tcfunc);
	
	glBegin(GL_TRIANGLE_STRIP);

	for (i=0; i < nverts; i++)
	{
	    if (nnormals != 0)
	        (*normalfunc)(n), n += nstride;
	    if (ncolors != 0)
	        (*colorfunc)(c), c += cstride;
	    if (ntc != 0)
		(*tcfunc)(tc), tc += tcstride;
	    if (haveMTCs)
		private_dispatchMTCs(renderPipe, p, i);
  	    (*vertexfunc)(v);
	    v += vstride;
	}

	glEnd();
    }
    else 			/* fast path */
    {
	private_rmEnableVertexArrays(nverts, ncolors, nnormals, ntc, 0, 0);
	glVertexPointer(vveclen, GL_FLOAT, sizeof(float) * vstride, (const GLvoid *)v);
    
	if (ncolors != 0)
	    glColorPointer(cveclen, GL_FLOAT, sizeof(float) * cstride, (const GLvoid *)c);

	if (ntc != 0)
	    glTexCoordPointer(tcveclen, GL_FLOAT,sizeof(float) * tcstride, (const GLvoid *)tc);

	if (nnormals != 0)
	    glNormalPointer(GL_FLOAT, sizeof(float) * nstride, (const GLvoid *)n);
	
	glDrawArrays(GL_TRIANGLE_STRIP, 0, nverts);

    }
    private_rmPrimitiveDisplayListEnd(renderPipe, p, listStat);
}


/* PRIVATE */
void
rmTriangleFan OGLPRIMPARMLIST()
{
    /* this code is written assuming per-vertex everything */
    /* for verts */
    float *v;
    int    vstride, nverts, vveclen;

    /* color data */
    float *c = NULL;
    int    cstride, ncolors, cveclen;

    /* texture coord data */
    float *tc = NULL;
    int    tcstride;
    int    ntc, tcveclen;

    /* normals */
    float *n;
    int    nstride, nveclen, nnormals;
    
    int listStat;

    private_lightingStateManip(p,s, rsc, RM_FALSE); 
    private_colorMaterialStateManip(p,s, rsc);
    
    listStat = private_rmPrimitiveDisplayListBegin(renderPipe,p);

    if (listStat == 0)
	return;

    r = NULL; 			/* foil compiler warning */
    
    /* get vertex data */
    private_rmGetBlobData(BLOB_VERTEX_INDEX, p, &vstride, &nverts, (void **)&v, &vveclen);

    /* get color data */
    private_rmGetBlobData(BLOB_COLOR_INDEX, p, &cstride, &ncolors, (void **)&c, &cveclen);

    /* get texture coord data */
    private_rmGetBlobData(BLOB_TC_INDEX, p, &tcstride, &ntc, (void **)&tc, &tcveclen);

    /* get normals info */
    private_rmGetBlobData(BLOB_NORMAL_INDEX, p, &nstride, &nnormals, (void **)&n, &nveclen);

    private_rmEnableVertexArrays(nverts, ncolors, nnormals, ntc, 0, 0);
    
    glVertexPointer(vveclen, GL_FLOAT, sizeof(float) * vstride, (const GLvoid *)v);
    
    if (ncolors != 0)
	glColorPointer(cveclen, GL_FLOAT, sizeof(float) * cstride, (const GLvoid *)c);

    if (ntc != 0)
	glTexCoordPointer(tcveclen, GL_FLOAT, sizeof(float) * tcstride, (const GLvoid *)tc);

    if (nnormals != 0)
	glNormalPointer(GL_FLOAT, sizeof(float) * nstride, (const GLvoid *)n);
	
    glDrawArrays(GL_TRIANGLE_FAN, 0, nverts);

    private_rmPrimitiveDisplayListEnd(renderPipe, p, listStat);
}

/* PRIVATE
 * Note: this code assumes per-vertex everything
 */
void
rmQuadStrip OGLPRIMPARMLIST()
{
    /* this code is written assuming per-vertex everything */
    /* for verts */
    float *v;
    int    vstride, nverts, vveclen;

    /* color data */
    float *c = NULL;
    int    cstride, ncolors, cveclen;

    /* texture coord data */
    float *tc = NULL;
    int tcstride;
    int ntc, tcveclen;

    /* normals */
    float *n;
    int    nstride, nveclen, nnormals;

    int listStat;

    private_lightingStateManip(p,s, rsc, RM_FALSE); 
    private_colorMaterialStateManip(p,s, rsc); 
    
    listStat = private_rmPrimitiveDisplayListBegin(renderPipe,p);

    if (listStat == 0)
	return;

    r = NULL; 			/* foil compiler warning */

    /* get vertex data */
    private_rmGetBlobData(BLOB_VERTEX_INDEX, p, &vstride, &nverts, (void **)&v, &vveclen);

    /* get color data */
    private_rmGetBlobData(BLOB_COLOR_INDEX, p, &cstride, &ncolors, (void **)&c, &cveclen);

    /* get texture coord data - NOTE: (2/2000) tc's & points not tested */
    private_rmGetBlobData(BLOB_TC_INDEX, p, &tcstride, &ntc, (void **)&tc, &tcveclen);

    /* get normals info */
    private_rmGetBlobData(BLOB_NORMAL_INDEX, p, &nstride, &nnormals, (void **)&n, &nveclen);

    private_rmEnableVertexArrays(nverts, ncolors, nnormals, ntc, 0, 0);
    
    glVertexPointer(vveclen, GL_FLOAT, sizeof(float) * vstride, (const GLvoid *)v);
    
    if (ncolors != 0)
	glColorPointer(cveclen, GL_FLOAT, sizeof(float) * cstride, (const GLvoid *)c);

    if (ntc != 0)
	glTexCoordPointer(tcveclen, GL_FLOAT,sizeof(float) * tcstride, (const GLvoid *)tc);

    if (nnormals != 0)
	glNormalPointer(GL_FLOAT, sizeof(float) * nstride, (const GLvoid *)n);
	
    glDrawArrays(GL_QUAD_STRIP, 0, nverts);

    private_rmPrimitiveDisplayListEnd(renderPipe, p, listStat);

}

void
rmPolys OGLPRIMPARMLIST()
{
    /*
     * this code assumes per-vertex everything.
     */
    /* for verts */
    float *v;
    int vstride, nverts, vveclen;

    /* color data */
    float *c=NULL;
    int cstride, ncolors, cveclen;

    /* texture coord data */
    float *tc=NULL;
    int tcstride;
    int ntc,tcveclen;

    /* normals */
    float *n;
    int nstride, nveclen, nnormals;

    /* lengths */
    int *l;
    int lstride, lveclen, nlengths;

    int first = 0,i;
    
    int listStat;

    private_lightingStateManip(p,s, rsc, RM_FALSE); 
    private_colorMaterialStateManip(p,s, rsc);
    
    listStat = private_rmPrimitiveDisplayListBegin(renderPipe,p);

    if (listStat == 0)
	return;

    r = NULL; 			/* foil compile warning */
    
    /* get vertex data */
    private_rmGetBlobData(BLOB_VERTEX_INDEX, p, &vstride,
			  &nverts, (void **)&v, &vveclen);

    /* get color data */
    private_rmGetBlobData(BLOB_COLOR_INDEX, p, &cstride,
			  &ncolors, (void **)&c, &cveclen);

    /* get texture coord data - NOTE: (2/2000) tc's & points not tested */
    private_rmGetBlobData(BLOB_TC_INDEX, p, &tcstride,
			  &ntc, (void **)&tc, &tcveclen);

    /* get normals info */
    private_rmGetBlobData(BLOB_NORMAL_INDEX, p, &nstride,
			  &nnormals, (void **)&n, &nveclen);

    /* get lengths as index data */
    private_rmGetBlobData(BLOB_INDEX_INDEX, p, &lstride,
			  &nlengths, (void **)&l, &lveclen);

    private_rmEnableVertexArrays(nverts,ncolors,nnormals,ntc,0,0);
    
    glVertexPointer(vveclen, GL_FLOAT, sizeof(float)*vstride,
		    (const GLvoid *)v);
    
    if (ncolors != 0)
	glColorPointer(cveclen, GL_FLOAT, sizeof(float)*cstride,
		       (const GLvoid *)c);

    if (ntc != 0)
	glTexCoordPointer(tcveclen, GL_FLOAT,sizeof(float)*tcstride,
			  (const GLvoid *)tc);

    if (nnormals != 0)
	glNormalPointer(GL_FLOAT, sizeof(float)*nstride, (const GLvoid *)n);
	
    for(i=0;i<nlengths; i++) 
    {
	glDrawArrays(GL_POLYGON, first, l[i]);
	first += l[i];
    }

    private_rmPrimitiveDisplayListEnd(renderPipe, p,listStat);
}
/* EOF */
