From 322297d68005c08b35e7c309a841553b73259a9c Mon Sep 17 00:00:00 2001 From: Holger Schemel Date: Tue, 19 Mar 2002 23:22:26 +0100 Subject: [PATCH] rnd-20020319-2-src --- CHANGES | 3 + src/libgame/image.c | 96 +++++++++++++---- src/libgame/image.h | 11 ++ src/libgame/pcx.c | 254 +++++++++++++++++++++++++++++++------------- src/main.h | 4 +- 5 files changed, 272 insertions(+), 96 deletions(-) diff --git a/CHANGES b/CHANGES index 4cac89f6..873ae7a6 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +Release Version 2.0.2 [XX XXX XXXX] +----------------------------------- + Release Version 2.0.1 [19 MAR 2002] ----------------------------------- - bug in explosion code fixed that broke level 24 of "Baby Ghost Mine" diff --git a/src/libgame/image.c b/src/libgame/image.c index 836f2843..ae53b44a 100644 --- a/src/libgame/image.c +++ b/src/libgame/image.c @@ -30,15 +30,23 @@ Image *newImage(unsigned int width, unsigned int height, unsigned int depth) Error(ERR_EXIT, "images with more than 256 colors are not supported"); depth = 8; + image = checked_malloc(sizeof(Image)); image->data = checked_malloc(width * height * bytes_per_pixel); image->width = width; image->height = height; image->depth = depth; image->rgb.used = 0; + for (i=0; irgb.color_used[i] = FALSE; + image->type = (depth < 8 ? IMAGETYPE_BITMAP : + depth > 8 ? IMAGETYPE_TRUECOLOR : IMAGETYPE_RGB); + + image->bytes_per_row = (depth + 7) / 8; + image->bytes_per_row *= width; + return image; } @@ -53,20 +61,33 @@ void freeImage(Image *image) /* extra colors to try allocating in private color maps to minimize flashing */ #define NOFLASH_COLORS 256 -/* architecture independent value-to-memory conversion +/* architecture independent value <-> memory conversions; note: the internal format is big endian */ -#define value_to_memory(value, ptr, length) ( \ -(length) == 1 ? (*( (byte *)(ptr) ) = ( value ) ) : \ -(length) == 2 ? (*( (byte *)(ptr) ) = (((unsigned long)(value))>> 8), \ - *(((byte *)(ptr))+1) = ( value ) ) : \ -(length) == 3 ? (*( (byte *)(ptr) ) = (((unsigned long)(value))>>16), \ - *(((byte *)(ptr))+1) = (((unsigned long)(value))>> 8), \ - *(((byte *)(ptr))+2) = ( value ) ) : \ - (*( (byte *)(ptr) ) = (((unsigned long)(value))>>24), \ - *(((byte *)(ptr))+1) = (((unsigned long)(value))>>16), \ - *(((byte *)(ptr))+2) = (((unsigned long)(value))>> 8), \ - *(((byte *)(ptr))+3) = ( value ) )) +#define memory_to_value(ptr, len) ( \ +(len) == 1 ? (unsigned long)( *( (byte *)(ptr)) ) : \ +(len) == 2 ? (unsigned long)(((unsigned long)(*( (byte *)(ptr)) ))<< 8) \ + + ( *(((byte *)(ptr))+1) ) : \ +(len) == 3 ? (unsigned long)(((unsigned long)(*( (byte *)(ptr)) ))<<16) \ + + (((unsigned long)(*(((byte *)(ptr))+1)))<< 8) \ + + ( *(((byte *)(ptr))+2) ) : \ + (unsigned long)(((unsigned long)(*( (byte *)(ptr)) ))<<24) \ + + (((unsigned long)(*(((byte *)(ptr))+1)))<<16) \ + + (((unsigned long)(*(((byte *)(ptr))+2)))<< 8) \ + + ( *(((byte *)(ptr))+3) ) ) + + +#define value_to_memory(value, ptr, len) ( \ +(len) == 1 ? (*( (byte *)(ptr) ) = ( value ) ) : \ +(len) == 2 ? (*( (byte *)(ptr) ) = (((unsigned long)(value))>> 8), \ + *(((byte *)(ptr))+1) = ( value ) ) : \ +(len) == 3 ? (*( (byte *)(ptr) ) = (((unsigned long)(value))>>16), \ + *(((byte *)(ptr))+1) = (((unsigned long)(value))>> 8), \ + *(((byte *)(ptr))+2) = ( value ) ) : \ + (*( (byte *)(ptr) ) = (((unsigned long)(value))>>24), \ + *(((byte *)(ptr))+1) = (((unsigned long)(value))>>16), \ + *(((byte *)(ptr))+2) = (((unsigned long)(value))>> 8), \ + *(((byte *)(ptr))+3) = ( value ) )) static Pixmap Image_to_Mask(Image *image, Display *display, Window window) { @@ -243,7 +264,7 @@ XImageInfo *Image_to_Pixmap(Display *display, int screen, Visual *visual, /* something completely unexpected happened */ - fprintf(stderr, "imageToXImage: XAllocColor failed on a TrueColor/Directcolor visual\n"); + fprintf(stderr, "Image_to_Pixmap: XAllocColor failed on a TrueColor/Directcolor visual\n"); free(redvalue); free(greenvalue); free(bluevalue); @@ -416,18 +437,49 @@ XImageInfo *Image_to_Pixmap(Display *display, int screen, Visual *visual, { Pixel pixval; - for (y=0; yheight; y++) /* general case */ + switch (image->type) { - for (x=0; xwidth; x++) + case IMAGETYPE_RGB: + { + for (y=0; yheight; y++) /* general case */ + { + for (x=0; xwidth; x++) + { + pixval = *src_ptr++; + pixval = + redvalue[image->rgb.red[pixval] >> 8] | + greenvalue[image->rgb.green[pixval] >> 8] | + bluevalue[image->rgb.blue[pixval] >> 8]; + value_to_memory(pixval, dst_ptr, bytes_per_pixel); + dst_ptr += bytes_per_pixel; + } + } + break; + } + + case IMAGETYPE_TRUECOLOR: { - pixval = *src_ptr++; - pixval = - redvalue[image->rgb.red[pixval] >> 8] | - greenvalue[image->rgb.green[pixval] >> 8] | - bluevalue[image->rgb.blue[pixval] >> 8]; - value_to_memory(pixval, dst_ptr, bytes_per_pixel); - dst_ptr += bytes_per_pixel; + for (y=0; yheight; y++) /* general case */ + { + for (x=0; xwidth; x++) + { + pixval = memory_to_value(src_ptr, image->depth); + pixval = + redvalue[TRUECOLOR_RED(pixval)] | + greenvalue[TRUECOLOR_GREEN(pixval)] | + bluevalue[TRUECOLOR_BLUE(pixval)]; + value_to_memory(pixval, dst_ptr, bytes_per_pixel); + src_ptr += image->depth; + dst_ptr += bytes_per_pixel; + } + } + break; } + + default: + Error(ERR_RETURN, "image type not supported"); + Error(ERR_EXIT, "RGB or TrueColor image needed"); + break; } break; } diff --git a/src/libgame/image.h b/src/libgame/image.h index 1e1b6cb5..2b3af63d 100644 --- a/src/libgame/image.h +++ b/src/libgame/image.h @@ -45,13 +45,24 @@ struct RGBMap typedef struct { + unsigned int type; /* type of image (True-Color etc.) */ struct RGBMap rgb; /* RGB map of image if IRGB type */ unsigned int width; /* width of image in pixels */ unsigned int height; /* height of image in pixels */ unsigned int depth; /* depth of image in bits if IRGB type */ + unsigned int bytes_per_row; /* ((depth + 7) / 8) bytes * width */ byte *data; /* image data */ } Image; +#define IMAGETYPE_BITMAP 0 /* monochrome bitmap */ +#define IMAGETYPE_RGB 1 /* RGB image with colormap */ +#define IMAGETYPE_TRUECOLOR 2 /* true-color image */ + +#define TRUECOLOR_RED(pixel) (((unsigned long)((pixel) & 0xff0000)) >> 16) +#define TRUECOLOR_GREEN(pixel) (((unsigned long)((pixel) & 0xff00)) >> 8) +#define TRUECOLOR_BLUE(pixel) ( (unsigned long)((pixel) & 0xff)) +#define RGB_TO_TRUECOLOR(r,g,b) ((((unsigned long)((r) & 0xff00)) << 8) | ((g) & 0xff00) | (((unsigned short)(b)) >> 8)) + Image *newImage(unsigned int, unsigned int, unsigned int); void freeImage(Image *); void freeXImage(Image *, XImageInfo *); diff --git a/src/libgame/pcx.c b/src/libgame/pcx.c index a43e67d5..58c19bd3 100644 --- a/src/libgame/pcx.c +++ b/src/libgame/pcx.c @@ -19,13 +19,12 @@ #include "misc.h" -#define PCX_DEBUG FALSE +#define PCX_DEBUG TRUE #define PCX_MAGIC 0x0a /* first byte in a PCX image file */ -#define PCX_LAST_VERSION 5 /* last acceptable version number */ +#define PCX_SUPPORTED_VERSION 5 /* last acceptable version number */ #define PCX_ENCODING 1 /* PCX encoding method */ #define PCX_256COLORS_MAGIC 0x0c /* first byte of a PCX 256 color map */ -#define PCX_MAXDEPTH 8 /* supports up to 8 bits per pixel */ #define PCX_MAXCOLORS 256 /* maximum number of colors */ #define PCX_HEADER_SIZE 128 @@ -36,7 +35,7 @@ struct PCX_Header unsigned char signature; /* PCX file identifier */ unsigned char version; /* version compatibility level */ unsigned char encoding; /* encoding method */ - unsigned char bits_per_pixel; /* bits per pixel, or depth */ + unsigned char bits_per_pixel; /* bits per pixel (not depth!) */ unsigned short xmin; /* X position of left edge */ unsigned short ymin; /* Y position of top edge */ unsigned short xmax; /* X position of right edge */ @@ -45,7 +44,7 @@ struct PCX_Header unsigned short vres; /* Y screen resolution of source image */ unsigned char palette[16][3]; /* PCX color map */ unsigned char reserved; /* should be 0, 1 if std res fax */ - unsigned char color_planes; /* bit planes in image */ + unsigned char color_planes; /* "color planes" in image */ unsigned short bytes_per_line;/* byte delta between scanlines */ unsigned short palette_type; /* 0 = undef, 1 = color, 2 = grayscale */ unsigned char filler[58]; /* fill to struct size of 128 */ @@ -54,6 +53,7 @@ struct PCX_Header /* global PCX error value */ int errno_pcx = PCX_Success; +#if 0 static byte *PCX_ReadBitmap(Image *image, byte *buffer_ptr, byte *buffer_last) { /* Run Length Encoding: If the two high bits are set, @@ -97,7 +97,99 @@ static byte *PCX_ReadBitmap(Image *image, byte *buffer_ptr, byte *buffer_last) /* return current buffer position for next decoding function */ return buffer_ptr; } +#endif + +static boolean PCX_ReadBitmap(FILE *file, struct PCX_Header *pcx, Image *image) +{ + int width = image->width; + int height = image->height; + int pcx_depth = pcx->bits_per_pixel * pcx->color_planes; + int bytes_per_row = pcx->color_planes * pcx->bytes_per_line; + byte *row_buffer = checked_malloc(bytes_per_row); + byte *bitmap_ptr = image->data; + int y; + + for (y = 0; y < height; y++) + { + /* decode a scan line into a temporary buffer first */ + byte *dst_ptr = (pcx_depth == 8) ? bitmap_ptr : row_buffer; + byte value = 0, count = 0; + int value_int; + int i; + + for (i = 0; i < bytes_per_row; i++) + { + if (count == 0) + { + if ((value_int = fgetc(file)) == EOF) + return FALSE; + value = (byte)value_int; + + if ((value & 0xc0) == 0xc0) /* this is a repeat count byte */ + { + count = value & 0x3f; /* extract repeat count from byte */ + if ((value_int = fgetc(file)) == EOF) + return FALSE; + value = (byte)value_int; + } + else + count = 1; + } + + dst_ptr[i] = value; + count--; + + if (pcx_depth == 8) + image->rgb.color_used[value] = TRUE; + } + + if (pcx_depth <= 4) /* expand planes to 1 byte/pixel */ + { + byte *src_ptr = row_buffer; + int plane; + + for (plane = 0; plane < pcx->color_planes; plane++) + { + int i, j, x = 0; + + for(i = 0; i < pcx->bytes_per_line; i++) + { + byte value = *src_ptr++; + + for(j = 7; j >= 0; j--) + { + byte bit = (value >> j) & 1; + + bitmap_ptr[x++] |= bit << plane; + } + } + } + } + else if (pcx_depth == 24) /* de-interlace planes */ + { + byte *src_ptr = row_buffer; + int plane; + + for(plane = 0; plane < pcx->color_planes; plane++) + { + int x; + + dst_ptr = bitmap_ptr + plane; + for(x = 0; x < width; x++) + { + *dst_ptr = *src_ptr++; + dst_ptr += pcx->color_planes; + } + } + } + + bitmap_ptr += image->bytes_per_row; + } + return TRUE; +} + +#if 0 static byte *PCX_ReadColormap(Image *image,byte *buffer_ptr, byte *buffer_last) { int i, magic; @@ -124,16 +216,59 @@ static byte *PCX_ReadColormap(Image *image,byte *buffer_ptr, byte *buffer_last) /* return current buffer position for next decoding function */ return buffer_ptr; } +#endif + +static boolean PCX_ReadColormap(FILE *file,struct PCX_Header *pcx,Image *image) +{ + int pcx_depth = pcx->bits_per_pixel * pcx->color_planes; + int num_colors = (1 << pcx_depth); + int i; + + if (image->depth != 8) + return TRUE; + + if (pcx_depth == 8) + { + byte value; + int value_int; + + /* look for a 256-colour palette */ + do + { + if ((value_int = fgetc(file)) == EOF) + return FALSE; + value = (byte)value_int; + } + while (value != PCX_256COLORS_MAGIC); + + /* read 256 colors from PCX colormap */ + for(i = 0; i < PCX_MAXCOLORS; i++) + { + image->rgb.red[i] = (byte)fgetc(file) << 8; + image->rgb.green[i] = (byte)fgetc(file) << 8; + image->rgb.blue[i] = (byte)fgetc(file) << 8; + } + } + else + { + for(i = 0; i < num_colors; i++) + { + image->rgb.red[i] = pcx->palette[i][0] << 8; + image->rgb.green[i] = pcx->palette[i][1] << 8; + image->rgb.blue[i] = pcx->palette[i][2] << 8; + } + } + + return TRUE; +} Image *Read_PCX_to_Image(char *filename) { FILE *file; - byte *file_buffer; - byte *buffer_ptr, *buffer_last; - unsigned int file_length; + byte header_buffer[PCX_HEADER_SIZE]; struct PCX_Header pcx; Image *image; - int width, height, depth; + int width, height, depth, pcx_depth; int i; errno_pcx = PCX_Success; @@ -144,57 +279,40 @@ Image *Read_PCX_to_Image(char *filename) return NULL; } - if (fseek(file, 0, SEEK_END) == -1) - { - fclose(file); - errno_pcx = PCX_ReadFailed; - return NULL; - } - - file_length = ftell(file); - rewind(file); - - if (file_length < PCX_HEADER_SIZE) + if (fread(header_buffer, 1, PCX_HEADER_SIZE, file) != PCX_HEADER_SIZE) { - /* PCX file is too short to contain a valid PCX header */ fclose(file); - errno_pcx = PCX_FileInvalid; - return NULL; - } - - file_buffer = checked_malloc(file_length); - - if (fread(file_buffer, 1, file_length, file) != file_length) - { - fclose(file); errno_pcx = PCX_ReadFailed; return NULL; } - fclose(file); - - pcx.signature = file_buffer[0]; - pcx.version = file_buffer[1]; - pcx.encoding = file_buffer[2]; - pcx.bits_per_pixel = file_buffer[3]; - pcx.xmin = file_buffer[4] + 256 * file_buffer[5]; - pcx.ymin = file_buffer[6] + 256 * file_buffer[7]; - pcx.xmax = file_buffer[8] + 256 * file_buffer[9]; - pcx.ymax = file_buffer[10] + 256 * file_buffer[11]; - pcx.color_planes = file_buffer[65]; - pcx.bytes_per_line = file_buffer[66] + 256 * file_buffer[67]; - pcx.palette_type = file_buffer[68] + 256 * file_buffer[69]; + pcx.signature = header_buffer[0]; + pcx.version = header_buffer[1]; + pcx.encoding = header_buffer[2]; + pcx.bits_per_pixel = header_buffer[3]; + pcx.xmin = (header_buffer[5] << 8) | header_buffer[4]; + pcx.ymin = (header_buffer[7] << 8) | header_buffer[6]; + pcx.xmax = (header_buffer[9] << 8) | header_buffer[8]; + pcx.ymax = (header_buffer[11] << 8) | header_buffer[10]; + pcx.color_planes = header_buffer[65]; + pcx.bytes_per_line = (header_buffer[67] << 8) | header_buffer[66]; + pcx.palette_type = (header_buffer[69] << 8) | header_buffer[68]; + + for (i = 0; i < 48; i++) + pcx.palette[i / 3][i % 3] = header_buffer[16 + i]; width = pcx.xmax - pcx.xmin + 1; height = pcx.ymax - pcx.ymin + 1; - depth = pcx.bits_per_pixel; + pcx_depth = pcx.bits_per_pixel * pcx.color_planes; + depth = ((pcx_depth + 7) / 8) * 8; - if (pcx.signature != PCX_MAGIC || pcx.version > PCX_LAST_VERSION || - pcx.encoding != PCX_ENCODING || pcx.color_planes > PCX_MAXDEPTH || + if (pcx.signature != PCX_MAGIC || + pcx.version != PCX_SUPPORTED_VERSION || + pcx.encoding != PCX_ENCODING || width < 0 || height < 0) { - free(file_buffer); + fclose(file); errno_pcx = PCX_FileInvalid; return NULL; @@ -203,10 +321,9 @@ Image *Read_PCX_to_Image(char *filename) #if PCX_DEBUG if (options.verbose) { - printf("%s is a %dx%d PC Paintbrush image with %d bitplanes\n", - filename, width, height, - pcx.color_planes); - printf("depth: %d\n", pcx.bits_per_pixel); + printf("%s is a %dx%d PC Paintbrush image\n", filename, width, height); + printf("depth: %d\n", depth); + printf("bits_per_pixel: %d\n", pcx.bits_per_pixel); printf("color_planes: %d\n", pcx.color_planes); printf("bytes_per_line: %d\n", pcx.bytes_per_line); printf("palette type: %s\n", @@ -218,43 +335,36 @@ Image *Read_PCX_to_Image(char *filename) /* allocate new image structure */ image = newImage(width, height, depth); - buffer_ptr = file_buffer + PCX_HEADER_SIZE; - buffer_last = file_buffer + file_length; - /* read compressed bitmap data */ - if ((buffer_ptr = PCX_ReadBitmap(image, buffer_ptr, buffer_last)) == NULL) + if (!PCX_ReadBitmap(file, &pcx, image)) { - free(file_buffer); + fclose(file); freeImage(image); errno_pcx = PCX_FileInvalid; return NULL; } - if (file_length < PCX_HEADER_SIZE + PCX_COLORMAP_SIZE) - { - /* PCX file is too short to contain a valid 256 colors colormap */ - fclose(file); - errno_pcx = PCX_ColorFailed; - return NULL; - } - /* read colormap data */ - if (!PCX_ReadColormap(image, buffer_ptr, buffer_last)) + if (!PCX_ReadColormap(file, &pcx, image)) { - free(file_buffer); + fclose(file); freeImage(image); + errno_pcx = PCX_ColorFailed; return NULL; } - free(file_buffer); + fclose(file); - /* determine number of used colormap entries */ - image->rgb.used = 0; - for (i=0; irgb.color_used[i]) - image->rgb.used++; + if (pcx_depth == 8) + { + /* determine number of used colormap entries for 8-bit PCX images */ + image->rgb.used = 0; + for (i=0; irgb.color_used[i]) + image->rgb.used++; + } #if PCX_DEBUG if (options.verbose) diff --git a/src/main.h b/src/main.h index 27cc057b..46d91120 100644 --- a/src/main.h +++ b/src/main.h @@ -1528,8 +1528,8 @@ extern int num_element_info; #define PROGRAM_VERSION_MAJOR 2 #define PROGRAM_VERSION_MINOR 0 -#define PROGRAM_VERSION_PATCH 1 -#define PROGRAM_VERSION_STRING "2.0.1" +#define PROGRAM_VERSION_PATCH 2 +#define PROGRAM_VERSION_STRING "2.0.2" #define PROGRAM_TITLE_STRING "Rocks'n'Diamonds" #define PROGRAM_AUTHOR_STRING "Holger Schemel" -- 2.34.1