home *** CD-ROM | disk | FTP | other *** search
- ;-----------------------------------------------------------------------
- ; 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(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
-
- cld
- mov ax,[_ScrnLogicalByteWidth]
- mul [StartY] ;offset in page of top rectangle scan line
- mov di,[StartX]
- shr di,1 ;X/4 = offset of first rectangle pixel in scan
- shr di,1 ; line
- 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
- shr cx,1
- shr cx,1 ;# 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(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
- 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
- shr di,1 ;X/4 = offset of first rectangle pixel in scan
- shr di,1 ; line
- 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
- shr cx,1
- shr cx,1 ;# 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]
- shr 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]
- shr ax,2 ;convert to width in addresses
- mul [SrcStartY] ;top source rect scan line
- mov si,[SrcStartX]
- mov bx,si
- shr 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
- shr 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]
- shr 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]
- shr 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
- shr si, 2
-
- mov di, DestLeft ; destination x in bytes
- shr di, 2
-
- mov bx, SrcRight ; right edge of source in bytes, rounded up
- add bx, 3
- shr 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
-