/* 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, imagesize;
    int noimagedata = (pixels == NULL) || crStateIsBufferBound(GL_PIXEL_UNPACK_BUFFER_ARB);

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

    if (!noimagedata)
    {
        imagesize = crImageSize( format, type, width, height );

        if (imagesize<=0)
        {
            crDebug("crPackDrawPixels: 0 image size, ignoring");
            return;
        }
        packet_length += imagesize;
    }

    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 );
    WRITE_DATA( 16, GLint, noimagedata );
    WRITE_DATA( 20, GLint, (GLint) (uintptr_t) pixels );

    if (!noimagedata)
    {
        crPixelCopy2D(width, height,
                      (void *) (data_ptr + 24), 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)
{
    CR_GET_PACKER_CONTEXT(pc);
    unsigned char *data_ptr;
    GLint stride = 0;
    GLint bytes_per_row;
    int bytes_per_pixel;
    *writeback = 0;

    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 crserver 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);
    }

    CR_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 );
    CR_CMDBLOCK_CHECK_FLUSH(pc);
    CR_UNLOCK_PACKER_CONTEXT(pc);
}

/* 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 noimagedata = (bitmap == NULL) || crStateIsBufferBound(GL_PIXEL_UNPACK_BUFFER_ARB);
    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 ) + sizeof(GLint);

    if (!noimagedata)
    {
        data_length = CEIL8(width) * height / 8;
        packet_length += data_length;
    }

    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, noimagedata );
    WRITE_DATA( 28, GLint, (GLint) (uintptr_t) bitmap);

    if (!noimagedata)
        crBitmapCopy(width, height, (GLubyte *)(data_ptr + 32), bitmap, unpack);

    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 )
{
    CR_GET_PACKER_CONTEXT(pc);
    unsigned char *data_ptr;
    (void) pc;
    CR_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 );
    CR_CMDBLOCK_CHECK_FLUSH(pc);
    CR_UNLOCK_PACKER_CONTEXT(pc);
}
