X-Git-Url: http://4ch.mooo.com/gitweb/?a=blobdiff_plain;f=16%2Fxlib%2Fxrect.asm;fp=16%2Fxlib%2Fxrect.asm;h=9b00356caa398773d07de6145d0298aec97ad360;hb=8a4b836c5347897d1a8279a46310fc79fd555574;hp=0000000000000000000000000000000000000000;hpb=e43b8a77b54a1a548279640403d56e9588e8dbad;p=16.git diff --git a/16/xlib/xrect.asm b/16/xlib/xrect.asm new file mode 100755 index 00000000..9b00356c --- /dev/null +++ b/16/xlib/xrect.asm @@ -0,0 +1,684 @@ +;----------------------------------------------------------------------- +; MODULE XRECT +; +; Rectangle functions all MODE X 256 Color resolutions +; +; Compile with Tasm. +; C callable. +; +; +; ****** XLIB - Mode X graphics library **************** +; ****** **************** +; ****** Written By Themie Gouthas **************** +; +; egg@dstos3.dsto.gov.au +; teg@bart.dsto.gov.au +;----------------------------------------------------------------------- + + +include xlib.inc +include xrect.inc + + + .data +; Plane masks for clipping left and right edges of rectangle. + LeftClipPlaneMask db 00fh,00eh,00ch,008h + RightClipPlaneMask db 00fh,001h,003h,007h + .code + +;--------------------------------------------------------------------------- +; Mode X (320x240, 256 colors) rectangle solid colour fill routine. +; +; Based on code originally published in DDJ Mag by M. Abrash +; +; with TASM 2. C near-callable as: +; +; void x_rect_fill_clipped(int StartX, int StartY, int EndX, int EndY, +; unsigned int PageBase, unsigne int color); +; +; + + +_x_rect_fill_clipped proc +ARG StartX:word,StartY:word,EndX:word,EndY:word,PageBase:word,Color:word + push bp ;preserve caller's stack frame + mov bp,sp ;point to local stack frame + push si ;preserve caller's register variables + push di + + mov dx,[_TopClip] ; Compare u.l. Y coord with Top + mov cx,[_BottomClip] + mov ax,[StartY] + mov bx,[EndY] + cmp dx,ax + jle @@CheckBottomClip + cmp dx,bx + jg @@NotVisible + mov [StartY],dx + +@@CheckBottomClip: + cmp cx,bx + jg @@CheckLeftClip + cmp cx,ax + jl @@NotVisible + mov [EndY],cx + +@@CheckLeftClip: + mov dx,[_LeftClip] ; Compare u.l. Y coord with Top + mov cx,[_RightClip] + mov ax,[StartX] + mov bx,[EndX] + sal dx,2 + sal cx,2 + cmp dx,ax + jle @@CheckRightClip + cmp dx,bx + jg @@NotVisible + mov [StartX],dx + +@@CheckRightClip: + cmp cx,bx + jg RFClipDone + cmp cx,ax + jl @@NotVisible + mov [EndX],cx + jmp RFClipDone + +@@NotVisible: + mov ax,1 + pop di ; restore registers + pop si + pop bp + ret +_x_rect_fill_clipped endp + + + +;--------------------------------------------------------------------------- +; Mode X (320x240, 256 colors) rectangle solid colour fill routine. +; +; Based on code originally published in DDJ Mag by M. Abrash +; +; with TASM 2. C near-callable as: +; +; void x_rect_fill(int StartX, int StartY, int EndX, int EndY, +; unsigned int PageBase, unsigne int color); +; +; + + +_x_rect_fill proc +ARG StartX:word,StartY:word,EndX:word,EndY:word,PageBase:word,Color:word + push bp ;preserve caller's stack frame + mov bp,sp ;point to local stack frame + push si ;preserve caller's register variables + push di + +RFClipDone: + cld + mov ax,[_ScrnLogicalByteWidth] + mul [StartY] ;offset in page of top rectangle scan line + mov di,[StartX] + sar di,2 ;X/4 = offset of first rectangle pixel in scan + add di,ax ;offset of first rectangle pixel in page + add di,[PageBase] ;offset of first rectangle pixel in + ; display memory + mov ax,SCREEN_SEG ;point ES:DI to the first rectangle + mov es,ax ; pixel's address + mov dx,SC_INDEX ;set the Sequence Controller Index to + mov al,MAP_MASK ; point to the Map Mask register + out dx,al + inc dx ;point DX to the SC Data register + mov si,[StartX] + and si,0003h ;look up left edge plane mask + mov bh,LeftClipPlaneMask[si] ; to clip & put in BH + mov si,[EndX] + and si,0003h ;look up right edge plane + mov bl,RightClipPlaneMask[si] ; mask to clip & put in BL + + mov cx,[EndX] ;calculate # of addresses across rect + mov si,[StartX] + cmp cx,si + jle @@FillDone ;skip if 0 or negative width + dec cx + and si,not 011b + sub cx,si + sar cx,2 ;# of addresses across rectangle to fill - 1 + jnz @@MasksSet ;there's more than one byte to draw + and bh,bl ;there's only one byte, so combine the left + ; and right edge clip masks +@@MasksSet: + mov si,[EndY] + sub si,[StartY] ;BX = height of rectangle + jle @@FillDone ;skip if 0 or negative height + mov ah,byte ptr [Color] ;color with which to fill + mov bp,[_ScrnLogicalByteWidth] ;stack frame isn't needed any more + sub bp,cx ;distance from end of one scan line to start + dec bp ; of next +@@FillRowsLoop: + push cx ;remember width in addresses - 1 + mov al,bh ;put left-edge clip mask in AL + out dx,al ;set the left-edge plane (clip) mask + mov al,ah ;put color in AL + stosb ;draw the left edge + dec cx ;count off left edge byte + js @@FillLoopBottom ;that's the only byte + jz @@DoRightEdge ;there are only two bytes + mov al,00fh ;middle addresses drawn 4 pixels at a pop + out dx,al ;set the middle pixel mask to no clip + mov al,ah ;put color in AL + rep stosb ;draw middle addresses four pixels apiece +@@DoRightEdge: + mov al,bl ;put right-edge clip mask in AL + out dx,al ;set the right-edge plane (clip) mask + mov al,ah ;put color in AL + stosb ;draw the right edge +@@FillLoopBottom: + add di,bp ;point to start of the next scan line of + ; the rectangle + pop cx ;retrieve width in addresses - 1 + dec si ;count down scan lines + jnz @@FillRowsLoop +@@FillDone: + pop di ;restore caller's register variables + pop si + pop bp ;restore caller's stack frame + ret +_x_rect_fill endp + + + +;--------------------------------------------------------------------------- +; Mode X (320x240, 256 colors) rectangle 4x4 pattern fill routine. +; Upper left corner of pattern is always aligned to a multiple-of-4 +; row and column. Works on all VGAs. Uses approach of copying the +; pattern to off-screen display memory, then loading the latches with +; the pattern for each scan line and filling each scan line four +; pixels at a time. Fills up to but not including the column at EndX +; and the row at EndY. No clipping is performed. All ASM code tested +; +; +; Based on code originally published in DDJ Mag by M. Abrash +; +; +; C near-callable as: +; +; void x_rect_pattern_clipped(int StartX, int StartY, int EndX, int EndY, +; unsigned int PageBase, char far * Pattern); +; +; + +_x_rect_pattern_clipped proc +ARG StartX:word,StartY:word,EndX:word,EndY:word,PageBase:word,Pattern:dword +LOCAL NextScanOffset:word,RectAddrWidth:word,Height:word=LocalStk + push bp ;preserve caller's stack frame + mov bp,sp ;point to local stack frame + sub sp,LocalStk ;allocate space for local vars + push si ;preserve caller's register variables + push di + push ds + + mov dx,[_TopClip] ; Compare u.l. Y coord with Top + mov cx,[_BottomClip] + mov ax,[StartY] + mov bx,[EndY] + cmp dx,ax + jle @@CheckBottomClip + cmp dx,bx + jg @@NotVisible + mov [StartY],dx + +@@CheckBottomClip: + cmp cx,bx + jg @@CheckLeftClip + cmp cx,ax + jl @@NotVisible + mov [EndY],cx + +@@CheckLeftClip: + mov dx,[_LeftClip] ; Compare u.l. Y coord with Top + mov cx,[_RightClip] + mov ax,[StartX] + mov bx,[EndX] + sal dx,2 + sal cx,2 + cmp dx,ax + jle @@CheckRightClip + cmp dx,bx + jg @@NotVisible + mov [StartX],dx + +@@CheckRightClip: + cmp cx,bx + jg RPClipDone + cmp cx,ax + jl @@NotVisible + mov [EndX],cx + jmp RPClipDone + +@@NotVisible: + mov ax,1 + pop ds + pop di ; restore registers + pop si + mov sp,bp + pop bp + ret + +_x_rect_pattern_clipped endp + +;--------------------------------------------------------------------------- +; Mode X (320x240, 256 colors) rectangle 4x4 pattern fill routine. +; Upper left corner of pattern is always aligned to a multiple-of-4 +; row and column. Works on all VGAs. Uses approach of copying the +; pattern to off-screen display memory, then loading the latches with +; the pattern for each scan line and filling each scan line four +; pixels at a time. Fills up to but not including the column at EndX +; and the row at EndY. No clipping is performed. All ASM code tested +; +; +; Based on code originally published in DDJ Mag by M. Abrash +; +; +; C near-callable as: +; +; void x_rect_pattern(int StartX, int StartY, int EndX, int EndY, +; unsigned int PageBase, char far * Pattern); + + + +_x_rect_pattern proc +ARG StartX:word,StartY:word,EndX:word,EndY:word,PageBase:word,Pattern:dword +LOCAL NextScanOffset:word,RectAddrWidth:word,Height:word=LocalStk + push bp ;preserve caller's stack frame + mov bp,sp ;point to local stack frame + sub sp,LocalStk ;allocate space for local vars + push si ;preserve caller's register variables + push di + push ds + +RPClipDone: + cld + mov ax,SCREEN_SEG ;point ES to display memory + mov es,ax + ;copy pattern to display memory buffer + lds si,dword ptr [Pattern] ;point to pattern to fill with + mov di,PATTERN_BUFFER ;point ES:DI to pattern buffer + mov dx,SC_INDEX ;point Sequence Controller Index to + mov al,MAP_MASK ; Map Mask + out dx,al + inc dx ;point to SC Data register + mov cx,4 ;4 pixel quadruplets in pattern +@@DownloadPatternLoop: + mov al,1 ; + out dx,al ;select plane 0 for writes + movsb ;copy over next plane 0 pattern pixel + dec di ;stay at same address for next plane + mov al,2 ; + out dx,al ;select plane 1 for writes + movsb ;copy over next plane 1 pattern pixel + dec di ;stay at same address for next plane + mov al,4 ; + out dx,al ;select plane 2 for writes + movsb ;copy over next plane 2 pattern pixel + dec di ;stay at same address for next plane + mov al,8 ; + out dx,al ;select plane 3 for writes + movsb ;copy over next plane 3 pattern pixel + ; and advance address + loop @@DownloadPatternLoop + pop ds + + mov dx,GC_INDEX ;set the bit mask to select all bits + mov ax,00000h+BIT_MASK ; from the latches and none from + out dx,ax ; the CPU, so that we can write the + ; latch contents directly to memory + mov ax,[StartY] ;top rectangle scan line + mov si,ax + and si,011b ;top rect scan line modulo 4 + add si,PATTERN_BUFFER ;point to pattern scan line that + ; maps to top line of rect to draw + mov dx,[_ScrnLogicalByteWidth] + mul dx ;offset in page of top rect scan line + mov di,[StartX] + mov bx,di + sar di,2 ;X/4 = offset of first rectangle pixel in scan + add di,ax ;offset of first rectangle pixel in page + add di,[PageBase] ;offset of first rectangle pixel in + ; display memory + and bx,0003h ;look up left edge plane mask + mov ah,LeftClipPlaneMask[bx] ; to clip + mov bx,[EndX] + and bx,0003h ;look up right edge plane + mov al,RightClipPlaneMask[bx] ; mask to clip + mov bx,ax ;put the masks in BX + + mov cx,[EndX] ;calculate # of addresses across rect + mov ax,[StartX] + cmp cx,ax + jle @@FillDone ;skip if 0 or negative width + dec cx + and ax,not 011b + sub cx,ax + sar cx,2 ;# of addresses across rectangle to fill - 1 + jnz @@MasksSet ;there's more than one pixel to draw + and bh,bl ;there's only one pixel, so combine the left + ; and right edge clip masks +@@MasksSet: + mov ax,[EndY] + sub ax,[StartY] ;AX = height of rectangle + jle @@FillDone ;skip if 0 or negative height + mov [Height],ax + mov ax,[_ScrnLogicalByteWidth] + sub ax,cx ;distance from end of one scan line to start + dec ax ; of next + mov [NextScanOffset],ax + mov [RectAddrWidth],cx ;remember width in addresses - 1 + mov dx,SC_INDEX+1 ;point to Sequence Controller Data reg + ; (SC Index still points to Map Mask) +@@FillRowsLoop: + mov cx,[RectAddrWidth] ;width across - 1 + mov al,es:[si] ;read display memory to latch this scan + ; line's pattern + inc si ;point to the next pattern scan line, wrapping + jnz short @@NoWrap ; back to the start of the pattern if + sub si,4 ; we've run off the end +@@NoWrap: + mov al,bh ;put left-edge clip mask in AL + out dx,al ;set the left-edge plane (clip) mask + stosb ;draw the left edge (pixels come from latches; + ; value written by CPU doesn't matter) + dec cx ;count off left edge address + js @@FillLoopBottom ;that's the only address + jz @@DoRightEdge ;there are only two addresses + mov al,00fh ;middle addresses drawn 4 pixels at a pop + out dx,al ;set middle pixel mask to no clip + rep stosb ;draw middle addresses four pixels apiece + ; (from latches; value written doesn't matter) +@@DoRightEdge: + mov al,bl ;put right-edge clip mask in AL + out dx,al ;set the right-edge plane (clip) mask + stosb ;draw the right edge (from latches; value + ; written doesn't matter) +@@FillLoopBottom: + add di,[NextScanOffset] ;point to the start of the next scan + ; line of the rectangle + dec word ptr [Height] ;count down scan lines + jnz @@FillRowsLoop +@@FillDone: + mov dx,GC_INDEX+1 ;restore the bit mask to its default, + mov al,0ffh ; which selects all bits from the CPU + out dx,al ; and none from the latches (the GC + ; Index still points to Bit Mask) + + pop di ;restore caller's register variables + pop si + mov sp,bp ;discard storage for local variables + pop bp ;restore caller's stack frame + ret +_x_rect_pattern endp + +;----------------------------------------------------------------------- +; Mode X (320x240, 256 colors) display memory to display memory copy +; routine. Left edge of source rectangle modulo 4 must equal left edge +; of destination rectangle modulo 4. Works on all VGAs. Uses approach +; of reading 4 pixels at a time from the source into the latches, then +; writing the latches to the destination. Copies up to but not +; including the column at SrcEndX and the row at SrcEndY. No +; clipping is performed. Results are not guaranteed if the source and +; destination overlap. +; +; +; Based on code originally published in DDJ Mag by M. Abrash +; +;C near-callable as: +; void x_cp_vid_rect(int SrcStartX, int SrcStartY, +; int SrcEndX, int SrcEndY, int DestStartX, +; int DestStartY, unsigned int SrcPageBase, +; unsigned int DestPageBase, int SrcBitmapWidth, +; int DestBitmapWidth); + +_x_cp_vid_rect proc + ARG SrcStartX:word,SrcStartY:word,SrcEndX:word,SrcEndY:word,DestStartX:word,DestStartY:word,SrcPageBase:word,DestPageBase:word,SrcBitmapW:word,DestBitmapW:word + LOCAL SrcNextOffs:word,DestNextOffs:word,RectAddrW:word,Height:word=LocalStk + push bp ;preserve caller's stack frame + mov bp,sp ;point to local stack frame + sub sp,LocalStk ;allocate space for local vars + push si ;preserve caller's register variables + push di + push ds + + cld + mov dx,GC_INDEX ;set the bit mask to select all bits + mov ax,00000h+BIT_MASK ; from the latches and none from + out dx,ax ; the CPU, so that we can write the + ; latch contents directly to memory + mov ax,SCREEN_SEG ;point ES to display memory + mov es,ax + mov ax,[DestBitmapW] + shr ax,2 ;convert to width in addresses + mul [DestStartY] ;top dest rect scan line + mov di,[DestStartX] + sar di,2 ;X/4 = offset of first dest rect pixel in + ; scan line + add di,ax ;offset of first dest rect pixel in page + add di,[DestPageBase] ;offset of first dest rect pixel + ; in display memory + mov ax,[SrcBitmapW] + sar ax,2 ;convert to width in addresses + mul [SrcStartY] ;top source rect scan line + mov si,[SrcStartX] + mov bx,si + sar si,2 ;X/4 = offset of first source rect pixel in + ; scan line + add si,ax ;offset of first source rect pixel in page + add si,[SrcPageBase] ;offset of first source rect + ; pixel in display memory + and bx,0003h ;look up left edge plane mask + mov ah,LeftClipPlaneMask[bx] ; to clip + mov bx,[SrcEndX] + and bx,0003h ;look up right edge plane + mov al,RightClipPlaneMask[bx] ; mask to clip + mov bx,ax ;put the masks in BX + + mov cx,[SrcEndX] ;calculate # of addresses across + mov ax,[SrcStartX] ; rect + cmp cx,ax + jle @@CopyDone ;skip if 0 or negative width + dec cx + and ax,not 011b + sub cx,ax + sar cx,2 ;# of addresses across rectangle to copy - 1 + jnz @@MasksSet ;there's more than one address to draw + and bh,bl ;there's only one address, so combine the left + ; and right edge clip masks +@@MasksSet: + mov ax,[SrcEndY] + sub ax,[SrcStartY] ;AX = height of rectangle + jle @@CopyDone ;skip if 0 or negative height + mov [Height],ax + mov ax,[DestBitmapW] + sar ax,2 ;convert to width in addresses + sub ax,cx ;distance from end of one dest scan line + dec ax ; to start of next + mov [DestNextOffs],ax + mov ax,[SrcBitmapW] + sar ax,2 ;convert to width in addresses + sub ax,cx ;distance from end of one source scan line + dec ax ; to start of next + mov [SrcNextOffs],ax + mov [RectAddrW],cx ;remember width in addresses - 1 + mov dx,SC_INDEX+1 ;point to Sequence Controller Data reg + ; (SC Index still points to Map Mask) + mov ax,es ;DS=ES=screen segment for MOVS + mov ds,ax +@@CopyRowsLoop: + mov cx,[RectAddrW] ;width across - 1 + mov al,bh ;put left-edge clip mask in AL + out dx,al ;set the left-edge plane (clip) mask + movsb ;copy the left edge (pixels go through + ; latches) + dec cx ;count off left edge address + js @@CopyLoopBottom ;that's the only address + jz @@DoRightEdge ;there are only two addresses + mov al,00fh ;middle addresses are drawn 4 pix per go + out dx,al ;set the middle pixel mask to no clip + rep movsb ;draw the middle addresses four pix per go + ; (pixels copied through latches) +@@DoRightEdge: + mov al,bl ;put right-edge clip mask in AL + out dx,al ;set the right-edge plane (clip) mask + movsb ;draw the right edge (pixels copied through + ; latches) +@@CopyLoopBottom: + add si,[SrcNextOffs] ;point to the start of + add di,[DestNextOffs] ; next source & dest lines + dec word ptr [Height] ;count down scan lines + jnz @@CopyRowsLoop +@@CopyDone: + mov dx,GC_INDEX+1 ;restore the bit mask to its default, + mov al,0ffh ; which selects all bits from the CPU + out dx,al ; and none from the latches (the GC + ; Index still points to Bit Mask) + pop ds + pop di ;restore caller's register variables + pop si + mov sp,bp ;discard storage for local variables + pop bp ;restore caller's stack frame + ret +_x_cp_vid_rect endp + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Copy a rectangular region of a VGA screen, with x coordinates +; rounded to the nearest byte -- source and destination may overlap. +; +; C near-callable as: +; +; void x_shift_rect (WORD SrcLeft, WORD SrcTop, +; WORD SrcRight, WORD SrcBottom, +; WORD DestLeft, WORD DestTop, WORD ScreenOffs); +; +; SrcRight is rounded up, and the left edges are rounded down, to ensure +; that the pixels pointed to by the arguments are inside the rectangle. +; +; The width of the rectangle in bytes (width in pixels / 4) +; cannot exceed 255. +; +; ax, bx, cx, dx, and es eat hot lead. +; +; This function was written by Matthew MacKenzie +; matm@eng.umd.edu + + align 2 +_x_shift_rect proc +ARG SrcLeft,SrcTop,SrcRight,SrcBottom,DestLeft,DestTop,ScreenOffs:word +LOCAL width_temp:word=LocalStk + + push bp + mov bp, sp + sub sp, LocalStk + push si + push di + push ds + + ; find values for width & x motion + mov si, SrcLeft ; source x in bytes + sar si, 2 + + mov di, DestLeft ; destination x in bytes + sar di, 2 + + mov bx, SrcRight ; right edge of source in bytes, rounded up + add bx, 3 + sar bx, 2 + sub bx, si + mov ax, bx ; width - 1 + inc bx ; we'll use this as an offset for moving up or down + mov width_temp, bx + + cld ; by default, strings increment + + cmp si, di + jge @@MovingLeft + +; we're moving our rectangle right, so we copy it from right to left + add si, ax ; source & destination will start on the right edge + add di, ax + neg bx + std ; strings decrement + +@@MovingLeft: + +; find values for height & y motion + mov cx, _ScrnLogicalByteWidth ; bytes to move to advance one line + mov ax, SrcTop + mov dx, DestTop ; default destination y + cmp ax, dx + jge @@MovingUp + +; we're moving our rectangle down, so we copy it from bottom to top + mov ax, SrcBottom ; source starts at bottom + add dx, ax ; add (height - 1) to destination y + sub dx, SrcTop + neg cx ; advance up screen rather than down + +@@MovingUp: + push dx ; save destination y during multiply + mul _ScrnLogicalByteWidth + add si, ax ; add y in bytes to source + pop ax ; restore destination y + mul _ScrnLogicalByteWidth + add di, ax ; add y in bytes to destination + + sub cx, bx ; final value for moving up or down + + add si, ScreenOffs ; source & destination are on the same screen + add di, ScreenOffs + + mov dx, SC_INDEX ; set map mask to all four planes + mov ax, 00f02h + out dx, ax + + mov dx, GC_INDEX ; set bit mask to take data from latches + mov ax, BIT_MASK ; rather than CPU + out dx, ax + + mov ax, SCREEN_SEG ; source and destination are VGA memory + mov es, ax + mov ds, ax + + mov ah, byte ptr width_temp ; width in bytes should fit in 8 bits + + mov bx, SrcBottom ; height - 1 + sub bx, SrcTop + + mov dx, cx ; bytes to add to advance one line + + xor ch, ch ; ready to rock + +@@LineLoop: + mov cl, ah ; load width in bytes + rep movsb ; move 4 pixels at a time using latches (YOW!) + + add si, dx ; advance source by one line + add di, dx ; advance destination by one line + + dec bx ; line counter + jge @@LineLoop ; 0 still means one more to go + + mov dx, GC_INDEX + 1; set bit mask to take data from CPU (normal setting) + mov al, 0ffh + out dx, al + +; kick + pop ds + pop di + pop si + mov sp, bp + pop bp + + ret +_x_shift_rect endp + + end +