
#include "util/u_memory.h"
#include "pipe/p_defines.h"
#include "brw_context.h"
#include "brw_defines.h"
#include "brw_pipe_rast.h"
#include "brw_wm.h"


static unsigned translate_fill( unsigned fill )
{
   switch (fill) {
   case PIPE_POLYGON_MODE_FILL:
      return CLIP_FILL;
   case PIPE_POLYGON_MODE_LINE:
      return CLIP_LINE;
   case PIPE_POLYGON_MODE_POINT:
      return CLIP_POINT;
   default:
      assert(0);
      return CLIP_FILL;
   }
}


/* Calculates the key for triangle-mode clipping.  Non-triangle
 * clipping keys use much less information and are computed on the
 * fly.
 */
static void
calculate_clip_key_rast( const struct brw_context *brw,
			 const struct pipe_rasterizer_state *templ,
			 const struct brw_rasterizer_state *rast,
			 struct brw_clip_prog_key *key)
{
   memset(key, 0, sizeof *key);

   if (brw->gen == 5)
       key->clip_mode = BRW_CLIPMODE_KERNEL_CLIP;
   else
       key->clip_mode = BRW_CLIPMODE_NORMAL;

   key->do_flat_shading = templ->flatshade;

   if (templ->cull_face == PIPE_FACE_FRONT_AND_BACK) {
      key->clip_mode = BRW_CLIPMODE_REJECT_ALL;
      return;
   }

   key->fill_ccw = CLIP_CULL;
   key->fill_cw = CLIP_CULL;

   if (!(templ->cull_face & PIPE_FACE_FRONT)) {
      if (templ->front_ccw)
         key->fill_ccw = translate_fill(templ->fill_front);
      else 
         key->fill_cw = translate_fill(templ->fill_front);
   }

   if (!(templ->cull_face & PIPE_FACE_BACK)) {
      if (templ->front_ccw)
         key->fill_cw = translate_fill(templ->fill_back);
      else 
         key->fill_ccw = translate_fill(templ->fill_back);
   }

   if (key->fill_cw == CLIP_LINE ||
       key->fill_ccw == CLIP_LINE ||
       key->fill_cw == CLIP_POINT ||
       key->fill_ccw == CLIP_POINT) {
      key->do_unfilled = 1;
      key->clip_mode = BRW_CLIPMODE_CLIP_NON_REJECTED;
   }

   switch (key->fill_cw) {
   case CLIP_POINT:
      key->offset_cw = templ->offset_point;
      break;
   case CLIP_LINE:
      key->offset_cw = templ->offset_line;
      break;
   case CLIP_FILL:
      key->offset_cw = templ->offset_tri;
      break;
   }

   switch (key->fill_ccw) {
   case CLIP_POINT:
      key->offset_ccw = templ->offset_point;
      break;
   case CLIP_LINE:
      key->offset_ccw = templ->offset_line;
      break;
   case CLIP_FILL:
      key->offset_ccw = templ->offset_tri;
      break;
   }

   if (templ->light_twoside && key->fill_cw != CLIP_CULL) 
      key->copy_bfc_cw = 1;
   
   if (templ->light_twoside && key->fill_ccw != CLIP_CULL) 
      key->copy_bfc_ccw = 1;
}


static void
calculate_line_stipple_rast( const struct pipe_rasterizer_state *templ,
			     struct brw_line_stipple *bls )
{
   GLfloat tmp = 1.0f / (templ->line_stipple_factor + 1);
   GLint tmpi = tmp * (1<<13);

   bls->header.opcode = CMD_LINE_STIPPLE_PATTERN;
   bls->header.length = sizeof(*bls)/4 - 2;
   bls->bits0.pattern = templ->line_stipple_pattern;
   bls->bits1.repeat_count = templ->line_stipple_factor + 1;
   bls->bits1.inverse_repeat_count = tmpi;
}

static void *brw_create_rasterizer_state( struct pipe_context *pipe,
					  const struct pipe_rasterizer_state *templ )
{
   struct brw_context *brw = brw_context(pipe);
   struct brw_rasterizer_state *rast;

   rast = CALLOC_STRUCT(brw_rasterizer_state);
   if (rast == NULL)
      return NULL;

   rast->templ = *templ;

   calculate_clip_key_rast( brw, templ, rast, &rast->clip_key );
   
   if (templ->line_stipple_enable)
      calculate_line_stipple_rast( templ, &rast->bls );

   /* Caclculate lookup value for WM IZ table.
    */
   if (templ->line_smooth) {
      if (templ->fill_front == PIPE_POLYGON_MODE_LINE &&
	  templ->fill_back == PIPE_POLYGON_MODE_LINE) {
	 rast->unfilled_aa_line = AA_ALWAYS;
      }
      else if (templ->fill_front == PIPE_POLYGON_MODE_LINE ||
	       templ->fill_back == PIPE_POLYGON_MODE_LINE) {
	 rast->unfilled_aa_line = AA_SOMETIMES;
      }
      else {
	 rast->unfilled_aa_line = AA_NEVER;
      }
   }
   else {
      rast->unfilled_aa_line = AA_NEVER;
   }

   return (void *)rast;
}


static void brw_bind_rasterizer_state(struct pipe_context *pipe,
				 void *cso)
{
   struct brw_context *brw = brw_context(pipe);
   brw->curr.rast = (const struct brw_rasterizer_state *)cso;
   brw->state.dirty.mesa |= PIPE_NEW_RAST;
}

static void brw_delete_rasterizer_state(struct pipe_context *pipe,
				  void *cso)
{
   struct brw_context *brw = brw_context(pipe);
   assert((const void *)cso != (const void *)brw->curr.rast);
   FREE(cso);
}



void brw_pipe_rast_init( struct brw_context *brw )
{
   brw->base.create_rasterizer_state = brw_create_rasterizer_state;
   brw->base.bind_rasterizer_state = brw_bind_rasterizer_state;
   brw->base.delete_rasterizer_state = brw_delete_rasterizer_state;
}

void brw_pipe_rast_cleanup( struct brw_context *brw )
{
}
