/*
 *   MediaMVP Server Library
 *
 *   (C) 2004 Dominic Morris
 *
 *   $Id: surface.c,v 1.15 2004/09/18 18:15:41 dom Exp $
 *   $Date: 2004/09/18 18:15:41 $
 *
 *   Implementation of the lowest level surface routines. All graphics
 *   routines call through this in the end
 *
 *   32 bit surfaces support alpha blending. This kicks in when we set
 *   a pixel on it, or blit a 8 (or 24) bit surface onto it. Blitting a
 *   32 bit surface just does a copy.
 *
 *   8/24 bit surfaces preserve any alpha channel information, this can
 *   be retrieved by changing the parameter to the map function. This will
 *   be ideal for when the onboard software supports an alpha channel.
 *   
 *   32 bit surface alpha blending is suitable for preparing a blended 
 *   screen *on* the server. Alpha channel information is not preserved,
 *   
 *   An alpha value of 0xFF is transparent.
 *
 */

#include "libmvp_internal.h"


typedef struct _colortbl {
    uint32_t rgb;
    uint8_t y, v, u;
} colortbl_t;

typedef struct {
    uint8_t  *image;
    colortbl_t colortbl[256];
    int       next_free_color;
} surface8_t;

typedef struct {
    uint32_t  *bitmap;
} surface24_t;

struct _surface {
    int       width;
    int       depth;
    bool_t    dirty;
    union {
        surface8_t   s8;
        surface24_t  s24;
    } sfc;
    void     (*dealloc)(surface_t *);
    void     (*clear)(surface_t *, uint32_t);
    void    *(*map)(surface_t *, mapmode_t mode, int *size);
    void     (*setpixel)(surface_t *, int, int, uint32_t);
    uint32_t (*getpixel)(surface_t *, int, int);
    void     (*blit)(surface_t *dest, surface_t *src, int delta_x, int delta_y, int width, int depth);
};





static void          rgb2yvu(uint8_t *py, uint8_t *pv, uint8_t *pu, int red, int green, int blue);
static int           surface_get_mapsize(surface_t *surface, mapmode_t mode);

static int           surface8_alloc(surface_t *surface);
static void          surface8_dealloc(surface_t *surface);
static uint8_t       get_color(surface_t *surface, uint32_t rgb);
static void          surface8_clear(surface_t *surface, uint32_t rgb);
static void         *surface8_map(surface_t *, mapmode_t mode, int *size);
static void          surface8_set_pixel(surface_t *surface, int x, int y, uint32_t rgb);
static uint32_t      surface8_get_pixel(surface_t *surface,int x, int y);
static void          surface8_blit(surface_t *dest, surface_t *src, int delta_x, int delta_y, int width, int depth);

static int           surface24_alloc(surface_t *surface);
static void          surface24_dealloc(surface_t *surface);
static void          surface24_clear(surface_t *surface, uint32_t rgb);
static void         *surface24_map(surface_t *surface, mapmode_t mode, int *size);
static void          surface24_set_pixel(surface_t *surface, int x, int y, uint32_t rgb);
static uint32_t      surface24_get_pixel(surface_t *surface,int x, int y);
static void          surface24_blit(surface_t *dest, surface_t *src, int delta_x, int delta_y, int width, int depth);
static void          surface32_set_pixel(surface_t *surface, int x, int y, uint32_t rgb);




#include "yuv_table.h"

/* Alpha blending routines lifted from 
 *  http://www.gamedev.net/reference/articles/article1594.asp 
 */
struct LookupLevel {
    uint8_t Values[256];
};

struct LookupTable {
    struct LookupLevel Levels[256];
} AlphaTable;

static  uint8_t clipByte(int value) {
  value = (0 & (-(int)(value < 0))) | (value & (-(int)!(value < 0)));
  value = (255 & (-(int)(value > 255))) | (value & (-(int)!(value > 255)));
  return value;
}

static int init_alpha_table() 
{
    static bool_t alpha_table_init = FALSE;

    float fValue, fAlpha;
    int iValue, iAlpha;

    if ( alpha_table_init ) 
        return 1;
    alpha_table_init = TRUE;

    for (iAlpha = 0; iAlpha < 256; iAlpha++) {
        fAlpha = ((float)iAlpha) / 255;
        for (iValue = 0; iValue < 256; iValue++) {
            fValue = ((float)iValue) / 255;
            AlphaTable.Levels[iAlpha].Values[iValue] = clipByte((int)((fValue * fAlpha) * 255));
        }
    }
    return 0;
}

struct LookupLevel *LookupPointer(int alpha) 
{
  return &AlphaTable.Levels[clipByte(alpha)];
}

#if 1
static void rgb2yvu(uint8_t *py, uint8_t *pv, uint8_t *pu, int red, int green, int blue)
{
	red = (red < 0 ? 0 : (red > 255 ? 255 : red));
	green = (green < 0 ? 0 : (green > 255 ? 255 : green));
	blue = (blue < 0 ? 0 : (blue > 255 ? 255 : blue));

    *py = (uint8_t)(y_lookup[red].red + y_lookup[green].green + y_lookup[blue].blue);
    *pv = (uint8_t)(v_lookup[red].red - v_lookup[green].green + v_lookup[blue].blue + 128.0);
    *pu = (uint8_t)(u_lookup[red].red - u_lookup[green].green - u_lookup[blue].blue + 128.0);
}
#endif

#if 0
static void rgb2yvu(uint8_t *py, uint8_t *pv, uint8_t *pu, int red, int green, int blue)
{
	double y,v,u,r,g,b;

	r = (double)red;
	g = (double)green;
	b = (double)blue;

	y = (0.299 * r) + (0.587 * g) + (0.144 * b);
	v = (0.500 * r) - (0.419 * g) - (0.081 * b) + 128;
	u = (-0.169 * r) - (0.331 * g) - (0.500 * b) + 128;

	/* Clamp values*/
	/* y = [16,235] */
	if(y > 235.0)
		y = 235.0;
	else if(y < 16.0)
		y = 16.0;

	/* u and v = [16,240] */
	if(v > 240.0)
		v = 240.0;
	else if(v < 16.0)
		v = 16.0;

	if(u > 240.0)
		u = 240.0;
	else if(u < 16.0)
		u = 16.0;

	*py = (uint8_t)y;
	*pv = (uint8_t)v;
	*pu = (uint8_t)u;
}
#endif

#if 0
static void rgb2yvu(uint8_t *py, uint8_t *pv, uint8_t *pu, int red, int green, int blue)
{
    int y,v,u;

    y = 0.30 * (double)red +
        0.59 * (double)green +
        0.11 * (double)blue;

    if ( y > 240 )
        y = 240;
    else if ( y < 0 )
        y = 0;

    v = -(0.15 * (double)red) -
        (0.29 * (double)green) +
        (0.44 * (double)blue) +
        128.0;

    u = (0.62 * (double)red) -
        (0.52 * (double)green) +
        (0.10 * (double)blue) +
        128.0;

    if ( v > 240 )
        v = 240;
    else if ( v < 0 )
        v = 0;

    if ( u > 240 )
        u = 240;
    else if ( u < 0 )
        u = 0;

    *py = y;
    *pv = v;
    *pu = u;
}
#endif

#if 0
static void rgb2yvu(uint8_t *py, uint8_t *pu, uint8_t *pv, int red, int green, int blue)
{
	double r1, g1, b1, r2, g2, b2, y, u, v;

	/*
	 * convert 0..255 RGB to floating point range 0.0->1.0
	 */
	r1 = (double)red / 255.0;
	g1 = (double)green / 255.0;
	b1 = (double)blue / 255.0;

	/*
	 * apply gamma correction
	 */

	if (r1 < 0.018)
		r2 = r1 * 4.5;
	else
		r2 = (1.099 * pow(r1, 0.45)) - 0.099;
		
	if (g1 < 0.018)
		g2 = g1 * 4.5;
	else
		g2 = (1.099 * pow(g1, 0.45)) - 0.099;
		
	if (b1 < 0.018)
		b2 = b1 * 4.5;
	else
		b2 = (1.099 * pow(b1, 0.45)) - 0.099;

	/*
	 * convert gamma corrected RGB to YUV space
	 */
	y = (0.2989 * r2) + (0.5866 * g2) + (0.1145 * b2);
	u = ( (-0.147 * r2)  - (0.289 * g2) + (0.436 * b2) ) + 0.5;
	v = ( (0.615 * r2) - (0.515 * g2) + (0.100 * b2) ) + 0.5;

	/*
	 * range clamp for errors (shouldn't be necessary)
	 */
	if (y < 0.0)
		y = 0.0;
	else if (y > 1.0)
		y = 1.0;
		
	if (u < 0.0)
		u = 0.0;
	else if (u > 1.0)
		u = 1.0;
		
	if (v < 0.0)
		v = 0.0;
	else if (v > 1.0)
		v = 1.0;

	/*
	 * convert back to byte values
	 */
	*py = (uint8_t)(y * 255.0);
	*pu = (uint8_t)(u * 255.0);
	*pv = (uint8_t)(v * 255.0);
}


#endif

#if 0
static void rgb2yvu(uint8_t *py, uint8_t *pu, uint8_t *pv, int red, int green, int blue)
{
	double r1, g1, b1, y, u, v;

	/*
	 * convert 0..255 RGB to floating point range 0.0->1.0
	 */
	r1 = (double)red / 255.0;
	g1 = (double)green / 255.0;
	b1 = (double)blue / 255.0;

	y = (0.299 * r1) + (0.587 * g1) + (0.114 * b1);
	u = (-0.169 * r1) - (0.331 * g1) + (0.500 * b1);
	v = (0.500 * r1) - (0.419 * g1) - (0.081 * b1);

	/*
	 * range clamp for errors (shouldn't be necessary)
	 */
	if (y < 0.0)
		y = 0.0;
	else if (y > 1.0)
		y = 1.0;
		
	if (u < 0.0)
		u = 0.0;
	else if (u > 1.0)
		u = 1.0;
		
	if (v < 0.0)
		v = 0.0;
	else if (v > 1.0)
		v = 1.0;

	/*
	 * convert back to byte values
	 */
	*py = (uint8_t)(y * 255.0);
	*pu = (uint8_t)(u * 255.0);
	*pv = (uint8_t)(v * 255.0);
}


#endif

#if 0

/*
 * rgb2yuv() -- convert a from RGB colour space to YUV colour space
 *
 * This version does it as per the Colour Space FAQ found at:
 *
 *	http://www.neuro.sfc.keio.ac.jp/~aly/polygon/info/color-space-faq.html
 *
 * and:
 *
 *	http://www.video-demystified.com/mm/tutor/ch03.pdf
 *
 * coded in a hurry by Mike Tubby, mike@tubby.org, 18-ARP-2004
 *
 * I think the RGB to YUV conversion only works properly if you take
 * gamma correction into account before doing the transform...
 *
 */

#define GAMMA_CORRECTION	(1.0/2.8)

static void rgb2yvu(uint8_t *py, uint8_t *pu, uint8_t *pv, int red, int green, int blue)
{
	double r1, g1, b1, r2, g2, b2, y, u, v;

	/*
	 * convert 0..255 RGB to floating point range 0.0->1.0
	 */
	r1 = (double)red / 255.0;
	g1 = (double)green / 255.0;
	b1 = (double)blue / 255.0;

	/*
	 * apply gamma correction
	 */
	r2 = pow(r1, GAMMA_CORRECTION);
	g2 = pow(g1, GAMMA_CORRECTION);
	b2 = pow(b1, GAMMA_CORRECTION);

	/*
	 * convert gamma corrected RGB to YUV space
	 */
	y = (0.2989 * r2) + (0.5866 * g2) + (0.1145 * b2);
	u = ( (-0.147 * r2)  - (0.289 * g2) + (0.436 * b2) ) + 0.5;
	v = ( (0.615 * r2) - (0.515 * g2) + (0.100 * b2) ) + 0.5;

	/*
	 * range clamp for errors - shouldn't be necessary
	 */
	if (y < 0.0)
		y = 0.0;
	else if (y > 1.0)
		y = 1.0;
		
	if (u < 0.0)
		u = 0.0;
	else if (u > 1.0)
		u = 1.0;
		
	if (v < 0.0)
		v = 0.0;
	else if (v > 1.0)
		v = 1.0;

	/*
	 * convert back to byte values
	 */
	*py = (uint8_t)(y * 255.0);
	*pu = (uint8_t)(u * 255.0);
	*pv = (uint8_t)(v * 255.0);
}

#endif

#if 0

#define SATURATION 0.70

static void rgb2yvu(uint8_t *py, uint8_t *pu, uint8_t *pv, int red, int green, int blue)
{
	double r1, g1, b1, y, u, v;

	/*
	 * convert 0..255 RGB to floating point range 0.0->1.0
	 */
	r1 = (double)red / 255.0;
	g1 = (double)green / 255.0;
	b1 = (double)blue / 255.0;

	/*
	 * convert gamma corrected RGB to YUV space
	 */
	y = (0.2989 * r1) + (0.5866 * g1) + (0.1145 * b1);
	u = ( ( (-0.147 * r1)  - (0.289 * g1) + (0.436 * b1) ) + 0.5) * SATURATION ;
	v = ( ( (0.615 * r1) - (0.515 * g1) + (0.100 * b1) ) + 0.5) * SATURATION;

	/*
	 * range clamp for errors - shouldn't be necessary
	 */
	if (y < 0.0)
		y = 0.0;
	else if (y > 1.0)
		y = 1.0;
		
	if (u < 0.0)
		u = 0.0;
	else if (u > 1.0)
		u = 1.0;
		
	if (v < 0.0)
		v = 0.0;
	else if (v > 1.0)
		v = 1.0;

	/*
	 * convert back to byte values
	 */
	*py = (uint8_t)(y * 255.0);
	*pu = (uint8_t)(u * 255.0);
	*pv = (uint8_t)(v * 255.0);
}

#endif

surface_t *surface_alloc(int width, int depth, int bpp)
{
    surface_t  *surface = (surface_t*)malloc(sizeof(*surface));

    if ( surface == NULL ) {
        return NULL;
    }

    init_alpha_table();

    /* Set up sizes */
    surface->width = width;
    surface->depth  = depth;
    surface->dirty = TRUE;

    switch ( bpp ) {
    case 8:
        surface8_alloc(surface);
        surface->clear = surface8_clear;
        surface->map = surface8_map;
        surface->setpixel = surface8_set_pixel;
        surface->getpixel = surface8_get_pixel;
        surface->dealloc = surface8_dealloc;
        surface->blit = surface8_blit;
        break;
    case 24:
        surface24_alloc(surface);
        surface->clear = surface24_clear;
        surface->map = surface24_map;
        surface->setpixel = surface24_set_pixel;
        surface->getpixel = surface24_get_pixel;
        surface->dealloc = surface24_dealloc;
        surface->blit = surface24_blit;
        break;
    case 32:
        surface24_alloc(surface);
        surface->clear = surface24_clear;
        surface->map = surface24_map;
        surface->setpixel = surface32_set_pixel;
        surface->getpixel = surface24_get_pixel;
        surface->dealloc = surface24_dealloc;
        surface->blit = surface24_blit;
        break;
    default:
        free(surface);
        surface = NULL;
        break;
    }

    return surface;
}

int surface_get_height(surface_t *surface)
{
    return surface->depth;
}

int surface_get_width(surface_t *surface)
{
    return surface->width;
}

void surface_dealloc(surface_t *surface)
{
    if ( surface == NULL ) {
        return;
    }

    surface->dealloc(surface);


    free(surface);
}

static int surface_get_mapsize(surface_t *surface, mapmode_t mode)
{
    switch ( mode ) {
    case MAP_YVU:
        return surface->width * surface->depth * 2;
    case MAP_AYVU:
    case MAP_RGB:
        return surface->width * surface->depth * 3;
    case MAP_ARGB:
        return surface->width * surface->depth * 4;
    }

    /* Will never reach here */
    return -1;
}



void surface_set_pixel(surface_t *surface, int x, int y, uint32_t rgb)
{
    if ( x >= 0 && x < surface->width && y >= 0 && y < surface->depth ) {
        surface->setpixel(surface,x,y,rgb);  
        surface->dirty = TRUE;
    }
}

uint32_t surface_get_pixel(surface_t *surface, int x, int y)
{
    if ( x >= 0 && x < surface->width && y >= 0 && y < surface->depth ) {
        return surface->getpixel(surface,x,y);
    }
    return 0;
}

void surface_clear(surface_t *surface, uint32_t rgb)
{
    surface->dirty = TRUE;
    surface->clear(surface,rgb);
}

void *surface_map(surface_t *surface,mapmode_t mode, int *size)
{
    return surface->map(surface,mode,size);
}

int surface_get_dirty(surface_t *surface)
{
    return surface->dirty;
}

void surface_set_dirty(surface_t *surface, int state)
{
    surface->dirty = state;
}


/* Routines for dealing with 8 bit surface */
static int surface8_alloc(surface_t *surface)
{
    surface->sfc.s8.next_free_color = 0;

    /* Allocate the RGB surfaces */
    surface->sfc.s8.image = (uint8_t*)calloc(surface->width * surface->depth,1);

    return 1;
}

static void surface8_dealloc(surface_t *surface)
{
    if ( surface->sfc.s8.image ) {
        free(surface->sfc.s8.image);
    }
}


static uint8_t get_color(surface_t *surface, uint32_t rgb)
{
    int i;
    colortbl_t* ct;
    for (i=0; i<surface->sfc.s8.next_free_color; i++) {
            if (surface->sfc.s8.colortbl[i].rgb == rgb) {
                return i;
            }
    }

    if (surface->sfc.s8.next_free_color >= 256) {
         Dprintf(DEBUG, "I don't like too many colors. Bye.\n");
         exit(1);
    }

    Dprintf(DEBUG, "allocating color %d\n", surface->sfc.s8.next_free_color);
    ct = &surface->sfc.s8.colortbl[surface->sfc.s8.next_free_color];
    ct->rgb = rgb;
    rgb2yvu(&ct->y, &ct->v, &ct->u, (rgb >> 16) & 0xFF, (rgb >> 8) & 0xFF, rgb & 0xFF);

    return surface->sfc.s8.next_free_color++;
}



static void surface8_clear(surface_t *surface, uint32_t rgb)
{
    uint8_t index;

    /* Reset the palette if we're clearing screens */
    surface->sfc.s8.next_free_color = 0;

    index = get_color(surface,rgb);

    memset(&surface->sfc.s8.image[0],index,surface->width * surface->depth);
}

static void *surface8_map(surface_t *surface, mapmode_t mode, int *size)
{
    uint8_t    *sfc;
    int         i,j;

    *size = surface_get_mapsize(surface,mode);


    sfc = (uint8_t*)malloc(*size);

    for ( j = 0, i = 0; i < surface->width * surface->depth; i++ ) {
        switch ( mode ) {
        case MAP_AYVU:   /* A1,A2,Y1,V1,U1,Y1 */
            sfc[j++] = ( (surface->sfc.s8.colortbl[ surface->sfc.s8.image[i+0] ].rgb ) >> 24 ) & 0xFF;
            sfc[j++] = ( (surface->sfc.s8.colortbl[ surface->sfc.s8.image[i+1] ].rgb ) >> 24 ) & 0xFF;
            /* Fall through */
        case MAP_YVU:
            sfc[j++] = surface->sfc.s8.colortbl[ surface->sfc.s8.image[i+0] ].y;
            sfc[j++] = surface->sfc.s8.colortbl[ surface->sfc.s8.image[i+0] ].v;
            sfc[j++] = surface->sfc.s8.colortbl[ surface->sfc.s8.image[i+0] ].u;
            sfc[j++] = surface->sfc.s8.colortbl[ surface->sfc.s8.image[i+1] ].y;
            i++;
            break;
        case MAP_ARGB:
            sfc[j++] = ( (surface->sfc.s8.colortbl[ surface->sfc.s8.image[i+0] ].rgb ) >> 24 ) & 0xFF;
            /* Fall through */
        case MAP_RGB:
            sfc[j++] = ( (surface->sfc.s8.colortbl[ surface->sfc.s8.image[i+0] ].rgb ) >> 16 ) & 0xFF;
            sfc[j++] = ( (surface->sfc.s8.colortbl[ surface->sfc.s8.image[i+0] ].rgb ) >> 8 ) & 0xFF;
            sfc[j++] = ( (surface->sfc.s8.colortbl[ surface->sfc.s8.image[i+0] ].rgb ) >> 0 ) & 0xFF;
            break;
        }      
    }


    return sfc;
}


static void surface8_set_pixel(surface_t *surface, int x, int y, uint32_t rgb)
{
    int offset = y * surface->width + x;
    uint8_t  index = get_color(surface,rgb);

    surface->sfc.s8.image[offset] = index;
}

static uint32_t surface8_get_pixel(surface_t *surface,int x, int y)
{
    int offset = y * surface->width + x;

    return surface->sfc.s8.colortbl[ surface->sfc.s8.image[offset] ].rgb;
}

static void surface8_blit(surface_t *dest, surface_t *src, int delta_x, int delta_y, int width, int depth)
{
    int   y,x;

    /* If they're different depths then we have to do a slow copy */
    for( y = 0; y < depth ; y++) {
	    for( x = 0; x < width; x++) {
		    uint32_t c = surface_get_pixel(src, x, y);
		    surface_set_pixel(dest, x + delta_x, y + delta_y, c);
	    }
    }
}


/* Routines for dealing with the 24 bit surface */
static int surface24_alloc(surface_t *surface)
{    
    /* Data is stored ARGB */
    surface->sfc.s24.bitmap = calloc(surface->width * surface->depth, sizeof(uint32_t));
   
    return 0;
}

static void surface24_dealloc(surface_t *surface)
{
    /* Deallocate the RGB surfaces */
   if ( surface->sfc.s24.bitmap ) {
       free(surface->sfc.s24.bitmap);
       surface->sfc.s24.bitmap = NULL;
   }
}



static void surface24_clear(surface_t *surface, uint32_t rgb)
{
    int   i;
    /* FIXME: This sucks */
    for ( i = 0; i < surface->width * surface->depth; i++ ) {
        surface->sfc.s24.bitmap[i] = rgb;
    } 
}

static void *surface24_map(surface_t *surface, mapmode_t mode, int *size)
{
    uint8_t    *sfc;
    int         i,j;


   *size = surface_get_mapsize(surface,mode);

    sfc = (uint8_t*)malloc(*size);  

    for ( j = 0, i = 0; i <surface->width * surface->depth; i++ ) {
        uint8_t   y1,u1,v1,y2,u2,v2;
        uint32_t  c = surface->sfc.s24.bitmap[i];
        uint32_t  c2;

        switch ( mode ) {
        case MAP_AYVU:
            sfc[j++] = ( c >> 24 ) & 0xFF;
            sfc[j++] = ( surface->sfc.s24.bitmap[i+1] >> 24 ) & 0xFF;
            /* Fall through */
        case MAP_YVU:
            rgb2yvu(&y1,&v1,&u1,(c >> 16 ) & 0xFF,( c >> 8 ) & 0xFF, ( c >> 0 ) & 0xFF);
            c2 = surface->sfc.s24.bitmap[i+1];
            rgb2yvu(&y2,&v2,&u2,(c2 >> 16 ) & 0xFF,( c2 >> 8 ) & 0xFF, ( c2 >> 0 ) & 0xFF);
            sfc[j++] = y1;
            sfc[j++] = v1;
            sfc[j++] = u1;
            sfc[j++] = y2;
            i++;
            break;
        case MAP_ARGB:        
            sfc[j++] = ( c >> 24 ) & 0xFF;
            /* Fall through */
        case MAP_RGB:
            sfc[j++] = ( c >> 16 ) & 0xFF;
            sfc[j++] = ( c >> 8 ) & 0xFF;
            sfc[j++] = ( c >> 0 ) & 0xFF;
            break;        
        }
    }
    return sfc;
}

static void surface24_set_pixel(surface_t *surface, int x, int y, uint32_t rgb)
{
    int offset = y * surface->width + x;
    surface->sfc.s24.bitmap[offset] = rgb;
}


static void surface32_set_pixel(surface_t *surface, int x, int y, uint32_t rgb)
{
    int offset = y * surface->width + x;
    struct LookupLevel *SourceTable;
    struct LookupLevel *DestTable;
    int alpha = ( rgb >> 24 ) & 0xFF;
    uint32_t newc = 0;
   

    if ( alpha ) {
        alpha = 255 - alpha;
        SourceTable = LookupPointer(alpha);
        DestTable = LookupPointer(255 - alpha);

        newc = (clipByte(SourceTable->Values[(rgb >> 16 ) & 0xFF] + DestTable->Values[(surface->sfc.s24.bitmap[offset] >> 16 ) & 0xFF]) << 16 )  +
            (clipByte(SourceTable->Values[(rgb >> 8 ) & 0xFF] + DestTable->Values[(surface->sfc.s24.bitmap[offset] >> 8 ) & 0xFF])  << 8 )  +
            (clipByte(SourceTable->Values[(rgb >> 0 ) & 0xFF] + DestTable->Values[(surface->sfc.s24.bitmap[offset] >> 0 ) & 0xFF])  << 0 );
        surface->sfc.s24.bitmap[offset] = newc;   
    } else {
        surface->sfc.s24.bitmap[offset] = rgb;
    }       
}


static uint32_t surface24_get_pixel(surface_t *surface,int x, int y)
{
    int offset = y * surface->width + x;

    return surface->sfc.s24.bitmap[offset];
}

static void surface24_blit(surface_t *dest, surface_t *src, int delta_x, int delta_y, int width, int depth)
{
    int   y;
    int   offset;
    int   offset2;

    for ( y = 0; y < depth; y++ ) {
        offset = ( (( y + delta_y ) * dest->width ) + delta_x ); 
        offset2 = ( y  * src ->width ) ; 
        memcpy(&dest->sfc.s24.bitmap[offset],&src->sfc.s24.bitmap[offset2], width * sizeof(uint32_t));
    }
}




 void surface_blit(surface_t *dest, surface_t *src, int delta_x, int delta_y, int width, int depth)
{
    int    x,y;

    /* Basic sanity checking */
    if ( width > src->width )
        width = src->width;
    if ( width + delta_x > dest->width )
        width = dest->width - delta_x;

    if ( depth > src->depth )
        depth = src->depth;
    if ( depth + delta_y > dest->depth )
        width = dest->depth - delta_y;



    if ( dest->depth == src->depth ) {
        dest->blit(dest,src,delta_x,delta_y,width,depth);
        dest->dirty = TRUE;
        return;
    }

    /* If they're different depths then we have to do a slow copy */
    for( y = 0; y < depth ; y++) {
	    for( x = 0; x < width; x++) {
		    uint32_t c = surface_get_pixel(src, x, y);
		    surface_set_pixel(dest, x + delta_x, y + delta_y, c);
	    }
    }

}

/*
 * Local Variables:
 *  indent-tabs-mode:nil
 *  require-final-newline:t
 *  c-basic-offset: 4
 * End:
 */
