home *** CD-ROM | disk | FTP | other *** search
/ CD-X 1 / cdx_01.iso / demodisc / basq / source / 3dvektor / xmode.asm < prev    next >
Encoding:
Assembly Source File  |  1994-10-29  |  135.3 KB  |  3,309 lines

  1. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  2. ; MODEX.ASM - A Complete Mode X Library
  3. ;
  4. ; Version 1.04 Release, 3 May 1993, By Matt Pritchard
  5. ; With considerable input from Michael Abrash
  6. ;
  7. ; The following information is donated to the public domain in
  8. ; the hopes that save other programmers much frustration.
  9. ;
  10. ; If you do use this code in a product, it would be nice if
  11. ; you include a line like "Mode X routines by Matt Pritchard"
  12. ; in the credits.
  13. ;
  14. ; Protected Mode modification by John McCarthy
  15. ; John McCarthy thanks Matt Pritchard for providing this code,
  16. ; and hopes Matt Pritchard is not offended by the changes.
  17. ;
  18. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  19. ;
  20. ; For all routines, the AX, BX, CX, DX, ES and FLAGS registers
  21. ; will not be preserved, while the DS, BP, SI and DI registers
  22. ; will be preserved.
  23. ;
  24. ; Unless specifically noted, All Parameters are assumed to be
  25. ; "PASSED BY VALUE".  That is, the actual value is placed on
  26. ; the stack.  When a reference is passed it is assumed to be
  27. ; a near pointer to a variable in the DGROUP segment.
  28. ;
  29. ; Routines that return a single 16-Bit integer value will
  30. ; return that value in the AX register.
  31. ;
  32. ; This code will *NOT* run on an 8086/8088 because 80286+
  33. ; specific instructions are used.   If you have an 8088/86
  34. ; and VGA, you can buy an 80386-40 motherboard for about
  35. ; $160 and move into the 90's.
  36. ;
  37. ; JM - revision, this code will *NOT* run on 80286 because of
  38. ; 80368+ code is used (and protected mode).
  39. ;
  40. ; This code is reasonably optimized: Most drawing loops have
  41. ; been unrolled once and memory references are minimized by
  42. ; keeping stuff in registers when possible.
  43. ;
  44. ; Error Trapping varies by Routine.  No Clipping is performed
  45. ; so the caller should verify that all coordinates are valid.
  46. ;
  47. ; Several Macros are used to simplify common 2 or 3 instruction
  48. ; sequences.  Several Single letter Text Constants also
  49. ; simplify common assembler expressions like "WORD PTR".
  50. ;
  51. ; ------------------ Mode X Variations ------------------
  52. ;
  53. ;  Mode #  Screen Size    Max Pages   Aspect Ratio (X:Y)
  54. ;
  55. ;    0      320 x 200      4 Pages         1.2:1
  56. ;    1      320 x 400      2 Pages         2.4:1
  57. ;    2      360 x 200      3 Pages        1.35:1
  58. ;    3      360 x 400      1 Page          2.7:1
  59. ;    4      320 x 240      3 Pages           1:1
  60. ;    5      320 x 480      1 Page            2:1
  61. ;    6      360 x 240      3 Pages       1.125:1
  62. ;    7      360 x 480      1 Page         2.25:1
  63. ;
  64. ; -------------------- The Legal Stuff ------------------
  65. ;
  66. ; No warranty, either written or implied, is made as to
  67. ; the accuracy and usability of this code product.  Use
  68. ; at your own risk.  Batteries not included.  Pepperoni
  69. ; and extra cheese available for an additional charge.
  70. ;
  71. ; ----------------------- The Author --------------------
  72. ;
  73. ; Matt Pritchard is a paid programmer who'd rather be
  74. ; writing games.  He can be reached at: P.O. Box 140264,
  75. ; Irving, TX  75014  USA.  Michael Abrash is a living
  76. ; god, who now works for Bill Gates (Microsoft).
  77. ;
  78. ; -------------------- Revision History -----------------
  79. ; 4-12-93: v1.02 - _set_point & _read_point now saves DI
  80. ;          _set_modex now saves SI
  81. ; 5-3-93:  v1.04 - added _load_dac_registers and
  82. ;          _read_dac_registers.  Expanded CLR Macro
  83. ;          to handle multiple registers
  84. ;
  85. ; Revisions by John McCarthy - sometime throughout June/93:
  86. ;
  87. ; - Protected mode addressing for all routines.
  88. ; - Conditional assembley for routines not wanted by user
  89. ; - Bios text addressing removed - see _set_vga_modex
  90. ; - File assembles for protected mode, variables and routines made public
  91. ; - _mode03 routine added to return to DOS mode.  Must be used in conjunction
  92. ;      with TRAN's protected mode header.
  93. ; - Also added routines to turn off the screen to avoid that screen  flicker
  94. ;      when changing into xmode.
  95. ;
  96. ; A note from John McCarthy:
  97. ;
  98. ;  When converting to protected mode, loop's, rep's, stosb's and such
  99. ;  must have the high word of the ecx,edi,esi registers set.  I have tested
  100. ;  the routines now that they have been converted and they seem to all work
  101. ;  fine, but if you find they don't jive, please send me a message/letter and
  102. ;  I will get right on it.
  103. ;
  104. ;  These routines originally came with all kinds of extra files for font
  105. ;  editing, pallet editing, C stuff and demos.  I have only supplied the
  106. ;  critical files from Matt to cut down on .zip file size.
  107. ;
  108. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  109.  
  110. x_fill_block equ 1                ; small routines are automatically included
  111. x_draw_line  equ 1                ; which x mode routines should be included
  112. x_set_point  equ 1                ; when assembled; 1 = enabled
  113. x_read_point equ 1
  114. x_gprintc    equ 1
  115. x_tgprintc   equ 1
  116. x_set_window equ 1
  117. x_print_str  equ 1
  118. x_tprint_str equ 1
  119. x_set_font   equ 1
  120. x_draw_bitmap  equ 1
  121. x_tdraw_bitmap equ 1
  122. x_copy_page    equ 1
  123. x_copy_bitmap  equ 1
  124.  
  125.          .386p
  126.          jumps
  127.  
  128. code32   segment para public use32
  129.          assume cs:code32, ds:code32
  130.  
  131.          include pmode.ext                  ; protected mode externals
  132.          include macros.inc                 ; guess...
  133.          include equ.inc                    ; list of constants
  134.  
  135. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  136. ; Macros
  137. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  138. ; macro to clear registers to 0
  139.  
  140. clr      macro register, r2, r3, r4, r5, r6
  141.          ifnb <register>
  142.          xor register, register             ; set register = 0
  143.          clr r2, r3, r4, r5, r6
  144.          endif
  145. endm
  146.  
  147. ; macros to decrement counter & jump on condition
  148.  
  149. loopx    macro register, destination
  150.          dec register                       ; counter--
  151.          jnz destination                    ; jump if not 0
  152. endm
  153.  
  154. loopjz   macro register, destination
  155.          dec register                       ; counter--
  156.          jz destination                     ; jump if 0
  157. endm
  158.  
  159.          ?x4 equ <?,?,?,?>
  160.          ?x3 equ <?,?,?>
  161.          nil equ 0
  162.  
  163. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  164. ;
  165. ; Xmode routines by Matt Prichard
  166. ; Modified for 386 protected mode by John McCarthy
  167. ; Protected mode header courtesy of TRAN
  168. ;
  169. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  170.  
  171. ; bit mask tables for left/right/character masks
  172.  
  173.          public _left_clip_mask
  174.          public _right_clip_mask
  175.  
  176. _left_clip_mask  db 0fh, 0eh, 0ch, 08h
  177. _right_clip_mask db 01h, 03h, 07h, 0fh
  178.  
  179. ; bit patterns for converting character fonts
  180.  
  181. char_plane_data db 00h,08h,04h,0ch,02h,0ah,06h,0eh
  182.                 db 01h,09h,05h,0dh,03h,0bh,07h,0fh
  183.  
  184. ; crtc register values for various configurations
  185.  
  186. mode_single_line: ; crtc setup data for 400/480 line modes
  187.          dw 04009h                          ; cell height (1 scan line)
  188.          dw 00014h                          ; dword mode off
  189.          dw 0e317h                          ; turn on byte mode
  190.          dw nil                             ; end of crtc data for 400/480 line mode
  191.  
  192. mode_double_line: ; crtc setup data for 200/240 line modes
  193.          dw 04109h                          ; cell height (2 scan lines)
  194.          dw 00014h                          ; dword mode off
  195.          dw 0e317h                          ; turn on byte mode
  196.          dw nil                             ; end of crtc data for 200/240 line mode
  197.  
  198. mode_320_wide: ; crtc setup data for 320 horz pixels
  199.          dw 05f00h                          ; horz total
  200.          dw 04f01h                          ; horz displayed
  201.          dw 05002h                          ; start horz blanking
  202.          dw 08203h                          ; end horz blanking
  203.          dw 05404h                          ; start h sync
  204.          dw 08005h                          ; end h sync
  205.          dw nil                             ; end of crtc data for 320 horz pixels
  206.  
  207. mode_360_wide: ; crtc setup data for 360 horz pixels
  208.          dw 06b00h                          ; horz total
  209.          dw 05901h                          ; horz displayed
  210.          dw 05a02h                          ; start horz blanking
  211.          dw 08e03h                          ; end horz blanking
  212.          dw 05e04h                          ; start h sync
  213.          dw 08a05h                          ; end h sync
  214.          dw nil                             ; end of crtc data for 360 horz pixels
  215.  
  216. mode_200_tall:
  217. mode_400_tall: ; crtc setup data for 200/400 line modes
  218.          dw 0bf06h                          ; vertical total
  219.          dw 01f07h                          ; overflow
  220.          dw 09c10h                          ; v sync start
  221.          dw 08e11h                          ; v sync end/prot cr0 cr7
  222.          dw 08f12h                          ; vertical displayed
  223.          dw 09615h                          ; v blank start
  224.          dw 0b916h                          ; v blank end
  225.          dw nil                             ; end of crtc data for 200/400 lines
  226.  
  227. mode_240_tall:
  228. mode_480_tall: ; crtc setup data for 240/480 line modes
  229.          dw 00d06h                          ; vertical total
  230.          dw 03e07h                          ; overflow
  231.          dw 0ea10h                          ; v sync start
  232.          dw 08c11h                          ; v sync end/prot cr0 cr7
  233.          dw 0df12h                          ; vertical displayed
  234.          dw 0e715h                          ; v blank start
  235.          dw 00616h                          ; v blank end
  236.          dw nil                             ; end of crtc data for 240/480 lines
  237.  
  238. ; table of display mode tables
  239.  
  240. mode_table:
  241.          dd o mode_320_x200, o mode_320x400
  242.          dd o mode_360_x200, o mode_360x400
  243.          dd o mode_320_x240, o mode_320x480
  244.          dd o mode_360_x240, o mode_360x480
  245.  
  246. ; table of display mode components
  247.  
  248. mode_320_x200: ; data for 320 by 200 pixels
  249.  
  250.          db 063h                            ; 400 scan lines & 25 mhz clock
  251.          db 4                               ; maximum of 4 pages
  252.          dw 320, 200                        ; displayed pixels (x,y)
  253.          dw 1302, 816                       ; max possible x and y sizes
  254.  
  255.          dd o mode_320_wide, o mode_200_tall
  256.          dd o mode_double_line, nil
  257.  
  258. mode_320x400: ; data for 320 by 400 pixels
  259.  
  260.          db 063h                            ; 400 scan lines & 25 mhz clock
  261.          db 2                               ; maximum of 2 pages
  262.          dw 320, 400                        ; displayed pixels x,y
  263.          dw 648, 816                        ; max possible x and y sizes
  264.  
  265.          dd o mode_320_wide, o mode_400_tall
  266.          dd o mode_single_line, nil
  267.  
  268. mode_360_x240: ; data for 360 by 240 pixels
  269.  
  270.          db 0e7h                            ; 480 scan lines & 28 mhz clock
  271.          db 3                               ; maximum of 3 pages
  272.          dw 360, 240                        ; displayed pixels x,y
  273.          dw 1092, 728                       ; max possible x and y sizes
  274.  
  275.          dd o mode_360_wide, o mode_240_tall
  276.          dd o mode_double_line , nil
  277.  
  278. mode_360x480: ; data for 360 by 480 pixels
  279.  
  280.          db 0e7h                            ; 480 scan lines & 28 mhz clock
  281.          db 1                               ; only 1 page possible
  282.          dw 360, 480                        ; displayed pixels x,y
  283.          dw 544, 728                        ; max possible x and y sizes
  284.  
  285.          dd o mode_360_wide, o mode_480_tall
  286.          dd o mode_single_line , nil
  287.  
  288. mode_320_x240: ; data for 320 by 240 pixels
  289.  
  290.          db 0e3h                            ; 480 scan lines & 25 mhz clock
  291.          db 3                               ; maximum of 3 pages
  292.          dw 320, 240                        ; displayed pixels x,y
  293.          dw 1088, 818                       ; max possible x and y sizes
  294.  
  295.          dd o mode_320_wide, o mode_240_tall
  296.          dd o mode_double_line, nil
  297.  
  298. mode_320x480: ; data for 320 by 480 pixels
  299.  
  300.          db 0e3h                            ; 480 scan lines & 25 mhz clock
  301.          db 1                               ; only 1 page possible
  302.          dw 320, 480                        ; displayed pixels x,y
  303.          dw 540, 818                        ; max possible x and y sizes
  304.  
  305.          dd o mode_320_wide, o mode_480_tall
  306.          dd o mode_single_line, nil
  307.  
  308. mode_360_x200: ; data for 360 by 200 pixels
  309.  
  310.          db 067h                            ; 400 scan lines & 28 mhz clock
  311.          db 3                               ; maximum of 3 pages
  312.          dw 360, 200                        ; displayed pixels (x,y)
  313.          dw 1302, 728                       ; max possible x and y sizes
  314.  
  315.          dd o mode_360_wide, o mode_200_tall
  316.          dd o mode_double_line, nil
  317.  
  318. mode_360x400: ; data for 360 by 400 pixels
  319.  
  320.          db 067h                            ; 400 scan lines & 28 mhz clock
  321.          db 1                               ; maximum of 1 pages
  322.          dw 360, 400                        ; displayed pixels x,y
  323.          dw 648, 816                        ; max possible x and y sizes
  324.  
  325.          dd o mode_360_wide, o mode_400_tall
  326.          dd o mode_single_line, nil
  327.  
  328. mode_data_table struc
  329.          m_miscr db ?                       ; value of misc_output register
  330.          m_pages db ?                       ; maximum possible # of pages
  331.          m_xsize dw ?                       ; x size displayed on screen
  332.          m_ysize dw ?                       ; y size displayed on screen
  333.          m_xmax  dw ?                       ; maximum possible x size
  334.          m_ymax  dw ?                       ; maximum possible y size
  335.          m_crtc  dd ?                       ; table of crtc register values
  336. mode_data_table ends
  337.  
  338. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  339. ; specific x mode data table format...
  340. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  341.  
  342. _screen_width    dw 0                       ; actual width of a line in bytes
  343. _screen_height   dw 0                       ; actual vertical height in pixels
  344.  
  345. _last_page       dw 0                       ; # of display pages
  346. _page_addr       dd 4 dup (0)               ; offsets to start of each page
  347.  
  348. _page_size       dw 0                       ; size of page in addr bytes
  349.  
  350. _display_page    dw 0                       ; page # currently displayed
  351. _active_page     dw 0                       ; page # currently active
  352.  
  353. _current_page    dd 0                       ; address of current page
  354.  
  355. _current_xoffset dw 0                       ; current display x offset
  356. _current_yoffset dw 0                       ; current display y offset
  357.  
  358. _current_moffset dd 0                       ; current start offset
  359.  
  360. _max_xoffset     dw 0                       ; current display x offset
  361. _max_yoffset     dw 0                       ; current display y offset
  362.  
  363. _charset_low     dd 0                       ; far ptr to char set: 0-127
  364. _charset_hi      dd 0                       ; far ptr to char set: 128-255
  365.  
  366.          public _screen_width
  367.          public _screen_height
  368.  
  369.          public _last_page
  370.          public _page_addr
  371.  
  372.          public _page_size
  373.  
  374.          public _display_page
  375.          public _active_page
  376.  
  377.          public _current_page
  378.  
  379.          public _current_xoffset
  380.          public _current_yoffset
  381.  
  382.          public _current_moffset
  383.  
  384.          public _max_xoffset
  385.          public _max_yoffset
  386.  
  387.          public _charset_low
  388.          public _charset_hi
  389.  
  390. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  391. ;_set_vga_modex% (modetype%, maxxpos%, maxypos%, pages%)
  392. ;
  393. ; sets up the specified version of mode x.  allows for
  394. ; the setup of multiple video pages, and a virtual
  395. ; screen which can be larger than the displayed screen
  396. ; (which can then be scrolled a pixel at a time)
  397. ;
  398. ; entry: modetype = desired screen resolution (0-7)
  399. ;
  400. ;     0 =  320 x 200, 4 pages max,   1.2:1 aspect ratio
  401. ;     1 =  320 x 400, 2 pages max,   2.4:1 aspect ratio
  402. ;     2 =  360 x 200, 3 pages max,  1.35:1 aspect ratio
  403. ;     3 =  360 x 400, 1 page  max,   2.7:1 aspect ratio
  404. ;     4 =  320 x 240, 3 pages max,     1:1 aspect ratio
  405. ;     5 =  320 x 480, 1 page  max,     2:1 aspect ratio
  406. ;     6 =  360 x 240, 3 pages max, 1.125:1 aspect ratio
  407. ;     7 =  360 x 480, 1 page  max,  2.25:1 aspect ratio
  408. ;
  409. ;        maxxpos = the desired virtual screen width
  410. ;        maxypos = the desired virtual screen height
  411. ;        pages   = the desired # of video pages
  412. ;
  413. ; exit:  ax = success flag:   0 = failure, <>0 = success
  414. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  415.  
  416. svm_stack struc
  417.          svm_table dd ?                     ; offset of mode info table
  418.          dd ?x3                             ; edi, esi, ebp
  419.          dd ?                               ; caller
  420.          svm_pages dw ?                     ; # of screen pages desired
  421.          svm_ysize dw ?                     ; vertical screen size desired
  422.          svm_xsize dw ?                     ; horizontal screen size desired
  423.          svm_mode  dw ?                     ; display resolution desired
  424. svm_stack ends
  425.  
  426.          public _set_vga_modex
  427.  
  428. _set_vga_modex:
  429.          push ebp esi edi                   ; preserve important registers
  430.          sub esp, 4                         ; allocate workspace
  431.          mov ebp, esp                       ; set up stack frame
  432.  
  433. ; check legality of mode request....
  434.  
  435.          movzx ebx, [ebp].svm_mode          ; get requested mode #
  436.  
  437.          cmp bx, num_modes                  ; is it 0..7?
  438.          jae @svm_badmodesetup              ; if not, error out
  439.  
  440.          shl bx, 2                          ; scale bx
  441.          mov esi, d mode_table[ebx]         ; si -> mode info
  442.          mov [ebp].svm_table, esi           ; save ptr for later use
  443.  
  444. ; check # of requested display pages
  445.  
  446.          mov cx, [ebp].svm_pages            ; get # of requested pages
  447.  
  448.          clr ch                             ; set hi word = 0!
  449.          cmp cl, [esi].m_pages              ; check # pages for mode
  450.  
  451.          ja @svm_badmodesetup               ; report error if too many pages
  452.          jcxz @svm_badmodesetup             ; report error if 0 pages
  453.  
  454. ; check validity of x size
  455.  
  456.          and [ebp].svm_xsize, 0fff8h        ; x size mod 8 must = 0
  457.  
  458.          mov ax, [ebp].svm_xsize            ; get logical screen width
  459.  
  460.          cmp ax, [esi].m_xsize              ; check against displayed x
  461.          jb @svm_badmodesetup               ; report error if too small
  462.          cmp ax, [esi].m_xmax               ; check against max x
  463.          ja @svm_badmodesetup               ; report error if too big
  464.  
  465. ; check validity of y size
  466.  
  467.          mov bx, [ebp].svm_ysize            ; get logical screen height
  468.          cmp bx, [esi].m_ysize              ; check against displayed y
  469.          jb @svm_badmodesetup               ; report error if too small
  470.          cmp bx, [esi].m_ymax               ; check against max y
  471.          ja @svm_badmodesetup               ; report error if too big
  472.  
  473. ; enough memory to fit it all?
  474.  
  475.          shr ax, 2                          ; # of bytes:line = xsize/4
  476.          mul cx                             ; ax = bytes/line * pages
  477.          mul bx                             ; dx:ax = total vga mem needed
  478.          jno @svm_continue                  ; exit if total size > 256k
  479.  
  480.          dec dx                             ; was it exactly 256k???
  481.          or dx, ax                          ; (dx = 1, ax = 0000)
  482.          jz @svm_continue                   ; if so, it's valid...
  483.  
  484. @svm_badmodesetup:
  485.  
  486.          clr ax                             ; return value = false
  487.          jmp @svm_exit                      ; normal exit
  488.  
  489. @svm_continue:
  490.  
  491.          mov v86r_ax,13h                    ; start with mode 13h
  492.          mov al,10h                         ; bios int 10h
  493.          int 33h                            ; let v86 handler call bios int 10h
  494.  
  495.          call _turn_screen_off              ; prevent flicker
  496.  
  497.          out_16 sc_index, chain4_off        ; disable chain 4 mode
  498.          out_16 sc_index, async_reset       ; (a)synchronous reset
  499.          out_8 misc_output, [esi].m_miscr   ; set new timing/size
  500.          out_16 sc_index, sequ_restart      ; restart sequencer ...
  501.  
  502.          out_8 crtc_index, 11h              ; select vert retrace end register
  503.          inc dx                             ; point to data
  504.          in al, dx                          ; get value, bit 7 = protect
  505.          and al, 7fh                        ; mask out write protect
  506.          out dx, al                         ; and send it back
  507.  
  508.          mov dx, crtc_index                 ; vga crtc registers
  509.          add esi, m_crtc                    ; si -> crtc parameter data
  510.  
  511. ; load tables of crtc parameters from list of tables
  512.  
  513. @svm_setup_table:
  514.  
  515.          mov edi, [esi]                     ; get pointer to crtc data tbl
  516.          add esi, 4                         ; point to next ptr entry
  517.          or edi, edi                        ; a nil ptr means that we have
  518.          jz @svm_set_data                   ; finished crtc programming
  519.  
  520. @svm_setup_crtc:
  521.          mov ax, [edi]                      ; get crtc data from table
  522.          add edi, 2                         ; advance pointer
  523.          or ax, ax                          ; at end of data table?
  524.          jz @svm_setup_table                ; if so, exit & get next table
  525.  
  526.          out dx, ax                         ; reprogram vga crtc reg
  527.          jmp s @svm_setup_crtc              ; process next table entry
  528.  
  529. ; initialize page & scroll info, edi = 0
  530.  
  531. @svm_set_data:
  532.          mov _display_page, di              ; display page = 0
  533.          mov _active_page, di               ; active page = 0
  534.          mov _current_xoffset, di           ; horz scroll index = 0
  535.          mov _current_yoffset, di           ; vert scroll index = 0
  536.          mov _current_moffset,edi           ; memory scroll index = 0
  537.  
  538.          rlp esi, vga_segment               ; segment for vga memory
  539.          mov _current_page, esi
  540.  
  541. ; set logical screen width, x scroll and our data
  542.  
  543.          mov esi, [ebp].svm_table           ; get saved ptr to mode info
  544.          mov ax, [ebp].svm_xsize            ; get display width
  545.  
  546.          mov cx, ax                         ; cx = logical width
  547.          sub cx, [esi].m_xsize              ; cx = max x scroll value
  548.          mov _max_xoffset, cx               ; set maximum x scroll
  549.  
  550.          shr ax, 2                          ; bytes = pixels / 4
  551.          mov _screen_width, ax              ; save width in pixels
  552.  
  553.          shr ax, 1                          ; offset value = bytes / 2
  554.          mov ah, 13h                        ; crtc offset register index
  555.          xchg al, ah                        ; switch format for out
  556.          out dx, ax                         ; set vga crtc offset reg
  557.  
  558. ; setup data table, y scroll, misc for other routines
  559.  
  560.          mov ax, [ebp].svm_ysize            ; get logical screen height
  561.  
  562.          mov cx, ax                         ; cx = logical height
  563.          sub bx, [esi].m_ysize              ; cx = max y scroll value
  564.          mov _max_yoffset, cx               ; set maximum y scroll
  565.  
  566.          mov _screen_height, ax             ; save height in pixels
  567.          mul _screen_width                  ; ax = page size in bytes,
  568.          mov _page_size, ax                 ; save page size
  569.  
  570.          mov cx, [ebp].svm_pages            ; get # of pages
  571.          mov _last_page, cx                 ; save # of pages
  572.  
  573.          clr bx                             ; page # = 0
  574.          rlp edx, vga_segment               ; page 0 offset = 0a0000h
  575.          movzx eax,ax                       ; clear top word of eax
  576.          movzx ebx,bx
  577.  
  578. @svm_set_pages:
  579.  
  580.          mov _page_addr[ebx], edx           ; set page #(bx) offset
  581.          add bx, 4                          ; page#++
  582.          add edx, eax                       ; compute addr of next page
  583.          loopx cx, @svm_set_pages           ; loop until all pages set
  584.  
  585. ; clear vga memory
  586.  
  587.          out_16 sc_index, all_planes_on     ; select all planes
  588.          mov edi, _current_page             ; -> start of vga memory
  589.  
  590.          clr ax                             ; ax = 0
  591.          cld                                ; block xfer forwards
  592.          mov ecx, 8000h                     ; 32k * 4 * 2 = 256k
  593.          rep stosw                          ; clear dat memory!
  594.         comment %
  595.          mov edi,offset DGROUP:_rs
  596.          mov byte ptr [edi+11h],rom_8x8_hi   ; ask for 8x8 font, 128-255
  597.          mov word ptr [edi+1ch],get_char_ptr ; service to get pointer
  598.          mov word ptr [edi+24h],_DATA
  599.          xor cx,cx
  600.          mov bx,10h
  601.          mov ax,300h
  602.          int 31h                            ; call vga bios
  603.          mov edi,offset DGROUP:_rs
  604.          xor ebp,ebp
  605.          xor eax,eax
  606.          mov bp,[edi+08h]
  607.          mov ax,[edi+22h]
  608.          segoff2ptr ebx,eax,ebp
  609.          mov _charset_hi, ebx               ; save char set offset
  610.  
  611.          mov edi,offset DGROUP:_rs
  612.          mov byte ptr [edi+11h],rom_8x8_lo   ; ask for 8x8 font, 0-127
  613.          mov word ptr [edi+1ch],get_char_ptr ; service to get pointer
  614.          mov word ptr [edi+24h],_DATA
  615.          xor cx,cx
  616.          mov bx,10h
  617.          mov ax,300h
  618.          int 31h                            ; call vga bios
  619.          mov edi,offset DGROUP:_rs
  620.          xor ebp,ebp
  621.          xor eax,eax
  622.          mov bp,[edi+08h]
  623.          mov ax,[edi+22h]
  624.          segoff2ptr ebx,eax,ebp
  625.          mov _charset_low, ebx              ; save char set offset
  626.         %
  627.  
  628.          call _turn_screen_on               ; prevent flicker
  629.  
  630.          mov eax, true                      ; return success code
  631.  
  632. @svm_exit:
  633.          add esp, 4                         ; deallocate workspace
  634.          pop edi esi ebp                    ; restore saved registers
  635.          ret 8                              ; exit & clean up stack
  636.  
  637. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  638. ;_set_modex% (mode%)
  639. ;
  640. ; quickie mode set - sets up mode x to default configuration
  641. ;
  642. ; entry: modetype = desired screen resolution (0-7)
  643. ;        (see _set_vga_modex for list)
  644. ;
  645. ; exit:  ax = success flag:   0 = failure, <>0= success
  646. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  647.  
  648. sm_stack struc
  649.          dd ?,?                             ; ebp, esi
  650.          dd ?                               ; caller
  651.          sm_mode dw ?                       ; desired screen resolution
  652. sm_stack ends
  653.  
  654.          public _set_modex
  655.  
  656. _set_modex:
  657.          push ebp esi                       ; preserve important registers
  658.          mov ebp, esp                       ; set up stack frame
  659.  
  660.          clr ax                             ; assume failure
  661.          movzx ebx, [ebp].sm_mode           ; get desired mode #
  662.          cmp bx, num_modes                  ; is it a valid mode #?
  663.          jae @smx_exit                      ; if not, don't bother
  664.  
  665.          push bx                            ; push mode parameter
  666.  
  667.          shl bx, 2                          ; scale bx to dword indexer
  668.          mov esi, d mode_table[ebx]         ; esi -> mode info
  669.  
  670.          push [esi].m_xsize                 ; push default x size
  671.          push [esi].m_ysize                 ; push default y size
  672.          mov al, [esi].m_pages              ; get default # of pages
  673.          clr ah                             ; hi byte = 0
  674.          push ax                            ; push # pages
  675.  
  676.          call _set_vga_modex                ; set up mode x!
  677.  
  678. @smx_exit:
  679.          pop esi ebp                        ; restore registers
  680.          ret 2                              ; exit & clean up stack
  681.  
  682. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  683. ;_clear_vga_screen (colornum%)
  684. ;
  685. ; clears the active display page
  686. ;
  687. ; entry: colornum = color value to fill the page with
  688. ;
  689. ; exit:  no meaningful values returned
  690. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  691.  
  692. cvs_stack struc
  693.          dd ?,?                             ; edi, ebp
  694.          dd ?                               ; caller
  695.          cvs_color db ?,?                   ; color to set screen to
  696. cvs_stack ends
  697.  
  698.          public _clear_vga_screen
  699.  
  700. _clear_vga_screen:
  701.  
  702.          push ebp edi                       ; preserve important registers
  703.          mov ebp, esp                       ; set up stack frame
  704.  
  705.          out_16 sc_index, all_planes_on     ; select all planes
  706.          mov edi, _current_page             ; point to active vga page
  707.  
  708.          mov al, [ebp].cvs_color            ; get color
  709.          mov ah, al                         ; copy for dword write
  710.          mov bp,ax
  711.          shl eax,16
  712.          mov ax,bp
  713.          cld                                ; block fill forwards
  714.  
  715.          movzx ecx, _page_size              ; get size of page
  716.          shr cx, 2                          ; divide by 4 for dwords
  717.          rep stosd                          ; block fill vga memory
  718.  
  719.          pop edi ebp                        ; restore saved registers
  720.          ret 2                              ; exit & clean up stack
  721.  
  722. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  723. ;_set_point (xpos%, ypos%, colornum%)
  724. ;
  725. ; plots a single pixel on the active display page
  726. ;
  727. ; entry: xpos     = x position to plot pixel at
  728. ;        ypos     = y position to plot pixel at
  729. ;        colornum = color to plot pixel with
  730. ;
  731. ; exit:  no meaningful values returned
  732. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  733.  
  734. sp_stack struc
  735.          dd ?,?                             ; ebp, edi
  736.          dd ?                               ; caller
  737.          setp_color db ?,?                  ; color of point to plot
  738.          setp_ypos dw ?                     ; y pos of point to plot
  739.          setp_xpos dw ?                     ; x pos of point to plot
  740. sp_stack ends
  741.  
  742.          public _set_point
  743.  
  744. _set_point:
  745.  
  746.          push ebp edi                       ; preserve registers
  747.          mov ebp, esp                       ; set up stack frame
  748.  
  749.          mov edi, _current_page             ; point to active vga page
  750.  
  751.          mov ax, [ebp].setp_ypos            ; get line # of pixel
  752.          mul _screen_width                  ; get offset to start of line
  753.  
  754.          clr ebx                            ; wipe high word
  755.          mov bx, [ebp].setp_xpos            ; get xpos
  756.          mov cx, bx                         ; copy to extract plane # from
  757.          shr bx, 2                          ; x offset (bytes) = xpos/4
  758.          add bx, ax                         ; offset = width*ypos + xpos/4
  759.  
  760.          mov ax, map_mask_plane1            ; map mask & plane select register
  761.          and cl, plane_bits                 ; get plane bits
  762.          shl ah, cl                         ; get plane select value
  763.          out_16 sc_index, ax                ; select plane
  764.  
  765.          mov al,[ebp].setp_color            ; get pixel color
  766.          mov [edi+ebx], al                  ; draw pixel
  767.  
  768.          pop edi ebp                        ; restore saved registers
  769.          ret 6                              ; exit and clean up stack
  770.  
  771. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  772. ;_read_point% (xpos%, ypos%)
  773. ;
  774. ; read the color of a pixel from the active display page
  775. ;
  776. ; entry: xpos = x position of pixel to read
  777. ;        ypos = y position of pixel to read
  778. ;
  779. ; exit:  ax   = color of pixel at (xpos, ypos)
  780. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  781.  
  782. rp_stack struc
  783.          dd ?,?                             ; ebp, edi
  784.          dd ?                               ; caller
  785.          rp_ypos dw ?                       ; y pos of point to read
  786.          rp_xpos dw ?                       ; x pos of point to read
  787. rp_stack ends
  788.  
  789.          public _read_point
  790.  
  791. _read_point:
  792.  
  793.          push ebp edi                       ; preserve registers
  794.          mov ebp, esp                       ; set up stack frame
  795.  
  796.          mov edi, _current_page             ; point to active vga page
  797.  
  798.          mov ax, [ebp].rp_ypos              ; get line # of pixel
  799.          mul _screen_width                  ; get offset to start of line
  800.  
  801.          clr ebx                            ; wipe high word
  802.          mov bx, [ebp].rp_xpos              ; get xpos
  803.          mov cx, bx
  804.          shr bx, 2                          ; x offset (bytes) = xpos/4
  805.          add bx, ax                         ; offset = width*ypos + xpos/4
  806.  
  807.          mov al, read_map                   ; gc read mask register
  808.          mov ah, cl                         ; get xpos
  809.          and ah, plane_bits                 ; & mask out plane #
  810.          out_16 gc_index, ax                ; select plane to read in
  811.  
  812.          clr eax                            ; clear return value hi byte
  813.          mov al, [edi+ebx]                  ; get color of pixel
  814.  
  815.          pop edi ebp                        ; restore saved registers
  816.          ret 4                              ; exit and clean up stack
  817.  
  818.          if x_fill_block eq 1
  819.  
  820. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  821. ;_fill_block (xpos1%, ypos1%, xpos2%, ypos2%, colornum%)
  822. ;
  823. ; fills a rectangular block on the active display page
  824. ;
  825. ; entry: xpos1    = left x position of area to fill
  826. ;        ypos1    = top y position of area to fill
  827. ;        xpos2    = right x position of area to fill
  828. ;        ypos2    = bottom y position of area to fill
  829. ;        colornum = color to fill area with
  830. ;
  831. ; exit:  no meaningful values returned
  832. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  833.  
  834. fb_stack struc
  835.          dd ?x3                             ; edi, esi, ebp
  836.          dd ?                               ; caller
  837.          fb_color db ?,?                    ; fill color
  838.          fb_ypos2 dw ?                      ; y pos of lower right pixel
  839.          fb_xpos2 dw ?                      ; x pos of lower right pixel
  840.          fb_ypos1 dw ?                      ; y pos of upper left pixel
  841.          fb_xpos1 dw ?                      ; x pos of upper left pixel
  842. fb_stack ends
  843.  
  844.          public _fill_block
  845.  
  846. _fill_block:
  847.  
  848.          push ebp esi edi                   ; preserve important registers
  849.          mov ebp, esp                       ; set up stack frame
  850.  
  851.          mov edi, _current_page             ; point to active vga page
  852.          cld                                ; direction flag = forward
  853.  
  854.          out_8 sc_index, map_mask           ; set up for plane select
  855.  
  856. ; validate pixel coordinates
  857. ; if necessary, swap so _x1 <= _x2, _y1 <= _y2
  858.  
  859.          clr eax
  860.          clr ecx
  861.          mov ax, [ebp].fb_ypos1             ; ax = _y1   is _y1< _y2?
  862.          mov bx, [ebp].fb_ypos2             ; bx = _y2
  863.          cmp ax, bx
  864.          jle @fb_noswap1
  865.  
  866.          mov [ebp].fb_ypos1, bx             ; swap _y1 and _y2 and save _y1
  867.          xchg ax, bx                        ; on stack for future use
  868.  
  869. @fb_noswap1:
  870.          sub bx, ax                         ; get y width
  871.          inc bx                             ; add 1 to avoid 0 value
  872.          mov [ebp].fb_ypos2, bx             ; save in ypos2
  873.  
  874.          mul _screen_width                  ; mul _y1 by bytes per line
  875.          add edi, eax                       ; di = start of line _y1
  876.  
  877.          mov ax, [ebp].fb_xpos1             ; check _x1 <= _x2
  878.          mov bx, [ebp].fb_xpos2             ;
  879.          cmp ax, bx
  880.          jle @fb_noswap2                    ; skip ahead if ok
  881.  
  882.          mov [ebp].fb_xpos2, ax             ; swap _x1 and _x2 and save _x2
  883.          xchg ax, bx                        ; on stack for future use
  884.  
  885. ; all our input values are in  order,  now  determine
  886. ; how many full "bands" 4 pixels wide (aligned) there
  887. ; are, and if there are partial bands (<4 pixels)  on
  888. ; the left and right edges.
  889.  
  890. @fb_noswap2:
  891.          movzx edx, ax                      ; dx = _x1 (pixel position)
  892.          shr edx, 2                         ; dx/4 = bytes into line
  893.          add edi, edx                       ; di = addr of upper-left corner
  894.  
  895.          movzx ecx, bx                      ; cx = _x2 (pixel position)
  896.          shr cx, 2                          ; cx/4 = bytes into line
  897.  
  898.          cmp dx, cx                         ; start and end in same band?
  899.          jne @fb_normal                     ; if not, check for l & r edges
  900.          jmp @fb_one_band_only              ; if so, then special processing
  901.  
  902. @fb_normal:
  903.          sub cx, dx                         ; cx = # bands -1
  904.          movzx esi, ax                      ; si = plane#(_x1)
  905.          and si, plane_bits                 ; if left edge is aligned then
  906.          jz @fb_l_plane_flush               ; no special processing..
  907.  
  908. ; draw "left edge" vertical strip of 1-3 pixels...
  909.  
  910.          out_8 sc_data, _left_clip_mask[esi] ; set left edge plane mask
  911.  
  912.          mov esi, edi                       ; si = copy of start addr (ul)
  913.  
  914.          mov dx, [ebp].fb_ypos2             ; get # of lines to draw
  915.          mov al, [ebp].fb_color             ; get fill color
  916.          movzx ebx, _screen_width           ; get vertical increment value
  917.  
  918. @fb_left_loop:
  919.          mov [esi], al                      ; fill in left edge pixels
  920.          add esi, ebx                       ; point to next line (below)
  921.          loopjz dx, @fb_left_cont           ; exit loop if all lines drawn
  922.  
  923.          mov [esi], al                      ; fill in left edge pixels
  924.          add esi, ebx                       ; point to next line (below)
  925.          loopx dx, @fb_left_loop            ; loop until left strip is drawn
  926.  
  927. @fb_left_cont:
  928.  
  929.          inc edi                            ; point to middle (or right) block
  930.          dec cx                             ; reset cx instead of jmp @fb_right
  931.  
  932. @fb_l_plane_flush:
  933.          inc cx                             ; add in left band to middle block
  934.  
  935. ; di = addr of 1st middle pixel (band) to fill
  936. ; cx = # of bands to fill -1
  937.  
  938. @fb_right:
  939.          movzx esi, [ebp].fb_xpos2          ; get xpos2
  940.          and si, plane_bits                 ; get plane values
  941.          cmp si, 0003                       ; plane = 3?
  942.          je @fb_r_edge_flush                ; hey, add to middle
  943.  
  944. ; draw "right edge" vertical strip of 1-3 pixels...
  945.  
  946.          out_8 sc_data, _right_clip_mask[esi] ; right edge plane mask
  947.  
  948.          mov esi, edi                       ; get addr of left edge
  949.          add esi, ecx                       ; add width-1 (bands)
  950.          dec esi                            ; to point to top of right edge
  951.  
  952.          mov dx, [ebp].fb_ypos2             ; get # of lines to draw
  953.          mov al, [ebp].fb_color             ; get fill color
  954.          movzx ebx, _screen_width           ; get vertical increment value
  955.  
  956. @fb_right_loop:
  957.          mov [esi], al                      ; fill in right edge pixels
  958.          add esi, ebx                       ; point to next line (below)
  959.          loopjz dx, @fb_right_cont          ; exit loop if all lines drawn
  960.  
  961.          mov [esi], al                      ; fill in right edge pixels
  962.          add esi, ebx                       ; point to next line (below)
  963.          loopx dx, @fb_right_loop           ; loop until left strip is drawn
  964.  
  965. @fb_right_cont:
  966.  
  967.          dec cx                             ; minus 1 for middle bands
  968.          jz @fb_exit                        ; uh.. no middle bands...
  969.  
  970. @fb_r_edge_flush:
  971.  
  972. ; di = addr of upper left block to fill
  973. ; cx = # of bands to fill in (width)
  974.  
  975.          out_8 sc_data, all_planes          ; write to all planes
  976.  
  977.          mov dx, _screen_width              ; dx = di increment
  978.          sub dx, cx                         ; = _screen_width-# planes filled
  979.  
  980.          mov ebx, ecx                       ; bx = quick refill for cx
  981.          mov si, [ebp].fb_ypos2             ; si = # of line to fill
  982.          mov al, [ebp].fb_color             ; get fill color
  983.  
  984. @fb_middle_loop:
  985.          rep stosb                          ; fill in entire line
  986.  
  987.          mov ecx, ebx                       ; recharge cx (line width)
  988.          add edi, edx                       ; point to start of next line
  989.          loopx si, @fb_middle_loop          ; loop until all lines drawn
  990.  
  991.          jmp s @fb_exit                     ; outa here
  992.  
  993. @fb_one_band_only:
  994.          movzx esi, ax                      ; get left clip mask, save _x1
  995.          and si, plane_bits                 ; mask out row #
  996.          mov al, _left_clip_mask[esi]       ; get left edge mask
  997.          mov si, bx                         ; get right clip mask, save _x2
  998.          and si, plane_bits                 ; mask out row #
  999.          and al, _right_clip_mask[esi]      ; get right edge mask byte
  1000.  
  1001.          out_8 sc_data, al                  ; clip for left & right masks
  1002.  
  1003.          mov cx, [ebp].fb_ypos2             ; get # of lines to draw
  1004.          mov al, [ebp].fb_color             ; get fill color
  1005.          clr ebx                            ; wipe high word
  1006.          mov bx, _screen_width              ; get vertical increment value
  1007.  
  1008. @fb_one_loop:
  1009.          mov [edi], al                      ; fill in pixels
  1010.          add edi, ebx                       ; point to next line (below)
  1011.          loopjz cx, @fb_exit                ; exit loop if all lines drawn
  1012.  
  1013.          mov [edi], al                      ; fill in pixels
  1014.          add edi, ebx                       ; point to next line (below)
  1015.          loopx cx, @fb_one_loop             ; loop until left strip is drawn
  1016.  
  1017. @fb_exit:
  1018.          pop edi esi ebp                    ; restore saved registers
  1019.          ret 10                             ; exit and clean up stack
  1020.  
  1021.          endif
  1022.          if x_draw_line eq 1
  1023.  
  1024. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1025. ;_draw_line (xpos1%, ypos1%, xpos2%, ypos2%, colornum%)
  1026. ;
  1027. ; draws a line on the active display page
  1028. ;
  1029. ; entry: xpos1    = x position of first point on line
  1030. ;        ypos1    = y position of first point on line
  1031. ;        xpos2    = x position of last point on line
  1032. ;        ypos2    = y position of last point on line
  1033. ;        colornum = color to draw line with
  1034. ;
  1035. ; exit:  no meaningful values returned
  1036. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1037.  
  1038. dl_stack struc
  1039.          dd ?x3                             ; edi, esi, ebp
  1040.          dd ?                               ; caller
  1041.          dl_colorf db ?,?                   ; line draw color
  1042.          dl_ypos2 dw ?                      ; y pos of last point
  1043.          dl_xpos2 dw ?                      ; x pos of last point
  1044.          dl_ypos1 dw ?                      ; y pos of first point
  1045.          dl_xpos1 dw ?                      ; x pos of first point
  1046. dl_stack ends
  1047.  
  1048.          public _draw_line
  1049.  
  1050. _draw_line:
  1051.  
  1052.          push ebp esi edi                   ; preserve important registers
  1053.          mov ebp, esp                       ; set up stack frame
  1054.          cld                                ; direction flag = forward
  1055.  
  1056.          out_8 sc_index, map_mask           ; set up for plane select
  1057.          mov ch, [ebp].dl_colorf            ; save line color in ch
  1058.  
  1059. ; check line type
  1060.  
  1061.          movzx esi, [ebp].dl_xpos1          ; ax = _x1   is _x1< _x2?
  1062.          movzx edi, [ebp].dl_xpos2          ; dx = _x2
  1063.          cmp si, di                         ; is _x1 < _x2
  1064.          je @dl_vline                       ; if _x1=_x2, draw vertical line
  1065.          jl @dl_noswap1                     ; if _x1 < _x2, don't swap
  1066.  
  1067.          xchg si, di                        ; _x2 is > _x1, so swap them
  1068.  
  1069. @dl_noswap1:
  1070.  
  1071. ; si = _x1, di = _x2
  1072.  
  1073.          mov ax, [ebp].dl_ypos1             ; ax = _y1   is _y1 <> _y2?
  1074.          cmp ax, [ebp].dl_ypos2             ; _y1 = _y2?
  1075.          je @dl_horz                        ; if so, draw a horizontal line
  1076.  
  1077.          jmp @dl_brezham                    ; diagonal line... go do it...
  1078.  
  1079. ; this code draws a horizontal line in mode x where:
  1080. ; si = _x1, di = _x2, and ax = _y1/_y2
  1081.  
  1082. @dl_horz:
  1083.  
  1084.          mul _screen_width                  ; offset = ypos * _screen_width
  1085.          mov dx, ax                         ; cx = line offset into page
  1086.  
  1087.          mov ax, si                         ; get left edge, save _x1
  1088.          and si, plane_bits                 ; mask out row #
  1089.          mov bl, _left_clip_mask[esi]       ; get left edge mask
  1090.          mov cx, di                         ; get right edge, save _x2
  1091.          and di, plane_bits                 ; mask out row #
  1092.          mov bh, _right_clip_mask[edi]      ; get right edge mask byte
  1093.  
  1094.          shr ax, 2                          ; get _x1 byte # (=_x1/4)
  1095.          shr cx, 2                          ; get _x2 byte # (=_x2/4)
  1096.  
  1097.          movzx eax, ax                      ; zero high words for add
  1098.          movzx edx, dx
  1099.          movzx ecx, cx
  1100.  
  1101.          mov edi, _current_page             ; point to active vga page
  1102.          add edi, edx                       ; point to start of line
  1103.          add edi, eax                       ; point to pixel _x1
  1104.  
  1105.          sub cx, ax                         ; cx = # of bands (-1) to set
  1106.          jnz @dl_longln                     ; jump if longer than one segment
  1107.  
  1108.          and bl, bh                         ; otherwise, merge clip masks
  1109.  
  1110. @dl_longln:
  1111.  
  1112.          out_8 sc_data, bl                  ; set the left clip mask
  1113.  
  1114.          mov al, [ebp].dl_colorf            ; get line color
  1115.          mov bl, al                         ; bl = copy of line color
  1116.          stosb                              ; set left (1-4) pixels
  1117.  
  1118.          jcxz @dl_exit3                     ; done if only one line segment
  1119.  
  1120.          dec cx                             ; cx = # of middle segments
  1121.          jz @dl_xrseg                       ; if no middle segments....
  1122.  
  1123. ; draw middle segments
  1124.  
  1125.          out_8 dx, all_planes               ; write to all planes
  1126.  
  1127.          mov al, bl                         ; get color from bl
  1128.          rep stosb                          ; draw middle (4 pixel) segments
  1129.  
  1130. @dl_xrseg:
  1131.          out_8 dx, bh                       ; select planes for right clip mask
  1132.          mov al, bl                         ; get color value
  1133.          stosb                              ; draw right (1-4) pixels
  1134. @dl_exit3:
  1135.          jmp s @dl_exit                     ; we are done...
  1136.  
  1137. ; this code draws a vertical line.  on entry:
  1138. ; ch = line color, si & di = _x1
  1139.  
  1140. @dl_vline:
  1141.  
  1142.          mov ax, [ebp].dl_ypos1             ; ax = _y1
  1143.          mov si, [ebp].dl_ypos2             ; si = _y2
  1144.          cmp ax, si                         ; is _y1 < _y2?
  1145.          jle @dl_noswap2                    ; if so, don't swap them
  1146.  
  1147.          xchg ax, si                        ; ok, now _y1 < _y2
  1148.  
  1149. @dl_noswap2:
  1150.  
  1151.          sub si, ax                         ; si = line height (_y2-_y1+1)
  1152.          inc si
  1153.  
  1154. ; ax = _y1, di = _x1, get offset into page into ax
  1155.  
  1156.          mul _screen_width                  ; offset = _y1 (ax) * screen width
  1157.          mov dx, di                         ; copy xpos into dx
  1158.          shr di, 2                          ; di = xpos/4
  1159.          add ax, di                         ; di = xpos/4 + screenwidth * _y1
  1160.  
  1161.          movzx eax, ax
  1162.          mov edi, _current_page             ; point to active vga page
  1163.          add edi, eax                       ; point to pixel _x1, _y1
  1164.  
  1165. ;select plane
  1166.  
  1167.          mov cl, dl                         ; cl = save _x1
  1168.          and cl, plane_bits                 ; get _x1 mod 4 (plane #)
  1169.          mov ax, map_mask_plane1            ; code to set plane #1
  1170.          shl ah, cl                         ; change to correct plane #
  1171.          out_16 sc_index, ax                ; select plane
  1172.  
  1173.          mov al, ch                         ; get saved color
  1174.          mov bx, _screen_width              ; get offset to advance line by
  1175.          movzx ebx, bx
  1176.  
  1177. @dl_vloop:
  1178.          mov [edi], al                      ; draw single pixel
  1179.          add edi, ebx                       ; point to next line
  1180.          loopjz si, @dl_exit                ; lines--, exit if done
  1181.  
  1182.          mov [edi], al                      ; draw single pixel
  1183.          add edi, ebx                       ; point to next line
  1184.          loopx si, @dl_vloop                ; lines--, loop until done
  1185.  
  1186. @dl_exit:
  1187.  
  1188.          jmp @dl_exit2                      ; done!
  1189.  
  1190. ; this code draws a diagonal line in mode x
  1191.  
  1192. @dl_brezham:
  1193.          mov edi, _current_page             ; point to active vga page
  1194.  
  1195.          mov ax, [ebp].dl_ypos1             ; get _y1 value
  1196.          mov bx, [ebp].dl_ypos2             ; get _y2 value
  1197.          mov cx, [ebp].dl_xpos1             ; get starting xpos
  1198.  
  1199.          cmp bx, ax                         ; _y2-_y1 is?
  1200.          jnc @dl_deltayok                   ; if _y2>=_y1 then goto...
  1201.  
  1202.          xchg bx, ax                        ; swap em...
  1203.          mov cx, [ebp].dl_xpos2             ; get new starting xpos
  1204.  
  1205. @dl_deltayok:
  1206.          mul _screen_width                  ; offset = _screen_width * _y1
  1207.          movzx eax, ax
  1208.  
  1209.          add edi, eax                       ; di -> start of line _y1 on page
  1210.          mov ax, cx                         ; ax = xpos (_x1)
  1211.          shr ax, 2                          ; /4 = byte offset into line
  1212.          add edi, eax                       ; di = starting pos (_x1,_y1)
  1213.  
  1214.          mov al, 11h                        ; staring mask
  1215.          and cl, plane_bits                 ; get plane #
  1216.          shl al, cl                         ; and shift into place
  1217.          mov ah, [ebp].dl_colorf            ; color in hi bytes
  1218.  
  1219.          push ax                            ; save mask,color...
  1220.  
  1221.          mov ah, al                         ; plane # in ah
  1222.          mov al, map_mask                   ; select plane register
  1223.          out_16 sc_index, ax                ; select initial plane
  1224.  
  1225.          mov ax, [ebp].dl_xpos1             ; get _x1 value
  1226.          mov bx, [ebp].dl_ypos1             ; get _y1 value
  1227.          mov cx, [ebp].dl_xpos2             ; get _x2 value
  1228.          mov dx, [ebp].dl_ypos2             ; get _y2 value
  1229.  
  1230.          movzx ebp, _screen_width           ; use bp for line width to
  1231.          ; to avoid extra memory access
  1232.  
  1233.          sub dx, bx                         ; figure delta_y
  1234.          jnc @dl_deltayok2                  ; jump if _y2 >= _y1
  1235.  
  1236.          add bx, dx                         ; put _y2 into _y1
  1237.          neg dx                             ; abs(delta_y)
  1238.          xchg ax, cx                        ; and exchange _x1 and _x2
  1239.  
  1240. @dl_deltayok2:
  1241.          mov bx, 08000h                     ; seed for fraction accumulator
  1242.  
  1243.          sub cx, ax                         ; figure delta_x
  1244.          jc @dl_drawleft                    ; if negative, go left
  1245.  
  1246.          jmp @dl_drawright                  ; draw line that slopes right
  1247.  
  1248. @dl_drawleft:
  1249.  
  1250.          neg cx                             ; abs(delta_x)
  1251.  
  1252.          cmp cx, dx                         ; is delta_x < delta_y?
  1253.          jb @dl_steepleft                   ; yes, so go do steep line
  1254.          ; (delta_y iterations)
  1255.  
  1256. ; draw a shallow line to the left in mode x
  1257.  
  1258. @dl_shallowleft:
  1259.          clr ax                             ; zero low word of delta_y * 10000h
  1260.          sub ax, dx                         ; dx:ax <- dx * 0ffffh
  1261.          sbb dx, 0                          ; include carry
  1262.          div cx                             ; divide by delta_x
  1263.  
  1264.          mov si, bx                         ; si = accumulator
  1265.          mov bx, ax                         ; bx = add fraction
  1266.          pop ax                             ; get color, bit mask
  1267.          mov dx, sc_data                    ; sequence controller data register
  1268.          inc cx                             ; inc delta_x so we can unroll loop
  1269.  
  1270. ; loop (_x2) to draw pixels, move left, and maybe down...
  1271.  
  1272. @dl_sllloop:
  1273.          mov [edi], ah                      ; set first pixel, plane data set up
  1274.          loopjz cx, @dl_sllexit             ; delta_x--, exit if done
  1275.  
  1276.          add si, bx                         ; add numerator to accumulator
  1277.          jnc @dl_slll2nc                    ; move down on carry
  1278.  
  1279.          add edi, ebp                       ; move down one line...
  1280.  
  1281. @dl_slll2nc:
  1282.          dec edi                            ; left one addr
  1283.          ror al, 1                          ; move left one plane, back on 0 1 2
  1284.          cmp al, 87h                        ; wrap?, if al <88 then carry set
  1285.          adc edi, 0                         ; adjust address: di = di + carry
  1286.          out dx, al                         ; set up new bit plane mask
  1287.  
  1288.          mov [edi], ah                      ; set pixel
  1289.          loopjz cx, @dl_sllexit             ; delta_x--, exit if done
  1290.  
  1291.          add si, bx                         ; add numerator to accumulator,
  1292.          jnc @dl_slll3nc                    ; move down on carry
  1293.  
  1294.          add edi, ebp                       ; move down one line...
  1295.  
  1296. @dl_slll3nc: ; now move left a pixel...
  1297.          dec edi                            ; left one addr
  1298.          ror al, 1                          ; move left one plane, back on 0 1 2
  1299.          cmp al, 87h                        ; wrap?, if al <88 then carry set
  1300.          adc edi, 0                         ; adjust address: di = di + carry
  1301.          out dx, al                         ; set up new bit plane mask
  1302.          jmp s @dl_sllloop                  ; loop until done
  1303.  
  1304. @dl_sllexit:
  1305.          jmp @dl_exit2                      ; and exit
  1306.  
  1307. ; draw a steep line to the left in mode x
  1308.  
  1309. @dl_steepleft:
  1310.          clr ax                             ; zero low word of delta_y * 10000h
  1311.          xchg dx, cx                        ; delta_y switched with delta_x
  1312.          div cx                             ; divide by delta_y
  1313.  
  1314.          mov si, bx                         ; si = accumulator
  1315.          mov bx, ax                         ; bx = add fraction
  1316.          pop ax                             ; get color, bit mask
  1317.          mov dx, sc_data                    ; sequence controller data register
  1318.          inc cx                             ; inc delta_y so we can unroll loop
  1319.  
  1320. ; loop (_x2) to draw pixels, move down, and maybe left
  1321.  
  1322. @dl_stlloop:
  1323.  
  1324.          mov [edi], ah                      ; set first pixel
  1325.          loopjz cx, @dl_stlexit             ; delta_y--, exit if done
  1326.  
  1327.          add si, bx                         ; add numerator to accumulator
  1328.          jnc @dl_stlnc2                     ; no carry, just move down!
  1329.  
  1330.          dec edi                            ; move left one addr
  1331.          ror al, 1                          ; move left one plane, back on 0 1 2
  1332.          cmp al, 87h                        ; wrap?, if al <88 then carry set
  1333.          adc edi, 0                         ; adjust address: di = di + carry
  1334.          out dx, al                         ; set up new bit plane mask
  1335.  
  1336. @dl_stlnc2:
  1337.          add edi, ebp                       ; advance to next line.
  1338.  
  1339.          mov [edi], ah                      ; set pixel
  1340.          loopjz cx, @dl_stlexit             ; delta_y--, exit if done
  1341.  
  1342.          add si, bx                         ; add numerator to accumulator
  1343.          jnc @dl_stlnc3                     ; no carry, just move down!
  1344.  
  1345.          dec edi                            ; move left one addr
  1346.          ror al, 1                          ; move left one plane, back on 0 1 2
  1347.          cmp al, 87h                        ; wrap?, if al <88 then carry set
  1348.          adc edi, 0                         ; adjust address: di = di + carry
  1349.          out dx, al                         ; set up new bit plane mask
  1350.  
  1351. @dl_stlnc3:
  1352.          add edi, ebp                       ; advance to next line.
  1353.          jmp s @dl_stlloop                  ; loop until done
  1354.  
  1355. @dl_stlexit:
  1356.          jmp @dl_exit2                      ; and exit
  1357.  
  1358. ; draw a line that goes to the right...
  1359.  
  1360. @dl_drawright:
  1361.          cmp cx, dx                         ; is delta_x < delta_y?
  1362.          jb @dl_steepright                  ; yes, so go do steep line
  1363.          ; (delta_y iterations)
  1364.  
  1365. ; draw a shallow line to the right in mode x
  1366.  
  1367. @dl_shallowright:
  1368.          clr ax                             ; zero low word of delta_y * 10000h
  1369.          sub ax, dx                         ; dx:ax <- dx * 0ffffh
  1370.          sbb dx, 0                          ; include carry
  1371.          div cx                             ; divide by delta_x
  1372.  
  1373.          mov si, bx                         ; si = accumulator
  1374.          mov bx, ax                         ; bx = add fraction
  1375.          pop ax                             ; get color, bit mask
  1376.          mov dx, sc_data                    ; sequence controller data register
  1377.          inc cx                             ; inc delta_x so we can unroll loop
  1378.  
  1379. ; loop (_x2) to draw pixels, move right, and maybe down...
  1380.  
  1381. @dl_slrloop:
  1382.          mov [edi], ah                      ; set first pixel, mask is set up
  1383.          loopjz cx, @dl_slrexit             ; delta_x--, exit if done..
  1384.  
  1385.          add si, bx                         ; add numerator to accumulator
  1386.          jnc @dl_slr2nc                     ; don't move down if carry not set
  1387.  
  1388.          add edi, ebp                       ; move down one line...
  1389.  
  1390. @dl_slr2nc: ; now move right a pixel...
  1391.          rol al, 1                          ; move right one addr if plane = 0
  1392.          cmp al, 12h                        ; wrap? if al >12 then carry not set
  1393.          adc edi, 0                         ; adjust address: di = di + carry
  1394.          out dx, al                         ; set up new bit plane mask
  1395.  
  1396.          mov [edi], ah                      ; set pixel
  1397.          loopjz cx, @dl_slrexit             ; delta_x--, exit if done..
  1398.  
  1399.          add si, bx                         ; add numerator to accumulator
  1400.          jnc @dl_slr3nc                     ; don't move down if carry not set
  1401.  
  1402.          add edi, ebp                       ; move down one line...
  1403.  
  1404. @dl_slr3nc:
  1405.          rol al, 1                          ; move right one addr if plane = 0
  1406.          cmp al, 12h                        ; wrap? if al >12 then carry not set
  1407.          adc edi, 0                         ; adjust address: di = di + carry
  1408.          out dx, al                         ; set up new bit plane mask
  1409.          jmp s @dl_slrloop                  ; loop till done
  1410.  
  1411. @dl_slrexit:
  1412.          jmp @dl_exit2                      ; and exit
  1413.  
  1414. ; draw a steep line to the right in mode x
  1415.  
  1416. @dl_steepright:
  1417.          clr ax                             ; zero low word of delta_y * 10000h
  1418.          xchg dx, cx                        ; delta_y switched with delta_x
  1419.          div cx                             ; divide by delta_y
  1420.  
  1421.          mov si, bx                         ; si = accumulator
  1422.          mov bx, ax                         ; bx = add fraction
  1423.          pop ax                             ; get color, bit mask
  1424.          mov dx, sc_data                    ; sequence controller data register
  1425.          inc cx                             ; inc delta_y so we can unroll loop
  1426.  
  1427. ; loop (_x2) to draw pixels, move down, and maybe right
  1428.  
  1429. @strloop:
  1430.          mov [edi], ah                      ; set first pixel, mask is set up
  1431.          loopjz cx, @dl_exit2               ; delta_y--, exit if done
  1432.  
  1433.          add si, bx                         ; add numerator to accumulator
  1434.          jnc @strnc2                        ; if no carry then just go down...
  1435.  
  1436.          rol al, 1                          ; move right one addr if plane = 0
  1437.          cmp al, 12h                        ; wrap? if al >12 then carry not set
  1438.          adc edi, 0                         ; adjust address: di = di + carry
  1439.          out dx, al                         ; set up new bit plane mask
  1440.  
  1441. @strnc2:
  1442.          add edi, ebp                       ; advance to next line.
  1443.  
  1444.          mov [edi], ah                      ; set pixel
  1445.          loopjz cx, @dl_exit2               ; delta_y--, exit if done
  1446.  
  1447.          add si, bx                         ; add numerator to accumulator
  1448.          jnc @strnc3                        ; if no carry then just go down...
  1449.  
  1450.          rol al, 1                          ; move right one addr if plane = 0
  1451.          cmp al, 12h                        ; wrap? if al >12 then carry not set
  1452.          adc edi, 0                         ; adjust address: di = di + carry
  1453.          out dx, al                         ; set up new bit plane mask
  1454.  
  1455. @strnc3:
  1456.          add edi, ebp                       ; advance to next line.
  1457.          jmp s @strloop                     ; loop till done
  1458.  
  1459. @dl_exit2:
  1460.          pop edi esi ebp                    ; restore saved registers
  1461.          ret 10                             ; exit and clean up stack
  1462.  
  1463.          endif
  1464.  
  1465. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1466. ;_set_dac_register (register%, red%, green%, blue%)
  1467. ;
  1468. ; sets a single (rgb) vga palette register
  1469. ;
  1470. ; entry: register = the dac # to modify (0-255)
  1471. ;        red      = the new red intensity (0-63)
  1472. ;        green    = the new green intensity (0-63)
  1473. ;        blue     = the new blue intensity (0-63)
  1474. ;
  1475. ; exit:  no meaningful values returned
  1476. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1477.  
  1478. sdr_stack struc
  1479.          dd ?                               ; ebp
  1480.          dd ?                               ; caller
  1481.          sdr_blue db ?,?                    ; blue data value
  1482.          sdr_green db ?,?                   ; green data value
  1483.          sdr_red db ?,?                     ; red data value
  1484.          sdr_register db ?,?                ; palette register #
  1485. sdr_stack ends
  1486.  
  1487.          public _set_dac_register
  1488.  
  1489. _set_dac_register:
  1490.  
  1491.          push ebp                           ; save bp
  1492.          mov ebp, esp                       ; set up stack frame
  1493.  
  1494. ; select which dac register to modify
  1495.  
  1496.          out_8 dac_write_addr, [ebp].sdr_register
  1497.  
  1498.          mov dx, pel_data_reg               ; dac data register
  1499.          out_8 dx, [ebp].sdr_red            ; set red intensity
  1500.          out_8 dx, [ebp].sdr_green          ; set green intensity
  1501.          out_8 dx, [ebp].sdr_blue           ; set blue intensity
  1502.  
  1503.          pop ebp                            ; restore registers
  1504.          ret 8                              ; exit & clean up stack
  1505.  
  1506. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1507. ;_get_dac_register (register%, &red%, &green%, &blue%)
  1508. ;
  1509. ; reads the rgb values of a single vga palette register
  1510. ;
  1511. ; entry: register = the dac # to read (0-255)
  1512. ;        red      = offset to red variable in ds
  1513. ;        green    = offset to green variable in ds
  1514. ;        blue     = offset to blue variable in ds
  1515. ;
  1516. ; exit:  the values of the integer variables red,
  1517. ;        green, and blue are set to the values
  1518. ;        taken from the specified dac register.
  1519. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1520.  
  1521. gdr_stack struc
  1522.          dd ?                               ; ebp
  1523.          dd ?                               ; caller
  1524.          gdr_blue dd ?                      ; addr of blue data value (where to put)
  1525.          gdr_green dd ?                     ; addr of green data value
  1526.          gdr_red dd ?                       ; addr of red data value
  1527.          gdr_register db ?,?                ; palette register #
  1528. gdr_stack ends
  1529.  
  1530.          public _get_dac_register
  1531.  
  1532. _get_dac_register:
  1533.  
  1534.          push ebp                           ; save bp
  1535.          mov ebp, esp                       ; set up stack frame
  1536.  
  1537. ; select which dac register to read in
  1538.  
  1539.          out_8 dac_read_addr, [ebp].gdr_register
  1540.  
  1541.          mov dx, pel_data_reg               ; dac data register
  1542.          clr ax                             ; clear ax
  1543.  
  1544.          in al, dx                          ; read red value
  1545.          mov ebx, [ebp].gdr_red             ; get address of red%
  1546.          mov [ebx], ax                      ; *red% = ax
  1547.  
  1548.          in al, dx                          ; read green value
  1549.          mov ebx, [ebp].gdr_green           ; get address of green%
  1550.          mov [ebx], ax                      ; *green% = ax
  1551.  
  1552.          in al, dx                          ; read blue value
  1553.          mov ebx, [ebp].gdr_blue            ; get address of blue%
  1554.          mov [ebx], ax                      ; *blue% = ax
  1555.  
  1556.          pop ebp                            ; restore registers
  1557.          ret 14                             ; exit & clean up stack
  1558.  
  1559. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1560. ;_load_dac_registers (seg paldata, startreg%, endreg%, sync%)
  1561. ;
  1562. ; sets a block of vga palette registers
  1563. ;
  1564. ; entry: paldata  = far pointer to block of palette data
  1565. ;        startreg = first register # in range to set (0-255)
  1566. ;        endreg   = last register # in range to set (0-255)
  1567. ;        sync     = wait for vertical retrace flag (boolean)
  1568. ;
  1569. ; exit:  no meaningful values returned
  1570. ;
  1571. ; notes: paldata is a lifar array of 3 byte palette values
  1572. ;        in the order: red  (0-63), green (0-63), blue (0-63)
  1573. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1574.  
  1575. ldr_stack struc
  1576.          dd ?,?                             ; ebp, esi
  1577.          dd ?                               ; caller
  1578.          ldr_sync dw ?                      ; vertical sync flag
  1579.          ldr_endreg db ?,?                  ; last register #
  1580.          ldr_startreg db ?,?                ; first register #
  1581.          ldr_paldata dd ?                   ; far ptr to palette data
  1582. ldr_stack ends
  1583.  
  1584.          public _load_dac_registers
  1585.  
  1586. _load_dac_registers:
  1587.  
  1588.          push ebp esi                       ; save registers
  1589.          mov ebp, esp                       ; set up stack frame
  1590.  
  1591.          mov ax, [ebp].ldr_sync             ; get vertical sync flag
  1592.          or ax, ax                          ; is sync flag = 0?
  1593.          jz @ldr_load                       ; if so, skip call
  1594.  
  1595.          call _sync_display                 ; wait for vsync
  1596.  
  1597. ; determine register #'s, size to copy, etc
  1598.  
  1599. @ldr_load:
  1600.  
  1601.          mov esi, [ebp].ldr_paldata         ; esi -> palette data
  1602.          mov dx, dac_write_addr             ; dac register # selector
  1603.  
  1604.          clr ax, bx                         ; clear for byte loads
  1605.          mov al, [ebp].ldr_startreg         ; get start register
  1606.          mov bl, [ebp].ldr_endreg           ; get end register
  1607.  
  1608.          sub bx, ax                         ; bx = # of dac registers -1
  1609.          inc bx                             ; bx = # of dac registers
  1610.          mov cx, bx                         ; cx = # of dac registers
  1611.          add cx, bx                         ; cx =  "   " * 2
  1612.          add cx, bx                         ; cx =  "   " * 3
  1613.          cld                                ; block outs forward
  1614.          out dx, al                         ; set up correct register #
  1615.  
  1616. ; load a block of dac registers
  1617.  
  1618.          mov dx, pel_data_reg               ; dac data register
  1619.          movzx ecx,cx
  1620.  
  1621.          rep outsb                          ; block set dac registers
  1622.  
  1623.          pop esi ebp                        ; restore registers
  1624.          ret 10                             ; exit & clean up stack
  1625.  
  1626. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1627. ;_read_dac_registers (seg paldata, startreg%, endreg%)
  1628. ;
  1629. ; reads a block of vga palette registers
  1630. ;
  1631. ; entry: paldata  = far pointer to block to store palette data
  1632. ;        startreg = first register # in range to read (0-255)
  1633. ;        endreg   = last register # in range to read (0-255)
  1634. ;
  1635. ; exit:  no meaningful values returned
  1636. ;
  1637. ; notes: paldata is a lifar array of 3 byte palette values
  1638. ;        in the order: red  (0-63), green (0-63), blue (0-63)
  1639. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1640.  
  1641. rdr_stack struc
  1642.          dd ?,?                             ; ebp, edi
  1643.          dd ?                               ; caller
  1644.          rdr_endreg db ?,?                  ; last register #
  1645.          rdr_startreg db ?,?                ; first register #
  1646.          rdr_paldata dd ?                   ; far ptr to palette data
  1647. rdr_stack ends
  1648.  
  1649.          public _read_dac_registers
  1650.  
  1651. _read_dac_registers:
  1652.  
  1653.          push ebp edi                       ; save registers
  1654.          mov ebp, esp                       ; set up stack frame
  1655.  
  1656. ; determine register #'s, size to copy, etc
  1657.  
  1658.          mov edi, [ebp].rdr_paldata         ; edi -> palette buffer
  1659.          mov dx, dac_read_addr              ; dac register # selector
  1660.  
  1661.          clr ax, bx                         ; clear for byte loads
  1662.          mov al, [ebp].rdr_startreg         ; get start register
  1663.          mov bl, [ebp].rdr_endreg           ; get end register
  1664.  
  1665.          sub bx, ax                         ; bx = # of dac registers -1
  1666.          inc bx                             ; bx = # of dac registers
  1667.          mov cx, bx                         ; cx = # of dac registers
  1668.          add cx, bx                         ; cx =  "   " * 2
  1669.          add cx, bx                         ; cx =  "   " * 3
  1670.          cld                                ; block ins forward
  1671.  
  1672. ; read a block of dac registers
  1673.  
  1674.          out dx, al                         ; set up correct register #
  1675.          mov dx, pel_data_reg               ; dac data register
  1676.          movzx ecx,cx
  1677.  
  1678.          rep insb                           ; block read dac registers
  1679.  
  1680.          pop edi ebp                        ; restore registers
  1681.          ret 8                              ; exit & clean up stack
  1682.  
  1683. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1684. ;_set_active_page (pageno%)
  1685. ;
  1686. ; sets the active display page to be used for future drawing
  1687. ;
  1688. ; entry: pageno = display page to make active
  1689. ;        (values: 0 to number of pages - 1)
  1690. ;
  1691. ; exit:  no meaningful values returned
  1692. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1693.  
  1694. sap_stack struc
  1695.          dd ?                               ; ebp
  1696.          dd ?                               ; caller
  1697.          sap_page dw ?                      ; page # for drawing
  1698. sap_stack ends
  1699.  
  1700.          public _set_active_page
  1701.  
  1702. _set_active_page:
  1703.  
  1704.          push ebp                           ; preserve registers
  1705.          mov ebp, esp                       ; set up stack frame
  1706.  
  1707.          movzx ebx, [ebp].sap_page          ; get desired page #
  1708.          cmp bx, _last_page                 ; is page # valid?
  1709.          jae @sap_exit                      ; if not, do nothing
  1710.  
  1711.          mov _active_page, bx               ; set active page #
  1712.  
  1713.          shl bx, 2                          ; scale page # to dword
  1714.          mov eax, _page_addr[ebx]           ; get offset to page
  1715.  
  1716.          mov _current_page, eax             ; and set for future mov's
  1717.  
  1718. @sap_exit:
  1719.          pop ebp                            ; restore registers
  1720.          ret 2                              ; exit and clean up stack
  1721.  
  1722. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1723. ;_get_active_page
  1724. ;
  1725. ; returns the video page # currently used for drawing
  1726. ;
  1727. ; entry: no parameters are passed
  1728. ;
  1729. ; exit:  ax = current video page used for drawing
  1730. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1731.  
  1732.          public _get_active_page
  1733.  
  1734. _get_active_page:
  1735.  
  1736.          mov ax, _active_page               ; get active page #
  1737.          ret                                ; exit and clean up stack
  1738.  
  1739. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1740. ;_set_display_page (displaypage)
  1741. ;
  1742. ; sets the currently visible display page.
  1743. ; when called this routine syncronizes the display
  1744. ; to the vertical blank.
  1745. ;
  1746. ; entry: pageno = display page to show on the screen
  1747. ;        (values: 0 to number of pages - 1)
  1748. ;
  1749. ; exit:  no meaningful values returned
  1750. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1751.  
  1752. sdp_stack struc
  1753.          dd ?                               ; ebp
  1754.          dd ?                               ; caller
  1755.          sdp_page dw ?                      ; page # to display...
  1756. sdp_stack ends
  1757.  
  1758.          public _set_display_page
  1759.  
  1760. _set_display_page:
  1761.  
  1762.          push ebp                           ; preserve registers
  1763.          mov ebp, esp                       ; set up stack frame
  1764.  
  1765.          movzx ebx, [ebp].sdp_page          ; get desired page #
  1766.          cmp bx, _last_page                 ; is page # valid?
  1767.          jae @sdp_exit                      ; if not, do nothing
  1768.  
  1769.          mov _display_page, bx              ; set display page #
  1770.  
  1771.          shl bx, 2                          ; scale page # to dword
  1772.          mov ecx, _page_addr[ebx]           ; get offset in memory to page
  1773.          add ecx, _current_moffset          ; adjust for any scrolling
  1774.          add ecx, _code32a                  ; adjust for protected mode
  1775.  
  1776. ; wait if we are currently in a vertical retrace
  1777.  
  1778.          mov dx, input_1                    ; input status #1 register
  1779.  
  1780. @dp_wait0:
  1781.          in al, dx                          ; get vga status
  1782.          and al, vert_retrace               ; in display mode yet?
  1783.          jnz @dp_wait0                      ; if not, wait for it
  1784.  
  1785. ; set the start display address to the new page
  1786.  
  1787.          cli
  1788.          mov dx, crtc_index                 ; we change the vga sequencer
  1789.  
  1790.          mov al, start_disp_lo              ; display start low register
  1791.          mov ah, cl                         ; low 8 bits of start addr
  1792.          out dx, ax                         ; set display addr low
  1793.  
  1794.          mov al, start_disp_hi              ; display start high register
  1795.          mov ah, ch                         ; high 8 bits of start addr
  1796.          out dx, ax                         ; set display addr high
  1797.          sti
  1798.  
  1799. ; wait for a vertical retrace to smooth out things
  1800.  
  1801.          mov dx, input_1                    ; input status #1 register
  1802.  
  1803. @dp_wait1:
  1804.          in al, dx                          ; get vga status
  1805.          and al, vert_retrace               ; vertical retrace start?
  1806.          jz @dp_wait1                       ; if not, wait for it
  1807.  
  1808. @sdp_exit:
  1809.          pop ebp                            ; restore registers
  1810.          ret 2                              ; exit and clean up stack
  1811.  
  1812. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1813. ;_get_display_page%
  1814. ;
  1815. ; returns the video page # currently displayed
  1816. ;
  1817. ; entry: no parameters are passed
  1818. ;
  1819. ; exit:  ax = current video page being displayed
  1820. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1821.  
  1822.          public _get_display_page
  1823.  
  1824. _get_display_page:
  1825.  
  1826.          mov ax, _display_page              ; get display page #
  1827.          ret                                ; exit & clean up stack
  1828.  
  1829.          if x_set_window eq 1
  1830.  
  1831. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1832. ;_set_window (displaypage%, xpos%, ypos%)
  1833. ;
  1834. ; since a logical screen can be larger than the physical
  1835. ; screen, scrolling is possible.  this routine sets the
  1836. ; upper left corner of the screen to the specified pixel.
  1837. ; also sets the display page to simplify combined page
  1838. ; flipping and scrolling.  when called this routine
  1839. ; syncronizes the display to the vertical blank.
  1840. ;
  1841. ; entry: displaypage = display page to show on the screen
  1842. ;        xpos        = # of pixels to shift screen right
  1843. ;        ypos        = # of lines to shift screen down
  1844. ;
  1845. ; exit:  no meaningful values returned
  1846. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1847.  
  1848. sw_stack struc
  1849.          dd ?                               ; ebp
  1850.          dd ?                               ; caller
  1851.          sw_ypos dw ?                       ; y pos of ul screen corner
  1852.          sw_xpos dw ?                       ; x pos of ul screen corner
  1853.          sw_page dw ?                       ; (new) display page
  1854. sw_stack ends
  1855.  
  1856.          public _set_window
  1857.  
  1858. _set_window:
  1859.  
  1860.          push ebp                           ; preserve registers
  1861.          mov ebp, esp                       ; set up stack frame
  1862.  
  1863. ; check if our scroll offsets are valid
  1864.  
  1865.          mov bx, [ebp].sw_page              ; get desired page #
  1866.          cmp bx, _last_page                 ; is page # valid?
  1867.          jae @sw_exit                       ; if not, do nothing
  1868.  
  1869.          mov ax, [ebp].sw_ypos              ; get desired y offset
  1870.          cmp ax, _max_yoffset               ; is it within limits?
  1871.          ja @sw_exit                        ; if not, exit
  1872.  
  1873.          mov cx, [ebp].sw_xpos              ; get desired x offset
  1874.          cmp cx, _max_xoffset               ; is it within limits?
  1875.          ja @sw_exit                        ; if not, exit
  1876.  
  1877. ; compute proper display start address to use
  1878.  
  1879.          mul _screen_width                  ; ax = yoffset * line width
  1880.          shr cx, 2                          ; cx / 4 = bytes into line
  1881.          add ax, cx                         ; ax = offset of upper left pixel
  1882.          movzx eax, ax
  1883.          movzx ebx, bx
  1884.  
  1885.          mov _current_moffset, eax          ; save offset info
  1886.  
  1887.          mov _display_page, bx              ; set current page #
  1888.          shl bx, 2                          ; scale page # to dword
  1889.          add eax, _page_addr[ebx]           ; get offset in vga to page
  1890.          add eax,_code32a                   ; adjust for protected mode segment
  1891.          mov bx, ax                         ; bx = desired display start
  1892.  
  1893.          mov dx, input_1                    ; input status #1 register
  1894.  
  1895. ; wait if we are currently in a vertical retrace
  1896.  
  1897. @sw_wait0:
  1898.          in al, dx                          ; get vga status
  1899.          and al, vert_retrace               ; in display mode yet?
  1900.          jnz @sw_wait0                      ; if not, wait for it
  1901.  
  1902. ; set the start display address to the new window
  1903.  
  1904.          mov dx, crtc_index                 ; we change the vga sequencer
  1905.          mov al, start_disp_lo              ; display start low register
  1906.          mov ah, bl                         ; low 8 bits of start addr
  1907.          out dx, ax                         ; set display addr low
  1908.  
  1909.          mov al, start_disp_hi              ; display start high register
  1910.          mov ah, bh                         ; high 8 bits of start addr
  1911.          out dx, ax                         ; set display addr high
  1912.  
  1913. ; wait for a vertical retrace to smooth out things
  1914.  
  1915.          mov dx, input_1                    ; input status #1 register
  1916.  
  1917. @sw_wait1:
  1918.          in al, dx                          ; get vga status
  1919.          and al, vert_retrace               ; vertical retrace start?
  1920.          jz @sw_wait1                       ; if not, wait for it
  1921.  
  1922. ; now set the horizontal pixel pan values
  1923.  
  1924.          out_8 attrib_ctrl, pixel_pan_reg   ; select pixel pan register
  1925.  
  1926.          mov ax, [ebp].sw_xpos              ; get desired x offset
  1927.          and al, 03                         ; get # of pixels to pan (0-3)
  1928.          shl al, 1                          ; shift for 256 color mode
  1929.          out dx, al                         ; fine tune the display!
  1930.  
  1931. @sw_exit:
  1932.          pop ebp                            ; restore saved registers
  1933.          ret 6                              ; exit and clean up stack
  1934.  
  1935. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1936. ;_get_x_offset%
  1937. ;
  1938. ; returns the x coordinate of the pixel currently display
  1939. ; in the upper left corner of the display
  1940. ;
  1941. ; entry: no parameters are passed
  1942. ;
  1943. ; exit:  ax = current horizontal scroll offset
  1944. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1945.  
  1946.          public _get_x_offset
  1947.  
  1948. _get_x_offset:
  1949.  
  1950.          mov ax, _current_xoffset           ; get current horz offset
  1951.          ret                                ; exit & clean up stack
  1952.  
  1953. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1954. ;_get_y_offset%
  1955. ;
  1956. ; returns the y coordinate of the pixel currently display
  1957. ; in the upper left corner of the display
  1958. ;
  1959. ; entry: no parameters are passed
  1960. ;
  1961. ; exit:  ax = current vertical scroll offset
  1962. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1963.  
  1964.          public _get_y_offset
  1965.  
  1966. _get_y_offset:
  1967.  
  1968.          mov ax, _current_yoffset           ; get current vertical offset
  1969.          ret                                ; exit & clean up stack
  1970.  
  1971.          endif
  1972.  
  1973. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1974. ;_sync_display
  1975. ;
  1976. ; pauses the computer until the next vertical retrace starts
  1977. ;
  1978. ; entry: no parameters are passed
  1979. ;
  1980. ; exit:  no meaningful values returned
  1981. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  1982.  
  1983.          public _sync_display
  1984.  
  1985. _sync_display:
  1986.  
  1987.          mov dx, input_1                    ; input status #1 register
  1988.  
  1989. ; wait for any current retrace to end
  1990.  
  1991. @sd_wait0:
  1992.          in al, dx                          ; get vga status
  1993.          and al, vert_retrace               ; in display mode yet?
  1994.          jnz @sd_wait0                      ; if not, wait for it
  1995.  
  1996. ; wait for the start of the next vertical retrace
  1997.  
  1998. @sd_wait1:
  1999.          in al, dx                          ; get vga status
  2000.          and al, vert_retrace               ; vertical retrace start?
  2001.          jz @sd_wait1                       ; if not, wait for it
  2002.  
  2003.          ret
  2004.  
  2005.          if x_gprintc eq 1
  2006.  
  2007. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  2008. ;_gprintc (charnum%, xpos%, ypos%, colorf%, colorb%)
  2009. ;
  2010. ; draws an ascii text character using the currently selected
  2011. ; 8x8 font on the active display page.  it would be a simple
  2012. ; exercise to make this routine process variable height fonts.
  2013. ;
  2014. ; entry: charnum = ascii character # to draw
  2015. ;        xpos    = x position to draw character at
  2016. ;        ypos    = y position of to draw character at
  2017. ;        colorf  = color to draw text character in
  2018. ;        colorb  = color to set _background to
  2019. ;
  2020. ; exit:  no meaningful values returned
  2021. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  2022.  
  2023. gpc_stack struc
  2024.          gpc_width  dd ?                    ; screen width-1
  2025.          gpc_lines  db ?,?                  ; scan lines to decode
  2026.          gpc_t_sets dd ?                    ; saved charset segment
  2027.          dd ?x3                             ; edi, esi, ebp
  2028.          dd ?                               ; caller
  2029.          gpc_colorb db ?,?                  ; _background color
  2030.          gpc_colorf db ?,?                  ; text color
  2031.          gpc_ypos dw ?                      ; y position to print at
  2032.          gpc_xpos dw ?                      ; x position to print at
  2033.          gpc_char db ?,?                    ; character to print
  2034. gpc_stack ends
  2035.  
  2036.          public _gprintc
  2037.  
  2038. _gprintc:
  2039.  
  2040.          push ebp esi edi                   ; preserve important registers
  2041.          sub esp, 10                        ; allocate workspace on stack
  2042.          mov ebp, esp                       ; set up stack frame
  2043.  
  2044.          mov edi, _current_page             ; point to active vga page
  2045.  
  2046.          movzx eax, _screen_width           ; get logical line width
  2047.          mov ebx, eax                       ; bx = screen width
  2048.          dec bx                             ;    = screen width-1
  2049.          mov [ebp].gpc_width,ebx            ; save for later use
  2050.  
  2051.          mul [ebp].gpc_ypos                 ; start of line = ypos * width
  2052.          add edi, eax                       ; di -> start of line ypos
  2053.  
  2054.          movzx eax, [ebp].gpc_xpos          ; get xpos of character
  2055.          mov cx, ax                         ; save copy of xpos
  2056.          shr ax, 2                          ; bytes into line = xpos/4
  2057.          add edi, eax                       ; di -> (xpos, ypos)
  2058.  
  2059. ;get source addr of character bit map  & save
  2060.  
  2061.          mov al, [ebp].gpc_char             ; get character #
  2062.          test al, 080h                      ; is hi bit set?
  2063.          jz @gpc_lowchar                    ; nope, use low char set ptr
  2064.  
  2065.          mov ebx, _charset_hi               ; bx = char set ptr:offset
  2066.          jmp s @gpc_set_char                ; go setup character ptr
  2067.  
  2068. @gpc_lowchar:
  2069.  
  2070.          mov ebx, _charset_low              ; bx = char set ptr:offset
  2071.  
  2072. @gpc_set_char:
  2073.          and eax, 07fh                      ; mask out hi bits
  2074.          shl ax, 3                          ; * 8 bytes per _bitmap
  2075.          add ebx, eax                       ; bx = offset of selected char
  2076.          mov [ebp].gpc_t_sets, ebx          ; save segment on stack
  2077.  
  2078.          and cx, plane_bits                 ; get plane #
  2079.          mov ch, all_planes                 ; get initial plane mask
  2080.          shl ch, cl                         ; and shift into position
  2081.          and ch, all_planes                 ; and mask to lower nibble
  2082.  
  2083.          mov al, 04                         ; 4-plane # = # of initial
  2084.          sub al, cl                         ; shifts to align bit mask
  2085.          mov cl, al                         ; shift count for shl
  2086.  
  2087. ;get segment of character map
  2088.  
  2089.          out_8 sc_index, map_mask           ; setup plane selections
  2090.          inc dx                             ; dx -> sc_data
  2091.  
  2092.          mov al, 08                         ; 8 lines to process
  2093.          mov [ebp].gpc_lines, al            ; save on stack
  2094.  
  2095. @gpc_decode_char_byte:
  2096.  
  2097.          mov esi, [ebp].gpc_t_sets          ; get esi = _fnt_string
  2098.  
  2099.          mov bh, [esi]                      ; get bit map
  2100.          inc esi                            ; point to next line
  2101.          mov [ebp].gpc_t_sets, esi          ; and save new pointer...
  2102.  
  2103.          clr eax                            ; clear ax
  2104.  
  2105.          clr bl                             ; clear bl
  2106.          rol bx, cl                         ; bl holds left edge bits
  2107.          movzx esi, bx                      ; use as table index
  2108.          and si, char_bits                  ; get low bits
  2109.          mov al, char_plane_data[esi]       ; get mask in al
  2110.          jz @gpc_no_left1bits               ; skip if no pixels to set
  2111.  
  2112.          mov ah, [ebp].gpc_colorf           ; get foreground color
  2113.          out dx, al                         ; set up screen mask
  2114.          mov [edi], ah                      ; write foreground color
  2115.  
  2116. @gpc_no_left1bits:
  2117.          xor al, ch                         ; invert mask for _background
  2118.          jz @gpc_no_left0bits               ; hey, no need for this
  2119.  
  2120.          mov ah, [ebp].gpc_colorb           ; get _background color
  2121.          out dx, al                         ; set up screen mask
  2122.          mov [edi], ah                      ; write foreground color
  2123.  
  2124. ;now do middle/last band
  2125.  
  2126. @gpc_no_left0bits:
  2127.          inc edi                            ; point to next byte
  2128.          rol bx, 4                          ; shift 4 bits
  2129.  
  2130.          movzx esi, bx                      ; make lookup pointer
  2131.          and si, char_bits                  ; get low bits
  2132.          mov al, char_plane_data[esi]       ; get mask in al
  2133.          jz @gpc_no_middle1bits             ; skip if no pixels to set
  2134.  
  2135.          mov ah, [ebp].gpc_colorf           ; get foreground color
  2136.          out dx, al                         ; set up screen mask
  2137.          mov [edi], ah                      ; write foreground color
  2138.  
  2139. @gpc_no_middle1bits:
  2140.          xor al, all_planes                 ; invert mask for _background
  2141.          jz @gpc_no_middle0bits             ; hey, no need for this
  2142.  
  2143.          mov ah, [ebp].gpc_colorb           ; get _background color
  2144.          out dx, al                         ; set up screen mask
  2145.          mov [edi], ah                      ; write foreground color
  2146.  
  2147. @gpc_no_middle0bits:
  2148.          xor ch, all_planes                 ; invert clip mask
  2149.          cmp cl, 4                          ; aligned by 4?
  2150.          jz @gpc_next_line                  ; if so, exit now..
  2151.  
  2152.          inc edi                            ; point to next byte
  2153.          rol bx, 4                          ; shift 4 bits
  2154.  
  2155.          movzx esi, bx                      ; make lookup pointer
  2156.          and si, char_bits                  ; get low bits
  2157.          mov al, char_plane_data[esi]       ; get mask in al
  2158.          jz @gpc_no_right1bits              ; skip if no pixels to set
  2159.  
  2160.          mov ah, [ebp].gpc_colorf           ; get foreground color
  2161.          out dx, al                         ; set up screen mask
  2162.          mov [edi], ah                      ; write foreground color
  2163.  
  2164. @gpc_no_right1bits:
  2165.  
  2166.          xor al, ch                         ; invert mask for _background
  2167.          jz @gpc_no_right0bits              ; hey, no need for this
  2168.  
  2169.          mov ah, [ebp].gpc_colorb           ; get _background color
  2170.          out dx, al                         ; set up screen mask
  2171.          mov [edi], ah                      ; write foreground color
  2172.  
  2173. @gpc_no_right0bits:
  2174.          dec edi                            ; adjust for next line advance
  2175.  
  2176. @gpc_next_line:
  2177.          add edi, [ebp].gpc_width           ; point to next line
  2178.          xor ch, char_bits                  ; flip the clip mask back
  2179.  
  2180.          dec [ebp].gpc_lines                ; count down lines
  2181.          jz @gpc_exit                       ; ok... done!
  2182.  
  2183.          jmp @gpc_decode_char_byte          ; again! hey!
  2184.  
  2185. @gpc_exit:
  2186.          add esp, 10                        ; deallocate stack workspace
  2187.          pop edi esi ebp                    ; restore saved registers
  2188.          ret 10                             ; exit and clean up stack
  2189.  
  2190.          endif
  2191.          if x_tgprintc eq 1
  2192.  
  2193. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  2194. ;_tgprintc (charnum%, xpos%, ypos%, colorf%)
  2195. ;
  2196. ; transparently draws an ascii text character using the
  2197. ; currently selected 8x8 font on the active display page.
  2198. ;
  2199. ; entry: charnum = ascii character # to draw
  2200. ;        xpos    = x position to draw character at
  2201. ;        ypos    = y position of to draw character at
  2202. ;        colorf  = color to draw text character in
  2203. ;
  2204. ; exit:  no meaningful values returned
  2205. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  2206.  
  2207. tpc_stack struc
  2208.          tpc_width  dd ?                    ; screen width-1
  2209.          tpc_lines  db ?,?                  ; scan lines to decode
  2210.          tpc_t_sets dd ?                    ; saved charset segment
  2211.          dd ?x3                             ; edi, esi, ebp
  2212.          dd ?                               ; caller
  2213.          tpc_colorf db ?,?                  ; text color
  2214.          tpc_ypos dw ?                      ; y position to print at
  2215.          tpc_xpos dw ?                      ; x position to print at
  2216.          tpc_char db ?,?                    ; character to print
  2217. tpc_stack ends
  2218.  
  2219.          public _tgprintc
  2220.  
  2221. _tgprintc:
  2222.  
  2223.          push ebp esi edi                   ; preserve important registers
  2224.          sub esp, 10                        ; allocate workspace on stack
  2225.          mov ebp, esp                       ; set up stack frame
  2226.  
  2227.          mov edi, _current_page             ; point to active vga page
  2228.  
  2229.          movzx eax, _screen_width           ; get logical line width
  2230.          mov ebx, eax                       ; bx = screen width
  2231.          dec bx                             ;    = screen width-1
  2232.          mov [ebp].tpc_width,ebx            ; save for later use
  2233.  
  2234.          mul [ebp].tpc_ypos                 ; start of line = ypos * width
  2235.          add edi, eax                       ; di -> start of line ypos
  2236.  
  2237.          movzx eax, [ebp].tpc_xpos          ; get xpos of character
  2238.          mov cx, ax                         ; save copy of xpos
  2239.          shr ax, 2                          ; bytes into line = xpos/4
  2240.          add edi, eax                       ; di -> (xpos, ypos)
  2241.  
  2242. ;get source addr of character bit map  & save
  2243.  
  2244.          mov al, [ebp].tpc_char             ; get character #
  2245.          test al, 080h                      ; is hi bit set?
  2246.          jz @tpc_lowchar                    ; nope, use low char set ptr
  2247.  
  2248.          mov ebx, _charset_hi               ; bx = char set ptr:offset
  2249.          jmp s @tpc_set_char                ; go setup character ptr
  2250.  
  2251. @tpc_lowchar:
  2252.  
  2253.          mov ebx, _charset_low              ; bx = char set ptr:offset
  2254.  
  2255. @tpc_set_char:
  2256.          and eax, 07fh                      ; mask out hi bits
  2257.          shl ax, 3                          ; * 8 bytes per _bitmap
  2258.          add ebx, eax                       ; bx = offset of selected char
  2259.          mov [ebp].tpc_t_sets, ebx          ; save segment on stack
  2260.  
  2261.          and cx, plane_bits                 ; get plane #
  2262.          mov ch, all_planes                 ; get initial plane mask
  2263.          shl ch, cl                         ; and shift into position
  2264.          and ch, all_planes                 ; and mask to lower nibble
  2265.  
  2266.          mov al, 04                         ; 4-plane # = # of initial
  2267.          sub al, cl                         ; shifts to align bit mask
  2268.          mov cl, al                         ; shift count for shl
  2269.  
  2270. ;get segment of character map
  2271.  
  2272.          out_8 sc_index, map_mask           ; setup plane selections
  2273.          inc dx                             ; dx -> sc_data
  2274.  
  2275.          mov al, 08                         ; 8 lines to process
  2276.          mov [ebp].tpc_lines, al            ; save on stack
  2277.  
  2278. @tpc_decode_char_byte:
  2279.  
  2280.          mov esi, [ebp].tpc_t_sets          ; get esi = _fnt_string
  2281.  
  2282.          mov bh, [esi]                      ; get bit map
  2283.          inc esi                            ; point to next line
  2284.          mov [ebp].tpc_t_sets, esi          ; and save new pointer...
  2285.  
  2286.          clr eax                            ; clear ax
  2287.  
  2288.          clr bl                             ; clear bl
  2289.          rol bx, cl                         ; bl holds left edge bits
  2290.          movzx esi, bx                      ; use as table index
  2291.          and si, char_bits                  ; get low bits
  2292.          mov al, char_plane_data[esi]       ; get mask in al
  2293.          jz @tpc_no_left1bits               ; skip if no pixels to set
  2294.  
  2295.          mov ah, [ebp].tpc_colorf           ; get foreground color
  2296.          out dx, al                         ; set up screen mask
  2297.          mov [edi], ah                      ; write foreground color
  2298.  
  2299. ;now do middle/last band
  2300.  
  2301. @tpc_no_left1bits:
  2302.          inc edi                            ; point to next byte
  2303.          rol bx, 4                          ; shift 4 bits
  2304.  
  2305.          movzx esi, bx                      ; make lookup pointer
  2306.          and si, char_bits                  ; get low bits
  2307.          mov al, char_plane_data[esi]       ; get mask in al
  2308.          jz @tpc_no_middle1bits             ; skip if no pixels to set
  2309.  
  2310.          mov ah, [ebp].tpc_colorf           ; get foreground color
  2311.          out dx, al                         ; set up screen mask
  2312.          mov [edi], ah                      ; write foreground color
  2313.  
  2314. @tpc_no_middle1bits:
  2315.          xor ch, all_planes                 ; invert clip mask
  2316.          cmp cl, 4                          ; aligned by 4?
  2317.          jz @tpc_next_line                  ; if so, exit now..
  2318.  
  2319.          inc edi                            ; point to next byte
  2320.          rol bx, 4                          ; shift 4 bits
  2321.  
  2322.          movzx esi, bx                      ; make lookup pointer
  2323.          and si, char_bits                  ; get low bits
  2324.          mov al, char_plane_data[esi]       ; get mask in al
  2325.          jz @tpc_no_right1bits              ; skip if no pixels to set
  2326.  
  2327.          mov ah, [ebp].tpc_colorf           ; get foreground color
  2328.          out dx, al                         ; set up screen mask
  2329.          mov [edi], ah                      ; write foreground color
  2330.  
  2331. @tpc_no_right1bits:
  2332.          dec edi                            ; adjust for next line advance
  2333.  
  2334. @tpc_next_line:
  2335.          add edi, [ebp].tpc_width           ; point to next line
  2336.          xor ch, char_bits                  ; flip the clip mask back
  2337.  
  2338.          dec [ebp].tpc_lines                ; count down lines
  2339.          jz @tpc_exit                       ; ok... done!
  2340.  
  2341.          jmp @tpc_decode_char_byte          ; again! hey!
  2342.  
  2343. @tpc_exit:
  2344.          add esp, 10                        ; deallocate stack workspace
  2345.          pop edi esi ebp                    ; restore saved registers
  2346.          ret 8                              ; exit and clean up stack
  2347.  
  2348.          endif
  2349.          if x_gprintc eq 1
  2350.  
  2351. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  2352. ;_print_str (seg _fnt_string, maxlen%, xpos%, ypos%, colorf%, colorb%)
  2353. ;
  2354. ; routine to quickly print a null terminated ascii _fnt_string on the
  2355. ; active display page up to a maximum length.
  2356. ;
  2357. ; entry: _fnt_string  = far pointer to ascii _fnt_string to print
  2358. ;        maxlen  = # of characters to print if no null found
  2359. ;        xpos    = x position to draw text at
  2360. ;        ypos    = y position of to draw text at
  2361. ;        colorf  = color to draw text in
  2362. ;        colorb  = color to set _background to
  2363. ;
  2364. ; exit:  no meaningful values returned
  2365. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  2366.  
  2367. ps_stack struc
  2368.          dd ?x3                             ; edi, esi, ebp
  2369.          dd ?                               ; caller
  2370.          ps_colorb dw ?                     ; _background color
  2371.          ps_colorf dw ?                     ; text color
  2372.          ps_ypos dw ?                       ; y position to print at
  2373.          ps_xpos dw ?                       ; x position to print at
  2374.          ps_len  dw ?                       ; maximum length of _fnt_string to print
  2375.          ps_text dd ?                       ; far ptr to text _fnt_string
  2376. ps_stack ends
  2377.  
  2378.          public _print_str
  2379.  
  2380. _print_str:
  2381.  
  2382.          push ebp esi edi                   ; preserve important registers
  2383.          mov ebp, esp                       ; set up stack frame
  2384.  
  2385. @ps_print_it:
  2386.  
  2387.          mov cx, [ebp].ps_len               ; get remaining text length
  2388.          jcxz @ps_exit                      ; exit when out of text
  2389.  
  2390.          mov edi, [ebp].ps_text             ; edi -> current char in text
  2391.          mov al, [edi]                      ; al = text character
  2392.          and ax, 00ffh                      ; clear high word
  2393.          jz @ps_exit                        ; exit if null character
  2394.  
  2395.          dec [ebp].ps_len                   ; remaining text length--
  2396.          inc [ebp].ps_text                  ; point to next text char
  2397.  
  2398. ; set up call to _gprintc
  2399.  
  2400.          push ax                            ; set character parameter
  2401.          mov bx, [ebp].ps_xpos              ; get xpos
  2402.          push bx                            ; set xpos parameter
  2403.          add bx, 8                          ; advance 1 char to right
  2404.          mov [ebp].ps_xpos, bx              ; save for next time through
  2405.  
  2406.          mov bx, [ebp].ps_ypos              ; get ypos
  2407.          push bx                            ; set ypos parameter
  2408.  
  2409.          mov bx, [ebp].ps_colorf            ; get text color
  2410.          push bx                            ; set colorf parameter
  2411.  
  2412.          mov bx, [ebp].ps_colorb            ; get _background color
  2413.          push bx                            ; set colorb parameter
  2414.  
  2415.          call _gprintc                      ; print character!
  2416.          jmp s @ps_print_it                 ; process next character
  2417.  
  2418. @ps_exit:
  2419.          pop edi esi ebp                    ; restore saved registers
  2420.          ret 14                             ; exit and clean up stack
  2421.  
  2422.          endif
  2423.          if x_tgprintc eq 1
  2424.  
  2425. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  2426. ;_tprint_str (seg _fnt_string, maxlen%, xpos%, ypos%, colorf%, colorb%)
  2427. ;
  2428. ; routine to quickly transparently print a null terminated ascii
  2429. ; _fnt_string on the active display page up to a maximum length.
  2430. ;
  2431. ; entry: _fnt_string  = far pointer to ascii _fnt_string to print
  2432. ;        maxlen  = # of characters to print if no null found
  2433. ;        xpos    = x position to draw text at
  2434. ;        ypos    = y position of to draw text at
  2435. ;        colorf  = color to draw text in
  2436. ;
  2437. ; exit:  no meaningful values returned
  2438. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  2439.  
  2440. tps_stack struc
  2441.          dd ?x3                             ; edi, esi, ebp
  2442.          dd ?                               ; caller
  2443.          tps_colorf dw ?                    ; text color
  2444.          tps_ypos dw ?                      ; y position to print at
  2445.          tps_xpos dw ?                      ; x position to print at
  2446.          tps_len dw ?                       ; maximum length of _fnt_string to print
  2447.          tps_text dd ?                      ; far ptr to text _fnt_string
  2448. tps_stack ends
  2449.  
  2450.          public _tprint_str
  2451.  
  2452. _tprint_str:
  2453.  
  2454.          push ebp esi edi                   ; preserve important registers
  2455.          mov ebp, esp                       ; set up stack frame
  2456.  
  2457. @ts_print_it:
  2458.  
  2459.          mov cx, [ebp].tps_len              ; get remaining text length
  2460.          jcxz @ts_exit                      ; exit when out of text
  2461.  
  2462.          mov edi, [ebp].tps_text            ; edi -> current char in text
  2463.          mov al, [edi]                      ; al = text character
  2464.          and ax, 00ffh                      ; clear high word
  2465.          jz @ts_exit                        ; exit if null character
  2466.  
  2467.          dec [ebp].tps_len                  ; remaining text length--
  2468.          inc [ebp].tps_text                 ; point to next text char
  2469.  
  2470. ; set up call to _tgprintc
  2471.  
  2472.          push ax                            ; set character parameter
  2473.          mov bx, [ebp].tps_xpos             ; get xpos
  2474.          push bx                            ; set xpos parameter
  2475.          add bx, 8                          ; advance 1 char to right
  2476.          mov [ebp].tps_xpos, bx             ; save for next time through
  2477.  
  2478.          mov bx, [ebp].tps_ypos             ; get ypos
  2479.          push bx                            ; set ypos parameter
  2480.  
  2481.          mov bx, [ebp].tps_colorf           ; get text color
  2482.          push bx                            ; set colorf parameter
  2483.  
  2484.          call _tgprintc                     ; print character!
  2485.          jmp s @ts_print_it                 ; process next character
  2486.  
  2487. @ts_exit:
  2488.          pop edi esi ebp                    ; restore saved registers
  2489.          ret 12                             ; exit and clean up stack
  2490.  
  2491.          endif
  2492.  
  2493. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  2494. ;_set_display_font(seg fontdata, fontnumber%)
  2495. ;
  2496. ; allows the user to specify their own font data for
  2497. ; wither the lower or upper 128 characters.
  2498. ;
  2499. ; entry: fontdata   = far pointer to font _bitmaps
  2500. ;        fontnumber = which half of set this is
  2501. ;                   = 0, lower 128 characters
  2502. ;                   = 1, upper 128 characters
  2503. ;
  2504. ; exit:  no meaningful values returned
  2505. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  2506.  
  2507. sdf_stack struc
  2508.          dd ?                               ; ebp
  2509.          dd ?                               ; caller
  2510.          sdf_which dw ?                     ; hi table/low table flag
  2511.          sdf_font  dd ?                     ; far ptr to font table
  2512. sdf_stack ends
  2513.  
  2514.          public _set_display_font
  2515.  
  2516. _set_display_font:
  2517.  
  2518.          push ebp                           ; preserve registers
  2519.          mov ebp, esp                       ; set up stack frame
  2520.  
  2521.          mov edi, [ebp].sdf_font            ; get far ptr to font
  2522.  
  2523.          mov esi, o _charset_low            ; assume lower 128 chars
  2524.          test [ebp].sdf_which, 1            ; font #1 selected?
  2525.          jz @sdf_set_font                   ; if not, skip ahead
  2526.  
  2527.          mov esi, o _charset_hi             ; ah, really it's 128-255
  2528.  
  2529. @sdf_set_font:
  2530.          mov [esi], edi                     ; set font pointer offset
  2531.  
  2532.          pop ebp                            ; restore registers
  2533.          ret 6                              ; we are done.. outa here
  2534.  
  2535. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  2536. ;_draw_bitmap (seg image, xpos%, ypos% )
  2537. ;
  2538. ; draws a variable sized graphics _bitmap such as a
  2539. ; picture or an icon on the current display page in
  2540. ; mode x.  the _bitmap is stored in a lifar byte array
  2541. ; corresponding to (0,0) (1,0), (2,0) .. (width, height)
  2542. ; this is the same lifar manner as mode 13h graphics.
  2543. ;
  2544. ; entry: image  = far pointer to _bitmap data
  2545. ;        xpos   = x position to place upper left pixel at
  2546. ;        ypos   = y position to place upper left pixel at
  2547. ;        width  = width of the _bitmap in pixels  - ommitted
  2548. ;        height = height of the _bitmap in pixels - ommitted
  2549. ;
  2550. ; exit:  no meaningful values returned
  2551. ;
  2552. ; routine has been modified so that first two words of a bitmap define
  2553. ; bitmap x and y size
  2554. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  2555.  
  2556. db_stack struc
  2557.          db_lineo dw ?                      ; offset to next line
  2558.          db_pixcount dw ?                   ; (minimum) # of pixels/line
  2559.          db_start dd ?                      ; addr of upper left pixel
  2560.          db_pixskew dw ?                    ; # of bytes to adjust eol
  2561.          db_skewflag dw ?                   ; extra pix on plane flag
  2562.          db_height dw ?                     ; height of _bitmap in pixels
  2563.          dd ?x3                             ; edi, esi, ebp
  2564.          dd ?                               ; caller
  2565.          db_ypos dw ?                       ; y position to draw _bitmap at
  2566.          db_xpos dw ?                       ; x position to draw _bitmap at
  2567.          db_image dd ?                      ; far pointer to graphics _bitmap
  2568. db_stack ends
  2569.  
  2570.          public _draw_bitmap
  2571.  
  2572. _draw_bitmap:
  2573.  
  2574.          push ebp esi edi                   ; preserve important registers
  2575.          sub esp, 14                        ; allocate workspace
  2576.          mov ebp, esp                       ; set up stack frame
  2577.  
  2578.          mov edi, _current_page             ; point to active vga page
  2579.          cld                                ; direction flag = forward
  2580.  
  2581.          movzx eax, [ebp].db_ypos           ; get ul corner ypos
  2582.          mul _screen_width                  ; ax = offset to line ypos
  2583.  
  2584.          movzx ebx, [ebp].db_xpos           ; get ul corner xpos
  2585.          mov cl, bl                         ; save plane # in cl
  2586.          shr bx, 2                          ; xpos/4 = offset into line
  2587.  
  2588.          add edi, eax                       ; edi -> start of line
  2589.          add edi, ebx                       ; edi -> upper left pixel
  2590.          mov [ebp].db_start, edi            ; save starting addr
  2591.  
  2592. ; compute line to line offset
  2593.  
  2594.          mov esi, [ebp].db_image            ; esi-> source image
  2595.          lodsw                              ; get x width
  2596.          mov bx,ax
  2597.          lodsw
  2598.          mov [ebp].db_height,ax
  2599.          add [ebp].db_image,4
  2600.  
  2601.          mov dx, bx                         ; save copy in dx
  2602.          shr bx, 2                          ; /4 = width in bands
  2603.          mov ax, _screen_width              ; get screen width
  2604.          sub ax, bx                         ; - (_bitmap width/4)
  2605.  
  2606.          mov [ebp].db_lineo, ax             ; save line width offset
  2607.          mov [ebp].db_pixcount, bx          ; minimum # pix to copy
  2608.  
  2609.          and dx, plane_bits                 ; get "partial band" size (0-3)
  2610.          mov [ebp].db_pixskew, dx           ; also end of line skew
  2611.          mov [ebp].db_skewflag, dx          ; save as flag/count
  2612.  
  2613.          and cx, plane_bits                 ; cl = starting plane #
  2614.          mov ax, map_mask_plane2            ; plane mask & plane select
  2615.          shl ah, cl                         ; select correct plane
  2616.          out_16 sc_index, ax                ; select plane...
  2617.          mov bh, ah                         ; bh = saved plane mask
  2618.          mov bl, 4                          ; bl = planes to copy
  2619.  
  2620. @db_copy_plane:
  2621.  
  2622.          mov esi, [ebp].db_image            ; esi-> source image
  2623.          mov dx, [ebp].db_height            ; # of lines to copy
  2624.          mov edi, [ebp].db_start            ; edi-> dest pos
  2625.  
  2626. @db_copy_line:
  2627.          mov cx, [ebp].db_pixcount          ; min # to copy
  2628.  
  2629.          test cl, 0fch                      ; 16+pixwide?
  2630.          jz @db_copy_remainder              ; nope...
  2631.  
  2632. ; pixel copy loop has been unrolled to x4
  2633.  
  2634. @db_copy_loop:
  2635.          movsb                              ; copy _bitmap pixel
  2636.          add esi, 3                         ; skip to next byte in same plane
  2637.          movsb                              ; copy _bitmap pixel
  2638.          add esi, 3                         ; skip to next byte in same plane
  2639.          movsb                              ; copy _bitmap pixel
  2640.          add esi, 3                         ; skip to next byte in same plane
  2641.          movsb                              ; copy _bitmap pixel
  2642.          add esi, 3                         ; skip to next byte in same plane
  2643.  
  2644.          sub cl, 4                          ; pixels to copy=-4
  2645.          test cl, 0fch                      ; 4+ pixels left?
  2646.          jnz @db_copy_loop                  ; if so, do another block
  2647.  
  2648. @db_copy_remainder:
  2649.          jcxz @db_next_line                 ; any pixels left on line
  2650.  
  2651. @db_cop_y2:
  2652.          movsb                              ; copy _bitmap pixel
  2653.          add esi,3                          ; skip to next byte in same plane
  2654.          loopx cx, @db_cop_y2               ; pixels to copy--, loop until done
  2655.  
  2656. @db_next_line:
  2657.  
  2658. ; any partial pixels? (some planes only)
  2659.  
  2660.          or cx, [ebp].db_skewflag           ; get skew count
  2661.          jz @db_next2                       ; if no partial pixels
  2662.  
  2663.          movsb                              ; copy _bitmap pixel
  2664.          dec edi                            ; back up to align
  2665.          dec esi                            ; back up to align
  2666.  
  2667. @db_next2:
  2668.          movzx eax, [ebp].db_pixskew        ; adjust skew
  2669.          add esi, eax
  2670.          movzx eax, [ebp].db_lineo          ; set to next display line
  2671.          add edi, eax
  2672.          loopx dx, @db_copy_line            ; lines to copy--, loop if more
  2673.  
  2674. ; copy next plane....
  2675.  
  2676.          dec bl                             ; planes to go--
  2677.          jz @db_exit                        ; hey! we are done
  2678.  
  2679.          rol bh, 1                          ; next plane in line...
  2680.          out_8 sc_data, bh                  ; select plane
  2681.  
  2682.          cmp al, 12h                        ; carry set if al=11h
  2683.          adc [ebp].db_start, 0              ; screen addr =+carry
  2684.          inc w [ebp].db_image               ; start @ next byte
  2685.  
  2686.          sub [ebp].db_skewflag, 1           ; reduce planes to skew
  2687.          adc [ebp].db_skewflag, 0           ; back to 0 if it was -1
  2688.  
  2689.          jmp @db_copy_plane                 ; go copy the next plane
  2690.  
  2691. @db_exit:
  2692.          add esp, 14                        ; deallocate workspace
  2693.          pop edi esi ebp                    ; restore saved registers
  2694.          ret 8                              ; exit and clean up stack
  2695.  
  2696. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  2697. ;_tdraw_bitmap (seg image, xpos%, ypos%)
  2698. ;
  2699. ; transparently draws a variable sized graphics _bitmap
  2700. ; such as a picture or an icon on the current display page
  2701. ; in mode x.  pixels with a value of 0 are not drawn,
  2702. ; leaving the previous "_background" contents intact.
  2703. ;
  2704. ; the _bitmap format is the same as for the _draw_bitmap function.
  2705. ;
  2706. ; entry: image  = far pointer to _bitmap data
  2707. ;        xpos   = x position to place upper left pixel at
  2708. ;        ypos   = y position to place upper left pixel at
  2709. ;        width  = width of the _bitmap in pixels   - ommitted
  2710. ;        height = height of the _bitmap in pixels  - ommitted
  2711. ;
  2712. ; exit:  no meaningful values returned
  2713. ;
  2714. ; routine has been modified so that first two words of _bitmap define
  2715. ; _bitmap x and y size
  2716. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  2717.  
  2718. tb_stack struc
  2719.          tb_lineo dw ?                      ; offset to next line
  2720.          tb_pixcount dw ?                   ; (minimum) # of pixels/line
  2721.          tb_start dd ?                      ; addr of upper left pixel
  2722.          tb_pixskew dw ?                    ; # of bytes to adjust eol
  2723.          tb_skewflag dw ?                   ; extra pix on plane flag
  2724.          tb_height dw ?                     ; height of _bitmap in pixels
  2725.          dd ?x3                             ; edi, esi, ebp
  2726.          dd ?                               ; caller
  2727.          tb_ypos dw ?                       ; y position to draw _bitmap at
  2728.          tb_xpos dw ?                       ; x position to draw _bitmap at
  2729.          tb_image dd ?                      ; far pointer to graphics _bitmap
  2730. tb_stack ends
  2731.  
  2732.          public _tdraw_bitmap
  2733.  
  2734. _tdraw_bitmap:
  2735.  
  2736.          push ebp esi edi                   ; preserve important registers
  2737.          sub esp, 14                        ; allocate workspace
  2738.          mov ebp, esp                       ; set up stack frame
  2739.  
  2740.          mov edi, _current_page             ; point to active vga page
  2741.          cld                                ; direction flag = forward
  2742.  
  2743.          movzx eax, [ebp].tb_ypos           ; get ul corner ypos
  2744.          mul _screen_width                  ; ax = offset to line ypos
  2745.  
  2746.          movzx ebx, [ebp].tb_xpos           ; get ul corner xpos
  2747.          mov cl, bl                         ; save plane # in cl
  2748.          shr bx, 2                          ; xpos/4 = offset into line
  2749.  
  2750.          add edi, eax                       ; edi -> start of line
  2751.          add edi, ebx                       ; edi -> upper left pixel
  2752.          mov [ebp].tb_start, edi            ; save starting addr
  2753.  
  2754. ; compute line to line offset
  2755.  
  2756.          mov esi, [ebp].tb_image            ; esi-> source image
  2757.          lodsw                              ; get x width
  2758.          mov bx,ax
  2759.          lodsw
  2760.          mov [ebp].tb_height,ax
  2761.          add [ebp].tb_image,4
  2762.  
  2763.          mov dx, bx                         ; save copy in dx
  2764.          shr bx, 2                          ; /4 = width in bands
  2765.          mov ax, _screen_width              ; get screen width
  2766.          sub ax, bx                         ; - (_bitmap width/4)
  2767.  
  2768.          mov [ebp].tb_lineo, ax             ; save line width offset
  2769.          mov [ebp].tb_pixcount, bx          ; minimum # pix to copy
  2770.  
  2771.          and dx, plane_bits                 ; get "partial band" size (0-3)
  2772.          mov [ebp].tb_pixskew, dx           ; also end of line skew
  2773.          mov [ebp].tb_skewflag, dx          ; save as flag/count
  2774.  
  2775.          and cx, plane_bits                 ; cl = starting plane #
  2776.          mov ax, map_mask_plane2            ; plane mask & plane select
  2777.          shl ah, cl                         ; select correct plane
  2778.          out_16 sc_index, ax                ; select plane...
  2779.          mov bh, ah                         ; bh = saved plane mask
  2780.          mov bl, 4                          ; bl = planes to copy
  2781.  
  2782. @tb_copy_plane:
  2783.  
  2784.          mov esi, [ebp].tb_image            ; esi-> source image
  2785.          mov dx, [ebp].tb_height            ; # of lines to copy
  2786.          mov edi, [ebp].tb_start            ; edi-> dest pos
  2787.  
  2788. ; here ah is set with the value to be considered
  2789. ; "transparent".  it can be changed!
  2790.  
  2791. @tb_copy_line:
  2792.          mov ah, 0                          ; value to detect 0
  2793.          mov cx, [ebp].tb_pixcount          ; min # to copy
  2794.  
  2795.          test cl, 0fch                      ; 16+pixwide?
  2796.          jz @tb_copy_remainder              ; nope...
  2797.  
  2798. ; pixel copy loop has been unrolled to x4
  2799.  
  2800. @tb_copy_loop:
  2801.          lodsb                              ; get pixel value in al
  2802.          add esi, 3                         ; skip to next byte in same plane
  2803.          cmp al, ah                         ; it is "transparent"?
  2804.          je @tb_skip_01                     ; skip ahead if so
  2805.          mov [edi], al                      ; copy pixel to vga screen
  2806.  
  2807. @tb_skip_01:
  2808.          lodsb                              ; get pixel value in al
  2809.          add esi, 3                         ; skip to next byte in same plane
  2810.          cmp al, ah                         ; it is "transparent"?
  2811.          je @tb_skip_02                     ; skip ahead if so
  2812.          mov [edi+1], al                    ; copy pixel to vga screen
  2813.  
  2814. @tb_skip_02:
  2815.          lodsb                              ; get pixel value in al
  2816.          add esi, 3                         ; skip to next byte in same plane
  2817.          cmp al, ah                         ; it is "transparent"?
  2818.          je @tb_skip_03                     ; skip ahead if so
  2819.          mov [edi+2], al                    ; copy pixel to vga screen
  2820.  
  2821. @tb_skip_03:
  2822.          lodsb                              ; get pixel value in al
  2823.          add esi, 3                         ; skip to next byte in same plane
  2824.          cmp al, ah                         ; it is "transparent"?
  2825.          je @tb_skip_04                     ; skip ahead if so
  2826.          mov [edi+3], al                    ; copy pixel to vga screen
  2827.  
  2828. @tb_skip_04:
  2829.          add edi, 4                         ; adjust pixel write location
  2830.          sub cl, 4                          ; pixels to copy=-4
  2831.          test cl, 0fch                      ; 4+ pixels left?
  2832.          jnz @tb_copy_loop                  ; if so, do another block
  2833.  
  2834. @tb_copy_remainder:
  2835.          jcxz @tb_next_line                 ; any pixels left on line
  2836.  
  2837. @tb_cop_y2:
  2838.          lodsb                              ; get pixel value in al
  2839.          add esi, 3                         ; skip to next byte in same plane
  2840.          cmp al, ah                         ; it is "transparent"?
  2841.          je @tb_skip_05                     ; skip ahead if so
  2842.          mov [edi], al                      ; copy pixel to vga screen
  2843.  
  2844. @tb_skip_05:
  2845.          inc edi                            ; advance dest addr
  2846.          loopx cx, @tb_cop_y2               ; pixels to copy--, loop until done
  2847.  
  2848. @tb_next_line:
  2849.  
  2850. ; any partial pixels? (some planes only)
  2851.  
  2852.          or cx, [ebp].tb_skewflag           ; get skew count
  2853.          jz @tb_next2                       ; if no partial pixels
  2854.  
  2855.          lodsb                              ; get pixel value in al
  2856.          dec esi                            ; backup to align
  2857.          cmp al, ah                         ; it is "transparent"?
  2858.          je @tb_next2                       ; skip ahead if so
  2859.          mov [edi], al                      ; copy pixel to vga screen
  2860.  
  2861. @tb_next2:
  2862.          movzx eax, [ebp].tb_pixskew        ; adjust skew
  2863.          add esi, eax
  2864.          movzx eax, [ebp].tb_lineo          ; set to next display line
  2865.          add edi, eax
  2866.          loopx dx, @tb_copy_line            ; lines to copy--, loop if more
  2867.  
  2868.          ;copy next plane....
  2869.  
  2870.          dec bl                             ; planes to go--
  2871.          jz @tb_exit                        ; hey! we are done
  2872.  
  2873.          rol bh, 1                          ; next plane in line...
  2874.          out_8 sc_data, bh                  ; select plane
  2875.  
  2876.          cmp al, 12h                        ; carry set if al=11h
  2877.          adc [ebp].tb_start, 0              ; screen addr =+carry
  2878.          inc w [ebp].tb_image               ; start @ next byte
  2879.  
  2880.          sub [ebp].tb_skewflag, 1           ; reduce planes to skew
  2881.          adc [ebp].tb_skewflag, 0           ; back to 0 if it was -1
  2882.  
  2883.          jmp @tb_copy_plane                 ; go copy the next plane
  2884.  
  2885. @tb_exit:
  2886.          add esp, 14                        ; deallocate workspace
  2887.          pop edi esi ebp                    ; restore saved registers
  2888.          ret 8                              ; exit and clean up stack
  2889.  
  2890. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  2891. ;_copy_page (sourcepage%, destpage%)
  2892. ;
  2893. ; duplicate on display page onto another
  2894. ;
  2895. ; entry: sourcepage = display page # to duplicate
  2896. ;        destpage   = display page # to hold copy
  2897. ;
  2898. ; exit:  no meaningful values returned
  2899. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  2900.  
  2901. cp_stack struc
  2902.          dd ?x3                             ; edi, esi, ebp
  2903.          dd ?                               ; caller
  2904.          cp_destp dw ?                      ; page to hold copied image
  2905.          cp_sourcep dw ?                    ; page to make copy from
  2906. cp_stack ends
  2907.  
  2908.          public _copy_page
  2909.  
  2910. _copy_page:
  2911.  
  2912.          push ebp esi edi                   ; preserve important registers
  2913.          mov ebp, esp                       ; set up stack frame
  2914.          cld                                ; block xfer forwards
  2915.  
  2916. ; make sure page #'s are valid
  2917.  
  2918.          mov ax, [ebp].cp_sourcep           ; get source page #
  2919.          cmp ax, _last_page                 ; is it > max page #?
  2920.          jae @cp_exit                       ; if so, abort
  2921.  
  2922.          mov bx, [ebp].cp_destp             ; get destination page #
  2923.          cmp bx, _last_page                 ; is it > max page #?
  2924.          jae @cp_exit                       ; if so, abort
  2925.  
  2926.          cmp ax, bx                         ; pages #'s the same?
  2927.          je @cp_exit                        ; if so, abort
  2928.  
  2929. ; setup esi and edi to video pages
  2930.  
  2931.          shl bx, 2                          ; scale index to dword
  2932.          mov edi, _page_addr[ebx]           ; offset to dest page
  2933.  
  2934.          mov bx, ax                         ; index to source page
  2935.          shl bx, 2                          ; scale index to dword
  2936.          mov esi, _page_addr[ebx]           ; offset to source page
  2937.  
  2938.          movzx ecx, _page_size              ; get size of page
  2939.  
  2940. ; setup vga registers for mem to mem copy
  2941.  
  2942.          out_16 gc_index, latches_on        ; data from latches = on
  2943.          out_16 sc_index, all_planes_on     ; copy all planes
  2944.  
  2945. ; note.. do *not* use movsw or movsd - they will
  2946. ; screw with the latches which are 8 bits x 4
  2947.  
  2948.          rep movsb                          ; copy entire page!
  2949.  
  2950. ; reset vga for normal memory access
  2951.  
  2952.          out_16 gc_index, latches_off       ; data from latches = off
  2953.  
  2954. @cp_exit:
  2955.          pop edi esi ebp                    ; restore saved registers
  2956.          ret 4                              ; exit and clean up stack
  2957.  
  2958. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  2959. ;_copy_bitmap (sourcepage%, _x1%, _y1%, _x2%, _y2%, destpage%, _scale_dest_x1%, _scale_dest_y1%)
  2960. ;
  2961. ; copies a _bitmap image from one display page to another
  2962. ; this routine is limited to copying images with the same
  2963. ; plane alignment.  to work: (_x1 mod 4) must = (_scale_dest_x1 mod 4)
  2964. ; copying an image to the same page is supported, but results
  2965. ; may be defined when the when the rectangular areas
  2966. ; (_x1, _y1) - (_x2, _y2) and (_scale_dest_x1, _scale_dest_y1) -
  2967. ; (_scale_dest_x1+(_x2-_x1), _scale_dest_y1+(_y2-_y1)) overlap...
  2968. ; no paramter checking to done to insure that
  2969. ; _x2 >= _x1 and _y2 >= _y1.  be careful...
  2970. ;
  2971. ; entry: sourcepage = display page # with source image
  2972. ;        _x1         = upper left xpos of source image
  2973. ;        _y1         = upper left ypos of source image
  2974. ;        _x2         = lower right xpos of source image
  2975. ;        _y2         = lower right ypos of source image
  2976. ;        destpage   = display page # to copy image to
  2977. ;        _scale_dest_x1     = xpos to copy ul corner of image to
  2978. ;        _scale_dest_y1     = ypos to copy ul corner of image to
  2979. ;
  2980. ; exit:  ax = success flag:   0 = failure / -1= success
  2981. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  2982.  
  2983. cb_stack struc
  2984.          cb_height dw ?                     ; height of image in lines
  2985.          cb_width dw ?                      ; width of image in "bands"
  2986.          dd ?x3                             ; edi, esi, ebp
  2987.          dd ?                               ; caller
  2988.          cb_scale_dest_y1 dw ?              ; destination ypos
  2989.          cb_scale_dest_x1 dw ?              ; destination xpos
  2990.          cb_destp dw ?                      ; page to copy _bitmap to
  2991.          cb_y2 dw ?                         ; lr ypos of image
  2992.          cb_x2 dw ?                         ; lr xpos of image
  2993.          cb_y1 dw ?                         ; ul ypos of image
  2994.          cb_x1 dw ?                         ; ul xpos of image
  2995.          cb_sourcep dw ?                    ; page containing source _bitmap
  2996. cb_stack ends
  2997.  
  2998.          public _copy_bitmap
  2999.  
  3000. _copy_bitmap:
  3001.  
  3002.          push ebp esi edi                   ; preserve important registers
  3003.          sub esp, 4                         ; allocate workspace on stack
  3004.          mov ebp, esp                       ; set up stack frame
  3005.  
  3006. ; prep registers (and keep jumps short!)
  3007.  
  3008.          cld                                ; block xfer forwards
  3009.  
  3010. ; make sure parameters are valid
  3011.  
  3012.          movzx ebx, [ebp].cb_sourcep        ; get source page #
  3013.          cmp bx, _last_page                 ; is it > max page #?
  3014.          jae @cb_abort                      ; if so, abort
  3015.  
  3016.          mov cx, [ebp].cb_destp             ; get destination page #
  3017.          cmp cx, _last_page                 ; is it > max page #?
  3018.          jae @cb_abort                      ; if so, abort
  3019.  
  3020.          mov ax, [ebp].cb_x1                ; get source _x1
  3021.          xor ax, [ebp].cb_scale_dest_x1     ; compare bits 0-1
  3022.          and ax, plane_bits                 ; check plane bits
  3023.          jnz @cb_abort                      ; they should cancel out
  3024.  
  3025. ; setup for copy processing
  3026.  
  3027.          out_8 sc_index, map_mask           ; set up for plane select
  3028.          out_16 gc_index, latches_on        ; data from latches = on
  3029.  
  3030. ; compute info about images, setup esi & edi
  3031.  
  3032.          mov ax, [ebp].cb_y2                ; height of _bitmap in lines
  3033.          sub ax, [ebp].cb_y1                ; is _y2 - _y1 + 1
  3034.          inc ax                             ; (add 1 since were not 0 based)
  3035.          mov [ebp].cb_height, ax            ; save on stack for later use
  3036.  
  3037.          mov ax, [ebp].cb_x2                ; get # of "bands" of 4 pixels
  3038.          mov dx, [ebp].cb_x1                ; the _bitmap occupies as _x2-_x1
  3039.          shr ax, 2                          ; get _x2 band (_x2 / 4)
  3040.          shr dx, 2                          ; get _x1 band (_x1 / 4)
  3041.          sub ax, dx                         ; ax = # of bands - 1
  3042.          inc ax                             ; ax = # of bands
  3043.          mov [ebp].cb_width, ax             ; save on stack for later use
  3044.  
  3045.          shl bx, 2                          ; scale source page to dword
  3046.          mov esi, _page_addr[ebx]           ; si = offset of source page
  3047.          mov ax, [ebp].cb_y1                ; get source _y1 line
  3048.          mul _screen_width                  ; ax = offset to line _y1
  3049.          movzx eax, ax
  3050.          add esi, eax                       ; si = offset to line _y1
  3051.          mov ax, [ebp].cb_x1                ; get source _x1
  3052.          shr ax, 2                          ; _x1 / 4 = byte offset
  3053.          add esi, eax                       ; si = byte offset to (_x1,_y1)
  3054.  
  3055.          mov bx, cx                         ; dest page index to bx
  3056.          shl bx, 2                          ; scale source page to dword
  3057.          mov edi, _page_addr[ebx]           ; di = offset of dest page
  3058.          mov ax, [ebp].cb_scale_dest_y1     ; get dest _y1 line
  3059.          mul _screen_width                  ; ax = offset to line _y1
  3060.          movzx eax, ax
  3061.          add edi, eax                       ; di = offset to line _y1
  3062.          mov ax, [ebp].cb_scale_dest_x1     ; get dest _x1
  3063.          shr ax, 2                          ; _x1 / 4 = byte offset
  3064.          add edi, eax                       ; di = byte offset to (d-_x1,d-_y1)
  3065.  
  3066.          mov cx, [ebp].cb_width             ; cx = width of image (bands)
  3067.          dec cx                             ; cx = 1?
  3068.          je @cb_only_one_band               ; 0 means image width of 1 band
  3069.  
  3070.          mov bx, [ebp].cb_x1                ; get source _x1
  3071.          and bx, plane_bits                 ; aligned? (bits 0-1 = 00?)
  3072.          jz @cb_check_right                 ; if so, check right alignment
  3073.          jnz @cb_left_band                  ; not aligned? well..
  3074.  
  3075. @cb_abort:
  3076.          clr ax                             ; return false (failure)
  3077.          jmp @cb_exit                       ; and finish up
  3078.  
  3079. ; copy when left & right clip masks overlap...
  3080.  
  3081. @cb_only_one_band:
  3082.          mov bx, [ebp].cb_x1                ; get left clip mask
  3083.          and bx, plane_bits                 ; mask out row #
  3084.          mov al, _left_clip_mask[ebx]       ; get left edge mask
  3085.          mov bx, [ebp].cb_x2                ; get right clip mask
  3086.          and bx, plane_bits                 ; mask out row #
  3087.          and al, _right_clip_mask[ebx]      ; get right edge mask byte
  3088.  
  3089.          out_8 sc_data, al                  ; clip for left & right masks
  3090.  
  3091.          mov cx, [ebp].cb_height            ; cx = # of lines to copy
  3092.          movzx edx, _screen_width           ; dx = width of screen
  3093.          clr ebx                            ; bx = offset into image
  3094.  
  3095. @cb_one_loop:
  3096.          mov al, [esi+ebx]                  ; load latches
  3097.          mov [edi+ebx], al                  ; unload latches
  3098.          add bx, dx                         ; advance offset to next line
  3099.          loopjz cx, @cb_one_done            ; exit loop if finished
  3100.  
  3101.          mov al, [esi+ebx]                  ; load latches
  3102.          mov [edi+ebx], al                  ; unload latches
  3103.          add bx, dx                         ; advance offset to next line
  3104.          loopx cx, @cb_one_loop             ; loop until finished
  3105.  
  3106. @cb_one_done:
  3107.          jmp @cb_finish                     ; outa here!
  3108.  
  3109. ; copy left edge of _bitmap
  3110.  
  3111. @cb_left_band:
  3112.  
  3113.          out_8 sc_data, _left_clip_mask[ebx] ; set left edge plane mask
  3114.  
  3115.          mov cx, [ebp].cb_height            ; cx = # of lines to copy
  3116.          mov dx, _screen_width              ; dx = width of screen
  3117.          clr ebx                            ; bx = offset into image
  3118.  
  3119. @cb_left_loop:
  3120.          mov al, [esi+ebx]                  ; load latches
  3121.          mov [edi+ebx], al                  ; unload latches
  3122.          add bx, dx                         ; advance offset to next line
  3123.          loopjz cx, @cb_left_done           ; exit loop if finished
  3124.  
  3125.          mov al, [esi+ebx]                  ; load latches
  3126.          mov [edi+ebx], al                  ; unload latches
  3127.          add bx, dx                         ; advance offset to next line
  3128.          loopx cx, @cb_left_loop            ; loop until finished
  3129.  
  3130. @cb_left_done:
  3131.          inc edi                            ; move dest over 1 band
  3132.          inc esi                            ; move source over 1 band
  3133.          dec [ebp].cb_width                 ; band width--
  3134.  
  3135. ; determine if right edge of _bitmap needs special copy
  3136.  
  3137. @cb_check_right:
  3138.          mov bx, [ebp].cb_x2                ; get source _x2
  3139.          and bx, plane_bits                 ; aligned? (bits 0-1 = 11?)
  3140.          cmp bl, 03h                        ; plane = 3?
  3141.          je @cb_copy_middle                 ; copy the middle then!
  3142.  
  3143. ; copy right edge of _bitmap
  3144.  
  3145. @cb_right_band:
  3146.  
  3147.          out_8 sc_data, _right_clip_mask[ebx] ; set right edge plane mask
  3148.  
  3149.          dec [ebp].cb_width                 ; band width--
  3150.          mov cx, [ebp].cb_height            ; cx = # of lines to copy
  3151.          mov dx, _screen_width              ; dx = width of screen
  3152.          movzx ebx, [ebp].cb_width          ; bx = offset to right edge
  3153.  
  3154. @cb_right_loop:
  3155.          mov al, [esi+ebx]                  ; load latches
  3156.          mov [edi+ebx], al                  ; unload latches
  3157.          add bx, dx                         ; advance offset to next line
  3158.          loopjz cx, @cb_right_done          ; exit loop if finished
  3159.  
  3160.          mov al, [esi+ebx]                  ; load latches
  3161.          mov [edi+ebx], al                  ; unload latches
  3162.          add bx, dx                         ; advance offset to next line
  3163.          loopx cx, @cb_right_loop           ; loop until finished
  3164.  
  3165. @cb_right_done:
  3166.  
  3167. ; copy the main block of the bitmap
  3168.  
  3169. @cb_copy_middle:
  3170.  
  3171.          mov cx, [ebp].cb_width             ; get width remaining
  3172.          jcxz @cb_finish                    ; exit if done
  3173.  
  3174.          out_8 sc_data, all_planes          ; copy all planes
  3175.  
  3176.          mov dx, _screen_width              ; get width of screen minus
  3177.          sub dx, cx                         ; image width (for adjustment)
  3178.          movzx edx, dx
  3179.          mov ax, [ebp].cb_height            ; ax = # of lines to copy
  3180.          movzx ecx,cx
  3181.          mov ebx, ecx                       ; bx = quick rep reload count
  3182.  
  3183. ; actual copy loop.  rep movsb does the work
  3184.  
  3185. @cb_middle_copy:
  3186.          mov ecx, ebx                       ; recharge rep count
  3187.          rep movsb                          ; move bands
  3188.          loopjz ax, @cb_finish              ; exit loop if finished
  3189.  
  3190.          add esi, edx                       ; adjust esi to next line
  3191.          add edi, edx                       ; adjust edi to next line
  3192.  
  3193.          mov ecx, ebx                       ; recharge rep count
  3194.          rep movsb                          ; move bands
  3195.  
  3196.          add esi, edx                       ; adjust esi to next line
  3197.          add edi, edx                       ; adjust edi to next line
  3198.          loopx ax, @cb_middle_copy          ; copy lines until done
  3199.  
  3200. @cb_finish:
  3201.          out_16 gc_index, latches_off       ; data from latches = on
  3202.  
  3203. @cb_exit:
  3204.          add esp, 4                         ; deallocate stack workspace
  3205.          pop edi esi ebp                    ; restore saved registers
  3206.          ret 16                             ; exit and clean up stack
  3207.  
  3208. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  3209. ; Return to mode 03 before exiting to dos
  3210. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  3211.  
  3212.          public _mode03
  3213.  
  3214. _mode03:
  3215.          mov v86r_ax,3h
  3216.          mov al,10h
  3217.          int 33h
  3218.          ret
  3219.  
  3220. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  3221. ; Wipe off palette (all black)
  3222. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  3223.  
  3224.          public _wipeoffpalette
  3225.  
  3226. _wipeoffpalette:
  3227.          mov ebx,eax
  3228.          xor al,al                          ; wipe palette, clear all to eax
  3229.          mov dx,3c8h
  3230.          out dx,al
  3231.          inc dx
  3232.          mov ecx,768/3
  3233.          mov esi,eax
  3234.          mov edi,eax
  3235.          shr esi,8
  3236.          shr edi,16
  3237.  
  3238. wipeit:
  3239.          mov eax,edi
  3240.          out dx,al
  3241.          mov eax,esi
  3242.          out dx,al
  3243.          mov eax,ebx
  3244.          out dx,al
  3245.          loop wipeit
  3246.  
  3247.          ret
  3248.  
  3249.          public _turn_screen_off
  3250.          public _turn_screen_on
  3251.  
  3252. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  3253. ; Turn screen off so palette doesn't cause flicker
  3254. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  3255.  
  3256. _turn_screen_off:                           ; guess what these do!
  3257.          mov dx,03dah                       ; these are used when changing video modes
  3258.          in al,dx                           ; to avoid any flicker
  3259.          mov dx,03c0h
  3260.          mov al,0
  3261.          out dx,al
  3262.          ret
  3263.  
  3264. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  3265. ; Turn screen back on so user can see nice fancy graphics stuff
  3266. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  3267.  
  3268. _turn_screen_on:
  3269.          mov dx,03dah
  3270.          in al,dx
  3271.          mov dx,03c0h
  3272.          mov al,20h
  3273.          out dx,al
  3274.          ret
  3275.  
  3276. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  3277. ; _Flip_page:
  3278. ; In:
  3279. ;    Regs=none
  3280. ; Out:
  3281. ;    Regs=none
  3282. ;
  3283. ; Notes:  This is used to:
  3284. ;  1) show the page we have been working on
  3285. ;  2) set _current_page to the other page (so we can work on it while the user
  3286. ;     looks at our first page)
  3287. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  3288.  
  3289.          public _flip_page
  3290.  
  3291. _flip_page:
  3292.          mov ax,_display_page
  3293.          xor al,1
  3294.          cmp ax,_last_page
  3295.          jae _sync_display                  ; if 1 page, do nothing except wait for vtrace
  3296.          push ax
  3297.          call _set_display_page
  3298.  
  3299.          movzx ebx,_active_page
  3300.          xor bl,1
  3301.          mov _active_page, bx               ; set active page #1 (for page flipping)
  3302.          shl ebx, 2                         ; scale page # to dword
  3303.          mov eax, _page_addr[ebx]           ; get offset to page
  3304.          mov _current_page, eax             ; and set for future mov's
  3305.          ret
  3306.  
  3307.          ends
  3308.          end
  3309.