/*
 * Notes:
 * 1. These functions plug into the gl_renderbuffer structure.
 * 2. The 'values' parameter always points to GLuint values, regardless of
 *    the actual Z buffer depth.
 */


#include "spantmp_common.h"

#ifndef DBG
#define DBG 0
#endif

#ifndef HAVE_HW_DEPTH_SPANS
#define HAVE_HW_DEPTH_SPANS 0
#endif

#ifndef HAVE_HW_DEPTH_PIXELS
#define HAVE_HW_DEPTH_PIXELS 0
#endif

static void TAG(WriteDepthSpan)( struct gl_context *ctx,
                                 struct gl_renderbuffer *rb,
                                 GLuint n, GLint x, GLint y,
				 const void *values,
				 const GLubyte mask[] )
{
   HW_WRITE_LOCK()
      {
         const VALUE_TYPE *depth = (const VALUE_TYPE *) values;
	 GLint x1;
	 GLint n1;
	 LOCAL_DEPTH_VARS;

	 y = Y_FLIP( y );

#if HAVE_HW_DEPTH_SPANS
	 (void) x1; (void) n1;

	 if ( DBG ) fprintf( stderr, "WriteDepthSpan 0..%d (x1 %d)\n",
			     (int)n, (int)x );

	 WRITE_DEPTH_SPAN();
#else
	 HW_CLIPLOOP()
	    {
	       GLint i = 0;
	       CLIPSPAN( x, y, n, x1, n1, i );

	       if ( DBG ) fprintf( stderr, "WriteDepthSpan %d..%d (x1 %d) (mask %p)\n",
				   (int)i, (int)n1, (int)x1, mask );

	       if ( mask ) {
		  for ( ; n1>0 ; i++, x1++, n1-- ) {
		     if ( mask[i] ) WRITE_DEPTH( x1, y, depth[i] );
		  }
	       } else {
		  for ( ; n1>0 ; i++, x1++, n1-- ) {
		     WRITE_DEPTH( x1, y, depth[i] );
		  }
	       }
	    }
	 HW_ENDCLIPLOOP();
#endif
      }
   HW_WRITE_UNLOCK();

   (void) ctx;
}


static void TAG(WriteDepthPixels)( struct gl_context *ctx,
                                   struct gl_renderbuffer *rb,
				   GLuint n,
				   const GLint x[],
				   const GLint y[],
				   const void *values,
				   const GLubyte mask[] )
{
   HW_WRITE_LOCK()
      {
         const VALUE_TYPE *depth = (const VALUE_TYPE *) values;
	 GLuint i;
	 LOCAL_DEPTH_VARS;

	 if ( DBG ) fprintf( stderr, "WriteDepthPixels\n" );

#if HAVE_HW_DEPTH_PIXELS
	 (void) i;

	 WRITE_DEPTH_PIXELS();
#else
	 HW_CLIPLOOP()
	    {
	       if ( mask ) {
		  for ( i = 0 ; i < n ; i++ ) {
		     if ( mask[i] ) {
			const int fy = Y_FLIP( y[i] );
			if ( CLIPPIXEL( x[i], fy ) )
			   WRITE_DEPTH( x[i], fy, depth[i] );
		     }
		  }
	       }
	       else {
		  for ( i = 0 ; i < n ; i++ ) {
		     const int fy = Y_FLIP( y[i] );
		     if ( CLIPPIXEL( x[i], fy ) )
			WRITE_DEPTH( x[i], fy, depth[i] );
		  }
	       }
	    }
	 HW_ENDCLIPLOOP();
#endif
      }
   HW_WRITE_UNLOCK();

   (void) ctx;
}


/* Read depth spans and pixels
 */
static void TAG(ReadDepthSpan)( struct gl_context *ctx,
                                struct gl_renderbuffer *rb,
				GLuint n, GLint x, GLint y,
				void *values )
{
   HW_READ_LOCK()
      {
         VALUE_TYPE *depth = (VALUE_TYPE *) values;
	 GLint x1, n1;
	 LOCAL_DEPTH_VARS;

	 y = Y_FLIP( y );

	 if ( DBG ) fprintf( stderr, "ReadDepthSpan\n" );

#if HAVE_HW_DEPTH_SPANS
	 (void) x1; (void) n1;

	 READ_DEPTH_SPAN();
#else
	 HW_CLIPLOOP()
	    {
	       GLint i = 0;
	       CLIPSPAN( x, y, n, x1, n1, i );
	       for ( ; n1>0 ; i++, n1-- ) {
		  READ_DEPTH( depth[i], x+i, y );
	       }
	    }
	 HW_ENDCLIPLOOP();
#endif
      }
   HW_READ_UNLOCK();
}

static void TAG(ReadDepthPixels)( struct gl_context *ctx,
                                  struct gl_renderbuffer *rb,
                                  GLuint n,
				  const GLint x[], const GLint y[],
				  void *values )
{
   HW_READ_LOCK()
      {
         VALUE_TYPE *depth = (VALUE_TYPE *) values;
	 GLuint i;
	 LOCAL_DEPTH_VARS;

	 if ( DBG ) fprintf( stderr, "ReadDepthPixels\n" );

#if HAVE_HW_DEPTH_PIXELS
	 (void) i;

	 READ_DEPTH_PIXELS();
#else
	 HW_CLIPLOOP()
	    {
	       for ( i = 0 ; i < n ;i++ ) {
		  int fy = Y_FLIP( y[i] );
		  if ( CLIPPIXEL( x[i], fy ) )
		     READ_DEPTH( depth[i], x[i], fy );
	       }
	    }
	 HW_ENDCLIPLOOP();
#endif
      }
   HW_READ_UNLOCK();

   (void) ctx;
}


/**
 * Initialize the given renderbuffer's span routines to point to
 * the depth/z functions we generated above.
 */
static void TAG(InitDepthPointers)(struct gl_renderbuffer *rb)
{
   rb->GetRow = TAG(ReadDepthSpan);
   rb->GetValues = TAG(ReadDepthPixels);
   rb->PutRow = TAG(WriteDepthSpan);
   rb->PutValues = TAG(WriteDepthPixels);
}


#if HAVE_HW_DEPTH_SPANS
#undef WRITE_DEPTH_SPAN
#undef WRITE_DEPTH_PIXELS
#undef READ_DEPTH_SPAN
#undef READ_DEPTH_PIXELS
#else
#undef WRITE_DEPTH
#undef READ_DEPTH
#endif
#undef TAG
#undef VALUE_TYPE