/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * RLE sprite generation routines. * * By Shawn Hargreaves. * * See readme.txt for copyright information. */ #include #include "allegro.h" #include "allegro/internal/aintern.h" /* get_rle_sprite: * Creates a run length encoded sprite based on the specified bitmap. * The returned sprite is likely to be a lot smaller than the original * bitmap, and can be drawn to the screen with draw_rle_sprite(). * * The compression is done individually for each line of the image. * Format is a series of command bytes, 1-127 marks a run of that many * solid pixels, negative numbers mark a gap of -n pixels, and 0 marks * the end of a line (since zero can't occur anywhere else in the data, * this can be used to find the start of a specified line when clipping). * For truecolor RLE sprites, the data and command bytes are both in the * same format (16 or 32 bits, 24 bpp data is padded to 32 bit aligment), * and the mask color (bright pink) is used as the EOL marker. */ RLE_SPRITE *get_rle_sprite(BITMAP *bitmap) { int depth; RLE_SPRITE *s; int x, y; int run; int pix; int c; ASSERT(bitmap); depth = bitmap_color_depth(bitmap); #define WRITE_TO_SPRITE8(x) { \ _grow_scratch_mem(c+1); \ p = (signed char *)_scratch_mem; \ p[c] = x; \ c++; \ } #define WRITE_TO_SPRITE16(x) { \ _grow_scratch_mem((c+1)*sizeof(int16_t)); \ p = (int16_t *)_scratch_mem; \ p[c] = x; \ c++; \ } #define WRITE_TO_SPRITE32(x) { \ _grow_scratch_mem((c+1)*sizeof(int32_t)); \ p = (int32_t *)_scratch_mem; \ p[c] = x; \ c++; \ } /* helper for building an RLE run */ #define DO_RLE(bits) \ { \ for (y=0; yh; y++) { \ run = -1; \ for (x=0; xw; x++) { \ pix = getpixel(bitmap, x, y) & 0xFFFFFF; \ if (pix != bitmap->vtable->mask_color) { \ if ((run >= 0) && (p[run] > 0) && (p[run] < 127)) \ p[run]++; \ else { \ run = c; \ WRITE_TO_SPRITE##bits(1); \ } \ WRITE_TO_SPRITE##bits(getpixel(bitmap, x, y)); \ } \ else { \ if ((run >= 0) && (p[run] < 0) && (p[run] > -128)) \ p[run]--; \ else { \ run = c; \ WRITE_TO_SPRITE##bits(-1); \ } \ } \ } \ WRITE_TO_SPRITE##bits(bitmap->vtable->mask_color); \ } \ } c = 0; switch (depth) { #ifdef ALLEGRO_COLOR8 case 8: { signed char *p = (signed char *)_scratch_mem; DO_RLE(8); } break; #endif #ifdef ALLEGRO_COLOR16 case 15: case 16: { signed short *p = (signed short *)_scratch_mem; DO_RLE(16); c *= sizeof(short); } break; #endif #if (defined ALLEGRO_COLOR24) || (defined ALLEGRO_COLOR32) case 24: case 32: { int32_t *p = (int32_t *)_scratch_mem; DO_RLE(32); c *= sizeof(int32_t); } break; #endif } s = malloc(sizeof(RLE_SPRITE) + c); if (s) { s->w = bitmap->w; s->h = bitmap->h; s->color_depth = depth; s->size = c; memcpy(s->dat, _scratch_mem, c); } return s; } /* destroy_rle_sprite: * Destroys an RLE sprite structure returned by get_rle_sprite(). */ void destroy_rle_sprite(RLE_SPRITE *sprite) { if (sprite) free(sprite); }