;----------------------------------------------------------------------- ; MODULE XCLIPPBM ; ; This module was written by Matthew MacKenzie ; matm@eng.umd.edu ; ; Clipped transfer of planar bitmaps from system memory to video memory. ; ; Compile with TASM. ; C near-callable. ; ; ****** XLIB - Mode X graphics library **************** ; ****** **************** ; ****** Written By Themie Gouthas **************** ; ; egg@dstos3.dsto.gov.au ; teg@bart.dsto.gov.au ;----------------------------------------------------------------------- include xlib.inc include xclippbm.inc .data align 2 ; global clipping variables _TopBound dw (?) _BottomBound dw (?) _LeftBound dw (?) _RightBound dw (?) ; VGA plane masks ColumnMask db 011h,022h,044h,088h ; bit delay timers LeftDelay db 0, 1, 2, 4 RightDelay db 0, 4, 2, 1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; _x_clip_pbm ; ; C near-callable as: ; ; void x_clip_pbm (int X, int Y, int ScreenOffs, char far * Bitmap); ; ; Bitmap is a planar bitmap, in the regular Xlib format. ; ; ax, bx, cx, and dx go south. .code public _x_clip_pbm align 2 _x_clip_pbm proc ARG X:word, Y:word, ScreenOffs:word, Bitmap:dword LOCAL left_counter, right_counter,column,clipped_height,clipped_width,screen_pos,bitmap_pos,bitmap_size,VGA_mask,width_copy,height_temp,screen_width:word=LocalStk ; Tasm 1.0 does not allow the \ line continuation ;LOCAL left_counter:word, right_counter:word, \ ; column:word, clipped_height:word, clipped_width:word, \ ; screen_pos:word, bitmap_pos:word, bitmap_size:word, \ ; VGA_mask:word, width_copy, height_temp:word, \ ; screen_width:word=LocalStk push bp mov bp, sp sub sp, LocalStk push si push di push ds ; sociopathic cases: are the clipping bounds out of order? mov ax, _TopBound cmp ax, _BottomBound jg @@GetOut mov ax, _LeftBound cmp ax, _RightBound jle @@ReasonableAndProper @@GetOut: ; return a 1 -- no image drawn pop ds pop di pop si mov ax, 1 mov sp, bp pop bp ret @@ReasonableAndProper: ; we need to use both the tables in ds and the height and width of the bitmap les si, Bitmap ; vertical position xor cx, cx mov cl, byte ptr es:[si + 1] ; height of bitmap xor ax, ax mov al, byte ptr es:[si] ; width of bitmap mul cx mov bitmap_size, ax mov ax, Y cmp ax, _BottomBound ; top edge below clipping box? jg @@GetOut mov bx, cx add bx, ax dec bx ; bottom edge = Y + height - 1 cmp bx, _TopBound jl @@GetOut sub bx, _BottomBound ; bottom margin = bottom edge - BottomBound jle @@NoBottomBound sub cx, bx ; clip bottom margin from height @@NoBottomBound: mov bx, _TopBound sub bx, ax ; top margin = TopBound - Y jle @@NoTopBound add ax, bx ; top edge = Y + top margin sub cx, bx ; clip top margin from height jmp @@KeepMargin @@NoTopBound: xor bx, bx @@KeepMargin: mov clipped_height, cx mul _ScrnLogicalByteWidth mov di, ax add di, ScreenOffs ; row of upper-left corner of blit mov cl, byte ptr es:[si] ; width of bitmap (ch is still 0 from height) mov ax, cx mul bx add si, ax add si, 2 ; starting position in bitmap ; horizontal position mov width_copy, cx mov dx, X cmp dx, _RightBound jg @@GetOut mov dx, 0 ; unclipped value for right delay mov ax, cx shl ax, 2 ; width in pixels add ax, X dec ax ; right edge = X + width in pixels - 1 cmp ax, _LeftBound jl @@GetOut sub ax, _RightBound ; right margin = right edge - RightBound jle @@NoRightBound mov bx, ax and bx, 3 mov dl, RightDelay[bx] shr ax, 2 sub cx, ax ; subtract clipped bytes from width @@NoRightBound: mov right_counter, dx mov dx, 0 ; unclipped value for left delay mov ax, _LeftBound sub ax, X ; left margin = LeftBound - X jle @@NoLeftBound mov bx, ax and bx, 3 mov dl, LeftDelay[bx] add ax, 3 shr ax, 2 ; left margin/4, rounded up sub cx, ax ; subtract clipped bytes from width add si, ax ; move starting position in bitmap past margin add di, ax ; move starting position on screen past margin @@NoLeftBound: mov left_counter, dx mov clipped_width, cx mov ax, X ; add x coordinate to screen position mov bx, ax sar ax, 2 add di, ax mov dx, SC_INDEX mov al, MAP_MASK out dx, al inc dx and bx, 3 ; initial mask xor ax, ax mov al, ColumnMask[bx] mov VGA_mask, ax out dx, al ; initial mask mov column, 4 mov bitmap_pos, si mov screen_pos, di mov ax, _ScrnLogicalByteWidth mov screen_width, ax ; since we move ds ; we've used all our tables, so we can change ds to point to the bitmap, ; and es to point to the screen mov ds, word ptr [Bitmap + 2] mov ax, SCREEN_SEG mov es, ax cld ; strings go forward mov bx, width_copy sub bx, clipped_width ; bytes to advance one line in bitmap ; let's actually draw something for a change @@WritePlane: mov ax, clipped_height mov height_temp, ax mov dx, screen_width sub dx, clipped_width ; bytes to advance one line across screen @@WriteLine: mov cx, clipped_width shr cx, 1 rep movsw ; in they went, two by two... adc cx, 0 rep movsb ; catch stray last byte, if it's there add si, bx ; advance one bitmap line add di, dx ; advance one screen line dec height_temp jnz @@WriteLine dec column jz @@OuttaHere ; only four columns per customer, please mov dx, SC_INDEX + 1 rol byte ptr VGA_mask, 1 adc screen_pos, 0 ; add to location if we've wrapped to plane 0 mov al, byte ptr VGA_mask out dx, al ; set VGA for next column shr right_counter, 1 jnc @@NoRightCounter dec clipped_width ; cut off right edge for later planes inc bx @@NoRightCounter: shr left_counter, 1 jnc @@NoLeftCounter inc clipped_width ; add to left edge for later planes dec bx dec bitmap_pos dec screen_pos @@NoLeftCounter: mov si, bitmap_pos add si, bitmap_size mov bitmap_pos, si mov di, screen_pos jmp @@WritePlane @@OuttaHere: ; return a 0 -- something was inside the boundary pop ds pop di pop si mov ax, 0 mov sp, bp pop bp ret _x_clip_pbm endp ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; _x_clip_masked_pbm ; ; C near-callable as: ; ; void x_clip_masked_pbm (int X, int Y, int ScreenOffs, char far * Bitmap); ; ; Bitmap is a planar bitmap, in the regular Xlib format. ; The width of the bitmap cannot be greater than 90 bytes, however. ; Ain't that just criminal? ; ; ax, bx, cx, and dx go south. ; one branch per pixel is more than enough -- we'll unroll the line-writing ; loop all the way to try to get a little speed (at the expense, as usual, ; of a chunk of memory) MaskedPoint macro offset mov al, [si + offset] or al, al jz $+6 mov es:[di + offset], al endm MaskedPointSize equ 11 public _x_clip_masked_pbm align 2 _x_clip_masked_pbm proc ARG X:word, Y:word, ScreenOffs:word, Bitmap:dword ; Tasm 1.0 does not allow the \ line continuation LOCAL left_counter,right_counter,column:word,clipped_height,screen_pos,bitmap_pos,bitmap_size,VGA_mask,width_copy,height_temp,screen_width:word=LocalStk ;LOCAL left_counter:word, right_counter:word, \ ; column:word, clipped_height:word, \ ; screen_pos:word, bitmap_pos:word, bitmap_size:word, \ ; VGA_mask:word, width_copy, height_temp:word, \ ; screen_width:word=LocalStk push bp mov bp, sp sub sp, LocalStk push si push di push ds ; sociopathic cases: are the clipping bounds out of order? mov ax, _TopBound cmp ax, _BottomBound jg @@GetOut mov ax, _LeftBound cmp ax, _RightBound jle @@ReasonableAndProper @@GetOut: ; return a 1 -- no image drawn pop ds pop di pop si mov ax, 1 mov sp, bp pop bp ret @@ReasonableAndProper: ; we need to use both the tables in ds and the height and width of the bitmap les si, Bitmap ; vertical position xor cx, cx mov cl, byte ptr es:[si + 1] ; height of bitmap xor ax, ax mov al, byte ptr es:[si] ; width of bitmap mul cx mov bitmap_size, ax mov ax, Y cmp ax, _BottomBound ; top edge below clipping box? jg @@GetOut mov bx, cx add bx, ax dec bx ; bottom edge = Y + height - 1 cmp bx, _TopBound jl @@GetOut sub bx, _BottomBound ; bottom margin = bottom edge - BottomBound jle @@NoBottomBound sub cx, bx ; clip bottom margin from height @@NoBottomBound: mov bx, _TopBound sub bx, ax ; top margin = TopBound - Y jle @@NoTopBound add ax, bx ; top edge = Y + top margin sub cx, bx ; clip top margin from height jmp @@KeepMargin @@NoTopBound: xor bx, bx @@KeepMargin: mov clipped_height, cx mul _ScrnLogicalByteWidth mov di, ax add di, ScreenOffs ; row of upper-left corner of blit mov cl, byte ptr es:[si] ; width of bitmap (ch is still 0 from height) mov ax, cx mul bx add si, ax add si, 2 ; starting position in bitmap ; horizontal position mov width_copy, cx mov dx, X cmp dx, _RightBound jg @@GetOut mov dx, 0 ; unclipped value for right delay mov ax, cx shl ax, 2 ; width in pixels add ax, X dec ax ; right edge = X + width in pixels - 1 cmp ax, _LeftBound jl @@GetOut sub ax, _RightBound ; right margin = right edge - RightBound jle @@NoRightBound mov bx, ax and bx, 3 mov dl, RightDelay[bx] shr ax, 2 sub cx, ax ; subtract clipped bytes from width @@NoRightBound: mov right_counter, dx mov dx, 0 ; unclipped value for left delay mov ax, _LeftBound sub ax, X ; left margin = LeftBound - X jle @@NoLeftBound mov bx, ax and bx, 3 mov dl, LeftDelay[bx] add ax, 3 shr ax, 2 ; left margin/4, rounded up sub cx, ax ; subtract clipped bytes from width add si, ax ; move starting position in bitmap past margin add di, ax ; move starting position on screen past margin @@NoLeftBound: mov left_counter, dx mov ax, cx imul ax, (-1 * MaskedPointSize) add ax, offset @@LineDone + 2 mov cx, ax ; jump offset for plotting mov ax, X ; add x coordinate to screen position mov bx, ax shr ax, 2 add di, ax mov dx, SC_INDEX mov al, MAP_MASK out dx, al inc dx and bx, 3 ; initial mask xor ax, ax mov al, ColumnMask[bx] mov VGA_mask, ax out dx, al mov column, 4 mov bitmap_pos, si mov screen_pos, di mov ax, _ScrnLogicalByteWidth mov screen_width, ax ; since we move ds ; we've used all our tables, so we can change ds to point to the bitmap, ; and es to point to the screen mov ds, word ptr [Bitmap + 2] mov ax, SCREEN_SEG mov es, ax mov bx, width_copy ; let's actually draw something for a change mov ax, clipped_height mov height_temp, ax mov dx, screen_width jmp cx ; 90 bottles of beer on the wall... PointLoop = 89 rept 89 MaskedPoint PointLoop PointLoop = PointLoop - 1 endm ; one bottle of beer... ; final point needs a different branch offset, so we don't use MaskedPoint mov al, [si] or al, al jz @@LineDone mov es:[di], al @@LineDone: add si, bx ; advance one bitmap line add di, dx ; advance one screen line dec height_temp jz @@PlaneDone jmp cx @@PlaneDone: dec column jz @@OuttaHere ; only four columns per customer, please mov dx, SC_INDEX + 1 rol byte ptr VGA_mask, 1 adc screen_pos, 0 ; move to new column if we've wrapped to plane 0 mov al, byte ptr VGA_mask out dx, al ; set VGA for next column shr right_counter, 1 jnc @@NoRightCounter add cx, MaskedPointSize ; cut off right edge for later planes @@NoRightCounter: shr left_counter, 1 jnc @@NoLeftCounter sub cx, MaskedPointSize ; add to left edge for later planes dec bitmap_pos dec screen_pos @@NoLeftCounter: mov si, bitmap_pos add si, bitmap_size mov bitmap_pos, si mov di, screen_pos mov ax, clipped_height mov height_temp, ax mov dx, screen_width jmp cx @@OuttaHere: ; return a 0 -- something was inside the boundary pop ds pop di pop si mov ax, 0 mov sp, bp pop bp ret _x_clip_masked_pbm endp end