#include #include #include //#include #include "xlib_all.h" /*-------------------------------------------------------------------------*/ /* ILBM320 by Mark E. Kern. The following source code may be used, */ /* modified, copied and shared with no obligation to the author */ /* whatsoever, as long as this notice accompanies the source. */ /* Please direct any questions to GEnie:MKERN1 or CS:70670,3120. */ /* Code written in Borland C++ in ANSI C mode. Sept 9,1991 */ /* ------------------------------------------------------------------------*/ /***************************************************************************\ ** ** * SHOWLBM by Todd Michael Lewis * * * * August 27, 1994 * * * * Using Mark E. Kern's code for the display of ILBMs, this routine was * * developed to show ILBMs using the XLIB graphic display library with a * * call to showLBM(x, y, LBM_FILE). * * * ** ** \***************************************************************************/ char testPBM[14] = { 3, 1, 1,1,1, 1,1,1, 1,1,0, 1,0,0, }; /* This defines the key information header contained in the ILBM format */ struct headform{ long flen; char msg2[8]; long hlen; int width; int length; int xoff; int yoff; char planes; char masking; char compression; char padbyte; int transparent; char x_aspect; char y_aspect; int screenWidth; int screenHeight; }; /* Structure used to store RGB values as they are read from the file */ struct RGBColor { char red; char green; char blue; }; char RGBpalette[768]; int ReadHeader(FILE *picFile, struct headform *header); int ReadCMap(FILE *picFile, struct headform *header); int DumpToScreen(FILE *picFile, struct headform *header, long page); void drawline(int *yoffset,unsigned char Vbuff[322], int *scanline,long page,int maxLines); long ReverseLong(long num); int ReverseWord(int num); int expo(int x,int y); void setDAC(struct RGBColor pallete[256]); /* expo calculates x^y and returns it as an integer value. */ int expo(int x,int y){ int answer=x; while(y > 1){ answer = answer * x; --y; } return(answer); } /* This code reverses the byte order in the long values read in from the file. This is to satisfy Intel's byte ordering scheme. */ long ReverseLong(long num){ long actualnum; actualnum = ((num >> 24) & 0x000000ff) | ((num >> 8) & 0x0000ff00) | ((num << 8) & 0x00ff0000) | ((num << 24) & 0xff000000); return(actualnum); } /* This code reverses the byte order in the word values read in from the file. This is to satisfy Intel's byte ordering scheme. */ int ReverseWord(int num){ int actualnum; actualnum = ((num >> 8) & 0x00ff) | ((num << 8) & 0xff00); return(actualnum); } /* main asks for the ILBM file to diplay, opens the file, and then proceeds to: 1)Init the graphics. 2)Read in the major header information. 3)Read in the color map and set the DAC registers. 4)Dump the image line by line from the file to the screen. 5)Wait for a keypress before closing up the file and shutting down. */ void showLBM(int startX, int startY, char *filename, long page) { FILE *picFile; struct headform header; picFile = fopen(filename,"rb"); ReadHeader(picFile,&header); ReadCMap(picFile,&header); DumpToScreen(picFile,&header, page); fclose(picFile); } /* ReadHeader takes a file pointer and starts to read in values into the header structure previously defined. It first checks to see if the file is an ILBM file by looking for the word "FORM", which should be in the beginning of the file. */ int ReadHeader(FILE *picFile, struct headform *header){ int err; char form[5]; fread(form,4,1,picFile); form[4]='\0'; if(strcmp("FORM",form) != 0) return(1); fread(&header->flen,sizeof(header->flen),1,picFile); fread(&header->msg2,8,1,picFile); fread(&header->hlen,4,1,picFile); fread(&header->width,sizeof(header->width),1,picFile); fread(&header->length,sizeof(header->length),1,picFile); fread(&header->xoff,sizeof(header->xoff),1,picFile); fread(&header->yoff,sizeof(header->yoff),1,picFile); fread(&header->planes,sizeof(header->planes),1,picFile); fread(&header->masking,sizeof(header->masking),1,picFile); fread(&header->compression,sizeof(header->compression),1,picFile); fread(&header->padbyte,sizeof(header->padbyte),1,picFile); fread(&header->transparent,sizeof(header->transparent),1,picFile); fread(&header->x_aspect,sizeof(header->x_aspect),1,picFile); fread(&header->y_aspect,sizeof(header->y_aspect),1,picFile); fread(&header->screenWidth,sizeof(header->screenWidth),1,picFile); fread(&header->screenHeight,sizeof(header->screenHeight),1,picFile); /* Finished loading in the header, now reverse the values to make them Intel compatible. */ header->flen = ReverseLong(header->flen); header->hlen = ReverseLong(header->hlen); header->width = ReverseWord(header->width); header->length = ReverseWord(header->length); header->xoff = ReverseWord(header->xoff); header->yoff = ReverseWord(header->yoff); header->transparent = ReverseWord(header->transparent); header->screenWidth = ReverseWord(header->screenWidth); header->screenHeight = ReverseWord(header->screenHeight); return(0); } /* ReadCMap first looks for the CMAP text in the file which denotes the beginning of the color information. Once it finds the CMAP header, it checks to see if the number of colors(x 3 for numbytes) matches the length of the CMAP, which is read in after the header. If everything is ok, it then loads up the array pallete with the rgb values contained in the CMAP section of the file. ReadCMap then calls setDAC to load the video DAC registers with the appropriate values. */ int ReadCMap(FILE *picFile, struct headform *header){ char form[5]; long CMAPsize; struct palettetype pal; unsigned char rgbTuple[3]; int x; int numColors; struct RGBColor pallete[256]; fread(form,4,1,picFile); form[4]='\0'; if(strcmp("CMAP",form) != 0) return(1); fread(&CMAPsize,sizeof(CMAPsize),1,picFile); CMAPsize=ReverseLong(CMAPsize); numColors=expo(2,header->planes); if(CMAPsize != (numColors*3)) return(1); for(x=0;x>2; pallete[x].green = rgbTuple[1]>>2; pallete[x].blue = rgbTuple[2]>>2; RGBpalette[x*3] = rgbTuple[0]>>2; RGBpalette[x*3+1] = rgbTuple[1]>>2; RGBpalette[x*3+2] = rgbTuple[2]>>2; } setDAC(pallete); return(0); } /* setDAC uses some pretty sophisticated funtions of Borland C. We first set up a bunch of variables to hold CPU register values in type REGS. Once we have done this, we can make some low level calls to the video BIOS to set up the colors we want in the picture. We enter a loop that sets each register to a RGB color combination and calls the BIOS routine to set the specific DAC register we are interesed in. */ void setDAC(struct RGBColor pallete[256]) { union REGS regs; int i; /* This sets up each of the 16 pallete entries to enable the proper DAC register when the pallete value is combined with the pixel value. */ /* for(i=0;i<16;++i){ regs.h.ah = 0x10; regs.h.al = 0x00; regs.h.bh = i; regs.h.bl = i; int86(0x10,®s,®s); } regs.h.bl = 0x00; for (i=0;i<256;++i){ regs.h.ah = 0x10; /* set specific DAC rgb register value */ // regs.h.al = 0x10; /* subfunction number, set register */ // regs.h.ch = pallete[i].green; /* CH contains the green value */ // regs.h.cl = pallete[i].blue; /* CL contains the blue value */ // regs.h.dh = pallete[i].red; /* DH contains the red value */ // int86(0x10, ®s, ®s); /* int 10h */ // ++regs.h.bl; // }*/ x_put_pal_raw(RGBpalette, 256, 0); } /* DumpToScreen unpacks the graphics information contained in the file. It first searches for the BODY header which precedes the actual graphics data. If we don't find the BODY header, the program will just crash, since I don't look out for the end of the file here. Once it finds the header, it reads in the next value, which is the length of the body. We use this value to read in the the next n number of bytes as specified by the body length. ILBM seems to use a run length encoding scheme to pack the data. The function looks at the first byte read. If the first byte read in is between -1 and -127, then this means we are to read in the next byte value, and repeat this value 1 to 127 times depending on the first byte value we read. I.E. if the first value we read was -1, we read the next value and repeat this value in the scanline 2 times (1-(-1)). If the header value was -128, we would do nothing, as this is the no-operation code. If the header value, call this n,is between 0 and 128, we interpret this to mean the next n bytes are to be read in normally and stuffed into the scanline without any sort of expansion or processing. Once this function has read enough bytes to make up a scanline (320 bytes in VGA mode 13h), we call a routine that dumps the scanline we just built to the screen. We keep doing this until we run out of bytes to read. Note that it is possible for an image to have more than 200 scanlines of data, but our scanline dump routine ignores lines past 200. */ int DumpToScreen(FILE *picFile, struct headform *header, long page){ int yoffset=0; /* the y coord of the scanline */ int index=0; /* index into the scanline array */ int pixelsToGo=0; /* number of pixels to go to form a line*/ int i; /* loop counter */ int maxLines = header->length; unsigned char Vbuff[322]; /* buffer to hold the scanline. It is 4 bytes longer than the regular length so it can hold hsize and vsize data for the putimage call */ int repeat; /* how many times to repeat the byte*/ char repeatValue; /* raw byte value from file */ char bufValue; /* raw buffer value read from file*/ long size; /* size of the BODY segment */ long bytesToGo; /* bytes to go till end of BODY */ char form[5]; /* holds header */ fread(form,4,1,picFile); form[4]='\0'; while(strcmp("BODY",form) != 0){ /* find the BODY */ form[0]=form[1]; form[1]=form[2]; form[2]=form[3]; form[3]=fgetc(picFile); } fread(&size,sizeof(size),1,picFile); bytesToGo = ReverseLong(size); // Vbuff[0]=(320-1) & 0xff; /* set up height and width of our scanline. Since we use putimage to dump our scanline, we have to tell it how big the 'shape' we are drawing to the screen is. In our case the shape is 320x1 in size.*/ // Vbuff[1]=(320-1) >> 8; // Vbuff[2]=1; // Vbuff[3]=0; Vbuff[0] = 160; Vbuff[1] = 1; index = index+2; // index = index+4; /* update the index into the scanline */ /* Check to see if the compression is of the proper type, which in our case is 1. If it is uncompressed, or if we don't know the compression type, we exit the program. */ if(header->compression != 1) return(1); while(bytesToGo > 0) { fread(&repeatValue,1,1,picFile); if(ferror(picFile)) { } --bytesToGo; repeat = repeatValue; if (repeat == -128); else if((repeat <= -1) && (repeat >= -127)) { fread(&bufValue,1,1,picFile); if(ferror(picFile)) { } --bytesToGo; for (i=0;i<(1-repeat);++i) { Vbuff[pixelsToGo+4-index] = bufValue; ++pixelsToGo; if(pixelsToGo == 320) drawline(&yoffset,Vbuff,&pixelsToGo,page, maxLines); } } else if((repeat >= 0) && (repeat <= 127)) { for(i=0;i<=repeat;++i) { fread(&(Vbuff[pixelsToGo+4-index]),1,1,picFile); if(ferror(picFile)) { } --bytesToGo; ++pixelsToGo; if(pixelsToGo == 320) drawline(&yoffset,Vbuff,&pixelsToGo,page,maxLines); } } /*end if*/ }/*end while bodysize*/ return(0); } /* drawline takes an array containing the scanline data we have just read in, and dumps it to the screen using the putimage call in the Borland BGI. The function then increments the yvalue to point to the next scanline, then resets the pixels to go value (scanline) to 0 again. If we are currently working on a scanline greater than can fit on the screen (i.e. greater than 200), we just ignore it and don't draw it to the screen. */ void drawline(int *yoffset,unsigned char Vbuff[322], int *scanline,long page, int maxLines) { // must split image because CHAR cannot hold a length of 320 unsigned char PBMbuff[162]; char *imagePtr; if(*yoffset <= maxLines) // putimage(0,*yoffset,Vbuff,COPY_PUT); imagePtr = Vbuff; x_bm_to_pbm(imagePtr, PBMbuff); x_put_pbm(0,*yoffset,page,PBMbuff); Vbuff[160] = 160; Vbuff[161] = 1; imagePtr+=160; x_bm_to_pbm(imagePtr, PBMbuff); x_put_pbm(160,*yoffset,page,PBMbuff); ++*yoffset; *scanline=0; }