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