//Note: tristrip backface-culling is disabled for clipping events because of an unidentified bug

#include "sysinc.h"
#include "vertexarray.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>


/*
** glDrawElements pipeline by Christian 'Surgeon' Michael
** Thanks to Olivier Fabre for bug-hunting
**
** major revision 05-07 april 2002:
** optimized path for GL_EXT_compiled_vertex_array
**
*/

extern void TMA_Start(LockTimeHandle *handle);
extern GLboolean TMA_Check(LockTimeHandle *handle);
extern void fog_Set(GLcontext context);

void GLLockArrays(GLcontext context, GLuint first, GLsizei count);
void GLUnLockArrays(GLcontext context);

extern void AE_ClipPoly(GLcontext context, PolyBuffer *out, int clipstart, ULONG or_codes);

extern void m_CombineMatrices(GLcontext context);

extern GLboolean DecideFrontface(GLcontext context, const MGLVertex *a, const MGLVertex *b, const MGLVertex *c, const int sign);

extern Convfn Convert;

GLboolean Clip_Volume_Bypass = GL_FALSE; //for compiled arrays

//NYI:

void E_DrawPoints        (GLcontext context, const int count, const UWORD *idx);
void E_DrawLines         (GLcontext context, const int count, const UWORD *idx);
void E_DrawLineStrip     (GLcontext context, const int count, const UWORD *idx);
void E_DrawLineLoop      (GLcontext context, const int count, const UWORD *idx);

void E_DrawQuads         (GLcontext context, const int count, const UWORD *idx);
void E_DrawQuadStrip     (GLcontext context, const int count, const UWORD *idx);

//implemented:


void E_DrawTriFan	   (GLcontext context, const int count, UWORD *idx);

void E_DrawPolygon       (GLcontext context, const int count, UWORD *idx);

void E_DrawTriStrip	   (GLcontext context, const int count, const UWORD *idx);

void E_DrawTriangles     (GLcontext context, const int count, const UWORD *idx);

void E_DrawFlatFan       (GLcontext context, const int count, const UWORD *idx);

static PolyBuffer clip[MGL_MAXVERTS>>2];
static PolyBuffer polys[MGL_MAXVERTS>>2];


INLINE GLboolean E_CheckTri(GLcontext context, const MGLVertex *a, const MGLVertex *b, const MGLVertex *c, const int sign)
{
	float area;
	float x1,y1;
	float x2,y2;

	x1 = b->v.x - a->v.x;
	y1 = b->v.y - a->v.y;
	x2 = c->v.x - a->v.x;
	y2 = c->v.y - a->v.y;
           
	area = y2*x1 - x2*y1;

	if(sign > 0)
		area = -area;

	if(area < context->MinTriArea)
		return GL_FALSE;
	else
		return GL_TRUE;
}


#define OF_11 0
#define OF_12 4
#define OF_13 8
#define OF_14 12

#define OF_21 1
#define OF_22 5
#define OF_23 9
#define OF_24 13

#define OF_31 2
#define OF_32 6
#define OF_33 10
#define OF_34 14

#define OF_41 3
#define OF_42 7
#define OF_43 11
#define OF_44 15


void TransformIndex(GLcontext context, const int size, const UWORD *idx)
{
   int i;

   #define a(x) (context->CombinedMatrix.v[OF_##x])

   if(context->ArrayPointer.FixpointTrans == GL_TRUE)
   {
	static int m[16];
	int tx,ty,tz,tw;
	int x,y,z;
	int cw;
      int *vp;
	ULONG local_outcode;
	UBYTE *vpointer;
	MGLVertex *v;
	int stride;
	const float fix2float = 1.f/32768.f;

      #define CLIP_EPS ((int)((1e-7)*32768.f))

 	#define b(x) (m[OF_##x])

      if(context->CombinedValid == GL_FALSE)
	{
	const float float2fix = 32768.f;

        	m_CombineMatrices(context);

		b(11)=(int)(a(11)*float2fix);
		b(12)=(int)(a(12)*float2fix);
		b(13)=(int)(a(13)*float2fix);
		b(14)=(int)(a(14)*float2fix);
		b(21)=(int)(a(21)*float2fix);
		b(22)=(int)(a(22)*float2fix);
		b(23)=(int)(a(23)*float2fix);
		b(24)=(int)(a(24)*float2fix);
		b(31)=(int)(a(31)*float2fix);
		b(32)=(int)(a(32)*float2fix);
		b(33)=(int)(a(33)*float2fix);
		b(34)=(int)(a(34)*float2fix);
		b(41)=(int)(a(41)*float2fix);
		b(42)=(int)(a(42)*float2fix);
		b(43)=(int)(a(43)*float2fix);
		b(44)=(int)(a(44)*float2fix);
	}

     stride = context->ArrayPointer.vertexstride;

     i = size-1;
     do
     {
     v = &(context->VertexBuffer[idx[i]]);
     vpointer = (context->ArrayPointer.verts + idx[i]*stride);

      vp = (int *)vpointer;

      x = vp[0];
      y = vp[1];
      z = vp[2];

	//pipelined transformations

   	tx  = x*b(11);
   	ty  = x*b(21);
   	tz  = x*b(31);
   	tw  = x*b(41);

	tx += y*b(12);
	ty += y*b(22);
	tz += y*b(32);
	tw += y*b(42);

	tx += z*b(13);
	ty += z*b(23);
	tz += z*b(33);
	tw += z*b(43);

	tx += b(14);
	ty += b(24);
	tz += b(34);
	tw += b(44);

	local_outcode = 0;

        if (tw < CLIP_EPS )
	  {
                local_outcode |= MGL_CLIP_NEGW;
	  }        
        if (-tw > tx)
        {
                local_outcode |= MGL_CLIP_LEFT;
        }
        else if (tx > tw)
        {
                local_outcode |= MGL_CLIP_RIGHT;
        }

        if (-tw > ty)
        {
                local_outcode |= MGL_CLIP_BOTTOM;
        }
        else if (ty > tw)
        {
                local_outcode |= MGL_CLIP_TOP;
        }
        
        if (-tw > tz)
        {
                local_outcode |= MGL_CLIP_BACK;
        }
        else if (tz > tw)
        {
                local_outcode |= MGL_CLIP_FRONT;
        }

	v->bx = (float)tx*fix2float;	
	v->by = (float)ty*fix2float;
	v->bz = (float)tz*fix2float;	
	v->bw = (float)tw*fix2float;	

      v->outcode = local_outcode;

     } while (i--);

	#undef b
	#undef CLIP_EPS	
   }
   else
   {
      float a11,a12,a13,a14;
      float a21,a22,a23,a24;
      float a31,a32,a33,a34;
      float a41,a42,a43,a44;
      float *vp;
      float cw;
      float x,y,z;
	ULONG local_outcode;
	UBYTE *vpointer;
	MGLVertex *v;
	int stride;

      #define CLIP_EPS (1e-7)

     if(context->CombinedValid == GL_FALSE)
        	m_CombineMatrices(context);

     a11=a(11); a12=a(12); a13=a(13); a14=a(14);
     a21=a(21); a22=a(22); a23=a(23); a24=a(24);
     a31=a(31); a32=a(32); a33=a(33); a34=a(34);
     a41=a(41); a42=a(42); a43=a(43); a44=a(44);

     stride = context->ArrayPointer.vertexstride;

     i = size-1;

     do
     {
     v = &(context->VertexBuffer[idx[i]]);
     vpointer = (context->ArrayPointer.verts + idx[i]*stride);
     vp = (float *)vpointer;

        x = vp[0];
        y = vp[1];
        z = vp[2];

        v->bx = a11*x + a12*y + a13*z + a14;
        v->by = a21*x + a22*y + a23*z + a24;
        v->bz = a31*x + a32*y + a33*z + a34;
        v->bw = a41*x + a42*y + a43*z + a44;

        cw = v->bw;
        local_outcode = 0;

        if (cw < CLIP_EPS )
                local_outcode |= MGL_CLIP_NEGW;
        
        if (-cw > v->bx)
        {
                local_outcode |= MGL_CLIP_LEFT;
        }
        else if (v->bx > cw)
        {
                local_outcode |= MGL_CLIP_RIGHT;
        }

        if (-cw > v->by)
        {
                local_outcode |= MGL_CLIP_BOTTOM;
        }
        else if (v->by > cw)
        {
                local_outcode |= MGL_CLIP_TOP;
        }
        
        if (-cw > v->bz)
        {
                local_outcode |= MGL_CLIP_BACK;
        }
        else if (v->bz > cw)
        {
                local_outcode |= MGL_CLIP_FRONT;
        }

        v->outcode = local_outcode;

     } while (i--);

     #undef CLIP_EPS
     #undef a
   }
}


//following 5 functions are called from glLockArrays
//05-04-02	returns number of onscreen verts

INLINE ULONG TransformRange(GLcontext context, const int first, const int size)
{
   int i;
   ULONG border;

   #define a(x) (context->CombinedMatrix.v[OF_##x])

   if(context->ArrayPointer.FixpointTrans == GL_TRUE)
   {
	static int m[16];
	int tx,ty,tz,tw;
	int x,y,z;
	int cw;
      int *vp;
	ULONG local_outcode;
	UBYTE *vpointer;
	MGLVertex *v;
	int stride;

      #define CLIP_EPS ((int)((1e-7)*32768.f))

 	#define b(x) (m[OF_##x])

      if(context->CombinedValid == GL_FALSE)
	{
	const float float2fix = 32768.f;

        	m_CombineMatrices(context);

		b(11)=(int)(a(11)*float2fix);
		b(12)=(int)(a(12)*float2fix);
		b(13)=(int)(a(13)*float2fix);
		b(14)=(int)(a(14)*float2fix);
		b(21)=(int)(a(21)*float2fix);
		b(22)=(int)(a(22)*float2fix);
		b(23)=(int)(a(23)*float2fix);
		b(24)=(int)(a(24)*float2fix);
		b(31)=(int)(a(31)*float2fix);
		b(32)=(int)(a(32)*float2fix);
		b(33)=(int)(a(33)*float2fix);
		b(34)=(int)(a(34)*float2fix);
		b(41)=(int)(a(41)*float2fix);
		b(42)=(int)(a(42)*float2fix);
		b(43)=(int)(a(43)*float2fix);
		b(44)=(int)(a(44)*float2fix);
	}

     stride = context->ArrayPointer.vertexstride;
     vpointer = (context->ArrayPointer.verts + first*stride);

     v = &(context->VertexBuffer[first]);

     border = 0;
     i = size;

     do
     {

      vp = (int *)vpointer;

      x = vp[0];
      y = vp[1];
      z = vp[2];

	//pipelined transformations

   	tx  = x*b(11);
   	ty  = x*b(21);
   	tz  = x*b(31);
   	tw  = x*b(41);

	tx += y*b(12);
	ty += y*b(22);
	tz += y*b(32);
	tw += y*b(42);

	tx += z*b(13);
	ty += z*b(23);
	tz += z*b(33);
	tw += z*b(43);

	tx += b(14);
	ty += b(24);
	tz += b(34);
	tw += b(44);

	local_outcode = 0;

        if (tw < CLIP_EPS )
	  {
                local_outcode |= MGL_CLIP_NEGW;
	  }        
        if (-tw > tx)
        {
                local_outcode |= MGL_CLIP_LEFT;
        }
        else if (tx > tw)
        {
                local_outcode |= MGL_CLIP_RIGHT;
        }

        if (-tw > ty)
        {
                local_outcode |= MGL_CLIP_BOTTOM;
        }
        else if (ty > tw)
        {
                local_outcode |= MGL_CLIP_TOP;
        }
        
        if (-tw > tz)
        {
                local_outcode |= MGL_CLIP_BACK;
        }
        else if (tz > tw)
        {
                local_outcode |= MGL_CLIP_FRONT;
        }

	border |= local_outcode;

      v->outcode = local_outcode;

	v->bx = (float)tx;	
	v->by = (float)ty;
	v->bz = (float)tz;	
	v->bw = (float)tw;	

     v++; vpointer += stride;

     } while (--i);

	#undef b
	#undef CLIP_EPS	
   }
   else
   {
     float a11,a12,a13,a14;
     float a21,a22,a23,a24;
     float a31,a32,a33,a34;
     float a41,a42,a43,a44;
     float *vp;
     float cw;
     float x,y,z;
     ULONG local_outcode;
     UBYTE *vpointer;
     MGLVertex *v;
     int stride;

     #define CLIP_EPS (1e-7)

     if(context->CombinedValid == GL_FALSE)
        	m_CombineMatrices(context);

     a11=a(11); a12=a(12); a13=a(13); a14=a(14);
     a21=a(21); a22=a(22); a23=a(23); a24=a(24);
     a31=a(31); a32=a(32); a33=a(33); a34=a(34);
     a41=a(41); a42=a(42); a43=a(43); a44=a(44);

     stride = context->ArrayPointer.vertexstride;
     vpointer = (context->ArrayPointer.verts + first*stride);

     v = &(context->VertexBuffer[first]);

     i = size;

     do
     {
        vp = (float *)vpointer;

        x = vp[0];
        y = vp[1];
        z = vp[2];

        v->bx = a11*x + a12*y + a13*z + a14;
        v->by = a21*x + a22*y + a23*z + a24;
        v->bz = a31*x + a32*y + a33*z + a34;
        v->bw = a41*x + a42*y + a43*z + a44;

     v++; vpointer += stride;

     } while (--i);

     v = &context->VertexBuffer[first];
     i = size;
     border = 0;

     do
     {
        cw = v->bw;
        local_outcode = 0;

        if (cw < CLIP_EPS )
	  {
                local_outcode |= MGL_CLIP_NEGW;
	  }        
        if (-cw > v->bx)
        {
                local_outcode |= MGL_CLIP_LEFT;
        }
        else if (v->bx > cw)
        {
                local_outcode |= MGL_CLIP_RIGHT;
        }

        if (-cw > v->by)
        {
                local_outcode |= MGL_CLIP_BOTTOM;
        }
        else if (v->by > cw)
        {
                local_outcode |= MGL_CLIP_TOP;
        }
        
        if (-cw > v->bz)
        {
                local_outcode |= MGL_CLIP_BACK;
        }
        else if (v->bz > cw)
        {
                local_outcode |= MGL_CLIP_FRONT;
        }

        v->outcode = local_outcode;

	border |= local_outcode;

      v++;
      } while (--i);

	#undef CLIP_EPS	
   }

   #undef a

   return border;
}


INLINE void ProjectRange(GLcontext context, const int first, const int size)
{
   int i, stride;
   float x,y,z,w;

   UBYTE *pointer;
   float *wa;
   float az;

   if(context->ZOffset_State == GL_TRUE)
   {
   	az = context->az + context->ZOffset;
   }
   else
   {
	az = context->az;
   }

   if(!(context->ClientState & GLCS_TEXTURE))
   {
   	MGLVertex *v = &context->VertexBuffer[first];
      i = size;

      do
      {
           x = v->bx;
           y = v->by;
           z = v->bz;
           w = 1.0 / v->bw;
        
           v->bx = context->ax + x * w * context->sx;
           v->by = context->ay - y * w * context->sy;
           v->bz = az + z * w * context->sz;

      v++;

      } while (--i);
   }
   else if (context->ArrayPointer.FixpointTrans == GL_TRUE)
   {
   	MGLVertex *v = &context->VertexBuffer[first];
   	stride = context->ArrayPointer.texcoordstride;
   	pointer = (UBYTE*)context->WBuffer + first * stride;


      i = size;

      do
      {
           x = v->bx;
           y = v->by;
           z = v->bz;
           w = 1.0 / v->bw;
        
           v->bx = context->ax + x * w * context->sx;
           v->by = context->ay - y * w * context->sy;
           v->bz = az + z * w * context->sz;

	     w *= 32768.f;
	     wa = (float*)pointer;	     
	     *wa = w;

      v++;
      pointer += stride;

      } while (--i);
   }
   else
   {
   	MGLVertex *v = &context->VertexBuffer[first];
   	stride = context->ArrayPointer.texcoordstride;
   	pointer = (UBYTE*)context->WBuffer + first * stride;


      i = size;

      do
      {
           x = v->bx;
           y = v->by;
           z = v->bz;
           w = 1.0 / v->bw;
        
           v->bx = context->ax + x * w * context->sx;
           v->by = context->ay - y * w * context->sy;
           v->bz = az + z * w * context->sz;

	     wa = (float*)pointer;	     
	     *wa = w;

      v++;
      pointer += stride;

      } while (--i);
   }
}


INLINE void ProjectRangeByOutcode(GLcontext context, const int first, const int size)
{
   int i, stride;
   float x,y,z,w;

   UBYTE *pointer;
   float *wa;
   float az;

   if(context->ZOffset_State == GL_TRUE)
   {
   	az = context->az + context->ZOffset;
   }
   else
   {
	az = context->az;
   }

   if(context->ArrayPointer.FixpointTrans == GL_TRUE)
   {
	const float fix2float = 1.f/32768.f;

	if(!(context->ClientState & GLCS_TEXTURE))
	{
	     MGLVertex *v = &context->VertexBuffer[first];

	     for (i=0; i<size; i++, v++)
	     {
           x = v->bx;
           y = v->by;
           z = v->bz;
           w = v->bw;

	     v->bx = fix2float * x;
	     v->by = fix2float * y;
	     v->bz = fix2float * z;
	     v->bw = fix2float * w;

	     if(v->outcode & context->ClipFlags)
		continue;

	     w = 1.0 / w;

	     v->v.x = context->ax + x * w * context->sx;
	     v->v.y = context->ay - y * w * context->sy;
	     v->v.z = az + z * w * context->sz;
	     }
	}
	else
	{
	     MGLVertex *v = &context->VertexBuffer[first];
	     stride = context->ArrayPointer.texcoordstride;
	     pointer = (UBYTE*)context->WBuffer + first * stride;

	     for (i=0; i<size; i++, v++, pointer += stride)
	     {
           x = v->bx;
           y = v->by;
           z = v->bz;
           w = v->bw;

	     v->bx = fix2float * x;
	     v->by = fix2float * y;
	     v->bz = fix2float * z;
	     v->bw = fix2float * w;

	     if(v->outcode & context->ClipFlags)
		continue;

           w = 1.0 / w;
        
 	     v->v.x = context->ax + x * w * context->sx;
	     v->v.y = context->ay - y * w * context->sy;
	     v->v.z = az + z * w * context->sz;

	     w *= 32768.f;
	     wa = (float*)pointer;	     
	     v->v.w = w;
	     *wa = w;
	     }
	}
   }
   else if(!(context->ClientState & GLCS_TEXTURE))
   {
    	MGLVertex *v = &context->VertexBuffer[first];

      for (i=0; i<size; i++, v++)
      {
	     if(v->outcode & context->ClipFlags)
		continue;

           x = v->bx;
           y = v->by;
           z = v->bz;
           w = 1.0 / v->bw;
        
	     v->v.x = context->ax + x * w * context->sx;
	     v->v.y = context->ay - y * w * context->sy;
	     v->v.z = az + z * w * context->sz;
       }
   }
   else
   {
   	MGLVertex *v = &context->VertexBuffer[first];
   	stride = context->ArrayPointer.texcoordstride;
   	pointer = (UBYTE*)context->WBuffer + first * stride;

      for (i=0; i<size; i++, v++, pointer += stride)
      {
	     if(v->outcode & context->ClipFlags)
		continue;

           x = v->bx;
           y = v->by;
           z = v->bz;
           w = 1.0 / v->bw;
        
	     v->v.x = context->ax + x * w * context->sx;
	     v->v.y = context->ay - y * w * context->sy;
	     v->v.z = az + z * w * context->sz;

	     v->v.w = w;

	     wa = (float*)pointer;	     
	     *wa = w;
      }
   }
}


INLINE void E_ToScreenArray(GLcontext context, const int count, const UWORD *idx)
{
   int i, stride;
   float x,y,z,w;

   UBYTE *pointer;
   float *wa;
   float az;

   if(context->ZOffset_State == GL_TRUE)
   {
   	az = context->az + context->ZOffset;
   }
   else
   {
	az = context->az;
   }

   if(!(context->ClientState & GLCS_TEXTURE))
   {
      i = 0;

      do
      {
   	MGLVertex *v = &context->VertexBuffer[idx[i]];

           x = v->bx;
           y = v->by;
           z = v->bz;
           w = 1.0 / v->bw;
        
           v->v.x = context->ax + x * w * context->sx;
           v->v.y = context->ay - y * w * context->sy;
           v->v.z = az + z * w * context->sz;
 
      i++;
      } while (i < count);
   }
   else
   {
   	stride = context->ArrayPointer.texcoordstride;

      i = 0;

      do
      {
   	MGLVertex *v = &context->VertexBuffer[idx[i]];

           x = v->bx;
           y = v->by;
           z = v->bz;
           w = 1.0 / v->bw;
        
           v->v.x = context->ax + x * w * context->sx;
           v->v.y = context->ay - y * w * context->sy;
           v->v.z = az + z * w * context->sz;

   	pointer = (UBYTE*)context->WBuffer + idx[i] * stride;
	wa = (float*)pointer;	     
	*wa = w;

      i++;
      } while (i < count);	
   }
}

INLINE void E_ToScreen(GLcontext context, int vnum)
{
	float *wa;
	float w = 1.0/context->VertexBuffer[vnum].bw;
	UBYTE *pointer = (UBYTE*)context->WBuffer + vnum * context->ArrayPointer.texcoordstride;

	context->VertexBuffer[vnum].v.x = context->ax + context->VertexBuffer[vnum].bx * w * context->sx;
	context->VertexBuffer[vnum].v.y = context->ay - context->VertexBuffer[vnum].by * w * context->sy;
	context->VertexBuffer[vnum].v.z = context->az + context->VertexBuffer[vnum].bz * w * context->sz;

	if (context->ZOffset_State == GL_TRUE)
		context->VertexBuffer[vnum].v.z += (W3D_Float)context->ZOffset;

	context->VertexBuffer[vnum].v.w = w; 

	wa = (float*)pointer;
	*wa = w;
}

#ifdef __VBCC__

#define V_ToScreen(ctx,vnum){\
static float wdiv;\
wdiv = 1.0 / ctx->VertexBuffer[vnum].bw; \
ctx->VertexBuffer[vnum].v.x = ctx->ax + ctx->VertexBuffer[vnum].bx * wdiv * ctx->sx; \
ctx->VertexBuffer[vnum].v.y = ctx->ay - ctx->VertexBuffer[vnum].by * wdiv * ctx->sy; \
ctx->VertexBuffer[vnum].v.z = ctx->az + ctx->VertexBuffer[vnum].bz * wdiv * ctx->sz; \
if (ctx->ZOffset_State == GL_TRUE) ctx->VertexBuffer[vnum].v.z += (W3D_Float)ctx->ZOffset; \
ctx->VertexBuffer[vnum].v.w = wdiv; \
}

#else

static INLINE void V_ToScreen(GLcontext context, int vnum)
{
	GLfloat wdiv = 1.f / context->VertexBuffer[vnum].bw;

	context->VertexBuffer[vnum].v.x = (W3D_Float)(context->ax + context->VertexBuffer[vnum].bx * wdiv * context->sx);

	context->VertexBuffer[vnum].v.y = (W3D_Float)(context->ay - context->VertexBuffer[vnum].by * wdiv * context->sy);

	context->VertexBuffer[vnum].v.z = (W3D_Float)(context->az + context->VertexBuffer[vnum].bz * wdiv * context->sz);

	if (context->ZOffset_State == GL_TRUE) context->VertexBuffer[vnum].v.z += (W3D_Float)context->ZOffset; \

	context->VertexBuffer[vnum].v.w = (W3D_Float)wdiv; \
}

#endif

void E_DrawPoints(GLcontext context, const int count, const UWORD *idx)
{
}

void E_DrawLines(GLcontext context, const int count, const UWORD *idx)
{
}

void E_DrawLineStrip(GLcontext context, const int count, const UWORD *idx)
{
}

void E_DrawLineLoop(GLcontext context, const int count, const UWORD *idx)
{
}

void E_DrawQuads(GLcontext context, const int count, const UWORD *idx)
{
}

void E_DrawQuadStrip(GLcontext context, const int count, const UWORD *idx)
{
}


void E_DrawTriFan(GLcontext context, const int count, UWORD *idx)
{
      int i,j;
	int size;
	ULONG and_code, or_code, guard_band;
      ULONG local_or, local_and;
      ULONG error;
      static W3D_Vertex **verts = NULL;
      static W3D_TrianglesV fan;
      static ULONG    complete[MGL_MAXVERTS];
      static GLboolean visible[MGL_MAXVERTS];
	static GLboolean projected[4096];
      int first, triangle;
      int cnum, pnum, backface, prevcopy, free;
      int sign;


	if(Clip_Volume_Bypass != GL_FALSE)
	{
	   size = count;

	   //first check if we are in guardband-mode
	   //and discard/shrink offscreen primitives

	   if((Clip_Volume_Bypass > GL_TRUE) && context->VertexBuffer[idx[0]].outcode)
	   {
		i = size - 2;

		local_and = context->VertexBuffer[idx[0]].outcode & context->VertexBuffer[idx[i]].outcode & context->VertexBuffer[idx[i+1]].outcode;

		if(local_and)
		{
			i--;

			while (i)
			{
			   if((local_and & context->VertexBuffer[idx[i]].outcode) == 0)
				break;
			   i--;
			}
		}

		if(i == 0)
		return;

		size = i+2;
	   }


	   if(context->CullFace_State == GL_FALSE)
	   {
		error = W3D_DrawElements(context->w3dContext, W3D_PRIMITIVE_TRIFAN, W3D_INDEX_UWORD, size, (void*)idx);
	   }
	   else
	   {
	   float fsign;
	   float area;
	   float x1,x2;
	   float y1,y2;

	   #define x(a) (context->VertexBuffer[idx[a]].bx)
	   #define y(a) (context->VertexBuffer[idx[a]].by)


		first = 0;
		backface = 0;

		fsign = (float)(-context->CurrentCullSign);
 
		if(size == 3)
		{
			x1 = x(1) - x(0);
			y1 = y(1) - y(0);
			x2 = x(2) - x(0);
			y2 = y(2) - y(0);

			area = y2*x1 - x2*y1;
			area *= fsign;
		}
		else
		{
			float x0,y0;
			float area2;

			x0 = x(0);
			y0 = y(0);
     
			x1 = x(1) - x0;
 			y1 = y(1) - y0;
			x2 = x(2) - x0;
			y2 = y(2) - y0;

			area = y2*x1 - x2*y1;
			area *= fsign;

			if(area < 0.f)
			{
				first++;
				area = 0.f;
			}
        
			i = 1;
			do
			{
             			x1 = x2;
                   		y1 = y2;
                   		x2 = x(i+2) - x0;
                   		y2 = y(i+2) - y0;

      	             	area2 = y2*x1 - x2*y1;
      	             	area2 *= fsign;
	
				if(area2 < 0.f)
				{
					if(first == i)
						first++;
	                              	else
						backface++;
				}
				else
				{
                                	backface = 0;
                                	area += area2;
				}

			i++;
			} while (i < size-2);
		}

		if(area < context->MinTriArea)
			return;

		size -= backface + first; //shrink

		if(first)
		{
			UWORD val = idx[first];

			idx[first] = idx[0];

			error = W3D_DrawElements(context->w3dContext, W3D_PRIMITIVE_TRIFAN, W3D_INDEX_UWORD, size, (void*)&idx[first]);

			idx[first] = val;
		}
		else
		{

			error = W3D_DrawElements(context->w3dContext, W3D_PRIMITIVE_TRIFAN, W3D_INDEX_UWORD, size, (void*)idx);

		}

	   #undef x
	   #undef y
	   }
	return;
	}

	sign = context->CurrentCullSign;

	if(context->ArrayPointer.transformed == GL_FALSE)
	{
		TransformIndex(context, count, idx);
	}


	or_code = 0;
	and_code = 0xff;

	for(i=0; i<count; i++)
	{
		and_code &= context->VertexBuffer[idx[i]].outcode;
		or_code |= context->VertexBuffer[idx[i]].outcode;
	}

	if(and_code)
		return;

	if(or_code == 0 || (or_code & context->ClipFlags))
	{
		guard_band = or_code;
	}
	else
	{
		float gcw;
		ULONG guard_code;
		MGLVertex *v;

		i = 0;
		guard_band = 0;

		do
		{
		v = &context->VertexBuffer[idx[i]];

		if(v->outcode)
		{
		gcw = v->bw * 2.0;
		guard_code = 0;

		if (-gcw > v->bx)
			guard_code |= MGL_CLIP_LEFT;
		else if (v->bx > gcw)
			guard_code |= MGL_CLIP_RIGHT;

		if (-gcw > v->by)
			guard_code |= MGL_CLIP_BOTTOM;
		else if (v->by > gcw)
			guard_code |= MGL_CLIP_TOP;

		guard_band |= guard_code;
		}

		i++;
		} while (i < count && guard_band == 0);
	}

	if (guard_band == 0)
	{
	   if(context->ArrayPointer.transformed == GL_FALSE)
	   E_ToScreenArray(context, count, idx);

	   if(context->CullFace_State == GL_FALSE)
	   {
		error = W3D_DrawElements(context->w3dContext, W3D_PRIMITIVE_TRIFAN, W3D_INDEX_UWORD, count, (void*)idx);
	   }
	   else
	   {
	   float fsign;
	   float area;
	   float x1,x2;
	   float y1,y2;

	   #define x(a) (context->VertexBuffer[idx[a]].v.x)
	   #define y(a) (context->VertexBuffer[idx[a]].v.y)


		fsign = (float)(-context->CurrentCullSign);

		first = 0;
		size = count;
		backface = 0;
 
		if(size == 3)
		{
			x1 = x(1) - x(0);
			y1 = y(1) - y(0);
			x2 = x(2) - x(0);
			y2 = y(2) - y(0);

			area = y2*x1 - x2*y1;
			area *= fsign;
		}
		else
		{
			float x0,y0;
			float area2;

			x0 = x(0);
			y0 = y(0);
     
			x1 = x(1) - x0;
 			y1 = y(1) - y0;
			x2 = x(2) - x0;
			y2 = y(2) - y0;

			area = y2*x1 - x2*y1;
			area *= fsign;

			if(area < 0.f)
			{
				first++;
				area = 0.f;
			}
        
			i = 1;
			do
			{
             			x1 = x2;
                   		y1 = y2;
                   		x2 = x(i+2) - x0;
                   		y2 = y(i+2) - y0;

      	             	area2 = y2*x1 - x2*y1;
      	             	area2 *= fsign;
	
				if(area2 < 0.f)
				{
					if(first == i)
						first++;
	                              	else
						backface++;
				}
				else
				{
                                	backface = 0;
                                	area += area2;
				}

			i++;
			} while (i < size-2);
		}

		if(area < context->MinTriArea)
			return;

		size -= backface + first; //shrink

		if(first)
		{
			UWORD val = idx[first];

			idx[first] = idx[0];

			error = W3D_DrawElements(context->w3dContext, W3D_PRIMITIVE_TRIFAN, W3D_INDEX_UWORD, size, (void*)&idx[first]);

			idx[first] = val;
		}
		else
		{
			error = W3D_DrawElements(context->w3dContext, W3D_PRIMITIVE_TRIFAN, W3D_INDEX_UWORD, size, (void*)idx);
		}

		#undef x
		#undef y
	   }

	return;
	}


        if (verts == NULL)
        {
                verts = (W3D_Vertex **)malloc(sizeof(W3D_Vertex *) * context->VertexBufferSize);
                if (!verts) return;
        }


        backface = 0;
        triangle = 0;
        i = 1;

	if(context->CullFace_State == GL_FALSE)
	{
        do
        {
                local_and = context->VertexBuffer[idx[0]].outcode
                        & context->VertexBuffer[idx[i]].outcode
                        & context->VertexBuffer[idx[i+1]].outcode;

                local_or = context->VertexBuffer[idx[0]].outcode
                        | context->VertexBuffer[idx[i]].outcode
                        | context->VertexBuffer[idx[i+1]].outcode;


                if (local_and == 0) // if the local and code is zero, we're not
                {
			complete[triangle] = local_or;
			visible[triangle] = GL_TRUE;
			backface = 0;
                }
                else
                {
                        visible[triangle] = GL_FALSE;    
                        backface++;
                }
           i++;
           triangle++;
        } while ( i< count-1);
	}
	else
	{
        do
        {
                local_and = context->VertexBuffer[idx[0]].outcode
                        & context->VertexBuffer[idx[i]].outcode
                        & context->VertexBuffer[idx[i+1]].outcode;

                local_or = context->VertexBuffer[idx[0]].outcode
                        | context->VertexBuffer[idx[i]].outcode
                        | context->VertexBuffer[idx[i+1]].outcode;


                if (local_and == 0) // if the local and code is zero, we're not
                {
		     complete[triangle] = local_or;

                   if(local_or & MGL_CLIP_NEGW)
                   {
                        visible[triangle] = GL_TRUE;
			  backface = 0;
                   }
                   else
                   {
                        visible[triangle] = DecideFrontface(context, &(context->VertexBuffer[idx[0]]), &(context->VertexBuffer[idx[i]]), &(context->VertexBuffer[idx[i+1]]), sign);

                        if(!visible[triangle])
				backface++;
			  else
				backface = 0;
                   }
                }
                else
                {
                        visible[triangle] = GL_FALSE;    
                        backface++;
                }
           i++;
           triangle++;
        } while ( i< count-1);
	}

        if(backface == triangle) //early out
        return;

	  size = count - backface;

 	  Convert(context, idx[0]);

 	  prevcopy = 0;
	  pnum = 0; 
	  cnum = 0;
        free = context->VertexBufferPointer;
        triangle = 0; i = 1;

        do
        {
                if (visible[triangle] == GL_FALSE) // case 3
                {
                        triangle ++;
                        i        ++;
                }
                else
                {

                        if (complete[triangle]) // case 1
                        {
                        clip[cnum].numverts = 3;
                        clip[cnum].verts[0] = idx[0];
                        clip[cnum].verts[1] = idx[i];
                        clip[cnum].verts[2] = idx[i+1];

			  if(prevcopy != i)
			  Convert(context, idx[i]);

			  Convert(context, idx[i+1]);
			  prevcopy = i+1;

                           AE_ClipPoly(context, &clip[cnum], free, complete[triangle]);

                           if(clip[cnum].numverts)
                           {
                              free = clip[cnum].nextfree;
                              cnum++;
                           }

                           triangle++; i++;
                        }
                        else
                        {   // case 2 (the difficult part)
                        int k=3;
                        polys[pnum].verts[0] = idx[0];
                        polys[pnum].verts[1] = idx[i];
                        polys[pnum].verts[2] = idx[i+1];

                            triangle++; i++;

                            while (complete[triangle]==0 && visible[triangle] && i<size-1)
                            {
                            polys[pnum].verts[k] = idx[i+1];

                            i++; k++; triangle++;
                            }

                        polys[pnum].numverts = k;
                        pnum++;
                        }
                }
        } while (i<size-1);


//Project to screen and draw:

  if(cnum)
  {
	if(context->ArrayPointer.transformed == GL_FALSE)
	{
	  for(i=0; i<size; i++)
	  {  
	 	projected[idx[i]] = GL_FALSE;
 	  }
	}

	for(i=context->VertexBufferPointer; i<free; i++)
	{
		V_ToScreen(context, i);
	}

  }

  if(pnum)
  {
      PolyBuffer *p;

      p = &polys[0];

	if(context->ArrayPointer.transformed == GL_FALSE)
	{
        E_ToScreen(context, p->verts[0]);
        E_ToScreen(context, p->verts[1]);
        E_ToScreen(context, p->verts[2]);
	
        projected[p->verts[0]] = GL_TRUE;
        projected[p->verts[1]] = GL_TRUE;
        projected[p->verts[2]] = GL_TRUE;

        if(p->numverts > 3)
        {
        i=3;
                do
                {
                        E_ToScreen(context, p->verts[i]);
                        projected[p->verts[i]] = GL_TRUE;
                i++;
                } while (i < p->numverts);
        }
	}

	error = W3D_DrawElements(context->w3dContext, W3D_PRIMITIVE_TRIFAN, W3D_INDEX_ULONG, p->numverts, (void*)p->verts);

	j = 1;
	while (j < pnum)
	{
	    p = &polys[j];

	    if(context->ArrayPointer.transformed == GL_FALSE)
	    {
                E_ToScreen(context, p->verts[1]);
                E_ToScreen(context, p->verts[2]);

                projected[p->verts[1]] = GL_TRUE;
                projected[p->verts[2]] = GL_TRUE;


                if(p->numverts > 3)
                {
                i=3;

                   do
                   {
                        E_ToScreen(context,  p->verts[i]);
                        projected[p->verts[i]] = GL_TRUE;
                   i++;
                   } while (i < p->numverts);
                }
	    }

	    error = W3D_DrawElements(context->w3dContext, W3D_PRIMITIVE_TRIFAN, W3D_INDEX_ULONG, p->numverts, (void*)p->verts);

	j++;
	}
  }

  if(cnum)
  {
  fan.tex = context->w3dTexBuffer[context->CurrentBinding];
  fan.st_pattern = NULL;

    j = 0;

    do
    {
	PolyBuffer *p = &clip[j];

	if(context->ArrayPointer.transformed == GL_FALSE)
	{
		for (i=0; i<p->numverts; i++)
		{
		  int vert = p->verts[i];

		  verts[i] = &(context->VertexBuffer[vert].v);

		  if(vert < context->VertexBufferPointer && projected[vert] == GL_FALSE)
		  {
		    	V_ToScreen(context, vert);
		    	projected[vert] = GL_TRUE; 
		  }

		}
	}
	else
	{
		for (i=0; i<p->numverts; i++)
		{
			verts[i] = &(context->VertexBuffer[p->verts[i]].v);
		}
	}

	fan.vertexcount = p->numverts;
	fan.v = verts;
	error = W3D_DrawTriFanV(context->w3dContext, &fan);

	j++;

    } while (j < cnum);
  }
}


void E_DrawTriStrip(GLcontext context, const int count, const UWORD *idx)
{
      int i,j;
	int size;
	ULONG and_code, or_code, guard_band;
      ULONG local_or, local_and;
      ULONG error;
      static W3D_Vertex **verts = NULL;
      static W3D_TrianglesV tris;
      static ULONG    complete[MGL_MAXVERTS];
      static GLboolean visible[MGL_MAXVERTS];
	static GLboolean projected[4096];
      int first;
      int cnum, pnum, backface, prevcopy, free;


	if(Clip_Volume_Bypass != GL_FALSE)
	{
	   size = count;
	   first = 0;

	   //first check if we are in guardband-mode
	   //and discard/shrink offscreen primitives

	   if((Clip_Volume_Bypass > GL_TRUE) && (context->VertexBuffer[idx[0]].outcode || context->VertexBuffer[idx[size-1]].outcode))
	   {
		i = size - 3;

		local_and = context->VertexBuffer[idx[i]].outcode & context->VertexBuffer[idx[i+1]].outcode & context->VertexBuffer[idx[i+2]].outcode;

		if(local_and)
		{
			i--;

			while (i >= 0)
			{
			   if((local_and & context->VertexBuffer[idx[i]].outcode) == 0)
				break;
			   i--;
			}
		}

		if(i < 0)
		return;

		size = i+3;

		if(size > 3)
		{
			local_and = context->VertexBuffer[idx[0]].outcode & context->VertexBuffer[idx[1]].outcode & context->VertexBuffer[idx[2]].outcode;

			i = 2;

			if(local_and)
			{
			   i++;

			   while(i < size-1)
			   {
				if((local_and & context->VertexBuffer[idx[i]].outcode) == 0)
					break;
				i++;

			   }
			}

			first = i-2;
		}
	   }

	   if(context->CullFace_State == GL_FALSE)
	   {
		error = W3D_DrawElements(context->w3dContext, W3D_PRIMITIVE_TRISTRIP, W3D_INDEX_UWORD, size-first, (void*)&idx[first]);
	   }
	   else
	   {
		float fsign;
		float area;
		float x1,x2;
		float y1,y2;

		#define x(a) (context->VertexBuffer[idx[a]].bx)
		#define y(a) (context->VertexBuffer[idx[a]].by)

		backface = 0;

		fsign = (float)(-context->CurrentCullSign);
		if(first % 2) fsign = -fsign;

                	if(size == 3)
        	  	{
                		x1 = x(first+1) - x(first);
                		y1 = y(first+1) - y(first);
                		x2 = x(first+2) - x(first);
                		y2 = y(first+2) - y(first);

                		area = y2*x1 - x2*y1;
                		area *= fsign;
		  	}
		  	else
		  	{
		  		float a1,a2,b1,b2;
		  		float area2;

              	   	i = first+1;

                		a1 = x(i);
                		b1 = y(i);
                		a2 = x(i+1);
                		b2 = y(i+1);

                		x1 = a1 - x(first);
                		y1 = b1 - y(first);
                		x2 = a2 - x(first);
                		y2 = b2 - y(first);

                		area = y2*x1 - x2*y1;
		  		area *= fsign;

 
                	   	if(area < 0.f)
                	   	{
                	        	first++;
                	        	area = 0.f;
                	   	}

        
                 	   	do
                	   	{
                	   	fsign = -fsign;

	                   	x1 = a2 - a1;
      	             	y1 = b2 - b1;
      	             	x2 = x(i+2) - a1;
      	             	y2 = y(i+2) - b1;
      	             	a1 = a2;
      	            	b1 = b2;
      	             	a2 = x(i+2);
      	             	b2 = y(i+2);

      	             	area2 = y2*x1 - x2*y1;
      	             	area2 *= fsign;
	
	                          if(area2 < 0.f)
	                          {
				  if(first == i)
					first++;
				  else
	                              	backface++;
      	                  }
      	                  else
                        	  {
                                	backface = 0;
                                	area += area2;
                        	  }

                   		i++;
                   		} while (i < size-2);

			size -= backface + first;
			}

		if(area < context->MinTriArea)
			return;

		error = W3D_DrawElements(context->w3dContext, W3D_PRIMITIVE_TRISTRIP, W3D_INDEX_UWORD, size, (void*)&idx[first]);

		#undef x
		#undef y
	   }
	return;
	}


	if(context->ArrayPointer.transformed == GL_FALSE)
	{
		TransformIndex(context, count, idx);
	}

	or_code = 0;
	and_code = 0xff;

	for(i=0; i<count; i++)
	{
		and_code &= context->VertexBuffer[idx[i]].outcode;
		or_code |= context->VertexBuffer[idx[i]].outcode;
	}

	if(and_code)
		return;

	if(or_code == 0 || (or_code & context->ClipFlags))
	{
		guard_band = or_code;
	}
	else
	{
		float gcw;
		ULONG guard_code;
		MGLVertex *v;

		i = 0;
		guard_band = 0;

		do
		{
		v = &context->VertexBuffer[idx[i]];

		if(v->outcode)
		{
		gcw = v->bw * 2.0;
		guard_code = 0;

		if (-gcw > v->bx)
			guard_code |= MGL_CLIP_LEFT;
		else if (v->bx > gcw)
			guard_code |= MGL_CLIP_RIGHT;

		if (-gcw > v->by)
			guard_code |= MGL_CLIP_BOTTOM;
		else if (v->by > gcw)
			guard_code |= MGL_CLIP_TOP;

		guard_band |= guard_code;
		}

		i++;
		} while (i < count && guard_band == 0);
	}

	if (guard_band == 0)
	{
		if(context->ArrayPointer.transformed == GL_FALSE)
		E_ToScreenArray(context, count, idx);

		if(context->CullFace_State == GL_FALSE)
		{
			error = W3D_DrawElements(context->w3dContext, W3D_PRIMITIVE_TRISTRIP, W3D_INDEX_UWORD, count, (void*)idx);

		}
		else
		{
		#define x(a) (context->VertexBuffer[idx[a]].v.x)
		#define y(a) (context->VertexBuffer[idx[a]].v.y)

		float fsign;
		float area;
		float x1,x2;
		float y1,y2;

		fsign = (float)(-context->CurrentCullSign);

		size = count;
		backface = 0;
		first = 0;

 
                	if(size == 3)
        	  	{
                		x1 = x(1) - x(0);
                		y1 = y(1) - y(0);
                		x2 = x(2) - x(0);
                		y2 = y(2) - y(0);

                		area = y2*x1 - x2*y1;
                		area *= fsign;
		  	}
		  	else
		  	{
		  		float a1,a2,b1,b2;
		  		float area2;

                		a1 = x(1);
                		b1 = y(1);
                		a2 = x(2);
                		b2 = y(2);

                		x1 = a1 - x(0);
                		y1 = b1 - y(0);
                		x2 = a2 - x(0);
                		y2 = b2 - y(0);

                		area = y2*x1 - x2*y1;
		  		area *= fsign;

                	   	if(area < 0.f)
                	   	{
                	        	first++;
                	        	area = 0.f;
                	   	}
        
                	   	i = 1;
                	   	do
                	   	{
                	   	fsign = -fsign;
	                   	x1 = a2 - a1;
      	             	y1 = b2 - b1;
      	             	x2 = x(i+2) - a1;
      	             	y2 = y(i+2) - b1;
      	             	a1 = a2;
      	            	b1 = b2;
      	             	a2 = x(i+2);
      	             	b2 = y(i+2);

      	             	area2 = y2*x1 - x2*y1;
      	             	area2 *= fsign;
	
	                          if(area2 < 0.f)
	                          {
				  if(first == i)
					first++;
				  else
	                              	backface++;
      	                  }
      	                  else
                        	  {
                                	backface = 0;
                                	area += area2;
                        	  }

                   		i++;
                   		} while (i < size-2);

			size -= first + backface;
			}

		if(area < context->MinTriArea)
			return;

		error = W3D_DrawElements(context->w3dContext, W3D_PRIMITIVE_TRISTRIP, W3D_INDEX_UWORD, size, (void*)&idx[first]); 

		#undef x
		#undef y

		}

	return;
	}


	if (verts == NULL)
	{
                verts = (W3D_Vertex **)malloc(sizeof(W3D_Vertex *) * context->VertexBufferSize);
                if (!verts) return;
	}


	backface = 0;
	i = 0;

      do
      {
                local_and = context->VertexBuffer[idx[i]].outcode
                        & context->VertexBuffer[idx[i+1]].outcode
                        & context->VertexBuffer[idx[i+2]].outcode;

                local_or = context->VertexBuffer[idx[i]].outcode
                        | context->VertexBuffer[idx[i+1]].outcode
                        | context->VertexBuffer[idx[i+2]].outcode;

                if (local_and == 0) // if the local and code is zero, we're not
                {
			complete[i] = local_or;
			visible[i] = GL_TRUE;
			backface = 0;
                }
                else
                {
                        visible[i] = GL_FALSE;    
                        backface++;
                }

      i++;
	} while (i < count-2);

	size = count - backface;

      free = context->VertexBufferPointer;

	prevcopy = -1;
	pnum = 0;
      cnum = 0;
      i = 0;

        do
        {
                if (visible[i] == GL_FALSE) // case 3
                {
                        i++;
                }
                else if (complete[i]) // case 1
                {
                        clip[cnum].numverts = 3;

                        clip[cnum].verts[0] = idx[i];
                        clip[cnum].verts[1] = idx[i+1];
                        clip[cnum].verts[2] = idx[i+2];

//this element is never shared with next triangle:

                        if(prevcopy == i+1)
                        {
                                Convert(context, idx[i+2]);
                        }
                        else if(prevcopy == i)
                        {
                                Convert(context, idx[i+1]);
                                Convert(context, idx[i+2]);
                        }
			  else
			  {
                                Convert(context, idx[i+0]);
                                Convert(context, idx[i+1]);
                                Convert(context, idx[i+2]);
			  }

//this element is never shared with previous triangle:

                        prevcopy = i+2;


                        AE_ClipPoly(context, &clip[cnum], free, complete[i]);
                        i++;

                        if(clip[cnum].numverts)
                        {
                              free = clip[cnum].nextfree;
                              cnum++;
                        }
                }
                else
                {   // case 2 (the difficult part)

			  int k = 3;
                        polys[pnum].verts[0] = i;
                        i++;

                        while (complete[i]==0 && visible[i] == GL_TRUE && i<size-2 && k < 64)
                        {
                            	i++; k++;
                        }

                        polys[pnum].numverts = k;
                        pnum++;
                }
        } while (i < size-2);


//Project to screen and draw:

  if(cnum)
  {
	if(context->ArrayPointer.transformed == GL_FALSE)
	{
	   for(i=0; i<size; i++)
	   {
		projected[idx[i]] = GL_FALSE;
	   }
	}

	for(i=context->VertexBufferPointer; i<free; i++)
	{
		V_ToScreen(context, i);
	}
  }

  if(pnum)
  {
	PolyBuffer *p;
	int start;

      p = &polys[0];
	start = p->verts[0];

	if(context->ArrayPointer.transformed == GL_FALSE)
	{
        E_ToScreen(context, idx[start+0]);
        E_ToScreen(context, idx[start+1]);
        E_ToScreen(context, idx[start+2]);

        projected[idx[start+0]] = GL_TRUE;
        projected[idx[start+1]] = GL_TRUE;
        projected[idx[start+2]] = GL_TRUE;

        i=3;
        while(i < p->numverts)
        {
 		E_ToScreen(context, idx[start+i]);
 		projected[idx[start+i]] = GL_TRUE;
		i++;
	  }
      }

	error = W3D_DrawElements(context->w3dContext, W3D_PRIMITIVE_TRISTRIP, W3D_INDEX_UWORD, p->numverts, (void*)&idx[start]);

      j = 1;

      while (j < pnum)
      {
              p = &polys[j];
	  	start = p->verts[0];

		if(context->ArrayPointer.transformed == GL_FALSE)
		{
	 
                if(projected[idx[start+0]] == GL_FALSE)
                E_ToScreen(context, idx[start+0]);

                E_ToScreen(context, idx[start+1]);
                E_ToScreen(context, idx[start+2]);

                projected[idx[start+0]] = GL_TRUE;
            	  projected[idx[start+1]] = GL_TRUE;
                projected[idx[start+2]] = GL_TRUE;

        	  i=3;
                while(i < p->numverts)
                {               
                        E_ToScreen(context, idx[start+i]);
                        projected[idx[start+i]] = GL_TRUE;
                i++;
                }
		}

	   error = W3D_DrawElements(context->w3dContext, W3D_PRIMITIVE_TRISTRIP, W3D_INDEX_UWORD, p->numverts, (void*)&idx[start]);

	j++;
      }
  }

  if(cnum)
  {
    tris.tex = context->w3dTexBuffer[context->CurrentBinding];
    tris.st_pattern = NULL;

    j = 0;

    do
    {
	PolyBuffer *p = &clip[j];

	if(context->ArrayPointer.transformed == GL_FALSE)
	{
		for (i=0; i<p->numverts; i++)
		{
		  int vert = p->verts[i];

		  verts[i] = &(context->VertexBuffer[vert].v);

		  if(vert < context->VertexBufferPointer && projected[vert] == GL_FALSE)
		  {
		    	V_ToScreen(context, vert);
		    	projected[vert] = GL_TRUE; 
		  }

		}
	}
	else
	{
		for (i=0; i<p->numverts; i++)
		{
			verts[i] = &(context->VertexBuffer[p->verts[i]].v);
		}
	}

	tris.vertexcount = p->numverts;
	tris.v = verts;

	error = W3D_DrawTriFanV(context->w3dContext, &tris);

	j++;
    } while (j < cnum);
  }
}


//added 27-05-02

void E_DrawTriangles_Locked(GLcontext context, const int count, const UWORD *idx)
{
      int i, j;
	ULONG local_and, local_or;
      ULONG error;
      static W3D_Vertex **verts = NULL;
      static W3D_TrianglesV fan;
	static ULONG trichain[MGL_MAXVERTS*3];
      static int sign;
	GLboolean visible;
      int cnum, free, chainverts;

	sign = context->CurrentCullSign;

	if(Clip_Volume_Bypass != GL_FALSE)
	{
	chainverts = 0;

		if(Clip_Volume_Bypass == GL_TRUE)
		{
		   if(context->CullFace_State == GL_FALSE)
		   {
			error = W3D_DrawElements(context->w3dContext, W3D_PRIMITIVE_TRIANGLES, W3D_INDEX_UWORD, count, (void *)idx);
		   }
		   else
		   {
			for(i=0; i<count; i+=3)
			{
			   if(E_CheckTri(context, &context->VertexBuffer[idx[i]], &context->VertexBuffer[idx[i+1]], &context->VertexBuffer[idx[i+2]], sign) == GL_TRUE)
			   {
				trichain[chainverts+0] = idx[i+0];
				trichain[chainverts+1] = idx[i+1];
				trichain[chainverts+2] = idx[i+2];
				chainverts+=3; 
			   }
			}

		   }
		}
		else
		{
		   if(context->CullFace_State == GL_FALSE)
		   for(i=0; i<count; i+=3)
		   {
	   		   local_and = context->VertexBuffer[idx[i]].outcode & context->VertexBuffer[idx[i+1]].outcode & context->VertexBuffer[idx[i+2]].outcode;

			   if(local_and == 0)
			   {

				trichain[chainverts+0] = idx[i+0];
				trichain[chainverts+1] = idx[i+1];
				trichain[chainverts+2] = idx[i+2];
				chainverts+=3;
			   }
		   }
		   else		
		   for(i=0; i<count; i+=3)
		   {
	   		local_and = context->VertexBuffer[idx[i]].outcode & context->VertexBuffer[idx[i+1]].outcode & context->VertexBuffer[idx[i+2]].outcode;

			if(local_and == 0)
			{

			   if(E_CheckTri(context, &context->VertexBuffer[idx[i]], &context->VertexBuffer[idx[i+1]], &context->VertexBuffer[idx[i+2]], sign) == GL_TRUE)
			   {
				trichain[chainverts+0] = idx[i+0];
				trichain[chainverts+1] = idx[i+1];
				trichain[chainverts+2] = idx[i+2];
				chainverts+=3;
			   }
			}
		   }
		}

	if(chainverts)
		error = W3D_DrawElements(context->w3dContext, W3D_PRIMITIVE_TRIANGLES, W3D_INDEX_ULONG, chainverts, (void *)trichain);

	return;
	}

	free = context->VertexBufferPointer;
	chainverts = 0;
	cnum = 0;
	i = 0;

	do
	{
	   local_and = context->VertexBuffer[idx[i]].outcode & context->VertexBuffer[idx[i+1]].outcode & context->VertexBuffer[idx[i+2]].outcode;

	   local_or = context->VertexBuffer[idx[i]].outcode | context->VertexBuffer[idx[i+1]].outcode | context->VertexBuffer[idx[i+2]].outcode;

	   if(local_and)
	   {
		i+=3;
	   }
	   else
	   {
		if (local_or == 0)
		{
		   if(context->CullFace_State == GL_FALSE)
		   {
		   	visible = GL_TRUE;
		   }
		   else
		   {
	      	   	visible = E_CheckTri(context, &context->VertexBuffer[idx[i]], &context->VertexBuffer[idx[i+1]], &context->VertexBuffer[idx[i+2]], sign);
		   }

	      	   if(visible)
	     	   {
		       trichain[chainverts+0] = idx[i+0];
		       trichain[chainverts+1] = idx[i+1];
		       trichain[chainverts+2] = idx[i+2];
		       chainverts += 3;
		   }
	        }
	        else
	        {
	           if(context->CullFace_State == GL_FALSE || (local_or & MGL_CLIP_NEGW))
	           {
		 	visible = GL_TRUE;
	      	   }
		   else
	           {
			visible = DecideFrontface(context, &(context->VertexBuffer[idx[i]]), &(context->VertexBuffer[idx[i+1]]), &(context->VertexBuffer[idx[i+2]]), sign);
	           }

	           if(visible)
	           {
                   Convert(context, idx[i]);
                   Convert(context, idx[i+1]);
                   Convert(context, idx[i+2]);

                   clip[cnum].numverts = 3;
                   clip[cnum].verts[0] = idx[i];
                   clip[cnum].verts[1] = idx[i+1];
                   clip[cnum].verts[2] = idx[i+2];

                   AE_ClipPoly(context, &clip[cnum], free, local_or);

                   if(clip[cnum].numverts)
                   {
			free = clip[cnum].nextfree;
			cnum++;
                   }
	           }
	        }
	    i+=3;
	    }
	} while (i < count);


	if(chainverts)
	{
		error = W3D_DrawElements(context->w3dContext, W3D_PRIMITIVE_TRIANGLES, W3D_INDEX_ULONG, chainverts, (void*)&trichain[0]);
	}


      if (cnum)
	{
	static PolyBuffer *p;
	static int start;

	   if(verts == NULL)
	   {
		verts = (W3D_Vertex **)malloc(sizeof(W3D_Vertex *) * context->VertexBufferSize);
              	if (!verts) return;
	   }

	   for(i=context->VertexBufferPointer; i<free; i++)
	   {
		V_ToScreen(context, i);
	   } 

	   fan.st_pattern = NULL;
	   fan.tex = context->w3dTexBuffer[context->CurrentBinding];

	   start = 0;
	   i = 0;

		do
		{
		   p = &clip[i];
		   j = 0;

		while (j < p->numverts)
		{
			verts[start+j] = &(context->VertexBuffer[p->verts[j]].v);

			j++;
		}

		fan.v = &verts[start];
		fan.vertexcount = p->numverts;
		start += p->numverts;

		error = W3D_DrawTriFanV(context->w3dContext, &fan);
		i++;
		} while (i < cnum);
      }
}


void E_DrawTriangles(GLcontext context, const int count, const UWORD *idx)
{
      int i, j;
	ULONG local_and, local_or;
      ULONG error;
      static W3D_Vertex **verts = NULL;
      static W3D_TrianglesV fan;
	static ULONG trichain[MGL_MAXVERTS*3]; //should be enough
      static GLboolean visible;
      static int sign;
      int cnum, free, chainverts;

	if(context->ArrayPointer.transformed == GL_TRUE)
	{
		E_DrawTriangles_Locked(context, count, idx);
			return;
	}

	sign = context->CurrentCullSign;

	TransformIndex(context, count, idx);

	free = context->VertexBufferPointer;
	chainverts = 0;
	cnum = 0;
	i = 0;

	do
	{
	   local_and = context->VertexBuffer[idx[i]].outcode & context->VertexBuffer[idx[i+1]].outcode & context->VertexBuffer[idx[i+2]].outcode;

	   local_or = context->VertexBuffer[idx[i]].outcode | context->VertexBuffer[idx[i+1]].outcode | context->VertexBuffer[idx[i+2]].outcode;

	   if(local_and)
	   {
		i+=3;
	   }
	   else
	   {
		if (local_or == 0)
		{
	      	   E_ToScreen(context, idx[i]);
	      	   E_ToScreen(context, idx[i+1]);
	      	   E_ToScreen(context, idx[i+2]);

		   if(context->CullFace_State == GL_FALSE)
		   {
		   	visible = GL_TRUE;
		   }
		   else
		   {
	      	   	visible = E_CheckTri(context, &context->VertexBuffer[idx[i]], &context->VertexBuffer[idx[i+1]], &context->VertexBuffer[idx[i+2]], sign);
		   }

	      	   if(visible)
	     	   {
		   trichain[chainverts+0] = idx[i+0];
		   trichain[chainverts+1] = idx[i+1];
		   trichain[chainverts+2] = idx[i+2];
		   chainverts += 3;
		   }
	        }
	        else
	        {
	           if(context->CullFace_State == GL_FALSE || (local_or & MGL_CLIP_NEGW))
	           {
		 	visible = GL_TRUE;
	      	   }
		   else
	           {
			visible = DecideFrontface(context, &(context->VertexBuffer[idx[i]]), &(context->VertexBuffer[idx[i+1]]), &(context->VertexBuffer[idx[i+2]]), sign);
	           }

	           if(visible)
	           {
                   Convert(context, idx[i]);
                   Convert(context, idx[i+1]);
                   Convert(context, idx[i+2]);

                   clip[cnum].numverts = 3;
                   clip[cnum].verts[0] = idx[i];
                   clip[cnum].verts[1] = idx[i+1];
                   clip[cnum].verts[2] = idx[i+2];

                   AE_ClipPoly(context, &clip[cnum], free, local_or);

                   if(clip[cnum].numverts)
                   {
			free = clip[cnum].nextfree;
			cnum++;
                   }
	           }
	        }
	    i+=3;
	    }
	} while (i < count);


	if(chainverts)
	{
		error = W3D_DrawElements(context->w3dContext, W3D_PRIMITIVE_TRIANGLES, W3D_INDEX_ULONG, chainverts, (void*)&trichain[0]);
	}


      if (cnum)
	{
	static PolyBuffer *p;
	static int start;

	if(verts == NULL)
	{
		verts = (W3D_Vertex **)malloc(sizeof(W3D_Vertex *) * context->VertexBufferSize);
              	if (!verts) return;
	}

	for(i=context->VertexBufferPointer; i<free; i++)
	{
		V_ToScreen(context, i);
	} 

	fan.st_pattern = NULL;
	fan.tex = context->w3dTexBuffer[context->CurrentBinding];

	start = 0;
	i = 0;

		do
		{
		   p = &clip[i];
		   j = 0;

		   while (j < p->numverts)
		   {
			int vert = p->verts[j];
			verts[start+j] = &(context->VertexBuffer[vert].v);

			if(vert < context->VertexBufferPointer)
			{
				V_ToScreen(context, vert);
			}
		   j++;
		   }

		fan.v = &verts[start];
		fan.vertexcount = p->numverts;

		start += p->numverts;

		error = W3D_DrawTriFanV(context->w3dContext, &fan);

		i++;
		} while (i < cnum);
      }
}

void E_DrawPolygon(GLcontext context, const int count, UWORD *idx)
{
	int i,j;
	ULONG error;
	ULONG and_code, or_code;
	PolyBuffer pclip;
      static W3D_Vertex **verts = NULL;
      static W3D_TrianglesV fan;

	if(Clip_Volume_Bypass != GL_FALSE)
	{
	   int size = count;

	   //first check if we are in guardband-mode
	   //and discard offscreen primitives

	   if((Clip_Volume_Bypass > GL_TRUE) && context->VertexBuffer[idx[0]].outcode)
	   {
		ULONG local_and;

		i = size - 2;

		local_and = context->VertexBuffer[idx[0]].outcode & context->VertexBuffer[idx[i]].outcode & context->VertexBuffer[idx[i+1]].outcode;

		if(local_and)
		{
			i--;

			while (i)
			{
			   if((local_and & context->VertexBuffer[idx[i]].outcode) == 0)
				break;
			   i--;
			}
		}

		if(i == 0)
		return;

		size = i+2;
	   }

	   if(context->CullFace_State == GL_TRUE)
	   {
		float x0,y0;
		float x1,y1;
		float x2,y2;
		GLfloat area;

		#define x(a) (context->VertexBuffer[idx[a]].v.x)
		#define y(a) (context->VertexBuffer[idx[a]].v.y)

		x0 = x(0);
		y0 = y(0);
		x1 = x(1) - x0;
		y1 = y(1) - y0;
		x2 = x(2) - x0;
		y2 = y(2) - y0;

		area = y2*x1 - x2*y1;

		i = 1;

		while (i < size-2)
		{
		   x1 = x2;
		   y1 = y2;
		   x2 = x(i+2) - x0;
		   y2 = y(i+2) - y0;

		   area += y2*x1 - x2*y1;
		   i++;
		}		

		if(context->CurrentCullSign > 0)
		area = -area;

		if(area < context->MinTriArea)
		return;

		#undef x
		#undef y
	   }

	   error = W3D_DrawElements(context->w3dContext, W3D_PRIMITIVE_TRIFAN, W3D_INDEX_UWORD, size, (void *)idx);

	return;
	}

	if(context->ArrayPointer.transformed == GL_FALSE)
	{
		TransformIndex(context, count, idx);
	}

	or_code = 0;
	and_code = 0xff;

	for(i=0; i<count; i++)
	{
		and_code &= context->VertexBuffer[idx[i]].outcode;
		or_code |= context->VertexBuffer[idx[i]].outcode;
	}

	if(and_code)
		return;

	if (or_code == 0)
	{
	   if(context->ArrayPointer.transformed == GL_FALSE)
	   {
		E_ToScreenArray(context, count, idx);
	   }

	   if(context->CullFace_State == GL_TRUE)
	   {
		float x0,y0;
		float x1,y1;
		float x2,y2;
		GLfloat area;

		#define x(a) (context->VertexBuffer[idx[a]].v.x)
		#define y(a) (context->VertexBuffer[idx[a]].v.y)

		x0 = x(0);
		y0 = y(0);
		x1 = x(1) - x0;
		y1 = y(1) - y0;
		x2 = x(2) - x0;
		y2 = y(2) - y0;

		area = y2*x1 - x2*y1;

		i = 1;

		while (i < count-2 && fabs(area) < context->MinTriArea)
		{
		   x1 = x2;
		   y1 = y2;
		   x2 = x(i+2) - x0;
		   y2 = y(i+2) - y0;

		   area += y2*x1 - x2*y1;
		   i++;
		}		

		if(context->CurrentCullSign > 0)
		area = -area;

		if(area < context->MinTriArea)
		return;

		#undef x
		#undef y
	   }

	error = W3D_DrawElements(context->w3dContext, W3D_PRIMITIVE_TRIFAN, W3D_INDEX_UWORD, count, (void *)idx);

	return;
	}

	if(verts == NULL)
	{
			verts = (W3D_Vertex **)malloc(sizeof(W3D_Vertex *) * context->VertexBufferSize);
              	if (!verts) return;
	}

	i = 0;
	do
	{
		Convert(context, idx[i]);
		pclip.verts[i] = idx[i];

	i++;
	} while (i < count);

	pclip.numverts = count;

	AE_ClipPoly(context, &pclip, context->VertexBufferPointer, or_code);

	if(pclip.numverts < 3)
		return;

	for(i=context->VertexBufferPointer; i<pclip.nextfree; i++)
	{
		V_ToScreen(context, i);
	}

	if(context->ArrayPointer.transformed == GL_FALSE)
	{
	   int vert;

	   i = 0;
	   do		   
	   {
		vert = pclip.verts[i];

		if(vert > context->VertexBufferPointer)
		V_ToScreen(context, vert);

		verts[i] = &(context->VertexBuffer[vert].v);

	   i++;
	   } while (i < pclip.numverts);
	}
	else
	{
	   i = 0;
	   do		   
	   {
		verts[i] = &(context->VertexBuffer[pclip.verts[i]].v);

	   i++;
	   } while (i < pclip.numverts);
	}

	if(context->CullFace_State == GL_TRUE)
	{
		float x0,y0;
		float x1,y1;
		float x2,y2;
		GLfloat area;

		#define x(a) (context->VertexBuffer[pclip.verts[a]].v.x)
		#define y(a) (context->VertexBuffer[pclip.verts[a]].v.y)

		x0 = x(0);
		y0 = y(0);
		x1 = x(1) - x0;
		y1 = y(1) - y0;
		x2 = x(2) - x0;
		y2 = y(2) - y0;

		area = y2*x1 - x2*y1;

		i = 1;

		while (i < pclip.numverts-2 && fabs(area) < context->MinTriArea)
		{
		   x1 = x2;
		   y1 = y2;
		   x2 = x(i+2) - x0;
		   y2 = y(i+2) - y0;

		   area += y2*x1 - x2*y1;
		   i++;
		}		

		if(context->CurrentCullSign > 0)
		area = -area;

		if(area < context->MinTriArea)
		return;

		#undef x
		#undef y
	}


	fan.tex = context->w3dTexBuffer[context->CurrentBinding];
	fan.st_pattern = NULL;
	fan.v = verts;
	fan.vertexcount = pclip.numverts;

	error = W3D_DrawTriFanV(context->w3dContext, &fan);
}

void E_DrawFlatFan(GLcontext context, const int count, const UWORD *idx)
{
	int i;
	int vnum;
	ULONG error;
	int Vstride;
	int Wstride;
      float *W;
      float *V;
 	MGLVertex *v;

      Vstride = context->ArrayPointer.vertexstride;
      Wstride = context->ArrayPointer.texcoordstride;

 	i = 0;
	do
	{
	vnum = idx[i];

      v = &context->VertexBuffer[vnum];
	V = (float*)(context->ArrayPointer.verts + vnum * Vstride);

         v->v.x = V[0];
         v->v.y = V[1];
         v->v.z = (double)V[2];

         if(context->ClientState & GLCS_TEXTURE)
         {
		W = (float*)((UBYTE*)context->WBuffer + vnum * Wstride);
              *W = 1.0;
         }

	i++;
      } while (i < count);

   error = W3D_DrawElements(context->w3dContext, W3D_PRIMITIVE_TRIFAN, W3D_INDEX_UWORD, count, (void *)idx);
}

//Range guardband-check added 18-05-02 (surgeon)

INLINE ULONG TestRangeGuardBand(GLcontext context, GLuint first, GLsizei count)
{
	int i; 
	ULONG border;
	MGLVertex *v;

	v = &context->VertexBuffer[first];

	i = 0;
	border = 0;

	while (i < count && border == 0)
	{
	   if(v->outcode)
	   {
		float gcw = v->bw * 2.0;

		if (-gcw > v->bx)
			border |= MGL_CLIP_LEFT;
		else if (v->bx > gcw)
			border |= MGL_CLIP_RIGHT;
		if (-gcw > v->by)
			border |= MGL_CLIP_BOTTOM;
		else if (v->by > gcw)
			border |= MGL_CLIP_TOP;
	   }

	   i++;
	   v++;
	}

	return border;
}

//FIXME: avoid redundary projections to a greater extent based on some simple statistics (on/off screen verts).

void GLLockArrays(GLcontext context, GLuint first, GLsizei count)
{
	int check_outcodes;
	ULONG offscreen;

	//pre-transform and code all verts within range:

	context->ArrayPointer.transformed = GL_TRUE;
	context->ArrayPointer.lockfirst = first;
	context->ArrayPointer.locksize  = count;

	offscreen = TransformRange(context, first, count);

	//extra test added 18-05-02:
	if(offscreen && !(offscreen & context->ClipFlags))
	{
		check_outcodes = 1;

		offscreen = TestRangeGuardBand(context, first, count);
	}
	else
	{
		check_outcodes = 0;
	}

	//project verts:

	if (offscreen)
	{
		Clip_Volume_Bypass = GL_FALSE;

		//handles fix2float if needed:

		ProjectRangeByOutcode(context, first, count);


	context->w3dContext->VPMode = W3D_VERTEX_F_F_D;
	context->w3dContext->VertexPointer = (void *)&(context->VertexBuffer[0].v.x);
	}
	else //all vertices on screen
	{
		Clip_Volume_Bypass = GL_TRUE + check_outcodes;

		ProjectRange(context, first, count);

	//we don't need to move w3d vertexpointer
 	//because only the results of the projection
	//are used later on.
	//However, path needs to be seperated from standard
	//because of backface culling.
	}
}

void GLUnlockArrays(GLcontext context)
{
	context->ArrayPointer.transformed = GL_FALSE;
	context->ArrayPointer.lockfirst = 0;
	context->ArrayPointer.locksize = 0;

	if(Clip_Volume_Bypass == GL_FALSE)
	{
	context->w3dContext->VPMode = W3D_VERTEX_F_F_F;
	context->w3dContext->VertexPointer = (void *)&(context->VertexBuffer[0].bx);
	}

	Clip_Volume_Bypass = GL_FALSE;
}

static INLINE void PreDraw(GLcontext context)
{
   if (context->FogDirty && context->Fog_State)
   {
        fog_Set(context);
        context->FogDirty = GL_FALSE;
   }

   if (context->ShadeModel == GL_FLAT && context->UpdateCurrentColor == GL_TRUE)
   {
	context->UpdateCurrentColor = GL_FALSE;
	W3D_SetCurrentColor(context->w3dContext, &context->CurrentColor);
   }

#ifdef AUTOMATIC_LOCKING_ENABLE

   if (context->LockMode == MGL_LOCK_MANUAL)
        return;

   else if (context->LockMode == MGL_LOCK_AUTOMATIC) // Automatic: Lock per primitive
   {
        if (W3D_SUCCESS == W3D_LockHardware(context->w3dContext))
        {
                context->w3dLocked = GL_TRUE;
        }
        else
        {
                printf("Error during LockHardware\n");
        }
   }
   else // Smart: Lock timer based
   {
        if (context->w3dLocked == GL_FALSE)
        {
            if (W3D_SUCCESS != W3D_LockHardware(context->w3dContext))
            {
                return; // give up
            }
            context->w3dLocked = GL_TRUE;
            TMA_Start(&(context->LockTime));
        }
   }

#endif

}

static INLINE void PostDraw(GLcontext context)
{
    context->VertexBufferPointer = 0;

#ifdef AUTOMATIC_LOCKING_ENABLE

    if (context->LockMode == MGL_LOCK_SMART && TMA_Check(&(context->LockTime)) == GL_TRUE)
    {
        // Time to unlock
        W3D_UnLockHardware(context->w3dContext);
        context->w3dLocked = GL_FALSE;
    }
    else if (context->LockMode == MGL_LOCK_AUTOMATIC)
    {
         W3D_UnLockHardware(context->w3dContext);
         context->w3dLocked = GL_FALSE;
    }

#endif

}


void GLDrawElements(GLcontext context, GLenum mode, const GLsizei count, GLenum type, const GLvoid *indices)
{
   int i;
   ULONG error, prim;
   UBYTE *ub;
   ULONG *ul;
   UWORD *idx;

#ifdef VA_SANITY_CHECK
   GLboolean ShadeModel_bypass;
   GLboolean TexCoord_bypass;
#endif

   switch(type)
   {
      case GL_UNSIGNED_SHORT:
			idx = (UWORD*)indices;

	break;

      case GL_UNSIGNED_BYTE:

		ub = (UBYTE *)indices;
		idx = context->ElementIndex;

		idx[0] = ub[0];
		idx[1] = ub[1];
		idx[2] = ub[2];

		i = 3;

		while (i < count)
		{
			idx[i] = ub[i];
		i++;
		}
	break;

      case GL_UNSIGNED_INT:

		ul = (ULONG *)indices;
		idx = context->ElementIndex;

		idx[0] = ul[0];
		idx[1] = ul[1];
		idx[2] = ul[2];

		i = 3;

		while (i < count)
		{
			idx[i] = ul[i];
		i++;
		}

	break;

      default:

		GLFlagError(context, 1, GL_INVALID_ENUM);

	break;
   }

#ifdef VA_SANITY_CHECK

   ShadeModel_bypass = GL_FALSE;

   if(context->ShadeModel == GL_SMOOTH && !(context->ClientState & GLCS_COLOR))
   {
	W3D_SetState(context->w3dContext, W3D_GOURAUD, W3D_DISABLE);
	context->ShadeModel = GL_FLAT;
   	ShadeModel_bypass = GL_TRUE;
   }

#endif

   PreDraw(context);

#ifdef VA_SANITY_CHECK

   TexCoord_bypass = GL_FALSE;

   if(context->Texture2D_State[0] == GL_FALSE || !(context->ClientState & GLCS_TEXTURE))
   {
      Set_W3D_Texture(context->w3dContext, 0, NULL);

	if(context->ClientState & GLCS_TEXTURE)
	{
	   context->ClientState &= ~GLCS_TEXTURE;
	   TexCoord_bypass = GL_TRUE;
	}
   }

#else

   if(context->Texture2D_State[0] == GL_FALSE)
   {
      Set_W3D_Texture(context->w3dContext, 0, NULL);
   }

#endif

   else
   {
        Set_W3D_Texture(context->w3dContext, 0, context->w3dTexBuffer[context->CurrentBinding]);
   }


   if(context->VertexArrayPipeline == GL_FALSE)
   {
	switch(mode)
	{
        case GL_POINTS:
		prim = W3D_PRIMITIVE_POINTS;
		break;
        case GL_LINE_STRIP:
		prim = W3D_PRIMITIVE_LINESTRIP;
		break;
        case GL_LINE_LOOP:
		prim = W3D_PRIMITIVE_LINELOOP;
		break;
        case GL_LINES:
		prim = W3D_PRIMITIVE_LINES;
		break;
        case GL_TRIANGLE_STRIP:
		prim = W3D_PRIMITIVE_TRISTRIP;
		break;
        case MGL_FLATFAN:
	  case GL_POLYGON:
        case GL_TRIANGLE_FAN:
 		prim = W3D_PRIMITIVE_TRIFAN;
		break;
        case GL_TRIANGLES:
		prim = W3D_PRIMITIVE_TRIANGLES;
		break;
        default:
            GLFlagError(context, 1, GL_INVALID_ENUM);
	}

	error = W3D_DrawElements(context->w3dContext, prim, W3D_INDEX_UWORD, count, (void*)&idx[0]);
   }
   else
   {

    if(context->ArrayPointer.transformed == GL_FALSE)
    {
	context->w3dContext->VPMode = W3D_VERTEX_F_F_D;
	context->w3dContext->VertexPointer = (void *)&(context->VertexBuffer[0].v.x);

	context->VertexBufferPointer = context->VertexBufferSize / 2;
	//avoid index-scan. Is this margin a safe assumption ?
    }
    else
    {
	context->VertexBufferPointer = context->ArrayPointer.lockfirst + context->ArrayPointer.locksize;
    }

#if 0
    if((count == 3) && (mode != MGL_FLATFAN))
    {
		E_DrawTriangle(context, idx);
    }
    else
#endif
    switch(mode)
    {
        case GL_TRIANGLE_STRIP:
		E_DrawTriStrip(context, count, idx);
		break;

        case GL_TRIANGLE_FAN:
		E_DrawTriFan(context, count, idx);
		break;

        case GL_TRIANGLES:
		E_DrawTriangles(context, count, idx);
		break;

        case GL_POLYGON:
		E_DrawPolygon(context, count, idx);
		break;

        case MGL_FLATFAN:
		E_DrawFlatFan(context, count, idx);
		break;

        default:
		GLFlagError(context, 1, GL_INVALID_ENUM);
    }

    if(context->ArrayPointer.transformed == GL_FALSE)
    {
    context->w3dContext->VPMode = W3D_VERTEX_F_F_F;
    context->w3dContext->VertexPointer = (void *)&(context->VertexBuffer[0].bx);
    }
   }

   PostDraw(context);

#ifdef VA_SANITY_CHECK

   if(ShadeModel_bypass == GL_TRUE)
   {
	W3D_SetState(context->w3dContext, W3D_GOURAUD, W3D_ENABLE);
	context->ShadeModel = GL_SMOOTH;
   }

   if(TexCoord_bypass == GL_TRUE)
   {
	context->ClientState |= GLCS_TEXTURE;
   }

#endif

}

#ifdef __VBCC__
#undef V_ToScreen
#endif
