/*
 * Author: Max Lingua <sunmax@libero.it>
 */

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

#include <sys/ioctl.h>

#include "s3v_context.h"
#include "s3v_vb.h"
#include "s3v_tris.h"

#include "main/glheader.h"
#include "main/mtypes.h"
#include "main/macros.h"
#include "main/colormac.h"

#include "swrast/swrast.h"
#include "swrast_setup/swrast_setup.h"
#include "tnl/tnl.h"
#include "tnl/t_context.h"
#include "tnl/t_pipeline.h"


/***********************************************************************
 *                   Build hardware rasterization functions            *
 ***********************************************************************/

#define DO_TRI			1
#define HAVE_RGBA		1
#define HAVE_SPEC		0
#define HAVE_BACK_COLORS	0
#define HAVE_HW_FLATSHADE	1
#define VERTEX			s3vVertex
#define TAB			rast_tab

#define VERT_SET_RGBA( v, c ) \
do { \
	UNCLAMPED_FLOAT_TO_RGBA_CHAN( v->ub4[4], c); \
/*	*(v->ub4[4]) = c; \ */ \
} while (0)
#define VERT_COPY_RGBA( v0, v1 ) v0->ui[4] = v1->ui[4]
/*
#define VERT_COPY_RGBA1( v0, v1 ) v0->ui[4] = v1->ui[4]
*/
#define VERT_SAVE_RGBA( idx )    color[idx] = v[idx]->ui[4]
#define VERT_RESTORE_RGBA( idx ) v[idx]->ui[4] = color[idx]

#define S3V_OFFSET_BIT  	0x01
#define S3V_TWOSIDE_BIT 	0x02
#define S3V_UNFILLED_BIT        0x04
#define S3V_FALLBACK_BIT        0x08
#define S3V_MAX_TRIFUNC 	0x10


static struct {
	tnl_points_func		points;
	tnl_line_func		line;
	tnl_triangle_func	triangle;
	tnl_quad_func		quad;
} rast_tab[S3V_MAX_TRIFUNC];

#define S3V_RAST_CULL_BIT	0x01
#define S3V_RAST_FLAT_BIT	0x02
#define S3V_RAST_TEX_BIT	0x04

static s3v_point_func s3v_point_tab[0x8];
static s3v_line_func s3v_line_tab[0x8];
static s3v_tri_func s3v_tri_tab[0x8];
static s3v_quad_func s3v_quad_tab[0x8];

#define IND (0)
#define TAG(x) x
#include "s3v_tritmp.h"

#define IND (S3V_RAST_CULL_BIT)
#define TAG(x) x##_cull
#include "s3v_tritmp.h"

#define IND (S3V_RAST_FLAT_BIT)
#define TAG(x) x##_flat
#include "s3v_tritmp.h"

#define IND (S3V_RAST_CULL_BIT|S3V_RAST_FLAT_BIT)
#define TAG(x) x##_cull_flat
#include "s3v_tritmp.h"

#define IND (S3V_RAST_TEX_BIT)
#define TAG(x) x##_tex
#include "s3v_tritmp.h"

#define IND (S3V_RAST_CULL_BIT|S3V_RAST_TEX_BIT)
#define TAG(x) x##_cull_tex
#include "s3v_tritmp.h"

#define IND (S3V_RAST_FLAT_BIT|S3V_RAST_TEX_BIT)
#define TAG(x) x##_flat_tex
#include "s3v_tritmp.h"

#define IND (S3V_RAST_CULL_BIT|S3V_RAST_FLAT_BIT|S3V_RAST_TEX_BIT)
#define TAG(x) x##_cull_flat_tex
#include "s3v_tritmp.h"

static void init_rast_tab( void )
{
	DEBUG(("*** init_rast_tab ***\n"));

	s3v_init();
	s3v_init_cull();
	s3v_init_flat();
	s3v_init_cull_flat();
	s3v_init_tex();
	s3v_init_cull_tex();
	s3v_init_flat_tex();
	s3v_init_cull_flat_tex();
}

/***********************************************************************
 *                    Rasterization fallback helpers                   *
 ***********************************************************************/


/* This code is hit only when a mix of accelerated and unaccelerated
 * primitives are being drawn, and only for the unaccelerated
 * primitives.  
 */

#if 0
static void 
s3v_fallback_quad( s3vContextPtr vmesa, 
		    const s3vVertex *v0, 
		    const s3vVertex *v1, 
		    const s3vVertex *v2, 
		    const s3vVertex *v3 )
{
   GLcontext *ctx = vmesa->glCtx;
   SWvertex v[4];
   s3v_translate_vertex( ctx, v0, &v[0] );
   s3v_translate_vertex( ctx, v1, &v[1] );
   s3v_translate_vertex( ctx, v2, &v[2] );
   s3v_translate_vertex( ctx, v3, &v[3] );
   DEBUG(("s3v_fallback_quad\n"));
/*   _swrast_Quad( ctx, &v[0], &v[1], &v[2], &v[3] ); */
}

static void 
s3v_fallback_tri( s3vContextPtr vmesa, 
		    const s3vVertex *v0, 
		    const s3vVertex *v1, 
		    const s3vVertex *v2 )
{
   GLcontext *ctx = vmesa->glCtx;
   SWvertex v[3];
   s3v_translate_vertex( ctx, v0, &v[0] );
   s3v_translate_vertex( ctx, v1, &v[1] );
   s3v_translate_vertex( ctx, v2, &v[2] );
   DEBUG(("s3v_fallback_tri\n"));
/*   _swrast_Triangle( ctx, &v[0], &v[1], &v[2] ); */
}

static void
s3v_fallback_line( s3vContextPtr vmesa,
		     const s3vVertex *v0,
		     const s3vVertex *v1 )
{
   GLcontext *ctx = vmesa->glCtx;
   SWvertex v[2];
   s3v_translate_vertex( ctx, v0, &v[0] );
   s3v_translate_vertex( ctx, v1, &v[1] );
   DEBUG(("s3v_fallback_line\n"));
   _swrast_Line( ctx, &v[0], &v[1] );
}

/*
static void 
s3v_fallback_point( s3vContextPtr vmesa, 
		      const s3vVertex *v0 )
{
   GLcontext *ctx = vmesa->glCtx;
   SWvertex v[1];
   s3v_translate_vertex( ctx, v0, &v[0] );
   _swrast_Point( ctx, &v[0] );
}
*/
#endif

/***********************************************************************
 *                    Choose rasterization functions                   *
 ***********************************************************************/

#define _S3V_NEW_RASTER_STATE 	(_NEW_FOG | \
				 _NEW_TEXTURE | \
				 _DD_NEW_TRI_SMOOTH | \
				 _DD_NEW_LINE_SMOOTH | \
				 _DD_NEW_POINT_SMOOTH | \
				 _DD_NEW_TRI_STIPPLE | \
				 _DD_NEW_LINE_STIPPLE)

#define LINE_FALLBACK (0)
#define TRI_FALLBACK (0)

static void s3v_nodraw_triangle(GLcontext *ctx, s3vVertex *v0,
                                s3vVertex *v1, s3vVertex *v2)
{
	(void) (ctx && v0 && v1 && v2);
}

static void s3v_nodraw_quad(GLcontext *ctx,
                            s3vVertex *v0, s3vVertex *v1,
                            s3vVertex *v2, s3vVertex *v3)
{
	(void) (ctx && v0 && v1 && v2 && v3);
}

void s3vChooseRasterState(GLcontext *ctx);

void s3vChooseRasterState(GLcontext *ctx)
{
	s3vContextPtr vmesa = S3V_CONTEXT(ctx);
	GLuint flags = ctx->_TriangleCaps;
	GLuint ind = 0;

	DEBUG(("*** s3vChooseRasterState ***\n"));

	if (ctx->Polygon.CullFlag) {
		if (ctx->Polygon.CullFaceMode == GL_FRONT_AND_BACK) {
			vmesa->draw_tri = (s3v_tri_func)s3v_nodraw_triangle;
			vmesa->draw_quad = (s3v_quad_func)s3v_nodraw_quad;
			return;
		}
		ind |= S3V_RAST_CULL_BIT;
		/* s3v_update_cullsign(ctx); */
	} /* else vmesa->backface_sign = 0; */

	if ( flags & DD_FLATSHADE )
		ind |= S3V_RAST_FLAT_BIT;

	if ( ctx->Texture.Unit[0]._ReallyEnabled ) {
		ind |= S3V_RAST_TEX_BIT;
	}

	DEBUG(("ind = %i\n", ind));

	vmesa->draw_line = s3v_line_tab[ind];
	vmesa->draw_tri = s3v_tri_tab[ind];
	vmesa->draw_quad = s3v_quad_tab[ind];
	vmesa->draw_point = s3v_point_tab[ind];

#if 0
	/* Hook in fallbacks for specific primitives.  CURRENTLY DISABLED
	 */
	
	if (flags & LINE_FALLBACK) 
		vmesa->draw_line = s3v_fallback_line;
	 
	if (flags & TRI_FALLBACK) {
		DEBUG(("TRI_FALLBACK\n"));
		vmesa->draw_tri = s3v_fallback_tri;
		vmesa->draw_quad = s3v_fallback_quad;
	}
#endif
}




/***********************************************************************
 *          Macros for t_dd_tritmp.h to draw basic primitives          *
 ***********************************************************************/

#define TRI( v0, v1, v2 ) \
do { \
	/*
	if (DO_FALLBACK) \
		vmesa->draw_tri( vmesa, v0, v1, v2 ); \
	else */ \
   	DEBUG(("TRI: max was here\n")); /* \
	s3v_draw_tex_triangle( vmesa, v0, v1, v2 ); */ \
	vmesa->draw_tri( vmesa, v0, v1, v2 ); \
} while (0)

#define QUAD( v0, v1, v2, v3 ) \
do { \
	DEBUG(("QUAD: max was here\n")); \
	vmesa->draw_quad( vmesa, v0, v1, v2, v3 ); \
} while (0)

#define LINE( v0, v1 ) \
do { \
	DEBUG(("LINE: max was here\n")); \
	vmesa->draw_line( vmesa, v0, v1 ); \
} while (0)

#define POINT( v0 ) \
do { \
	vmesa->draw_point( vmesa, v0 ); \
} while (0)


/***********************************************************************
 *              Build render functions from dd templates               *
 ***********************************************************************/

/*
#define S3V_OFFSET_BIT 	0x01
#define S3V_TWOSIDE_BIT	0x02
#define S3V_UNFILLED_BIT	0x04
#define S3V_FALLBACK_BIT	0x08
#define S3V_MAX_TRIFUNC	0x10


static struct {
   points_func		points;
   line_func		line;
   triangle_func	triangle;
   quad_func		quad;
} rast_tab[S3V_MAX_TRIFUNC];
*/

#define DO_FALLBACK  (IND & S3V_FALLBACK_BIT)
#define DO_OFFSET    (IND & S3V_OFFSET_BIT)
#define DO_UNFILLED  (IND & S3V_UNFILLED_BIT)
#define DO_TWOSIDE   (IND & S3V_TWOSIDE_BIT)
#define DO_FLAT      0
#define DO_TRI       1
#define DO_QUAD      1
#define DO_LINE      1
#define DO_POINTS    1
#define DO_FULL_QUAD 1

#define HAVE_RGBA         1
#define HAVE_SPEC         0
#define HAVE_BACK_COLORS  0
#define HAVE_HW_FLATSHADE 1
#define VERTEX            s3vVertex
#define TAB               rast_tab

#define DEPTH_SCALE 1.0
#define UNFILLED_TRI unfilled_tri
#define UNFILLED_QUAD unfilled_quad
#define VERT_X(_v) _v->v.x
#define VERT_Y(_v) _v->v.y
#define VERT_Z(_v) _v->v.z
#define AREA_IS_CCW( a ) (a > 0)
#define GET_VERTEX(e) (vmesa->verts + (e<<vmesa->vertex_stride_shift))

#if 0
#define VERT_SET_RGBA( v, c ) \
do { \
/*    UNCLAMPED_FLOAT_TO_RGBA_CHAN( v->ub4[4], c) */ \
} while (0)

#define VERT_COPY_RGBA( v0, v1 ) v0->ui[4] = v1->ui[4]
/*
#define VERT_COPY_RGBA1( v0, v1 ) v0->ui[4] = v1->ui[4]
*/
#define VERT_SAVE_RGBA( idx )    color[idx] = v[idx]->ui[4]
#define VERT_RESTORE_RGBA( idx ) v[idx]->ui[4] = color[idx]   
#endif

#define LOCAL_VARS(n) \
	s3vContextPtr vmesa = S3V_CONTEXT(ctx); \
	GLuint color[n]; \
	(void) color;


/***********************************************************************
 *                Helpers for rendering unfilled primitives            *
 ***********************************************************************/

static const GLuint hw_prim[GL_POLYGON+1] = {
	PrimType_Points,
	PrimType_Lines,
	PrimType_Lines,
	PrimType_Lines,
	PrimType_Triangles,
	PrimType_Triangles,
	PrimType_Triangles,
	PrimType_Triangles,
	PrimType_Triangles,
	PrimType_Triangles
};

static void s3vResetLineStipple( GLcontext *ctx );
static void s3vRasterPrimitive( GLcontext *ctx, GLuint hwprim );
static void s3vRenderPrimitive( GLcontext *ctx, GLenum prim );
/*
extern static void s3v_lines_emit(GLcontext *ctx, GLuint start, GLuint end);
extern static void s3v_tris_emit(GLcontext *ctx, GLuint start, GLuint end);
*/
#define RASTERIZE(x) if (vmesa->hw_primitive != hw_prim[x]) \
                        s3vRasterPrimitive( ctx, hw_prim[x] )
#define RENDER_PRIMITIVE vmesa->render_primitive
#define TAG(x) x
#define IND S3V_FALLBACK_BIT
#include "tnl_dd/t_dd_unfilled.h"
#undef IND

/***********************************************************************
 *                      Generate GL render functions                   *
 ***********************************************************************/

#define IND (0)
#define TAG(x) x
#include "tnl_dd/t_dd_tritmp.h"

#define IND (S3V_OFFSET_BIT)
#define TAG(x) x##_offset
#include "tnl_dd/t_dd_tritmp.h"

#define IND (S3V_TWOSIDE_BIT)
#define TAG(x) x##_twoside
#include "tnl_dd/t_dd_tritmp.h"

#define IND (S3V_TWOSIDE_BIT|S3V_OFFSET_BIT)
#define TAG(x) x##_twoside_offset
#include "tnl_dd/t_dd_tritmp.h"

#define IND (S3V_UNFILLED_BIT)
#define TAG(x) x##_unfilled
#include "tnl_dd/t_dd_tritmp.h"

#define IND (S3V_OFFSET_BIT|S3V_UNFILLED_BIT)
#define TAG(x) x##_offset_unfilled
#include "tnl_dd/t_dd_tritmp.h"

#define IND (S3V_TWOSIDE_BIT|S3V_UNFILLED_BIT)
#define TAG(x) x##_twoside_unfilled
#include "tnl_dd/t_dd_tritmp.h"

#define IND (S3V_TWOSIDE_BIT|S3V_OFFSET_BIT|S3V_UNFILLED_BIT)
#define TAG(x) x##_twoside_offset_unfilled
#include "tnl_dd/t_dd_tritmp.h"


static void init_render_tab( void )
{
	DEBUG(("*** init_render_tab ***\n"));

	init();
	init_offset();
	init_twoside();
	init_twoside_offset();
	init_unfilled();
	init_offset_unfilled();
	init_twoside_unfilled();
	init_twoside_offset_unfilled();
}


/**********************************************************************/
/*               Render unclipped begin/end objects                   */
/**********************************************************************/

#define VERT(x) (s3vVertex *)(s3vverts + (x << shift))

#define RENDER_POINTS( start, count ) \
	DEBUG(("RENDER_POINTS...(ok)\n")); \
	for ( ; start < count ; start++) \
		vmesa->draw_line( vmesa, VERT(start), VERT(start) )
	/*      vmesa->draw_point( vmesa, VERT(start) ) */

#define RENDER_LINE( v0, v1 ) \
	/* DEBUG(("RENDER_LINE...(ok)\n")); \ */ \
	vmesa->draw_line( vmesa, VERT(v0), VERT(v1) ); \
	DEBUG(("RENDER_LINE...(ok)\n"))

#define RENDER_TRI( v0, v1, v2 )  \
	DEBUG(("RENDER_TRI...(ok)\n")); \
	vmesa->draw_tri( vmesa, VERT(v0), VERT(v1), VERT(v2) )

#define RENDER_QUAD( v0, v1, v2, v3 ) \
	DEBUG(("RENDER_QUAD...(ok)\n")); \
	/* s3v_draw_quad( vmesa, VERT(v0), VERT(v1), VERT(v2),VERT(v3) ) */\
	/* s3v_draw_triangle( vmesa, VERT(v0), VERT(v1), VERT(v2) ); \
	s3v_draw_triangle( vmesa, VERT(v0), VERT(v2), VERT(v3) ) */ \
	vmesa->draw_quad( vmesa, VERT(v0), VERT(v1), VERT(v2), VERT(v3) ) 
	
#define INIT(x) s3vRenderPrimitive( ctx, x );
#undef LOCAL_VARS
#define LOCAL_VARS						\
   s3vContextPtr vmesa = S3V_CONTEXT(ctx);		\
   const GLuint shift = vmesa->vertex_stride_shift;		\
   const char *s3vverts = (char *)vmesa->verts;		\
   const GLboolean stipple = ctx->Line.StippleFlag;		\
   (void) stipple;
#define RESET_STIPPLE	if ( stipple ) s3vResetLineStipple( ctx );
#define RESET_OCCLUSION
#define PRESERVE_VB_DEFS
#define ELT(x) (x)
#define TAG(x) s3v_##x##_verts
#include "tnl_dd/t_dd_rendertmp.h"


/**********************************************************************/
/*                   Render clipped primitives                        */
/**********************************************************************/

static void s3vRenderClippedPoly( GLcontext *ctx, const GLuint *elts, 
				   GLuint n )
{
	s3vContextPtr vmesa = S3V_CONTEXT(ctx);
	struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
	TNLcontext *tnl = TNL_CONTEXT(ctx);
	GLuint prim = vmesa->render_primitive;

	DEBUG(("I AM in: s3vRenderClippedPoly\n"));

	/* Render the new vertices as an unclipped polygon. 
	 */
	if (1)
	{
	GLuint *tmp = VB->Elts;
	VB->Elts = (GLuint *)elts;
	tnl->Driver.Render.PrimTabElts[GL_POLYGON]
		( ctx, 0, n, PRIM_BEGIN|PRIM_END );

	VB->Elts = tmp;
	}

	/* Restore the render primitive
	 */
#if 1
	if (prim != GL_POLYGON) {
		DEBUG(("and prim != GL_POLYGON\n"));
		tnl->Driver.Render.PrimitiveNotify( ctx, prim );
	}
	
#endif
}

static void s3vRenderClippedLine( GLcontext *ctx, GLuint ii, GLuint jj )
{
   TNLcontext *tnl = TNL_CONTEXT(ctx);
   /*tnl->Driver.LineFunc = s3v_line_tab[2];*/ /* _swsetup_Line; */

   DEBUG(("I AM in: s3vRenderClippedLine\n"));
   tnl->Driver.Render.Line( ctx, ii, jj );
}


/**********************************************************************/
/*                    Choose render functions                         */
/**********************************************************************/



#define _S3V_NEW_RENDERSTATE (_DD_NEW_TRI_UNFILLED |		\
			       _DD_NEW_TRI_LIGHT_TWOSIDE |	\
			       _DD_NEW_TRI_OFFSET)

#define ANY_RASTER_FLAGS (DD_TRI_LIGHT_TWOSIDE|DD_TRI_OFFSET|DD_TRI_UNFILLED)

static void s3vChooseRenderState(GLcontext *ctx)
{
   s3vContextPtr vmesa = S3V_CONTEXT(ctx);
   TNLcontext *tnl = TNL_CONTEXT(ctx);
   GLuint flags = ctx->_TriangleCaps;
   GLuint index = 0;

   DEBUG(("s3vChooseRenderState\n"));

   if (flags & ANY_RASTER_FLAGS) {
      if (flags & DD_TRI_LIGHT_TWOSIDE)       index |= S3V_TWOSIDE_BIT;
      if (flags & DD_TRI_OFFSET)	      index |= S3V_OFFSET_BIT;
      if (flags & DD_TRI_UNFILLED)	      index |= S3V_UNFILLED_BIT;
   }

   DEBUG(("vmesa->RenderIndex = %i\n", vmesa->RenderIndex));
   DEBUG(("index = %i\n", index));

   if (vmesa->RenderIndex != index) {
      vmesa->RenderIndex = index;

      tnl->Driver.Render.Points = rast_tab[index].points;
      tnl->Driver.Render.Line = rast_tab[index].line;
      tnl->Driver.Render.Triangle = rast_tab[index].triangle;
      tnl->Driver.Render.Quad = rast_tab[index].quad;

      if (vmesa->RenderIndex == 0)
         tnl->Driver.Render.PrimTabVerts = s3v_render_tab_verts;
      else
         tnl->Driver.Render.PrimTabVerts = _tnl_render_tab_verts;
      tnl->Driver.Render.PrimTabElts = _tnl_render_tab_elts;
      tnl->Driver.Render.ClippedLine = s3vRenderClippedLine;
      tnl->Driver.Render.ClippedPolygon = s3vRenderClippedPoly;
   }
}


/**********************************************************************/
/*                 High level hooks for t_vb_render.c                 */
/**********************************************************************/



/* Determine the rasterized primitive when not drawing unfilled 
 * polygons.
 *
 * Used only for the default render stage which always decomposes
 * primitives to trianges/lines/points.  For the accelerated stage,
 * which renders strips as strips, the equivalent calculations are
 * performed in s3v_render.c.
 */

static void s3vRasterPrimitive( GLcontext *ctx, GLuint hwprim )
{
	s3vContextPtr vmesa = S3V_CONTEXT(ctx);
/*	__DRIdrawablePrivate *dPriv = vmesa->driDrawable; */
	GLuint cmd = vmesa->CMD;
	
	unsigned int _hw_prim = hwprim;

	DEBUG(("s3vRasterPrimitive: hwprim = 0x%x ", _hw_prim));

/*	printf("* vmesa->CMD = 0x%x\n", vmesa->CMD); */

	if (vmesa->hw_primitive != _hw_prim)
	{
		DEBUG(("(new one) ***\n"));
		cmd &= ~DO_MASK;
		cmd &= ~ALPHA_BLEND_MASK;
		vmesa->hw_primitive = _hw_prim;

		if (_hw_prim == PrimType_Triangles) {
		/* TRI */
	                DEBUG(("->switching to tri\n"));
			cmd |= (vmesa->_tri[vmesa->_3d_mode] | vmesa->_alpha[vmesa->_3d_mode]);
	        } else if (_hw_prim == PrimType_Lines
			|| _hw_prim == PrimType_Points) {
		/* LINE */
        	        DEBUG(("->switching to line\n"));
			cmd |= (DO_3D_LINE | vmesa->_alpha[0]);
		} else  {
		/* ugh? */
			DEBUG(("->switching to your sis'ass\n"));
		}
        
		DEBUG(("\n"));

		vmesa->restore_primitive = _hw_prim;
		/* 0xacc16827: good value -> lightened newave!!! */
		vmesa->CMD = cmd;
		CMDCHANGE();
	}
}

static void s3vRenderPrimitive( GLcontext *ctx, GLenum prim )
{
	s3vContextPtr vmesa = S3V_CONTEXT(ctx);
	__DRIdrawablePrivate *dPriv = vmesa->driDrawable;
	GLuint cmd = vmesa->CMD;

	unsigned int _hw_prim = hw_prim[prim];

	vmesa->render_primitive = prim;
	vmesa->hw_primitive = _hw_prim;
   
	DEBUG(("s3vRenderPrimitive #%i ", prim));
	DEBUG(("_hw_prim = 0x%x\n", _hw_prim));

/*	printf(" vmesa->CMD = 0x%x\n", vmesa->CMD); */

	if (_hw_prim != vmesa->restore_primitive) {
		DEBUG(("_hw_prim != vmesa->restore_primitive (was 0x%x)\n",
			vmesa->restore_primitive));
#if 1
		cmd &= ~DO_MASK;
		cmd &= ~ALPHA_BLEND_MASK;
/*		
		printf(" cmd = 0x%x\n", cmd);
		printf(" vmesa->_3d_mode=%i; vmesa->_tri[vmesa->_3d_mode]=0x%x\n",
			vmesa->_3d_mode, vmesa->_tri[vmesa->_3d_mode]);
		printf("vmesa->alpha[0] = 0x%x; vmesa->alpha[1] = 0x%x\n",
			vmesa->_alpha[0], vmesa->_alpha[1]);
*/		
	   	if (_hw_prim == PrimType_Triangles) { /* TRI */
			DEBUG(("->switching to tri\n"));
   			cmd |= (vmesa->_tri[vmesa->_3d_mode] | vmesa->_alpha[vmesa->_3d_mode]);
			DEBUG(("vmesa->TexStride = %i\n", vmesa->TexStride));
			DEBUG(("vmesa->TexOffset = %i\n", vmesa->TexOffset));
			DMAOUT_CHECK(3DTRI_Z_BASE, 12);
		} else { /* LINE */
			DEBUG(("->switching to line\n"));
			cmd |= (DO_3D_LINE | vmesa->_alpha[0]);
			DMAOUT_CHECK(3DLINE_Z_BASE, 12);
		}

		DMAOUT(vmesa->s3vScreen->depthOffset & 0x003FFFF8);
		DMAOUT(vmesa->DestBase);
		/* DMAOUT(vmesa->ScissorLR); */
		/* DMAOUT(vmesa->ScissorTB); */

		/* NOTE: we need to restore all these values since we
		 * are coming back from a vmesa->restore_primitive */
		DMAOUT( (0 << 16) | (dPriv->w-1) );
		DMAOUT( (0 << 16) | (dPriv->h-1) );
		DMAOUT( (vmesa->SrcStride << 16) | vmesa->TexStride );
		DMAOUT(vmesa->SrcStride);
		DMAOUT(vmesa->TexOffset);
		DMAOUT(vmesa->TextureBorderColor);
		DMAOUT(0); /* FOG */
		DMAOUT(0);
		DMAOUT(0);
	        DMAOUT(cmd);
		/* 0xacc16827: good value -> lightened newave!!! */
        DMAFINISH();

	vmesa->CMD = cmd;
#endif
	}

	DEBUG(("\n"));

	vmesa->restore_primitive = _hw_prim;
}

static void s3vRunPipeline( GLcontext *ctx )
{
	s3vContextPtr vmesa = S3V_CONTEXT(ctx);

	DEBUG(("*** s3vRunPipeline ***\n"));

	if ( vmesa->new_state )
		s3vDDUpdateHWState( ctx );

	if (vmesa->new_gl_state) {

		if (vmesa->new_gl_state & _NEW_TEXTURE) {
			s3vUpdateTextureState( ctx );
		}

		if (!vmesa->Fallback) {
			if (vmesa->new_gl_state & _S3V_NEW_VERTEX)
				s3vChooseVertexState( ctx );
      
			if (vmesa->new_gl_state & _S3V_NEW_RASTER_STATE)
				s3vChooseRasterState( ctx );
      
			if (vmesa->new_gl_state & _S3V_NEW_RENDERSTATE)
				s3vChooseRenderState( ctx );
		}

	vmesa->new_gl_state = 0;
	
	}

	_tnl_run_pipeline( ctx );
}

static void s3vRenderStart( GLcontext *ctx )
{
	/* Check for projective texturing.  Make sure all texcoord
	 * pointers point to something.  (fix in mesa?)  
	 */

	DEBUG(("s3vRenderStart\n"));
	/* s3vCheckTexSizes( ctx ); */
}

static void s3vRenderFinish( GLcontext *ctx )
{
   if (0)
      _swrast_flush( ctx );	/* never needed */
}

static void s3vResetLineStipple( GLcontext *ctx )
{
/*   s3vContextPtr vmesa = S3V_CONTEXT(ctx); */

   /* Reset the hardware stipple counter.
    */
/*
   CHECK_DMA_BUFFER(vmesa, 1);
   WRITE(vmesa->buf, UpdateLineStippleCounters, 0);
*/
}


/**********************************************************************/
/*           Transition to/from hardware rasterization.               */
/**********************************************************************/


void s3vFallback( s3vContextPtr vmesa, GLuint bit, GLboolean mode )
{
   GLcontext *ctx = vmesa->glCtx;
   TNLcontext *tnl = TNL_CONTEXT(ctx);
   GLuint oldfallback = vmesa->Fallback;

   DEBUG(("*** s3vFallback: "));

   if (mode) {
      vmesa->Fallback |= bit;
      if (oldfallback == 0) {
		 DEBUG(("oldfallback == 0 ***\n"));
		 _swsetup_Wakeup( ctx );
		 _tnl_need_projected_coords( ctx, GL_TRUE );
		 vmesa->RenderIndex = ~0;
      }
   }
   else {
      DEBUG(("***\n"));
      vmesa->Fallback &= ~bit;
      if (oldfallback == bit) {
	 	_swrast_flush( ctx );
	 	tnl->Driver.Render.Start = s3vRenderStart;
	 	tnl->Driver.Render.PrimitiveNotify = s3vRenderPrimitive;
	 	tnl->Driver.Render.Finish = s3vRenderFinish;
	 	tnl->Driver.Render.BuildVertices = s3vBuildVertices;
   		tnl->Driver.Render.ResetLineStipple = s3vResetLineStipple;
	 	vmesa->new_gl_state |= (_S3V_NEW_RENDERSTATE|
					_S3V_NEW_RASTER_STATE|
					_S3V_NEW_VERTEX);
      }
   }
}


/**********************************************************************/
/*                            Initialization.                         */
/**********************************************************************/


void s3vInitTriFuncs( GLcontext *ctx )
{
   s3vContextPtr vmesa = S3V_CONTEXT(ctx);
   TNLcontext *tnl = TNL_CONTEXT(ctx);
   static int firsttime = 1;

   if (firsttime) {
      init_rast_tab();
      init_render_tab();
      firsttime = 0;
   }
   
   vmesa->RenderIndex = ~0;

   tnl->Driver.RunPipeline = s3vRunPipeline;
   tnl->Driver.Render.Start = s3vRenderStart;
   tnl->Driver.Render.Finish = s3vRenderFinish; 
   tnl->Driver.Render.PrimitiveNotify = s3vRenderPrimitive;
   tnl->Driver.Render.ResetLineStipple = s3vResetLineStipple;
/*
   tnl->Driver.RenderInterp = _swsetup_RenderInterp;
   tnl->Driver.RenderCopyPV = _swsetup_RenderCopyPV;
*/
   tnl->Driver.Render.BuildVertices = s3vBuildVertices;
}
