'PCX viewer. 'Only works for 256 color .pcx files, at 320x200 resolution (for now:) 'Original idea from Dave Navarro. 'Changes by Mark Phllips and Al Musella, DPM 'Source code formatted by BFLite, by James Davis. 'The sample .pcx figure was done by my son, Zachary Musella, 2 1/2 years old! 'See the attached file: pcx.txt for details on how to decode pcx files 'This is released to the public domain. Use at your own risk! 'Compare the speed of this to Vpic! $LIB ALL - $DYNAMIC DEFINT A - Z TYPE Pcxheader Mfg AS BYTE Ver AS BYTE Enc AS BYTE Bpp AS BYTE Xmin AS INTEGER Ymin AS INTEGER Xmax AS INTEGER Ymax AS INTEGER Hres AS INTEGER Vres AS INTEGER Pal AS STRING * 48 Resrv AS BYTE Colpl AS BYTE Bpl AS INTEGER Paltyp AS INTEGER Filler AS STRING * 58 END TYPE DIM Header AS SHARED Pcxheader DIM Times AS SHARED BYTE DIM Chunksize AS SHARED WORD DIM Maxscrnptr AS SHARED WORD DIM Fsize AS SHARED LONG DIM Textofst AS SHARED WORD DIM Handle AS SHARED INTEGER DIM Buffer AS SHARED STRING * 32256 Chunksize = 32256 Disfile$ = COMMAND$ 'file to DISplay IF Disfile$ = "" THEN COLOR 14, 1 CLS PRINT " .PCX Viewer" PRINT " This viewer only works with 300x200x256 .pcxs for now!" FILES "*.pcx" INPUT "PCX file to Display: (Don't include the .pcx):", Disfile$ ELSE Disfile$ = REMOVE$(Disfile$, ".PCX") END IF F$ = DIR$(Disfile$ + ".PCX") IF F$ = "" THEN PRINT "No File Found" END END IF T1# = TIMER CALL pcxdisplay(F$) T6# = TIMER A$ = INPUT$(1) CALL pcxResetScreen PRINT F$; " took "; using"###.######"; (T6# - T1#); PRINT " seconds to display!" END SUB PcxDisplay(F$) 'display .pcx f$ on screen - only works for mode 13h now 'Set up the buffer to hold raw data Textofst = VARPTR(Buffer) 'the seg = ds for fixed len string 'Open the file and get the dos handle and file size OPEN F$ FOR BINARY ACCESS READ SHARED AS #1 Handle = FILEATTR(1, 2) 'The dos handle for this file Fsize& = LOF(1) 'Make sure we can do this file Get# 1, , Header IF Header.mfg <> 10 AND Header.ver <> 5 THEN PRINT "Not a 256 color PCX file!" END END IF Wid = Header.xmax - Header.xmin Dep = Header.ymax - Header.ymin IF Wid + 1 > 320 OR Dep + 1 > 200 THEN PRINT "is too big for Mode 13h" END ELSE PRINT END IF 'Load PCX Palette (have to divide the raw values by 4 to 'get them into 256 color format Tmp& = LOF(1) - 768 Seek# 1, Tmp& 'this is where the pallette data is stored DIM Palete AS STRING * 768 ' GET$ 1, 768, Palete 'read it all in in 1 chunk 'Now divide each entry by 4 to scale to 256 color Paloff?? = VARPTR(Palete) ! mov AX,DS ;set es=ds to set up stosb ! mov ES,AX ! mov CX,768 ! mov AX,Paloff?? ! mov SI,AX ;let si and di point to palete string ! mov DI,AX PalShift: ! Lodsb ;al<-ds:si incr si ! shr AL,1 ! shr AL,1 ;divide by 4 (quickly:) 'shift bug ! Stosb ! loop Palshift Seek# 1, 128 ' go to beginning of graphic data 'Set the graphics mode 320x200x256 ! mov AX,&H0013 ; set mode 13h ! int &H10 'set up the new pallette Palptr = VARPTR(Palete) Palseg = VARSEG(Palete) ! mov AX,&H1012 ;set new palette ! mov BX,0 ! mov CX,256 ! mov DX,Palptr ! mov ES,Palseg ! int &H10 Maxscrnptr?? = (Wid + 1) * (Dep + 1) 'points to the highest posible postion on screen CALL pcxshow 'actually decodes and displays the file CLOSE 1 END SUB SUB PCXshow() 'must be called from PCXDisplay - not directly! 'Set up es:di to point to next location on screen ! mov AX,&h0A000 ! mov ES,AX ;es points to VGA buffer ! mov DI,0 ;di holds screen offset pcx1: ! call getchunk ;returns cx=buffersize, si offset of buffer pcx2: ! or CX,CX ;if cx=0, we are done ! jz pcxdone ! mov BL,[Si] ;bl now holds the color byte ! inc SI ! dec CX ! jnz pcx2a ! call getchunk ! or CX,CX ! jz pcxdone pcx2a: ! mov BH,1 ;bh holds run count, assume 1 for now ! mov AL,BL ! and AL,&hc0 ;check if the 2 most sig bits are set ! cmp AL,&hc0 ! jnz pcx3 ;if not run byte, just dispaly color al, bh Times ! mov AL,BL ! and AL,&h3f ! mov BH,AL ! mov BL,[Si] ;bl now holds the color byte ! inc SI ! dec CX ! jnz pcx3 ! call getchunk ! or CX,CX ! jz pcxdone pcx3: ! push CX ! push AX ! mov CX,0 ! mov CL,BH ! mov AL,BL ! rep Stosb ! pop AX ! pop CX ! mov AX,DI ! cmp AX,Maxscrnptr?? ! jnz pcx2 ! jmp pcxdone GetChunk: ' or the remaining portion of the file if <32256 bytes are left ' and returns cx with # of bytes in the string to process ' returns si with start of buffer in ds ! push AX ! push BX ! push DX ! mov AX,Fsize[00] ! mov BX,Fsize[02] ! mov CX,AX ! or CX,BX ! jz chunkdone ;if no more bytes left - exit the loop ! mov CX,Chunksize ! or BX,BX ! jnz Chunk2 ! cmp AX,CX ! ja Chunk2 ! mov CX,AX Chunk2: ! sub WORD Ptr Fsize[00],CX ! sbb WORD Ptr Fsize[02],0 ! mov AH,&h3F ! mov BX,Handle ! mov DX,Textofst ! int &h21 ! mov SI,DX ; cx=len si=offset ! pop DX ! pop BX ! pop AX ! cld chunkdone: ! retn PCXDone: END SUB SUB PCXResetScreen ! mov AX,3 ;'set text mode and reset palette ! int &h10 CLS END SUB