procedure UNCRUNCH (var Addr1,Addr2; BlkLen:Integer); (* This is the routine for displaying crunched TheDraw image files. The crunched data format is a simple custom protocol for reproducing any image. The control codes below decimal 32 are reserved for this function. Characters 32 and above are written directly to the destination address. The following shows the format of a control code sequence. Please note that not all functions use the optional bytes or . Data Structure: [[]] 0..15 = New Foreground Color 16..23 = New Background Color 24 = Go down to next line, return to same horizontal position as when routine was started (akin to a c/r). 25 = Displays number of spaces. 26 = Displays number of . Also used to display ANY characters below #32. This function is the only way to do this although it uses three bytes. Otherwise the code would be interpreted as another command. 27 = Toggles on/off the foreground attribute blink flag. 28..31 = reserved ---------------------------------------------------------------------------- To use this routine, call the procedure with the crunched image data as the first parameter, the display address as the second parameter, and the length of the crunched image data as the third parameter. Assume we have an ImageData file of a 40 character by 10 line block. Also the following defintions. ie: { TheDraw Pascal Crunched Screen Image } const <- This CONST area is IMAGEDATA_WIDTH = 40; generated by TheDraw IMAGEDATA_DEPTH = 10; IMAGEDATA_LENGTH = 467; IMAGEDATA : array [1..467] of Char = (...list of image bytes here...); type ScreenType = array [0..3999] of Byte; var ScreenAddr : ScreenType absolute $B800:$0000; begin UnCrunch (IMAGEDATA,ScreenAddr[ (34*2) + (5*160) -162],IMAGEDATA_LENGTH); end; SCREENADDR is a variable mapped to the same location as the physical video addresses (via Turbo's absolute addressing). The rather messy array offset tells UnCrunch where to start displaying the ImageData block. The 34*2 indicates the horizontal position number 34 with the 5*160 indicating line number 5. This is similar to a Turbo GOTOXY (34,5) statement. The original horizontal starting offset is remembered by the uncrunch routine. The offset is restored upon moving down to the next line. This permits a block to be displayed correctly anywhere on the screen. ie: ÚÄ horizontal starting offset V +-------------------------------------------------+ | | | | <- Assume this | | is the video | ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ | display. | ³ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ³ | | ³ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ³ | | ³ÛÛ ImageData block ÛÛ³ | | ³ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ³ | | ³ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ³ | | ³ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ³ | | ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ | | | | | | | +-------------------------------------------------+ The ImageData block could just as well have been display in the upper-left corner of the screen with: UNCRUNCH (IMAGEDATA,ScreenAddr[ (1*2) + (1*160) -162],IMAGEDATA_LENGTH); Notice the array address changed to the equivilant of GOTOXY (1,1); To display the block in the lower-right corner you would use: UNCRUNCH (IMAGEDATA,ScreenAddr[ (40*2) + (15*160) -162],IMAGEDATA_LENGTH); In this example, the block is 40 characters wide by 10 lines deep. Thus, to display such a large block, we must display the block at GOTOXY (40,15); That's it! The routine was designed for easy use and understanding; however, for some people the best way is to experiment. Create a program using the above examples, perhaps with a 40x10 block (or any size). Good luck! *) begin inline ( $1E/ { PUSH DS ;Save data segment.} $C5/$B6/ADDR1/ { LDS SI,[BP+Addr1] ;Source Address} $C4/$BE/ADDR2/ { LES DI,[BP+Addr2] ;Destination Addr} $8B/$8E/BLKLEN/ { MOV CX,[BP+BlkLen] ;Length of block} $E3/$5B/ { JCXZ Done} $8B/$D7/ { MOV DX,DI ;Save X coordinate for later.} $33/$C0/ { XOR AX,AX ;Set Current attributes.} $FC/ { CLD} $AC/ {LOOPA: LODSB ;Get next character.} $3C/$20/ { CMP AL,32 ;If a control character, jump.} $72/$05/ { JC ForeGround} $AB/ { STOSW ;Save letter on screen.} $E2/$F8/ {Next: LOOP LOOPA} $EB/$4C/ { JMP Short Done} {ForeGround:} $3C/$10/ { CMP AL,16 ;If less than 16, then change the} $73/$07/ { JNC BackGround ;foreground color. Otherwise jump.} $80/$E4/$F0/ { AND AH,0F0H ;Strip off old foreground.} $0A/$E0/ { OR AH,AL} $EB/$F1/ { JMP Next} {BackGround:} $3C/$18/ { CMP AL,24 ;If less than 24, then change the} $74/$13/ { JZ NextLine ;background color. If exactly 24,} $73/$19/ { JNC FlashBitToggle ;then jump down to next line.} $2C/$10/ { SUB AL,16 ;Otherwise jump to multiple output} $02/$C0/ { ADD AL,AL ;routines.} $02/$C0/ { ADD AL,AL} $02/$C0/ { ADD AL,AL} $02/$C0/ { ADD AL,AL} $80/$E4/$8F/ { AND AH,8FH ;Strip off old background.} $0A/$E0/ { OR AH,AL} $EB/$DA/ { JMP Next} {NextLine:} $81/$C2/$A0/$00/ { ADD DX,160 ;If equal to 24,} $8B/$FA/ { MOV DI,DX ;then jump down to} $EB/$D2/ { JMP Next ;the next line.} {FlashBitToggle:} $3C/$1B/ { CMP AL,27 ;Does user want to toggle the blink} $72/$07/ { JC MultiOutput ;attribute?} $75/$CC/ { JNZ Next} $80/$F4/$80/ { XOR AH,128 ;Done.} $EB/$C7/ { JMP Next} {MultiOutput:} $3C/$19/ { CMP AL,25 ;Set Z flag if multi-space output.} $8B/$D9/ { MOV BX,CX ;Save main counter.} $AC/ { LODSB ;Get count of number of times} $8A/$C8/ { MOV CL,AL ;to display character.} $B0/$20/ { MOV AL,32} $74/$02/ { JZ StartOutput ;Jump here if displaying spaces.} $AC/ { LODSB ;Otherwise get character to use.} $4B/ { DEC BX ;Adjust main counter.} {StartOutput:} $32/$ED/ { XOR CH,CH} $41/ { INC CX} $F3/$AB/ { REP STOSW} $8B/$CB/ { MOV CX,BX} $49/ { DEC CX ;Adjust main counter.} $E0/$AA/ { LOOPNZ LOOPA ;Loop if anything else to do...} $1F); {Done: POP DS ;Restore data segment.} end; {UNCRUNCH}