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