/*===========================================================================*/
/*                                                                           */
/* Mesa-3.0 DirectX 6 Driver                                                 */
/*                                                                           */
/* By Leigh McRae                                                            */
/*                                                                           */
/* http://www.altsoftware.com/                                               */
/*                                                                           */
/* Copyright (c) 1999-1998  alt.software inc.  All Rights Reserved           */
/*===========================================================================*/
#include <stdio.h>
#include "clip.h"
#include "context.h"
#include "light.h"
#include "lines.h"
#include "macros.h"
#include "matrix.h"
#include "pb.h"
#include "points.h"
#include "types.h"
#include "vb.h"
#include "vbrender.h"
#include "xform.h"
#include "D3DMesa.h"

static void SetRenderStates( GLcontext *ctx );
static void DebugRenderStates( GLcontext *ctx, BOOL bForce );

static void RenderPointsVB( GLcontext *ctx, GLuint start, GLuint end );
static void RenderTriangleVB( GLcontext *ctx, GLuint start, GLuint end );
static void RenderTriangleFanVB( GLcontext *ctx, GLuint start, GLuint end );
static void RenderTriangleStripVB( GLcontext *ctx, GLuint start, GLuint end );
static void RenderQuadVB( GLcontext *ctx, GLuint start, GLuint end );
static void RenderQuad( GLcontext *ctx, GLuint v1, GLuint v2, GLuint v3, GLuint v4, GLuint pv );
void		RenderOneTriangle( GLcontext *ctx, GLuint v1, GLuint v2, GLuint v3, GLuint pv );
void 	RenderOneLine( GLcontext *ctx, GLuint v1, GLuint v2, GLuint pv );

/*  I went with a D3D vertex buffer that is 6 times that of the Mesa one */
/* instead of having the D3D one flush when its full.  This way Mesa will*/
/* handle all the flushing.  I need x6 as points can use 4 vertex each.  */
D3DTLVERTEX 	D3DTLVertices[ (VB_MAX*6) ];    
GLuint   		VList[VB_SIZE];
/*===========================================================================*/
/* Compute Z offsets for a polygon with plane defined by (A,B,C,D)           */
/* D is not needed. TODO: Currently we are calculating this but not using it.*/
/*===========================================================================*/
/* RETURN:                                                                   */
/*===========================================================================*/
static void OffsetPolygon( GLcontext *ctx, GLfloat a, GLfloat b, GLfloat c )
{
  GLfloat	ac, 
          bc, 
          m,
          offset;

  DPF(( DBG_FUNC, "OffsetPolygon();" ));

  if ( (c < 0.001F) && (c > - 0.001F) ) 
  {
    /* Prevents underflow problems. */
    ctx->PointZoffset   = 0.0F;
    ctx->LineZoffset    = 0.0F;
    ctx->PolygonZoffset = 0.0F;
  }
  else 
  {
    ac = a / c;
    bc = b / c;
    if ( ac < 0.0F )  
	 ac = -ac;
    if ( bc<0.0F )  
	 bc = -bc;
    m = MAX2( ac, bc );     /* m = sqrt( ac*ac + bc*bc ); */

    offset = (m * ctx->Polygon.OffsetFactor + ctx->Polygon.OffsetUnits);
    ctx->PointZoffset   = ctx->Polygon.OffsetPoint ? offset : 0.0F;
    ctx->LineZoffset    = ctx->Polygon.OffsetLine  ? offset : 0.0F;
    ctx->PolygonZoffset = ctx->Polygon.OffsetFill  ? offset : 0.0F;
  }

  DPF(( DBG_PRIM_INFO, "OffsetPolygon: %f", offset ));
}
/*===========================================================================*/
/*  Compute signed area of the n-sided polgyon specified by vertices         */
/* vb->Win[] and vertex list vlist[].                                        */
/*  A clockwise polygon will return a negative area.  A counter-clockwise    */
/* polygon will return a positive area.  I have changed this function to     */
/* actually calculate twice the area as its faster and still gives the sign. */
/*===========================================================================*/
/* RETURN: signed area of the polgon.                                        */
/*===========================================================================*/
static GLfloat PolygonArea( const struct vertex_buffer *vb, GLuint n, const GLuint vlist[] )
{
  GLfloat	area;
  GLuint  i;

  DPF(( DBG_FUNC, "PolygonArea();" ));

#define  j0    vlist[i]
#define  j1    vlist[(i+1)%n]
#define  x0    vb->Win[j0][0]
#define  y0    vb->Win[j0][1]
#define  x1    vb->Win[j1][0]
#define  y1    vb->Win[j1][1]

  /* area = sum of trapezoids */
  for( i = 0, area = 0.0; i < n; i++ ) 
    area += ((x0 - x1) * (y0 + y1));  /* Note: no divide by two here! */

#undef x0
#undef y0
#undef x1
#undef y1
#undef j1
#undef j0

  // TODO: I don't see the point or * 0.5 as we just want the sign...
  return area;
}
/*===========================================================================*/
/*  Render a polygon that needs clipping on at least one vertex. The function*/
/* will first clip the polygon to any user clipping planes then clip to the  */
/* viewing volume.  The final polygon will be draw as single triangles that  */
/* first need minor proccessing (culling, offset, etc) before we draw the    */
/* polygon as a fan.  NOTE: the fan is draw as single triangles as its not   */
/* formed sequentaly in the VB but is in the vlist[].                        */
/*===========================================================================*/
/* RETURN:                                                                   */
/*===========================================================================*/
static void RenderClippedPolygon( GLcontext *ctx, GLuint n, GLuint vlist[] )
{
  struct vertex_buffer	*VB = ctx->VB;
  GLfloat 			(*win)[3] = VB->Win,
                         *proj = ctx->ProjectionMatrix,
                         ex, ey, 
                         fx, fy, c,
	                    wInv; 
  GLuint				index,
	                    pv,
                         facing;

  DPF(( DBG_FUNC, "RenderClippedPolygon();" ));

  DPF(( DBG_PRIM_INFO, "RenderClippedtPolygon( %d )", n ));

  /* Which vertex dictates the color when flat shading. */
  pv = (ctx->Primitive==GL_POLYGON) ? vlist[0] : vlist[n-1];

  /*  Clipping may introduce new vertices.  New vertices will be stored in */
  /* the vertex buffer arrays starting with location VB->Free.  After we've*/
  /* rendered the polygon, these extra vertices can be overwritten.        */
  VB->Free = VB_MAX;

  /* Clip against user clipping planes in eye coord space. */
  if ( ctx->Transform.AnyClip ) 
  {
    n = gl_userclip_polygon( ctx, n, vlist );
    if ( n < 3 )
	 return;

    /* Transform vertices from eye to clip coordinates:  clip = Proj * eye */
    for( index = 0; index < n; index++ ) 
    {
	 TRANSFORM_POINT( VB->Clip[vlist[index]], proj, VB->Eye[vlist[index]] );
    }
  }

  /* Clip against view volume in clip coord space */
  n = gl_viewclip_polygon( ctx, n, vlist );
  if ( n < 3 )
    return;

  /* Transform new vertices from clip to ndc to window coords.    */
  /* ndc = clip / W    window = viewport_mapping(ndc)             */
  /* Note that window Z values are scaled to the range of integer */
  /* depth buffer values.                                         */

  /* Only need to compute window coords for new vertices */
  for( index = VB_MAX; index < VB->Free; index++ ) 
  {
    if ( VB->Clip[index][3] != 0.0F ) 
    {
	 wInv = 1.0F / VB->Clip[index][3];

	 win[index][0] = VB->Clip[index][0] * wInv * ctx->Viewport.Sx + ctx->Viewport.Tx;
	 win[index][1] = VB->Clip[index][1] * wInv * ctx->Viewport.Sy + ctx->Viewport.Ty;
	 win[index][2] = VB->Clip[index][2] * wInv * ctx->Viewport.Sz + ctx->Viewport.Tz;
    }
    else 
    {
	 /* Can't divide by zero, so... */
	 win[index][0] = win[index][1] = win[index][2] = 0.0F;
    }
  }

  /* Draw filled polygon as a triangle fan */
  for( index = 2; index < n; index++ ) 
  {
    /* Compute orientation of triangle */
    ex = win[vlist[index-1]][0] - win[vlist[0]][0];
    ey = win[vlist[index-1]][1] - win[vlist[0]][1];
    fx = win[vlist[index]][0]   - win[vlist[0]][0];
    fy = win[vlist[index]][1]   - win[vlist[0]][1];
    c = (ex * fy) - (ey * fx);

    /* polygon is perpindicular to view plane, don't draw it */
    if ( (c == 0.0F) && !ctx->Polygon.Unfilled )
	 continue;

    /* Backface culling. */
    facing = (c < 0.0F) ^ ctx->Polygon.FrontBit;
    if ( (facing + 1) & ctx->Polygon.CullBits )  
	 continue;
        
    if ( ctx->IndirectTriangles & DD_TRI_LIGHT_TWOSIDE ) 
    {
	 if ( facing == 1 ) 
	 {
	   /* use back color */
	   VB->Color   = VB->Bcolor;
	   VB->Specular= VB->Bspec;
	 }
	 else 
	 {
	   /* use front color */
	   VB->Color   = VB->Fcolor;
	   VB->Specular= VB->Fspec;
	 }
    }

    if ( ctx->IndirectTriangles & DD_TRI_OFFSET ) 
    {
	 /* finish computing plane equation of polygon, compute offset */
	 GLfloat fz = win[vlist[index]][2]   - win[vlist[0]][2];  
	 GLfloat ez = win[vlist[index-1]][2] - win[vlist[0]][2];
	 GLfloat a = (ey * fz) - (ez * fy);
	 GLfloat b = (ez * fx) - (ex * fz);
	 OffsetPolygon( ctx, a, b, c );
    }
    RenderOneTriangle( ctx, vlist[0], vlist[index-1], vlist[index], pv );
  }
}
/*===========================================================================*/
/*  This function gets called when either the vertex buffer is full or glEnd */
/* has been called.  If the we aren't in rendering mode (FEEDBACK) then I    */
/* pass the vertex buffer back to Mesa to deal with by returning FALSE.      */
/*  If I can render the primitive types in the buffer directly then I will   */
/* return TRUE after I render the vertex buffer and reset the vertex buffer. */
/*                                                                           */
/* TODO: I don't handle the special case of when the vertex buffer is full   */
/*      and we have a primitive that bounds this buffer and the next one to  */
/*      come.  I'm not sure right now if Mesa handles this for me...         */
/*===========================================================================*/
/* RETURN: TRUE, FALSE.                                                      */
/*===========================================================================*/
GLboolean RenderVertexBuffer( GLcontext *ctx, GLboolean allDone )
{
  struct vertex_buffer	*VB = ctx->VB;
  GLuint 		    		index,
	                    vlist[VB_SIZE];

  DPF(( DBG_FUNC, "RenderVertexBuffer();" ));

  /* We only need to hook actual tri's that need rendering. */
  if ( ctx->RenderMode != GL_RENDER )
  {
	   //	   (ctx->Visual->AccumBits > 0) )
	   //	   (ctx->Visual->StencilBits > 0) )
    DPF(( DBG_PRIM_INFO, "Passing VB back to Mesa" ));
    return FALSE;
  }

  /*  I'm going to set the states here so that all functions will  */
  /* be assured to have the right states.  If Mesa's vertex bufefr */
  /* function calls one of my primitive functions (TRI,POINT,LINE) */
  /* it will need the right states.  So instead of doing it in the */
  /* primitive function I will always do it here at risk of some   */
  /* slow down to some cases...                                    */
  SetRenderStates( ctx );

  switch( ctx->Primitive ) 
  {
    case GL_POINTS:
	 DPF(( DBG_PRIM_INFO, "GL_POINTS( %d )", VB->Count ));
	 RenderPointsVB( ctx, 0, VB->Count );
	 break;

    case GL_LINES:
    case GL_LINE_STRIP:
    case GL_LINE_LOOP:
	 /*  Not supported functions yet so pass back that we failed to */
	 /* render the vertex buffer and Mesa will have to do it.       */
	 DPF(( DBG_PRIM_INFO, "GL_LINE_?( %d )", VB->Count ));
	 return FALSE;

    case GL_TRIANGLES:
	 if ( VB->Count < 3 )
	 {
	   DPF(( DBG_PRIM_WARN, "GL_TRIANGLES( %d )", VB->Count ));
	   return FALSE;
	 }

	 DPF(( DBG_PRIM_INFO, "GL_TRIANGLES( %d )", VB->Count ));
      RenderTriangleVB( ctx, 0, VB->Count );
	 break;

    case GL_TRIANGLE_STRIP:
	 if ( VB->Count < 3 )
	 {
	   DPF(( DBG_PRIM_WARN, "GL_TRIANGLE_STRIP( %d )", VB->Count ));
	   return FALSE;
	 }

	 DPF(( DBG_PRIM_INFO, "GL_TRIANGLE_STRIP( %d )", VB->Count ));
	 RenderTriangleStripVB( ctx, 0, VB->Count );
	 break;

    case GL_TRIANGLE_FAN:
	 if ( VB->Count < 3 )
	 {
	   DPF(( DBG_PRIM_WARN, "GL_TRIANGLE_FAN( %d )", VB->Count ));
	   return FALSE;
	 }

	 DPF(( DBG_PRIM_INFO, "GL_TRIANGLE_FAN( %d )", VB->Count ));
	 RenderTriangleFanVB( ctx, 0, VB->Count );
	 break;

    case GL_QUADS:
	 if ( VB->Count < 4 )
	 {
	   DPF(( DBG_PRIM_WARN, "GL_QUADS( %d )", VB->Count ));
	   return FALSE;
	 }

	  DPF(( DBG_PRIM_INFO, "GL_QUADS( %d )", VB->Count ));
	  RenderQuadVB( ctx, 0, VB->Count );
	  break;

    case GL_QUAD_STRIP:
	 if ( VB->Count < 4 )
	 {
	   DPF(( DBG_PRIM_WARN, "GL_QUAD_STRIP( %d )", VB->Count ));
	   return FALSE;
	 }

	 DPF(( DBG_PRIM_INFO, "GL_QUAD_STRIP( %d )", VB->Count ));

	 if ( VB->ClipOrMask ) 
	 {
	   for( index = 3; index < VB->Count; index += 2 ) 
	   {
		if ( VB->ClipMask[index-3] & VB->ClipMask[index-2] & VB->ClipMask[index-1] & VB->ClipMask[index] & CLIP_ALL_BITS ) 
		{
		   /* All points clipped by common plane */
		  DPF(( DBG_PRIM_WARN, "GL_QUAD_STRIP( %d )", VB->Count ));
		  continue;
		}
		else if ( VB->ClipMask[index-3] | VB->ClipMask[index-2] | VB->ClipMask[index-1] | VB->ClipMask[index] ) 
		{
		  vlist[0] = index - 3;
		  vlist[1] = index - 2;
		  vlist[2] = index;
		  vlist[3] = index - 1;
		  RenderClippedPolygon( ctx, 4, vlist );
		}
		else 
		{
		  RenderQuad( ctx, (index-3), (index-2), index, (index-1), index );
		}	
	   }
	 }
	 else 
	 {
	   /* No clipping needed */
	   for( index = 3; index < VB->Count; index += 2 ) 
		RenderQuad( ctx, (index-3), (index-2), index, (index-1), index );
	 }	
	 break;
	   
    case GL_POLYGON:
	 if ( VB->Count < 3 ) 
	 {
	   DPF(( DBG_PRIM_WARN, "GL_POLYGON( %d )", VB->Count ));
	   return FALSE;
	 }

	 DPF(( DBG_PRIM_INFO, "GL_POLYGON( %d )", VB->Count ));

	 /* All points clipped by common plane, draw nothing */
	 if ( !(VB->ClipAndMask & CLIP_ALL_BITS) ) 
	   RenderTriangleFanVB( ctx, 0, VB->Count );
	 break;

    default:
	 /* should never get here */
	 gl_problem( ctx, "invalid mode in gl_render_vb" );
   }
 
  DPF(( DBG_PRIM_INFO, "ResetVB" ));

  /* We return TRUE to indicate we rendered the VB. */
  gl_reset_vb( ctx, allDone );
  return TRUE;
}
/*===========================================================================*/
/*  This function will render the current vertex buffer as triangles.  The   */
/* buffer has to be able to be rendered directly.  This means that we are    */
/* filled, no offsets, no culling and one sided rendering.  Also we must be  */
/* in render mode of course.                                                 */
/*  First I will fill the global D3D vertice buffer.  Next I will set all the*/
/* states for D3D based on the current OGL state.  Finally I pass the D3D VB */
/* to the wrapper that call DrawPrimitives.                                  */
/*===========================================================================*/
/* RETURN:                                                                   */
/*===========================================================================*/
static void RenderTriangleVB( GLcontext *ctx, GLuint start, GLuint end )
{
  D3DMESACONTEXT      	*pContext = (D3DMESACONTEXT *)ctx->DriverCtx;
  struct vertex_buffer 	*VB = ctx->VB;
  int                    index,
                         cVertex,
                         height = (pContext->pShared->rectW.bottom - pContext->pShared->rectW.top);
   DWORD                	dwPVColor;
   GLfloat              	ex, ey, 
                         fx, fy, c;
   GLuint               	facing;

   DPF(( DBG_FUNC, "RenderTriangleVB" ));

   if ( (!(ctx->IndirectTriangles & DD_SW_SETUP)) && !VB->ClipOrMask )
   {
	DPF(( DBG_PRIM_INFO, "DirectTriangles( %d )", (end-start) ));
	for( index = start, cVertex = 0; index < end; )
	{
	  dwPVColor = (VB->Color[(index+2)][3]<<24) | (VB->Color[(index+2)][0]<<16) | (VB->Color[(index+2)][1]<<8) | VB->Color[(index+2)][2];
   
	  /*=====================================*/
	  /* Populate the the triangle vertices. */
	  /*=====================================*/
	  D3DTLVertices[cVertex].sx     = D3DVAL( VB->Win[index][0] );
	  D3DTLVertices[cVertex].sy     = D3DVAL( (height - VB->Win[index][1]) );
	  D3DTLVertices[cVertex].sz     = D3DVAL( VB->Win[index][2] );
	  D3DTLVertices[cVertex].tu     = D3DVAL( VB->TexCoord[index][0] );
	  D3DTLVertices[cVertex].tv     = D3DVAL( VB->TexCoord[index][1] );
	  D3DTLVertices[cVertex].rhw    = D3DVAL( (1.0 / VB->Clip[index][3]) );
	  D3DTLVertices[cVertex++].color= (ctx->Light.ShadeModel == GL_FLAT) ?
	                                  dwPVColor :
                                       (VB->Color[index][3]<<24) | (VB->Color[index][0]<<16) | (VB->Color[index][1]<<8) | VB->Color[index][2];
	  index++;
   
	  D3DTLVertices[cVertex].sx     = D3DVAL( VB->Win[index][0] );
	  D3DTLVertices[cVertex].sy     = D3DVAL( (height - VB->Win[index][1]) );
	  D3DTLVertices[cVertex].sz     = D3DVAL( VB->Win[index][2] );
	  D3DTLVertices[cVertex].tu     = D3DVAL( VB->TexCoord[index][0] );
	  D3DTLVertices[cVertex].tv     = D3DVAL( VB->TexCoord[index][1] );
	  D3DTLVertices[cVertex].rhw    = D3DVAL( (1.0 / VB->Clip[index][3]) );
	  D3DTLVertices[cVertex++].color= (ctx->Light.ShadeModel == GL_FLAT) ?
                                       dwPVColor :
                                       (VB->Color[index][3]<<24) | (VB->Color[index][0]<<16) | (VB->Color[index][1]<<8) | VB->Color[index][2];
	  index++;
      
	  D3DTLVertices[cVertex].sx     = D3DVAL( VB->Win[index][0] );
	  D3DTLVertices[cVertex].sy     = D3DVAL( (height - VB->Win[index][1]) );
	  D3DTLVertices[cVertex].sz     = D3DVAL( VB->Win[index][2] );
	  D3DTLVertices[cVertex].tu     = D3DVAL( VB->TexCoord[index][0] );
	  D3DTLVertices[cVertex].tv     = D3DVAL( VB->TexCoord[index][1] );
	  D3DTLVertices[cVertex].rhw    = D3DVAL( (1.0 / VB->Clip[index][3]) );
	  D3DTLVertices[cVertex++].color= dwPVColor;
	  index++;
	}
   }
   else
   {
#define v1     index
#define v2     (index+1)
#define v3     (index+2)

	for( index = start, cVertex = 0; index < end; index += 3 )
	{
	  if ( VB->ClipMask[v1] & VB->ClipMask[v2] & VB->ClipMask[v3] & CLIP_ALL_BITS ) 
	  {
	    continue;
	  }
	  else if ( VB->ClipMask[v1] | VB->ClipMask[v2] | VB->ClipMask[v3] ) 
	  {
	    VList[0] = v1;
	    VList[1] = v2;
	    VList[2] = v3;
	    RenderClippedPolygon( ctx, 3, VList );
	    continue;
	  }

	  /* Compute orientation of triangle */
	  ex = VB->Win[v2][0] - VB->Win[v1][0];
	  ey = VB->Win[v2][1] - VB->Win[v1][1];
	  fx = VB->Win[v3][0] - VB->Win[v1][0];
	  fy = VB->Win[v3][1] - VB->Win[v1][1];
	  c = (ex * fy) - (ey * fx);

	  /* polygon is perpindicular to view plane, don't draw it */
	  if ( (c == 0.0F) && !ctx->Polygon.Unfilled )
	    continue;

	  /* Backface culling. */
	  facing = (c < 0.0F) ^ ctx->Polygon.FrontBit;
	  if ( (facing + 1) & ctx->Polygon.CullBits )  
	    continue;

	  if ( ctx->IndirectTriangles & DD_TRI_LIGHT_TWOSIDE ) 
	  {
	    if ( facing == 1 ) 
	    {
		 /* use back color */
		 VB->Color   = VB->Bcolor;
		 VB->Specular= VB->Bspec;
	    }
	    else 
	    {
		 /* use front color */
		 VB->Color   = VB->Fcolor;
		 VB->Specular= VB->Fspec;
	    }
	  }

	  if ( ctx->IndirectTriangles & DD_TRI_OFFSET ) 
	  {
	    /* Finish computing plane equation of polygon, compute offset */
	    GLfloat fz = VB->Win[v3][2] - VB->Win[v1][2];  
	    GLfloat ez = VB->Win[v2][2] - VB->Win[v1][2];
	    GLfloat a = (ey * fz) - (ez * fy);
	    GLfloat b = (ez * fx) - (ex * fz);
	    OffsetPolygon( ctx, a, b, c );
	  }

	  /*=====================================*/
	  /* Populate the the triangle vertices. */
	  /*=====================================*/
	  /* Solve the prevoking vertex color as we need it for the 3rd triangle and flat shading. */
	  dwPVColor = (VB->Color[v3][3]<<24) | (VB->Color[v3][0]<<16) | (VB->Color[v3][1]<<8) | VB->Color[v3][2];
   
	  D3DTLVertices[cVertex].sx     = D3DVAL( VB->Win[v1][0] );
	  D3DTLVertices[cVertex].sy     = D3DVAL( (height - VB->Win[v1][1]) );
	  D3DTLVertices[cVertex].sz     = D3DVAL( (VB->Win[v1][2] + ctx->PolygonZoffset) );
	  D3DTLVertices[cVertex].tu     = D3DVAL( VB->TexCoord[v1][0] );
	  D3DTLVertices[cVertex].tv     = D3DVAL( VB->TexCoord[v1][1] );
	  D3DTLVertices[cVertex].rhw    = D3DVAL( (1.0 / VB->Clip[v1][3]) );
	  D3DTLVertices[cVertex++].color= (ctx->Light.ShadeModel == GL_FLAT) ?
                                       dwPVColor :
                                       (VB->Color[v1][3]<<24) | (VB->Color[v1][0]<<16) | (VB->Color[v1][1]<<8) | VB->Color[v1][2];
   
	  D3DTLVertices[cVertex].sx     = D3DVAL( VB->Win[v2][0] );
	  D3DTLVertices[cVertex].sy     = D3DVAL( (height - VB->Win[v2][1]) );
	  D3DTLVertices[cVertex].sz     = D3DVAL( (VB->Win[v2][2] + ctx->PolygonZoffset) );
	  D3DTLVertices[cVertex].tu     = D3DVAL( VB->TexCoord[v2][0] );
	  D3DTLVertices[cVertex].tv     = D3DVAL( VB->TexCoord[v2][1] );
	  D3DTLVertices[cVertex].rhw    = D3DVAL( (1.0 / VB->Clip[v2][3]) );
	  D3DTLVertices[cVertex++].color= (ctx->Light.ShadeModel == GL_FLAT) ?
                                       dwPVColor :
                                       (VB->Color[v2][3]<<24) | (VB->Color[v2][0]<<16) | (VB->Color[v2][1]<<8) | VB->Color[v2][2];
      
	  D3DTLVertices[cVertex].sx     = D3DVAL( VB->Win[v3][0] );
	  D3DTLVertices[cVertex].sy     = D3DVAL( (height - VB->Win[v3][1]) );
	  D3DTLVertices[cVertex].sz     = D3DVAL( (VB->Win[v3][2] + ctx->PolygonZoffset) );
	  D3DTLVertices[cVertex].tu     = D3DVAL( VB->TexCoord[v3][0] );
	  D3DTLVertices[cVertex].tv     = D3DVAL( VB->TexCoord[v3][1] );
	  D3DTLVertices[cVertex].rhw    = D3DVAL( (1.0 / VB->Clip[v3][3]) );
	  D3DTLVertices[cVertex++].color= dwPVColor;
	}
#undef v1
#undef v2
#undef v3
   }    

   /* Render the converted vertex buffer. */  
   if ( cVertex > 2 )
	DrawPrimitiveHAL( pContext->pShared, D3DPT_TRIANGLELIST, &D3DTLVertices[0], cVertex );
}
/*===========================================================================*/
/*  This function will render the current vertex buffer as a triangle fan.   */
/* The buffer has to be able to be rendered directly.  This means that we are*/
/* filled, no offsets, no culling and one sided rendering.  Also we must be  */
/* in render mode of course.                                                 */
/*  First I will fill the global D3D vertice buffer.  Next I will set all the*/
/* states for D3D based on the current OGL state.  Finally I pass the D3D VB */
/* to the wrapper that call DrawPrimitives.                                  */
/*===========================================================================*/
/* RETURN:                                                                   */
/*===========================================================================*/
static void RenderTriangleFanVB( GLcontext *ctx, GLuint start, GLuint end )
{
  D3DMESACONTEXT     	*pContext = (D3DMESACONTEXT *)ctx->DriverCtx;
  struct vertex_buffer 	*VB = ctx->VB;
  int                  	index,
                         cVertex,
                         height = (pContext->pShared->rectW.bottom - pContext->pShared->rectW.top);
   GLfloat              	ex, ey, 
                         fx, fy, c;
   GLuint               	facing;
   DWORD                	dwPVColor;

   DPF(( DBG_FUNC, "RenderTriangleFanVB();" ));

   /* Special case that we can blast the fan without culling, offset, etc... */
   if ( (!(ctx->IndirectTriangles & DD_SW_SETUP)) && !VB->ClipOrMask && (ctx->Light.ShadeModel != GL_FLAT) )
   {
	DPF(( DBG_PRIM_INFO, "DirectTriangles( %d )", (end-start) ));

	/* Seed the the fan. */
	D3DTLVertices[0].sx   = D3DVAL( VB->Win[start][0] );
	D3DTLVertices[0].sy   = D3DVAL( (height - VB->Win[start][1]) );
	D3DTLVertices[0].sz   = D3DVAL( VB->Win[start][2] );
	D3DTLVertices[0].tu   = D3DVAL( VB->TexCoord[start][0] );
	D3DTLVertices[0].tv   = D3DVAL( VB->TexCoord[start][1] );
	D3DTLVertices[0].rhw  = D3DVAL( (1.0 / VB->Clip[start][3]) );
	D3DTLVertices[0].color= (VB->Color[start][3]<<24) | (VB->Color[start][0]<<16) | (VB->Color[start][1]<<8) | VB->Color[start][2];
   
	/* Seed the the fan. */
	D3DTLVertices[1].sx   = D3DVAL( VB->Win[(start+1)][0] );
	D3DTLVertices[1].sy   = D3DVAL( (height - VB->Win[(start+1)][1]) );
	D3DTLVertices[1].sz   = D3DVAL( VB->Win[(start+1)][2] );
	D3DTLVertices[1].tu   = D3DVAL( VB->TexCoord[(start+1)][0] );
	D3DTLVertices[1].tv   = D3DVAL( VB->TexCoord[(start+1)][1] );
	D3DTLVertices[1].rhw  = D3DVAL( (1.0 / VB->Clip[(start+1)][3]) );
	D3DTLVertices[1].color= (VB->Color[(start+1)][3]<<24) | (VB->Color[(start+1)][0]<<16) | (VB->Color[(start+1)][1]<<8) | VB->Color[(start+1)][2];
   
	for( index = (start+2), cVertex = 2; index < end; index++, cVertex++ )
	{
	  /*=================================*/
	  /* Add the next vertex to the fan. */
	  /*=================================*/
	  D3DTLVertices[cVertex].sx     = D3DVAL( VB->Win[index][0] );
	  D3DTLVertices[cVertex].sy     = D3DVAL( (height - VB->Win[index][1]) );
	  D3DTLVertices[cVertex].sz     = D3DVAL( VB->Win[index][2] );
	  D3DTLVertices[cVertex].tu     = D3DVAL( VB->TexCoord[index][0] );
	  D3DTLVertices[cVertex].tv     = D3DVAL( VB->TexCoord[index][1] );
	  D3DTLVertices[cVertex].rhw    = D3DVAL( (1.0 / VB->Clip[index][3]) );
	  D3DTLVertices[cVertex].color  = (VB->Color[index][3]<<24) | (VB->Color[index][0]<<16) | (VB->Color[index][1]<<8) | VB->Color[index][2];
      }

	/* Render the converted vertex buffer. */  
	if ( cVertex )
	  DrawPrimitiveHAL( pContext->pShared, D3DPT_TRIANGLEFAN, &D3DTLVertices[0], cVertex );
   }
   else
   {
#define v1     start
#define v2     (index-1)
#define v3     index

	for( index = (start+2), cVertex = 0; index < end; index++ )
	{
	  if ( VB->ClipOrMask ) 
	  {
	    /* All points clipped by common plane */
	    if ( VB->ClipMask[v1] & VB->ClipMask[v2] & VB->ClipMask[v3] & CLIP_ALL_BITS ) 
	    {
		 continue;
	    }
	    else if ( VB->ClipMask[v1] | VB->ClipMask[v2] | VB->ClipMask[v3] ) 
	    {
		 VList[0] = v1;
		 VList[1] = v2;
		 VList[2] = v3;
		 RenderClippedPolygon( ctx, 3, VList );
		 continue;
	    }
	  }

	  /* Compute orientation of triangle */
	  ex = VB->Win[v2][0] - VB->Win[v1][0];
	  ey = VB->Win[v2][1] - VB->Win[v1][1];
	  fx = VB->Win[v3][0] - VB->Win[v1][0];
	  fy = VB->Win[v3][1] - VB->Win[v1][1];
	  c = (ex * fy) - (ey * fx);
   
	  /* polygon is perpindicular to view plane, don't draw it */
	  if ( (c == 0.0F) && !ctx->Polygon.Unfilled )
	    continue;

	  /* Backface culling. */
	  facing = (c < 0.0F) ^ ctx->Polygon.FrontBit;
	  if ( (facing + 1) & ctx->Polygon.CullBits )  
	    continue;
   
	  if ( ctx->IndirectTriangles & DD_TRI_OFFSET ) 
	  {
	    /* Finish computing plane equation of polygon, compute offset */
	    GLfloat fz = VB->Win[v3][2] - VB->Win[v1][2];  
	    GLfloat ez = VB->Win[v2][2] - VB->Win[v1][2];
	    GLfloat a = (ey * fz) - (ez * fy);
	    GLfloat b = (ez * fx) - (ex * fz);
	    OffsetPolygon( ctx, a, b, c );
	  }

	  /*=====================================*/
	  /* Populate the the triangle vertices. */
	  /*=====================================*/
	  dwPVColor = (VB->Color[v3][3]<<24) | (VB->Color[v3][0]<<16) | (VB->Color[v3][1]<<8) | VB->Color[v3][2];

	  D3DTLVertices[cVertex].sx     = D3DVAL( VB->Win[v1][0] );
	  D3DTLVertices[cVertex].sy     = D3DVAL( (height - VB->Win[v1][1]) );
	  D3DTLVertices[cVertex].sz     = D3DVAL( (VB->Win[v1][2] + ctx->PolygonZoffset) );
	  D3DTLVertices[cVertex].tu     = D3DVAL( VB->TexCoord[v1][0] );
	  D3DTLVertices[cVertex].tv     = D3DVAL( VB->TexCoord[v1][1] );
	  D3DTLVertices[cVertex].rhw    = D3DVAL( (1.0 / VB->Clip[v1][3]) );
	  D3DTLVertices[cVertex++].color= (ctx->Light.ShadeModel == GL_FLAT) ? dwPVColor :
                                         (VB->Color[v1][3]<<24) | (VB->Color[v1][0]<<16) | (VB->Color[v1][1]<<8) | VB->Color[v1][2];
      
	  D3DTLVertices[cVertex].sx     = D3DVAL( VB->Win[v2][0] );
	  D3DTLVertices[cVertex].sy     = D3DVAL( (height - VB->Win[v2][1]) );
	  D3DTLVertices[cVertex].sz     = D3DVAL( (VB->Win[v2][2] + ctx->PolygonZoffset)  );
	  D3DTLVertices[cVertex].tu     = D3DVAL( VB->TexCoord[v2][0] );
	  D3DTLVertices[cVertex].tv     = D3DVAL( VB->TexCoord[v2][1] );
	  D3DTLVertices[cVertex].rhw    = D3DVAL( (1.0 / VB->Clip[v2][3]) );
	  D3DTLVertices[cVertex++].color= (ctx->Light.ShadeModel == GL_FLAT) ? dwPVColor :
                                         (VB->Color[v2][3]<<24) | (VB->Color[v2][0]<<16) | (VB->Color[v2][1]<<8) | VB->Color[v2][2];
         
	  D3DTLVertices[cVertex].sx     = D3DVAL( VB->Win[v3][0] );
	  D3DTLVertices[cVertex].sy     = D3DVAL( (height - VB->Win[v3][1]) );
	  D3DTLVertices[cVertex].sz     = D3DVAL( (VB->Win[v3][2] + ctx->PolygonZoffset) );
	  D3DTLVertices[cVertex].tu     = D3DVAL( VB->TexCoord[v3][0] );
	  D3DTLVertices[cVertex].tv     = D3DVAL( VB->TexCoord[v3][1] );
	  D3DTLVertices[cVertex].rhw    = D3DVAL( (1.0 / VB->Clip[v3][3]) );
	  D3DTLVertices[cVertex++].color= dwPVColor;
	}

	/* Render the converted vertex buffer. */  
	if ( cVertex )
	  DrawPrimitiveHAL( pContext->pShared, D3DPT_TRIANGLELIST, &D3DTLVertices[0], cVertex );
#undef v1
#undef v2
#undef v3
   }
}
/*===========================================================================*/
/*  This function will render the current vertex buffer as a triangle strip. */
/* The buffer has to be able to be rendered directly.  This means that we are*/
/* filled, no offsets, no culling and one sided rendering.  Also we must be  */
/* in render mode of course.                                                 */
/*  First I will fill the global D3D vertice buffer.  Next I will set all the*/
/* states for D3D based on the current OGL state.  Finally I pass the D3D VB */
/* to the wrapper that call DrawPrimitives.                                  */
/*===========================================================================*/
/* RETURN:                                                                   */
/*===========================================================================*/
static void RenderTriangleStripVB( GLcontext *ctx, GLuint start, GLuint end )
{
  D3DMESACONTEXT     	*pContext = (D3DMESACONTEXT *)ctx->DriverCtx;
  struct vertex_buffer 	*VB = ctx->VB;
  int                    index,
                         cVertex = 0,
	                    v1, v2, v3,
                         height = (pContext->pShared->rectW.bottom - pContext->pShared->rectW.top);
  GLfloat              	ex, ey, 
                         fx, fy, c;
  GLuint               	facing;
  DWORD                	dwPVColor;

  DPF(( DBG_FUNC, "RenderTriangleStripVB();" ));

  /* Special case that we can blast the fan without culling, offset, etc... */
  if ( (!(ctx->IndirectTriangles & DD_SW_SETUP)) && !VB->ClipOrMask && (ctx->Light.ShadeModel != GL_FLAT) )
  {
    DPF(( DBG_PRIM_PROFILE, "DirectTriangles" ));

    /* Seed the the strip. */
    D3DTLVertices[0].sx   = D3DVAL( VB->Win[start][0] );
    D3DTLVertices[0].sy   = D3DVAL( (height - VB->Win[start][1]) );
    D3DTLVertices[0].sz   = D3DVAL( VB->Win[start][2] );
    D3DTLVertices[0].tu   = D3DVAL( VB->TexCoord[start][0] );
    D3DTLVertices[0].tv   = D3DVAL( VB->TexCoord[start][1] );
    D3DTLVertices[0].rhw  = D3DVAL( (1.0 / VB->Clip[start][3]) );
    D3DTLVertices[0].color= (VB->Color[start][3]<<24) | (VB->Color[start][0]<<16) | (VB->Color[start][1]<<8) | VB->Color[start][2];

    /* Seed the the strip. */
    D3DTLVertices[1].sx   = D3DVAL( VB->Win[(start+1)][0] );
    D3DTLVertices[1].sy   = D3DVAL( (height - VB->Win[(start+1)][1]) );
    D3DTLVertices[1].sz   = D3DVAL( VB->Win[(start+1)][2] );
    D3DTLVertices[1].tu   = D3DVAL( VB->TexCoord[(start+1)][0] );
    D3DTLVertices[1].tv   = D3DVAL( VB->TexCoord[(start+1)][1] );
    D3DTLVertices[1].rhw  = D3DVAL( (1.0 / VB->Clip[(start+1)][3]) );
    D3DTLVertices[1].color= (VB->Color[(start+1)][3]<<24) | (VB->Color[(start+1)][0]<<16) | (VB->Color[(start+1)][1]<<8) | VB->Color[(start+1)][2];
   
    for( index = (start+2), cVertex = 2; index < end; index++, cVertex++ )
    {
	 /*===================================*/
	 /* Add the next vertex to the strip. */
	 /*===================================*/
	 D3DTLVertices[cVertex].sx     = D3DVAL( VB->Win[index][0] );
	 D3DTLVertices[cVertex].sy     = D3DVAL( (height - VB->Win[index][1]) );
	 D3DTLVertices[cVertex].sz     = D3DVAL( VB->Win[index][2] );
	 D3DTLVertices[cVertex].tu     = D3DVAL( VB->TexCoord[index][0] );
	 D3DTLVertices[cVertex].tv     = D3DVAL( VB->TexCoord[index][1] );
	 D3DTLVertices[cVertex].rhw    = D3DVAL( (1.0 / VB->Clip[index][3]) );
	 D3DTLVertices[cVertex].color  = (VB->Color[index][3]<<24) | (VB->Color[index][0]<<16) | (VB->Color[index][1]<<8) | VB->Color[index][2];
    }

    /* Render the converted vertex buffer. */  
    if ( cVertex )
	 DrawPrimitiveHAL( pContext->pShared, D3DPT_TRIANGLESTRIP, &D3DTLVertices[0], cVertex );
  }
  else
  {
    for( index = (start+2); index < end; index++ ) 
    {
	 /* We need to switch order so that winding won't be a problem. */
	 if ( index & 1 )
	 {
	   v1 = index - 1;
	   v2 = index - 2;
	   v3 = index - 0;
	 }
	 else
	 {
	   v1 = index - 2;
	   v2 = index - 1;
	   v3 = index - 0;
	 }

	 /* All vertices clipped by common plane */
	 if ( VB->ClipMask[v1] & VB->ClipMask[v2] & VB->ClipMask[v3] & CLIP_ALL_BITS ) 
	   continue;

	 /* Check if any vertices need clipping. */
	 if ( VB->ClipMask[v1] | VB->ClipMask[v2] | VB->ClipMask[v3] ) 
	 {
	   VList[0] = v1;
	   VList[1] = v2;
	   VList[2] = v3;
	   RenderClippedPolygon( ctx, 3, VList );
	 }
	 else 
	 {
	   /* Compute orientation of triangle */
	   ex = VB->Win[v2][0] - VB->Win[v1][0];
	   ey = VB->Win[v2][1] - VB->Win[v1][1];
	   fx = VB->Win[v3][0] - VB->Win[v1][0];
	   fy = VB->Win[v3][1] - VB->Win[v1][1];
	   c = (ex * fy) - (ey * fx);

	   /* Polygon is perpindicular to view plane, don't draw it */
	   if ( (c == 0.0F) && !ctx->Polygon.Unfilled )
		continue;

	   /* Backface culling. */
	   facing = (c < 0.0F) ^ ctx->Polygon.FrontBit;
	   if ( (facing + 1) & ctx->Polygon.CullBits )  
		continue;

	   /* Need right color if we have two sided lighting. */
	   if ( ctx->IndirectTriangles & DD_TRI_LIGHT_TWOSIDE ) 
	   {
		if ( facing == 1 ) 
		{
		  /* use back color */
		  VB->Color   = VB->Bcolor;
		  VB->Specular= VB->Bspec;
		}
		else 
		{
		  /* use front color */
		  VB->Color   = VB->Fcolor;
		  VB->Specular= VB->Fspec;
		}
	   }

	   if ( ctx->IndirectTriangles & DD_TRI_OFFSET ) 
	   {
		/* Finish computing plane equation of polygon, compute offset */
		GLfloat fz = VB->Win[v3][2] - VB->Win[v1][2];  
		GLfloat ez = VB->Win[v2][2] - VB->Win[v1][2];
		GLfloat a = (ey * fz) - (ez * fy);
		GLfloat b = (ez * fx) - (ex * fz);
		OffsetPolygon( ctx, a, b, c );
	   }
	   /*=====================================*/
	   /* Populate the the triangle vertices. */
	   /*=====================================*/

	   /* Solve the prevoking vertex color as we need it for the 3rd triangle and flat shading. */
	   dwPVColor = (VB->Color[v3][3]<<24) | (VB->Color[v3][0]<<16) | (VB->Color[v3][1]<<8) | VB->Color[v3][2];
   
	   D3DTLVertices[cVertex].sx     = D3DVAL( VB->Win[v1][0] );
	   D3DTLVertices[cVertex].sy     = D3DVAL( (height - VB->Win[v1][1]) );
	   D3DTLVertices[cVertex].sz     = D3DVAL( (VB->Win[v1][2] + ctx->PolygonZoffset) );
	   D3DTLVertices[cVertex].tu     = D3DVAL( VB->TexCoord[v1][0] );
	   D3DTLVertices[cVertex].tv     = D3DVAL( VB->TexCoord[v1][1] );
	   D3DTLVertices[cVertex].rhw    = D3DVAL( (1.0 / VB->Clip[v1][3]) );
	   D3DTLVertices[cVertex++].color= (ctx->Light.ShadeModel == GL_FLAT) ?
                                        dwPVColor :
                                        (VB->Color[v1][3]<<24) | (VB->Color[v1][0]<<16) | (VB->Color[v1][1]<<8) | VB->Color[v1][2];
   
	   D3DTLVertices[cVertex].sx     = D3DVAL( VB->Win[v2][0] );
	   D3DTLVertices[cVertex].sy     = D3DVAL( (height - VB->Win[v2][1]) );
	   D3DTLVertices[cVertex].sz     = D3DVAL( (VB->Win[v2][2] + ctx->PolygonZoffset) );
	   D3DTLVertices[cVertex].tu     = D3DVAL( VB->TexCoord[v2][0] );
	   D3DTLVertices[cVertex].tv     = D3DVAL( VB->TexCoord[v2][1] );
	   D3DTLVertices[cVertex].rhw    = D3DVAL( (1.0 / VB->Clip[v2][3]) );
	   D3DTLVertices[cVertex++].color= (ctx->Light.ShadeModel == GL_FLAT) ?
                                          dwPVColor :
                                          (VB->Color[v2][3]<<24) | (VB->Color[v2][0]<<16) | (VB->Color[v2][1]<<8) | VB->Color[v2][2];
      
	   D3DTLVertices[cVertex].sx     = D3DVAL( VB->Win[v3][0] );
	   D3DTLVertices[cVertex].sy     = D3DVAL( (height - VB->Win[v3][1]) );
	   D3DTLVertices[cVertex].sz     = D3DVAL( (VB->Win[v3][2] + ctx->PolygonZoffset) );
	   D3DTLVertices[cVertex].tu     = D3DVAL( VB->TexCoord[v3][0] );
	   D3DTLVertices[cVertex].tv     = D3DVAL( VB->TexCoord[v3][1] );
	   D3DTLVertices[cVertex].rhw    = D3DVAL( (1.0 / VB->Clip[v3][3]) );
	   D3DTLVertices[cVertex++].color= dwPVColor;
	 }
    }

    /* Render the converted vertex buffer. */  
    if ( cVertex )	
	 DrawPrimitiveHAL( pContext->pShared, D3DPT_TRIANGLELIST, &D3DTLVertices[0], cVertex );
  }	
}
/*===========================================================================*/
/*  This function will render the current vertex buffer as Quads.  The buffer*/
/* has to be able to be rendered directly.  This means that we are filled, no*/
/* offsets, no culling and one sided rendering.  Also we must be in render   */
/* mode of cource.                                                           */
/*  First I will fill the global D3D vertice buffer.  Next I will set all the*/
/* states for D3D based on the current OGL state.  Finally I pass the D3D VB */
/* to the wrapper that call DrawPrimitives.                                  */
/*===========================================================================*/
/* RETURN:                                                                   */
/*===========================================================================*/
static void RenderQuadVB( GLcontext *ctx, GLuint start, GLuint end )
{
  D3DMESACONTEXT       	*pContext = (D3DMESACONTEXT *)ctx->DriverCtx;
  struct vertex_buffer	*VB = ctx->VB;
  int                  	index,
                         cVertex,
                         height = (pContext->pShared->rectW.bottom - pContext->pShared->rectW.top);
  DWORD                	dwPVColor;
  GLfloat             	ex, ey, 
                         fx, fy, c;
  GLuint				facing;  /* 0=front, 1=back */

  DPF(( DBG_FUNC, "RenderQuadVB();" ));

#define  v1 (index)
#define  v2 (index+1)
#define  v3 (index+2)
#define  v4 (index+3)

  if ( (!(ctx->IndirectTriangles & DD_SW_SETUP)) && !VB->ClipOrMask )
  {
    DPF(( DBG_PRIM_PROFILE, "DirectTriangles" ));

    for( cVertex = 0, index = start; index < end; index += 4 )
    {
	 if ( ctx->Light.ShadeModel == GL_FLAT )
	   dwPVColor = (VB->Color[v4][3]<<24) | (VB->Color[v4][0]<<16) | (VB->Color[v4][1]<<8) | VB->Color[v4][2];
   
	 /*=====================================*/
	 /* Populate the the triangle vertices. */
	 /*=====================================*/
	 D3DTLVertices[cVertex].sx     = D3DVAL( VB->Win[v1][0] );
	 D3DTLVertices[cVertex].sy     = D3DVAL( (height - VB->Win[v1][1]) );
	 D3DTLVertices[cVertex].sz     = D3DVAL( VB->Win[v1][2] );
	 D3DTLVertices[cVertex].tu     = D3DVAL( VB->TexCoord[v1][0] );
	 D3DTLVertices[cVertex].tv     = D3DVAL( VB->TexCoord[v1][1] );
	 D3DTLVertices[cVertex].rhw    = D3DVAL( (1.0 / VB->Clip[v1][3]) );
	 D3DTLVertices[cVertex++].color= (ctx->Light.ShadeModel == GL_FLAT) ? 
                                      dwPVColor :
	                                 (VB->Color[v1][3]<<24) | (VB->Color[v1][0]<<16) | (VB->Color[v1][1]<<8) | VB->Color[v1][2];
   
	 D3DTLVertices[cVertex].sx     = D3DVAL( VB->Win[v2][0] );
	 D3DTLVertices[cVertex].sy     = D3DVAL( (height - VB->Win[v2][1]) );
	 D3DTLVertices[cVertex].sz     = D3DVAL( VB->Win[v2][2] );
	 D3DTLVertices[cVertex].tu     = D3DVAL( VB->TexCoord[v2][0] );
	 D3DTLVertices[cVertex].tv     = D3DVAL( VB->TexCoord[v2][1] );
	 D3DTLVertices[cVertex].rhw    = D3DVAL( (1.0 / VB->Clip[v2][3]) );
	 D3DTLVertices[cVertex++].color= (ctx->Light.ShadeModel == GL_FLAT) ? 
                                      dwPVColor :
                                      (VB->Color[v2][3]<<24) | (VB->Color[v2][0]<<16) | (VB->Color[v2][1]<<8) | VB->Color[v2][2];
      
	 D3DTLVertices[cVertex].sx     = D3DVAL( VB->Win[v3][0] );
	 D3DTLVertices[cVertex].sy     = D3DVAL( (height - VB->Win[v3][1]) );
	 D3DTLVertices[cVertex].sz     = D3DVAL( VB->Win[v3][2] );
	 D3DTLVertices[cVertex].tu     = D3DVAL( VB->TexCoord[v3][0] );
	 D3DTLVertices[cVertex].tv     = D3DVAL( VB->TexCoord[v3][1] );
	 D3DTLVertices[cVertex].rhw    = D3DVAL( (1.0 / VB->Clip[v3][3]) );
	 D3DTLVertices[cVertex++].color= (ctx->Light.ShadeModel == GL_FLAT) ? 
	                                 dwPVColor :
                                      (VB->Color[v3][3]<<24) | (VB->Color[v3][0]<<16) | (VB->Color[v3][1]<<8) | VB->Color[v3][2];
   
	 D3DTLVertices[cVertex].sx     = D3DVAL( VB->Win[v1][0] );
	 D3DTLVertices[cVertex].sy     = D3DVAL( (height - VB->Win[v1][1]) );
	 D3DTLVertices[cVertex].sz     = D3DVAL( VB->Win[v1][2] );
	 D3DTLVertices[cVertex].tu     = D3DVAL( VB->TexCoord[v1][0] );
	 D3DTLVertices[cVertex].tv     = D3DVAL( VB->TexCoord[v1][1] );
	 D3DTLVertices[cVertex].rhw    = D3DVAL( (1.0 / VB->Clip[v1][3]) );
	 D3DTLVertices[cVertex++].color= (ctx->Light.ShadeModel == GL_FLAT) ? 
	                                 dwPVColor :
                                      (VB->Color[v1][3]<<24) | (VB->Color[v1][0]<<16) | (VB->Color[v1][1]<<8) | VB->Color[v1][2];
   
	 D3DTLVertices[cVertex].sx     = D3DVAL( VB->Win[v3][0] );
	 D3DTLVertices[cVertex].sy     = D3DVAL( (height - VB->Win[v3][1]) );
	 D3DTLVertices[cVertex].sz     = D3DVAL( VB->Win[v3][2] );
	 D3DTLVertices[cVertex].tu     = D3DVAL( VB->TexCoord[v3][0] );
	 D3DTLVertices[cVertex].tv     = D3DVAL( VB->TexCoord[v3][1] );
	 D3DTLVertices[cVertex].rhw    = D3DVAL( (1.0 / VB->Clip[v3][3]) );
	 D3DTLVertices[cVertex++].color= (ctx->Light.ShadeModel == GL_FLAT) ? 
                                      dwPVColor :
                                      (VB->Color[v3][3]<<24) | (VB->Color[v3][0]<<16) | (VB->Color[v3][1]<<8) | VB->Color[v3][2];
   
	 D3DTLVertices[cVertex].sx     = D3DVAL( VB->Win[v4][0] );
	 D3DTLVertices[cVertex].sy     = D3DVAL( (height - VB->Win[v4][1]) );
	 D3DTLVertices[cVertex].sz     = D3DVAL( VB->Win[v4][2] );
	 D3DTLVertices[cVertex].tu     = D3DVAL( VB->TexCoord[v4][0] );
	 D3DTLVertices[cVertex].tv     = D3DVAL( VB->TexCoord[v4][1] );
	 D3DTLVertices[cVertex].rhw    = D3DVAL( (1.0 / VB->Clip[v4][3]) );
	 D3DTLVertices[cVertex++].color= (ctx->Light.ShadeModel == GL_FLAT) ? 
                                      dwPVColor :
                                      (VB->Color[v4][3]<<24) | (VB->Color[v4][0]<<16) | (VB->Color[v4][1]<<8) | VB->Color[v4][2];
    }
  }
  else
  {
    for( cVertex = 0, index = start; index < end; index += 4 )
    {
	 if ( VB->ClipMask[v1] & VB->ClipMask[v2] & VB->ClipMask[v3]  & VB->ClipMask[v4] & CLIP_ALL_BITS ) 
	 {
	   continue;
	 }	
	 else if ( VB->ClipMask[v1] | VB->ClipMask[v2] | VB->ClipMask[v3] | VB->ClipMask[v4] ) 
	 {
	   VList[0] = v1;
	   VList[1] = v2;
	   VList[2] = v3;
	   VList[3] = v4;
	   RenderClippedPolygon( ctx, 4, VList );
	   continue;
	 }

	 /* Compute orientation of triangle */
	 ex = VB->Win[v2][0] - VB->Win[v1][0];
	 ey = VB->Win[v2][1] - VB->Win[v1][1];
	 fx = VB->Win[v3][0] - VB->Win[v1][0];
	 fy = VB->Win[v3][1] - VB->Win[v1][1];
	 c = (ex * fy) - (ey * fx);

	 /* polygon is perpindicular to view plane, don't draw it */
	 if ( (c == 0.0F) && !ctx->Polygon.Unfilled )
	   continue;

	 /* Backface culling. */
	 facing = (c < 0.0F) ^ ctx->Polygon.FrontBit;
	 if ( (facing + 1) & ctx->Polygon.CullBits ) 
	   continue;

	 if ( ctx->IndirectTriangles & DD_TRI_LIGHT_TWOSIDE ) 
	 {
	   if ( facing == 1 ) 
	   {
		/* use back color */
		VB->Color   = VB->Bcolor;
		VB->Specular= VB->Bspec;
	   }
	   else 
	   {
		/* use front color */
		VB->Color   = VB->Fcolor;
		VB->Specular= VB->Fspec;
	   }	
	 }	

	 if ( ctx->IndirectTriangles & DD_TRI_OFFSET ) 
	 {
	   /* Finish computing plane equation of polygon, compute offset */
	   GLfloat fz = VB->Win[v3][2] - VB->Win[v1][2];  
	   GLfloat ez = VB->Win[v2][2] - VB->Win[v1][2];
	   GLfloat a = (ey * fz) - (ez * fy);
	   GLfloat b = (ez * fx) - (ex * fz);
	   OffsetPolygon( ctx, a, b, c );
	 }

	 if ( ctx->Light.ShadeModel == GL_FLAT )
	   dwPVColor = (VB->Color[v4][3]<<24) | (VB->Color[v4][0]<<16) | (VB->Color[v4][1]<<8) | VB->Color[v4][2];
   
	 /*=====================================*/
	 /* Populate the the triangle vertices. */
	 /*=====================================*/
	 D3DTLVertices[cVertex].sx     = D3DVAL( VB->Win[v1][0] );
	 D3DTLVertices[cVertex].sy     = D3DVAL( (height - VB->Win[v1][1]) );
	 D3DTLVertices[cVertex].sz     = D3DVAL( (VB->Win[v1][2] + ctx->PolygonZoffset) );
	 D3DTLVertices[cVertex].tu     = D3DVAL( VB->TexCoord[v1][0] );
	 D3DTLVertices[cVertex].tv     = D3DVAL( VB->TexCoord[v1][1] );
	 D3DTLVertices[cVertex].rhw    = D3DVAL( (1.0 / VB->Clip[v1][3]) );
	 D3DTLVertices[cVertex++].color= (ctx->Light.ShadeModel == GL_FLAT) ? 
                                       dwPVColor :
                                       (VB->Color[v1][3]<<24) | (VB->Color[v1][0]<<16) | (VB->Color[v1][1]<<8) | VB->Color[v1][2];
   
	 D3DTLVertices[cVertex].sx     = D3DVAL( VB->Win[v2][0] );
	 D3DTLVertices[cVertex].sy     = D3DVAL( (height - VB->Win[v2][1]) );
	 D3DTLVertices[cVertex].sz     = D3DVAL( (VB->Win[v2][2] + ctx->PolygonZoffset) );
	 D3DTLVertices[cVertex].tu     = D3DVAL( VB->TexCoord[v2][0] );
	 D3DTLVertices[cVertex].tv     = D3DVAL( VB->TexCoord[v2][1] );
	 D3DTLVertices[cVertex].rhw    = D3DVAL( (1.0 / VB->Clip[v2][3]) );
	 D3DTLVertices[cVertex++].color= (ctx->Light.ShadeModel == GL_FLAT) ? 
                                       dwPVColor :
                                       (VB->Color[v2][3]<<24) | (VB->Color[v2][0]<<16) | (VB->Color[v2][1]<<8) | VB->Color[v2][2];
      
	 D3DTLVertices[cVertex].sx     = D3DVAL( VB->Win[v3][0] );
	 D3DTLVertices[cVertex].sy     = D3DVAL( (height - VB->Win[v3][1]) );
	 D3DTLVertices[cVertex].sz     = D3DVAL( (VB->Win[v3][2] + ctx->PolygonZoffset) );
	 D3DTLVertices[cVertex].tu     = D3DVAL( VB->TexCoord[v3][0] );
	 D3DTLVertices[cVertex].tv     = D3DVAL( VB->TexCoord[v3][1] );
	 D3DTLVertices[cVertex].rhw    = D3DVAL( (1.0 / VB->Clip[v3][3]) );
	 D3DTLVertices[cVertex++].color= (ctx->Light.ShadeModel == GL_FLAT) ? 
                                       dwPVColor :
                                       (VB->Color[v3][3]<<24) | (VB->Color[v3][0]<<16) | (VB->Color[v3][1]<<8) | VB->Color[v3][2];
   
	 D3DTLVertices[cVertex].sx     = D3DVAL( VB->Win[v1][0] );
	 D3DTLVertices[cVertex].sy     = D3DVAL( (height - VB->Win[v1][1]) );
	 D3DTLVertices[cVertex].sz     = D3DVAL( (VB->Win[v1][2] + ctx->PolygonZoffset) );
	 D3DTLVertices[cVertex].tu     = D3DVAL( VB->TexCoord[v1][0] );
	 D3DTLVertices[cVertex].tv     = D3DVAL( VB->TexCoord[v1][1] );
	 D3DTLVertices[cVertex].rhw    = D3DVAL( (1.0 / VB->Clip[v1][3]) );
	 D3DTLVertices[cVertex++].color= (ctx->Light.ShadeModel == GL_FLAT) ? 
	                                  dwPVColor :
                                       (VB->Color[v1][3]<<24) | (VB->Color[v1][0]<<16) | (VB->Color[v1][1]<<8) | VB->Color[v1][2];
   
	 D3DTLVertices[cVertex].sx     = D3DVAL( VB->Win[v3][0] );
	 D3DTLVertices[cVertex].sy     = D3DVAL( (height - VB->Win[v3][1]) );
	 D3DTLVertices[cVertex].sz     = D3DVAL( (VB->Win[v3][2] + ctx->PolygonZoffset) );
	 D3DTLVertices[cVertex].tu     = D3DVAL( VB->TexCoord[v3][0] );
	 D3DTLVertices[cVertex].tv     = D3DVAL( VB->TexCoord[v3][1] );
	 D3DTLVertices[cVertex].rhw    = D3DVAL( (1.0 / VB->Clip[v3][3]) );
	 D3DTLVertices[cVertex++].color= (ctx->Light.ShadeModel == GL_FLAT) ? 
                                       dwPVColor :
                                       (VB->Color[v3][3]<<24) | (VB->Color[v3][0]<<16) | (VB->Color[v3][1]<<8) | VB->Color[v3][2];
   
	 D3DTLVertices[cVertex].sx     = D3DVAL( VB->Win[v4][0] );
	 D3DTLVertices[cVertex].sy     = D3DVAL( (height - VB->Win[v4][1]) );
	 D3DTLVertices[cVertex].sz     = D3DVAL( (VB->Win[v4][2] + ctx->PolygonZoffset) );
	 D3DTLVertices[cVertex].tu     = D3DVAL( VB->TexCoord[v4][0] );
	 D3DTLVertices[cVertex].tv     = D3DVAL( VB->TexCoord[v4][1] );
	 D3DTLVertices[cVertex].rhw    = D3DVAL( (1.0 / VB->Clip[v4][3]) );
	 D3DTLVertices[cVertex++].color= (ctx->Light.ShadeModel == GL_FLAT) ? 
                                       dwPVColor :
                                       (VB->Color[v4][3]<<24) | (VB->Color[v4][0]<<16) | (VB->Color[v4][1]<<8) | VB->Color[v4][2];
    }
  }

#undef   v4
#undef   v3
#undef   v2
#undef   v1

  /* Render the converted vertex buffer. */  
  if ( cVertex )
    DrawPrimitiveHAL( pContext->pShared, D3DPT_TRIANGLELIST, &D3DTLVertices[0], cVertex );
}
/*===========================================================================*/
/*                                                                           */
/*===========================================================================*/
/* RETURN: TRUE, FALSE.                                                      */
/*===========================================================================*/
static void RenderQuad( GLcontext *ctx, GLuint v1, GLuint v2, GLuint v3, GLuint v4, GLuint pv )
{
  D3DMESACONTEXT     	*pContext = (D3DMESACONTEXT *)ctx->DriverCtx;
  struct vertex_buffer 	*VB = ctx->VB;
  int                  	height = (pContext->pShared->rectW.bottom - pContext->pShared->rectW.top);
  DWORD                	dwPVColor;
  GLfloat              	ex, ey, 
                         fx, fy, c;
  GLuint               	facing;  /* 0=front, 1=back */
  static D3DTLVERTEX   	TLVertices[6];

  DPF(( DBG_FUNC, "RenderQuad" ));
  DPF(( DBG_PRIM_INFO, "RenderQuad( 1 )" ));

  /* Compute orientation of triangle */
  ex = VB->Win[v2][0] - VB->Win[v1][0];
  ey = VB->Win[v2][1] - VB->Win[v1][1];
  fx = VB->Win[v3][0] - VB->Win[v1][0];
  fy = VB->Win[v3][1] - VB->Win[v1][1];
  c = (ex * fy) - (ey * fx);

  /* polygon is perpindicular to view plane, don't draw it */
  if ( (c == 0.0F) && !ctx->Polygon.Unfilled )
    return;

  /* Backface culling. */
  facing = (c < 0.0F) ^ ctx->Polygon.FrontBit;
  if ( (facing + 1) & ctx->Polygon.CullBits )  
    return;

  if ( ctx->IndirectTriangles & DD_TRI_LIGHT_TWOSIDE ) 
  {
    if ( facing == 1 ) 
    {
	 /* use back color */
	 VB->Color   = VB->Bcolor;
	 VB->Specular= VB->Bspec;
    }
    else 
    {
	 /* use front color */
	 VB->Color   = VB->Fcolor;
	 VB->Specular= VB->Fspec;
    }
  }

  if ( ctx->IndirectTriangles & DD_TRI_OFFSET ) 
  {
    /* Finish computing plane equation of polygon, compute offset */
    GLfloat fz = VB->Win[v3][2] - VB->Win[v1][2];  
    GLfloat ez = VB->Win[v2][2] - VB->Win[v1][2];
    GLfloat a = (ey * fz) - (ez * fy);
    GLfloat b = (ez * fx) - (ex * fz);
    OffsetPolygon( ctx, a, b, c );
  }
  
  if ( ctx->Light.ShadeModel == GL_FLAT )
    dwPVColor = (VB->Color[pv][3]<<24) | (VB->Color[pv][0]<<16) | (VB->Color[pv][1]<<8) | VB->Color[pv][2];

  /*=====================================*/
  /* Populate the the triangle vertices. */
  /*=====================================*/
  TLVertices[0].sx      = D3DVAL( VB->Win[v1][0] );
  TLVertices[0].sy      = D3DVAL( (height - VB->Win[v1][1]) );
  TLVertices[0].sz      = D3DVAL( (VB->Win[v1][2] + ctx->PolygonZoffset) );
  TLVertices[0].tu      = D3DVAL( VB->TexCoord[v1][0] );
  TLVertices[0].tv      = D3DVAL( VB->TexCoord[v1][1] );
  TLVertices[0].rhw     = D3DVAL( (1.0 / VB->Clip[v1][3]) );
  TLVertices[0].color   = (ctx->Light.ShadeModel == GL_FLAT) ? dwPVColor :
                           (VB->Color[v1][3]<<24) | (VB->Color[v1][0]<<16) | (VB->Color[v1][1]<<8) | VB->Color[v1][2];

   TLVertices[1].sx      = D3DVAL( VB->Win[v2][0] );
   TLVertices[1].sy      = D3DVAL( (height - VB->Win[v2][1]) );
   TLVertices[1].sz      = D3DVAL( (VB->Win[v2][2] + ctx->PolygonZoffset) );
   TLVertices[1].tu      = D3DVAL( VB->TexCoord[v2][0] );
   TLVertices[1].tv      = D3DVAL( VB->TexCoord[v2][1] );
   TLVertices[1].rhw     = D3DVAL( (1.0 / VB->Clip[v2][3]) );
   TLVertices[1].color   = (ctx->Light.ShadeModel == GL_FLAT) ? dwPVColor :
                           (VB->Color[v2][3]<<24) | (VB->Color[v2][0]<<16) | (VB->Color[v2][1]<<8) | VB->Color[v2][2];
   
   TLVertices[2].sx      = D3DVAL( VB->Win[v3][0] );
   TLVertices[2].sy      = D3DVAL( (height - VB->Win[v3][1]) );
   TLVertices[2].sz      = D3DVAL( (VB->Win[v3][2] + ctx->PolygonZoffset) );
   TLVertices[2].tu      = D3DVAL( VB->TexCoord[v3][0] );
   TLVertices[2].tv      = D3DVAL( VB->TexCoord[v3][1] );
   TLVertices[2].rhw     = D3DVAL( (1.0 / VB->Clip[v3][3]) );
   TLVertices[2].color   = (ctx->Light.ShadeModel == GL_FLAT) ? dwPVColor :
                           (VB->Color[v3][3]<<24) | (VB->Color[v3][0]<<16) | (VB->Color[v3][1]<<8) | VB->Color[v3][2];

   TLVertices[3].sx      = D3DVAL( VB->Win[v3][0] );
   TLVertices[3].sy      = D3DVAL( (height - VB->Win[v3][1]) );
   TLVertices[3].sz      = D3DVAL( (VB->Win[v3][2] + ctx->PolygonZoffset) );
   TLVertices[3].tu      = D3DVAL( VB->TexCoord[v3][0] );
   TLVertices[3].tv      = D3DVAL( VB->TexCoord[v3][1] );
   TLVertices[3].rhw     = D3DVAL( (1.0 / VB->Clip[v3][3]) );
   TLVertices[3].color   = (ctx->Light.ShadeModel == GL_FLAT) ? dwPVColor :
                           (VB->Color[v3][3]<<24) | (VB->Color[v3][0]<<16) | (VB->Color[v3][1]<<8) | VB->Color[v3][2];

   TLVertices[4].sx      = D3DVAL( VB->Win[v4][0] );
   TLVertices[4].sy      = D3DVAL( (height - VB->Win[v4][1]) );
   TLVertices[4].sz      = D3DVAL( (VB->Win[v4][2] + ctx->PolygonZoffset) );
   TLVertices[4].tu      = D3DVAL( VB->TexCoord[v4][0] );
   TLVertices[4].tv      = D3DVAL( VB->TexCoord[v4][1] );
   TLVertices[4].rhw     = D3DVAL( (1.0 / VB->Clip[v4][3]) );
   TLVertices[4].color   = (ctx->Light.ShadeModel == GL_FLAT) ? dwPVColor :
                           (VB->Color[v4][3]<<24) | (VB->Color[v4][0]<<16) | (VB->Color[v4][1]<<8) | VB->Color[v4][2];

   TLVertices[5].sx      = D3DVAL( VB->Win[v1][0] );
   TLVertices[5].sy      = D3DVAL( (height - VB->Win[v1][1]) );
   TLVertices[5].sz      = D3DVAL( (VB->Win[v1][2] + ctx->PolygonZoffset) );
   TLVertices[5].tu      = D3DVAL( VB->TexCoord[v1][0] );
   TLVertices[5].tv      = D3DVAL( VB->TexCoord[v1][1] );
   TLVertices[5].rhw     = D3DVAL( (1.0 / VB->Clip[v1][3]) );
   TLVertices[5].color   = (ctx->Light.ShadeModel == GL_FLAT) ? dwPVColor :
                           (VB->Color[v1][3]<<24) | (VB->Color[v1][0]<<16) | (VB->Color[v1][1]<<8) | VB->Color[v1][2];

   /* Draw the two triangles. */  
   DrawPrimitiveHAL( pContext->pShared, D3DPT_TRIANGLELIST, &TLVertices[0], 6 );
}
/*===========================================================================*/
/*                                                                           */
/*===========================================================================*/
/* RETURN: TRUE, FALSE.                                                      */
/*===========================================================================*/
void	RenderOneTriangle( GLcontext *ctx, GLuint v1, GLuint v2, GLuint v3, GLuint pv )
{
  D3DMESACONTEXT       	*pContext = (D3DMESACONTEXT *)ctx->DriverCtx;
  struct vertex_buffer 	*VB = ctx->VB;
  int                  	height = (pContext->pShared->rectW.bottom - pContext->pShared->rectW.top);
  DWORD                	dwPVColor;
  static D3DTLVERTEX   	TLVertices[3];

  DPF(( DBG_FUNC, "RenderOneTriangle" ));
  DPF(( DBG_PRIM_INFO, "RenderTriangle( 1 )" ));

  /*=====================================*/
  /* Populate the the triangle vertices. */
  /*=====================================*/
  if ( ctx->Light.ShadeModel == GL_FLAT )
    dwPVColor = (VB->Color[pv][3]<<24) | (VB->Color[pv][0]<<16) | (VB->Color[pv][1]<<8) | VB->Color[pv][2];

  TLVertices[0].sx      = D3DVAL( VB->Win[v1][0] );
  TLVertices[0].sy      = D3DVAL( (height - VB->Win[v1][1]) );
  TLVertices[0].sz      = D3DVAL( (VB->Win[v1][2] + ctx->PolygonZoffset) );
  TLVertices[0].tu      = D3DVAL( VB->TexCoord[v1][0] );
  TLVertices[0].tv      = D3DVAL( VB->TexCoord[v1][1] );
  TLVertices[0].rhw     = D3DVAL( (1.0 / VB->Clip[v1][3]) );
  TLVertices[0].color   = (ctx->Light.ShadeModel == GL_FLAT) ? dwPVColor :
                          (VB->Color[v1][3]<<24) | (VB->Color[v1][0]<<16) | (VB->Color[v1][1]<<8) | VB->Color[v1][2];
  DPF(( DBG_PRIM_INFO, "V1 -> x:%f y:%f z:%f c:%x",
	   TLVertices[0].sx,
	   TLVertices[0].sy,
	   TLVertices[0].sz,
	   TLVertices[0].color ));

  TLVertices[1].sx      = D3DVAL( VB->Win[v2][0] );
  TLVertices[1].sy      = D3DVAL( (height - VB->Win[v2][1]) );
  TLVertices[1].sz      = D3DVAL( (VB->Win[v2][2] + ctx->PolygonZoffset) );
  TLVertices[1].tu      = D3DVAL( VB->TexCoord[v2][0] );
  TLVertices[1].tv      = D3DVAL( VB->TexCoord[v2][1] );
  TLVertices[1].rhw     = D3DVAL( (1.0 / VB->Clip[v2][3]) );
  TLVertices[1].color   = (ctx->Light.ShadeModel == GL_FLAT) ? dwPVColor :
                          (VB->Color[v2][3]<<24) | (VB->Color[v2][0]<<16) | (VB->Color[v2][1]<<8) | VB->Color[v2][2];
  DPF(( DBG_PRIM_INFO, "V2 -> x:%f y:%f z:%f c:%x",
	   TLVertices[1].sx,
	   TLVertices[1].sy,
	   TLVertices[1].sz,
	   TLVertices[1].color ));
   
  TLVertices[2].sx      = D3DVAL( VB->Win[v3][0] );
  TLVertices[2].sy      = D3DVAL( (height - VB->Win[v3][1]) );
  TLVertices[2].sz      = D3DVAL( (VB->Win[v3][2] + ctx->PolygonZoffset) );
  TLVertices[2].tu      = D3DVAL( VB->TexCoord[v3][0] );
  TLVertices[2].tv      = D3DVAL( VB->TexCoord[v3][1] );
  TLVertices[2].rhw     = D3DVAL( (1.0 / VB->Clip[v3][3]) );
  TLVertices[2].color   = (ctx->Light.ShadeModel == GL_FLAT) ? dwPVColor :
                          (VB->Color[v3][3]<<24) | (VB->Color[v3][0]<<16) | (VB->Color[v3][1]<<8) | VB->Color[v3][2];
  DPF(( DBG_PRIM_INFO, "V3 -> x:%f y:%f z:%f c:%x",
	   TLVertices[2].sx,
	   TLVertices[2].sy,
	   TLVertices[2].sz,
	   TLVertices[2].color ));

  /* Draw the triangle. */  
  DrawPrimitiveHAL( pContext->pShared, D3DPT_TRIANGLELIST, &TLVertices[0], 3 );
}
/*===========================================================================*/
/*                                                                           */
/*===========================================================================*/
/* RETURN: TRUE, FALSE.                                                      */
/*===========================================================================*/
void RenderOneLine( GLcontext *ctx, GLuint v1, GLuint v2, GLuint pv )
{
  D3DMESACONTEXT     	*pContext = (D3DMESACONTEXT *)ctx->DriverCtx;
  struct vertex_buffer 	*VB = ctx->VB;
  int                  	height = (pContext->pShared->rectW.bottom - pContext->pShared->rectW.top);
  DWORD                	dwPVColor;
  static D3DTLVERTEX	TLVertices[2];

  DPF(( DBG_FUNC, "RenderOneLine" ));
  DPF(( DBG_PRIM_INFO, "RenderLine( 1 )" ));

  if ( VB->MonoColor ) 
    dwPVColor = (pContext->aCurrent<<24) | (pContext->rCurrent<<16) | (pContext->gCurrent<<8) | pContext->bCurrent;
  else 	
    dwPVColor = (VB->Color[pv][3]<<24) | (VB->Color[pv][0]<<16) | (VB->Color[pv][1]<<8) | VB->Color[pv][2];

   TLVertices[0].sx      = D3DVAL( VB->Win[v1][0] );
   TLVertices[0].sy      = D3DVAL( (height - VB->Win[v1][1]) );
   TLVertices[0].sz      = D3DVAL( (VB->Win[v1][2] + ctx->LineZoffset) );
   TLVertices[0].tu      = D3DVAL( VB->TexCoord[v1][0] );
   TLVertices[0].tv      = D3DVAL( VB->TexCoord[v1][1] );
   TLVertices[0].rhw     = D3DVAL( (1.0 / VB->Clip[v1][3]) );
   TLVertices[0].color   = (ctx->Light.ShadeModel == GL_FLAT) ? dwPVColor :
                           (VB->Color[v1][3]<<24) | (VB->Color[v1][0]<<16) | (VB->Color[v1][1]<<8) | VB->Color[v1][2];

   TLVertices[1].sx      = D3DVAL( VB->Win[v2][0] );
   TLVertices[1].sy      = D3DVAL( (height - VB->Win[v2][1]) );
   TLVertices[1].sz      = D3DVAL( (VB->Win[v2][2] + ctx->LineZoffset) );
   TLVertices[1].tu      = D3DVAL( VB->TexCoord[v2][0] );
   TLVertices[1].tv      = D3DVAL( VB->TexCoord[v2][1] );
   TLVertices[1].rhw     = D3DVAL( (1.0 / VB->Clip[v2][3]) );
   TLVertices[1].color   = (ctx->Light.ShadeModel == GL_FLAT) ? dwPVColor :
                           (VB->Color[v2][3]<<24) | (VB->Color[v2][0]<<16) | (VB->Color[v2][1]<<8) | VB->Color[v2][2];

   /* Draw line from (x0,y0) to (x1,y1) with current pixel color/index */
   DrawPrimitiveHAL( pContext->pShared, D3DPT_LINELIST, &TLVertices[0], 2 );
}
/*===========================================================================*/
/*  This function was written to convert points into triangles.  I did this  */
/* as all card accelerate triangles and most drivers do this anyway.  In hind*/
/* thought this might be a bad idea as some cards do better.                 */
/*===========================================================================*/
/* RETURN:                                                                   */
/*===========================================================================*/
static void RenderPointsVB( GLcontext *ctx, GLuint start, GLuint end )
{
  D3DMESACONTEXT 		*pContext = (D3DMESACONTEXT *)ctx->DriverCtx;
  struct vertex_buffer 	*VB = ctx->VB;
  struct pixel_buffer 	*PB = ctx->PB;
  GLuint 				index;
  GLfloat                radius, z,
                         xmin, ymin, 
                         xmax, ymax;
  GLint				cVertex,
                         height = (pContext->pShared->rectW.bottom - pContext->pShared->rectW.top);
  DWORD				dwPVColor;
  
  DPF(( DBG_FUNC, "RenderPointsVB();" ));

  radius = CLAMP( ctx->Point.Size, MIN_POINT_SIZE, MAX_POINT_SIZE ) * 0.5F;

  for( index = start, cVertex = 0; index <= end; index++ ) 
  {
    if ( VB->ClipMask[index] == 0 ) 
    {
	 xmin = D3DVAL( VB->Win[index][0] - radius );
	 xmax = D3DVAL( VB->Win[index][0] + radius );
	 ymin = D3DVAL( height - VB->Win[index][1] - radius );
	 ymax = D3DVAL( height - VB->Win[index][1] + radius );
	 z    = D3DVAL( (VB->Win[index][2] + ctx->PointZoffset) );

	 dwPVColor = (VB->Color[index][3]<<24) | 
	             (VB->Color[index][0]<<16) | 
	             (VB->Color[index][1]<<8) | 
                  VB->Color[index][2];

	 D3DTLVertices[cVertex].sx	  = xmin;
	 D3DTLVertices[cVertex].sy      = ymax;
	 D3DTLVertices[cVertex].sz      = z;
	 D3DTLVertices[cVertex].tu      = 0.0;
	 D3DTLVertices[cVertex].tv      = 0.0;
	 D3DTLVertices[cVertex].rhw     = D3DVAL( (1.0 / VB->Clip[index][3]) );
	 D3DTLVertices[cVertex++].color = dwPVColor;

	 D3DTLVertices[cVertex].sx      = xmin;
	 D3DTLVertices[cVertex].sy      = ymin;
	 D3DTLVertices[cVertex].sz      = z;
	 D3DTLVertices[cVertex].tu      = 0.0;
	 D3DTLVertices[cVertex].tv      = 0.0;
	 D3DTLVertices[cVertex].rhw     = D3DVAL( (1.0 / VB->Clip[index][3]) );
	 D3DTLVertices[cVertex++].color = dwPVColor;
   
	 D3DTLVertices[cVertex].sx      = xmax;
	 D3DTLVertices[cVertex].sy      = ymin;
	 D3DTLVertices[cVertex].sz      = z;
	 D3DTLVertices[cVertex].tu      = 0.0;
	 D3DTLVertices[cVertex].tv      = 0.0;
	 D3DTLVertices[cVertex].rhw     = D3DVAL( (1.0 / VB->Clip[index][3]) );
	 D3DTLVertices[cVertex++].color = dwPVColor;
   
	 D3DTLVertices[cVertex].sx      = xmax;
	 D3DTLVertices[cVertex].sy      = ymin;
	 D3DTLVertices[cVertex].sz      = z;
	 D3DTLVertices[cVertex].tu      = 0.0;
	 D3DTLVertices[cVertex].tv      = 0.0;
	 D3DTLVertices[cVertex].rhw     = D3DVAL( (1.0 / VB->Clip[index][3]) );
	 D3DTLVertices[cVertex++].color = dwPVColor;

	 D3DTLVertices[cVertex].sx	  = xmax;
	 D3DTLVertices[cVertex].sy      = ymax;
	 D3DTLVertices[cVertex].sz      = z;
	 D3DTLVertices[cVertex].tu      = 0.0;
	 D3DTLVertices[cVertex].tv      = 0.0;
	 D3DTLVertices[cVertex].rhw     = D3DVAL( (1.0 / VB->Clip[index][3]) );
	 D3DTLVertices[cVertex++].color = dwPVColor;

	 D3DTLVertices[cVertex].sx	  = xmin;
	 D3DTLVertices[cVertex].sy      = ymax;
	 D3DTLVertices[cVertex].sz      = z;
	 D3DTLVertices[cVertex].tu      = 0.0;
	 D3DTLVertices[cVertex].tv      = 0.0;
	 D3DTLVertices[cVertex].rhw     = D3DVAL( (1.0 / VB->Clip[index][3]) );
	 D3DTLVertices[cVertex++].color = dwPVColor;
    }
  }

  /* Render the converted vertex buffer. */  
  if ( cVertex )
    DrawPrimitiveHAL( pContext->pShared, D3DPT_TRIANGLELIST, &D3DTLVertices[0], cVertex );
}
/*===========================================================================*/
/*  This gets call before we render any primitives so that the current OGL   */
/* states will be mapped the D3D context.  I'm still not sure how D3D works  */
/* but I'm finding that it doesn't act like a state machine as OGL is.  It   */
/* looks like the state gets set back to the defaults after a DrawPrimitives */
/* or an EndScene.  Also I set states that are the default even though this  */
/* is redundant as the defaults seem screwed up.                             */
/* TODO: make a batch call.                                                  */
/*===========================================================================*/
/* RETURN:                                                                   */
/*===========================================================================*/
static void SetRenderStates( GLcontext *ctx )
{
   D3DMESACONTEXT	*pContext = (D3DMESACONTEXT *)ctx->DriverCtx;
   DWORD          	dwFunc;
   static	BOOL		bTexture = FALSE;
   static int		texName = -1;

   DPF(( DBG_FUNC, "SetRenderStates();" ));

   if ( g_DBGMask & DBG_STATES )
	DebugRenderStates( ctx, FALSE );

   SetStateHAL( pContext->pShared, D3DRENDERSTATE_CULLMODE, D3DCULL_NONE );
   SetStateHAL( pContext->pShared, D3DRENDERSTATE_DITHERENABLE, (ctx->Color.DitherFlag) ? TRUE : FALSE );

   /*================================================*/
   /* Check too see if there are new TEXTURE states. */
   /*================================================*/
   if ( ctx->Texture.ReallyEnabled )
   {
      switch( ctx->Texture.Set[ctx->Texture.CurrentSet].EnvMode )
      {
        case GL_MODULATE:
		if ( ctx->Texture.Set[ctx->Texture.CurrentSet].Current->Image[0]->Format == GL_RGBA )
		  dwFunc = pContext->pShared->dwTexFunc[d3dtblend_modulatealpha];
		else
		  dwFunc = pContext->pShared->dwTexFunc[d3dtblend_modulate];
		break;

	   case GL_BLEND:
		dwFunc = pContext->pShared->dwTexFunc[d3dtblend_decalalpha];
		break;
  
        case GL_REPLACE:
		dwFunc = pContext->pShared->dwTexFunc[d3dtblend_decal];
		break;

        case GL_DECAL:
		if ( ctx->Texture.Set[ctx->Texture.CurrentSet].Current->Image[0]->Format == GL_RGBA )
		  dwFunc = pContext->pShared->dwTexFunc[d3dtblend_decalalpha];
		else
		  dwFunc = pContext->pShared->dwTexFunc[d3dtblend_decal];
		break;
      }
      SetStateHAL( pContext->pShared, D3DRENDERSTATE_TEXTUREMAPBLEND, dwFunc );
      
      switch( ctx->Texture.Set[ctx->Texture.CurrentSet].Current->MagFilter )
      {
	   case GL_NEAREST:
		dwFunc = D3DFILTER_NEAREST;
		break;
        case GL_LINEAR:
		dwFunc = D3DFILTER_LINEAR;
		break;
        case GL_NEAREST_MIPMAP_NEAREST:
		dwFunc = D3DFILTER_MIPNEAREST;
		break;
        case GL_LINEAR_MIPMAP_NEAREST:
		dwFunc = D3DFILTER_LINEARMIPNEAREST;
		break;
        case GL_NEAREST_MIPMAP_LINEAR:
		dwFunc = D3DFILTER_MIPLINEAR;
		break;
        case GL_LINEAR_MIPMAP_LINEAR:
		dwFunc = D3DFILTER_LINEARMIPLINEAR;
		break;
      }
      SetStateHAL( pContext->pShared, D3DRENDERSTATE_TEXTUREMAG, dwFunc );

      switch( ctx->Texture.Set[ctx->Texture.CurrentSet].Current->MinFilter )
      {
	   case GL_NEAREST:
		dwFunc = D3DFILTER_NEAREST;
		break;
        case GL_LINEAR:
		dwFunc = D3DFILTER_LINEAR;
		break;
        case GL_NEAREST_MIPMAP_NEAREST:
		dwFunc = D3DFILTER_MIPNEAREST;
		break;
        case GL_LINEAR_MIPMAP_NEAREST:
		dwFunc = D3DFILTER_LINEARMIPNEAREST;
		break;
        case GL_NEAREST_MIPMAP_LINEAR:
		dwFunc = D3DFILTER_MIPLINEAR;
		break;
        case GL_LINEAR_MIPMAP_LINEAR:
		dwFunc = D3DFILTER_LINEARMIPLINEAR;
		break;
      }
      SetStateHAL( pContext->pShared, D3DRENDERSTATE_TEXTUREMIN, dwFunc  );

	 /* Another hack to cut down on redundant texture binding. */
	 //	 if ( texName != ctx->Texture.Set[ctx->Texture.CurrentSet].Current->Name )
	 //	 {
	   texName = ctx->Texture.Set[ctx->Texture.CurrentSet].Current->Name;
	   CreateTMgrHAL( pContext->pShared, 
				   texName,
				   0,
				   ctx->Texture.Set[ctx->Texture.CurrentSet].Current->Image[0]->Format,
				   (RECT *)NULL,
				   ctx->Texture.Set[ctx->Texture.CurrentSet].Current->Image[0]->Width, 
				   ctx->Texture.Set[ctx->Texture.CurrentSet].Current->Image[0]->Height,
				   TM_ACTION_BIND,
				   (void *)ctx->Texture.Set[ctx->Texture.CurrentSet].Current->Image[0]->Data );
	   //	 }
	 bTexture = TRUE;
   }
   else
   {
	/* This is nasty but should cut down on the number of redundant calls. */
	if ( bTexture == TRUE )
	{
	  DisableTMgrHAL( pContext->pShared );
	  bTexture = FALSE;
	}
   }

   /*===============================================*/
   /* Check too see if there are new RASTER states. */
   /*===============================================*/

   // TODO: no concept of front & back.
   switch( ctx->Polygon.FrontMode )
   {
     case GL_POINT:
	  SetStateHAL( pContext->pShared, D3DRENDERSTATE_FILLMODE, D3DFILL_POINT );
	  break;
     case GL_LINE:
	  SetStateHAL( pContext->pShared, D3DRENDERSTATE_FILLMODE, D3DFILL_WIREFRAME );
	  break;
     case GL_FILL:
	  SetStateHAL( pContext->pShared, D3DRENDERSTATE_FILLMODE, D3DFILL_SOLID );
	  break;
   }

   /*************/
   /* Z-Buffer. */
   /*************/
   if ( ctx->Depth.Test == GL_TRUE )
   {
	switch( ctx->Depth.Func )
	{  
	  case GL_NEVER:    
	    dwFunc = D3DCMP_NEVER;        
	    break;
	  case GL_LESS:     
	    dwFunc = D3DCMP_LESS;         
	    break;
  	  case GL_GEQUAL:   
	    dwFunc = D3DCMP_GREATEREQUAL; 
	    break;
  	  case GL_LEQUAL:   
	    dwFunc = D3DCMP_LESSEQUAL;    
	    break;
	  case GL_GREATER:  
	    dwFunc = D3DCMP_GREATER;      
	    break;
	  case GL_NOTEQUAL: 
	    dwFunc = D3DCMP_NOTEQUAL;     
	    break;
	  case GL_EQUAL:    
	    dwFunc = D3DCMP_EQUAL;        
	    break;
	  case GL_ALWAYS:   
	    dwFunc = D3DCMP_ALWAYS;       
	    break;
	}
	SetStateHAL( pContext->pShared, D3DRENDERSTATE_ZFUNC, dwFunc );
	SetStateHAL( pContext->pShared, D3DRENDERSTATE_ZENABLE, TRUE );
   }	
   else
   {
	SetStateHAL( pContext->pShared, D3DRENDERSTATE_ZENABLE, FALSE );
   }

   /*******************/
   /* Z-Write Enable. */
   /*******************/
   SetStateHAL( pContext->pShared, D3DRENDERSTATE_ZWRITEENABLE , (ctx->Depth.Mask == GL_TRUE) ? TRUE : FALSE );

   /***************/
   /* Alpha test. */
   /***************/
   if ( ctx->Color.AlphaEnabled == GL_TRUE )
   {
	switch( ctx->Color.AlphaFunc )
     {  
	  case GL_NEVER:    
	    dwFunc = D3DCMP_NEVER;        
	    break;
	  case GL_LESS:     
	    dwFunc = D3DCMP_LESS;         
	    break;
  	  case GL_GEQUAL:   
	    dwFunc = D3DCMP_GREATEREQUAL; 
	    break;
  	  case GL_LEQUAL:   
	    dwFunc = D3DCMP_LESSEQUAL;    
	    break;
	  case GL_GREATER:  
	    dwFunc = D3DCMP_GREATER;      
	    break;
	  case GL_NOTEQUAL: 
	    dwFunc = D3DCMP_NOTEQUAL;     
	    break;
	  case GL_EQUAL:    
	    dwFunc = D3DCMP_EQUAL;        
	    break;
	  case GL_ALWAYS:   
	    dwFunc = D3DCMP_ALWAYS;       
	    break;
	}
	SetStateHAL( pContext->pShared, D3DRENDERSTATE_ALPHAFUNC , dwFunc );
	SetStateHAL( pContext->pShared, D3DRENDERSTATE_ALPHATESTENABLE, TRUE );
   }
   else
   {
	SetStateHAL( pContext->pShared, D3DRENDERSTATE_ALPHATESTENABLE, FALSE );
   }

   /****************/
   /* Alpha blend. */
   /****************/
   if ( ctx->Color.BlendEnabled == GL_TRUE )
   {
	switch( ctx->Color.BlendSrc ) 
	{
	  case GL_ZERO:	    			
	    dwFunc = pContext->pShared->dwSrcBlendCaps[s_zero];
	    break;
       case GL_ONE:                     
	    dwFunc = pContext->pShared->dwSrcBlendCaps[s_one];
	    break;
       case GL_DST_COLOR:               
	    dwFunc = pContext->pShared->dwSrcBlendCaps[s_dst_color];
	    break;
       case GL_ONE_MINUS_DST_COLOR:     
	    dwFunc = pContext->pShared->dwSrcBlendCaps[s_one_minus_dst_color];
	    break;
       case GL_SRC_ALPHA:               
	    dwFunc = pContext->pShared->dwSrcBlendCaps[s_src_alpha];
	    break;
       case GL_ONE_MINUS_SRC_ALPHA:     
	    dwFunc = pContext->pShared->dwSrcBlendCaps[s_one_minus_src_alpha];
	    break;
       case GL_DST_ALPHA:               
	    dwFunc = pContext->pShared->dwSrcBlendCaps[s_dst_alpha];
	    break;
       case GL_ONE_MINUS_DST_ALPHA:     
	    dwFunc = pContext->pShared->dwSrcBlendCaps[s_one_minus_dst_alpha];
	    break;
       case GL_SRC_ALPHA_SATURATE:      
	    dwFunc = pContext->pShared->dwSrcBlendCaps[s_src_alpha_saturate];
	    break;
       case GL_CONSTANT_COLOR:          
	    dwFunc = pContext->pShared->dwSrcBlendCaps[s_constant_color];
	    break;
       case GL_ONE_MINUS_CONSTANT_COLOR:
	    dwFunc = pContext->pShared->dwSrcBlendCaps[s_one_minus_constant_color];
	    break;
       case GL_CONSTANT_ALPHA:          
	    dwFunc = pContext->pShared->dwSrcBlendCaps[s_constant_alpha];
	    break;
       case GL_ONE_MINUS_CONSTANT_ALPHA:
	    dwFunc = pContext->pShared->dwSrcBlendCaps[s_one_minus_constant_alpha];
	    break;
	}
	SetStateHAL( pContext->pShared, D3DRENDERSTATE_SRCBLEND, dwFunc );

	switch( ctx->Color.BlendDst ) 
	{
       case GL_ZERO:                  	
	    dwFunc = pContext->pShared->dwDestBlendCaps[d_zero];
	    break;
       case GL_ONE:                     
	    dwFunc = pContext->pShared->dwDestBlendCaps[d_one];
	    break;
       case GL_SRC_COLOR:               
	    dwFunc = pContext->pShared->dwDestBlendCaps[d_src_color];
	    break;
       case GL_ONE_MINUS_SRC_COLOR:     
	    dwFunc = pContext->pShared->dwDestBlendCaps[d_one_minus_src_color];
	    break;
       case GL_SRC_ALPHA:               
	    dwFunc = pContext->pShared->dwDestBlendCaps[d_src_alpha];
	    break;
       case GL_ONE_MINUS_SRC_ALPHA:     
	    dwFunc = pContext->pShared->dwDestBlendCaps[d_one_minus_src_alpha];
	    break;
       case GL_DST_ALPHA:               
	    dwFunc = pContext->pShared->dwDestBlendCaps[d_dst_alpha];
	    break;
       case GL_ONE_MINUS_DST_ALPHA:     
	    dwFunc = pContext->pShared->dwDestBlendCaps[d_one_minus_dst_alpha];
	    break;
       case GL_CONSTANT_COLOR:          
	    dwFunc = pContext->pShared->dwDestBlendCaps[d_constant_color];
	    break;
       case GL_ONE_MINUS_CONSTANT_COLOR:
	    dwFunc = pContext->pShared->dwDestBlendCaps[d_one_minus_constant_color];
	    break;
       case GL_CONSTANT_ALPHA:          
	    dwFunc = pContext->pShared->dwDestBlendCaps[d_constant_alpha];
	    break;
       case GL_ONE_MINUS_CONSTANT_ALPHA:
	    dwFunc = pContext->pShared->dwDestBlendCaps[d_one_minus_constant_alpha];
	    break;
	}
	SetStateHAL( pContext->pShared, D3DRENDERSTATE_DESTBLEND, dwFunc );
	SetStateHAL( pContext->pShared, D3DRENDERSTATE_ALPHABLENDENABLE, TRUE );
   }
   else
   {
	SetStateHAL( pContext->pShared, D3DRENDERSTATE_ALPHABLENDENABLE, FALSE );
   }
}
/*===========================================================================*/
/*  If this function is called it will track the changes to the current      */
/* states that I'm setting in Direct3D.  I did this so that the DPF's would  */
/* be under control!                                                         */
/*===========================================================================*/
/* RETURN:                                                                   */
/*===========================================================================*/
static void DebugRenderStates( GLcontext *ctx, BOOL bForce )
{
   D3DMESACONTEXT	*pContext = (D3DMESACONTEXT *)ctx->DriverCtx;
   DWORD			dwFunc;
   static int		dither = -1,
	               texture = -1,
                    textName = -1,
	               textEnv = -1,
                    textMin = -1,
                    textMag = -1,
                    polyMode = -1,
	               depthTest = -1,
	               depthFunc = -1,
	               depthMask = -1,
	               alphaTest = -1,
                    alphaFunc = -1,
	               blend = -1,
                    blendSrc = -1,
                    blendDest = -1;

   /* Force a displayed update of all current states. */
   if ( bForce )
   {
	dither = texture = textName = textEnv = textMin = textMag = -1;
	polyMode = depthTest = depthFunc = depthMask = -1;
	alphaTest = alphaFunc = blend = blendSrc = blendDest = -1;
   }

   if ( dither != ctx->Color.DitherFlag )
   {
	dither = ctx->Color.DitherFlag;
	DPF(( 0, "\tDither\t\t%s", (dither) ? "ENABLED" : "--------" ));
   }
   if ( depthTest != ctx->Depth.Test )
   {
	depthTest = ctx->Depth.Test;
	DPF(( 0, "\tDepth Test\t%s", (depthTest) ? "ENABLED" : "--------" ));
   }
   if ( alphaTest != ctx->Color.AlphaEnabled )
   {	
	alphaTest = ctx->Color.AlphaEnabled;
	
	DPF(( 0, "\tAlpha Test\t%s", (alphaTest) ? "ENABLED" : "--------" ));
   }
   if ( blend != ctx->Color.BlendEnabled )
   {	
	blend = ctx->Color.BlendEnabled;
	
	DPF(( 0, "\tBlending\t%s", (blend) ? "ENABLED" : "--------" ));
   }

   /*================================================*/
   /* Check too see if there are new TEXTURE states. */
   /*================================================*/
   if ( texture != ctx->Texture.ReallyEnabled )
   {
	texture = ctx->Texture.ReallyEnabled;
	DPF(( 0, "\tTexture\t\t%s", (texture) ? "ENABLED" : "--------" ));
   }	

   if ( ctx->Texture.Set[ctx->Texture.CurrentSet].Current )
   {
	if ( ctx->Texture.Set[ctx->Texture.CurrentSet].Current->Name != textName )
	{
	  textName = ctx->Texture.Set[ctx->Texture.CurrentSet].Current->Name;
	  DPF(( 0, "\tTexture Name:\t%d", textName ));
	  DPF(( 0, "\tTexture Format:\t%s", 
		   (ctx->Texture.Set[ctx->Texture.CurrentSet].Current->Image[0]->Format == GL_RGBA) ? 
		   "GL_RGBA" : "GLRGB" ));
	}

	if ( textEnv != ctx->Texture.Set[ctx->Texture.CurrentSet].EnvMode )
	{
	  textEnv = ctx->Texture.Set[ctx->Texture.CurrentSet].EnvMode;

	  switch( textEnv )
	  {
       case GL_MODULATE:
	    DPF(( 0, "\tTexture\tMode\tGL_MODULATE" ));
	    break;
       case GL_BLEND:
	    DPF(( 0, "\tTexture\tMode\tGL_BLEND" ));
	    break;
       case GL_REPLACE:
	    DPF(( 0, "\tTexture\tMode\tGL_REPLACE" ));
	    break;
       case GL_DECAL:
	    DPF(( 0, "\tTexture\tMode\tGL_DECAL" ));
	    break;
	  }
	}

	if ( textMag != ctx->Texture.Set[ctx->Texture.CurrentSet].Current->MagFilter )
	{
	  textMag = ctx->Texture.Set[ctx->Texture.CurrentSet].Current->MagFilter;
	  
	  switch( textMag )
	  {
       case GL_NEAREST:
	    DPF(( 0, "\tTexture MAG\tGL_NEAREST" ));
	    break;
       case GL_LINEAR:
	    DPF(( 0, "\tTexture MAG\tGL_LINEAR" ));
	    break;
       case GL_NEAREST_MIPMAP_NEAREST:
	    DPF(( 0, "\tTexture MAG\tGL_NEAREST_MIPMAP_NEAREST" ));
	    break;
       case GL_LINEAR_MIPMAP_NEAREST:
	    DPF(( 0, "\tTexture MAG\tGL_LINEAR_MIPMAP_NEAREST" ));
	    break;
       case GL_NEAREST_MIPMAP_LINEAR:
	    DPF(( 0, "\tTexture MAG\tGL_NEAREST_MIPMAP_LINEAR" ));
	    break;
       case GL_LINEAR_MIPMAP_LINEAR:
	    DPF(( 0, "\tTexture MAG\tGL_LINEAR_MIPMAP_LINEAR" ));
	    break;
	  }
	}

	if ( textMin != ctx->Texture.Set[ctx->Texture.CurrentSet].Current->MinFilter )
	{
	  textMin = ctx->Texture.Set[ctx->Texture.CurrentSet].Current->MinFilter;

	  switch( textMin )
	  {
       case GL_NEAREST:
	    DPF(( 0, "\tTexture MIN\tGL_NEAREST" ));
	    break;
       case GL_LINEAR:
	    DPF(( 0, "\tTexture MIN\tGL_LINEAR" ));
	    break;
       case GL_NEAREST_MIPMAP_NEAREST:
	    DPF(( 0, "\tTexture MIN\tGL_NEAREST_MIPMAP_NEAREST" ));
	    break;
       case GL_LINEAR_MIPMAP_NEAREST:
	    DPF(( 0, "\tTexture MIN\tGL_LINEAR_MIPMAP_NEAREST" ));
	    break;
       case GL_NEAREST_MIPMAP_LINEAR:
	    DPF(( 0, "\tTexture MIN\tGL_LINEAR_MIPMAP_LINEAR" ));
	    break;
       case GL_LINEAR_MIPMAP_LINEAR:
	    DPF(( 0, "\tTexture MIN\tGL_LINEAR_MIPMAP_LINEAR" ));
	    break;
	  }
	}	
   }

   if ( ctx->Polygon.FrontMode != polyMode )
   {
	polyMode = ctx->Polygon.FrontMode;

	switch( polyMode )
	{
       case GL_POINT:
	    DPF(( 0, "\tMode\t\tGL_POINT" ));
	    break;
       case GL_LINE:
	    DPF(( 0, "\tMode\t\tGL_LINE" ));
	    break;
       case GL_FILL:
	    DPF(( 0, "\tMode\t\tGL_FILL" ));
	    break;
	}
   }

   if ( depthFunc != ctx->Depth.Func )
   {
	depthFunc = ctx->Depth.Func;

	switch( depthFunc )
	{  
       case GL_NEVER:    
	    DPF(( 0, "\tDepth Func\tGL_NEVER" ));
	    break;
       case GL_LESS:     
	    DPF(( 0, "\tDepth Func\tGL_LESS" ));
	    break;
       case GL_GEQUAL:   
	    DPF(( 0, "\tDepth Func\tGL_GEQUAL" ));
	    break;
       case GL_LEQUAL:   
	    DPF(( 0, "\tDepth Func\tGL_LEQUAL" ));
	    break;
       case GL_GREATER:  
	    DPF(( 0, "\tDepth Func\tGL_GREATER" ));
	    break;
       case GL_NOTEQUAL: 
 	    DPF(( 0, "\tDepth Func\tGL_NOTEQUAL" ));
	    break;
       case GL_EQUAL:    
	    DPF(( 0, "\tDepth Func\tGL_EQUAL" ));
	    break;
       case GL_ALWAYS:   
	    DPF(( 0, "\tDepth Func\tGL_ALWAYS" ));
	    break;
	}
   }	

   if ( depthMask != ctx->Depth.Mask )
   {
	depthMask = ctx->Depth.Mask;
	DPF(( 0, "\tZWrite\t\t%s", (depthMask) ? "ENABLED" : "--------" ));
   }

   if ( alphaFunc != ctx->Color.AlphaFunc )
   {
	alphaFunc = ctx->Color.AlphaFunc;

	switch( alphaFunc )
     {  
	  case GL_NEVER:    
	    DPF(( 0, "\tAlpha Func\tGL_NEVER" ));
	    break;
	  case GL_LESS:     
	    DPF(( 0, "\tAlpha Func\tGL_LESS" ));
	    break;
  	  case GL_GEQUAL:   
	    DPF(( 0, "\tAlpha Func\tGL_GEQUAL" ));
	    break;
  	  case GL_LEQUAL:   
	    DPF(( 0, "\tAlpha Func\tGL_LEQUAL" ));
	    break;
	  case GL_GREATER:  
	    DPF(( 0, "\tAlpha Func\tGL_GREATER" ));
	    break;
	  case GL_NOTEQUAL: 
	    DPF(( 0, "\tAlpha Func\tGL_NOTEQUAL" ));
	    break;
	  case GL_EQUAL:    
	    DPF(( 0, "\tAlpha Func\tGL_EQUAL" ));
	    break;
	  case GL_ALWAYS:   
	    DPF(( 0, "\tAlpha Func\tGL_ALWAYS" ));
	    break;
	}
   }

   if ( blendSrc != ctx->Color.BlendSrc ) 
   {
	blendSrc = ctx->Color.BlendSrc;

	switch( blendSrc ) 
	{
	  case GL_ZERO:	    			
	    DPF(( 0, "\tSRC Blend\tGL_ZERO" ));
	    break;
       case GL_ONE:                     
	    DPF(( 0, "\tSRC Blend\tGL_ONE" ));
	    break;
       case GL_DST_COLOR:               
	    DPF(( 0, "\tSRC Blend\tGL_DST_COLOR" ));
	    break;
       case GL_ONE_MINUS_DST_COLOR:     
	    DPF(( 0, "\tSRC Blend\tGL_ONE_MINUS_DST_COLOR" ));
	    break;
       case GL_SRC_ALPHA:               
	    DPF(( 0, "\tSRC Blend\tGL_SRC_ALPHA" ));
	    break;
       case GL_ONE_MINUS_SRC_ALPHA:     
	    DPF(( 0, "\tSRC Blend\tGL_MINUS_SRC_ALPHA" ));
	    break;
       case GL_DST_ALPHA:               
	    DPF(( 0, "\tSRC Blend\tGL_DST_ALPHA" ));
	    break;
       case GL_ONE_MINUS_DST_ALPHA:     
	    DPF(( 0, "\tSRC Blend\tGL_ONE_MINUS_DST_ALPHA" ));
	    break;
       case GL_SRC_ALPHA_SATURATE:      
	    DPF(( 0, "\tSRC Blend\tGL_SRC_ALPHA_SATURATE" ));
	    break;
       case GL_CONSTANT_COLOR:          
	    DPF(( 0, "\tSRC Blend\tGL_CONSTANT_COLOR" ));
	    break;
       case GL_ONE_MINUS_CONSTANT_COLOR:
	    DPF(( 0, "\tSRC Blend\tGL_ONE_MINUS_CONSTANT_COLOR" ));
	    break;
       case GL_CONSTANT_ALPHA:          
	    DPF(( 0, "\tSRC Blend\tGL_CONSTANT_ALPHA" ));
	    break;
       case GL_ONE_MINUS_CONSTANT_ALPHA:
	    DPF(( 0, "\tSRC Blend\tGL_ONE_MINUS_CONSTANT_ALPHA" ));
	    break;
	}
   }

   if ( blendDest != ctx->Color.BlendDst ) 
   {
	blendDest = ctx->Color.BlendDst;

	switch( blendDest ) 
	{
       case GL_ZERO:                  	
	    DPF(( 0, "\tDST Blend\tGL_ZERO" ));
	    break;
       case GL_ONE:                     
	    DPF(( 0, "\tDST Blend\tGL_ONE" ));
	    break;
       case GL_SRC_COLOR:               
	    DPF(( 0, "\tDST Blend\tGL_SRC_COLOR" ));
	    break;
       case GL_ONE_MINUS_SRC_COLOR:     
	    DPF(( 0, "\tDST Blend\tGL_ONE_MINUS_SRC_COLOR" ));
	    break;
       case GL_SRC_ALPHA:               
	    DPF(( 0, "\tDST Blend\tGL_SRC_ALPHA" ));
	    break;
       case GL_ONE_MINUS_SRC_ALPHA:     
	    DPF(( 0, "\tDST Blend\tGL_ONE_MINUS_SRC_ALPHA" ));
	    break;
       case GL_DST_ALPHA:               
	    DPF(( 0, "\tDST Blend\tGL_DST_ALPHA" ));
	    break;
       case GL_ONE_MINUS_DST_ALPHA:     
	    DPF(( 0, "\tDST Blend\tGL_ONE_MINUS_DST_ALPHA" ));
	    break;
       case GL_CONSTANT_COLOR:          
	    DPF(( 0, "\tDST Blend\tGL_CONSTANT_COLOR" ));
	    break;
       case GL_ONE_MINUS_CONSTANT_COLOR:
	    DPF(( 0, "\tDST Blend\tGL_ONE_MINUS_CONSTANT_COLOR" ));
	    break;
       case GL_CONSTANT_ALPHA:          
	    DPF(( 0, "\tDST Blend\tGL_CONSTANT_ALPHA" ));
	    break;
       case GL_ONE_MINUS_CONSTANT_ALPHA:
	    DPF(( 0, "\tDST Blend\tGL_ONE_MINUS_CONSTANT_ALPHA" ));
	    break;
	}
   }	
}
