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