Previous | Table of Contents | Next

LISTING 44.2 L44-2.ASM

    ; Low-level animation routines.
    ; Tested with TASM

    SCREEN-WIDTH       equ     80      ;screen width in bytes
    INPUT-STATUS-1     equ     03dah   ;Input Status 1 register
    CRTC-INDEX         equ     03d4h   ;CRT Controller Index reg
    START-ADDRESS-HIGH equ     0ch     ;bitmap start address high byte
    START-ADDRESS-LOW  equ     0dh     ;bitmap start address low byte
    GC-INDEX           equ     03ceh   ;Graphics Controller Index reg
    SET-RESET          equ     0       ;GC index of Set/Reset reg
    G-MODE             equ     5       ;GC index of Mode register

            .model  small
            .data
    BIOS8x8Ptr dd   ?       ;points to BIOS 8x8 font
    ; Tables used to look up left and right clip masks.
    LeftMask d    0ffh, 07fh, 03fh, 01fh, 00fh, 007h, 003h, 001h
    RightMask d   080h, 0c0h, 0e0h, 0f0h, 0f8h, 0fch, 0feh, 0ffh

            .code
    ; Draws the specified filled rectangle in the specified color.
    ; Assumes the display is in mode 12h. Does not clip and assumes
    ; rectangle coordinates are valid.
    ;
    ; C near-callable as: void DrawRect(int LeftX, int TopY, int RightX,
    ;       int BottomY, int Color, unsigned int ScrnOffset,
    ;       unsigned int ScrnSegment);

    DrawRectParms   struc
            dw      2 dup (?) ;pushed BP and return address
    LeftX   dw      ?               ;X coordinate of left side of rectangle
    TopY    dw      ?               ;Y coordinate of top side of rectangle
    RightX  dw      ?               ;X coordinate of right side of rectangle
    BottomY dw      ?               ;Y coordinate of bottom side of rectangle
    Color   dw      ?               ;color in which to draw rectangle (only the
                                    ; lower 4 bits matter)
    ScrnOffset  dw  ?               ;offset of base of bitmap in which to draw
    ScrnSegment dw  ?               ;segment of base of bitmap in which to draw
    DrawRectParms   ends

            public  -DrawRect
    -DrawRect       proc    near
            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     dx,GC-INDEX
            mov     al,SET-RESET
            mov     ah,byte ptr Color[bp]
            out     dx,ax           ;set the color in which to draw
            mov     ax,G-MODE + (0300h)
            out     dx,ax           ;set to write mode 3
            les     di,dword ptr ScrnOffset[bp] ;point to bitmap start
            mov     ax,SCREEN-WIDTH
            mul     TopY[bp]         ;point to the start of the top scan
            add     di,ax            ; line to fill
            mov     ax,LeftX[bp]
            mov     bx,ax
            shr     ax,1             ;/8 = byte offset from left of screen
            shr     ax,1
            shr     ax,1
            add     di,ax            ;point to the upper-left corner of fill area
            and     bx,7             ;isolate intrapixel address
            mov     dl,LeftMask[bx]  ;set the left-edge clip mask
            mov     bx,RightX[bp]
            mov     si,bx
            and     bx,7             ;isolate intrapixel address of right edge
            mov     dh,RightMask[bx] ;set the right-edge clip mask
            mov     bx,LeftX[bp]
            and     bx,NOT 7         ;intrapixel address of left edge
            su    si,bx
            shr     si,1
            shr     si,1
            shr     si,1             ;# of bytes across spanned by rectangle - 1
            jnz     MasksSet         ;if there's only one byte across,
            and     dl,dh            ; combine the masks
    MasksSet:
            mov     bx,BottomY[bp]
            su    bx,TopY[bp]        ;# of scan lines to fill - 1
    FillLoop:
            push    di               ;remember line start offset
            mov     al,dl            ;left edge clip mask
            xchg    es:[di],al       ;draw the left edge
            inc     di               ;point to the next byte
            mov     cx,si            ;# of bytes left to do
            dec     cx               ;# of bytes left to do - 1
            js      LineDone         ;that's it if there's only 1 byte across
            jz      DrawRightEdge    ;no middle bytes if only 2 bytes across
            mov     al,0ffh          ;non-edge bytes are solid
            rep     stos             ;draw the solid bytes across the middle
    DrawRightEdge:
            mov     al,dh            ;right-edge clip mask
            xchg    es:[di],al       ;draw the right edge
    LineDone:
            pop     di               ;retrieve line start offset
            add     di,SCREEN-WIDTH  ;point to the next line
            dec     bx               ;count off scan lines
            jns     FillLoop

            pop     di               ;restore caller's register variables
            pop     si
            pop     bp               ;restore caller's stack frame
            ret
    -DrawRect       endp

    ; Shows the page at the specified offset in the bitmap. Page is
    ; displayed when this routine returns.
    ;
    ; C near-callable as: void ShowPage(unsigned int StartOffset);

    ShowPageParms   struc
            dw      2 dup (?)         ;pushed BP and return address
    StartOffset dw  ?           ;offset in bitmap of page to display
    ShowPageParms   ends

            public  -ShowPage
    -ShowPage       proc    near
            push    bp                ;preserve caller's stack frame
            mov     bp,sp             ;point to local stack frame
    ; Wait for display enable to be active (status is active low), to be
    ; sure both halves of the start address will take in the same frame.
            mov     bl,START-ADDRESS-LOW        ;preload for fastest
            mov     bh,byte ptr StartOffset[bp] ; flipping once display
            mov     cl,START-ADDRESS-HIGH       ; enable is detected
            mov     ch,byte ptr StartOffset+1[bp]
            mov     dx,INPUT-STATUS-1
    WaitDE:
            in      al,dx
            test    al,01h
            jnz     WaitDE            ;display enable is active low (0 = active)
    ; Set the start offset in display memory of the page to display.
            mov     dx,CRTC-INDEX
            mov     ax,bx
            out     dx,ax             ;start address low
            mov     ax,cx
            out     dx,ax             ;start address high
    ; Now wait for vertical sync, so the other page will be invisible when
    ; we start drawing to it.
            mov     dx,INPUT-STATUS-1
    WaitVS:
            in      al,dx
            test    al,08h
            jz      WaitVS            ;vertical sync is active high (1 = active)
            pop     bp                ;restore caller's stack frame
            ret
    -ShowPage       endp

    ; Displays the specified image at the specified location in the
    ; specified bitmap, in the desired color.
    ;
    ; C near-callable as: void DrawImage(int LeftX, int TopY,
    ;       image **RotationTable, int Color, unsigned int ScrnOffset,
    ;       unsigned int ScrnSegment);

    DrawImageParms  struc
            dw      2 dup (?) ;pushed BP and return address
    DILeftX       dw   ?            ;X coordinate of left side of image
    DITopY        dw   ?            ;Y coordinate of top side of image
    RotationTable dw   ?            ;pointer to table of pointers to image
                                    ; rotations
    DIColor       dw   ?            ;color in which to draw image (only the
                                    ; lower 4 bits matter)
    DIScrnOffset  dw   ?            ;offset of base of bitmap in which to draw
    DIScrnSegment dw   ?            ;segment of base of bitmap in which to draw
    DrawImageParms  ends

    image struc
    WidthInBytes    dw      ?
    Height          dw      ?
    BitPattern      dw      ?
    image ends

            public  -DrawImage
    -DrawImage      proc    near
            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     dx,GC-INDEX
            mov     al,SET-RESET
            mov     ah,byte ptr DIColor[bp]
            out     dx,ax           ;set the color in which to draw
            mov     ax,G-MODE + (0300h)
            out     dx,ax           ;set to write mode 3
            les     di,dword ptr DIScrnOffset[bp] ;point to bitmap start
            mov     ax,SCREEN-WIDTH
            mul     DITopY[bp]      ;point to the start of the top scan
            add     di,ax           ; line on which to draw
            mov     ax,DILeftX[bp]
            mov     bx,ax
            shr     ax,1            ;/8 = byte offset from left of screen
            shr     ax,1
            shr     ax,1
            add     di,ax           ;point to the upper-left corner of draw area
            and     bx,7            ;isolate intrapixel address
            shl     bx,1            ;*2 for word look-up
            add     bx,RotationTable[bp] ;point to the image structure for
            mov     bx,[bx]              ; the intrabyte rotation
            mov     dx,[bx].WidthInBytes ;image width
            mov     si,[bx].BitPattern   ;pointer to image pattern bytes
            mov     bx,[bx].Height       ;image height
    DrawImageLoop:
            push    di                   ;remember line start offset
            mov     cx,dx                ;# of bytes across
    DrawImageLineLoop:
            lods                         ;get the next image byte
            xchg    es:[di],al           ;draw the next image byte
            inc     di                   ;point to the following screen byte
            loop    DrawImageLineLoop
            pop     di                   ;retrieve line start offset
            add     di,SCREEN-WIDTH      ;point to the next line
            dec     bx                   ;count off scan lines
            jnz     DrawImageLoop

            pop     di                   ;restore caller's register variables
            pop     si
            pop     bp                   ;restore caller's stack frame
            ret
    -DrawImage      endp

    ; Draws a 0-terminated text string at the specified location in the
    ; specified bitmap in white, using the 8x8 BIOS font. Must be at an X
    ; coordinate that's a multiple of 8.
    ;
    ; C near-callable as: void TextUp(char *Text, int LeftX, int TopY,
    ;       unsigned int ScrnOffset, unsigned int ScrnSegment);

    TextUpParms     struc
                     dw    2 dup (?) ;pushed BP and return address
    Text             dw    ?            ;pointer to text to draw
    TULeftX          dw    ?            ;X coordinate of left side of rectangle
                                        ; (must be a multiple of 8)
    TUTopY           dw    ?            ;Y coordinate of top side of rectangle
    TUScrnOffset     dw    ?            ;offset of base of bitmap in which to draw
    TUScrnSegment    dw    ?            ;segment of base of bitmap in which to draw
    TextUpParms     ends

            public  -TextUp
    -TextUp proc    near
            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     dx,GC-INDEX
            mov     ax,G-MODE + (0000h)
            out     dx,ax   ;set to write mode 0
            les     di,dword ptr TUScrnOffset[bp] ;point to bitmap start
            mov     ax,SCREEN-WIDTH
            mul     TUTopY[bp]           ;point to the start of the top scan
            add     di,ax                ; line the text starts on
            mov     ax,TULeftX[bp]
            mov     bx,ax
            shr     ax,1                 ;/8 = byte offset from left of screen
            shr     ax,1
            shr     ax,1
            add     di,ax                ;point to the upper-left corner of first char
            mov     si,Text[bp]          ;point to text to draw
    TextUpLoop:
            lods                         ;get the next character to draw
            and     al,al
            jz      TextUpDone           ;done if null byte
            push    si                   ;preserve text string pointer
            push    di                   ;preserve character's screen offset
            push    ds                   ;preserve default data segment
            call    CharUp               ;draw this character
            pop     ds                   ;restore default data segment
            pop     di                   ;retrieve character's screen offset
            pop     si                   ;retrieve text string pointer
            inc     di                   ;point to next character's start location
            jmp     TextUpLoop

    TextUpDone:
            pop     di                   ;restore caller's register variables
            pop     si
            pop     bp                   ;restore caller's stack frame
            ret

    CharUp:                              ;draws the character in AL at ES:DI
            lds     si,[BIOS8x8Ptr]      ;point to the 8x8 font start
            mov     bl,al
            su    bh,bh
            shl     bx,1
            shl     bx,1
            shl     bx,1                 ;*8 to look up character offset in font
            add     si,bx                ;point DS:Sito character data in font
            mov     cx,8                 ;characters are 8 high
    CharUpLoop:
            movs                         ;copy the next character pattern byte
            add     di,SCREEN-WIDTH-1    ;point to the next dest byte
            loop    CharUpLoop
            ret
    -TextUp endp

    ; Sets the pointer to the BIOS 8x8 font.
    ;
    ; C near-callable as: extern void SetBIOS8x8Font(void);

            public  -SetBIOS8x8Font
    -SetBIOS8x8Font proc    near
            push    bp                  ;preserve caller's stack frame
            push    si                  ;preserve caller's register variables
            push    di                  ; and data segment (don't assume BIOS
            push    ds                  ; preserves anything)
            mov     ah,11h              ;BIOS character generator function
            mov     al,30h              ;BIOS information subfunction
            mov     bh,3                ;request 8x8 font pointer
            int     10h                 ;invoke BIOS video services
            mov     word ptr [BIOS8x8Ptr],bp  ;store the pointer
            mov     word ptr [BIOS8x8Ptr+2],es
            pop     ds
            pop     di                  ;restore caller's register variables
            pop     si
            pop     bp                  ;restore caller's stack frame
            ret
    -SetBIOS8x8Font endp
            end

Previous | Table of Contents | Next

Graphics Programming Black Book © 2001 Michael Abrash