/*
 * $Id: draw.c,v 1.4 2001/02/01 14:36:49 tfrieden Exp $
 *
 * $Date: 2001/02/01 14:36:49 $
 * $Revision: 1.4 $
 *
 * (C) 1999 by Hyperion
 * All rights reserved
 *
 * This file is part of the MiniGL library project
 * See the file Licence.txt for more details
 *
 */


// Surgeon: Polygon clip/reject tests:
// Primary bottleneck on 68060 is CPU/FPU.
// On PPC it is more often bandwidth/fillrate.
// The following define adjusts level of rejection-tests

#define PRIORITIZE_BANDWIDTH 1

#ifdef __PPC__ 
#define PRIORITIZE_FILLRATE  1
#endif


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

#include <math.h>

#include <stdlib.h>
#ifdef __VBCC__
#include <stdio.h>
#endif

#ifdef DISABLE_TRANSFORMATION
#warning "Compiling without transformation pipeline. Only flat geometry supported"
#endif

static char rcsid[] = "$Id: draw.c,v 1.4 2001/02/01 14:36:49 tfrieden Exp $";

#define DUMP_VERTEX2(vert)

//for multitexturing:
extern void TMA_Start(LockTimeHandle *handle);
extern GLboolean TMA_Check(LockTimeHandle *handle);
extern void fog_Set(GLcontext context);


void d_DrawPoly(GLcontext context, MGLPolygon *poly);
void dh_DrawPolyFF(GLcontext context, MGLPolygon *poly);
void d_DrawPoints        (GLcontext);
void d_DrawLines         (GLcontext);
void d_DrawLineStrip     (GLcontext);
void d_DrawTriangles     (GLcontext);
void d_DrawTriangleFan   (GLcontext);
void d_DrawTriangleStrip (GLcontext);
void d_DrawQuads         (GLcontext);
void d_DrawFixPoly       (GLcontext);
void d_DrawMtexPoly      (GLcontext);
void d_DrawSmoothPoly    (GLcontext);
void d_DrawNormalPoly    (GLcontext);
void d_DrawQuadStrip     (GLcontext);
void d_DrawTrianglesVA   (GLcontext); //Surgeon
void d_DrawFlat	   (GLcontext);

#if 0
void d_DrawFlatFan       (GLcontext);
void d_DrawFlatStrip     (GLcontext);
#endif


INLINE GLvoid v_Transform(GLcontext context);

#ifndef __VBCC__ //replaced with macro
	INLINE void v_ToScreen(GLcontext context, int i);
#endif

extern void m_CombineMatrices(GLcontext context);
extern void m_BuildInverted(GLcontext context);

extern void hc_ClipAndDrawLine(GLcontext context, MGLPolygon *poly, ULONG or_codes);
extern void hc_ClipAndDrawPoly(GLcontext context, MGLPolygon *poly, ULONG or_codes);

extern void hc_ClipPoly(GLcontext context, MGLPolygon *poly, PolyBuffer *out, int clipstart, ULONG or_codes);

extern void hc_ClipPolyFF(GLcontext context, MGLPolygon *poly, ULONG or_codes);


//this index is generated by clip function:

static PolyBuffer clip[MGL_MAXVERTS];


//Surgeon: moved from GLVertex*f to after culling:

INLINE void PrepTexCoords(GLcontext context, int start, const int numverts, GLboolean cullfan)
{
   int i;
   GLfloat umul, vmul;
   MGLVertex *v;

   if(context->Texture2D_State[0] == GL_TRUE && context->w3dTexBuffer[context->CurrentBinding])
   {
	if (context->w3dChipID == W3D_CHIP_VIRGE)
	{
		umul = (float)(context->w3dTexBuffer[context->CurrentBinding]->texwidth-1);
		vmul = (float)(context->w3dTexBuffer[context->CurrentBinding]->texheight-1);
	}
	else
	{
		umul = (float)(context->w3dTexBuffer[context->CurrentBinding]->texwidth);
		vmul = (float)(context->w3dTexBuffer[context->CurrentBinding]->texheight);
	}

	if(cullfan == GL_TRUE)
	{
		context->VertexBuffer[0].v.u *= umul;
		context->VertexBuffer[0].v.v *= vmul;
	}

	v = &(context->VertexBuffer[start]);
	i = numverts;

	do
	{
		v->v.u *= umul;
		v->v.v *= vmul;
	v++;
	} while (--i);
   }
}



#define CM_0 OF_11
#define CM_1 OF_12
#define CM_2 OF_13
#define CM_3 OF_21
#define CM_4 OF_22
#define CM_5 OF_23
#define CM_6 OF_31
#define CM_7 OF_32
#define CM_8 OF_33


/*
** This computationally intensive piece of code generates coordinates
** for the reflective image used in spherical environment mapping.
** This is a good place for optimizations.
** After generation, transforms into the clipping space...
**
** Note that this is after the book. It is probably a big time-eater.
**
** (Turned out not to be so time intensive after all...)
*/


void v_GenTexCoords(GLcontext context, int vertex)
{
#ifdef __M68K__
	float u[4];
#endif
	float ul;
	float nx,ny,nz;
	float nu;
	float rx,ry,rz;
	float m;
	float s,t;

	float a11,a12,a13,a14;
	float a21,a22,a23,a24;
	float a31,a32,a33,a34;
	float a41,a42,a43,a44;

	float b11,b12,b13,b14;
	float b21,b22,b23,b24;
	float b31,b32,b33,b34;
	float b41,b42,b43,b44;

	#define a(x)  (CurrentMV->v[OF_##x])
	#define b(x)  (CurrentP->v[OF_##x])
	#define verx  (context->VertexBuffer[vertex].bx)
	#define very  (context->VertexBuffer[vertex].by)
	#define verz  (context->VertexBuffer[vertex].bz)
	#define verw  (context->VertexBuffer[vertex].bw)

#ifdef __PPC__

	a11 = a(11);	b11 = b(11);
	a12 = a(12);	b12 = b(12);
	a13 = a(13);	b13 = b(13);
	a14 = a(14);	b14 = b(14);

	a21 = a(21);	b21 = b(21);
	a22 = a(22);	b22 = b(22);
	a23 = a(23);	b23 = b(23);
	a24 = a(24);	b24 = b(24);

	a31 = a(31);	b31 = b(31);
	a32 = a(32);	b32 = b(32);
	a33 = a(33);	b33 = b(33);
	a34 = a(34);	b34 = b(34);

	a41 = a(41);	b41 = b(41);
	a42 = a(42);	b42 = b(42);
	a43 = a(43);	b43 = b(43);
	a44 = a(44);	b44 = b(44);

	#define A_0 a14
	#define A_1 a24
	#define A_2 a34
	#define A_3 a44

	#define u(x) (A_##x)

#else

	a11 = a(11);	b11 = b(11);
	a12 = a(12);	b12 = b(12);
	a13 = a(13);	b13 = b(13);
	u[0] = a(14);	b14 = b(14);

	a21 = a(21);	b21 = b(21);
	a22 = a(22);	b22 = b(22);
	a23 = a(23);	b23 = b(23);
	u[1] = a(24);	b24 = b(24);

	a31 = a(31);	b31 = b(31);
	a32 = a(32);	b32 = b(32);
	a33 = a(33);	b33 = b(33);
	u[2] = a(34);	b34 = b(34);

	a41 = a(41);	b41 = b(41);
	a42 = a(42);	b42 = b(42);
	a43 = a(43);	b43 = b(43);
	u[3] = a(44);	b44 = b(44);

	#define u(x) (u[x])

#endif

//some common special-case optimizations by surgeon

	if(context->WOne_Hint == GL_FALSE)
	{
		if(!(CurrentMV->flags & MGLMASK_0001))
		{
		u(0) *= verw;
		u(1) *= verw;
		u(2) *= verw;
		u(3) *= verw;

		u(0) += verz*a13;
		u(1) += verz*a23;
		u(2) += verz*a33;
		u(3) += verz*a43;

		u(0) += very*a12;
		u(1) += very*a22;
		u(2) += very*a32;
		u(3) += very*a42;

		u(0) += verx*a11;
		u(1) += verx*a21;
		u(2) += verx*a31;
		u(3) += verx*a41;
		}
		else //special case
		{
		u(0) *= verw;
		u(1) *= verw;
		u(2) *= verw;
		u(3) = verw;

		u(0) += verz*a13;
		u(1) += verz*a23;
		u(2) += verz*a33;

		u(0) += very*a12;
		u(1) += very*a22;
		u(2) += very*a32;

		u(0) += verx*a11;
		u(1) += verx*a21;
		u(2) += verx*a31;
		}
	}
	else //special case
	{
		if(!(CurrentMV->flags & MGLMASK_0001))
		{
		u(0) += verz*a13;
		u(1) += verz*a23;
		u(2) += verz*a33;
		u(3) += verz*a43;

		u(0) += very*a12;
		u(1) += very*a22;
		u(2) += very*a32;
		u(3) += very*a42;

		u(0) += verx*a11;
		u(1) += verx*a21;
		u(2) += verx*a31;
		u(3) += verx*a41;
		}
		else //special case
		{
		u(0) += verz*a13;
		u(1) += verz*a23;
		u(2) += verz*a33;

		u(0) += very*a12;
		u(1) += very*a22;
		u(2) += very*a32;

		u(0) += verx*a11;
		u(1) += verx*a21;
		u(2) += verx*a31;
		}
	}

	b14 *= u(3); 
	b24 *= u(3); 
	b34 *= u(3); 
	b44 *= u(3); 

	b14 += u(2)*b13; 
	b24 += u(2)*b23; 
	b34 += u(2)*b33; 
	b44 += u(2)*b43; 

	b14 += u(1)*b12; 
	b24 += u(1)*b22; 
	b34 += u(1)*b32; 
	b44 += u(1)*b42; 

	b14 += u(0)*b11; 
	b24 += u(0)*b21; 
	b34 += u(0)*b31; 
	b44 += u(0)*b41; 

	verx = b14;
	very = b24;
	verz = b34;
	verw = b44;


	#undef a
	#undef b
	#undef verx
	#undef very
	#undef verz
	#undef verw


	if(u(3) != 1.f)
	{
		u(3) = 1.0 / u(3);
		u(0) *= u(3);
		u(1) *= u(3);
		u(2) *= u(3);
	}

	ul = (float)sqrt((double)(u(0)*u(0)+u(1)*u(1)+u(2)*u(2)));

	if (ul == 0.f)
		return;

	ul = 1.0 / ul;
	u(0) *= ul;
	u(1) *= ul;
	u(2) *= ul;

	if(context->NormalBufferPointer > 0)
	{
	int nbp = context->VertexBuffer[vertex].normal;

	#define ver(c)  (context->NormalBuffer[nbp].c)
	#define b(x)    (context->InvRot[x])

		// InvRot is row-major

		nx  = ver(x)*b(0);
		ny  = ver(x)*b(1);
		nz  = ver(x)*b(2);
	
		nx += ver(y)*b(3);
		ny += ver(y)*b(4);
		nz += ver(y)*b(5);

		nx += ver(z)*b(6);
		ny += ver(z)*b(7);
		nz += ver(z)*b(8);
	
	#undef b
	#undef ver
	}
	else
	{
	#define ver(c)  (context->NormalBuffer[0].c)
	#define b(x)    (context->InvRot[x])

		// InvRot is row-major

		nx  = ver(x)*b(0);
		ny  = ver(x)*b(1);
		nz  = ver(x)*b(2);
	
		nx += ver(y)*b(3);
		ny += ver(y)*b(4);
		nz += ver(y)*b(5);

		nx += ver(z)*b(6);
		ny += ver(z)*b(7);
		nz += ver(z)*b(8);
	
	#undef b
	#undef ver
	}


	nu  = nx*u(0) + ny*u(1) + nz*u(2);
	nu *= 2.f;

	rx = u(0) - nx*nu;
	ry = u(1) - ny*nu;
	rz = u(2) - nz*nu;

	rz += 1.f;	
	m = 0.5f / (float)sqrt((double)(rx*rx + ry*ry + rz*rz));


	if (context->TextureGenS_State == GL_TRUE)
	{
		s = rx*m + 0.5;
		context->VertexBuffer[vertex].v.u = s;
	}

	if (context->TextureGenT_State == GL_TRUE)
	{
		t = ry*m + 0.5;
		context->VertexBuffer[vertex].v.v = t;
	}

#undef u
}


INLINE GLvoid v_Transform(GLcontext context)
{
#if !defined(DISABLE_TRANSFORMATION)
	int i;

   if (context->TextureGenS_State == GL_TRUE || context->TextureGenT_State == GL_TRUE)
   {
#ifndef INLINE_MATRIX_INVERSION
	if (context->InvRotValid == GL_FALSE)
		m_BuildInverted(context);
#endif
	for (i=0; i<context->VertexBufferPointer; i++)
	{
		v_GenTexCoords(context, i);
	}
   }

   else
   {
	if (context->CombinedValid == GL_FALSE)
	{
		m_CombineMatrices(context);
	}

	if (context->WOne_Hint == GL_FALSE)
	{
	    #define a(x) (context->CombinedMatrix.v[OF_##x])

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

	    MGLVertex *v = &context->VertexBuffer[0];

	    i = context->VertexBufferPointer;
	    do
	    {
		float x = v->bx;
		float y = v->by;
		float z = v->bz;
		float w = v->bw;

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

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

		#undef a
	}
	else
	{
	    #define a(x) (context->CombinedMatrix.v[OF_##x])

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

	    MGLVertex *v = &context->VertexBuffer[0];

	    i = context->VertexBufferPointer;

	    do
	    {
		float x = v->bx;
		float y = v->by;
		float z = v->bz;

		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++;
	    } while (--i);

	#undef a
    }
  }
#else
// Does nothing
#endif
}


#ifdef __VBCC__

//VBCC only does inlining on highest optimization level :-/

#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; \
if (context->CurrentTexQValid == GL_FALSE) ctx->VertexBuffer[vnum].v.w = wdiv; \
else ctx->VertexBuffer[vnum].v.w = ctx->VertexBuffer[vnum].q;}\

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

#else

INLINE void v_ToScreen(GLcontext context, int i)
{
#if !defined(DISABLE_TRANSFORMATION)

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

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

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

	if (context->CurrentTexQValid == GL_FALSE)
		context->VertexBuffer[i].v.w = w;
	else
		context->VertexBuffer[i].v.w = context->VertexBuffer[i].q;

#else
	context->VertexBuffer[i].v.x = context->VertexBuffer[i].bx;
	context->VertexBuffer[i].v.y = context->VertexBuffer[i].by;
	context->VertexBuffer[i].v.z = 1.0 - context->VertexBuffer[i].bz;
	context->VertexBuffer[i].v.w = context->VertexBuffer[i].q;
#endif
}

INLINE void v_ToScreenVA(GLcontext context, int i)
{
	float w;
	w = 1.0 / context->VertexBuffer[i].bw;

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

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

	if (context->CurrentTexQValid == GL_FALSE)
		context->VertexBuffer[i].v.w = w;
	else
		context->VertexBuffer[i].v.w = context->VertexBuffer[i].q;
}


#endif


/*
** Multitexturing:
** See mglDrawMultitexBuffer
*/

#define ENABLE_BLEND {if(mini_CurrentContext->Blend_State == GL_FALSE) W3D_SetState(context->w3dContext, W3D_BLENDING, W3D_ENABLE);}

#define DISABLE_BLEND {if(mini_CurrentContext->Blend_State == GL_FALSE) W3D_SetState(context->w3dContext, W3D_BLENDING, W3D_DISABLE);}



#if 0 //should go to same buffer as GL_POLYGON

static void Multitex_PolyBuffer(GLcontext context, W3D_Vertex **verts, int numpolys, GLboolean typecheck)
{
	int i,j;
	int first;
	ULONG error;
	static W3D_TrianglesV tris;


	ENABLE_BLEND

	tris.tex = context->w3dTexBuffer[context->VirtualBinding];
	tris.st_pattern = NULL;

	i = 0;
	first = 0;

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

	float w = context->w3dTexBuffer[context->VirtualBinding]->texwidth;
	float h = context->w3dTexBuffer[context->VirtualBinding]->texheight;


		for(j=0; j<p->numverts; j++)
		{
	MGLVertex *v = &context->VertexBuffer[p->verts[j]];

	v->v.u = v->tcoord.s * w;
	v->v.v = v->tcoord.t * h;

		}

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

	   if(typecheck && p->type == W3D_PRIMITIVE_TRISTRIP)
	   { 
	  	error = W3D_DrawTriStripV(context->w3dContext, &tris);
	   }
	   else
	   {
	  	error = W3D_DrawTriFanV(context->w3dContext, &tris);
	   }

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

	DISABLE_BLEND
}

#endif


//Surgeon: from hclip.c - hc_CodePoint is inlined manually

#define CLIP_EPS (1e-7)


//primitive point emulation by Surgeon - works on voodoo3

void d_DrawPoints(GLcontext context)
{
#if !defined(DISABLE_TRANSFORMATION)
    int i,j;
    W3D_Triangle tri;
    MGLVertex *vf;
    ULONG error;

	if(context->CullFace_State == GL_TRUE && context->CurrentCullFace == GL_FRONT_AND_BACK)
	return;

	v_Transform(context);


    vf = context->VertexBuffer;

    for (i=0; i<context->VertexBufferPointer; i++)
    {
	    MGLVertex *v = &vf[i];
	    float w = v->bw;

		if (w < CLIP_EPS )
		{
			continue;
		}

		if (-w > v->bx)
		{
			continue;
		}
		else if (v->bx > w)
		{
			continue;
		}

		if (-w > v->by)
		{
			continue;
		}
		else if (v->by > w)
		{
			continue;
		}
	
		if (-w > v->bz)
		{
			continue;
		}
		else if (v->bz > w)
		{
			continue;
		}


		v_ToScreen(context, i);

		tri.v1 = context->VertexBuffer[i].v;
		tri.v2 = context->VertexBuffer[i].v;
		tri.v3 = context->VertexBuffer[i].v;
		tri.v2.y += context->CurrentPointSize;
		tri.v3.x += context->CurrentPointSize;
		tri.tex = NULL;
		tri.st_pattern = NULL;

		error = W3D_DrawTriangle(context->w3dContext, &tri);
	}
#else
    int i;
    W3D_Point p;
    ULONG error;

    for (i=0;i<context->VertexBufferPointer; i++)
    {
	v_ToScreen(context,i);
	p.v1 = (context->VertexBuffer[i].v);
	p.tex = NULL;
	p.pointsize = 1; //diameter
	error = W3D_DrawPoint(context->w3dContext, &p);
    }
#endif
}

void d_DrawLines(GLcontext context)
{
#if !defined(DISABLE_TRANSFORMATION)
    int i,j;
    W3D_Line lin;
    ULONG or_code, and_code;
    ULONG error;

	if(context->CullFace_State == GL_TRUE && context->CurrentCullFace == GL_FRONT_AND_BACK)
	return;

	v_Transform(context);

    for (i=0; i<context->VertexBufferPointer; i+=2)
    {
	   for (j=i; j<i+2;j++)
	   {
		MGLVertex *v = &(context->VertexBuffer[j]);
		float w = v->bw;
		ULONG outcode = 0;

		if (w < CLIP_EPS )
		{
			outcode |= MGL_CLIP_NEGW;
		}

		if (-w > v->bx)
		{
			outcode |= MGL_CLIP_LEFT;
		}
		else if (v->bx > w)
		{
			outcode |= MGL_CLIP_RIGHT;
		}

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

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

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

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

	if (and_code) continue;

	PrepTexCoords(context, i, 2, GL_FALSE);

	if (or_code == 0)
	{

	    v_ToScreen(context, i);
	    v_ToScreen(context, i+1);
	    lin.v1 = (context->VertexBuffer[i+0].v);
	    lin.v2 = (context->VertexBuffer[i+1].v);
	    lin.tex = context->w3dTexBuffer[context->CurrentBinding];
	    lin.st_pattern = 0;
	    lin.st_enable = 0;
	    lin.st_factor = 1;
	    error = W3D_DrawLine(context->w3dContext, &lin);
//            if (error != W3D_SUCCESS) kprintf("W3D_DrawTriangle = %ld\n",error);
	}
	else
	{
	    static MGLPolygon poly;
	    poly.numverts = 2;
	    poly.verts[0] = i;
	    poly.verts[1] = i+1;
	    hc_ClipAndDrawLine(context, &poly, or_code);
	}
    }
#else
    int i;
    W3D_Line lin;
    ULONG error;

	PrepTexCoords(context, 0, context->VertexBufferPointer, GL_FALSE);

    for (i=0;i<context->VertexBufferPointer; i+=2)
    {
	v_ToScreen(context,i);
	v_ToScreen(context,i+1);
	lin.v1 = (context->VertexBuffer[i+0].v);
	lin.v2 = (context->VertexBuffer[i+1].v);
	lin.tex = context->w3dTexBuffer[context->CurrentBinding];
	lin.st_pattern = 0;
	lin.st_enable = 0;
	lin.st_factor = 1;
	error = W3D_DrawLine(context->w3dContext, &lin);
//        if (error != W3D_SUCCESS) kprintf("W3D_DrawTriangle = %ld\n", error);
    }
#endif
}

void dh_DrawLine(GLcontext context, MGLPolygon *poly)
{
    ULONG error;
    static W3D_Line lin;

    v_ToScreen(context, poly->verts[0]);
    lin.v1 = (context->VertexBuffer[poly->verts[0]].v);
    v_ToScreen(context, poly->verts[1]);
    lin.v2 = (context->VertexBuffer[poly->verts[1]].v);

    lin.tex = context->w3dTexBuffer[context->CurrentBinding];
    lin.st_pattern = 0;
    lin.st_enable = 0;
    lin.st_factor  = 1;
    #ifndef NODRAW
    error = W3D_DrawLine(context->w3dContext, &lin);
//    if (error != W3D_SUCCESS) kprintf("W3D_DrawTriFan = %ld\n", error);
    #endif
}

void d_DrawLineStrip(GLcontext context)
{
}

//surgeon: added fast path when primitive or_code equals 0
//surgeon: added buffering for clipping events
//multitexturing not finished yet

void d_DrawTriangleFan(GLcontext context)
{
#if !defined(DISABLE_TRANSFORMATION)
	int i,j;
	ULONG and_code, or_code;
	ULONG local_or, local_and, guard_band;
	ULONG error;
	static W3D_Vertex **verts = NULL;
	static GLboolean visible[MGL_MAXVERTS]; // Should be enough...?
	static ULONG   complete[MGL_MAXVERTS];  // Ditto
	static W3D_TrianglesV fan;
	int triangle;
	int pnum, free, backface, first, size;

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

	}

	if(context->CullFace_State == GL_TRUE && context->CurrentCullFace == GL_FRONT_AND_BACK)
	return;

	v_Transform(context);

	and_code = 0xff; or_code = 0;

	for (i=0; i<context->VertexBufferPointer; i++)
	{
		MGLVertex *v = &(context->VertexBuffer[i]);
		float w = v->bw;
		ULONG outcode = 0;

		if (w < CLIP_EPS )
		{
			outcode |= MGL_CLIP_NEGW;
		}

		if (-w > v->bx)
		{
			outcode |= MGL_CLIP_LEFT;
		}
		else if (v->bx > w)
		{
			outcode |= MGL_CLIP_RIGHT;
		}

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

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

	}

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

	i = context->VertexBufferPointer;
	guard_band = 0;

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

   if (guard_band == 0) //trifan completely visible
   {
	   first = 0;
	   size = context->VertexBufferPointer;

	   v_ToScreen(context, 0);
	   v_ToScreen(context, 1);
	   v_ToScreen(context, 2);

	   i = 3;
	   while (i < context->VertexBufferPointer)
	   {
		v_ToScreen(context, i);
	   i++;
	   }

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

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

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

	   	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 *= sign;
		}
		else
		{
		   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 *= sign;

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

		   i = 1;
		   do
		   {
		   float area2;

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

		   area2 = y2*x1 - x2*y1;
		   area2 *= sign;

		     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;
	   }
	#undef x
	#undef y

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

	i = 1;

	do
	{
	   verts[i] = &(context->VertexBuffer[i+first].v);
	   i++;
	} while (i < size);

	PrepTexCoords(context, first+1, size-1, GL_TRUE);

	fan.tex = context->w3dTexBuffer[context->CurrentBinding];
	fan.vertexcount = size;
	fan.st_pattern = NULL;
	fan.v = &verts[0];

	W3D_DrawTriFanV(context->w3dContext, &fan);

   return;
   }

	/*
	** Up to now everything is like a polygon. Unlike a polygon, however,
	** triangle fans and strips may be concave, and each individual triangle
	** might be backfacing.
	**
	** We calculate how many of the triangles are visible.
	*/

	backface = 0;

   if(context->CullFace_State == GL_FALSE)
   {
	for (i=1,triangle=0; i<context->VertexBufferPointer - 1; i++, triangle++)
	{
		local_or = context->VertexBuffer[0].outcode
			| context->VertexBuffer[i].outcode
			| context->VertexBuffer[i+1].outcode;

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


		if (local_and == 0) // if the local and code is zero, we're not
		{                   // completely off screen.
// if our local or codes are zero, we are completely visible

			complete[triangle] = local_or;
			visible[triangle] = GL_TRUE;
			backface = 0;
		}
		else
		{
			visible[triangle] = GL_FALSE;
			backface++;
		}
	}
   }
   else
   {
	for (i=1,triangle=0; i<context->VertexBufferPointer - 1; i++, triangle++)
	{
		local_or = context->VertexBuffer[0].outcode
			| context->VertexBuffer[i].outcode
			| context->VertexBuffer[i+1].outcode;

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


		if (local_and == 0) // if the local and code is zero, we're not
		{                   // completely off screen.
// if our local or codes are zero, we are completely visible

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

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

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

	context->VertexBufferPointer -= backface; //surgeon 260302

	PrepTexCoords(context, 0, context->VertexBufferPointer, GL_FALSE);

	/*
	** Draw...
	** There are three cases:
	**
	** 1) Triangle is partially visible
	** 2) Triangle is fully visible
	** 3) Triangle is invisible
	**
	** In case 1, we draw the triangle with clip_ClipAndDrawPoly.
	** In case 2, we collect a triangle fan/strip of maximum length
	** and draw that directly
	** in case 3... WE IGNORE IT! HA!
	*/

	free = context->VertexBufferPointer;
	pnum = 0;

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

				hc_ClipPoly(context, &poly, &clip[pnum], free, complete[triangle]);
				triangle++; i++;

				if(clip[pnum].numverts)
				{
				free = clip[pnum].nextfree;
				pnum++;
				}
			}
			else
			{   // case 2 (the difficult part)
				int k=3;
				clip[pnum].verts[0] = 0;
				clip[pnum].verts[1] = i;
				clip[pnum].verts[2] = i+1;

				triangle ++;
				i        ++;

				while (complete[triangle]==0 && visible[triangle] && i<context->VertexBufferPointer - 1)
				{
				clip[pnum].verts[k] = i+1;

				i++; k++; triangle++;
				}
			clip[pnum].numverts = k;
			pnum++;
			}
		}
	} while (i<context->VertexBufferPointer-1);


//Project to screen and draw:

	visible[context->VertexBufferPointer-2] = GL_FALSE;
	visible[context->VertexBufferPointer-1] = GL_FALSE;

   //project clipverts

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

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

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

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

		if(vert < context->VertexBufferPointer && visible[vert] < 2 /*== GL_FALSE*/)
		{
		   visible[vert] = 2/*GL_TRUE*/;
		   v_ToScreen(context, vert);
		}

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

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

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

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

#if 0
   if(context->Texture2D_State[1])
	Multitex_PolyBuffer(context, verts, pnum, GL_FALSE);
#endif

#else
	int i;
	ULONG error;
	static W3D_Vertex *verts[MGL_MAXVERTS];
	static W3D_TrianglesV tris;

	PrepTexCoords(context, 0, context->VertexBufferPointer, GL_FALSE);

	for (i=0; i<context->VertexBufferPointer; i++)
	{
		v_ToScreen(context, i);
		verts[i] = &(context->VertexBuffer[i].v);
	}

	tris.tex = context->w3dTexBuffer[context->CurrentBinding];
	tris.st_pattern = NULL;
	tris.vertexcount = context->VertexBufferPointer;
	tris.v = verts;

	#ifndef NODRAW
	error = W3D_DrawTriFanV(context->w3dContext, &tris);
	#endif
#endif
}

//surgeon: added fast path when primitive or_code equals 0
//surgeon: added buffering for clipping events
//multitexturing not finished yet

void d_DrawTriangleStrip(GLcontext context)
{
#if !defined(DISABLE_TRANSFORMATION)
	int i,j;
	ULONG and_code, or_code, guard_band;
	ULONG local_or, local_and;
	ULONG error;
	static W3D_Vertex **verts = NULL;
	static GLboolean visible[MGL_MAXVERTS];     // Should be enough...?
	static ULONG   complete[MGL_MAXVERTS];    // Ditto
	static W3D_TrianglesV tris;
	int triangle = 0;
/*
	GLenum CurrentFrontFace = context->CurrentFrontFace;
*/
	GLint CurrentCullSign = context->CurrentCullSign;
	int pnum, free, backface, first, size;


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

	}

	if(context->CullFace_State == GL_TRUE && context->CurrentCullFace == GL_FRONT_AND_BACK)
	return;

	v_Transform(context);

	and_code = 0xff;
	or_code = 0;

	for (i=0; i<context->VertexBufferPointer; i++)
	{
		MGLVertex *v = &(context->VertexBuffer[i]);
		float w = v->bw;
		ULONG outcode = 0;

		if (w < CLIP_EPS )
		{
			outcode |= MGL_CLIP_NEGW;
		}

		if (-w > v->bx)
		{
			outcode |= MGL_CLIP_LEFT;
		}
		else if (v->bx > w)
		{
			outcode |= MGL_CLIP_RIGHT;
		}

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

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

	}

   if (and_code)
		return;

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

	i = context->VertexBufferPointer;
	guard_band = 0;

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

   if (guard_band == 0) //tristrip completely visible
   {
	first = 0;
	size = context->VertexBufferPointer;

	   v_ToScreen(context, 0);
	   v_ToScreen(context, 1);
	   v_ToScreen(context, 2);

	   i = 3;
	   while (i < context->VertexBufferPointer)
	   {
		v_ToScreen(context, i);
	   i++;
	   }

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

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

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

		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 *= sign;
		}
		else
		{
		float a1 = x(1);
		float b1 = y(1);
		float a2 = x(2);
		float 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 *= sign;

		   if(area < 0.f)
		   {
			first++;
			area = 0.f;
		   }
	
		   i = 1;
		   do
		   {
		   float area2;
	           sign = -sign; //reverse order

		   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 *= sign;

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

	#undef x
	#undef y

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

	PrepTexCoords(context, first, size, GL_FALSE);

	tris.tex = context->w3dTexBuffer[context->CurrentBinding];
	tris.vertexcount = size;
	tris.v = &verts[0];
	tris.st_pattern = NULL;

	W3D_DrawTriStripV(context->w3dContext, &tris);

   return;
   }


	/*
	** Up to now everything is like a polygon. Unlike a polygon, however,
	** triangle fans and strips may be concave, and each individual triangle
	** might be backfacing.
	**
	** We calculate how many of the triangles are visible.
	*/

	backface = 0;

   if(context->CullFace_State == GL_FALSE)
   {
	for (triangle=0; triangle<context->VertexBufferPointer - 2; triangle++)
	{
	   local_or = context->VertexBuffer[triangle+0].outcode
				 | context->VertexBuffer[triangle+1].outcode
				 | context->VertexBuffer[triangle+2].outcode;

	   local_and = context->VertexBuffer[triangle+0].outcode
				  & context->VertexBuffer[triangle+1].outcode
				  & context->VertexBuffer[triangle+2].outcode;


 // if the local and code is zero, we're not completely off screen.
	   if (local_and == 0)
	   {
		complete[triangle] = local_or; 
		visible[triangle] = GL_TRUE;
		backface = 0;
	   }
	   else
	   {
		visible[triangle] = GL_FALSE;
		backface++;
	   }
	}
   }
   else
   {
	for (triangle=0; triangle<context->VertexBufferPointer - 2; triangle++)
	{
	   local_or = context->VertexBuffer[triangle].outcode
				 | context->VertexBuffer[triangle+1].outcode
				 | context->VertexBuffer[triangle+2].outcode;

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


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

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

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

	   context->CurrentCullSign = -context->CurrentCullSign;
	}
   }

	context->CurrentCullSign = CurrentCullSign;
   
//early out:
	if(triangle == backface)
	return;

	context->VertexBufferPointer -= backface; //surgeon 260302

	PrepTexCoords(context, 0, context->VertexBufferPointer, GL_FALSE);

	/*
	** Draw...
	** There are three cases:
	**
	** 1) Triangle is partially visible
	** 2) Triangle is fully visible
	** 3) Triangle is invisible
	**
	** In case 1, we draw the triangle with clip_ClipAndDrawPoly.
	** In case 2, we collect a triangle fan/strip of maximum length
	** and draw that directly
	** in case 3... WE IGNORE IT! HA!
	*/

	free = context->VertexBufferPointer;
	pnum = 0;

	triangle = 0;
	do
	{

		if (visible[triangle] == GL_FALSE) // case 3
		{
			triangle ++;
		}
		else
		{
			if (complete[triangle]) // case 1
			{
				static MGLPolygon poly;

				poly.numverts = 3;
				poly.verts[0] = triangle + 0;
				poly.verts[1] = triangle + 1;
				poly.verts[2] = triangle + 2;

				hc_ClipPoly(context, &poly, &clip[pnum], free, complete[triangle]);

				if(clip[pnum].numverts)
				{
				clip[pnum].type = W3D_PRIMITIVE_TRIFAN;
				free = clip[pnum].nextfree;
				pnum++;
				}

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

				triangle++;

				while (complete[triangle]==0 && visible[triangle] && triangle<context->VertexBufferPointer - 2 && k < 64)
				{
				clip[pnum].verts[k] = triangle+2;

				k++; triangle++;
				}

			clip[pnum].numverts = k;
			clip[pnum].type = W3D_PRIMITIVE_TRISTRIP;
			pnum++;
			}
		}

	} while (triangle<context->VertexBufferPointer - 2);


//Project to screen and Draw:

	visible[context->VertexBufferPointer-2] = GL_FALSE;
	visible[context->VertexBufferPointer-1] = GL_FALSE;

	//project clipverts without index lookup

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

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

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

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

		if(vert < context->VertexBufferPointer && visible[vert] < 2)
		{
		   v_ToScreen(context, vert);
		   visible[vert] = 2;
		}

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

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

	  if(p->type == W3D_PRIMITIVE_TRIFAN)
	  { 
	  	error = W3D_DrawTriFanV(context->w3dContext, &tris);
	  }
	  else
	  {
	  	error = W3D_DrawTriStripV(context->w3dContext, &tris);
	  }

	first += p->numverts;
	j++;
	} while (j < pnum);

#if 0
   if(context->Texture2D_State[1])
	Multitex_PolyBuffer(context, verts, pnum, GL_TRUE);
#endif

#else
		int i;
		ULONG error;
		static W3D_Vertex *verts[MGL_MAXVERTS];
		static W3D_TrianglesV tris;

	PrepTexCoords(context, 0, context->VertexBufferPointer, GL_FALSE);

		for (i=0; i<context->VertexBufferPointer-1; i++)
		{
			v_ToScreen(context, i);
			verts[i] = &(context->VertexBuffer[i].v);
		}

		tris.tex = context->w3dTexBuffer[context->CurrentBinding];
		tris.st_pattern = NULL;
		tris.vertexcount = context->VertexBufferPointer-1;
		tris.v = verts;
		#ifndef NODRAW
		error = W3D_DrawTriStripV(context->w3dContext, &tris);
		#endif
#endif
}

void d_DrawQuadStrip(GLcontext context)
{
#if !defined(DISABLE_TRANSFORMATION)
	int i,j;
	ULONG or_code, and_code;
	ULONG error;

	static W3D_Vertex *verts[4];
	static W3D_TrianglesV tris;

	if(context->CullFace_State == GL_TRUE && context->CurrentCullFace == GL_FRONT_AND_BACK)
	return;

	v_Transform(context);

	PrepTexCoords(context, 0, context->VertexBufferPointer, GL_FALSE);

	for (j=0; j<context->VertexBufferPointer; j++)
	{
		MGLVertex *v = &(context->VertexBuffer[j]);
		float w = v->bw;
		ULONG outcode = 0;

		if (w < CLIP_EPS )
		{
			outcode |= MGL_CLIP_NEGW;
		}

		if (-w > v->bx)
		{
			outcode |= MGL_CLIP_LEFT;
		}
		else if (v->bx > w)
		{
			outcode |= MGL_CLIP_RIGHT;
		}

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

		v->outcode = outcode;
	}


	for (i=0; i<context->VertexBufferPointer-2; i+=2)
	{
		or_code = context->VertexBuffer[i+0].outcode
				| context->VertexBuffer[i+1].outcode
				| context->VertexBuffer[i+2].outcode
				| context->VertexBuffer[i+3].outcode;

		and_code = context->VertexBuffer[i+0].outcode
				 & context->VertexBuffer[i+1].outcode
				 & context->VertexBuffer[i+2].outcode
				 & context->VertexBuffer[i+3].outcode;

		if (and_code) continue;

		if(context->CullFace_State == GL_TRUE && !(or_code & MGL_CLIP_NEGW))
		{
			if (hc_DecideFrontface(context, &(context->VertexBuffer[i]),
			&(context->VertexBuffer[i+1]),
			&(context->VertexBuffer[i+2])) == GL_FALSE) continue;
		}

		if (or_code == 0)
		{
			v_ToScreen(context, i);
			v_ToScreen(context, i+1);
			v_ToScreen(context, i+2);
			v_ToScreen(context, i+3);

			verts[0] = &(context->VertexBuffer[i+0].v);
			verts[1] = &(context->VertexBuffer[i+1].v);
			verts[2] = &(context->VertexBuffer[i+3].v);
			verts[3] = &(context->VertexBuffer[i+2].v);
			tris.tex = context->w3dTexBuffer[context->CurrentBinding];
			tris.st_pattern = NULL;
			tris.vertexcount = 4;
			tris.v = verts;

			error = W3D_DrawTriFanV(context->w3dContext, &tris);
		}
		else
		{
			static MGLPolygon poly;
			poly.numverts = 4;
			poly.verts[0] = i;
			poly.verts[1] = i+1;
			poly.verts[2] = i+3;
			poly.verts[3] = i+2;

			hc_ClipAndDrawPoly(context, &poly, or_code);
		}
	}
#else
	int i;
	ULONG error;
	static W3D_Vertex *verts[4];
	static W3D_TrianglesV tris;

	PrepTexCoords(context, 0, context->VertexBufferPointer, GL_FALSE);

	for (i=0; i<context->VertexBufferPointer-2; i+=2)
	{
	    v_ToScreen(context, i);
	    v_ToScreen(context, i+1);
	    v_ToScreen(context, i+2);
	    v_ToScreen(context, i+3);

	    verts[0] = &(context->VertexBuffer[i+0].v);
	    verts[1] = &(context->VertexBuffer[i+1].v);
	    verts[2] = &(context->VertexBuffer[i+3].v);
	    verts[3] = &(context->VertexBuffer[i+2].v);
	    tris.tex = context->w3dTexBuffer[context->CurrentBinding];
	    tris.st_pattern = NULL;
	    tris.vertexcount = 4;
	    tris.v = verts;

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

void d_DrawQuads(GLcontext context)
{
#if !defined(DISABLE_TRANSFORMATION)
	int i,j;
	ULONG or_code, and_code;
	ULONG error;
	static W3D_Vertex *verts[4];
	static W3D_TrianglesV tris;

	if(context->CullFace_State == GL_TRUE && context->CurrentCullFace == GL_FRONT_AND_BACK)
	return;

	v_Transform(context);

	for (i=0; i<context->VertexBufferPointer; i+=4)
	{
	   for (j=i; j<i+4;j++)
	   {
		MGLVertex *v = &(context->VertexBuffer[j]);
		float w = v->bw;
		ULONG outcode = 0;

		if (w < CLIP_EPS )
		{
			outcode |= MGL_CLIP_NEGW;
		}

		if (-w > v->bx)
		{
			outcode |= MGL_CLIP_LEFT;
		}
		else if (v->bx > w)
		{
			outcode |= MGL_CLIP_RIGHT;
		}

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

		v->outcode = outcode;
	  }

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

		and_code = context->VertexBuffer[i+0].outcode
				 & context->VertexBuffer[i+1].outcode
				 & context->VertexBuffer[i+2].outcode
				 & context->VertexBuffer[i+3].outcode;

		if (and_code) continue;


		if(context->CullFace_State == GL_TRUE && !(or_code & MGL_CLIP_NEGW))
		{
			if (hc_DecideFrontface(context, &(context->VertexBuffer[i]),
			&(context->VertexBuffer[i+1]),
			&(context->VertexBuffer[i+2])) == GL_FALSE) continue;
		}

		PrepTexCoords(context, i, 4, GL_FALSE);

		if (or_code == 0)
		{
			v_ToScreen(context, i);
			v_ToScreen(context, i+1);
			v_ToScreen(context, i+2);
			v_ToScreen(context, i+3);

			verts[0] = &(context->VertexBuffer[i+0].v);
			verts[1] = &(context->VertexBuffer[i+1].v);
			verts[2] = &(context->VertexBuffer[i+2].v);
			verts[3] = &(context->VertexBuffer[i+3].v);
			tris.tex = context->w3dTexBuffer[context->CurrentBinding];
			tris.st_pattern = NULL;
			tris.vertexcount = 4;
			tris.v = verts;
			#ifndef NODRAW
			error = W3D_DrawTriFanV(context->w3dContext, &tris);
			#else
			printf("d_DrawQuads\n");
			DUMP_VERTEX(context->VertexBuffer[i+0]);
			DUMP_VERTEX(context->VertexBuffer[i+1]);
			DUMP_VERTEX(context->VertexBuffer[i+2]);
			DUMP_VERTEX(context->VertexBuffer[i+3]);
			printf("-----------------------------------\n");
			#endif
		}
		else
		{
			static MGLPolygon poly;
			poly.numverts = 4;
			poly.verts[0] = i;
			poly.verts[1] = i+1;
			poly.verts[2] = i+2;
			poly.verts[3] = i+3;
			hc_ClipAndDrawPoly(context, &poly, or_code);
		}
	}

#else
	int i;
	ULONG error;
	static W3D_Vertex *verts[4];
	static W3D_TrianglesV tris;

	PrepTexCoords(context, 0, context->VertexBufferPointer, GL_FALSE);

	for (i=0; i<context->VertexBufferPointer; i+=4)
	{
	    v_ToScreen(context, i);
	    v_ToScreen(context, i+1);
	    v_ToScreen(context, i+2);
	    v_ToScreen(context, i+3);

	    verts[0] = &(context->VertexBuffer[i+0].v);
	    verts[1] = &(context->VertexBuffer[i+1].v);
	    verts[2] = &(context->VertexBuffer[i+2].v);
	    verts[3] = &(context->VertexBuffer[i+3].v);
	    tris.tex = context->w3dTexBuffer[context->CurrentBinding];
	    tris.st_pattern = NULL;
	    tris.vertexcount = 4;
	    tris.v = verts;

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



//For chaining and buffering multitexture-polys:

typedef struct MtexPolyIdx_s
{
	W3D_Texture	*tmu[2];
	GLuint		first;
	GLuint		count;

} MtexPolyIdx;


//alternative to W3D_Vertex:

typedef struct W3D_VAVertex_s
{
	float x,y,z,w;
	float s1,t1,s2,t2;
	ULONG color;
	ULONG _pad_[3]; //16 byte align

} W3D_VAVertex;


#define MTEX_INDEXSIZE 1024
#define MTEX_VERTEXBUFFERSIZE 4096

static MtexPolyIdx pidx[MTEX_INDEXSIZE];
static int polypointer = 0;

static W3D_VAVertex *mtex_pbuffer = NULL;

GLboolean AllocMtex()
{
	int i;

	if(mtex_pbuffer == NULL)
	{
		mtex_pbuffer = (W3D_VAVertex *) malloc( sizeof(W3D_VAVertex) * MTEX_VERTEXBUFFERSIZE);
	}

	if(!mtex_pbuffer)
		return GL_FALSE;

	return GL_TRUE;
}

void FreeMtex(void)
{
	if(mtex_pbuffer) free(mtex_pbuffer);
}

#define CPACK(r,g,b,a) \
(ULONG)( (((ULONG)((a)*255.f))<<24) | (((ULONG)((r)*255.f))<<16) | (((ULONG)((g)*255.f))<<8) | ((ULONG)(b*255.f)) )


static void v_MtexToScreen_Flat(GLcontext context, int i, int bufpointer)
{
	float x,y,z,w;
	float az;

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

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

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

	mtex_pbuffer[bufpointer].x = x;
	mtex_pbuffer[bufpointer].y = y;
	mtex_pbuffer[bufpointer].z = z;
	mtex_pbuffer[bufpointer].w = w;

	mtex_pbuffer[bufpointer].s1 = context->VertexBuffer[i].v.u;
	mtex_pbuffer[bufpointer].t1 = context->VertexBuffer[i].v.v;

	mtex_pbuffer[bufpointer].s2 = context->VertexBuffer[i].tcoord.s;
	mtex_pbuffer[bufpointer].t2 = context->VertexBuffer[i].tcoord.t;

}

static void v_MtexToScreen_Smooth(GLcontext context, int i, int bufpointer)
{
	float x,y,z,w;
	float az;

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

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

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

	mtex_pbuffer[bufpointer].s1 = context->VertexBuffer[i].v.u ;
	mtex_pbuffer[bufpointer].t1 = context->VertexBuffer[i].v.v ;

	mtex_pbuffer[bufpointer].s2 = context->VertexBuffer[i].tcoord.s;
	mtex_pbuffer[bufpointer].t2 = context->VertexBuffer[i].tcoord.t;

	mtex_pbuffer[bufpointer].color = CPACK(context->VertexBuffer[i].v.color.r, context->VertexBuffer[i].v.color.g, context->VertexBuffer[i].v.color.b, context->VertexBuffer[i].v.color.a);
}

static void ProjectMtex_Flat(GLcontext context, int numverts, int bufstart)
{
	int i;
	int bufpointer;
	float az;
	float x,y,z,w;

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

	i = 0;
	bufpointer = bufstart;

	do
	{
	w = 1.0 / context->VertexBuffer[i].bw;

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

	mtex_pbuffer[bufpointer].x = x;
	mtex_pbuffer[bufpointer].y = y;
	mtex_pbuffer[bufpointer].z = z;
	mtex_pbuffer[bufpointer].w = w;

	mtex_pbuffer[bufpointer].s1 = context->VertexBuffer[i].v.u;
	mtex_pbuffer[bufpointer].t1 = context->VertexBuffer[i].v.v;

	mtex_pbuffer[bufpointer].s2 = context->VertexBuffer[i].tcoord.s;
	mtex_pbuffer[bufpointer].t2 = context->VertexBuffer[i].tcoord.t;

	i++; bufpointer++;
	} while (i < numverts);

}

static void ProjectMtex_Smooth(GLcontext context, int numverts, int bufstart)
{
	int i;
	int bufpointer;
	float az;
	float x,y,z,w;

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

	i = 0;
	bufpointer = bufstart;

	do
	{
	w = 1.0 / context->VertexBuffer[i].bw;

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

	mtex_pbuffer[bufpointer].s1 = context->VertexBuffer[i].v.u;
	mtex_pbuffer[bufpointer].t1 = context->VertexBuffer[i].v.v;

	mtex_pbuffer[bufpointer].s2 = context->VertexBuffer[i].tcoord.s;
	mtex_pbuffer[bufpointer].t2 = context->VertexBuffer[i].tcoord.t;

	mtex_pbuffer[bufpointer].color = CPACK(context->VertexBuffer[i].v.color.r, context->VertexBuffer[i].v.color.g, context->VertexBuffer[i].v.color.b, context->VertexBuffer[i].v.color.a);

	i++; bufpointer++;
	} while (i < numverts);

}


void d_DrawSmoothPoly(GLcontext context)
{
	int i,j;
	ULONG and_code, or_code, local_or, guard_band;
	ULONG error;
	static MGLPolygon poly;
	static W3D_Vertex **verts = NULL;
	static W3D_TrianglesV fan;
	static ULONG complete[MGL_MAXVERTS];
	int triangle;
	int nocull;
	int pnum, free;

	if(context->VertexBufferPointer < 3)
		return;

	if(context->CullFace_State == GL_TRUE && context->CurrentCullFace == GL_FRONT_AND_BACK)
		return;

	v_Transform(context);

	and_code = 0xff; or_code = 0;

	for (i=0; i<context->VertexBufferPointer; i++)
	{
		MGLVertex *v = &(context->VertexBuffer[i]);
		float w = v->bw;
		ULONG outcode = 0;

		if (w < CLIP_EPS )
		{
			outcode |= MGL_CLIP_NEGW;
		}

		if (-w > v->bx)
		{
			outcode |= MGL_CLIP_LEFT;
		}
		else if (v->bx > w)
		{
			outcode |= MGL_CLIP_RIGHT;
		}

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

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

		poly.verts[i] = i;
	}

   if (and_code)
	return;


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


   poly.numverts = context->VertexBufferPointer;


#if defined(PRIORITIZE_BANDWIDTH) || defined(PRIORITIZE_FILRATE)

   //try to shrink primitive:

   if(context->VertexBuffer[0].outcode && poly.numverts > 3)
   {
	ULONG local_and;
	int size;
	int first;

	first = 0;
	i = poly.numverts - 2;

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

	if(local_and)
	{
		i--;

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

		   i--;
		}
	}

	size = i+2;

	if(size > 3)
	{
	   i = 1;

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

	   if(local_and)
	   {
		i++;

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

	   first = i-1;
	}

	if((size < poly.numverts) || first)
	{
	   context->VertexBufferPointer = size;

	   poly.numverts = size - first;

	   or_code = context->VertexBuffer[0].outcode;
	
	   i = 1;
	   do
	   {
		poly.verts[i] = first+i;
		or_code |= context->VertexBuffer[first+i].outcode;

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

#endif

//guardband-test:

   if(or_code == 0 || (or_code & context->ClipFlags))
   {
	guard_band = or_code;
   }
   else
   {
	guard_band = 0;
	i = 0;

	do
	{
	  MGLVertex *v = &context->VertexBuffer[poly.verts[i]];

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

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

	   if (-gcw > v->by)
		guard_band |= MGL_CLIP_BOTTOM;
	   else if (v->by > gcw)
		guard_band |= MGL_CLIP_TOP;
	   }
	i++;
	} while (i < poly.numverts && guard_band == 0);

   }

   if(guard_band == 0)
   {
	int vert;

	if( poly.numverts == 3 && context->CullFace_State == GL_TRUE)
	{
		if( hc_DecideFrontface(context, &context->VertexBuffer[0], &context->VertexBuffer[poly.verts[1]], &context->VertexBuffer[poly.verts[1] + 1]) == GL_FALSE)
		return;
	}

	PrepTexCoords(context, poly.verts[1], poly.numverts, GL_TRUE);


	verts[0] = &(context->VertexBuffer[0].v);
	v_ToScreen(context, 0);

	vert = poly.verts[1];
	i = 1;

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

	i++; vert++;
	} while (i < poly.numverts);


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

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

	return;
   }

   i = poly.verts[1];
   triangle = 0;

   if(context->CullFace_State == GL_FALSE)
   {
	do
	{
		complete[triangle] = context->VertexBuffer[0].outcode | context->VertexBuffer[i].outcode | context->VertexBuffer[i+1].outcode;

	triangle++; i++;
	} while (i < context->VertexBufferPointer-1);
   }
   else
   {
	nocull = 0;

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

		complete[triangle] = local_or;

		if(local_or & MGL_CLIP_NEGW)
		{
		   nocull = 1;
		}
		else if(nocull == 0)
		{
		   if(hc_DecideFrontface(context, &context->VertexBuffer[0], &context->VertexBuffer[i], &context->VertexBuffer[i+1]) == GL_TRUE)
		   {
			nocull = 1;
		   }
		}

	i++; triangle++;
	} while (i < context->VertexBufferPointer - 1);
	
//early out:
	if(nocull == 0)
		return;
   }

	PrepTexCoords(context, poly.verts[1], poly.numverts, GL_TRUE);

	i = poly.verts[1];
	triangle = 0;
	free = context->VertexBufferPointer;
	pnum = 0;

	do
	{
		if (complete[triangle]) // case 1
		{
			static MGLPolygon cpoly;

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

			hc_ClipPoly(context, &cpoly, &clip[pnum], free, complete[triangle]);

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

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

			triangle ++;
			i        ++;

			while (complete[triangle]==0 && i<context->VertexBufferPointer - 1)
			{
				clip[pnum].verts[k] = i+1;
				i++; k++; triangle++;
			}
		clip[pnum].numverts = k;
		pnum++;
		}

	} while (i<context->VertexBufferPointer-1);


   //project clipverts

   // mark unprojected verts within the vertexbuffer-range

   for(i=0; i<context->VertexBufferPointer; i++)
   {
	complete[i] = 0;
   }

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

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

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

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

	   if(vert < context->VertexBufferPointer && complete[vert] == 0)
	   {
		complete[vert] = 1;
		v_ToScreen(context, vert);
	   }

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

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

   } while (++j < pnum);
}


void d_DrawMtexPoly(GLcontext context)
{
   int i,j;
   ULONG and_code, or_code, guard_band;
   static MGLPolygon poly;
   static int mtexverts;
   static int start;

	if(context->VertexBufferPointer < 3)
		return;

	if(context->CullFace_State == GL_TRUE && context->CurrentCullFace == GL_FRONT_AND_BACK)
		return;

	v_Transform(context);

	and_code = 0xff; or_code = 0;

	for (i=0; i<context->VertexBufferPointer; i++)
	{
		MGLVertex *v = &(context->VertexBuffer[i]);
		float w = v->bw;
		ULONG outcode = 0;

		if (w < CLIP_EPS )
		{
			outcode |= MGL_CLIP_NEGW;
		}

		if (-w > v->bx)
		{
			outcode |= MGL_CLIP_LEFT;
		}
		else if (v->bx > w)
		{
			outcode |= MGL_CLIP_RIGHT;
		}

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

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

		poly.verts[i] = i;
	}

	if (and_code)
	return;

	poly.numverts = context->VertexBufferPointer;

#if defined(PRIORITIZE_BANDWIDTH) || defined(PRIORITIZE_FILRATE)

   //try to shrink primitive:

   if(context->VertexBuffer[0].outcode && poly.numverts > 3)
   {
	ULONG local_and;
	int size;
	int first;

	first = 0;
	i = poly.numverts - 2;

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

	if(local_and)
	{
		i--;

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

		   i--;
		}
	}

	size = i+2;

	if(size > 3)
	{
	   i = 1;

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

	   if(local_and)
	   {
		i++;

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

	   first = i-1;
	}

	if((size < poly.numverts) || first)
	{
	   context->VertexBufferPointer = size;

	   poly.numverts = size - first;

	   or_code = context->VertexBuffer[0].outcode;
	
	   i = 1;
	   do
	   {
		poly.verts[i] = first+i;
		or_code |= context->VertexBuffer[first+i].outcode;

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

#endif


   if( poly.numverts == 3 && context->CullFace_State == GL_TRUE && !(or_code & MGL_CLIP_NEGW) )
   {
	if( hc_DecideFrontface(context, &context->VertexBuffer[0], &context->VertexBuffer[poly.verts[1]], &context->VertexBuffer[poly.verts[1] + 1]) == GL_FALSE)
		return;
   }


//guardband-test

   if(or_code == 0 || (or_code & context->ClipFlags))
   {
   	guard_band = or_code;
   }
   else
   {
	i = 0;
	guard_band = 0;

	do
	{
	  MGLVertex *v = &context->VertexBuffer[poly.verts[i]];

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

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

	   }

	i++;
	} while (i < poly.numverts && guard_band == 0);
   }

   if(polypointer == 0)
 	mtexverts = 0; //reset

   start = mtexverts;

   if(or_code == 0)
   {
	if(context->ShadeModel == GL_SMOOTH)
	{
		ProjectMtex_Smooth(context, poly.numverts, mtexverts);
	}
	else
	{
		ProjectMtex_Flat(context, poly.numverts, mtexverts);
	}

	mtexverts += poly.numverts;
   }
   else
   {
	if(guard_band)
	{
	   hc_ClipPolyFF(context, &poly, or_code);

	   if(!poly.numverts)
		return;
	}

	if(context->ShadeModel == GL_SMOOTH)
	{
		for(i=0; i< poly.numverts; i++)
		{
			v_MtexToScreen_Smooth(context, poly.verts[i], mtexverts++);
		}
	}
	else
	{
		for(i=0; i< poly.numverts; i++)
		{
			v_MtexToScreen_Flat(context, poly.verts[i], mtexverts++);
		}
	}
   }

   pidx[polypointer].count = poly.numverts;
   pidx[polypointer].first = start;
   pidx[polypointer].tmu[0] = context->w3dTexBuffer[context->CurrentBinding];
   pidx[polypointer].tmu[1] = context->w3dTexBuffer[context->VirtualBinding];
   polypointer++;
}


void d_DrawNormalPoly(GLcontext context)
{
	int i,j;
	ULONG error;
	ULONG and_code, or_code, guard_band;
	static W3D_Vertex **verts = NULL;
	static W3D_TrianglesV fan;
	static MGLPolygon poly;

	if(context->VertexBufferPointer < 3)
		return;

	if(context->CullFace_State == GL_TRUE && context->CurrentCullFace == GL_FRONT_AND_BACK)
		return;

	v_Transform(context);

	and_code = 0xff; or_code = 0;

	for (i=0; i<context->VertexBufferPointer; i++)
	{
		MGLVertex *v = &(context->VertexBuffer[i]);
		float w = v->bw;
		ULONG outcode = 0;

		if (w < CLIP_EPS )
		{
			outcode |= MGL_CLIP_NEGW;
		}

		if (-w > v->bx)
		{
			outcode |= MGL_CLIP_LEFT;
		}
		else if (v->bx > w)
		{
			outcode |= MGL_CLIP_RIGHT;
		}

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

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

		poly.verts[i] = i;
	}

   if (and_code)
	return;

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

   poly.numverts = context->VertexBufferPointer;


#if defined(PRIORITIZE_BANDWIDTH) || defined(PRIORITIZE_FILRATE)

   //try to shrink primitive:

   if(context->VertexBuffer[0].outcode && poly.numverts > 3)
   {
	ULONG local_and;
	int size;
	int first;

	first = 0;
	i = poly.numverts - 2;

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

	if(local_and)
	{
		i--;

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

		   i--;
		}
	}

	size = i+2;

	if(size > 3)
	{
	   i = 1;

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

	   if(local_and)
	   {
		i++;

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

	   first = i-1;
	}

	if((size < poly.numverts) || first)
	{
	   context->VertexBufferPointer = size;

	   poly.numverts = size - first;

	   or_code = context->VertexBuffer[0].outcode;
	
	   i = 1;
	   do
	   {
		poly.verts[i] = first+i;
		or_code |= context->VertexBuffer[first+i].outcode;

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

#endif

   if( poly.numverts == 3 && context->CullFace_State == GL_TRUE && !(or_code & MGL_CLIP_NEGW) )
   {
	if( hc_DecideFrontface(context, &context->VertexBuffer[0], &context->VertexBuffer[poly.verts[1]], &context->VertexBuffer[poly.verts[1] + 1]) == GL_FALSE)
		return;
   }

   PrepTexCoords(context, poly.verts[1], poly.numverts, GL_TRUE);


//guardband-test

   if(or_code == 0 || (or_code & context->ClipFlags))
   {
   	guard_band = or_code;
   }
   else
   {
	i = 0;
	guard_band = 0;

	do
	{
	  MGLVertex *v = &context->VertexBuffer[poly.verts[i]];

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

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

	i++;
	} while (i < poly.numverts && guard_band == 0);
   }


   if(guard_band == 0)
   {
	int vert;

	verts[0] = &(context->VertexBuffer[0].v);
	v_ToScreen(context, 0);

	vert = poly.verts[1];
	i = 1;

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

	i++; vert++;
	} while (i < poly.numverts);

   }
   else
   {
	   hc_ClipPolyFF(context, &poly, or_code);

	   if(!poly.numverts)
		return;

	   i=0;

	   do
	   {
		verts[i] = &(context->VertexBuffer[poly.verts[i]].v);
		v_ToScreen(context, poly.verts[i]);

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

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

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


/*
surgeon: added fast path when primitive or_code equals 0
surgeon: added buffering for clipping events

surgeon: added a version (d_DrawTrianglesVA) that uses W3D_DrawElements/W3D_DrawArray for unclipped chains of triangles. (DrawFn) Pointer is set in GLEnd, based on the number of triangles in the pipeline.
*/

void d_DrawTriangles(GLcontext context)
{
#if !defined(DISABLE_TRANSFORMATION)
	int i,j;
	static W3D_TriangleV tri;
	ULONG or_code, and_code;
	ULONG error;

	if(context->CullFace_State == GL_TRUE && context->CurrentCullFace == GL_FRONT_AND_BACK)
	return;

	v_Transform(context);

	for (i=0; i<context->VertexBufferPointer; i++)
	{
		MGLVertex *v = &(context->VertexBuffer[i]);
		float w = v->bw;
		ULONG outcode = 0;

		if (w < CLIP_EPS )
		{
			outcode |= MGL_CLIP_NEGW;
		}

		if (-w > v->bx)
		{
			outcode |= MGL_CLIP_LEFT;
		}
		else if (v->bx > w)
		{
			outcode |= MGL_CLIP_RIGHT;
		}

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

		v->outcode = outcode;
	}


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


	for (i=0; i<context->VertexBufferPointer; i+=3)
	{
	   or_code = context->VertexBuffer[i+0].outcode
				| context->VertexBuffer[i+1].outcode
				| context->VertexBuffer[i+2].outcode;

	   and_code = context->VertexBuffer[i+0].outcode
				 & context->VertexBuffer[i+1].outcode
				 & context->VertexBuffer[i+2].outcode;

	   if (and_code)
		continue;

	   if(context->CullFace_State == GL_TRUE && !(or_code & MGL_CLIP_NEGW))
	   {
		if (hc_DecideFrontface(context,
		&(context->VertexBuffer[i+0]),
		&(context->VertexBuffer[i+1]),
		&(context->VertexBuffer[i+2])) == GL_FALSE)
			continue;
	   }

	   PrepTexCoords(context, i, 3, GL_FALSE);

	   if (or_code == 0)
	   {
		v_ToScreen(context, i+0);
		v_ToScreen(context, i+1);
		v_ToScreen(context, i+2);

		tri.v1 = &(context->VertexBuffer[i+0].v);
		tri.v2 = &(context->VertexBuffer[i+1].v);
		tri.v3 = &(context->VertexBuffer[i+2].v);

		error = W3D_DrawTriangleV(context->w3dContext, &tri);
	   }
	   else
	   {
		static MGLPolygon poly;
		poly.numverts = 3;
		poly.verts[0] = i+0;
		poly.verts[1] = i+1;
		poly.verts[2] = i+2;

		hc_ClipAndDrawPoly(context, &poly, or_code);
	   }
	}
#else
	int i;
	static W3D_TriangleV tri;
	ULONG error;

	PrepTexCoords(context, 0, context->VertexBufferPointer, GL_FALSE);

	for (i=0; i<context->VertexBufferPointer; i+=3)
	{
		v_ToScreen(context, i);
		v_ToScreen(context, i+1);
		v_ToScreen(context, i+2);

		tri.v1 = &(context->VertexBuffer[i+0].v);
		tri.v2 = &(context->VertexBuffer[i+1].v);
		tri.v3 = &(context->VertexBuffer[i+2].v);
		tri.tex = context->w3dTexBuffer[context->CurrentBinding];
		tri.st_pattern = NULL;
		error = W3D_DrawTriangleV(context->w3dContext, &tri);
	}
#endif
}

void d_DrawTrianglesVA(GLcontext context)
{
	int i,j;
	ULONG or_code, and_code;
	ULONG error;
	ULONG vcount;	//counter for vertices
	GLbitfield ClientState;
	GLboolean continous;
	GLfloat sign;
	UWORD *vaindex;

	v_Transform(context);

	for (i=0; i<context->VertexBufferPointer; i++)
	{
		MGLVertex *v = &(context->VertexBuffer[i]);
		float w = v->bw;
		ULONG outcode = 0;

		if (w < CLIP_EPS )
		{
			outcode |= MGL_CLIP_NEGW;
		}

		if (-w > v->bx)
		{
			outcode |= MGL_CLIP_LEFT;
		}
		else if (v->bx > w)
		{
			outcode |= MGL_CLIP_RIGHT;
		}

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

		v->outcode = outcode;
	}

	vcount = 0;
	vaindex = &context->ElementIndex[0];

	continous = GL_TRUE; //decide drawfunc
	sign = (GLfloat)-context->CurrentCullSign;

	for (i=0; i<context->VertexBufferPointer; i+=3)
	{
	   or_code = context->VertexBuffer[i+0].outcode
				| context->VertexBuffer[i+1].outcode
				| context->VertexBuffer[i+2].outcode;

	   and_code = context->VertexBuffer[i+0].outcode
				 & context->VertexBuffer[i+1].outcode
				 & context->VertexBuffer[i+2].outcode;

	   if (and_code)
	   {
		continous = GL_FALSE;
		continue;
	   }

	   if (or_code == 0)
	   {
		v_ToScreenVA(context, i+0);
		v_ToScreenVA(context, i+1);
		v_ToScreenVA(context, i+2);

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

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

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

		   if (area < context->MinTriArea)
		   {
			continous = GL_FALSE;
			continue;
		   }

		   #undef x
		   #undef y
		}

	        //build index for W3D_DrawElements

		vaindex[vcount+0] = i+0;
		vaindex[vcount+1] = i+1;
		vaindex[vcount+2] = i+2;
		vcount += 3;
	   }
  	   else
	   {
		static MGLPolygon poly;

		continous = GL_FALSE;

		if(context->CullFace_State == GL_TRUE && !(or_code & MGL_CLIP_NEGW))
		{
			if (hc_DecideFrontface(context, &(context->VertexBuffer[i+0]), &(context->VertexBuffer[i+1]), &(context->VertexBuffer[i+2])) == GL_FALSE)
			continue;
		}

	        PrepTexCoords(context, i, 3, GL_FALSE);

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

		hc_ClipAndDrawPoly(context, &poly, or_code);
	   }
	}

	ClientState = GLCS_VERTEX;

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

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

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

	Set_W3D_VertexPointer(context->w3dContext, (void*)&(context->VertexBuffer->bx), sizeof(MGLVertex), W3D_VERTEX_F_F_F, 0);

	if(context->ShadeModel == GL_SMOOTH)
	{
		ClientState |= GLCS_COLOR;

		Set_W3D_ColorPointer(context->w3dContext, (void*)&(context->VertexBuffer->v.color.r), sizeof(MGLVertex), W3D_COLOR_FLOAT, W3D_CMODE_RGBA, 0);
	}


// draw with fastest method

	if(continous == GL_TRUE)
	{
		error = W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRIANGLES, 0, context->VertexBufferPointer);
	}
	else
	{
		error = W3D_DrawElements(context->w3dContext, W3D_PRIMITIVE_TRIANGLES, W3D_INDEX_UWORD, vcount, (void*)&vaindex[0]);
	}

	Reset_W3D_ArrayPointers(context, ClientState);

}


/*
** A MGL_FLATFAN / MGL_FLATSTRIP is a triangle fan or strip
** that is specified in device corrdinates and is drawn
** regardless of current matrix or viewport
**
** Very useful for bypassing the transformation pipeline 
**
*/

void d_DrawFlat(GLcontext context)
{
	ULONG error;

	int i;

	static W3D_Vertex *verts[MGL_MAXVERTS];
	static W3D_TrianglesV tris;

	PrepTexCoords(context, 0, context->VertexBufferPointer, GL_FALSE);

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

	context->VertexBuffer[i].v.x = (W3D_Float) context->VertexBuffer[i].bx;
	context->VertexBuffer[i].v.y = (W3D_Float) context->VertexBuffer[i].by;
	context->VertexBuffer[i].v.z = (W3D_Double) context->VertexBuffer[i].bz;
	context->VertexBuffer[i].v.w = (W3D_Float) context->VertexBuffer[i].bw;

	}

	tris.tex = context->w3dTexBuffer[context->CurrentBinding];
	tris.st_pattern = NULL;
	tris.v = verts;
	tris.vertexcount = context->VertexBufferPointer;

	#ifndef NODRAW

	if(context->CurrentPrimitive == MGL_FLATSTRIP)
	{
		error = W3D_DrawTriStripV(context->w3dContext, &tris);
	}
	else //MGL_FLATFAN
	{
		error = W3D_DrawTriFanV(context->w3dContext, &tris);
	}

	#endif
}


void dh_DrawPoly(GLcontext context, MGLPolygon *poly)
{
	int i;
	ULONG error;
	static W3D_Vertex *verts[8];//max clipverts for quad
	static W3D_TrianglesV tris;

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

	tris.tex = context->w3dTexBuffer[context->CurrentBinding];
	tris.st_pattern = NULL;
	tris.vertexcount = poly->numverts;
	tris.v = verts;
	#ifndef NODRAW
	error = W3D_DrawTriFanV(context->w3dContext, &tris);
	#endif
}


/*
** See below for the interface to MiniGL/OpenGL
*/

static void d_DrawMtexPolyChains(GLcontext context, GLuint unit, GLuint size)
{
	int i;
	ULONG error;

	if(unit == 0)
	{
		i = 0;
		do
		{
			Set_W3D_Texture(context->w3dContext, 0, pidx[i].tmu[0]);

			error = W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRIFAN, pidx[i].first, pidx[i].count);

		i++;
		} while(i < size);
	}
	else
	{
		i = 0;
		do
		{
			Set_W3D_Texture(context->w3dContext, 0, pidx[i].tmu[1]);

			error = W3D_DrawArray(context->w3dContext, W3D_PRIMITIVE_TRIFAN, pidx[i].first, pidx[i].count);

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

/*
**

MiniGL API:

mglDrawMultitexBuffer(GLenum bs, GLenum bd, GLenum env)

where bs = BlendSrc, bd = BlendDst, env = TexEnv

This function should be called when all polys are in chain or a global state change make it required.
It sets the supplied state-parameters, draws the buffer, and returns the context as it was before.


**
*/

void MGLDrawMultitexBuffer (GLcontext context, GLenum BSrc, GLenum BDst, GLenum TexEnv)
{
	GLboolean blendfunc_changed;
	GLboolean depthmask_changed;
	GLbitfield ClientState;
	GLenum CurBlendSrc, CurBlendDst;

	if(polypointer == 0)
		return;

#ifdef AUTOMATIC_LOCKING_ENABLE

	if (context->LockMode != MGL_LOCK_MANUAL)
	{ 
	   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

	if (context->FogDirty && context->Fog_State)
	{
		fog_Set(context);
		context->FogDirty = GL_FALSE;
	}

	if(context->CurTexEnv != TexEnv)
	{
		W3D_Texture *tex = pidx[0].tmu[1];

		switch(TexEnv)
		{
		case GL_MODULATE:
			W3D_SetTexEnv(context->w3dContext, tex, W3D_MODULATE, NULL);
			break;
		case GL_DECAL:
			W3D_SetTexEnv(context->w3dContext, tex, W3D_DECAL, NULL);
			break;
		default:
		case GL_REPLACE:
			W3D_SetTexEnv(context->w3dContext, tex, W3D_REPLACE, NULL);
			break;
		}
	}

	if(context->CurBlendSrc != BSrc || context->CurBlendDst != BDst)
	{
		CurBlendSrc = context->CurBlendSrc;
		CurBlendDst = context->CurBlendDst;

	   	GLBlendFunc(context, BSrc, BDst);
		blendfunc_changed = GL_TRUE;
	}
	else
	{
		blendfunc_changed = GL_FALSE;
	}

	//set vertexpointer to the multitexturebuffer

	Set_W3D_VertexPointer(context->w3dContext, (void*)&mtex_pbuffer[0].x, sizeof(W3D_VAVertex), W3D_VERTEX_F_F_F, 0); 

	//set the texcoordpointer to tmu0 coords:

	Set_W3D_TexCoordPointer(context->w3dContext, (void*)&mtex_pbuffer[0].s1, sizeof(W3D_VAVertex), 0, 4, -4, W3D_TEXCOORD_NORMALIZED);


	if(context->ShadeModel == GL_FLAT && context->UpdateCurrentColor == GL_TRUE)
	{
		W3D_SetCurrentColor(context->w3dContext, &context->CurrentColor);
		context->UpdateCurrentColor = GL_FALSE;
	}
	else if(context->ShadeModel == GL_SMOOTH)
	{
		Set_W3D_ColorPointer(context->w3dContext, (void*)&mtex_pbuffer[0].color, sizeof(W3D_VAVertex), W3D_COLOR_UBYTE, W3D_CMODE_ARGB, 0); 
	}

	//draw the buffered primitives for tmu[0]

	d_DrawMtexPolyChains(context, 0, polypointer);

#if 0
	//Disable Zbuffer updates for second pass

	if(context->DepthMask == GL_TRUE)
	{
		W3D_SetState(context->w3dContext, W3D_ZBUFFERUPDATE, W3D_DISABLE);

		depthmask_changed = GL_TRUE;
	}
	else
	{
		depthmask_changed = GL_FALSE;
	}
#endif

	//switch the texcoordpointer to tmu1 coords:

	Set_W3D_TexCoordPointer(context->w3dContext, (void*)&mtex_pbuffer[0].s2, sizeof(W3D_VAVertex), 0, 4, -12, W3D_TEXCOORD_NORMALIZED);

	//draw the buffered primitives for tmu[1] with blending enabled:

	ENABLE_BLEND

	d_DrawMtexPolyChains(context, 1, polypointer);

	DISABLE_BLEND

	polypointer = 0; //reset the buffer

	//restore vertexpointers to their previous position

	ClientState = GLCS_VERTEX | GLCS_TEXTURE;

	if(context->ShadeModel == GL_SMOOTH)
	{
		ClientState |= GLCS_COLOR;
	}

	Reset_W3D_ArrayPointers(context, ClientState);

#if 0
	if(depthmask_changed == GL_TRUE)
	{
		W3D_SetState(context->w3dContext, W3D_ZBUFFERUPDATE, W3D_ENABLE);
	}
#endif

	//reset states to entry-level

	if(blendfunc_changed == GL_TRUE)
	{
		GLBlendFunc(context, CurBlendSrc, CurBlendDst);
	}

	if(context->CurTexEnv != TexEnv)
	{
		W3D_Texture *tex = pidx[0].tmu[1];

		switch(context->CurTexEnv)
		{
		case GL_MODULATE:
			W3D_SetTexEnv(context->w3dContext, tex, W3D_MODULATE, NULL);
			break;
		case GL_DECAL:
			W3D_SetTexEnv(context->w3dContext, tex, W3D_DECAL, NULL);
			break;
		default:
		case GL_REPLACE:
			W3D_SetTexEnv(context->w3dContext, tex, W3D_REPLACE, NULL);
			break;
		}
	}

#ifdef AUTOMATIC_LOCKING_ENABLE

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

#endif

}

#ifdef __VBCC__

	#undef v_ToScreen
	#undef v_ToScreenVA

#endif
