/*
 * $Id: vertexarray.c,v 1.3 2001/02/05 16:56:03 tfrieden Exp $
 *
 * $Date: 2001/02/05 16:56:03 $
 * $Revision: 1.3 $
 *
 * (C) 1999 by Hyperion
 * All rights reserved
 *
 * This file is part of the MiniGL library project
 * See the file Licence.txt for more details
 *
 */

/*
** glDrawArrays pipeline by Christian 'SuRgEoN' Michael
** Thanks to Olivier Fabre for bug-hunting
*/

/*
** revised 07-04-02:
**
** In some cases A_DrawTriangles didn't use the correct
** start position during backface-culling
**
** Support for GL_EXT_compiled_vertex_array was added.
**
** When Clip_Volume_Bypass is GL_FALSE, it will wrap
** to GLDrawElements (at the very beginning of GLDrawArrays,
** which is ofcourse not an optimal solution.
** Anyways, the use if glDrawArrays is probably rare in case
** of compiled arrays, but it should be supported.
** One possible solution to this is to make the default
** W3D_VertexPointer point to the W3D_Vertex struct inside
** the vertexbuffer like for elements, but it would probably
** lower the general performance of glDrawArrays.
*/


#include "sysinc.h"
#include "vertexarray.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>


/*

NOTE:
	Transformation and clipping pipeline can be turned on/off with glDisable/glEnable(MGL_ARRAY_TRANSFORMATIONS) before the pointers are set.

The MGL_FLATFAN will work regardless of pipeline state.

Tricky stuff:

Problem 1: We don't want to copy texcoords unless we really have to (clipping) and we don't want to write the w-coords to application-arrays since a texcoordpointer is allowed to have a stride of 2.

	Current solution:
	We allocate some memory exclusively for the w-coords
	in order to cope with any texcoordstride.
	The relative w-coord buffer offset is calculated
	whenever texcoordpointer is set.

Problem 2: Clipping events are expensive because texcoords and colors currently need to be converted and copied to the vertexbuffer.

	Solution: ?? Currently, a sort of guardband is used
		     in order to avoid clipping in most cases.


TODO:

- Implement remaining GL primitives.
- Implement MGL_UBYTE_ARGB color-format (Voodoo3 native)
- Write pointer-wrapper for glInterleavedArrays and proper
  optimized conversion-routines for clipping.
- Implement multitexturing (virtual TMU for now).

*/



//NYI:

void A_DrawPoints        (GLcontext context, const int first, const int count);
void A_DrawLines         (GLcontext context, const int first, const int count);
void A_DrawLineStrip     (GLcontext context, const int first, const int count);
void A_DrawLineLoop      (GLcontext context, const int first, const int count);

void A_DrawQuads         (GLcontext context, const int first, const int count);
void A_DrawQuadStrip      (GLcontext context, const int first, const int count);

//implemented:

void A_DrawTriFan	   (GLcontext context, const int first, const int count);
void A_DrawTriStrip	   (GLcontext context, const int first, const int count);
void A_DrawTriangles     (GLcontext context, const int first, const int count);
void A_DrawPolygon       (GLcontext context, const int first, const int count);
void A_DrawFlatFan       (GLcontext context, const int first, const int count);


extern void TMA_Start(LockTimeHandle *handle);
extern GLboolean TMA_Check(LockTimeHandle *handle);
extern void fog_Set(GLcontext context);
static INLINE void PreDraw(GLcontext context);
static INLINE void PostDraw(GLcontext context);


static GLboolean Reset_W3D_VertexPointer = GL_TRUE;

int A_TransformArray (GLcontext context, const int first, const int size);

void A_ToScreenArray(GLcontext context, const int first, const int size);


extern void m_CombineMatrices(GLcontext context);


//Culling:

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


//Clipping (convert color and texcoords to vertexbuffer)

void Convert_F_RGB(GLcontext context, int i);
void Convert_F_RGBA(GLcontext context, int i);
void Convert_UB_RGB(GLcontext context, int i);
void Convert_UB_RGBA(GLcontext context, int i);
void Convert_UB_BGR(GLcontext context, int i);
void Convert_UB_BGRA(GLcontext context, int i);
void Convert_UB_ARGB(GLcontext context, int i);

//pointer to color/texcoord conversion routine for clipping events:

Convfn Convert = (Convfn)Convert_F_RGBA;

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



//stuff for compiled arrays:  added 07-04-2002

extern GLboolean Clip_Volume_Bypass;

#define MAX_ELEMENTS 16384 //should be enough

static UWORD e_wrap[MAX_ELEMENTS]; //should be enough 

//called from MGLInit:

void Init_ArrayToElements_Warpper(void)
{
	int i;

	for (i=0; i<MAX_ELEMENTS; i++)
		e_wrap[i] = i;
}

//called at the very beginning of GLDrawArrays in case clipping is needed with compiled arrays:

extern void GLDrawElements(GLcontext context, GLenum mode, const GLsizei count, GLenum type, const GLvoid *indices);

// end of compiled arrays support


int A_TransformArray (GLcontext context, const int first, const int size)
{
   int i;
   ULONG and_code, or_code, guard_band;

        #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

        #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 *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);

     and_code = 0xff;
     or_code = 0;

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

     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;
        }

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

      v->outcode = local_outcode;
      and_code &= local_outcode;
      or_code  |= local_outcode;

     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);


     //prepare culling;

     and_code = 0xff;
     or_code = 0;

     v = &context->VertexBuffer[first];

     i = size;

     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;
        }

        and_code &= local_outcode;
        or_code  |= local_outcode;
        v->outcode = local_outcode;

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

	#undef CLIP_EPS	
   }

   #undef a

   if (and_code)
	return -1;

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

	i = size;
	guard_band = 0;

	v = &context->VertexBuffer[first];

	do
	{

	  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;
  	  }

	v++;
	} while (--i && guard_band == 0);

   return (int)guard_band;
   }
}


void A_ToScreenArray(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);
   }
}



//fix to float conversion

INLINE void ConvertFixverts(GLcontext context, const int first, const int count)
{
	const float f = 1.0/32768.f;
	MGLVertex *v = &context->VertexBuffer[first];
	int i = count;

	do
	{
		v->bx = v->bx * f;
		v->by = v->by * f;
		v->bz = v->bz * f;
		v->bw = v->bw * f;

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


// special case color-copy / texcoord-conversion routines


void Convert_F_RGB(GLcontext context, int i)
{
   MGLVertex *v;

   v = &context->VertexBuffer[i];

   if(context->ClientState & GLCS_TEXTURE)
   {
   float *tex = (float*)(context->ArrayPointer.texcoords + i * context->ArrayPointer.texcoordstride);

	v->v.u = tex[0] * (float)context->w3dTexBuffer[context->CurrentBinding]->texwidth;
	v->v.v = tex[1] * (float)context->w3dTexBuffer[context->CurrentBinding]->texheight;
   }

   if(context->ShadeModel == GL_SMOOTH)
   {
   float *col = (float*)(context->ArrayPointer.colors + i * context->ArrayPointer.colorstride);;

      v->v.color.r = col[0];
      v->v.color.g = col[1];
      v->v.color.b = col[2];
	v->v.color.a = 1.0;
   }
}


void Convert_F_RGBA(GLcontext context, int i)
{
   MGLVertex *v;

   v = &context->VertexBuffer[i];

   if(context->ClientState & GLCS_TEXTURE)
   {
   float *tex = (float*)(context->ArrayPointer.texcoords + i * context->ArrayPointer.texcoordstride);

	v->v.u = tex[0] * (float)context->w3dTexBuffer[context->CurrentBinding]->texwidth;
	v->v.v = tex[1] * (float)context->w3dTexBuffer[context->CurrentBinding]->texheight;
   }

   if(context->ShadeModel == GL_SMOOTH)
   {
   float *col = (float*)(context->ArrayPointer.colors + i * context->ArrayPointer.colorstride);;

      v->v.color.r = col[0];
      v->v.color.g = col[1];
      v->v.color.b = col[2];
      v->v.color.a = col[3];
   }
}


void Convert_UB_RGB(GLcontext context, int i)
{
   MGLVertex *v;

   v = &context->VertexBuffer[i];

   if(context->ClientState & GLCS_TEXTURE)
   {
   float *tex = (float*)(context->ArrayPointer.texcoords + i * context->ArrayPointer.texcoordstride);

	v->v.u = tex[0] * (float)context->w3dTexBuffer[context->CurrentBinding]->texwidth;
	v->v.v = tex[1] * (float)context->w3dTexBuffer[context->CurrentBinding]->texheight;
   }

   if(context->ShadeModel == GL_SMOOTH)
   {
   UBYTE *col = (context->ArrayPointer.colors + i * context->ArrayPointer.colorstride);
   float f = 1.0/255.0;

      v->v.color.r = (float)col[0]*f;
      v->v.color.g = (float)col[1]*f;
      v->v.color.b = (float)col[2]*f;
      v->v.color.a = 1.0;
   }
}


void Convert_UB_RGBA(GLcontext context, int i)
{
   MGLVertex *v;

   v = &context->VertexBuffer[i];

   if(context->ClientState & GLCS_TEXTURE)
   {
   float *tex = (float*)(context->ArrayPointer.texcoords + i * context->ArrayPointer.texcoordstride);

	v->v.u = tex[0] * (float)context->w3dTexBuffer[context->CurrentBinding]->texwidth;
	v->v.v = tex[1] * (float)context->w3dTexBuffer[context->CurrentBinding]->texheight;
   }

   if(context->ShadeModel == GL_SMOOTH)
   {
   UBYTE *col = (context->ArrayPointer.colors + i * context->ArrayPointer.colorstride);
   float f = 1.0/255.0;

      v->v.color.r = (float)col[0]*f;
      v->v.color.g = (float)col[1]*f;
      v->v.color.b = (float)col[2]*f;
      v->v.color.a = (float)col[3]*f;
   }
}


void Convert_UB_BGR(GLcontext context, int i)
{
   MGLVertex *v;

   v = &context->VertexBuffer[i];

   if(context->ClientState & GLCS_TEXTURE)
   {
   float *tex = (float*)(context->ArrayPointer.texcoords + i * context->ArrayPointer.texcoordstride);

	v->v.u = tex[0] * (float)context->w3dTexBuffer[context->CurrentBinding]->texwidth;
	v->v.v = tex[1] * (float)context->w3dTexBuffer[context->CurrentBinding]->texheight;
   }

   if(context->ShadeModel == GL_SMOOTH)
   {
   UBYTE *col = (context->ArrayPointer.colors + i * context->ArrayPointer.colorstride);
   float f = 1.0/255.0;

      v->v.color.b = (float)col[0]*f;
      v->v.color.g = (float)col[1]*f;
      v->v.color.r = (float)col[2]*f;
      v->v.color.a = 1.0;
   }
}

void Convert_UB_BGRA(GLcontext context, int i)
{
   MGLVertex *v;

   v = &context->VertexBuffer[i];

   if(context->ClientState & GLCS_TEXTURE)
   {
   float *tex = (float*)(context->ArrayPointer.texcoords + i * context->ArrayPointer.texcoordstride);

	v->v.u = tex[0] * (float)context->w3dTexBuffer[context->CurrentBinding]->texwidth;
	v->v.v = tex[1] * (float)context->w3dTexBuffer[context->CurrentBinding]->texheight;
   }

   if(context->ShadeModel == GL_SMOOTH)
   {
   UBYTE *col = (context->ArrayPointer.colors + i * context->ArrayPointer.colorstride);
   float f = 1.0/255.0;

      v->v.color.b = (float)col[0]*f;
      v->v.color.g = (float)col[1]*f;
      v->v.color.r = (float)col[2]*f;
      v->v.color.a = (float)col[3]*f;
   }
}

void Convert_UB_ARGB(GLcontext context, int i)
{
   MGLVertex *v;

   v = &context->VertexBuffer[i];

   if(context->ClientState & GLCS_TEXTURE)
   {
   float *tex = (float*)(context->ArrayPointer.texcoords + i * context->ArrayPointer.texcoordstride);

	v->v.u = tex[0] * (float)context->w3dTexBuffer[context->CurrentBinding]->texwidth;
	v->v.v = tex[1] * (float)context->w3dTexBuffer[context->CurrentBinding]->texheight;
   }

   if(context->ShadeModel == GL_SMOOTH)
   {
   UBYTE *col = (context->ArrayPointer.colors + i * context->ArrayPointer.colorstride);
   float f = 1.0/255.0;

      v->v.color.a = (float)col[0]*f;
      v->v.color.r = (float)col[1]*f;
      v->v.color.g = (float)col[2]*f;
      v->v.color.b = (float)col[3]*f;
   }
}


GLboolean DecideFrontface(GLcontext context, const MGLVertex *a, const MGLVertex *b, const MGLVertex *c, int sign)
{
        float a1,a2,b1,b2,r;
        float aw,bw,cw;

        aw = 1.0 / a->bw;
        bw = 1.0 / b->bw;
        cw = 1.0 / c->bw;

        a1 = a->bx*aw - b->bx*bw;
        a2 = a->by*aw - b->by*bw;
        b1 = c->bx*cw - b->bx*bw;
        b2 = c->by*cw - b->by*bw;

        r  = (a1*b2-a2*b1);

#if 0 //this test eliminates less than 1 in 1000 triangles

        #define EPSILON (1e-5)

        if (fabs(a1) < EPSILON && fabs(a2) < EPSILON)
        {
                return GL_FALSE;
        }
        if (fabs(b1) < EPSILON && fabs(b2) < EPSILON)
        {
                return GL_FALSE;
        }

#endif

        if((sign < 0 && r < 0.0) || (sign > 0 && r > 0.0))
                return GL_FALSE;
        else
                return GL_TRUE;
}


INLINE void A_ToScreen(GLcontext context, int vnum)
{
	UBYTE *pointer;
	float *wa;

	float w = 1.0/context->VertexBuffer[vnum].bw;

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

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

	pointer = (UBYTE*)context->WBuffer + vnum * context->ArrayPointer.texcoordstride;
	wa = (float*)pointer;
	*wa = w;
}



//avoid double projections:

#ifdef __VBCC__

#define A_ToV(ctx, e) {\
MGLVertex *v = &ctx->VertexBuffer[e];\
v->v.x = v->bx;\
v->v.y = v->by;\
v->v.z = v->bz;\
v->v.w = 1.0 / v->bw; \
}

#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 A_ToV(GLcontext context, int e)
{
	context->VertexBuffer[e].v.x = (W3D_Float)context->VertexBuffer[e].bx;
	context->VertexBuffer[e].v.y = (W3D_Float)context->VertexBuffer[e].by;
	context->VertexBuffer[e].v.z = (W3D_Float)context->VertexBuffer[e].bz;
	context->VertexBuffer[e].v.w = (W3D_Float)(1.0 / context->VertexBuffer[e].bw);
}

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 A_DrawPoints(GLcontext context, const int first, const int count)
{
}


void A_DrawLines(GLcontext context, const int first, const int count)
{
}


void A_DrawLineStrip(GLcontext context, const int first, const int count)
{
}


void A_DrawLineLoop(GLcontext context, const int first, const int count)
{
}


void A_DrawQuads(GLcontext context, const int first, const int count)
{
}


void A_DrawQuadStrip(GLcontext context, const int first, const int count)
{
}


void A_DrawTriFan(GLcontext context, const int first, const int count)
{
      int i,j;
	int size;
	int outcode;
      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];
      int triangle;
      static PolyBuffer polys[64];
      PolyBuffer clip[64];
      int pnum, cnum, backface, prevcopy, free;
      int sign;


	if(Clip_Volume_Bypass != GL_FALSE)
	{
	//compiled arrays

	   size = count;

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

	   if(Clip_Volume_Bypass == GL_TRUE + 1)
	   {
		i = first + size - 2;

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

			if(local_and == 0)
				break;

		size--;
		i--;
		} while (i > first);

		if(size < 3)
			return;
	   }

	   if(context->CullFace_State == GL_FALSE)
	   {
		error = W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRIFAN, first, size);
	   }
	   else
	   {
	   int newfirst;
	   float fsign;
	   float area;
	   float x1,x2;
	   float y1,y2;

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

		fsign = (float)-context->CurrentCullSign;

		backface = 0;
		newfirst = 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)
                   	{
                	        newfirst++;
                	        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(newfirst == i)
					newfirst++;
				  else
	                              	backface++;
      	                  }
      	                  else
                        	  {
                                backface = 0;
                                area += area2;
                        	  }

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

		if(area < context->MinTriArea)
		return;

		size -= backface; //cut end

		if( newfirst )
		{
		
			size -= newfirst;
			newfirst += first;

			e_wrap[newfirst] = first;

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

			e_wrap[newfirst] = newfirst;
		}
		else
		{
			error = W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRIFAN, first, size);
		}
	   #undef x
	   #undef y
	   }
	return;
	}

	sign = context->CurrentCullSign;

	outcode = A_TransformArray(context, first, count);
	

	  if(outcode < 0)
	  {
		return;
	  }

	  if (outcode == 0)
	  {
		size = count;

		A_ToScreenArray(context, first, count);

		if(context->CullFace_State == GL_TRUE)
		{
		int newfirst;
		float fsign;
		float area;
		float x1,x2;
		float y1,y2;

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

		fsign = (float)-sign;

		backface = 0;
		newfirst = 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)
                	   	{
                	        newfirst++;
                	        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(newfirst == i)
					newfirst++;
				  else
	                              	backface++;
      	                  }
      	                  else
                        	  {
                                backface = 0;
                                area += area2;
                        	  }

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

			if(area < context->MinTriArea)
			return;

			size -= backface; //cut end

			if( newfirst )
			{
				size -= newfirst;
				newfirst += first;

				e_wrap[newfirst] = first;

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

				e_wrap[newfirst] = newfirst;

				return;
			}

		#undef x
		#undef y
		}

		error = W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRIFAN, first, size);

	  return;
	  }


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

	  if(context->ArrayPointer.FixpointTrans == GL_TRUE)
	  {
		ConvertFixverts(context, first, count);
	  }

        backface = 0;
        triangle = 0;
        i = first+1;

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

                local_or = context->VertexBuffer[first].outcode
                        | context->VertexBuffer[i].outcode
                        | context->VertexBuffer[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 (triangle < count - 2);
   }
   else
   {
        do
        {
                local_and = context->VertexBuffer[first].outcode
                        & context->VertexBuffer[i].outcode
                        & context->VertexBuffer[i+1].outcode;

                local_or = context->VertexBuffer[first].outcode
                        | context->VertexBuffer[i].outcode
                        | context->VertexBuffer[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[first]), &(context->VertexBuffer[i]), &(context->VertexBuffer[i+1]), sign);

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


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

	  size = count - backface;
	  context->VertexBufferPointer -= backface;

     	  Convert(context, first);

        prevcopy = 0;
        pnum = 0;
        cnum = 0;
        free = context->VertexBufferPointer;
        triangle = 0; i = first + 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] = first;
                                clip[cnum].verts[1] = i + 0;
                                clip[cnum].verts[2] = i + 1;

                                if(prevcopy != i)
                                Convert(context, i+0);

                                Convert(context, 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] = first;
                                polys[pnum].verts[1] = i+0;
                                polys[pnum].verts[2] = i+1;
        
                                triangle++; i++;

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

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

//Project to screen and draw:

   //avoid some double-projections

   if(cnum)
   {
   for(i=0; i<size; i++)
	visible[first+i] = 0;

   //project clipped verts without index lookup

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

   if(pnum) //draw buffered unclipped trifans
   {
        PolyBuffer *p;

        p = &polys[0];
        i = p->verts[1];

        A_ToScreen(context, first);
        A_ToScreen(context, i);
        A_ToScreen(context, i+1);

        visible[first] = 1;
        visible[i] = 1;
        visible[i+1] = 1;

        if(p->numverts > 3)
        {
        int last = p->verts[p->numverts-1];
        i+=2;
                do
                {
                        A_ToScreen(context, i);
                        visible[i] = 1;
                i++;
                } while (i <= last);
        }

        if(p->verts[1] == (first+1))
        {
        error = W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRIFAN, first, p->numverts);
        }
        else
        {
        error = W3D_DrawElements(context->w3dContext, W3D_PRIMITIVE_TRIFAN, W3D_INDEX_ULONG, p->numverts, (void*)p->verts);
        }

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

                A_ToScreen(context, i);
                A_ToScreen(context, i+1);

                visible[i] = 1;
                visible[i+1] = 1;

                if(p->numverts > 3)
                {
                int last = p->verts[p->numverts-1];
                i+=2;

                   do
                   {
                        A_ToScreen(context, i);
                        visible[i] = 1;
                   i++;
                   } while (i <= last);
                }

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

        j++;
        }
   }

   if(cnum) //draw clipped triangles
   {
   int first = 0;

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

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

          for (i=0; i<p->numverts; i++)
          {
                int vert = p->verts[i];

                if(vert < context->VertexBufferPointer)
                {
                   switch(visible[vert])
                   {
                        case 2:
                                break;
                        case 1:
                                A_ToV(context, vert);
                                visible[vert] = 2;
                                break;
                        default:
                                V_ToScreen(context, vert);
                                visible[vert] = 2;
                                break;
                   }
                }

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

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

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

          first += p->numverts;

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


void A_DrawTriStrip(GLcontext context, const int first, const int count)
{
      int i,j;
	int size;
	int outcode;
      ULONG local_or, local_and;
      ULONG error;
      static W3D_Vertex **verts = NULL;
      static W3D_TrianglesV fan;
      static GLboolean visible[MGL_MAXVERTS];
      static ULONG    complete[MGL_MAXVERTS];
      int triangle;
      static PolyBuffer polys[64];
      PolyBuffer clip[64];
      int pnum, cnum, backface, free, prevcopy;
      int sign;

	if(Clip_Volume_Bypass != GL_FALSE)
	{
	//compiled arrays
	size = count;

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

	   if(Clip_Volume_Bypass == GL_TRUE + 1)
	   {
		i = first + size - 3;
		do			
		{
			local_and = context->VertexBuffer[i].outcode & context->VertexBuffer[i+1].outcode & context->VertexBuffer[i+2].outcode;

			if(local_and == 0)
				break;

		size--;
		i--;
		} while (i >= first);

		if(size < 3)
			return;
	   }

	   if(context->CullFace_State == GL_FALSE)
	   {
		error = W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRISTRIP, first, size);
	   }
	   else
	   {
	   int newfirst;
	   float fsign;
	   float area;
	   float x1,x2;
	   float y1,y2;

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

		fsign = (float)-context->CurrentCullSign;

		backface = 0;
		newfirst = 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)
             	   	{
             	        	newfirst++;
             	        	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(newfirst == i)
					newfirst++;
				  else
	                              	backface++;
				}
				else
 				{
                                backface = 0;
                                area += area2;
				}

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

	   if(area < context->MinTriArea)
		return;

	   size -= newfirst + backface;
	   newfirst += first;

	   error = W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRISTRIP, newfirst, size);

	   #undef x
	   #undef y
	   }
	return;
	}

	sign = context->CurrentCullSign;

	outcode = A_TransformArray(context, first, count);

	  if (outcode < 0)
	  {
		return;
	  }

	  if (outcode == 0)
	  {
		int newfirst;
		size = count;

		A_ToScreenArray(context, first, count);

		if(context->CullFace_State == GL_FALSE)
		{
			newfirst = first;
		}
		else
		{
		#define x(a) (context->VertexBuffer[first+a].bx)
		#define y(a) (context->VertexBuffer[first+a].by)

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

		fsign = (float)-sign;

		backface = 0;
		newfirst = 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)
                	   	{
                	        newfirst++;
                	        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(newfirst == i)
					newfirst++;
				  else
	                              	backface++;
      	                  }
      	                  else
                        	  {
                                backface = 0;
                                area += area2;
                        	  }

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

		if(area < context->MinTriArea)
			return;

		size -= newfirst + backface;
		newfirst += first;

		#undef x
		#undef y
		}
	
		   error = W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRISTRIP, newfirst, size);

	  return;
	  }

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

	  if(context->ArrayPointer.FixpointTrans == GL_TRUE)
	  {
		ConvertFixverts(context, first, count);
	  }


        backface = 0;
        triangle = 0;
        i = first;

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

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

                if (local_and == 0)
                {
			complete[triangle] = local_or;
			visible[triangle] = GL_TRUE;
			backface = 0;
                }
                else
                {
                        visible[triangle] = GL_FALSE;
                        backface++;
                }

           i++;
           triangle++;
        } while (triangle < count - 2);
   }
   else
   {
        do
        {
                local_and = context->VertexBuffer[i+0].outcode
                                  & context->VertexBuffer[i+1].outcode
                                  & context->VertexBuffer[i+2].outcode;

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

                if (local_and == 0)
                {
                complete[triangle] = local_or;

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

                        if(!visible[triangle])
                        	backface++;
			  else
			  	backface = 0;
                   }
                }
                else
                {
                        visible[triangle] = GL_FALSE;
                        backface++;
                }

                sign = -sign; //reverse order

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

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

	size = count - backface;
	context->VertexBufferPointer -= backface;

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

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

//this element is never shared with next triangle:
                                if(prevcopy == i+1)
                                {
                                   Convert(context, i+2);
                                }

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

//this element is never shared with previous triangle:

                                prevcopy = i+2;

                           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] = i+0;
                                //polys[pnum].verts[1] = i+1;
                                //polys[pnum].verts[2] = i+2;

                                triangle++; i++;

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

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



//Project to screen and Draw:

   //avoid some double-projections

   if(cnum)
   {
   for(i=0; i < size; i++)
	visible[first+i] = 0;

   //project clipped verts without need for index lookup

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

   if(pnum) //draw buffered unclipped tristrips
   {
        PolyBuffer *p;

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

        A_ToScreen(context, i);
        A_ToScreen(context, i+1);
        A_ToScreen(context, i+2);

        visible[i] = 1;
        visible[i+1] = 1;
        visible[i+2] = 1;

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

                do
                {
                        A_ToScreen(context, i);
                        visible[i] = 1;
                i++;
                } while (i < last);
        }

        error = W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRISTRIP, p->verts[0], p->numverts);

        j = 1;
        while (j < pnum)
        {
        int prev_projected = p->verts[0] + p->numverts-1;

                p = &polys[j];
                i = p->verts[0];

                if (i != prev_projected)
                {
                        A_ToScreen(context, i);
                        visible[i] = 1;
                }

                A_ToScreen(context, i+1);
                A_ToScreen(context, i+2);

                visible[i+1] = 1;
                visible[i+2] = 1;

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

                   do
                   {
                        A_ToScreen(context, i);
                        visible[i] = 1;
                   i++;
                   } while (i < last);
                }

        error = W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRISTRIP, p->verts[0], p->numverts);

        j++;
        }
   }

   if(cnum) //draw clipped triangles
   {
   int first = 0;

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

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

          for (i=0; i<p->numverts; i++)
          {
                int vert = p->verts[i];

                if(vert < context->VertexBufferPointer)
                {
                   switch(visible[vert])
                   {
                        case 2:
                                break;
                        case 1:
                                A_ToV(context, vert);
                                visible[vert] = 2;
                                break;
                        default:
                                V_ToScreen(context, vert);
                                visible[vert] = 2;
                                break;
                   }
                }
          verts[i+first] = &(context->VertexBuffer[vert].v);
          }

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

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

          first += p->numverts;

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


void A_DrawTriangles(GLcontext context, const int first, const int count)
{
      int i,j;
	int outcode;
      static ULONG   complete;
      ULONG error;
      static W3D_Vertex **verts = NULL;
      static GLboolean visible;
      PolyBuffer clip[128]; //should be enough
      static int sign;
      int cnum, free, start;
	static int chainverts;


	if(Clip_Volume_Bypass != GL_FALSE)
	{
	//compiled arrays

	   if(context->CullFace_State == GL_FALSE)
	   {
			error = W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRIANGLES, first, count);
	   }
	   else
	   {
	   int start;
	   float area;
	   float x1,y1;
	   float x2,y2;

	   #define x(i) (context->VertexBuffer[first+i].bx)
	   #define y(i) (context->VertexBuffer[first+i].by)
 
		start = 0;
		chainverts = 0;
		sign = context->CurrentCullSign;

		for(i=0; i<count; i+=3)
		{
		   if(Clip_Volume_Bypass == GL_TRUE + 1)
		   {
			if(context->VertexBuffer[first+i].outcode & context->VertexBuffer[first+i+1].outcode & context->VertexBuffer[first+i+2].outcode)
			{
			   if(chainverts)
			   {
				error = W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRIANGLES, first + start, chainverts);

				chainverts = 0;
			   }

			continue;
			}
		   }

			x1 = x(i+1) - x(i);
			y1 = y(i+1) - y(i);
			x2 = x(i+2) - x(i);
			y2 = y(i+2) - y(i);

			area = y2*x1 - x2*y1;

			if(sign > 0)
			area = -area;

			if(area < context->MinTriArea)
			{
			   if(chainverts)
			   {
				error = W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRIANGLES, first + start, chainverts);

				chainverts = 0;
			   }
			}
			else
			{
			   if(chainverts == 0)
			   {
				start = i;
			   }

			   chainverts += 3;
			}
		}

		if(chainverts) //draw remainder
		{
			error = W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRIANGLES, first + start, chainverts);
		}

	   #undef x
	   #undef y
	   }
	return;
	}

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

	sign = context->CurrentCullSign;
	chainverts = 0;
	cnum = 0;
	free = context->VertexBufferPointer;
	start = first;
	i = first;

	do
	{
	   outcode = A_TransformArray(context, i, 3);

	   if(outcode < 0)
	   {
		if(chainverts)
		{
			error = W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRIANGLES, start, chainverts);

		chainverts = 0;
		}

	   i+=3;
	   }
	   else
	   {
		complete = (ULONG)outcode;

      	if(complete == 0)
		{
	      	   A_ToScreenArray(context, i, 3);

		   if(context->CullFace_State == GL_FALSE)
		   {
			visible = GL_TRUE;
		   }
		   else
		   {
		   #define x(a) (context->VertexBuffer[a].bx)
		   #define y(a) (context->VertexBuffer[a].by)

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

			x1 = x(i+1) - x(i);
			y1 = y(i+1) - y(i);
			x2 = x(i+2) - x(i);
			y2 = y(i+2) - y(i);

			area = y2*x1 - x2*y1;

			if(sign > 0)
			area = -area;

			if(area < context->MinTriArea)
				visible = GL_FALSE;
			else
				visible = GL_TRUE;

		   #undef x
		   #undef y
		   }

	      	   if(visible)
	      	   {
			if(chainverts == 0)
			{
				start = i;
				chainverts = 3;
			}
			else
			{
				chainverts += 3;
			}
		   }
		   else if (chainverts)
		   {
			error = W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRIANGLES, start, chainverts);

			chainverts = 0;
		   }
	   i+=3;
	   }
	   else
	   {
		   if(chainverts)
		   {
			error = W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRIANGLES, start, chainverts);

		        chainverts = 0;
		   }


		   if(context->ArrayPointer.FixpointTrans == GL_TRUE)
		   {
			ConvertFixverts(context, i, 3);
		   }

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

	           if(visible)
	           {
                   Convert(context, i+0);
                   Convert(context, i+1);
                   Convert(context, i+2);

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

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

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


	if(chainverts) //draw remainder of unclipped triangles
	{
		error = W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRIANGLES, start, chainverts);
	}

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

	fan.st_pattern = 0;
	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);
			V_ToScreen(context, p->verts[j]);
		   j++;
		   }

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

		   start += p->numverts;

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

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

#if 0
void A_DrawTriangle(GLcontext context, const int first)
{
	int i;
	int outcode;
	ULONG complete;
      ULONG error;
      static W3D_Vertex *verts[16];
      static W3D_TrianglesV fan;
      PolyBuffer clip;


	if(Clip_Volume_Bypass != GL_FALSE)
	{
	   if(context->CullFace_State == GL_FALSE)
	   {
		error = W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRIANGLES, first, 3);
	   }
	   else
	   {
	   float area;
	   float x1,y1;
	   float x2,y2;

	   #define x(i) (context->VertexBuffer[first+i].bx)
	   #define y(i) (context->VertexBuffer[first+i].by)
 
			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;

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

			if(area > context->MinTriArea)
			{
				error = W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRIANGLES, first, 3);
			}
	   #undef x
	   #undef y
	   }
	return;
	}

	outcode = A_TransformArray(context, first, 3);

	if(outcode < 0)
	{
		return;
	}
	else if (outcode == 0)
	{
	   A_ToScreenArray(context, first, 3);

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

	   #define x(i) (context->VertexBuffer[first+i].bx)
	   #define y(i) (context->VertexBuffer[first+i].by)
 
			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;

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

			if(area < context->MinTriArea)
				return;
	   #undef x
	   #undef y
	   }

	error = W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRIANGLES, first, 3);

	return;
	}

	complete = (ULONG)outcode;

	if(context->CullFace_State == GL_TRUE && !(complete & MGL_CLIP_NEGW))
	{
		if(DecideFrontface(context, &(context->VertexBuffer[first]), &(context->VertexBuffer[first+1]), &(context->VertexBuffer[first+2]), context->CurrentCullSign) == GL_FALSE)
		return;
	}

	Convert(context, first);
	Convert(context, first+1);
	Convert(context, first+2);

	clip.numverts = 3;
	clip.verts[0] = first;
	clip.verts[1] = first+1;
	clip.verts[2] = first+2;

	AE_ClipPoly(context, &clip, context->VertexBufferPointer, complete);

	if(clip.numverts < 3)
		return;

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

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

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

void A_DrawPolygon(GLcontext context, const int first, const int count)
{
	int i,j;
	int outcode;
	ULONG complete;
	ULONG error;
	GLboolean visible;	
	PolyBuffer clip;
      static W3D_Vertex **verts = NULL;
      static W3D_TrianglesV fan;


	if(Clip_Volume_Bypass != GL_FALSE)
	{
	//compiled arrays

	   if(Clip_Volume_Bypass == GL_TRUE + 1)
	   {
		ULONG and_code;

		and_code = 0xff;

		for(i=first; i<first+count; i++)
			and_code &= context->VertexBuffer[i].outcode;

		if(and_code)
			return;

	   }

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

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

		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_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRIFAN, first, count);

	return;
	}

	outcode = A_TransformArray(context, first, count);

	if(outcode < 0)
		return;

	else if(outcode == 0)
	{
	   A_ToScreenArray(context, first, count);

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

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

		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_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRIFAN, first, count);
	}
	else
	{
	complete = (ULONG)outcode;

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


	        if(context->ArrayPointer.FixpointTrans == GL_TRUE)
	        {
		   ConvertFixverts(context, first, count);
	        }

		i = first;
		j = 0;

		while (i < first + count)
		{
			Convert(context, i);
			clip.verts[j++] = i;
		i++;
		}

		clip.numverts = count;

		AE_ClipPoly(context, &clip, context->VertexBufferPointer, complete);

		if(clip.numverts < 3)
			return;

		i = 0;
		do
		{
			verts[i] = &(context->VertexBuffer[clip.verts[i]].v);

		   	V_ToScreen(context, clip.verts[i]);
		i++;
		} while (i < clip.numverts);


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

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

		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 < clip.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 = 0;
	fan.v = verts;
	fan.vertexcount = clip.numverts;

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


void A_DrawFlatFan(GLcontext context, const int first, const int count)
{
	int i;
	ULONG error;
 	MGLVertex *v;

	int Vstride;
	UBYTE *Vpointer;
	int Wstride;
	UBYTE *Wpointer;
      float *W;

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

	Wpointer = (UBYTE*)context->WBuffer + first * Wstride;
	Vpointer = context->ArrayPointer.verts + first * Vstride;

   v = &context->VertexBuffer[first];

   if(context->ArrayPointer.FixpointTrans == GL_TRUE)
   {
      int *V;
	i = count;

	do
	{
         V = (int*)Vpointer;

         v->bx = (float)V[0];
         v->by = (float)V[1];
         v->bz = (float)V[2];

         if(context->ClientState & GLCS_TEXTURE)
         {
		W = (float*)Wpointer;
              *W = 1.0;
         }

	v++; Vpointer += Vstride; Wpointer += Wstride;
      } while (--i);
   }
   else
   {
      float *V;
	i = count;

	do
	{
         V = (float*)Vpointer;

         v->bx = V[0];
         v->by = V[1];
         v->bz = V[2];

         if(context->ClientState & GLCS_TEXTURE)
         {
		W = (float*)Wpointer;
              *W = 1.0;
         }

	v++; Vpointer += Vstride; Wpointer += Wstride;
      } while (--i);
   }

   error = W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRIFAN, first, count);
}

//end of pipeline

#ifdef VA_SANITY_CHECK

// Swap_TextureCoordPointers added 01-06-2002
// Thanks to Olivier Fabre for making me aware of possible
// memprot problems without such a safety-check.
// It will only be needed if glTexcoordPointer,
// GL_TEXTURE_COORD_ARRAY and GL_TEXTURE_2D state are not
// in "sync".

void Swap_TextureCoordPointers(GLcontext context, GLboolean enable) 
{
	if(enable == GL_TRUE)
	{
		Set_W3D_TexCoordPointer(context->w3dContext, (void*)context->ArrayPointer.texcoords, context->ArrayPointer.texcoordstride, 0, sizeof(GLfloat), context->ArrayPointer.w_off, W3D_TEXCOORD_NORMALIZED);
	}
	else
	{
	// guaranteed valid spot as long as vertexbuffer
	// is big enough

		Set_W3D_TexCoordPointer(context->w3dContext, (void*)&context->VertexBuffer[0].v.u, sizeof(MGLVertex), 0, 4, -4, W3D_TEXCOORD_NORMALIZED);
	}
}

#else

	#define Swap_TextureCoordPointers(c,e) {}

#endif

void GLEnableClientState(GLcontext context, GLenum state)
{
        switch (state)
        {
                case GL_TEXTURE_COORD_ARRAY:
			context->ClientState |= GLCS_TEXTURE;
			Swap_TextureCoordPointers(context, GL_TRUE); 
			break;

                case GL_COLOR_ARRAY:
                      context->ClientState |= GLCS_COLOR;
                      break;

                case GL_VERTEX_ARRAY:
                      context->ClientState |= GLCS_VERTEX;
                      break;

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


void GLDisableClientState(GLcontext context, GLenum state)
{
        switch (state)
        {
                case GL_TEXTURE_COORD_ARRAY:
                        context->ClientState &= ~GLCS_TEXTURE;
			  Swap_TextureCoordPointers(context, GL_FALSE); 
                        break;

                case GL_COLOR_ARRAY:
                        context->ClientState &= ~GLCS_COLOR;
                        break;

                case GL_VERTEX_ARRAY:
                        context->ClientState &= ~GLCS_VERTEX;
                        break;

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

}

#if 0 //NYI

void GLInterleavedArrays(GLcontext context, GLenum format, GLsizei stride, const GLvoid *pointer)
{

   #define PTR context->ArrayPointer

   PTR.colorpointer = NULL;
   PTR.texcoordpointer = NULL;

   switch((int)format)
   {
	case GL_V2F:
		context->ClientState = GLCS_VERTEX;
		PTR.verts = (UBYTE *)pointer;
		if(stride == 0)
			PTR.vertexstride = 2*sizeof(GLfloat);
		else
			PTR.vertexstride = stride;
	break;
	case GL_V3F:
		context->ClientState = GLCS_VERTEX;
		PTR.verts = (UBYTE *)pointer;
		if(stride == 0)
			PTR.vertexstride = 3*sizeof(GLfloat);
		else
			PTR.vertexstride = stride;
	break;
	case GL_C4UB_V2F:
		context->ClientState = GLCS_VERTEX|GLCS_COLOR;
		PTR.colors = (UBYTE *)pointer;
		PTR.verts = ((UBYTE *)pointer + 4);
		PTR.colormode = W3D_COLOR_UBYTE | W3D_CMODE_RGBA;
		if(stride == 0)
		{
			PTR.vertexstride = PTR.colorstride = 2*sizeof(GLfloat) + 4*sizeof(GLubyte);
		}
		else
		{
			PTR.vertexstride = PTR.colorstride = stride;
		}
	break;
	case GL_C4UB_V3F:
		context->ClientState = GLCS_VERTEX|GLCS_COLOR;
		PTR.colors = (UBYTE *)pointer;
		PTR.verts = ((UBYTE *)pointer + 4);
		PTR.colormode = W3D_COLOR_UBYTE | W3D_CMODE_RGBA;
		if(stride == 0)
		{
			PTR.vertexstride = PTR.colorstride = 3*sizeof(GLfloat) + 4*sizeof(GLubyte);
		}
		else
		{
			PTR.vertexstride = PTR.colorstride = stride;
		}
	break;
	case GL_C3F_V3F:
		context->ClientState = GLCS_VERTEX|GLCS_COLOR;
		PTR.colors = (UBYTE *)pointer;
		PTR.verts = ((UBYTE *)pointer + 12);
		PTR.colormode = W3D_COLOR_FLOAT | W3D_CMODE_RGB;

		if(stride == 0)
		{
			PTR.vertexstride = PTR.colorstride = 6*sizeof(GLfloat);
		}
		else
		{
			PTR.vertexstride = PTR.colorstride = stride;
		}
	break;
	case GL_T2F_V3F:
		context->ClientState = GLCS_VERTEX|GLCS_TEXTURE;
		PTR.texcoords = (UBYTE *)pointer;
		PTR.verts = ((UBYTE *)pointer + 8);
		if(stride == 0)
		{
			PTR.vertexstride = PTR.texcoordstride = 5*sizeof(GLfloat);
		}
		else
		{
			PTR.vertexstride = PTR.texcoordstride = stride;
		}
	break;
	case GL_T2F_C4UB_V3F:
		context->ClientState = GLCS_VERTEX|GLCS_TEXTURE|GLCS_COLOR;
		PTR.texcoords = (UBYTE *)pointer;
		PTR.colors = ((UBYTE *)pointer + 8);
		PTR.verts = ((UBYTE *)pointer + 12);
		PTR.colormode = W3D_COLOR_UBYTE | W3D_CMODE_RGBA;
		if(stride == 0)
		{
			PTR.vertexstride = PTR.colorstride = PTR.texcoordstride = 5*sizeof(GLfloat) + 4*sizeof(GLubyte);
		}
		else
		{
			PTR.vertexstride = PTR.colorstride = PTR.texcoordstride = stride;
		}
	break;
	case GL_T2F_C3F_V3F:
		context->ClientState = GLCS_VERTEX|GLCS_TEXTURE|GLCS_COLOR;
		PTR.texcoords = (UBYTE *)pointer;
		PTR.colors = ((UBYTE *)pointer + 8);
		PTR.verts = ((UBYTE *)pointer + 20);
		PTR.colormode = W3D_COLOR_FLOAT | W3D_CMODE_RGB;
		if(stride == 0)
		{
			PTR.vertexstride = PTR.colorstride = PTR.texcoordstride = 8*sizeof(GLfloat);
		}
		else
		{
			PTR.vertexstride = PTR.colorstride = PTR.texcoordstride = stride;
		}
	break;
   }

   #undef PTR

}

#endif


static GLboolean cur_pipeline_state = GL_TRUE;

void GLTexCoordPointer(GLcontext context, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
{
   int w3dStride;
   int w_off;
   BYTE *base, *target;

//check pipeline state to make sure that w_off was calculated:

    if((context->VertexArrayPipeline == cur_pipeline_state) && (context->ArrayPointer.texcoords == (UBYTE*)pointer))
        return;


#ifdef VA_SANITY_CHECK

    if(!pointer) //thanks to OF for making me aware..
    {
	context->ArrayPointer.texcoords = (UBYTE*)&context->VertexBuffer[0].v.u;
	context->ArrayPointer.texcoordstride = sizeof(MGLVertex);
	context->ArrayPointer.w_off = -4;
	
      Set_W3D_TexCoordPointer(context->w3dContext, (void*)&context->VertexBuffer[0].v.u, sizeof(MGLVertex), 0, sizeof(GLfloat), -4, W3D_TEXCOORD_NORMALIZED);

	return;
    }

#endif

    if (stride == 0)	w3dStride = size*sizeof(GLfloat);
    else		w3dStride = stride;

    if (type != GL_FLOAT)   GLFlagError(context, 1, GL_INVALID_ENUM);

    context->ArrayPointer.texcoords = (UBYTE*)pointer;
    context->ArrayPointer.texcoordstride = w3dStride;

    cur_pipeline_state = context->VertexArrayPipeline;

    if(context->VertexArrayPipeline == GL_FALSE)
    {
    	if (size != 4)          GLFlagError(context, 1, GL_INVALID_VALUE);

	Set_W3D_TexCoordPointer(context->w3dContext, (void*)context->ArrayPointer.texcoords, 4*sizeof(GLfloat), 0, sizeof(GLfloat), 3*sizeof(GLfloat), W3D_TEXCOORD_NORMALIZED);
    }
    else
    {
      //find w_array-offset relative to current pointer:

	target = (BYTE*)&context->WBuffer[0];
	base   = (BYTE*)pointer;

	if(target < base)
	{
		w_off = (base - target);
		w_off = -w_off;	
	}
	else
	{
		w_off = (target - base);
	}

	context->ArrayPointer.w_off = w_off;

      Set_W3D_TexCoordPointer(context->w3dContext, (void*)context->ArrayPointer.texcoords, w3dStride, 0, sizeof(GLfloat), w_off, W3D_TEXCOORD_NORMALIZED);
   }
}


void GLColorPointer(GLcontext context, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
{
    int w3dStride;
    ULONG w3dType, w3dFormat;

    if(context->ArrayPointer.colors == (UBYTE*)pointer)
        return;

#ifdef VA_SANITY_CHECK

    if(!pointer) //thanks to OF for making me aware..
    {
	context->ArrayPointer.colors = (UBYTE*)&context->VertexBuffer[0].color[0];
      context->ArrayPointer.colorstride = sizeof(MGLVertex);
	context->ArrayPointer.colormode = W3D_COLOR_UBYTE | W3D_CMODE_RGBA;
  	Convert = (Convfn)Convert_UB_RGBA;

      Set_W3D_ColorPointer(context->w3dContext, (void *)&context->VertexBuffer[0].color[0], sizeof(MGLVertex),
            W3D_COLOR_UBYTE, W3D_CMODE_RGBA, 0);
 
	return;
    }

#endif

    if (type != GL_UNSIGNED_BYTE && type != GL_FLOAT && type != MGL_UBYTE_BGRA && type != MGL_UBYTE_ARGB)
        GLFlagError(context, 1, GL_INVALID_ENUM);

    if (stride == 0)
        w3dStride = size * (type == GL_FLOAT ? sizeof(GLfloat) : sizeof(GLubyte));
    else
        w3dStride = stride;

    context->ArrayPointer.colors = (UBYTE*)pointer;
    context->ArrayPointer.colorstride = w3dStride;


    if(type == GL_FLOAT)
	w3dType = W3D_COLOR_FLOAT;
    else
	w3dType = W3D_COLOR_UBYTE;


    if (type != MGL_UBYTE_ARGB)
    {
	  if(type == GL_FLOAT)
	  {
		if(size == 3)
		{
		   w3dFormat = W3D_CMODE_RGB;
  		   Convert   = (Convfn)Convert_F_RGB;
		}
		else
		{
		   w3dFormat = W3D_CMODE_RGBA;
  		   Convert   = (Convfn)Convert_F_RGBA;
		}
	  }
	  else if (type == MGL_UBYTE_BGRA)
	  {
		if(size == 3)
		{
		   w3dFormat = W3D_CMODE_BGR;
		   Convert   = (Convfn)Convert_UB_BGR;
		}
		else
		{
		   w3dFormat = W3D_CMODE_BGRA;
		   Convert   = (Convfn)Convert_UB_BGRA;
		}
	  }
	  else // GL_UNSIGNED_BYTE
	  {
		if(size == 3)
		{
		   w3dFormat = W3D_CMODE_RGB;
  		   Convert   = (Convfn)Convert_UB_RGB;
		}
		else
		{
		   w3dFormat = W3D_CMODE_RGBA;
  		   Convert   = (Convfn)Convert_UB_RGBA;
		}
	  }
    }
    else
    {
		w3dFormat = W3D_CMODE_ARGB;
		Convert   = (Convfn)Convert_UB_ARGB;
    }

    context->ArrayPointer.colormode = w3dType | w3dFormat;

    Set_W3D_ColorPointer(context->w3dContext, (void *)context->ArrayPointer.colors, w3dStride, w3dType, w3dFormat, 0);
}


void GLVertexPointer(GLcontext context, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
{
    int w3dStride;

    if (size < 3 || type != GL_FLOAT || type != GL_INT)
    GLFlagError(context, 1, GL_INVALID_VALUE);

    if(context->ArrayPointer.verts == (UBYTE*)pointer)
        return;

#ifdef VA_SANITY_CHECK

    if(!pointer) //thanks to OF for making me aware..
    {
	context->ArrayPointer.verts = (UBYTE*)&context->VertexBuffer[0].bx;
	context->ArrayPointer.vertexstride = sizeof(MGLVertex);


	if (Reset_W3D_VertexPointer == GL_TRUE)
	{
		Set_W3D_VertexPointer(context->w3dContext, (void *) &(context->VertexBuffer->bx), sizeof(MGLVertex), W3D_VERTEX_F_F_F, 0);
	Reset_W3D_VertexPointer = GL_FALSE;
	}

    return;
    }

#endif

    if(type == GL_INT)
    {
	context->ArrayPointer.FixpointTrans = GL_TRUE;
      if (stride == 0) w3dStride = size * sizeof(GLint);
	else w3dStride = stride;
    }
    else
    {
	context->ArrayPointer.FixpointTrans = GL_FALSE;
      if (stride == 0) w3dStride = size * sizeof(GLfloat);
	else w3dStride = stride;
    }

    context->ArrayPointer.verts = (UBYTE*)pointer;
    context->ArrayPointer.vertexstride = w3dStride;


    if(context->VertexArrayPipeline == GL_FALSE)
    {
	if(type == GL_INT)
      GLFlagError(context, 1, GL_INVALID_VALUE);

	Reset_W3D_VertexPointer = GL_TRUE; //not default

	Set_W3D_VertexPointer(context->w3dContext, (void *)pointer, w3dStride, W3D_VERTEX_F_F_F, 0);
    }
    else if (Reset_W3D_VertexPointer == GL_TRUE)
    {
	Set_W3D_VertexPointer(context->w3dContext, (void *) &(context->VertexBuffer->bx), sizeof(MGLVertex), W3D_VERTEX_F_F_F, 0);

	Reset_W3D_VertexPointer = 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 GLDrawArrays(GLcontext context, GLenum mode, const GLint first, const GLsizei count)
{
   ULONG error, prim;
   int k;

#ifdef VA_SANITY_CHECK
   GLboolean ShadeModel_bypass;
   GLboolean TexCoord_bypass;
#endif

   //11-04-02 - check for compiled arrays
   //sorry - no time to write proper handling for this.
   //Anyways, glDrawArrays is rarely used within a lock.

   if(context->ArrayPointer.transformed == GL_TRUE && Clip_Volume_Bypass == GL_FALSE)
   {
	GLDrawElements(context, mode, count, GL_UNSIGNED_SHORT, (void*)&(e_wrap[first]));
	return;
   }


#ifdef VA_SANITY_CHECK

   ShadeModel_bypass = GL_FALSE;

   //Thanks to OF for making me aware of this unlikely case

   if(!(context->ClientState & GLCS_COLOR) && context->ShadeModel == GL_SMOOTH)
   {
	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_DrawArray(context->w3dContext, prim, first, count);

   }
   else
   {
	if(context->ArrayPointer.transformed == GL_TRUE)
	{
		context->VertexBufferPointer = context->ArrayPointer.lockfirst + context->ArrayPointer.locksize;
	}
	else
	{
		context->VertexBufferPointer = first + count;
	}
#if 0
	if((count == 3) && (mode != MGL_FLATFAN))
	{
		A_DrawTriangle(context, first);
	}
	else
#endif
	switch(mode)
	{
      	case GL_TRIANGLE_STRIP:
	  	A_DrawTriStrip(context, first, count);
		break;

        	case GL_TRIANGLE_FAN:
	  	A_DrawTriFan(context, first, count);
		break;

        	case GL_TRIANGLES:
	  	A_DrawTriangles(context, first, count);
		break;

        	case GL_POLYGON:
	  	A_DrawPolygon(context, first, count);
		break;

		case MGL_FLATFAN:
		A_DrawFlatFan(context, first, count);
	   	break;

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

   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
#undef A_ToV
#endif
