home *** CD-ROM | disk | FTP | other *** search
/ Graphics Programming Black Book (Special Edition) / BlackBook.bin / disk1 / source / chapter23 / l23-1.asm next >
Assembly Source File  |  1997-06-18  |  21KB  |  558 lines

  1. ; Sample VGA program.
  2. ; Animates four balls bouncing around a playfield by using
  3. ; page flipping. Playfield is panned smoothly both horizontally
  4. ; and vertically.
  5. ; Assembled with TASM 4.0, linked with TLINK 6.10
  6. ; Checked by Jim Mischel 11/21/94
  7. ;
  8. stack   segment para stack 'STACK'
  9.         db      512 dup(?)
  10. stack   ends
  11. ;
  12. MEDRES_VIDEO_MODE       equ     0       ;define for 640x350 video mode
  13.                                         ; comment out for 640x200 mode
  14. VIDEO_SEGMENT   equ     0a000h          ;display memory segment for
  15.                                         ; true VGA graphics modes
  16. LOGICAL_SCREEN_WIDTH    equ     672/8   ;width in bytes and height in scan
  17. LOGICAL_SCREEN_HEIGHT   equ     384     ; lines of the virtual screen
  18.                                         ; we'll work with
  19. PAGE0           equ     0       ;flag for page 0 when page flipping
  20. PAGE1           equ     1       ;flag for page 1 when page flipping
  21. PAGE0_OFFSET    equ     0       ;start offset of page 0 in VGA memory
  22. PAGE1_OFFSET    equ     LOGICAL_SCREEN_WIDTH * LOGICAL_SCREEN_HEIGHT
  23.                                 ;start offset of page 1 (both pages
  24.                                 ; are 672x384 virtual screens)
  25. BALL_WIDTH      equ     24/8    ;width of ball in display memory bytes
  26. BALL_HEIGHT     equ     24      ;height of ball in scan lines
  27. BLANK_OFFSET    equ     PAGE1_OFFSET * 2        ;start of blank image
  28.                                                 ; in VGA memory
  29. BALL_OFFSET     equ     BLANK_OFFSET + (BALL_WIDTH * BALL_HEIGHT)
  30.                                 ;start offset of ball image in VGA memory
  31. NUM_BALLS       equ     4       ;number of balls to animate
  32. ;
  33. ; VGA register equates.
  34. ;
  35. SC_INDEX        equ     3c4h    ;SC index register
  36. MAP_MASK        equ     2       ;SC map mask register
  37. GC_INDEX        equ     3ceh    ;GC index register
  38. GC_MODE         equ     5       ;GC mode register
  39. CRTC_INDEX      equ     03d4h   ;CRTC index register
  40. START_ADDRESS_HIGH equ  0ch     ;CRTC start address high byte
  41. START_ADDRESS_LOW equ   0dh     ;CRTC start address low byte
  42. CRTC_OFFSET     equ     13h     ;CRTC offset register
  43. INPUT_STATUS_1  equ     03dah   ;VGA status register
  44. VSYNC_MASK      equ     08h     ;vertical sync bit in status register 1
  45. DE_MASK         equ     01h     ;display enable bit in status register 1
  46. AC_INDEX        equ     03c0h   ;AC index register
  47. HPELPAN         equ     20h OR 13h      ;AC horizontal pel panning register
  48.                                         ; (bit 7 is high to keep palette RAM
  49.                                         ; addressing on)
  50. dseg    segment para common 'DATA'
  51. CurrentPage             db      PAGE1           ;page to draw to
  52. CurrentPageOffset       dw      PAGE1_OFFSET
  53. ;
  54. ; Four plane's worth of multicolored ball image.
  55. ;
  56. BallPlane0Image label   byte            ;blue plane image
  57.         db      000h, 03ch, 000h, 001h, 0ffh, 080h
  58.         db      007h, 0ffh, 0e0h, 00fh, 0ffh, 0f0h
  59.         db      4 * 3 dup(000h)
  60.         db      07fh, 0ffh, 0feh, 0ffh, 0ffh, 0ffh
  61.         db      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh
  62.         db      4 * 3 dup(000h)
  63.         db      07fh, 0ffh, 0feh, 03fh, 0ffh, 0fch
  64.         db      03fh, 0ffh, 0fch, 01fh, 0ffh, 0f8h
  65.         db      4 * 3 dup(000h)
  66. BallPlane1Image label   byte            ;green plane image
  67.         db      4 * 3 dup(000h)
  68.         db      01fh, 0ffh, 0f8h, 03fh, 0ffh, 0fch
  69.         db      03fh, 0ffh, 0fch, 07fh, 0ffh, 0feh
  70.         db      07fh, 0ffh, 0feh, 0ffh, 0ffh, 0ffh
  71.         db      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh
  72.         db      8 * 3 dup(000h)
  73.         db      00fh, 0ffh, 0f0h, 007h, 0ffh, 0e0h
  74.         db      001h, 0ffh, 080h, 000h, 03ch, 000h
  75. BallPlane2Image label   byte            ;red plane image
  76.         db      12 * 3 dup(000h)
  77.         db      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh
  78.         db      0ffh, 0ffh, 0ffh, 07fh, 0ffh, 0feh
  79.         db      07fh, 0ffh, 0feh, 03fh, 0ffh, 0fch
  80.         db      03fh, 0ffh, 0fch, 01fh, 0ffh, 0f8h
  81.         db      00fh, 0ffh, 0f0h, 007h, 0ffh, 0e0h
  82.         db      001h, 0ffh, 080h, 000h, 03ch, 000h
  83. BallPlane3Image label   byte            ;intensity on for all planes,
  84.                                         ; to produce high-intensity colors
  85.         db      000h, 03ch, 000h, 001h, 0ffh, 080h
  86.         db      007h, 0ffh, 0e0h, 00fh, 0ffh, 0f0h
  87.         db      01fh, 0ffh, 0f8h, 03fh, 0ffh, 0fch
  88.         db      03fh, 0ffh, 0fch, 07fh, 0ffh, 0feh
  89.         db      07fh, 0ffh, 0feh, 0ffh, 0ffh, 0ffh
  90.         db      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh
  91.         db      0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh
  92.         db      0ffh, 0ffh, 0ffh, 07fh, 0ffh, 0feh
  93.         db      07fh, 0ffh, 0feh, 03fh, 0ffh, 0fch
  94.         db      03fh, 0ffh, 0fch, 01fh, 0ffh, 0f8h
  95.         db      00fh, 0ffh, 0f0h, 007h, 0ffh, 0e0h
  96.         db      001h, 0ffh, 080h, 000h, 03ch, 000h
  97. ;
  98. BallX           dw      15, 50, 40, 70          ;array of ball x coords
  99. BallY           dw      40, 200, 110, 300       ;array of ball y coords
  100. LastBallX       dw      15, 50, 40, 70          ;previous ball x coords
  101. LastBallY       dw      40, 100, 160, 30        ;previous ball y coords
  102. BallXInc        dw      1, 1, 1, 1              ;x move factors for ball
  103. BallYInc        dw      8, 8, 8, 8              ;y move factors for ball
  104. BallRep         dw      1, 1, 1, 1              ;# times to keep moving
  105.                                                 ; ball according to current
  106.                                                 ; increments
  107. BallControl     dw      Ball0Control, Ball1Control      ;pointers to current
  108.                 dw      Ball2Control, Ball3Control      ; locations in ball
  109.                                                         ; control strings
  110. BallControlString       dw      Ball0Control, Ball1Control ;pointers to
  111.                         dw      Ball2Control, Ball3Control ; start of ball
  112.                                                            ; control strings
  113. ;
  114. ; Ball control strings.
  115. ;
  116. Ball0Control    label   word
  117.         dw      10, 1, 4, 10, -1, 4, 10, -1, -4, 10, 1, -4, 0
  118. Ball1Control    label   word
  119.         dw      12, -1, 1, 28, -1, -1, 12, 1, -1, 28, 1, 1, 0
  120. Ball2Control    label   word
  121.         dw      20, 0, -1, 40, 0, 1, 20, 0, -1, 0
  122. Ball3Control    label   word
  123.         dw      8, 1, 0, 52, -1, 0, 44, 1, 0, 0
  124. ;
  125. ; Panning control string.
  126. ;
  127. ifdef MEDRES_VIDEO_MODE
  128. PanningControlString    dw      32, 1, 0, 34, 0, 1, 32, -1, 0, 34, 0, -1, 0
  129. else
  130. PanningControlString    dw      32, 1, 0, 184, 0, 1, 32, -1, 0, 184, 0, -1, 0
  131. endif
  132. PanningControl  dw      PanningControlString    ;pointer to current location
  133.                                                 ; in panning control string
  134. PanningRep      dw      1       ;# times to pan according to current
  135.                                 ; panning increments
  136. PanningXInc     dw      1       ;x panning factor
  137. PanningYInc     dw      0       ;y panning factor
  138. HPan            db      0       ;horizontal pel panning setting
  139. PanningStartOffset dw   0       ;start offset adjustment to produce vertical
  140.                                 ; panning & coarse horizontal panning
  141. dseg    ends
  142. ;
  143. ; Macro to set indexed register P2 of chip with index register
  144. ; at P1 to AL.
  145. ;
  146. SETREG  macro   P1, P2
  147.         mov     dx,P1
  148.         mov     ah,al
  149.         mov     al,P2
  150.         out     dx,ax
  151.         endm
  152. ;
  153. cseg    segment para public 'CODE'
  154.         assume  cs:cseg, ds:dseg
  155. start   proc    near
  156.         mov     ax,dseg
  157.         mov     ds,ax
  158. ;
  159. ; Select graphics mode.
  160. ;
  161. ifdef MEDRES_VIDEO_MODE
  162.         mov     ax,010h
  163. else
  164.         mov     ax,0eh
  165. endif
  166.         int     10h
  167. ;
  168. ; ES always points to VGA memory.
  169. ;
  170.         mov     ax,VIDEO_SEGMENT
  171.         mov     es,ax
  172. ;
  173. ; Draw border around playfield in both pages.
  174. ;
  175.         mov     di,PAGE0_OFFSET
  176.         call    DrawBorder      ;page 0 border
  177.         mov     di,PAGE1_OFFSET
  178.         call    DrawBorder      ;page 1 border
  179. ;
  180. ; Draw all four plane's worth of the ball to undisplayed VGA memory.
  181. ;
  182.         mov     al,01h          ;enable plane 0
  183.         SETREG  SC_INDEX, MAP_MASK
  184.         mov     si,offset BallPlane0Image
  185.         mov     di,BALL_OFFSET
  186.         mov     cx,BALL_WIDTH * BALL_HEIGHT
  187.         rep movsb
  188.         mov     al,02h          ;enable plane 1
  189.         SETREG  SC_INDEX, MAP_MASK
  190.         mov     si,offset BallPlane1Image
  191.         mov     di,BALL_OFFSET
  192.         mov     cx,BALL_WIDTH * BALL_HEIGHT
  193.         rep movsb
  194.         mov     al,04h          ;enable plane 2
  195.         SETREG  SC_INDEX, MAP_MASK
  196.         mov     si,offset BallPlane2Image
  197.         mov     di,BALL_OFFSET
  198.         mov     cx,BALL_WIDTH * BALL_HEIGHT
  199.         rep movsb
  200.         mov     al,08h          ;enable plane 3
  201.         SETREG  SC_INDEX, MAP_MASK
  202.         mov     si,offset BallPlane3Image
  203.         mov     di,BALL_OFFSET
  204.         mov     cx,BALL_WIDTH * BALL_HEIGHT
  205.         rep movsb
  206. ;
  207. ; Draw a blank image the size of the ball to undisplayed VGA memory.
  208. ;
  209.         mov     al,0fh                  ;enable all memory planes, since the
  210.         SETREG  SC_INDEX, MAP_MASK      ; blank has to erase all planes
  211.         mov     di,BLANK_OFFSET
  212.         mov     cx,BALL_WIDTH * BALL_HEIGHT
  213.         sub     al,al
  214.         rep stosb
  215. ;
  216. ; Set VGA to write mode 1, for block copying ball and blank images.
  217. ;
  218.         mov     dx,GC_INDEX
  219.         mov     al,GC_MODE
  220.         out     dx,al           ;point GC Index to GC Mode register
  221.         inc     dx              ;point to GC Data register
  222.         jmp     $+2             ;delay to let bus settle
  223.         in      al,dx           ;get current state of GC Mode
  224.         and     al,not 3        ;clear the write mode bits
  225.         or      al,1            ;set the write mode field to 1
  226.         jmp     $+2             ;delay to let bus settle
  227.         out     dx,al
  228. ;
  229. ; Set VGA offset register in words to define logical screen width.
  230. ;
  231.         mov     al,LOGICAL_SCREEN_WIDTH / 2
  232.         SETREG  CRTC_INDEX, CRTC_OFFSET
  233. ;
  234. ; Move the balls by erasing each ball, moving it, and
  235. ; redrawing it, then switching pages when they're all moved.
  236. ;
  237. BallAnimationLoop:
  238.         mov     bx,( NUM_BALLS * 2 ) - 2
  239. EachBallLoop:
  240. ;
  241. ; Erase old image of ball in this page (at location from one more earlier).
  242. ;
  243.         mov     si,BLANK_OFFSET ;point to blank image
  244.         mov     cx,[LastBallX+bx]
  245.         mov     dx,[LastBallY+bx]
  246.         call    DrawBall
  247. ;
  248. ; Set new last ball location.
  249. ;
  250.         mov     ax,[BallX+bx]
  251.         mov     [LastballX+bx],ax
  252.         mov     ax,[BallY+bx]
  253.         mov     [LastballY+bx],ax
  254. ;
  255. ; Change the ball movement values if it's time to do so.
  256. ;
  257.         dec     [BallRep+bx]            ;has current repeat factor run out?
  258.         jnz     MoveBall
  259.         mov     si,[BallControl+bx]     ;it's time to change movement values
  260.         lodsw                           ;get new repeat factor from
  261.                                         ; control string
  262.         and     ax,ax                   ;at end of control string?
  263.         jnz     SetNewMove
  264.         mov     si,[BallControlString+bx]       ;reset control string
  265.         lodsw                           ;get new repeat factor
  266. SetNewMove:
  267.         mov     [BallRep+bx],ax         ;set new movement repeat factor
  268.         lodsw                           ;set new x movement increment
  269.         mov     [BallXInc+bx],ax
  270.         lodsw                           ;set new y movement increment
  271.         mov     [BallYInc+bx],ax
  272.         mov     [BallControl+bx],si     ;save new control string pointer
  273. ;
  274. ; Move the ball.
  275. ;
  276. MoveBall:
  277.         mov     ax,[BallXInc+bx]
  278.         add     [BallX+bx],ax           ;move in x direction
  279.         mov     ax,[BallYInc+bx]
  280.         add     [BallY+bx],ax           ;move in y direction
  281. ;
  282. ; Draw ball at new location.
  283. ;
  284.         mov     si,BALL_OFFSET  ;point to ball's image
  285.         mov     cx,[BallX+bx]
  286.         mov     dx,[BallY+bx]
  287.         call    DrawBall
  288. ;
  289.         dec     bx
  290.         dec     bx
  291.         jns     EachBallLoop
  292.  
  293. ;
  294. ; Set up the next panning state (but don't program it into the
  295. ; VGA yet).
  296. ;
  297.         call    AdjustPanning
  298.  
  299. ;
  300. ; Wait for display enable (pixel data being displayed) so we know
  301. ; we're nowhere near vertical sync, where the start address gets
  302. ; latched and used.
  303. ;
  304.         call    WaitDisplayEnable
  305. ;
  306. ; Flip to the new page by changing the start address.
  307. ;
  308.         mov     ax,[CurrentPageOffset]
  309.         add     ax,[PanningStartOffset]
  310.         push    ax
  311.         SETREG  CRTC_INDEX, START_ADDRESS_LOW
  312.         mov     al,byte ptr [CurrentPageOffset+1]
  313.         pop     ax
  314.         mov     al,ah
  315.         SETREG  CRTC_INDEX, START_ADDRESS_HIGH
  316. ;
  317. ; Wait for vertical sync so the new start address has a chance
  318. ; to take effect.
  319. ;
  320.         call    WaitVSync
  321. ;
  322. ; Set horizontal panning now, just as new start address takes effect.
  323. ;
  324.         mov     al,[HPan]
  325.         mov     dx,INPUT_STATUS_1
  326.         in      al,dx                   ;reset AC addressing to index reg
  327.         mov     dx,AC_INDEX
  328.         mov     al,HPELPAN
  329.         out     dx,al                   ;set AC index to pel pan reg
  330.         mov     al,[HPan]
  331.         out     dx,al                   ;set new pel panning
  332. ;
  333. ; Flip the page to draw to to the undisplayed page.
  334. ;
  335.         xor     [CurrentPage],1
  336.         jnz     IsPage1
  337.         mov     [CurrentPageOffset],PAGE0_OFFSET
  338.         jmp     short EndFlipPage
  339. IsPage1:
  340.         mov     [CurrentPageOffset],PAGE1_OFFSET
  341. EndFlipPage:
  342. ;
  343. ; Exit if a key's been hit.
  344. ;
  345.         mov     ah,1
  346.         int     16h
  347.         jnz     Done
  348.         jmp     BallAnimationLoop
  349. ;
  350. ; Finished, clear key, reset screen mode and exit.
  351. ;
  352. Done:
  353.         mov     ah,0    ;clear key
  354.         int     16h
  355. ;
  356.         mov     ax,3    ;reset to text mode
  357.         int     10h
  358. ;
  359.         mov     ah,4ch  ;exit to DOS
  360.         int     21h
  361. ;
  362. start   endp
  363. ;
  364. ; Routine to draw a ball-sized image to all planes, copying from
  365. ; offset SI in VGA memory to offset CX,DX (x,y) in VGA memory in
  366. ; the current page.
  367. ;
  368. DrawBall        proc    near
  369.         mov     ax,LOGICAL_SCREEN_WIDTH
  370.         mul     dx      ;offset of start of top image scan line
  371.         add     ax,cx   ;offset of upper left of image
  372.         add     ax,[CurrentPageOffset]  ;offset of start of page
  373.         mov     di,ax
  374.         mov     bp,BALL_HEIGHT
  375.         push    ds
  376.         push    es
  377.         pop     ds      ;move from VGA memory to VGA memory
  378. DrawBallLoop:
  379.         push    di
  380.         mov     cx,BALL_WIDTH
  381.         rep movsb       ;draw a scan line of image
  382.         pop     di
  383.         add     di,LOGICAL_SCREEN_WIDTH ;point to next destination scan line
  384.         dec     bp
  385.         jnz     DrawBallLoop
  386.         pop     ds
  387.         ret
  388. DrawBall        endp
  389. ;
  390. ; Wait for the leading edge of vertical sync pulse.
  391. ;
  392. WaitVSync       proc    near
  393.         mov     dx,INPUT_STATUS_1
  394. WaitNotVSyncLoop:
  395.         in      al,dx
  396.         and     al,VSYNC_MASK
  397.         jnz     WaitNotVSyncLoop
  398. WaitVSyncLoop:
  399.         in      al,dx
  400.         and     al,VSYNC_MASK
  401.         jz      WaitVSyncLoop
  402.         ret
  403. WaitVSync       endp
  404.  
  405. ;
  406. ; Wait for display enable to happen (pixels to be scanned to
  407. ; the screen, indicating we're in the middle of displaying a frame).
  408. ;
  409. WaitDisplayEnable       proc    near
  410.         mov     dx,INPUT_STATUS_1
  411. WaitDELoop:
  412.         in      al,dx
  413.         and     al,DE_MASK
  414.         jnz     WaitDELoop
  415.         ret
  416. WaitDisplayEnable       endp
  417.  
  418. ;
  419. ; Perform horizontal/vertical panning.
  420. ;
  421. AdjustPanning   proc    near
  422.         dec     [PanningRep]    ;time to get new panning values?
  423.         jnz     DoPan
  424.         mov     si,[PanningControl]     ;point to current location in
  425.                                         ; panning control string
  426.         lodsw                           ;get panning repeat factor
  427.         and     ax,ax                   ;at end of panning control string?
  428.         jnz     SetnewPanValues
  429.         mov     si,offset PanningControlString  ;reset to start of string
  430.         lodsw                           ;get panning repeat factor
  431. SetNewPanValues:
  432.         mov     [PanningRep],ax         ;set new panning repeat value
  433.         lodsw
  434.         mov     [PanningXInc],ax        ;horizontal panning value
  435.         lodsw
  436.         mov     [PanningYInc],ax        ;vertical panning value
  437.         mov     [PanningControl],si     ;save current location in panning
  438.                                         ; control string
  439. ;
  440. ; Pan according to panning values.
  441. ;
  442. DoPan:
  443.         mov     ax,[PanningXInc]        ;horizontal panning
  444.         and     ax,ax
  445.         js      PanLeft                 ;negative means pan left
  446.         jz      CheckVerticalPan
  447.         mov     al,[HPan]
  448.         inc     al                      ;pan right; if pel pan reaches
  449.         cmp     al,8                    ; 8, it's time to move to the
  450.         jb      SetHPan                 ; next byte with a pel pan of 0
  451.         sub     al,al                   ; and a start offset that's one
  452.         inc     [PanningStartOffset]    ; higher
  453.         jmp     short SetHPan
  454. PanLeft:
  455.         mov     al,[HPan]
  456.         dec     al                      ;pan left; if pel pan reaches -1,
  457.         jns     SetHPan                 ; it's time to move to the next
  458.         mov     al,7                    ; byte with a pel pan of 7 and a
  459.         dec     [PanningStartOffset]    ; start offset that's one lower
  460. SetHPan:
  461.         mov     [HPan],al               ;save new pel pan value
  462. CheckVerticalPan:
  463.         mov     ax,[PanningYInc]        ;vertical panning
  464.         and     ax,ax
  465.         js      PanUp                   ;negative means pan up
  466.         jz      EndPan
  467.         add     [PanningStartOffset],LOGICAL_SCREEN_WIDTH
  468.                                         ;pan down by advancing the start
  469.                                         ; address by a scan line
  470.         jmp     short EndPan
  471. PanUp:
  472.         sub     [PanningStartOffset],LOGICAL_SCREEN_WIDTH
  473.                                         ;pan up by retarding the start
  474.                                         ; address by a scan line
  475. EndPan:
  476.         ret
  477. ;
  478. ; Draw textured border around playfield that starts at DI.
  479. ;
  480. DrawBorder      proc    near
  481. ;
  482. ; Draw the left border.
  483. ;
  484.         push    di
  485.         mov     cx,LOGICAL_SCREEN_HEIGHT / 16
  486. DrawLeftBorderLoop:
  487.         mov     al,0ch          ;select red color for block
  488.         call    DrawBorderBlock
  489.         add     di,LOGICAL_SCREEN_WIDTH * 8
  490.         mov     al,0eh          ;select yellow color for block
  491.         call    DrawBorderBlock
  492.         add     di,LOGICAL_SCREEN_WIDTH * 8
  493.         loop    DrawLeftBorderLoop
  494.         pop     di
  495. ;
  496. ; Draw the left border.
  497. ;
  498.         push    di
  499.         add     di,LOGICAL_SCREEN_WIDTH - 1
  500.         mov     cx,LOGICAL_SCREEN_HEIGHT / 16
  501. DrawRightBorderLoop:
  502.         mov     al,0eh          ;select yellow color for block
  503.         call    DrawBorderBlock
  504.         add     di,LOGICAL_SCREEN_WIDTH * 8
  505.         mov     al,0ch          ;select red color for block
  506.         call    DrawBorderBlock
  507.         add     di,LOGICAL_SCREEN_WIDTH * 8
  508.         loop    DrawRightBorderLoop
  509.         pop     di
  510. ;
  511. ; Draw the top border.
  512. ;
  513.         push    di
  514.         mov     cx,(LOGICAL_SCREEN_WIDTH - 2) / 2
  515. DrawTopBorderLoop:
  516.         inc     di
  517.         mov     al,0eh          ;select yellow color for block
  518.         call    DrawBorderBlock
  519.         inc     di
  520.         mov     al,0ch          ;select red color for block
  521.         call    DrawBorderBlock
  522.         loop    DrawTopBorderLoop
  523.         pop     di
  524. ;
  525. ; Draw the bottom border.
  526. ;
  527.         add     di,(LOGICAL_SCREEN_HEIGHT - 8) * LOGICAL_SCREEN_WIDTH
  528.         mov     cx,(LOGICAL_SCREEN_WIDTH - 2) / 2
  529. DrawBottomBorderLoop:
  530.         inc     di
  531.         mov     al,0ch          ;select red color for block
  532.         call    DrawBorderBlock
  533.         inc     di
  534.         mov     al,0eh          ;select yellow color for block
  535.         call    DrawBorderBlock
  536.         loop    DrawBottomBorderLoop
  537.         ret
  538. DrawBorder      endp
  539. ;
  540. ; Draws an 8x8 border block in color in AL at location DI.
  541. ; DI preserved.
  542. ;
  543. DrawBorderBlock proc    near
  544.         push    di
  545.         SETREG  SC_INDEX, MAP_MASK
  546.         mov     al,0ffh
  547.         rept 8
  548.         stosb
  549.         add     di,LOGICAL_SCREEN_WIDTH - 1
  550.         endm
  551.         pop     di
  552.         ret
  553. DrawBorderBlock endp
  554. AdjustPanning   endp
  555. cseg    ends
  556.         end     start
  557.  
  558.