X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgfxloader.c;fp=src%2Fgfxloader.c;h=9a28f43541d85a40420b30655833bf729c820dff;hb=b2a0ff1ddd4430110b331129469dabb8ea7b6ba7;hp=0000000000000000000000000000000000000000;hpb=823bddb0d9cc63ddda17a2cd20266aa3b82bde38;p=rocksndiamonds.git diff --git a/src/gfxloader.c b/src/gfxloader.c new file mode 100644 index 00000000..9a28f435 --- /dev/null +++ b/src/gfxloader.c @@ -0,0 +1,1155 @@ +/*********************************************************** +* Rocks'n'Diamonds -- McDuffin Strikes Back! * +*----------------------------------------------------------* +* ©1995 Artsoft Development * +* Holger Schemel * +* 33659 Bielefeld-Senne * +* Telefon: (0521) 493245 * +* eMail: aeglos@valinor.owl.de * +* aeglos@uni-paderborn.de * +* q99492@pbhrzx.uni-paderborn.de * +*----------------------------------------------------------* +* gfxloader.c * +***********************************************************/ + +#include "gfxloader.h" + + + + + + +extern Window window; +extern void Delay(long); + + + + + + +#ifdef DEBUG +/* +#define DEBUG_GIF +#define DEBUG_ILBM +*/ +#endif + +struct IFF_ILBM_FORM_big_endian +{ + char magic_FORM[4]; + unsigned char chunk_size[4]; + char magic_ILBM[4]; +}; + +struct IFF_ILBM_BMHD_big_endian +{ + char Width[2], Height[2]; + char LeftEdge[2], TopEdge[2]; + char Depth; + char Mask; + char Compression; + char pad1; + char transparentColor[2]; + char xAspect, yAspect; + char pageWidth[2], pageHeight[2]; +}; + +struct IFF_ILBM_BMHD +{ + unsigned int Width, Height; + int LeftEdge, TopEdge; + unsigned int Depth; + unsigned int Mask; + unsigned int Compression; + unsigned char pad1; + unsigned int transparentColor; + unsigned int xAspect, yAspect; + int pageWidth, pageHeight; +}; + +static int ConvertXImageDepth(Display *, XImage **); +static int Read_GIF_to_Pixmap_or_Bitmap(Display *, char *, Pixmap *, int); + +#define READ_GIF_TO_BITMAP 0 +#define READ_GIF_TO_PIXMAP 1 + + +int Read_GIF_to_Bitmap(Display *display, char *filename, Pixmap *pixmap) +{ + printf("Read_GIF_to_Bitmap\n"); + + + + + return(Read_GIF_to_Pixmap_or_Bitmap(display, filename, + pixmap, READ_GIF_TO_BITMAP)); +} + +int Read_GIF_to_Pixmap(Display *display, char *filename, Pixmap *pixmap) +{ + printf("Read_GIF_to_Pixmap\n"); + + + + + return(Read_GIF_to_Pixmap_or_Bitmap(display, filename, + pixmap, READ_GIF_TO_PIXMAP)); +} + +int Read_GIF_to_Pixmap_or_Bitmap(Display *display, char *filename, + Pixmap *pixmap, int mode) +{ + XImage *image = NULL; + Pixmap new_pixmap = 0; + int return_code; + + *pixmap = 0; + return_code = Read_GIF_to_XImage(display, filename, &image); + if (return_code != GIF_Success) + return(return_code); + + if (image) + { + int screen = DefaultScreen(display); + Drawable root = RootWindow(display,screen); + int depth = DefaultDepth(display, screen); + int width = image->width; + int height = image->height; + + if (mode == READ_GIF_TO_BITMAP) + { + int i,x,y; + unsigned long black_pixel = BlackPixel(display,screen); + int bytes_per_line = (width+7) / 8; + int size = bytes_per_line * height; + char *data, *ptr; + + data = (char *)malloc(size); + if (!data) + return(GIF_NoMemory); + + ptr = data; + for(i=0;i filesize) + return(GIF_FileInvalid); + } + while(ch1); + + free(RawGIF); /* We're done with the raw data now... */ + +#ifdef DEBUG_GIF + fprintf(stderr, "done\n"); + fprintf(stderr, " Decompressing... "); +#endif + + /* Allocate the X Image */ + ImageData = (byte *) malloc(Width*Height); + if (!ImageData) + return(GIF_NoMemory); + + new_image = XCreateImage(display,visual,8,ZPixmap,0,ImageData, + Width,Height,8,Width); + if (!new_image) + return(GIF_NoMemory); + + BytesPerScanline = Width; + + + /* Decompress the file, continuing until you see the GIF EOF code. + * One obvious enhancement is to add checking for corrupt files here. + */ + + Code = ReadCode(); + while (Code != EOFCode) + { + /* Clear code sets everything back to its initial value, then reads the + * immediately subsequent code as uncompressed data. + */ + + if (Code == ClearCode) + { + CodeSize = InitCodeSize; + MaxCode = (1 << CodeSize); + ReadMask = MaxCode - 1; + FreeCode = FirstFree; + CurCode = OldCode = Code = ReadCode(); + FinChar = CurCode & BitMask; + AddToPixel(FinChar); + } + else + { + /* If not a clear code, then must be data: + * save same as CurCode and InCode + */ + + CurCode = InCode = Code; + + /* If greater or equal to FreeCode, not in the hash table yet; + * repeat the last character decoded + */ + + if (CurCode >= FreeCode) + { + CurCode = OldCode; + OutCode[OutCount++] = FinChar; + } + + /* Unless this code is raw data, pursue the chain pointed to by CurCode + * through the hash table to its end; each code in the chain puts its + * associated output code on the output queue. + */ + + while (CurCode > BitMask) + { + if (OutCount > 1024) + return(GIF_FileInvalid); + + OutCode[OutCount++] = Suffix[CurCode]; + CurCode = Prefix[CurCode]; + } + + /* The last code in the chain is treated as raw data. */ + + FinChar = CurCode & BitMask; + OutCode[OutCount++] = FinChar; + + /* Now we put the data out to the Output routine. + * It's been stacked LIFO, so deal with it that way... + */ + + for (i = OutCount - 1; i >= 0; i--) + AddToPixel(OutCode[i]); + OutCount = 0; + + /* Build the hash table on-the-fly. No table is stored in the file. */ + + Prefix[FreeCode] = OldCode; + Suffix[FreeCode] = FinChar; + OldCode = InCode; + + /* Point to the next slot in the table. If we exceed the current + * MaxCode value, increment the code size unless it's already 12. If it + * is, do nothing: the next code decompressed better be CLEAR + */ + + FreeCode++; + if (FreeCode >= MaxCode) + { + if (CodeSize < 12) + { + CodeSize++; + MaxCode *= 2; + ReadMask = (1 << CodeSize) - 1; + } + } + } + Code = ReadCode(); + } + + free(Raster); + +#ifdef DEBUG_GIF + fprintf(stderr, "done\n"); + fprintf(stderr," %d colors used\n",numused); +#endif + + if (file != stdin) + fclose(file); + + if (ColorDicking(display) != GIF_Success) + return(GIF_ColorFailed); + + *image = new_image; + return(GIF_Success); +} + + +/* Fetch the next code from the raster data stream. The codes can be + * any length from 3 to 12 bits, packed into 8-bit bytes, so we have to + * maintain our location in the Raster array as a BIT Offset. We compute + * the byte Offset into the raster array by dividing this by 8, pick up + * three bytes, compute the bit Offset into our 24-bit chunk, shift to + * bring the desired code to the bottom, then mask it off and return it. + */ + +static int ReadCode() +{ + int RawCode, ByteOffset; + + ByteOffset = BitOffset / 8; + RawCode = Raster[ByteOffset] + (0x100 * Raster[ByteOffset + 1]); + if (CodeSize >= 8) + RawCode += (0x10000 * Raster[ByteOffset + 2]); + RawCode >>= (BitOffset % 8); + BitOffset += CodeSize; + return(RawCode & ReadMask); +} + + +static void AddToPixel(byte Index) +{ + if (YC= Height) + { + Pass++; + YC = 4; + } + break; + + case 1: + YC += 8; + if (YC >= Height) + { + Pass++; + YC = 2; + } + break; + + case 2: + YC += 4; + if (YC >= Height) + { + Pass++; + YC = 1; + } + break; + + case 3: + YC += 2; + break; + + default: + break; + } + } + } +} + + +static int ColorDicking(Display *display) +{ + /* we've got the picture loaded, we know what colors are needed. get 'em */ + + register int i,j; + static byte lmasks[8] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80}; + byte lmask, *ptr; + int screen = DefaultScreen(display); + Colormap cmap = DefaultColormap(display,screen); + int dispcells = DisplayCells(display,screen); + + int strip = 0; + int nostrip = 0; + + if (!HasColormap) + return(GIF_Success); + /* no need to allocate any colors if no colormap in GIF file */ + + /* Allocate the X colors for this picture */ + + if (nostrip) + { + /* nostrip was set. try REAL hard to do it */ + for (i=j=0; i>8)) + + abs(g - (ctab[j].green>>8)) + + abs(b - (ctab[j].blue>>8)); + if (d=0; i--) + if (used[i]) + XFreeColors(display,cmap,cols+i,1,0L); + } + else + break; + } + +#ifdef DEBUG_GIF + if (j && strip<8) + fprintf(stderr,"%s: stripped %d bits\n",progname,strip); +#endif + + if (strip==8) + { + fprintf(stderr,"UTTERLY failed to allocate the desired colors.\n"); + for (i=0; idepth == %d\n", + (*image)->depth); + printf("DefaultDepth(display, screen) == %d\n", + DefaultDepth(display, screen)); + + + + + if ((*image)->depth != depth) + { + XImage *old_image, *new_image; + /* + Visual *visual = DefaultVisual(display,screen); + */ + int width = (*image)->width; + int height = (*image)->height; + register int dwx, dwy; + byte *data; + + + + + + printf("ConvertXImageDepth: ---------> CONVERTING...\n"); + + + + + + + data = (byte *)malloc(width * height * depth); + old_image = *image; + + /* + new_image = XCreateImage(display,visual,depth, + ZPixmap,0,data,width,height,8,0); + */ + + new_image = XGetImage(display,RootWindow(display,screen), + 0,0,width,height,0xffffffff,ZPixmap); + + + if (!new_image) + return(GIF_NoMemory); + + if (old_image->depth == 8 && new_image->depth == 4) + { + /* speedup for the most common format change */ + + register byte *sptr = (byte *)old_image->data; + register byte *dptr = (byte *)new_image->data; + + for (dwy=1; dwy<=height; dwy++) + { + for (dwx=1; dwx 4 bit */ + { + unsigned long pixel_value; + + for (dwx=0; dwx 0xff) + printf("pixel = %lx", pixel_value); + + XPutPixel(new_image, dwx, dwy, pixel_value); + } + } + } + + free(old_image->data); + old_image->data = NULL; + XDestroyImage(old_image); + + *image = new_image; + } + + return(GIF_Success); +} + + +static unsigned long be2long(unsigned char *be) /* big-endian -> long int */ +{ + return((be[0]<<24) | (be[1]<<16) | (be[2]<<8) | be[3]); +} + +static unsigned short be2short(unsigned char *be) /* big-endian -> short int */ +{ + return((be[0]<<8) | be[1]); +} + +static struct IFF_ILBM_BMHD *ConvertBMHD(unsigned char *header_data) +{ + struct IFF_ILBM_BMHD_big_endian *bmhd_be; + struct IFF_ILBM_BMHD *bmhd; + + bmhd_be = (struct IFF_ILBM_BMHD_big_endian *)header_data; + bmhd = (struct IFF_ILBM_BMHD *)malloc(sizeof(struct IFF_ILBM_BMHD)); + if (!bmhd) + return(NULL); + + bmhd->Width = be2short(bmhd_be->Width); + bmhd->Height = be2short(bmhd_be->Height); + bmhd->LeftEdge = be2short(bmhd_be->LeftEdge); + bmhd->TopEdge = be2short(bmhd_be->TopEdge); + bmhd->Depth = (int)bmhd_be->Depth; + bmhd->Mask = (int)bmhd_be->Mask; + bmhd->Compression = (int)bmhd_be->Compression; + bmhd->pad1 = bmhd_be->pad1; + bmhd->transparentColor = be2short(bmhd_be->transparentColor); + bmhd->xAspect = (int)bmhd_be->xAspect; + bmhd->yAspect = (int)bmhd_be->yAspect; + bmhd->pageWidth = be2short(bmhd_be->pageWidth); + bmhd->pageHeight = be2short(bmhd_be->pageHeight); + + return(bmhd); +} + +static unsigned char MSBitFirst2LSBitFirst(unsigned char msb_byte) +{ + unsigned char lsb_byte = 0; + int i; + + for(i=7;i>=0;i--) + { + lsb_byte |= (msb_byte & 1) << i; + msb_byte >>= 1; + } + + return(lsb_byte); +} + +int Read_ILBM_to_Bitmap(Display *display, char *filename, Pixmap *pixmap) +{ + Pixmap new_pixmap = 0; + int screen = DefaultScreen(display); + Drawable root = RootWindow(display,screen); + struct IFF_ILBM_FORM_big_endian *form_header; + struct IFF_ILBM_BMHD *bitmap_header; + unsigned long file_len, body_len; + unsigned char *file_data, *bitmap_data; + unsigned char *file_ptr, *bitmap_ptr, *body_ptr; + unsigned char byte_count, byte_value; + int i,x,y,z; + int width, height, depth; + int bytes_per_line, bitmap_size; + FILE *file; + + + + + + printf("Read_ILBM_to_Bitmap\n"); + + + + + if (!(file = fopen(filename,"r"))) + return(ILBM_OpenFailed); + + if (fseek(file,0,SEEK_END) < 0) + { + fclose(file); + return(ILBM_ReadFailed); + } + + file_len = ftell(file); + rewind(file); + + if (!(file_data = (unsigned char *)malloc(file_len))) + { + fclose(file); + return(ILBM_NoMemory); + } + + if (fread(file_data,1,file_len,file) != file_len) + { + free(file_data); + fclose(file); + return(ILBM_ReadFailed); + } + + fclose(file); + + form_header = (struct IFF_ILBM_FORM_big_endian *)file_data; + + if (strncmp(form_header->magic_FORM,"FORM",4) || + file_len != be2long(form_header->chunk_size)+8 || + strncmp(form_header->magic_ILBM,"ILBM",4)) + { +#ifdef DEBUG_ILBM + printf("%s: IFF chunk 'FORM' and/or 'ILBM' not found.\n",filename); +#endif + free(file_data); + return(ILBM_FileInvalid); + } + + bitmap_header = NULL; + body_ptr = NULL; + file_ptr = file_data + 12; + + while(file_ptr < (unsigned char *)(file_data + file_len)) + { + if (!strncmp(file_ptr,"BMHD",4)) + { +#ifdef DEBUG_ILBM + printf("%s: IFF chunk 'BMHD' found.\n",filename); +#endif + bitmap_header = ConvertBMHD(file_ptr + 8); + file_ptr += be2long(file_ptr + 4) + 8; + continue; + } + else if (!strncmp(file_ptr,"BODY",4)) + { +#ifdef DEBUG_ILBM + printf("%s: IFF chunk 'BODY' found.\n",filename); +#endif + body_ptr = file_ptr + 8; + body_len = be2long(file_ptr + 4); + file_ptr += be2long(file_ptr + 4) + 8; + continue; + } + else + { +#ifdef DEBUG_ILBM + printf("%s: IFF chunk '%c%c%c%c' found (but not used).\n",filename, + file_ptr[0],file_ptr[1],file_ptr[2],file_ptr[3]); +#endif + /* other chunk not recognized here */ + file_ptr += be2long(file_ptr + 4) + 8; + continue; + } + } + + if (!bitmap_header || !body_ptr) + { +#ifdef DEBUG_ILBM + printf("%s: IFF chunk 'BMHD' and/or 'BODY' not found.\n",filename); +#endif + free(file_data); + return(ILBM_FileInvalid); + } + + width = bitmap_header->Width; + height = bitmap_header->Height; + depth = bitmap_header->Depth; + +#ifdef DEBUG_ILBM + if (depth > 1) + printf("%s: %d bitplanes found; using only the first plane.\n", + filename,depth); +#endif + + bytes_per_line = ((width + 15) / 16) * 2; + bitmap_size = bytes_per_line * height; + + bitmap_data = (char *)malloc(bitmap_size); + if (!bitmap_data) + { + free(file_data); + free(bitmap_header); + return(ILBM_NoMemory); + } + + bitmap_ptr = bitmap_data; + for(i=0;iCompression) + { + while(x++ < bytes_per_line) + *bitmap_ptr++ |= MSBitFirst2LSBitFirst(*body_ptr++); + } + else + { + while(x < bytes_per_line) + { + byte_count = *body_ptr++; + + if (byte_count <= 128) + { + for(i=0;i