Previous Table of Contents Next


LISTING 48.3 L48-3.ASM

; 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 SourceEndX and the row at SourceEndY. No
; clipping is performed. Results are not guaranteed if the source and
; destination overlap. C near-callable as:
;
;    void CopyScreenToScreenX(int SourceStartX, int SourceStartY,
;       int SourceEndX, int SourceEndY, int DestStartX,
;       int DestStartY, unsigned int SourcePageBase,
;       unsigned int DestPageBase, int SourceBitmapWidth,
;       int DestBitmapWidth);

SC_INDEX     equ    03c4h   ;Sequence Controller Index register port
MAP_MASK     equ    02h     ;index in SC of Map Mask register
GC_INDEX     equ    03ceh   ;Graphics Controller Index register port
BIT_MASK     equ    08h     ;index in GC of Bit Mask register
SCREEN_SEG   equ    0a000h  ;segment of display memory in Mode X

parms   struc
              dw  2 dup (?) ;pushed BP and return address
SourceStartX  dw  ?         ;X coordinate of upper-left corner of source
SourceStartY  dw  ?         ;Y coordinate of upper-left corner of source
SourceEndX    dw  ?         ;X coordinate of lower-right corner of source
                            ; (the row at SourceEndX is not copied)
SourceEndY    dw  ?         ;Y coordinate of lower-right corner of source
                            ; (the column at SourceEndY is not copied)
DestStartX    dw  ?         ;X coordinate of upper-left corner of dest
DestStartY    dw  ?         ;Y coordinate of upper-left corner of dest
SourcePageBase dw ?         ;base offset in display memory of page in
                            ; which source resides
DestPageBase  dw  ?         ;base offset in display memory of page in
                            ; which dest resides
SourceBitmapWidth  dw   ?   ;# of pixels across source bitmap
                            ; (must be a multiple of 4)
DestBitmapWidth    dw   ?   ;# of pixels across dest bitmap
                            ; (must be a multiple of 4)
parms   ends

SourceNextScanOffset equ -2 ;local storage for distance from end of
                            ; one source scan line to start of next
DestNextScanOffset   equ -4 ;local storage for distance from end of
                            ; one dest scan line to start of next
RectAddrWidth     equ -6    ;local storage for address width of rectangle
Height       equ -8;local storage for height of rectangle
STACK_FRAME_SIZE     equ  8

        .model  small
        .data
; Plane masks for clipping left and right edges of rectangle.
LeftClipPlaneMask       db      00fh,00eh,00ch,008h
RightClipPlaneMask      db      00fh,001h,003h,007h
        .code
        public  _CopyScreenToScreenX
_CopyScreenToScreenX proc    near
        push    bp      ;preserve caller’s stack frame
        mov     bp,sp   ;point to local stack frame
        sub     sp,STACK_FRAME_SIZE ;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,[bp+DestBitmapWidth]
        shr     ax,1               ;convert to width in addresses
        shr     ax,1
        mul     [bp+DestStartY]    ;top dest rect scan line
        mov     di,[bp+DestStartX]
        shr     di,1               ;X/4 = offset of first dest rect pixel in
        shr     di,1               ; scan line
        add     di,ax              ;offset of first dest rect pixel in page
        add     di,[bp+DestPageBase] ;offset of first dest rect pixel
                                   ; in display memory
        mov     ax,[bp+SourceBitmapWidth]
        shr     ax,1               ;convert to width in addresses
        shr     ax,1
        mul     [bp+SourceStartY]  ;top source rect scan line
        mov     si,[bp+SourceStartX]
        mov     bx,si
        shr     si,1               ;X/4 = offset of first source rect pixel in
        shr     si,1               ; scan line
        add     si,ax              ;offset of first source rect pixel in page
        add     si,[bp+SourcePageBase] ;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,[bp+SourceEndX]
        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,[bp+SourceEndX] ;calculate # of addresses across
        mov     ax,[bp+SourceStartX] ; rect
        cmp     cx,ax
        jle     CopyDone           ;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 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,[bp+SourceEndY]
        sub     ax,[bp+SourceStartY]  ;AX = height of rectangle
        jle     CopyDone           ;skip if 0 or negative height
        mov     [bp+Height],ax
        mov     ax,[bp+DestBitmapWidth]
        shr     ax,1               ;convert to width in addresses
        shr     ax,1
        sub     ax,cx              ;distance from end of one dest scan line to
        dec     ax                 ; start of next
        mov     [bp+DestNextScanOffset],ax
        mov     ax,[bp+SourceBitmapWidth]
        shr     ax,1               ;convert to width in addresses
        shr     ax,1
        sub     ax,cx              ;distance from end of one source scan line to
        dec     ax                 ; start of next
        mov     [bp+SourceNextScanOffset],ax
        mov     [bp+RectAddrWidth],cx ;remember width in addresses - 1
;----------------------BUG FIX
mov     dx,SC_INDEX
        mov     al,MAP_MASK
        out     dx,al              ;point SC Index reg to Map Mask
        inc     dx                 ;point to SC Data reg
;----------------------BUG FIX
        mov     ax,es              ;DS=ES=screen segment for MOVS
        mov     ds,ax
CopyRowsLoop:
        mov     cx,[bp+RectAddrWidth] ;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 pixels at a pop
        out     dx,al              ;set the middle pixel mask to no clip
        rep     movsb              ;draw the middle addresses four pixels apiece
                                   ; (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,[bp+SourceNextScanOffset] ;point to the start of
        add     di,[bp+DestNextScanOffset]   ; next source & dest lines
        dec     word ptr [bp+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
_CopyScreenToScreenX endp
        end


Previous Table of Contents Next

Graphics Programming Black Book © 2001 Michael Abrash