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