2000 ;ANIM.ASM grafikrutiner init_mouse PROTO C, max_x:WORD, max_y:WORD, start_x:WORD,start_y:WORD load_iff PROTO C, mode:WORD, fname:PTR BYTE, picseg:VARARG load_pcx PROTO C, mode:WORD, fname:PTR BYTE, picseg:VARARG line PROTO C, x1:WORD,y1:WORD,x2:WORD,y2:WORD,color:WORD ; box PROTO C, x1:WORD,y1:WORD,x2:WORD,y2:WORD ; setviewport PROTO C, ulx:WORD,uly:WORD,lrx:WORD,lry:WORD putspriteinv PROTO C, x:WORD,y:WORD,wide:WORD,deep:WORD, sprtseg:WORD,sprtoffs:WORD,destseg:WORD putsprite PROTO C, x:WORD,y:WORD,wide:WORD,deep:WORD, sprtseg:WORD,sprtoffs:WORD,destseg:WORD putimginv PROTO C,x:WORD,y:WORD,wide:WORD,deep:WORD, srcseg:WORD,destseg:WORD putimg PROTO C,x:WORD,y:WORD,wide:WORD,deep:WORD, srcseg:WORD,destseg:WORD PUBLIC set_mode13 PUBLIC set_mode3 PUBLIC get_mouse_event PUBLIC get_button_status PUBLIC exit_mouse PUBLIC vsync PUBLIC dis_refresh PUBLIC ena_refresh INCLUDE DOS.INC INCLUDE BIOS.INC .MODEL SMALL,C .386 .DOSSEG ;-------------------- musrutiner ------------------------ .DATA PUBLIC mousex PUBLIC mousey mousex dw 0 mousey dw 0 PUBLIC event_flags event_flags dw ? mousefreeze db ? .CODE mousehandler PROC FAR push ax push bx push dx push ds mov bx,@data mov ds,bx cmp byte ptr[mousefreeze],1 jz exit_handler mov mousex,cx ;update mouse coordinates mov mousey,dx mov cx,0 ;clear flags test ax,1 jz not_moved or cx,1 not_moved: test ax,2 ;Check Left button pressed jz not_leftbpress or cx,2 not_leftbpress: test ax,4 ;Check Left button released jz not_leftbrel or cx,4 not_leftbrel: test ax,8 ;Check right button pressed jz not_rightbpress or cx,8 not_rightbpress: test ax,16 ;Check right button released jz exit_handler or cx,16 exit_handler: mov event_flags,cx pop ds pop dx pop bx pop ax retf mousehandler ENDP init_mouse PROC C USES cx dx, max_x:WORD, max_y:WORD, start_x:WORD, start_y:WORD mov ax,0 ;Mouse driver function 0 -- reset and detect int 33h cmp ax,0 jz no_driver_installed mov mousefreeze,1 ;Freeze handler until installation completed mov dx,max_x ;Pixels horizontally mov ax,7 ;mouse driver function 7 -- set max x range mov cx,0 ;Minimum range int 33h mov dx,max_y ;Pixels vertically mov ax,8 ;mouse driver function 8 -- set max y range mov cx,0 ;Minimum range int 33h ; Now install user routine mov ax,cs mov es,ax mov dx, offset mousehandler mov cx,31 ;bits for calling routine mov ax,12 ;Function 12 -- set user routine int 33h mov cx,start_x ;xcoord mov dx,start_y ;ycoord mov ax,4 ;mouse driver function 4 -- set mouse position int 33h mov mousefreeze,0 ;Now the handler can start its work mov ax,1 no_driver_installed: ret init_mouse ENDP get_mouse_event PROC mov ax,event_flags mov event_flags,0 ret get_mouse_event ENDP get_button_status PROC mov ax,3 int 33h mov ax,bx ret get_button_status ENDP exit_mouse PROC mov ax,0 int 33h ret exit_mouse ENDP ;---------------------------------------------------------------------------- set_mode13 PROC mov ax, 0013h int 10h ret set_mode13 ENDP set_mode3 PROC mov ax, 0003h int 10h ret set_mode3 ENDP vsync PROC mov dx,3dah wt1: in al,dx test al,00001000b jnz wt1 wt2: in al,dx test al,00001000b ;wait until bit 4 is 1 jz wt2 ;indicating vertical blank started ret vsync ENDP dis_refresh PROC mov ah,12h mov al,1 mov bl,36h int 10h ret dis_refresh ENDP ena_refresh PROC mov ah,12h mov al,0 mov bl,36h int 10h ret ena_refresh ENDP ;------------------------------------------------------------------------ ;Extern procedur f”r att ladda en komprimerad IFF/ILBM fil i 320x200x256 ;Laddar in hela den komprimerade delen i minnet innan ;dekomprimering. Kr„ver mer fritt minne, men g†r mycket ;snabbare. ; ; anropas med INVOKE load_iff,,,[] ; mode: 0 = ladda direkt till bildminne ; 1 = skapa bildbuffert och ladda in till denna ; 2 = ladda in i redan allokerad buffert (bufferns segment anges som ; sista parameter) ; ; returv„rden: AX = -1 om fel,annars inladdad bilds segment om mode=1 ; BX = bildens bredd ; CX = bildens h”jd ;----------------------------------------------------------------------- read32bit MACRO add di,3 @Read di,1,handle dec di @Read di,1,handle dec di @Read di,1,handle dec di @Read di,1,handle ENDM read16bit MACRO add di,1 @Read di,1,handle dec di @Read di,1,handle ENDM w EQU word ptr calc_offs MACRO xchg ah,al ; ax=256*y add bx,ax ; bx=256*y+x shr ax,2 add bx,ax ; bx=320*y+x (+ offset in buffer if needed.) ENDM .DATA FORM dd 4d524f46h ILBM dd 4d424c49h BMHD dd 44484d42h CMAP dd 50414d43h BODY dd 59444f42h no_iffstr db 'This is not an IFF/ILBM file!',13,10,'$' no_compstr db 'Not a compressed IFF/ILBM file!',13,10,'$' vidseg dw 0a000h .DATA? comp_seg dw ? uncomp_seg dw ? handle dw ? img_size dw ? block_id dd ? block_len dd ? wdth dw ? hght dw ? xwdth dw ? planes db ? compress db ? inbyte db ? inbyte2 db ? scan dw ? plane db ? adr dw ? nxtline dw ? palbuf db 768 dup (?) BMHDbuf db 20 dup (?) .CODE load_iff PROC C, mode:WORD, fname:PTR BYTE, picseg:VARARG mov dx,fname @OpenFile dx,0 jc error mov handle,ax call read_lbmhdr jc error mov dx,w[block_len] add dx,15 shr dx,4 @GetBlock dx jc error mov comp_seg,ax mov di,dx push ds @Read 0,w[block_len],handle,comp_seg ;H„r laddas hela den pop ds ;komprimerade delen in cmp mode,0 jz mode_0 cmp mode,1 jz mode_1 cmp mode,2 jz mode_2 mode_0: ;Ladda direkt till bildminne mov es,vidseg jmp over_modes mode_1: ;Mode 1 = ladda till buffert mov ax,64000/16 ;buffert skapas i denna procedur @GetBlock ax jc error mov uncomp_seg,ax mov es,uncomp_seg jmp over_mode2 mode_2: mov es,picseg[0] ;Ladda till redan allokerad buffert over_mode2: mov di,0 mov eax,0 mov cx,64000/4 cld rep stosd ;Clear buffer over_modes: mov xwdth,320 mov gs,comp_seg mov si,0 mov scan,0 nxt_scan: mov plane,0 nxt_plane: mov bx,0 mov ax,scan calc_offs mov di,bx add bx,wdth mov bp,bx ;Index to next line mov cl,plane do_line: mov dl,gs:[si] inc si mov inbyte,dl cmp inbyte,128 ja repeat_byte jz next ; 80h = Pad byte mov bx,0 mov bl,inbyte lp1: mov dh,gs:[si] inc si mov dl,dh shr dl,7 and dl,1 shl dl,cl or es:[di],dl inc di mov dl,dh shr dl,6 and dl,1 shl dl,cl or es:[di],dl inc di mov dl,dh shr dl,5 and dl,1 shl dl,cl or es:[di],dl inc di mov dl,dh shr dl,4 and dl,1 shl dl,cl or es:[di],dl inc di mov dl,dh shr dl,3 and dl,1 shl dl,cl or es:[di],dl inc di mov dl,dh shr dl,2 and dl,1 shl dl,cl or es:[di],dl inc di mov dl,dh shr dl,1 and dl,1 shl dl,cl or es:[di],dl inc di mov dl,dh and dl,1 shl dl,cl or es:[di],dl inc di dec bl jns lp1 jmp next repeat_byte: mov dh,gs:[si] inc si mov bx,0 mov bl,inbyte not bl add bl,1 lp2: mov dl,dh shr dl,7 and dl,1 shl dl,cl or es:[di],dl inc di mov dl,dh shr dl,6 and dl,1 shl dl,cl or es:[di],dl inc di mov dl,dh shr dl,5 and dl,1 shl dl,cl or es:[di],dl inc di mov dl,dh shr dl,4 and dl,1 shl dl,cl or es:[di],dl inc di mov dl, 2000 dh shr dl,3 and dl,1 shl dl,cl or es:[di],dl inc di mov dl,dh shr dl,2 and dl,1 shl dl,cl or es:[di],dl inc di mov dl,dh shr dl,1 and dl,1 shl dl,cl or es:[di],dl inc di mov dl,dh and dl,1 shl dl,cl or es:[di],dl inc di dec bl jns lp2 next: cmp di,bp jb do_line inc plane mov dl,planes cmp plane,dl jb nxt_plane inc scan mov dx,hght cmp scan,dx jb nxt_scan mov es,comp_seg @FreeBlock ;Frig”r den tempor„ra inladdningsbufferten @CloseFile handle mov ax,uncomp_seg mov bx,wdth mov cx,hght ret error: mov ax,-1 ret load_iff ENDP read_lbmhdr PROC mov ax,ds mov es,ax lea di,block_id[0] @Read di,4,handle lea si,FORM[0] cmpsd jnz no_iff mov di,offset block_len @Read di,4,handle lea di,block_id[0] @Read di,4,handle lea si,ILBM[0] cmpsd jnz no_iff get_bmhd: lea di,block_id[0] @Read di,4,handle lea di,block_len[0] read32bit lea si,block_id[0] lea di,BMHD[0] cmpsd jz go_on1 @MovePtrRel handle,block_len jmp get_bmhd go_on1: mov di,offset BMHDbuf @Read di,20,handle mov bx,di mov dx,[bx] ror dx,8 mov wdth,dx mov dx,[bx+2] ror dx,8 mov hght,dx mov dl,[bx+8] mov planes,dl mov dl,[bx+10] mov compress,dl cmp byte ptr[compress],0 jz no_compress get_cmap: lea di,block_id[0] @Read di,4,handle lea di,block_len[0] read32bit lea si,block_id[0] lea di,CMAP[0] cmpsd jz go_on2 @MovePtrRel handle,block_len jmp get_cmap go_on2: mov di,offset palbuf @Read di,w[block_len],handle lea di,palbuf[0] mov cx,w[block_len] shiftpal: shr byte ptr[di],2 inc di loop shiftpal mov ah,10h ;Set palette mov al,12h mov bx,0 mov cx,256 mov dx,offset palbuf int 10h get_body: lea di,block_id[0] @Read di,4,handle lea di,block_len[0] read32bit lea si,block_id[0] lea di,BODY[0] cmpsd jz go_on3 @MovePtrRel handle,block_len jmp get_body go_on3: clc ret no_iff: mov ah,9 mov dx,offset no_iffstr int 21h stc ret no_compress: mov ah,9 mov dx,offset no_compstr int 21h stc ret read_lbmhdr ENDP ;------ Rutin f”r att ladda in en fil i PCX-format i 320x200x256 ---------- ; ; anropas med INVOKE load_pcx,,,[] ; mode: 0 = ladda direkt till bildminne ; 1 = skapa bildbuffert och ladda in till denna ; 2 = ladda in i redan allokerad buffert (bufferns segment anges som ; sista parameter) ; ; returv„rden: AX = -1 om fel,annars inladdad bilds segment om mode=1 ; BX = bildens bredd ; CX = bildens h”jd ;-------------------------------------------------------------------------- .DATA pcxhdrstruct STRUCT manufacturer db ? version db ? encoding db ? bitsPerPixel db ? xmin dw ? ymin dw ? xmax dw ? ymax dw ? hres dw ? vres dw ? palette db 48 dup (?) reserved db ? colourPlanes db ? bytesPerLine dw ? paletteType dw ? filler db 58 dup (?) pcxhdrstruct ENDS pcxhdr pcxhdrstruct <> no_pcxstr db 'This is not a PCX file!',13,10,'$' malloc_errstr db 'Not enough memory!',13,10,'$' comp_len dd ? end_of_line dw ? pal_start dd ? .CODE load_pcx PROC C, mode:WORD, fname:PTR BYTE, picseg:VARARG mov dx,fname @OpenFile dx,0 mov handle,ax jc error call read_pcxhdr jc error mov edx,comp_len add edx,15 shr edx,4 @GetBlock dx jc error mov comp_seg,ax mov di,0 mov si,comp_seg nxtblk: push ds @Read di,8000h,handle,si ;H„r laddas hela den pop ds ;komprimerade delen in cmp ax,8000h jnz end_reached add di,8000h jnz no_segchg add si,1000h ;change segment if needed no_segchg: jmp nxtblk end_reached: cmp mode,0 jz mode_0 cmp mode,1 jz mode_1 cmp mode,2 jz mode_2 mode_0: ;Ladda direkt till bildminne mov es,vidseg jmp over_modes mode_1: ;Mode 1 = ladda till buffert mov ax,64000/16 ;buffert skapas i denna procedur @GetBlock ax mov uncomp_seg,ax mov es,ax jmp over_modes mode_2: mov es,picseg[0] ;Ladda till redan allokerad buffert over_modes: mov fs,comp_seg mov si,0 mov di,0 mov dx,hght mov scan,dx nxt_line: mov dx,di add dx,pcxhdr.bytesPerLine mov end_of_line,dx nxt_byte: mov dl,fs:[si] inc si jnz no_segchg1 mov ax,fs add ax,1000h mov fs,ax no_segchg1: mov al,dl and al,0c0h cmp al,0c0h jnz just_store and dl,3fh xor cx,cx mov cl,dl mov dl,fs:[si] inc si jnz no_segchg2 mov ax,fs add ax,1000h mov fs,ax no_segchg2: run_lp: mov es:[di],dl inc di loop run_lp jmp over_juststore just_store: mov es:[di],dl inc di over_juststore: cmp di,end_of_line jb nxt_byte dec scan jnz nxt_line mov es,comp_seg @FreeBlock ;Frig”r den tempor„ra inladdningsbufferten @CloseFile handle mov ax,uncomp_seg mov bx,wdth mov cx,hght ret error: mov ax,-1 ret load_pcx ENDP read_pcxhdr PROC mov di,offset pcxhdr @Read di,128,handle cmp pcxhdr.manufacturer,0ah jnz no_pcx cmp pcxhdr.version,5 jnz no_pcx @GetFileSize handle ror eax,16 mov ax,dx rol eax,16 mov comp_len,eax sub comp_len,128 sub eax,768 mov pal_start,eax @MovePtrAbs handle,pal_start mov di,offset palbuf @Read di,768,handle ;L„s in palett lea di,palbuf[0] mov cx,768 shiftpal: shr byte ptr[di],2 inc di loop shiftpal mov ax,ds mov es,ax mov ah,10h ;Set palette mov al,12h mov bx,0 mov cx,256 mov dx,offset palbuf int 10h ;seek to start of image data @MovePtrAbs handle,128 mov dx,pcxhdr.xmax sub dx,pcxhdr.xmin add dx,1 mov wdth,dx mov dx,pcxhdr.ymax sub dx,pcxhdr.ymin add dx,1 mov hght,dx clc ret no_pcx: mov ah,9 mov dx,offset no_pcxstr int 21h stc ret read_pcxhdr ENDP ;***** ;***** line ;***** ; The following line routine is a modified version of code in Richard ; Wilton's book "Programmer's Guide to PC and PS/2 Video Systems". SCREENSEG EQU 0A000h PIXELADDR MACRO xchg ah,al ; ax=256*y add bx,ax ; bx=256*y+x shr ax,2 add bx,ax ; bx=320*y+x (+ offset in buffer if needed.) mov ax,SCREENSEG mov es,ax ; es:bx=address of pixel ENDM line PROC C, x1:WORD, y1:WORD, x2:WORD, y2:WORD, colour:WORD LOCAL VARincr1:WORD, VARincr2:WORD, VARroutine:WORD ; check for vertical lines mov si,320 ; initial y-increment mov cx,x2 sub cx,x1 ; cx=x2-x1 jz vertLine ; force x1 < x2 jns L01 ; jump if x1=0 neg cx ; force dy>=0 mov ax,bx ; ax=y2 L31: inc cx 2000 ; cx=# of pixels to draw mov bx,x1 ; bx=x PIXELADDR ; es:bx mov di,bx ; es:di dec si ; si=bytes/line-1 mov ax,colour L32: stosb add di,si ; next line loop L32 jmp Lexit ; routine for horizontal lines (slope=0) horizLine: mov ax,y1 mov bx,x1 PIXELADDR ; es:bx mov di,bx ; es:di mov ax,colour mov ah,al mov bx,ax shl eax,16 mov ax,bx inc cx mov dx,cx shr cx,2 rep stosd mov cx,dx and cx,0000000000000011b rep stosb jmp Lexit ; routine for dy<=dx (slope<=1) ; es:di -> video buffer ; bx=y-increment ; cx =# of pixels to draw ; si=decision variable loSlopeLine: mov ax,colour L11: stosb ; put pixel, increment x or si,si ; test sign of d jns L12 ; jump id d>=0 add si,VARincr1 ; d=d+incr1 loop L11 jmp Lexit L12: add si,VARincr2 ; d=d+incr2 add di,bx ; increment y loop L11 jmp Lexit ; routine for dy>dx (slope >1) ; es:di -> video buffer ; bx=y-increment ; cx=# of pixels to draw ; si=decision variable hiSlopeLine: mov ax,colour L21: stosb ; put pixel, increment x add di,bx ; increment y L22: or si,si ; test sign of d jns L23 ; jump if d>=0 add si,VARincr1 ; d=d+incr1 dec di ; dec x (inc by stosb) loop L21 jmp Lexit L23: add si,VARincr2 ; d=d+incr2 loop L21 Lexit: ret line ENDP ; .DATA ; ;ViewPortULX dw 0 ;ViewPortULY dw 0 ;ViewPortLRX dw 319 ;ViewPortLRY dw 199 ; ; .CODE ; ;setviewport PROC SYSCALL, ; ulx:WORD,uly:WORD,lrx:WORD,lry:WORD ; ; mov ax,ulx ; mov ViewPortULX,ax ; mov ax,uly ; mov ViewPortULY,ax ; mov ax,lrx ; mov ViewPortLRX,ax ; mov ax,lry ; mov ViewPortLRY,ax ; ret ; ;setviewport ENDP ULX = 0 ULY = 0 LRX = 319 LRY = 199 ;***** ;***** Draws a sprite with clipping in "Invisible" mode ;***** Any pixel with color value 0 is not written out ;***** parts taken from The Graphics Engine putspriteinv PROC C, x:WORD,y:WORD,wide:WORD,deep:WORD,sprtseg:WORD,sprtoffs:WORD,destseg:WORD mov si,sprtoffs mov cx,wide ;xsize mov dx,deep ; ysize mov ax,x cmp ax,LRX ; check x <= VIEWPORTLRX jg quit cmp ax,ULX ; check x >= VIEWPORTULX jl xLessThanMin checkxMax: mov ax,x add ax,cx ; right edge of image cmp ax,LRX jg truncateRightImage ; truncate if necessary checkyMin: mov ax,y cmp ax,LRY ; check y <= OUTVIEWPORTLRY jg quit cmp ax,ULY ; check y >= OUTVIEWPORTULY jl yLessThanMin checkyMax: mov ax,y add ax,dx ; bottom of image cmp ax,LRY jg truncateBottomImage ; truncate if necessary jmp drawImage ; jump to draw logic xLessThanMin: ; clip x to 0 mov bx,ULX mov x,bx sub bx,ax add si,bx sub cx,bx cmp cx,0 jle quit ; quit if offscreen jmp checkxMax quit: ; exit routine ret truncateRightImage: ; truncate the excess of right edge sub ax,LRX ; ax=right edge from before dec ax sub cx,ax jmp checkyMin yLessThanMin: ; clip y to VIEWPORTULY mov bx,ULY mov y,bx sub bx,ax sub dx,bx cmp dx,0 jle quit ; quit if offscreen push dx push cx mov ax,bx mov cx,320 mul cx pop cx pop dx add si,ax jmp checkyMax truncateBottomImage: ; clip y to OUTVIEWPORTLRY sub ax,LRY dec ax sub dx,ax cmp dx,0 ; quit if no lines left jle quit ; fall through to drawImage drawImage: ; label for @@yGreaterThanMax jmp ; calculate the pixel address mov es,destseg mov di,x mov ax,y xchg ah,al ; ax=256*y add di,ax ; di=256*y+x shr ax,2 ; ax=64*y add di,ax ; di=320*y+x push ds mov ds,sprtseg mov ax,320 sub ax,cx ; update destAdd push bp mov bp,ax mov bx,cx xor ch,ch y_lp: mov ax,bx x_lp: mov cl,ds:[si] jcxz skip_palreg0 mov es:[di],cl skip_palreg0: inc si inc di dec ax jnz x_lp add si,bp ;next line add di,bp dec dx jnz y_lp pop bp pop ds ret putspriteinv ENDP ;***** Draws a sprite with clipping in "replace" mode ;***** parts taken from The Graphics Engine ;***** putsprite PROC C, x:WORD,y:WORD,wide:WORD,deep:WORD,sprtseg:WORD,sprtoffs:WORD,destseg:WORD mov si,sprtoffs mov cx,wide ;xsize mov dx,deep ;ysize mov ax,x cmp ax,LRX ; check x <= VIEWPORTLRX jg quit cmp ax,ULX ; check x >= VIEWPORTULX jl xLessThanMin checkxMax: mov ax,x add ax,cx ; right edge of image cmp ax,LRX jg truncateRightImage ; truncate if necessary checkyMin: mov ax,y cmp ax,LRY ; check y <= OUTVIEWPORTLRY jg quit cmp ax,ULY ; check y >= OUTVIEWPORTULY jl yLessThanMin checkyMax: mov ax,y add ax,dx ; bottom of image cmp ax,LRY jg truncateBottomImage ; truncate if necessary jmp drawImage ; jump to draw logic xLessThanMin: ; clip x to 0 mov bx,ULX mov x,bx sub bx,ax add si,bx sub cx,bx cmp cx,0 jle quit ; quit if offscreen jmp checkxMax quit: ; exit routine ret truncateRightImage: ; truncate the excess of right edge sub ax,LRX ; ax=right edge from before dec ax sub cx,ax jmp checkyMin yLessThanMin: ; clip y to VIEWPORTULY mov bx,ULY mov y,bx sub bx,ax sub dx,bx cmp dx,0 jle quit ; quit if offscreen push dx push cx mov ax,bx mov cx,320 mul cx pop cx pop dx add si,ax jmp checkyMax truncateBottomImage: ; clip y to OUTVIEWPORTLRY sub ax,LRY dec ax sub dx,ax cmp dx,0 ; quit if no lines left jle quit ; fall through to drawImage drawImage: mov es,destseg ; CALCULATE PIXEL ADDRESS mov di,x mov ax,y xchg ah,al ; ax=256*y add di,ax ; di=256*y+x shr ax,2 ; ax=64*y add di,ax ; di=320*y+x push ds mov ds,sprtseg mov ax,320 sub ax,cx ; update destAdd mov bx,cx ; BX = CX jmp LoopA ; jump to loop entry point LoopB: mov cx,bx ; CX = line length in bytes add di,ax ; update DI add si,ax ; and SI LoopA: shr cx,2 ; CX = line length in dwords rep movsd ; move the dwords mov cx,bx ; restore CX and cx,0000000000000011b ; CX = number of residual bytes rep movsb ; move the residual bytes, if any dec dx ; decrement loop counter jnz LoopB ; restart loop if necesary pop ds jmp quit ; done loop, quit putsprite ENDP ; putimginv copies an area from one segment to another with the same ; x and y coordinates for src and dest. Invisible mode. putimginv PROC C, x:WORD,y:WORD,wide:WORD,deep:WORD,srcseg:WORD,destseg:WORD LOCAL x2:WORD,y2:WORD,dest_x:WORD,dest_y:WORD mov dx,x mov dest_x,dx add dx,wide sub dx,1 mov x2,dx mov dx,y mov dest_y,dx add dx,deep sub dx,1 mov y2,dx ; mov bx,ViewportULX ; preload for speed ; mov cx,ViewportLRX mov ax,x ; clip x1 cmp ax,ULX jge L1b mov x,ULX jmp L2a L1b: cmp ax,LRX jle L2a ret L2a: mov ax,x2 ; clip x2 cmp ax,ULX jge L2b ret L2b: cmp ax,LRX jle L3a mov x2,LRX L3a: ; mov bx,ViewportULY ; preload for speed ; mov cx,ViewportLRY mov a f3a x,y ; clip y1 cmp ax,ULY jge L3b mov y,ULY jmp L4a L3b: cmp ax,LRY jle L4a ret L4a: mov ax,y2 ; clip y2 cmp ax,ULY jge L4b ret L4b: cmp ax,LRY jle L5 mov y2,LRY L5: mov es,destseg mov di,dest_x mov ax,dest_y cmp di,ULX jge destx_ok mov di,ULX destx_ok: cmp ax,ULY jge desty_ok mov ax,ULY desty_ok: ; calculate dest offset xchg ah,al ; ax=256*y add di,ax ; di=256*y+x shr ax,2 ; ax=64*y add di,ax ; di=320*y+x push ds mov ds,srcseg mov ax,x2 ;calculate source width sub ax,x inc ax push ax ;save source width for later mov si,x ;Calculate source offset mov ax,y xchg ah,al ; ax=256*y add si,ax ; si=256*y+x shr ax,2 add si,ax ; si=320*y+x (+ offset in buffer if needed.) mov ax,x2 ; calculate srcAdd sub ax,x mov dx,319 sub dx,ax push dx ; save srcAdd for later mov ax,y2 ; y loop counter sub ax,y mov dx,ax inc dx pop ax ; pop srcAdd pop cx ; pop source width push bp mov bp,ax mov bx,cx xor ch,ch y_lp: mov ax,bx x_lp: mov cl,ds:[si] jcxz skip_palreg0 mov es:[di],cl skip_palreg0: inc si inc di dec ax jnz x_lp add si,bp ;next line add di,bp dec dx jnz y_lp pop bp pop ds ret putimginv ENDP ; putimg copies an area from one segment to another with the same ; x and y coordinates for src and dest. Replace mode. putimg PROC C, x:WORD,y:WORD,wide:WORD,deep:WORD,srcseg:WORD,destseg:WORD LOCAL x2:WORD,y2:WORD,dest_x:WORD,dest_y:WORD mov dx,x mov dest_x,dx add dx,wide sub dx,1 mov x2,dx mov dx,y mov dest_y,dx add dx,deep sub dx,1 mov y2,dx ; mov bx,ViewportULX ; preload for speed ; mov cx,ViewportLRX mov ax,x ; clip x1 cmp ax,ULX jge L1b mov x,ULX jmp L2a L1b: cmp ax,LRX jle L2a ret L2a: mov ax,x2 ; clip x2 cmp ax,ULX jge L2b ret L2b: cmp ax,LRX jle L3a mov x2,LRX L3a: ; mov bx,ViewportULY ; preload for speed ; mov cx,ViewportLRY mov ax,y ; clip y1 cmp ax,ULY jge L3b mov y,ULY jmp L4a L3b: cmp ax,LRY jle L4a ret L4a: mov ax,y2 ; clip y2 cmp ax,ULY jge L4b ret L4b: cmp ax,LRY jle L5 mov y2,LRY L5: mov es,destseg mov di,dest_x mov ax,dest_y cmp di,ULX jge no_x_adj mov di,ULX no_x_adj: cmp ax,ULY jge no_y_adj mov ax,ULY no_y_adj: ; calculate dest offset xchg ah,al ; ax=256*y add di,ax ; di=256*y+x shr ax,2 ; ax=64*y add di,ax ; di=320*y+x push ds mov ds,srcseg mov ax,x2 ;calculate source width sub ax,x inc ax push ax ;save source width for later mov si,x ;Calculate source offset mov ax,y xchg ah,al ; ax=256*y add si,ax ; si=256*y+x shr ax,2 add si,ax ; si=320*y+x (+ offset in buffer if needed.) mov ax,x2 ; calculate srcAdd sub ax,x mov dx,319 sub dx,ax push dx ; save srcAdd for later mov ax,y2 ; y loop counter sub ax,y mov dx,ax inc dx pop ax ; pop srcAdd pop cx ; pop source width mov bx,cx ; BX = CX jmp LoopB ; jump to loop entry point LoopA: mov cx,bx ; CX = line length in bytes add si,ax ; update SI add di,ax ; update DI LoopB: shr cx,2 ; CX = line length in dwords rep movsd ; move the dwords mov cx,bx ; restore CX and cx,0000000000000011b ; CX = number of residual bytes rep movsb ; move the residual bytes, if any dec dx ; decrement loop counter jnz LoopA ; restart loop if necesary pop ds ret putimg ENDP END . 0