home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 June / SIMTEL_0692.cdr / msdos / pctech / aug86.arc / SPRITES.ARC / SPRITES2.ASM < prev    next >
Assembly Source File  |  1986-09-15  |  21KB  |  627 lines

  1. ;
  2. ; *** Listing 2 ***
  3. ;
  4. ;These routines produce the effect of hardware sprites in software
  5. ; on IBM PC compatible computers. They put objects onto the screen
  6. ; in a manner which preserves the background, and produces no
  7. ; undesirable fringe or overlap effects. Operations which affect
  8. ; video buffer memory are performed as much as possible during
  9. ; video non-display periods to avoid other undesirable effects.
  10. ;
  11. ; Entry points and parameters:
  12. ;
  13. ;   Initialize - Sets the background buffer address to be used to erase
  14. ;    objects, resets internal flags and queue, and on EGAs
  15. ;    sets up the use of the vertical interrupt to drive the
  16. ;    drawing routines.
  17. ;
  18. ;    Inputs    - AX holds paragraph address of background buffer.
  19. ;    Outputs - None.
  20. ;
  21. ;   Terminate  - Resets the EGA vertical interrupt hardware and vector
  22. ;
  23. ;    Inputs    - None.
  24. ;    Outputs - None.
  25. ;
  26. ;   Object_services - Sets X,Y and Form address for a given object
  27. ;    to be drawn, and activates or deactivates the object.
  28. ;
  29. ;    Inputs    - CX holds X position in bytes (0-79) of upper
  30. ;           left hand corner of object. 0 is leftmost.
  31. ;        - BX holds Y position in lines (0-198) 0 is top.
  32. ;           BX must be even! Objects cannot start on odd lines.
  33. ;           Objects must also be an even number of lines high.
  34. ;        - DI holds object number. Higher numbered objects
  35. ;           will appear to be in front of lower numbered
  36. ;           objects when they overlap.
  37. ;        - SI holds the offset in the code segment of the form
  38. ;           to be drawn for the object. A value of 0ffffh means
  39. ;           that the object is to be erased, then ignored.
  40. ;           Forms must be in the following format:
  41. ;
  42. ;              byte 0 - height in lines (h)
  43. ;              byte 1 - width in bytes  (w)
  44. ;              followed by w X h (mask word, image word) pairs.
  45. ;
  46. ;    Outputs - None.
  47. ;
  48. ;    Registers - All are saved, except flags
  49. ;
  50. ;    Warning - No bounds checking is done. X,Y or object numbers
  51. ;           out of range can send your program into hyperspace.
  52. ;
  53. ;   Put_objects_on_screen - This routine should be called by a program
  54. ;    running on a CGA to put the objects on the screen. It must be
  55. ;    far-called as if it were an interrupt routine. For example:
  56. ;
  57. ;               pushf
  58. ;               call far ptr put_objects_on_screen
  59. ;
  60. ;    For best results this routine should be called immediately
  61. ;     upon the sensing of vertical retrace.
  62. ;
  63. ;    Inputs    - None.
  64. ;    Outputs - None.
  65. ;
  66. ; Vert_int_modulo_count - This memory word is incremented each time
  67. ;   the objects are put into the screen map. On EGAs it can be used
  68. ;   to synchronize a program to the constant time base provided by
  69. ;   the vertical interrupt.
  70. ;
  71. ;The flag below must be set properly before assembling this program
  72. ;
  73. ega    equ  1         ;1 to assemble for Enhanced Graphics Adapter
  74.              ;0 to assemble for Color Graphics Adapter
  75. cga    equ  (ega xor 1) ;the opposite status of ega
  76. ;
  77. bios_data_segment segment at 40h    ;BIOS keeps its data at 400h;
  78.     org    63h            ;at 463h is a word that holds
  79. bios_crtc_base_address    dw    ?    ; the CRT controller's base
  80. bios_data_segment ends            ; address
  81. ;
  82. ;
  83. cseg    segment para public 'cseg'
  84.     assume    cs:cseg,ds:cseg,es:nothing
  85.     public    initialize,terminate,object_services
  86.     public    put_objects_on_screen,vert_int_modulo_count
  87. ;
  88. ;Memory for the parameters used to keep track of objects is reserved
  89. ; below. Many of the parameters stored are very code specific so that
  90. ; the size and number of objects which could be processed during
  91. ; vertical non-display time could be maximized.
  92. ;
  93. number_of_objects equ    3  ;this should be set to the maximum number
  94.                ; of objects or priorities which will
  95.                ; need to be kept track of at one time.
  96. ;
  97. queue label word
  98. ;
  99. draw_screen_offset    dw ?  ;offset in screen memory buffer of upper
  100.                   ; left hand corner of object. 0ffffh if
  101.                   ; object is to be ignored.
  102. dist_to_odd_scan_line    dw ?  ;distance from end of object on an even
  103.                   ; scan line to the start of the object
  104.                   ; on the next (odd) scan line
  105. dist_to_even_scan_line    dw ?  ;distance from end of object on an odd
  106.                   ; scan line to the start of the object
  107.                   ; on the next (even) scan line
  108. ;
  109. erase_parms label word
  110. ;
  111. erase_width         dw ?  ;the object's screen image width in words
  112. erase_entry_point    dw ?  ;the address of the inline code to do erase
  113. erase_screen_offset  dw ?  ;the address where object was last drawn
  114.                ; 0ffffh if object is not to be erased.
  115. erase_image_offset   dw ?  ;used to determine if need to erase when
  116.                ; object is in old position
  117. ;
  118. length_of_erase_parms equ $-erase_parms
  119. ;
  120. draw_col_entry_point dw ?  ;address of the column code for drawing
  121. draw_row_entry_point dw ?  ;address of the row inline code for drawing
  122. draw_image_offset    dw ?  ;offset in the code segment of the image
  123. ;
  124. queue_item_length equ ($ - queue) ;number of bytes for each item
  125. distance_from_entry_point_to_next_item equ $ - erase_entry_point
  126. distance_from_image_to_next_item equ $ - draw_image_offset
  127. ;
  128.     db    (  (number_of_objects-1) * queue_item_length ) dup(?)
  129. end_of_queue label word
  130. ;
  131. vert_int_modulo_count    dw 0  ;incremented each time a vertical
  132.                   ; interrupt occurs
  133. background_segment    dw ?  ;place to hold the paragraph address
  134.                   ; of the background buffer used to
  135.                   ; erase objects
  136. crtc_base_address    dw ?  ;will hold register address
  137. ;
  138. old_int10_offset    dw ?  ;place to store the vector contents
  139. old_int10_segment    dw ?  ; so they can be restored when finished
  140. ;
  141. old_int_mask        db ?  ;place to store the mask register's
  142.                   ; contents so it can be restored
  143. ;
  144. true    equ    1  ;used for flag values
  145. false    equ    0  ;
  146. ;
  147. need_to_draw_something_flag db false ;true if a change needs to be
  148.                      ; made to any of the objects'
  149.                      ; screen images
  150. ;
  151. screen_buffer_paragraph_adr equ 0b800h
  152. ;
  153. ;
  154. initialize proc near
  155.     cld                   ;count up
  156.     push    ds               ;
  157.     mov    cs:[background_segment],ax ;store background adr
  158.     mov    ax,cs               ;make data segment
  159.     mov    ds,ax               ; same as code segment
  160.                        ; since that is where data
  161.     mov    es,ax               ; used by this routine is
  162.     mov    di,offset queue        ;turn off all objects
  163.     mov    cx,(number_of_objects * queue_item_length)/2
  164.     mov    ax,0ffffh           ;
  165.     rep stosw               ;
  166. ;
  167.     mov    [need_to_draw_something_flag],false ;nothing to draw
  168. if ega
  169.     sub    ax,ax                ;swapping interrupt
  170.     mov    ds,ax                ; vectors with our
  171.     mov    bx,(10*4)            ; interrupt handler
  172.     mov    ax,offset put_objects_on_screen ;our vertical int
  173.     mov    dx,cs                ; handler address
  174.     cli                    ;disable interrupts
  175.     xchg    [bx],ax             ;offset
  176.     xchg    [bx+2],dx            ;segment
  177.     mov    cs:[old_int10_offset],ax    ;save old value so we
  178.     mov    cs:[old_int10_segment],dx    ; can restore it upon
  179. ;                        ; termination
  180.     mov    ax,bios_data_segment        ;find the register
  181.     mov    ds,ax                ; address
  182.     assume    ds:bios_data_segment        ;
  183.     mov    dx,[bios_crtc_base_address]    ;
  184.     mov    cs:[crtc_base_address],dx    ;save it in code seg
  185.     mov    al,11h                ;select vertical
  186.     out    dx,al                ; retrace end register
  187.     mov    al,04h                ; and enable & clear
  188.     inc    dx                ; vertical interrupt
  189.     out    dx,al                ;
  190.     jmp    $+2                ;allow time for bus to
  191.                         ; settle in ATs
  192.     mov    al,14h                ;then release clear
  193.     out    dx,al                ;
  194. ;
  195.     in    al,21h                ;enable IRQ2
  196.     mov    cs:[old_int_mask],al        ; save old value
  197.     and    al,not 4            ;
  198.     out    21h,al                ;
  199. ;
  200.     sti                    ;enable interrupts
  201. endif
  202.     pop    ds                ;restore data segment
  203.     assume    ds:cseg
  204.     ret
  205. initialize endp
  206. ;
  207. terminate    proc    near   ;only needs to be used when assembled
  208. if ega                   ; for use on an EGA
  209.     mov    dx,[crtc_base_address]
  210.     mov    al,11h
  211.     out    dx,al
  212.     inc    dx
  213.     mov    al,24h           ;bit 5 high to disable, bit 4 low to
  214.     out    dx,al           ; clear vertical interrupt
  215.     push    ds
  216.     sub    ax,ax              ;restore original interrupt
  217.     mov    ds,ax              ; 10 vector
  218.     mov    bx,(10*4)          ;
  219.     mov    ax,cs:[old_int10_offset]  ;
  220.     mov    dx,cs:[old_int10_segment] ;
  221.     cli                  ;make sure interrupt
  222.     mov    [bx],ax           ; doesn't occur while
  223.     mov    [bx+2],dx          ; there is an inconsistant
  224.                       ; vector/mask
  225.     mov    bl,cs:[old_int_mask]      ;restore IRQ2 mask bit
  226.     and    bl,4              ; to state it had when
  227.     in    al,21h              ; Initialize was called
  228.     and    al,not 4          ;
  229.     or    al,bl              ;
  230.     out    21h,al              ;
  231.     sti
  232.     pop    ds
  233. endif
  234.     ret
  235. terminate endp
  236. ;
  237. object_services proc near
  238.     cld            ;
  239.     push    es        ;save the registers used
  240.     push    ds        ;
  241.     push    ax        ;
  242.     push    bx        ;
  243.     push    cx        ;
  244.     push    si        ;
  245.     push    di        ;
  246. ;
  247.     mov    ax,cs        ;everything will be in code segment
  248.     mov    es,ax        ;
  249.     mov    ds,ax        ;
  250.  
  251. ;
  252.     shl    di,1        ;multiply object number
  253.     shl    di,1        ; which is in DI by 20 to
  254.     mov    ax,di        ; find object's parameter table
  255.     shl    di,1        ; offset in queue structure
  256.     shl    di,1        ; (NOTE: If a code change alters
  257.     add    di,ax        ;  queue_item_length this code must
  258. ;                ;  be changed!)
  259.     mov    ax,offset queue ;point directly to object's first
  260.     add    di,ax        ; parameter
  261.     mov    ax,[bx+even_line_screen_offset_table]
  262.     add    ax,cx        ;find screen offset of top left corner
  263. if ega
  264.     cli     ;can't allow parameters to be just half
  265.          ; changed if a vertical interrupt occurs
  266. endif
  267.     cmp    si,0ffffh    ;if object is to be turned off then
  268.     jne    save_position    ; need to store a 0ffffh for the draw
  269.     mov    ax,si        ; screen position
  270.     stosw            ;
  271.     jmp short finish_services
  272. save_position:            ;
  273.     stosw         ;save as first parameter (draw_screen_offset)
  274.     lodsb         ;get the height of the image
  275.     xor    ah,ah     ;make height a word
  276.     mov    bx,ax     ;store height
  277.     lodsb         ;get the width of the image in bytes
  278.     mov    cx,2000h ;calculate amount to add after even scan
  279.     sub    cx,ax     ; lines are drawn to get the address of the
  280.     xchg    ax,cx     ; next scan line, and store it in queue
  281.     stosw         ;
  282.     mov    ax,1fb0h ;calculate amount to subtract after odd scan
  283.     add    ax,cx     ; lines are drawn to get the address of the
  284.     stosw         ; next scan line, and store it in queue
  285.     mov    ax,cx     ;store the width in queue
  286.     shr    ax,1     ; width is stored as number of words
  287.     stosw         ;
  288.     mov    ax,[bx+erase_inline_vector_table-2]
  289.              ;-2 because there is no 0 lines entry point
  290.     stosw         ;store the place to jump to erase an image
  291.              ; of this height
  292.     add    di,4     ;skip erase_screen_offset and
  293.              ; erase_image_offset as these are filled
  294.              ; in when an object is drawn
  295.     xchg    si,cx     ;swap image offset with width
  296.     mov    ax,[si+column_inline_vector_table-2] ;inline code adr
  297.     stosw         ; driver operates with words, so there is no
  298.              ; need to divide SI by two to do table lookup
  299.     mov    ax,[bx+row_inline_vector_table-2] ;inline code adr
  300.     stosw         ; which calls column inline code for each row
  301.     mov    [di],cx  ;last param to put on queue is image offset
  302. ;
  303. finish_services:
  304.     mov    [need_to_draw_something_flag],true ;record change
  305. if ega
  306.     sti         ;all parameters have been put on queue
  307.              ; so interrupts are safe now
  308. endif
  309.     pop    di     ;restore those registers that were used
  310.     pop    si     ;
  311.     pop    cx     ;
  312.     pop    bx     ;
  313.     pop    ax     ;
  314.     pop    ds     ;
  315.     pop    es     ;
  316.     ret         ;
  317. object_services endp
  318. ;
  319. ;This table is used to find the offset of an even scan line in the
  320. ; memory map of the color graphics adapter in medium resolution mode.
  321. ;
  322. even_line_screen_offset_table label word
  323. xx=0
  324.     rept    100    ;there are 100 even lines
  325.     dw    xx*50h    ; each is 50h (80 decimal) long
  326. xx=xx+1
  327.     endm
  328. ;
  329. use_old_vector:
  330.     pop    ax    ;restore registers used before
  331.     pop    dx    ; jumping to previous IRQ2 handler
  332.     jmp dword ptr cs:[old_int10_offset]
  333. ;
  334. put_objects_on_screen proc far
  335.     push    dx    ;save registers used by EGA code
  336.     push    ax    ;
  337. if ega
  338.             ;must check if interrupt is being signaled
  339.             ; by the EGA card, as specified by IBM
  340.             ; technical documents. If not, it needs to
  341.     mov    dx,3c2h ; be handled by another routine in the vector
  342.     in    al,dx    ; chain.
  343.     test    al,80h
  344.     jz    use_old_vector
  345. endif
  346.     inc    cs:[vert_int_modulo_count]     ;count vert interrupts
  347.     sti                       ;enable interrupts
  348.     cmp    cs:[need_to_draw_something_flag],true ;anything to do?
  349.     je    process_queue               ; jmp if there is
  350.                            ; otherwise do nothing
  351. if ega
  352.     cli
  353.     mov    al,20h    ;issue a non_specific EOI (End Of Interrupt)
  354.     out    20h,al    ; so that interrupt controller chip will
  355.             ; acknowledge future vertical interrupts
  356.     mov    dx,cs:[crtc_base_address] ;re-enable ega card interrupt
  357.     mov    al,11h    ;select vertical
  358.     out    dx,al    ; retrace end register
  359.     mov    al,04h    ; and clear vertical
  360.     inc    dx    ; interrupt
  361.     out    dx,al    ;
  362.     jmp    $+2    ;allow time for bus to
  363.             ; settle in ATs
  364.     mov    al,14h    ;then release clear
  365.     out    dx,al    ;
  366. endif
  367.     pop    ax    ;restore original values
  368.     pop    dx    ;
  369.     iret
  370. ;
  371. skip_this_object:
  372.     add    si,queue_item_length         ;point SI to next item
  373.     cmp    si,offset end_of_queue         ;see if we are done
  374.     je    draw                 ; jmp to draw if we are
  375.     jmp    get_next_objects_screen_adr  ; if not, erase next
  376. ;
  377. process_queue:
  378.     push    bx    ;save the rest of the world
  379.     push    cx    ;
  380.     push    bp    ;
  381.     push    si    ;
  382.     push    di    ;
  383.     push    ds    ;
  384.     push    es    ;
  385. ;
  386.     push    cs    ;setup environment
  387.     pop    ds    ; data is in code segment
  388.     cld        ; we will count up
  389.     mov    ax,screen_buffer_paragraph_adr
  390.     mov    es,ax    ; ES points to screen memory
  391. ;
  392.     mov    si,offset queue ;point to beginning of queue
  393. ;
  394. ;Erase all the active objects which have old screen positions
  395. ; different from their present screen position or have different
  396. ; image offsets
  397. ;
  398. get_next_objects_screen_adr:
  399.     mov    ax,[si+erase_screen_offset-draw_screen_offset]
  400.                   ; get the screen buffer
  401.                   ; offset of last draw
  402.     cmp    ax,0ffffh      ;if ffffh then object is
  403.     je    skip_this_object  ; yet to be drawn
  404.     cmp    ax,[si]       ;if new and old positions and
  405.     jne    erase_this_object ; images are same then skip erase
  406.     mov    di,[si+erase_image_offset-draw_screen_offset]
  407.     cmp    di,[si+draw_image_offset-draw_screen_offset]
  408.     je    skip_this_object  ;
  409. erase_this_object:
  410.     inc    si          ;point to next parameter
  411.     inc    si          ;
  412.     mov    di,ax          ;save screen buffer adr
  413.     lodsw              ;get distance to odd scan line
  414.     mov    bp,ax          ; save in BP for inline code use
  415.     lodsw              ;get distance to even scan line
  416.     mov    dx,ax          ; save in DX for inline code use
  417.     lodsw              ;get the width in words for erase
  418.     mov    cx,[si]       ;get address of erase inline code
  419. ;
  420.     push    si          ;save position so next object
  421.     push    ds          ; can be found
  422.     mov    ds,[background_segment] ;stuff to erase with
  423.     call    cx          ;erase it!
  424.     pop    ds          ;restore where
  425.     pop    si          ; we left off in queue
  426.     add    si,distance_from_entry_point_to_next_item ;next item
  427.     cmp    si,offset end_of_queue         ;see if we are done
  428.     jne    get_next_objects_screen_adr  ; jmp if more to erase
  429. ;
  430. ;Draw all the active objects by AND/ORing into screen buffer
  431. ;
  432. draw:
  433.     mov    si,offset queue   ;point to beginning of queue
  434. ;
  435. get_next_objects_screen_adr2:
  436.     lodsw              ;get screen buffer offset
  437.     mov    [si+erase_screen_offset-draw_screen_offset-2],ax
  438.                   ;save what will be old position
  439.     mov    di,[si+draw_image_offset-draw_screen_offset-2]
  440.                   ;save what will be old image offset
  441.     mov    [si+erase_image_offset-draw_screen_offset-2],di
  442.     cmp    ax,0ffffh      ;see if object is active
  443.     je    skip_this_object2 ; jmp if it isn't
  444.     mov    di,ax          ;save screen buffer adr
  445.     lodsw              ;get distance to odd scan line
  446.     mov    bp,ax          ; save in BP for inline code use
  447.     lodsw              ;get distance to even scan line
  448.     mov    dx,ax          ; save in DX for inline code use
  449.     add    si,length_of_erase_parms ;skip the erase parameters
  450.     lodsw              ;get the draw inline row adr
  451.     mov    cx,ax          ; save in CX for inline use
  452.     lodsw              ;get the draw inline row adr
  453.     mov    bx,ax          ; save in BX for call to inline
  454.     lodsw              ;get draw_image offset
  455.     push    si          ;save pointer to next queue item
  456.     mov    si,ax          ;save draw image in SI
  457.     call    bx          ;draw it!
  458.     pop    si          ;restore where we left off in queue
  459.     cmp    si,offset end_of_queue         ;see if we are done
  460.     jne    get_next_objects_screen_adr2 ; jmp if more to erase
  461. ;
  462. finish_up:
  463. if ega
  464.     cli
  465.     mov    al,20h    ;issue a non_specific EOI (End Of Interrupt)
  466.     out    20h,al    ; so that interrupt controller chip will
  467.             ; acknowledge future vertical interrupts
  468.     mov    dx,cs:[crtc_base_address] ;re-enable interrupt
  469.     mov    al,11h    ;select vertical
  470.     out    dx,al    ; retrace end register
  471.     mov    al,04h    ; and clear vertical
  472.     inc    dx    ; interrupt
  473.     out    dx,al    ;
  474.     jmp    $+2    ;allow time for bus to
  475.             ; settle in ATs
  476.     mov    al,14h    ;then release clear
  477.     out    dx,al    ;
  478. endif
  479.     pop    es    ;restore all registers
  480.     pop    ds    ;
  481.     pop    di    ;
  482.     pop    si    ;
  483.     pop    bp    ;
  484.     pop    cx    ;
  485.     pop    bx    ;
  486.     pop    ax    ;
  487.     pop    dx    ;
  488.     mov    cs:[need_to_draw_something_flag],false
  489.             ;indicate no reason to    draw again until the
  490.             ; queue is changed
  491.     iret        ;restore flags and contine where interrupted
  492. ;
  493. skip_this_object2:
  494.     add    si,(queue_item_length-2)     ;point SI to next item
  495.     cmp    si,offset end_of_queue         ;see if we are done
  496.     jne    get_next_objects_screen_adr2 ; jmp if not
  497.     jmp short finish_up             ; jmp if all finished
  498. put_objects_on_screen endp
  499. ;
  500. ;
  501. ;This is inline code for finding the screen address for each line
  502. ; of the image and calling the AND-OR inline code.
  503. ;
  504. rlabel     macro     xx    ;this macro is used to label the inline code
  505. rline&xx&:        ; entry points
  506.     endm
  507. ;
  508. ;
  509. ; inline code for rows
  510. ;
  511. xx=42            ;there will be an entry point for each even
  512.             ; number of lines between 2 and 40. They will
  513.             ; be labeled "rline2", "rline4", ... "rline40"
  514.     rept    20    ;each repeat handles two lines
  515. xx=xx-2         ;calculate number of lines for entry point
  516.     rlabel    %xx    ;put in label for entry point
  517.  
  518.     call    cx    ;CX holds address of inline columns code
  519.     add    di,bp    ;calculate the address to start next line
  520.     call    cx    ;process image for odd scan line
  521.     sub    di,dx    ;calculate the address to start next line
  522.     endm        ; the next line will be an even line
  523.     ret
  524. ;
  525. ;Inline code for AND-ORing a line of the image into the screen
  526. ;
  527. clabel     macro    xx    ;this macro is used to label the inline code
  528. cline&xx&:        ; entry points for number of columns to AND-OR
  529.     endm        ;
  530. ;
  531. xx=10            ;this code can handle an image up to ten words
  532.     rept    10    ; wide
  533.     clabel    %xx    ;put in label for entry based on number of
  534.             ; words in a column
  535.     lodsw           ;get mask word
  536.     and    ax,es:[di] ;mask out background
  537.     or    ax,[si]    ;insert data word
  538.     inc    si       ;point to next mask word
  539.     inc    si       ;
  540.     stosw           ;return modified word to memory
  541. xx=xx-1            ;adjust label number
  542.     endm
  543.     ret           ;this return is executed at the end of every
  544.                ; line
  545. ;
  546. ;This table is used as an indirect address for jumping into
  547. ; the inline code for image moving.
  548. ;
  549. row_inline_vector_table label word ;there is no entry point for zero
  550.                    ; lines. Starting at 2 eliminates
  551.                    ; the need to store a dummy entry
  552.                    ; point address
  553. row_entry_address   macro   xx       ;this macro is used to generate
  554.         dw    rline&xx&  ; the labels corresponding to the
  555.         endm           ; inline code entry points
  556. ;
  557. xx=2
  558.     rept    20
  559.     row_entry_address    %xx
  560. xx=xx+2
  561.     endm
  562. ;
  563. ;This table is used as an indirect address for jumping into
  564. ; the inline code for exclusive-ORing columns.
  565. ;
  566. column_inline_vector_table label word     ;there is no entry point for zero
  567.                      ; lines. Starting at 2 eliminates
  568.                      ; the need to store a dummy entry
  569.                      ; point address
  570. column_entry_address   macro   xx     ;this macro is used to generate
  571.          dw     cline&xx&     ; the labels corresponding to the
  572.          endm             ; inline code entry points
  573. ;
  574. xx=1
  575.     rept    10
  576.     column_entry_address   %xx
  577. xx=xx+1
  578.     endm
  579. ;
  580. ;This is inline code for erasing the image by restoring the screen
  581. ; memory map from the background buffer.
  582. ;
  583. elabel    macro    xx    ;this macro is used to label the inline code
  584. eline&xx&:        ; entry points
  585.     endm
  586. ;
  587. xx=42            ;there will be an entry point for each even
  588.             ; number of lines between 2 and 40. They will
  589.             ; be labeled "eline2", "eline4", ... "eline40"
  590.     rept    20
  591. xx=xx-2         ;calculate number of lines for this entry point
  592.     elabel  %xx     ;put in label for entry point
  593.     mov     si,di   ;erase using same offset in background buffer
  594.     mov     cx,ax   ;put width of image in words in CX to prepare for
  595.     rep     movsw   ; repeated move string on even line
  596.     add     di,bp   ;calculate address of next line DI + (2000h-width)
  597.     mov     si,di   ;erase using same offset in background buffer
  598.     mov     cx,ax   ;put width of image in bytes in CX to prepare for
  599.     rep     movsw   ; repeated move string on odd line
  600.     sub     di,dx   ;calculate address of next line DI - (1fb0h+width)
  601.     endm
  602.     ret
  603. ;
  604. ;This table is used as an indirect address for jumping into
  605. ; the inline code for erasing an image.
  606. ;
  607. erase_inline_vector_table label word ;there is no entry point for zero
  608.                      ; lines. Starting at 2 eliminates
  609.                      ; the need to store a dummy entry
  610.                      ; point address
  611. entry_address    macro    xx         ;this macro is used to generate
  612.         dw    eline&xx&    ; the labels corresponding to the
  613.         endm             ; inline code entry points
  614. ;
  615. xx=2
  616.     rept    20
  617.     entry_address    %xx
  618. xx=xx+2
  619.     endm
  620. ;
  621. cseg    ends
  622.     end
  623.  
  624.  
  625.  
  626.  
  627.