'=========================================================================== ' Subject: FAST 320X200X256 PCX VIEWER Date: 09-02-96 (10:10) ' Author: Jonathan Leger Code: QB, QBasic, PDS ' Origin: leger@mail.dtx.net Packet: GRAPHICS.ABC '=========================================================================== '***** PCX.BAS ***************************************************** '*** The original code for this routine was found in VGAPCX.BAS *** '*** At first I optomized the code in that file, and eventually *** '*** I ended up re-writing the whole thing. That PCX loader did *** '*** a number of things differently, including loading the color *** '*** palette _last_. This routine loads the palette first, so *** '*** you can see the "correct" picture as the PCX is loading. In *** '*** addition to that, I use all integers for speed and load the *** '*** file in chunks of 2,000 bytes (instead of 1 byte at a time, *** '*** as in the other routine, VGAPCX.BAS). I thank the uknown *** '*** author of that original version, VGAPCX.BAS, because if he *** '*** had not put out that sample code, this PCX loader would not *** '*** be possible. *** '******************************************************************* '*** On a 486dx2-66, the old version (VGAPCX.BAS) loaded the PCX *** '*** in about 21 seconds. This new version does so in about 1.5 *** '*** seconds. The speed varies depending on the level of file *** '*** compression attained by the PCX file. *** '******************************************************************* DEFINT A-Z DECLARE SUB ShowPCX (file$) '*** If you're using Qbasic 1.1, change this line to '*** ShowPCX ".pcx" ShowPCX COMMAND$ WHILE INKEY$ = "": WEND SCREEN 0: WIDTH 80 '*** Loads a Version 5, 320x200x256c PCX file. '*** If you have any questions or comments about any of this code, '*** please contact me, Jonathan Leger, at leger@mail.dtx.net. SUB ShowPCX (file$) SCREEN 13 DIM pcxpal AS STRING * 768, pcxversion AS STRING * 1 pcxnum = FREEFILE OPEN file$ FOR BINARY AS #pcxnum '*** Get the PCX version from the header. GET #pcxnum, 2, pcxversion '*** If we're using version 5, then load the palette. IF ASC(pcxversion) = 5 THEN '*** Grab the palette out of the file. GET #1, LOF(pcxnum) - 767, pcxpal '*** Start with color 0. pal = 0 '*** Grab the red/green/blue value from our palette (PCXPAL) and '*** send them to the monitor using OUT. FOR p = 1 TO 768 STEP 3 OUT &H3C8, pal red% = INT(ASC(MID$(pcxpal, p, 1)) / 4) OUT &H3C9, red% green% = INT(ASC(MID$(pcxpal, p + 1, 1)) / 4) OUT &H3C9, green% blue% = INT(ASC(MID$(pcxpal, p + 2, 1)) / 4) OUT &H3C9, blue% pal = pal + 1 NEXT p END IF '*** Jump past the file header. SEEK #pcxnum, 129 '*** We'll be sending the output the the screen, so our segment '*** is &HA000 (VGA screen memory) and our offset is 0. You can '*** change these values to, say, decompress the image into an '*** array or something. fxoffset = 0: fxsegment = &HA000 '*** We'll be reading chunks of 2,000 bytes. You can increase or '*** decrease this depending on your needs. I noticed little or '*** no difference when the chunk size went past 2,000, so I left '*** it at 2,000 to add as little over-head as possible with maximum '*** speed. datasize = 2000 '*** Load our first chunk of data and point to the beginning of that '*** data. pcxdata$ = INPUT$(datasize, pcxnum) datacount = 1 '*** To increase speed, we'll be drawing the screen in two loops, '*** that way we can use integers to point to the next pixel instead '*** of long integers. Doing this gains tremendous speed. FOR half = 1 TO 2 '*** On the second loop, this will add &H7D0 (32000) to our '*** segment so we'll be writing to the second half of the screen. '*** On the first loop, this will simply set our segment to &HA000. fxtotal = fxsegment + fxoffset DEF SEG = fxtotal FOR c = 0 TO 31999 '*** If we're out of data, then we need to load the next chunk. IF datacount > datasize THEN pcxdata$ = INPUT$(datasize, pcxnum) datacount = 1 END IF '*** Get the next byte from our data chunk. clr = ASC(MID$(pcxdata$, datacount, 1)) datacount = datacount + 1 '*** If we're out of data, then we load the next chunk. IF datacount > datasize THEN pcxdata$ = INPUT$(datasize, pcxnum) datacount = 1 END IF '*** If the byte we pulled from the data has bit 6 and 7 set, '*** (which would make the value greater than 192), then that '*** means we'll be repeating a color. So we pull the next '*** byte from our data chunk (which is the color), and put '*** it on the screen CLR - 192 times (in other words, we '*** take the value of the first 5 bits in the byte and put '*** the pixel to the screen that many times.) IF clr > 192 THEN LPS = clr - 192 clr = ASC(MID$(pcxdata$, datacount, 1)) datacount = datacount + 1 FOR L = LPS TO 1 STEP -1 POKE c, clr c = c + 1 NEXT L c = c - 1 ELSE '*** Since the byte was less than 192, then we just poke the '*** pixel to the screen. POKE c, clr END IF NEXT c '*** We'll move to the second half of the screen by adding 32,000 '*** (HEX = 7D0) bytes to our segment value. fxoffset = fxoffset + &H7D0 NEXT half '*** All done! Close the file. CLOSE pcxnum '*** Return to BASIC's default segment. Very important! DEF SEG END SUB