/* ** ILBM file loader by John Romero (C) 1990 PCRcade ** ** Loads and decompresses an ILBM-format file to the ** screen in either CGA, EGA or MCGA -- compressed or ** or unpacked! ** ** Merely pass the filename of the image to LoadLBM ** and sit back! The proper graphics mode is initialized ** and the screen (or brush) is loaded and displayed! ** */ struct LBMinfo { int width,height,planes; } CurrentLBM; #include #include #include #include #include #include #define SC_index 0x3c4 #define SC_mapmask 2 /* ** FUNCTION PROTOTYPES */ void GetChunkID(char far *buffer,char *tempstr); int NextChunkID(char far *buffer); void far *Decompress(char far *buffer,char *unpacked,int bpwidth,char planes); void far *SetupLBM(char *filename); void Do_CGA_Screen(char far *buffer,char compress,char planes,int width,int height); void Do_EGA_Screen(char far *buffer,char compress,char planes,int width,int height,int scrwidth); void Do_MCGA_Screen(char far *buffer,char compress,int width,int height); void EGA_MoveBitplane(char far *from,char far *to,int bpwidth); char typestr[5],far *startbuff; // EGA loader NOTE: the "scrwidth" var should be 0=320 mode,1=640 mode void LoadLBM(char *filename,int scrwidth,int graphflag) { char far *buffer,far *cmap; char planes, tempstr[5], compress; int handle, width, height; if((buffer = SetupLBM(filename))==NULL) exit(1); /* ** Need to get BMHD info, like: ** - screen width, height ** - # of bitplanes ** - compression flag (YES/NO) */ CurrentLBM.width=width = (*(buffer+9)&0xFF)+(*(buffer+8)*256); CurrentLBM.height=height = (*(buffer+11)&0xFF)+(*(buffer+10)*256); CurrentLBM.planes=planes = *(buffer+16); compress = *(buffer+18); /* if ((strcmp(typestr,"PBM ")!=0)&&(planes==8)) { printf("This VGA screen is not in PBM format, but ILBM, which I\ncannot decode at this time.\n"); exit(1); }*/ /* ** Find the CMAP chunk so I can remap the registers... */ movedata(FP_SEG(buffer),FP_OFF(buffer),_DS,(unsigned)tempstr,4); tempstr[4]=0; while (strcmp(tempstr,"CMAP")!=0) { buffer += NextChunkID(buffer); movedata(FP_SEG(buffer),FP_OFF(buffer),_DS,(unsigned)tempstr,4); } cmap = buffer+8; /* ** Now, find the BODY chunk... */ movedata(FP_SEG(buffer),FP_OFF(buffer),_DS,(unsigned)tempstr,4); while (strcmp(tempstr,"BODY")!=0) { buffer += NextChunkID(buffer); movedata(FP_SEG(buffer),FP_OFF(buffer),_DS,(unsigned)tempstr,4); } /* ** Found the BODY chunk! Here we go! */ buffer += 8; /* point to actual data */ /* Turn graphics mode on, if desired */ if (graphflag==1) { switch (planes) { case 2: { _AX=4; geninterrupt(0x10); break; } case 4: { _AX=0x0d; geninterrupt(0x10); scrwidth=0; break; } case 8: { _AX=0x13; geninterrupt(0x10); break; } } } switch (planes) { case 2: Do_CGA_Screen(buffer,compress,planes,width,height); break; case 4: Do_EGA_Screen(buffer,compress,planes,width,height,scrwidth); break; case 8: { unsigned int i; for (i=0;i<0x300;i++) (unsigned char)*cmap++ >>= 2; cmap -= 0x300; // reset to beginning again _BX = 0; _CX = 0x100; _ES = FP_SEG(cmap); _DX = FP_OFF(cmap); _AX = 0x1012; geninterrupt(0x10); Do_MCGA_Screen(buffer,compress,width,height); break; } default: { printf("This screen has %d bitplanes. I don't understand that sort of stuff.\n",planes); exit(); } } farfree((void far *)startbuff); } //============================================== //= //= Load a *LARGE* file into a FAR buffer! //= by John Romero (C) 1990 PCRcade //= //============================================== unsigned long LoadFile(char *filename,char far *buffer) { unsigned int handle,flength1,flength2,buf1,buf2,foff1,foff2; FILE *f; buf1=FP_OFF(buffer); buf2=FP_SEG(buffer); asm mov WORD PTR foff1,0 // file offset = 0 (start) asm mov WORD PTR foff2,0 f=fopen(filename,"r+b"); if (f==NULL) goto out; handle=fileno(f); /*asm push ds asm lds dx, filename asm mov ax,3d00h // OPEN w/handle (read only) asm int 21h asm jc out asm pop ds */ //asm mov handle,ax asm mov bx,ax asm xor cx,cx asm xor dx,dx asm mov ax,4202h asm int 21h // SEEK (find file length) asm jc out asm mov flength1,ax asm mov flength2,dx asm mov cx,flength2 asm inc cx // <- at least once! L_1: asm push cx asm mov cx,foff2 asm mov dx,foff1 asm mov ax,4200h asm int 21h // SEEK from start asm push ds asm mov bx,handle asm mov cx,-1 asm mov dx,buf1 asm mov ax,buf2 asm mov ds,ax asm mov ah,3fh // READ w/handle asm int 21h asm pop ds asm pop cx asm jc out asm cmp ax,-1 asm jne out asm push cx // need to read the last byte asm push ds // into the segment! IMPORTANT! asm mov bx,handle asm mov cx,1 asm mov dx,buf1 asm add dx,-1 asm mov ax,buf2 asm mov ds,ax asm mov ah,3fh asm int 21h asm pop ds asm pop cx asm add buf2,1000h asm inc WORD PTR foff2 asm loop L_1 out: asm mov bx,handle // CLOSE w/handle asm mov ah,3eh asm int 21h return (flength2*0x10000+flength1); } void far *SetupLBM(char *filename) { int handle; char far *buffer; char tempstr[64]; buffer = startbuff = (char far *)farmalloc(0xf000); if (buffer==NULL) return(NULL); strupr(filename); if (strstr(filename,".")==NULL) strcat(filename,".LBM"); LoadFile(filename,buffer); GetChunkID(buffer,tempstr); if (strcmp(tempstr,"FORM")!=0) { printf("This isn't in ILBM FORM format file!\n"); return(NULL); } /* ** point past the FORM chunk ** and see if this really IS ** and ILBM file */ buffer += 8; GetChunkID(buffer,tempstr); strcpy(typestr,tempstr); // save file type if ((strcmp(tempstr,"ILBM")!=0) && (strcmp(tempstr,"PBM ")!=0) ) { printf("This isn't an ILBM format file!\n"); return(NULL); } /* ** point to BMHD chunk, the first NORMAL chunk! */ buffer += 4; GetChunkID(buffer,tempstr); if (strcmp(tempstr,"BMHD")!=0) { printf("What kind of ILBM is this? There's no BMHD chunk!\n"); return(NULL); } return(buffer); } void GetChunkID(char far *buffer,char *tempstr) { movedata(FP_SEG(buffer),FP_OFF(buffer),_DS,(unsigned)tempstr,4); tempstr[4]=0; } int NextChunkID(char far *buffer) { unsigned int newoffset; newoffset = (*(buffer+7)&0xFF) + (*(buffer+6)*256); if ((newoffset & 1)==1) newoffset += 1; return(newoffset+8); /* +8 because chunk + offset = 8 bytes! */ } /* ** CGA loader */ void Do_CGA_Screen(char far *buffer,char compress,char planes,int width,int height) { unsigned int bpwidth, loopY, loopX, loopB, offset, data; char far *screen, b1, b2, unpacked[80]; bpwidth = width/8; for (loopY=0;loopY>= 2; b1 >>= 1; b2 >>= 1; } */ *screen = data >> 8; *(screen+1) = data; screen += 2; } if (compress==0) buffer += bpwidth*planes; } } /* ** EGA loader (NOTE: the "scrwidth" var should be 0=320 mode,1=640 mode */ void Do_EGA_Screen(char far *buffer,char compress,char planes,int width,int height,int scrwidth) { unsigned int bpwidth, loopY, loopX, loopB, offset, data; char far *screen = (char far *)0xa0000000, b1, b2, unpacked[160]; bpwidth = width/8; for (loopY=0;loopY>tloop2); } movedata(_DS,(unsigned)unpacked1,FP_SEG(screen),FP_OFF(screen),width); } else movedata(_DS,(unsigned)unpacked,FP_SEG(screen),FP_OFF(screen),width); } else { movedata(FP_SEG(buffer),FP_OFF(buffer),FP_SEG(screen),FP_OFF(screen),width); buffer += width; } screen = MK_FP(0xa000,FP_OFF(screen)+320); } } /* ** ILBM's RLE decompressor. Merely pass the address of the compressed ** ILBM bitplane data, where to unpack it, the # of bytes each bitplane ** takes up, and the # of bit planes to unpack. */ void far *Decompress(char far *buffer,char *unpacked,int bpwidth,char planes) { int count, offset, loopP; unsigned char byte, rept; for (loopP=0;loopP 0x80) { rept = (rept^0xff)+2; byte = *(buffer+1); buffer+=2; memset(unpacked,byte,rept); } else if (rept < 0x80) { rept++; movedata(FP_SEG(buffer),FP_OFF(buffer)+1,_DS,(unsigned) unpacked,rept); buffer += rept+1; } count += rept; unpacked += rept; } while (count