/* Copyright (c) 2001, Stanford University
 * All rights reserved
 *
 * See the file LICENSE.txt for information on redistributing this software.
 */

#include "packer.h"
#include "cr_pixeldata.h"
#include "cr_error.h"
#include "cr_mem.h"
#include "cr_version.h"


void PACK_APIENTRY crPackDrawPixels( GLsizei width, GLsizei height, 
																		 GLenum format, GLenum type,
																		 const GLvoid *pixels,
																		 const CRPixelPackState *unpackstate )
{
	unsigned char *data_ptr;
	int packet_length;

	if (pixels == NULL)
	{
		return;
	}

#if 0
	/* WHAT IS THIS FOR?  Disabled by Brian on 3 Dec 2003 */
	if (type == GL_BITMAP)
	{
		crPackBitmap( width, height, 0, 0, 0, 0,
									(const GLubyte *) pixels, unpackstate );
	}
#endif

	packet_length = 
		sizeof( width ) +
		sizeof( height ) +
		sizeof( format ) +
		sizeof( type );

	packet_length += crImageSize( format, type, width, height );

	data_ptr = (unsigned char *) crPackAlloc( packet_length );
	WRITE_DATA( 0, GLsizei, width );
	WRITE_DATA( 4, GLsizei, height );
	WRITE_DATA( 8, GLenum, format );
	WRITE_DATA( 12, GLenum, type );

	crPixelCopy2D( width, height,
								 (void *) (data_ptr + 16), format, type, NULL, /* dst */
								 pixels, format, type, unpackstate );  /* src */

	crHugePacket( CR_DRAWPIXELS_OPCODE, data_ptr );
    crPackFree( data_ptr );
}

void PACK_APIENTRY crPackReadPixels( GLint x, GLint y, GLsizei width, 
																		 GLsizei height, GLenum format,
																		 GLenum type, GLvoid *pixels,
																		 const CRPixelPackState *packstate,
																		 int *writeback)
{
	GET_PACKER_CONTEXT(pc);
	unsigned char *data_ptr;
	GLint stride = 0;
	GLint bytes_per_row;
	int bytes_per_pixel;
	(void)writeback;

	bytes_per_pixel = crPixelSize(format, type);
	if (bytes_per_pixel <= 0) {
		char string[80];
		sprintf(string, "crPackReadPixels(format 0x%x or type 0x%x)", format, type);
		__PackError(__LINE__, __FILE__, GL_INVALID_ENUM, string);
		return;
	}

	/* default bytes_per_row so gl stub can allocate memory */
	bytes_per_row = width * bytes_per_pixel;

	stride = bytes_per_row;
	if (packstate->alignment != 1) {
		 GLint remainder = bytes_per_row % packstate->alignment;
		 if (remainder)
				stride = bytes_per_row + (packstate->alignment - remainder);
	}

	GET_BUFFERED_POINTER(pc, 48 + sizeof(CRNetworkPointer) );
	WRITE_DATA( 0,  GLint,  x );
	WRITE_DATA( 4,  GLint,  y );
	WRITE_DATA( 8,  GLsizei,  width );
	WRITE_DATA( 12, GLsizei,  height );
	WRITE_DATA( 16, GLenum, format );
	WRITE_DATA( 20, GLenum, type );
	WRITE_DATA( 24, GLint,  stride ); /* XXX not really used! */
	WRITE_DATA( 28, GLint, packstate->alignment );
	WRITE_DATA( 32, GLint, packstate->skipRows );
	WRITE_DATA( 36, GLint, packstate->skipPixels );
	WRITE_DATA( 40, GLint, bytes_per_row );
	WRITE_DATA( 44, GLint, packstate->rowLength );
	WRITE_NETWORK_POINTER( 48, (char *) pixels );
	WRITE_OPCODE( pc, CR_READPIXELS_OPCODE );
}

/* Round N up to the next multiple of 8 */
#define CEIL8(N)  (((N) + 7) & ~0x7)

void PACK_APIENTRY crPackBitmap( GLsizei width, GLsizei height, 
		GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove,
		const GLubyte *bitmap, const CRPixelPackState *unpack )
{
	const int isnull = (bitmap == NULL);
	unsigned char *data_ptr;
	int data_length = 0;
	GLubyte *destBitmap = NULL;
	int packet_length = 
		sizeof( width ) + 
		sizeof( height ) +
		sizeof( xorig ) + 
		sizeof( yorig ) + 
		sizeof( xmove ) + 
		sizeof( ymove ) +
		sizeof( GLuint );

	if ( bitmap )
	{
		data_length = CEIL8(width) * height / 8;
		packet_length += data_length;

		data_ptr = (unsigned char *) crPackAlloc( packet_length );
		destBitmap = data_ptr + 28;

		crBitmapCopy(width, height, destBitmap, bitmap, unpack);
		/*
		crMemcpy(destBitmap, bitmap, data_length);
		*/
	}
	else {
		data_ptr = (unsigned char *) crPackAlloc( packet_length );
	}

	WRITE_DATA( 0, GLsizei, width );
	WRITE_DATA( 4, GLsizei, height );
	WRITE_DATA( 8, GLfloat, xorig );
	WRITE_DATA( 12, GLfloat, yorig );
	WRITE_DATA( 16, GLfloat, xmove );
	WRITE_DATA( 20, GLfloat, ymove );
	WRITE_DATA( 24, GLuint, isnull );

	crHugePacket( CR_BITMAP_OPCODE, data_ptr );
    crPackFree( data_ptr );
}
/*
       ZPix - compressed DrawPixels
*/
void PACK_APIENTRY crPackZPixCR( GLsizei width, GLsizei height, 
        GLenum format, GLenum type,
        GLenum ztype, GLint zparm, GLint length,
        const GLvoid *pixels,
        const CRPixelPackState *unpackstate )
{
	unsigned char *data_ptr;
	int packet_length;
	(void)unpackstate;

	if (pixels == NULL)
	{
		return;
	}

	packet_length = 
		sizeof( int ) +  /* packet size */
		sizeof( GLenum ) +  /* extended opcode */
		sizeof( width ) +
		sizeof( height ) +
		sizeof( format ) +
		sizeof( type ) +
		sizeof( ztype ) +
		sizeof( zparm ) +
		sizeof( length );

	packet_length += length;

/* XXX JAG
  crDebug("PackZPixCR: fb %d x %d, state %d, zlen = %d, plen = %d",
                               width, height, ztype, length, packet_length);
*/
	data_ptr = (unsigned char *) crPackAlloc( packet_length );
	WRITE_DATA(  0, GLenum , CR_ZPIXCR_EXTEND_OPCODE );
	WRITE_DATA(  4, GLsizei, width );
	WRITE_DATA(  8, GLsizei, height );
	WRITE_DATA( 12, GLenum,  format );
	WRITE_DATA( 16, GLenum,  type );
	WRITE_DATA( 20, GLenum,  ztype );
	WRITE_DATA( 24, GLint,   zparm );
	WRITE_DATA( 28, GLint,   length );

	crMemcpy((void *) (data_ptr+32), pixels, length);

	crHugePacket( CR_EXTEND_OPCODE, data_ptr );
    crPackFree( data_ptr );
}


void PACK_APIENTRY
crPackGetTexImage( GLenum target, GLint level, GLenum format, GLenum type,
									 GLvoid * pixels, const CRPixelPackState * packstate,
									 int * writeback )
{
	GET_PACKER_CONTEXT(pc);
	unsigned char *data_ptr;
	(void) pc;
	GET_BUFFERED_POINTER( pc, 40 );
	WRITE_DATA( 0, GLint, 40 );
	WRITE_DATA( 4, GLenum, CR_GETTEXIMAGE_EXTEND_OPCODE );
	WRITE_DATA( 8, GLenum, target );
	WRITE_DATA( 12, GLint, level );
	WRITE_DATA( 16, GLenum, format );
	WRITE_DATA( 20, GLenum, type );
	WRITE_NETWORK_POINTER( 24, (void *) pixels );
	WRITE_NETWORK_POINTER( 32, (void *) writeback );
	WRITE_OPCODE( pc, CR_EXTEND_OPCODE );
}
