home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1994 #1 / monster.zip / monster / PROG_PAS / XLIB_TP5.ZIP / UNITS / X_MAIN.PAS < prev    next >
Pascal/Delphi Source File  |  1994-01-22  |  66KB  |  1,949 lines

  1. {$G+}   (* Code for 286 or better *)
  2. unit X_Main;
  3.  
  4. (*
  5.     Global basic procedures.
  6.  
  7.     ****** XLIB - Mode X graphics library                ****************
  8.     ******                                               ****************
  9.     ****** Written By Themie Gouthas ( C-Version )       ****************
  10.     ****** Converted By Christian Harms in TP            ****************
  11.  
  12.     Gouthas : egg@dstos3.dsto.gov.au or teg@bart.dsto.gov.au
  13.     Harms   : harms@minnie.informatik.uni-stuttgart.de
  14.  
  15. *)
  16.  
  17. interface
  18.  
  19. uses X_Const;
  20.  
  21. (* Set Mode X - see Video-Modes in unit X_Const .                          *)
  22. procedure x_set_mode(mode,logicalscrwidth:Word);
  23.  
  24. (* return count of avaible modi                                            *)
  25. function  x_Max_Modi:Byte;
  26.  
  27. (* set X and Y to GetMaxX and GetMaxY in the mode Mode                     *)
  28. procedure x_Mode_Info(Mode:Byte;var X,Y:Word);
  29.  
  30. (* set TextMode back.                                                      *)
  31. procedure x_Text_Mode;
  32.  
  33. (* Set the write/read plane - only for intern functions.                   *)
  34. procedure x_select_default_plane(Plane:Byte);
  35.  
  36. (* Set upper, left Corner of activ page (page to draw)                     *)
  37. procedure x_set_activ_start_addr(x,y:Word);
  38. (* Set upper, left Corner of visible pager (page you can see)              *)
  39. procedure x_set_visible_start_addr(x,y:Word);
  40. (* Set Splitscreen   if line>=GetMaxY then no_splitScreen.                 *)
  41. procedure x_set_splitscreen(Line : Word);
  42. (* Set Clipping window for bitmaps.                                        *)
  43. procedure x_set_clip_rect(left,top,right,bottom:Word);
  44.  
  45. (* Clear the whole virtuell Screen.                                        *)
  46. procedure X_ClearAll;
  47. (* Clear  from Line1 to Line 2                                             *)
  48. procedure ClearScreen(Line1,Line2,Color:Word);
  49.  
  50. (* Look at TP-Help    Point cursor on name and press Ctrl+F1               *)
  51. procedure PutPixel(x,y:Word;Color:Byte);
  52. function  GetPixel(x,y: Word): Byte;
  53. procedure Line(x1,y1,x2,y2,Color:Word);
  54. procedure rectangle(x1,y1,x2,y2,Color:Word);       (* not filled *)
  55. procedure triangle(x1,y1,x2,y2,x3,y3,Color:Word);  (* not filled *)
  56. procedure LineTo(x,y,Color:Integer);
  57. procedure MoveTo(x,y:Integer);
  58.  
  59. procedure x_circle(x,y,r,Color:Word);
  60. procedure x_filled_circle(x,y,r,Color:Word);
  61.  
  62. implementation
  63.  
  64. uses My_Asm;
  65.  
  66. (* Mode X CRTC register tweaks for various resolutions *)
  67.  
  68. const X320Y200 : Array[0..4] of Word =
  69.     (      $0200, (* 0e3h    ; dot clock / Nº of CRTC Registers to update *)
  70.            $0014, (* turn off dword mode                             *)
  71.            $e317, (* turn on byte mode                               *)
  72.            320,   (* width                                           *)
  73.            200);  (* height                                          *)
  74.  
  75.       X320Y240 : Array[0..12] of Word =
  76.     (     $0ae3,  (* dot clock                                       *)
  77.           $0d06,(* vertical total                                    *)
  78.           $3e07,(* overflow (bit 8 of vertical counts)               *)
  79.           $4109,(* cell height (2 to double-scan)                    *)
  80.           $ea10,(* v sync start                                      *)
  81.           $ac11,(* v sync end and protect cr0-cr7                    *)
  82.           $df12,(* vertical displayed                                *)
  83.           $0014,(* turn off ord mode                                 *)
  84.           $e715,(* v blank start                                     *)
  85.           $0616,(* v blank end                                       *)
  86.           $e317,(* turn on byte mode                                 *)
  87.           320,   (* width                                            *)
  88.           240);  (* height                                           *)
  89.  
  90.       X360Y200 : Array[0..10] of Word =
  91.     (     $08e7,  (* dot clock                                       *)
  92.           $6b00,(* horz total                                        *)
  93.           $5901,(* horz displayed                                    *)
  94.           $5a02,(* start horz blanking                               *)
  95.           $8e03,(* end horz blanking                                 *)
  96.           $5e04,(* start  sync                                       *)
  97.           $8a05,(* end  sync                                         *)
  98.           $0014,(* turn off ord mode                                 *)
  99.           $e317,(* turn on byte mode                                 *)
  100.           360,   (* width                                            *)
  101.           200);  (* height                                           *)
  102.  
  103.       X360Y240 : Array[0..19] of Word =
  104.     (     $11e7,  (* dot clock                                       *)
  105.           $6b00,(* horz total                                        *)
  106.           $5901,(* horz displayed                                    *)
  107.           $5a02,(* start horz blanking                               *)
  108.           $8e03,(* end horz blanking                                 *)
  109.           $5e04,(* start  sync                                       *)
  110.           $8a05,(* end  sync                                         *)
  111.           $0d06,(* vertical total                                    *)
  112.           $3e07,(* overflow (bit 8 of vertical counts)               *)
  113.           $4109,(* cell height (2 to double-scan)                    *)
  114.           $ea10, (* v sync start                                     *)
  115.           $ac11, (* v sync end and protect cr0-cr7                   *)
  116.           $df12, (* vertical displayed                               *)
  117.           $2d13, (* offset;                                          *)
  118.           $0014, (* turn off ord mode                                *)
  119.           $e715, (* v blank start                                    *)
  120.           $0616, (* v blank end                                      *)
  121.           $e317, (* turn on byte mode                                *)
  122.           360,
  123.           240);
  124.  
  125.       X376Y282 : Array[0..20] of Word =
  126.     (     $12e7,
  127.           $6e00, (* horz total                                       *)
  128.           $5d01, (* horz displayed                                   *)
  129.           $5e02, (* start horz blanking                              *)
  130.           $9103, (* end horz blanking                                *)
  131.           $6204, (* start h sync                                     *)
  132.           $8f05, (* end h sync                                       *)
  133.           $6206, (* vertical total                                   *)
  134.           $f007, (* overflow                                         *)
  135.           $6109, (* cell height                                      *)
  136.           $310f, (*                                                  *)
  137.           $3710, (* v sync start                                     *)
  138.           $8911, (* v sync end and protect cr0-cr7                   *)
  139.           $3312, (* vertical displayed                               *)
  140.           $2f13, (* offset                                           *)
  141.           $0014, (* turn off ord mode                                *)
  142.           $3c15, (* v blank start                                    *)
  143.           $5c16, (* v blank end                                      *)
  144.           $e317, (* turn on byte mode                                *)
  145.           376,
  146.           282);
  147.  
  148.  
  149.       X320Y400 : Array[0..5] of Word =
  150.     (     $03e3,   (* dot clock                                      *)
  151.           $4009, (* cell height                                      *)
  152.           $0014, (* turn off ord mode                                *)
  153.           $e317, (* turn on byte mode                                *)
  154.           320,    (* width                                           *)
  155.           400);   (* height                                          *)
  156.  
  157.       X320Y480 : Array[0..12] of Word =
  158.     (     $0Ae3,   (* dotclock                                       *)
  159.           $0d06, (* vertical total                                   *)
  160.           $3e07, (* overflow (bit 8 of vertical counts)              *)
  161.           $4009, (* cell height (2 to double-scan)                   *)
  162.           $ea10, (* v sync start                                     *)
  163.           $ac11, (* v sync end and protect cr0-cr7                   *)
  164.           $df12, (* vertical displayed                               *)
  165.           $0014, (* turn off ord mode                                *)
  166.           $e715, (* v blank start                                    *)
  167.           $0616, (* v blank end                                      *)
  168.           $e317, (* turn on byte mode                                *)
  169.           320,    (* width                                           *)
  170.           480);   (* height                                          *)
  171.  
  172.       X360Y400 : Array[0..11] of Word =
  173.     (     $09e7,   (* dot clock                                      *)
  174.           $6b00, (* horz total                                       *)
  175.           $5901, (* horz displayed                                   *)
  176.           $5a02, (* start horz blanking                              *)
  177.           $8e03, (* end horz blanking                                *)
  178.           $5e04, (* start  sync                                      *)
  179.           $8a05, (* end  sync                                        *)
  180.           $4009, (* cell height                                      *)
  181.           $0014, (* turn off ord mode                                *)
  182.           $e317, (* turn on byte mode                                *)
  183.           360,    (* width                                           *)
  184.           400);   (* height                                          *)
  185.  
  186.  
  187.  
  188.       X360Y480 : Array[0..19] of Word =
  189.     (     $11e7,
  190.           $6b00, (* horz total                                       *)
  191.           $5901, (* horz displayed                                   *)
  192.           $5a02, (* start horz blanking                              *)
  193.           $8e03, (* end horz blanking                                *)
  194.           $5e04, (* start h sync                                     *)
  195.           $8a05, (* end h sync                                       *)
  196.           $0d06, (* vertical total                                   *)
  197.           $3e07, (* overflow                                         *)
  198.           $4009, (* cell height                                      *)
  199.           $ea10, (* v sync start                                     *)
  200.           $ac11, (* v sync end and protect cr0-cr7                   *)
  201.           $df12, (* vertical displayed                               *)
  202.           $2d13, (* offset                                           *)
  203.           $0014, (* turn off ord mode                                *)
  204.           $e715, (* v blank start                                    *)
  205.           $0616, (* v blank end                                      *)
  206.           $e317, (* turn on byte mode                                *)
  207.           360,
  208.           480);
  209.  
  210.       X360Y360 : Array[0..17] of Word =
  211.     (     $0fe7,
  212.           $6b00, (* horz total                                       *)
  213.           $5901, (* horz displayed                                   *)
  214.           $5a02, (* start horz blanking                              *)
  215.           $8e03, (* end horz blanking                                *)
  216.           $5e04, (* start h sync                                     *)
  217.           $8a05, (* end h sync                                       *)
  218.           $4009, (* cell height                                      *)
  219.           $8810, (* v sync start                                     *)
  220.           $8511, (* v sync end and protect cr0-cr7                   *)
  221.           $6712, (* vertical displayed                               *)
  222.           $2d13, (* offset                                           *)
  223.           $0014, (* turn off ord mode                                *)
  224.           $6d15, (* v blank start                                    *)
  225.           $ba16, (* v blank end                                      *)
  226.           $e317, (* turn on byte mode                                *)
  227.           360,
  228.           360);
  229.  
  230.      X376Y308 : Array[0..20] of Word =
  231.     (     $12e7,
  232.           $6e00, (* horz total                                       *)
  233.           $5d01, (* horz displayed                                   *)
  234.           $5e02, (* start horz blanking                              *)
  235.           $9103, (* end horz blanking                                *)
  236.           $6204, (* start h sync                                     *)
  237.           $8f05, (* end h sync                                       *)
  238.           $6206, (* vertical total                                   *)
  239.           $0f07, (* overflow                                         *)
  240.           $4009, (*                                                  *)
  241.           $310f, (*                                                  *)
  242.           $3710, (* v sync start                                     *)
  243.           $8911, (* v sync end and protect cr0-cr7                   *)
  244.           $3312, (* vertical displayed                               *)
  245.           $2f13, (* offset                                           *)
  246.           $0014, (* turn off ord mode                                *)
  247.           $3c15, (* v blank start                                    *)
  248.           $5c16, (* v blank end                                      *)
  249.           $e317, (* turn on byte mode                                *)
  250.           376,
  251.           308);
  252.  
  253.       X376Y564 : Array[0..20] of Word =
  254.     (     $12e7,
  255.           $6e00, (* horz total                                       *)
  256.           $5d01, (* horz displayed                                   *)
  257.           $5e02, (* start horz blanking                              *)
  258.           $9103, (* end horz blanking                                *)
  259.           $6204, (* start h sync                                     *)
  260.           $8f05, (* end h sync                                       *)
  261.           $6206, (* vertical total                                   *)
  262.           $f007, (* overflow                                         *)
  263.           $6009, (*                                                  *)
  264.           $310f, (*                                                  *)
  265.           $3710, (* v sync start                                     *)
  266.           $8911, (* v sync end and protect cr0-cr7                   *)
  267.           $3312, (* vertical displayed                               *)
  268.           $2f13, (* offset                                           *)
  269.           $0014, (* turn off ord mode                                *)
  270.           $3c15, (* v blank start                                    *)
  271.           $5c16, (* v blank end                                      *)
  272.           $e317, (* turn on byte mode                                *)
  273.           376,
  274.           564);
  275.  
  276.      X256Y200 : Array[0..10] of Word =
  277.        (      $08e3,    (* dot clock, Number of CRTC Registers to update  *)
  278.           $5f00,    (* horz total                                    *)
  279.           $3f01,    (* horz displayed                                *)
  280.           $4202,    (* start horz blanking                           *)
  281.           $9f03,    (* end horz blanking                             *)
  282.           $4c04,    (* start h sync                                  *)
  283.           $0005,    (* end h sync                                    *)
  284.           $0014,    (* turn off dword mode                           *)
  285.           $e317,    (* turn on byte mode                             *)
  286.           256,
  287.           200);
  288.  
  289.  
  290.      X256Y240 : Array[0..18] of Word =
  291.        (     $10e3,    (* dot clock, Number of CRTC Registers to update  *)
  292.          $5f00,    (* horz total                                     *)
  293.          $3f01,    (* horz displayed                                 *)
  294.          $4202,    (* start horz blanking                            *)
  295.          $9f03,    (* end horz blanking                              *)
  296.          $4c04,    (* start h sync                                   *)
  297.          $0005,    (* end h sync                                     *)
  298.          $0d06,    (* vertical total                                 *)
  299.          $3e07,    (* overflow (bit 8 of vertical counts)            *)
  300.          $4109,    (* cell height (2 to double-scan)                 *)
  301.          $ea10,    (* v sync start                                   *)
  302.          $ac11,    (* v sync end and protect cr0-cr7                 *)
  303.          $df12,    (* vertical displayed                             *)
  304.          $0014,    (* turn off dword mode                            *)
  305.          $e715,    (* v blank start                                  *)
  306.          $0616,    (* v blank end                                    *)
  307.          $e317,    (* turn on byte mode                              *)
  308.          256,
  309.          240);
  310.  
  311.  
  312.       LAST_X_MODE=13;
  313.       ModeTable : Array[0..Last_X_MODE] of Word =
  314.     (     ofs(X320Y200),
  315.           ofs(X320Y240),
  316.           ofs(X360Y200),
  317.           ofs(X360Y240),
  318.           ofs(X376Y282),
  319.           ofs(X320Y400),
  320.           ofs(X320Y480),
  321.           ofs(X360Y400),
  322.           ofs(X360Y480),
  323.           ofs(X360Y360),
  324.           ofs(X376Y308),
  325.           ofs(X376Y564),
  326.           ofs(X256Y200),
  327.           ofs(X256Y240) );
  328.  
  329.  
  330. (* Index/data pairs for CRT Controller registers that differ between *)
  331. (* mode 13h and mode X.                                              *)
  332.  
  333. (* Pelpan values for 0,1,2,3 pixel panning to the left, respectively *)
  334.       PelPanMask : Array[0..3] of Byte = (0,2,4,6);
  335.  
  336. var   DoubleScanFlag:Boolean;  (* Flag to indicate double scanned mode  *)
  337.  
  338. function X_Max_Modi:Byte;
  339. begin;
  340.   X_Max_Modi:=SizeOf(ModeTable) div 2-1;
  341. end;
  342.  
  343. procedure X_Mode_Info(Mode:Byte;var X,Y:Word);  assembler;
  344. asm;
  345.         xor   ax,ax
  346.         mov   al,Mode
  347.     mov   di,ax
  348.     shl   di,1
  349.     add   di,OFFSET ModeTable
  350.     mov   di,ds:[di]
  351.     inc   di
  352.     xor   ah,ah
  353.     mov   al,ds:[di]
  354.     dec   di
  355.     shl   ax,1
  356.     add   di,ax
  357.     mov   cx,ds:[di+2]        (* cx := X *)
  358.     mov   dx,ds:[di+4]        (* dx := Y *)
  359.     les   si,dword ptr [X]
  360.     mov   es:[si],cx
  361.     les   si,dword ptr [Y]
  362.     mov   es:[si],dx
  363. end;
  364.  
  365.  
  366.  
  367. (* ------------------------------------------------------------------------ *)
  368. (* Local Logical Screen Width setting function                              *)
  369. (* cx = Requitrd Logical Width                                              *)
  370. (*                                                                          *)
  371. (* WARNING: no registers are preserved                                      *)
  372.  
  373. procedure SetLogicalScrWidth;  assembler;
  374. asm
  375.     mov   dx,CRTC_INDEX
  376.     mov   al,CRTC_OFFSET
  377.     out   dx,al
  378.     inc   dx
  379.  
  380.     mov   ax,cx
  381.     cmp   ax,ScrnPhysicalPixelWidth(* Is logical width >= physical width *)
  382.     jge   @@ValidLogicalWidth      (* yes - continue                    *)
  383.     mov   ax,bx                    (* no - set logical width = physical *)
  384.  
  385. @@ValidLogicalWidth:
  386.     shr   ax,3
  387.     out   dx,al
  388.  
  389.     (* The EXACT logical pixel width may not have been possible since   *)
  390.     (* it should be divisible by 8. Round down to the closest possible  *)
  391.     (* width and update the status variables                            *)
  392.  
  393.     shl   ax,1
  394.     mov   bx,ax
  395.     mov   ScrnLogicalByteWidth,ax  (* Store the byte width of virtual   *)
  396.     mov   RightClip,ax             (* Set default Right clip column     *)
  397.                        (* screen                            *)
  398.     sub   ax,ScrnPhysicalByteWidth (* Calculate and store Max X position*)
  399.     shl   ax,2                     (* of physical screen in virtual     *)
  400.     mov   MaxScrollX,ax            (* screen in pixels                  *)
  401.     mov   ax,bx                    (* set ax to byte width of virt scrn *)
  402.     shl   ax,2                     (* convert to pixels                 *)
  403.     mov   ScrnLogicalPixelWidth,ax (* store virt scrn pixel width       *)
  404.     mov   cx,ax                    (* save ax (return value)            *)
  405.  
  406.     (* calculate no. non split screen rows in video ram                 *)
  407.  
  408.     mov   ax,$ffff                 (* cx = Maximum video ram offset     *)
  409.     sub   dx,dx                    (* DX:AX is divide operand,  set DX = 0 *)
  410.     div   bx                       (* divide ax by ScrnLogicalByteWidth *)
  411.     mov   ScrnLogicalHeight,ax     (* Save Screen Logical Height        *)
  412.     mov   BottomClip,ax            (* Set default bottom clip row       *)
  413.     sub   ax,ScrnPhysicalHeight    (* Update the maximum Y position of  *)
  414.     mov   MaxScrollY,ax            (* Physical screen in logical screen *)
  415.     mov   ax,cx                    (* restore ax (return value)         *)
  416.  
  417.     (* calculate initial NonVisual                                      *)
  418.     mov  ax,ScrnLogicalByteWidth
  419.     mul  ScrnPhysicalHeight
  420.     mov  NonVisual_Offs,ax
  421.  
  422. @@Done:
  423. end;
  424.  
  425.  
  426. (* -----------------------------------------------------------------------  *)
  427. (* Mode X graphics mode set with a virtual screen                           *)
  428. (*   logical screen width.                                                  *)
  429. (*                                                                          *)
  430. (* returns the actual width of the allocated virtual screen in pixels       *)
  431. (* if a valid mode was selected otherwise returns -1                        *)
  432. (*                                                                          *)
  433. (* Saves virtual screen pixel width in ScrnLogicalPixelWidth.               *)
  434. (* Saves virtual screen byte  width in ScrnLogicalByteWidth.                *)
  435. (* Physical screen dimensions are set in ScrnPhysicalPixelWidth,            *)
  436. (* ScrnPhysicalByteWidth and ScrnPhysicalHeight                             *)
  437. (*                                                                          *)
  438. (*                                                                          *)
  439. (* Modes:  0  = 320 x 200  (256 color)  NOTE: Some of these modes require   *)
  440. (*         1  = 320 x 240  (256 color)     vertical size adjustment.        *)
  441. (*         2  = 360 x 200  (256 color)                                      *)
  442. (*         3  = 360 x 240  (256 color)                                      *)
  443. (*         4  = 376 x 282  (256 color)                                      *)
  444. (*         5  = 320 x 400  (256 color)                                      *)
  445. (*         6  = 320 x 480  (256 color)                                      *)
  446. (*         7  = 360 x 400  (256 color)                                      *)
  447. (*         8  = 360 x 480  (256 color)                                      *)
  448. (*         9  = 360 x 360  (256 color)                                      *)
  449. (*         10 = 376 x 308  (256 color)                                      *)
  450. (*         11 = 376 x 564  (256 color)                                      *)
  451. (*                                                                          *)
  452. (* Written by Themie Gouthas,                                               *)
  453. (* parts adapted from M. Abrash code.                                       *)
  454. (* ------------------------------------------------------------------------ *)
  455. procedure x_set_mode(mode,logicalscrwidth:Word); assembler;
  456. asm
  457.     mov InGraphics,0
  458.     mov ErrorValue,0
  459.     mov DoubleScanFlag,0
  460.     mov CurrXMode,0
  461.     mov ScrnPhysicalByteWidth,0
  462.     mov ScrnPhysicalPixelWidth,0
  463.     mov ScrnPhysicalHeight,0
  464.     mov SplitScrnOffs,0
  465.     mov SplitScrnScanLine,0
  466.     mov SplitScrnVisibleHeight,0
  467.     mov SplitScrnActive,0
  468.     mov Page0_Offs,0
  469.     mov Page1_Offs,0
  470.     mov Page2_Offs,0
  471.     mov ScrnLogicalByteWidth,0
  472.     mov ScrnLogicalPixelWidth,0
  473.     mov ScrnLogicalHeight,0
  474.     mov MaxScrollX,0
  475.     mov MaxScrollY,0
  476.     mov DoubleBufferActive,0
  477.     mov VisiblePageIdx,0
  478.     mov HiddenPageOffs,0
  479.     mov VisiblePageOffs,0
  480.     mov NonVisual_Offs,0
  481.     mov TopClip,0
  482.     mov BottomClip,0
  483.     mov LeftClip,0
  484.     mov RightClip,0
  485.     mov PhysicalStartPixelX,0
  486.     mov PhysicalStartByteX,0
  487.     mov PhysicalStartY,0
  488.         mov Active_StartX,0
  489.         mov Active_StartY,0
  490.  
  491.     cld
  492.  
  493.         mov   ax,ds
  494.         mov   es,ax
  495.     mov   cx,mode
  496.     cmp   cx,LAST_X_MODE        (*  have we selected a valid mode       *)
  497.     jle   @@ValidMode           (*  Yes !                               *)
  498.  
  499.     mov   InGraphics,FALSE   (*  No return -1                           *)
  500.     mov   ax,-1
  501.     jmp  @Ende
  502.  
  503. @@ValidMode:
  504.  
  505.     mov   CurrXMode,cx
  506.     mov   InGraphics,TRUE
  507.  
  508.     xor   al,al
  509.     cmp   cx,3
  510.     jg    @@SetDoubleScanFlag
  511.     mov   al,TRUE
  512. @@SetDoubleScanFlag:
  513.     mov   DoubleScanFlag,al
  514.  
  515.     push  cx                    (*  some bios's dont preserve cx        *)
  516.     mov   ax,13h                (*  let the BIOS set standard 256-color *)
  517.     int   10h                   (*   mode (320x200 linear)              *)
  518.     pop   cx
  519.  
  520.     mov   dx,SC_INDEX
  521.     mov   ax,0604h
  522.     out   dx,ax                 (*  disable chain4 mode                 *)
  523.     mov   ax,0100h
  524.     out   dx,ax                 (*  synchronous reset while setting Misc*)
  525.                     (*   Output for safety, even though clock*)
  526.                     (*   unchanged                          *)
  527.  
  528.     mov   bx,offset ModeTable
  529.     shl   cx,1
  530.     add   bx,cx
  531.     mov   si, word ptr [bx]
  532.     lodsb
  533.  
  534.     or    al,al
  535.     jz    @@DontSetDot
  536.     mov   dx,MISC_OUTPUT
  537.     out   dx,al               (*  select the dot clock and Horiz        *)
  538.                   (*   scanning rate                        *)
  539. @@DontSetDot:
  540.     mov   dx,SC_INDEX
  541.     mov   ax,0300h
  542.     out   dx,ax                (*  undo reset (restart sequencer)       *)
  543.  
  544.  
  545.     mov   dx,CRTC_INDEX       (*  reprogram the CRT Controller          *)
  546.     mov   al,11h              (*  VSync End reg contains register write *)
  547.     out   dx,al               (*  protect bit                           *)
  548.     inc   dx                  (*  CRT Controller Data register          *)
  549.     in    al,dx               (*  get current VSync End register setting*)
  550.     and   al,$7f              (*  remove write protect on various       *)
  551.     out   dx,al               (*  CRTC registers                        *)
  552.     dec   dx                  (*  CRT Controller Index                  *)
  553.     cld
  554.     xor   cx,cx
  555.     lodsb
  556.     mov   cl,al
  557.  
  558. @@SetCRTParmsLoop:
  559.     lodsw                     (*  get the next CRT Index/Data pair      *)
  560.     out   dx,ax               (*  set the next CRT Index/Data pair      *)
  561.     loop  @@SetCRTParmsLoop
  562.  
  563.     mov   dx,SC_INDEX
  564.     mov   ax,0f02h
  565.     out   dx,ax               (*  enable writes to all four planes      *)
  566.     mov   ax,SCREEN_SEG       (*  now clear all display memory, 8 pixels*)
  567.     mov   es,ax               (*  at a time                             *)
  568.     sub   di,di               (*  point ES:DI to display memory         *)
  569.     sub   ax,ax               (*  clear to zero-value pixels            *)
  570.     mov   cx,$8000            (*  # of words in display memory          *)
  571.     rep   stosw               (*  clear all of display memory           *)
  572.  
  573.     (* Fix for single line         *)
  574.  
  575.     (* mov   dx,CRTC_INDEX       *)
  576.     (* mov   al,MAX_SCAN_LINE    *)
  577.     (* out   dx,al               *)
  578.     (* inc   dx                  *)
  579.     (* mov   al,0C0h             *)
  580.     (* out   dx,al               *)
  581.  
  582.     (*   Set pysical screen dimensions                                 *)
  583.  
  584.     lodsw                            (*  Load scrn pixel width         *)
  585.     mov   ScrnPhysicalPixelWidth,ax  (*   from tweak table and store   *)
  586.     mov   SplitScrnScanLine,ax       (*  No splitscrn ==               *)
  587.                      (*  splitscrn=PhysicalscrnHeight  *)
  588.     mov   bx,ax                      (*  Copy width for later use      *)
  589.     shr   ax,2                       (*  Convert to byte width         *)
  590.     mov   ScrnPhysicalByteWidth,ax   (*  Store for later use           *)
  591.     lodsw                            (*  Load Screen Phys. Height      *)
  592.     mov   ScrnPhysicalHeight,ax      (*  Store for later use           *)
  593.  
  594.  
  595.     (*   Mode X is set, now set the required logical page width.       *)
  596.  
  597.     mov     cx,logicalscrwidth
  598.  
  599.     call    SetLogicalScrWidth
  600.  
  601.     mov   ax,GetMaxY
  602.     mov   SplitScrnScanLine,ax
  603.     xor   ax,ax
  604.     mov   cx,ScrnLogicalByteWidth
  605.     mov   es,ax
  606.     mov   bx,$44a
  607.     mov   es:[bx],cx            (* Update Bios-ScreenWidth *)
  608.  
  609.     mov   cx,logicalscrwidth
  610.     mov   dx,Crtc_Index
  611.     mov   al,CRTC_OFFSET
  612.     out   dx,al
  613.     inc   dx
  614.     mov   ax,cx
  615.     cmp   ax,ScrnPhysicalPixelWidth
  616.     jge   @@ValidLogicalWidth
  617.     mov   ax,bx
  618.  
  619. @@ValidLogicalWidth:
  620.     shr   ax,3
  621.     out   dx,al
  622.     shl   ax,1
  623.     mov   bx,ax
  624.     mov   ScrnLogicalByteWidth,ax
  625.     mov   RightClip,ax
  626.     sub   ax,ScrnPhysicalByteWidth
  627.     shl   ax,2
  628.     mov   MaxScrollX,ax
  629.     mov   ax,bx
  630.     shl   ax,2
  631.     mov   ScrnLogicalPixelWidth,ax
  632.     mov   cx,ax
  633.     mov   ax,0ffffh
  634.     sub   dx,dx
  635.     div   bx
  636.     mov   ScrnLogicalHeight,ax
  637.     mov   BottomClip,ax
  638.     sub   ax,ScrnPhysicalHeight
  639.     mov   MaxScrollY,ax
  640.     mov   ax,cx
  641.     mov   ax,ScrnLogicalByteWidth
  642.     mul   ScrnPhysicalHeight
  643.     mov   NonVisual_Offs,ax
  644.  
  645. @@Done:
  646.  
  647. @ende:  (*   Call to unchain to save Mode-X in TP *)
  648. {    mov   ax,$CB00
  649.     int   $10       }
  650. end;
  651.  
  652. procedure X_Text_Mode;assembler;
  653. asm;
  654.   mov ax,03
  655.   int $10;
  656. end;
  657.  
  658. (*----------------------------------------------------------------------  *)
  659. (* Mode X (256 color mode) set default access video plane                 *)
  660. (*                                                                        *)
  661. (*    x_select_default_plane(plane:Byte);                                 *)
  662. (*                                                                        *)
  663. (* Enables Read/Write access to a plane using general memory access       *)
  664. (* methods                                                                *)
  665. (*                                                                        *)
  666. (* Written by Themie Gouthas                                              *)
  667. (*----------------------------------------------------------------------  *)
  668. procedure x_select_default_plane(Plane:Byte); assembler;
  669. asm
  670.     mov  cl,byte ptr [Plane]
  671.  
  672.     (* SELECT WRITE PLANE *)
  673.     and  cl,011b              (* CL = plane                           *)
  674.     mov  ax,0100h + MAP_MASK  (* AL = index in SC of Map Mask reg     *)
  675.     shl  ah,cl                (* set only the bit for the required    *)
  676.                   (*  plane to 1                          *)
  677.     mov  dx,SC_INDEX          (* set the Map Mask to enable only the  *)
  678.     out  dx,ax                (*  pixel's plane                       *)
  679.  
  680.     (* SELECT READ PLANE  *)
  681.     mov  ah,cl                (* AH = plane                           *)
  682.     mov  al,READ_MAP          (* AL = index in GC of the Read Map reg *)
  683.     mov  dx,GC_INDEX          (* set the Read Map to read the pixel's *)
  684.     out  dx,ax                (*  plane                               *)
  685.  
  686. end;
  687.  
  688.  
  689.  
  690.  
  691. {
  692. (* ----------------------------------------------------------------------
  693. (*  Mode X (256 color mode) Set Mode X split screen starting row
  694. (*  The split screen resides on the bottom half of the screen and has a
  695. (*  starting address of A000:0000
  696. (*
  697. (*  C near-callable as:
  698. (*     void x_set_splitscreen(unsigned int line)(*
  699. (*
  700. (*  Updates _Page0_Offs to reflect the existence of the split screen region
  701. (*  ie _MainScrnOffset is set to the offset of the first pixel beyond the split
  702. (*  screen region
  703. (*
  704. (*  Written by Themie Gouthas
  705. (* ----------------------------------------------------------------------
  706. }
  707.  
  708. procedure x_set_splitscreen(Line : Word);
  709. VAR CRTC: Word ABSOLUTE $0000:$0463;
  710. BEGIN
  711.   if DoubleScanFlag then Inc(Line,Line);
  712.   Port[CRTC] := $18;              (* Index für Line Compare Reg. *)
  713.   Port[CRTC+1] := Lo(line);   (* Lowbyte laden *)
  714.   Port[CRTC] := $07;              (* Index für Overflow Reg. *)
  715.   IF (Line AND $100) > 0 THEN
  716.     (* Line Compare-Bit 8 = 1, also Overflow-Bit 4 setzen: *)
  717.     Port[CRTC+1] := Port[CRTC+1] OR $10
  718.   ELSE
  719.     (* Line Compare-Bit 8 = 0, also Overflow-Bit 4 zurücksetzen: *)
  720.     Port[CRTC+1] := Port[CRTC+1] AND NOT $10;
  721.   Port[CRTC] := $09;               (* Index für Max. Scanline Reg. *)
  722.   IF (Line AND $200) > 0 THEN
  723.     (* Line Compare-Bit 9 = 1, Max. Scanline-Bit 6 setzen: *)
  724.     Port[CRTC+1] := Port[CRTC+1] OR $40
  725.   ELSE
  726.     (* Line Compare-Bit 9 = 0, Max. Scanline-Bit 6 zurücksetzen: *)
  727.     Port[CRTC+1] := Port[CRTC+1] AND NOT $40;
  728.   SplitScrnOffs:=0;
  729.   SplitScrnScanLine:=Line;
  730.   SplitScrnVisibleHeight:=GetMaxY-Line;
  731. END;
  732.  
  733.  
  734.  
  735. (* -----------------------------------------------------------------------  *)
  736. (*  Mode X (256 color mode) Set Mode X non split screen start address       *)
  737. (*    of logical screen.                                                    *)
  738. (*  C near-callable as:                                                     *)
  739. (*                                                                          *)
  740. (*     void x_set_start_addr(unsigned int x, unsigned int y)(*              *)
  741. (*                                                                          *)
  742. (*  Params: StartOffset is offset of first byte of logical screen ram       *)
  743. (*            (Useful if you want to double buffer by splitting your non    *)
  744. (*             split screen video ram into 2 pages)                         *)
  745. (*         X,Y coordinates of the top left hand corner of the physical screen *)
  746. (*            within the logical screen                                     *)
  747. (*            X must not exceed (Logical screen width - Physical screen width)*)
  748. (*            Y must not exceed (Logical screen height - Physical screen height)*)
  749. (*                                                                          *)
  750. (*                                                                          *)
  751. (*  Written by Themie Gouthas,                                              *)
  752. (*  Parts addapted from M. Abrash code published in DDJ Mag.                *)
  753. (* ------------------------------------------------------------------------ *)
  754. procedure x_set_activ_start_addr(x,y:Word);
  755. begin;
  756.   if x>ScrnLogicalPixelWidth-ScrnPhysicalPixelWidth then
  757.           x:=(ScrnLogicalPixelWidth-ScrnPhysicalPixelWidth) and $FFF8;
  758.   if y>ScrnLogicalHeight-ScrnPhysicalHeight then
  759.           y:=ScrnLogicalHeight-ScrnPhysicalHeight;
  760.   ScreenOfs:=y*ScrnLogicalByteWidth+x div 4;
  761.  
  762. end;
  763.  
  764. procedure x_set_visible_start_addr(x,y:Word);   assembler;
  765. asm
  766.     mov  si,x
  767.     mov  ax,ScrnLogicalByteWidth     (*  Calculate Offset increment     *)
  768.     mov  cx,y                        (*  for Y                          *)
  769.     mul  cx
  770.     cmp  DoubleBufferActive,TRUE     (*  Do we have double buffering ?  *)
  771.     je   @@PageResolution
  772. @PageFlipEntry1:
  773.     add  ax,Page0_Offs               (*  no - add page 0 offset         *)
  774.     jmp  @@AddColumn
  775.  
  776. @PageFlipEntry2:
  777.  
  778.     mov  PhysicalStartPixelX,si
  779.     mov  PhysicalStartY,cx
  780.  
  781. @@PageResolution:
  782.     add  ax,VisiblePageOffs          (*  Add visible page offset        *)
  783.  
  784. @@AddColumn:
  785.     mov  cx,si
  786.     shr  cx,2
  787.     mov  PhysicalStartByteX,cx
  788.     add  ax,cx                       (*  add the column offset for X    *)
  789.     mov  bh,al                       (*  setup CRTC start addr regs and *)
  790.                      (*  values in word registers for   *)
  791.     mov  ch,ah                       (*  fast word outs                 *)
  792.  
  793. @StartAddrEntry:
  794.     mov  bl,ADDR_LOW
  795.     mov  cl,ADDR_HIGH
  796.     and  si,0003h             (*  select pel pan register value for the *)
  797.     mov  ah,[offset PelPanMask+si]    (*  required x coordinate                 *)
  798.     mov  al,PEL_PANNING+20h
  799.     mov  si,ax
  800.  
  801.     mov  dx,INPUT_STATUS_0    (* Wait for trailing edge of Vsync pulse  *)
  802. @@WaitDE:
  803.     in   al,dx
  804.     test al,01h
  805.     jnz  @@WaitDE            (* display enable is active low (0 = active)*)
  806.  
  807.     mov  dx,CRTC_INDEX
  808.     mov  ax,bx
  809.     out  dx,ax               (* start address low                       *)
  810.     mov  ax,cx
  811.     out  dx,ax               (* start address high                      *)
  812.  
  813.     mov  dx,AC_INDEX
  814.     mov  ax,si                (*  Point the attribute controller to pel pan*)
  815.     out  dx,al                (*  reg. Bit 5 also set to prevent blanking  *)
  816.     mov  al,ah
  817.     out  dx,al                (*  load new Pel Pan setting.             *)
  818.  
  819.  
  820. (*  Now wait for vertical sync, so the other page will be invisible when    *)
  821. (*  we start drawing to it.                                                 *)
  822.     mov  dx,INPUT_STATUS_0    (* Wait for trailing edge of Vsync pulse  *)
  823. @@WaitVS:
  824.     in   al,dx
  825.     test al,08h
  826.     jz @@WaitVS           (* display enable is active low (0 = active)  *)
  827.  
  828.     mov  ErrorValue,OK
  829. end;
  830.  
  831.  
  832. (* -----------------------------------------------------------------------*)
  833. (*  Set Clipping rectangle                                                *)
  834. (*  C callable as:                                                        *)
  835. (*                                                                        *)
  836. (*                                                                        *)
  837. (*     int x_set_clip_rect(WORD left,WORD top, WORD right, WORD bottom);  *)
  838. (*                                                                        *)
  839. (*                                                                        *)
  840. (*  NOTE clipping is byte oriented. "left" and "right" are in bytes not pixels. *)
  841. (*     Only selected functions perform any clipping at all.               *)
  842. (*                                                                        *)
  843. (*  Written by Themie Gouthas                                             *)
  844. (* -----------------------------------------------------------------------*)
  845.  
  846. procedure x_set_clip_rect(left,top,right,bottom:Word); assembler;
  847. asm
  848.        mov   cl,2
  849.        mov   ax,[left]
  850.        mov   bx,[right]
  851.        cmp   bx,ax
  852.        jns   @@CorrectXOrder
  853.        xchg  bx,ax
  854. @@CorrectXOrder:
  855.        shr   ax,cl
  856.        shr   bx,cl
  857.        mov   [LeftClip],ax
  858.        mov   [RightClip],bx
  859.        mov   ax,[top]
  860.        mov   bx,[bottom]
  861.        cmp   bx,ax
  862.        jns   @@CorrectYOrder
  863.        xchg  bx,ax
  864. @@CorrectYOrder:
  865.        mov   [TopClip],ax
  866.        mov   [BottomClip],bx
  867. end;
  868.  
  869.  
  870.  
  871. procedure X_ClearAll; assembler;
  872. asm;
  873.        mov  ax,0F00h + MAP_MASK  (* AL = index in SC of Map Mask reg     *)
  874.        mov  dx,SC_INDEX          (* set the Map Mask to enable all       *)
  875.        out  dx,ax                (*  pixel's planes                      *)
  876.  
  877.        mov  ax,SCREEN_SEG
  878.        mov  es,ax
  879.        xor  ax,ax
  880.        mov  di,ax
  881.        mov  cx,$FFFF
  882.        rep  stosb
  883. end;
  884.  
  885. procedure ClearScreen(Line1,Line2,Color:Word); assembler;
  886. asm;
  887.        mov  ax,0F00h + MAP_MASK  (* AL = index in SC of Map Mask reg     *)
  888.        mov  dx,SC_INDEX          (* set the Map Mask to enable all       *)
  889.        out  dx,ax                (*  pixel's planes                      *)
  890.  
  891.        mov  ax,SCREEN_SEG
  892.        mov  es,ax
  893.        mov  ax,Line1
  894.        mov  bx,ScrnLogicalByteWidth
  895.        mul  bx
  896.        mov  di,ax
  897.        mov  ax,Line2
  898.        sub  ax,Line1
  899.        mov  bx,ScrnLogicalByteWidth
  900.        mul  bx
  901.        mov  cx,ax
  902.        mov  ax,Color
  903.        rep  stosb
  904. end;
  905.  
  906. (* --------------------------------------------------------------------- *)
  907. (*  Mode X (256 color mode) write pixel routine.                         *)
  908. (*                                                                       *)
  909. (*  Based on code originally published in DDJ Mag by M. Abrash           *)
  910. (*                                                                       *)
  911. {$F+}
  912. procedure PutPixel (x,y:Word;Color:Byte);  assembler;
  913. asm;
  914.     mov  ax,X_Const.ScrnLogicalByteWidth
  915.     mul  Y                    (* offset of pixel's scan line in page *)
  916.     mov  bx,X
  917.     shr  bx,2                 (* X/4 = offset of pixel in scan line  *)
  918.     add  bx,ax                (* offset of pixel in page             *)
  919.     add  bx,X_Const.ScreenOfs (* offset of pixel in display memory   *)
  920.     mov  ax,SCREEN_SEG
  921.     mov  es,ax                (* point ES:BX to the pixel's address  *)
  922.  
  923.     mov  cl,byte ptr [X]
  924.     and  cl,011b              (* CL = pixel's plane                  *)
  925.     mov  ax,$100 + MAP_MASK   (* AL = index in SC of Map Mask reg    *)
  926.     shl  ah,cl                (* set only the bit for the pixel's    *)
  927.                   (*  plane to 1                         *)
  928.     mov  dx,SC_INDEX          (* set the Map Mask to enable only the *)
  929.     out  dx,ax                (*  pixel's plane                      *)
  930.  
  931.     mov  al,byte ptr [Color]
  932.     mov  es:[bx],al           (* draw the pixel in the desired color *)
  933. end;
  934. (* --------------------------------------------------------------------- *)
  935. (*  Mode X read pixel routine.                                           *)
  936. (*                                                                       *)
  937. (*  Based on code originally published in DDJ Mag by M. Abrash           *)
  938. (*                                                                       *)
  939.  
  940. function GetPixel(x,y:Word):Byte;   assembler;
  941. asm;
  942.     mov  ax,X_Const.ScrnLogicalByteWidth
  943.     mul  [Y]                  (* offset of pixel's scan line in page *)
  944.     mov  bx,[X]
  945.     shr  bx,2                 (* X/4 = offset of pixel in scan line  *)
  946.     add  bx,ax                (* offset of pixel in page             *)
  947.     add  bx,X_Const.ScreenOfs (* offset of pixel in display memory   *)
  948.     mov  ax,SCREEN_SEG
  949.     mov  es,ax                (* point ES:BX to the pixel's address  *)
  950.  
  951.     mov  ah,byte ptr [X]
  952.     and  ah,011b              (* AH = pixel's plane                  *)
  953.     mov  al,READ_MAP          (* AL = index in GC of the Read Map reg *)
  954.     mov  dx,GC_INDEX          (* set the Read Map to read the pixel's *)
  955.     out  dx,ax                (*  plane                              *)
  956.  
  957.     mov  al,es:[bx]           (* read the pixel's color              *)
  958.     sub  ah,ah                (* convert it to an unsigned int       *)
  959. end;
  960. {$F-}
  961.  
  962.  
  963. (* --------------------------------------------------------------------- *)
  964. (* Line drawing function for all MODE X 256 Color resolutions.            *)
  965. (* Based on code from "PC and PS/2 Video Systems" by Richard Wilton.     *)
  966. (*                                                                       *)
  967.  
  968. procedure Line(x1,y1,x2,y2,Color:Word); assembler;
  969.  
  970. var vertincr,incr1,incr2,routine:word;
  971. label HiSlopeLine,LoSlopeLine;
  972. asm;
  973.     mov     ax,0a000h
  974.     mov     es,ax
  975.  
  976.     mov     dx,3c4h         (* setup for plane mask access *)
  977.  
  978. (*  check for vertical line *)
  979.  
  980.     mov     si,X_Const.ScrnLogicalByteWidth
  981.     mov     cx,x2
  982.     sub     cx,x1
  983.     jz      @VertLine
  984.  
  985. (* force x1 < x2 *)
  986.  
  987.     jns     @L01
  988.  
  989.     neg     cx
  990.  
  991.     mov     bx,x2
  992.     xchg    bx,x1
  993.     mov     x2,bx
  994.  
  995.     mov     bx,y2
  996.     xchg    bx,y1
  997.     mov     y2,bx
  998.  
  999. (* calc dy = abs(y2 - y1) *)
  1000.  
  1001. @L01:
  1002.     mov     bx,y2
  1003.     sub     bx,y1
  1004.     jnz     @skip
  1005.     jmp     @HorizLine
  1006. @skip:  jns     @L03
  1007.  
  1008.     neg     bx
  1009.     neg     si
  1010.  
  1011. (* select appropriate routine for slope of line *)
  1012.  
  1013. @L03:
  1014.     mov     vertincr,si
  1015.     mov     routine,offset LoSlopeLine
  1016.     cmp     bx,cx
  1017.     jle     @L04
  1018.     mov     routine,offset HiSlopeLine
  1019.     xchg    bx,cx
  1020.  
  1021. (* calc initial decision variable and increments *)
  1022.  
  1023. @L04:
  1024.     shl     bx,1
  1025.     mov     incr1,bx
  1026.     sub     bx,cx
  1027.     mov     si,bx
  1028.     sub     bx,cx
  1029.     mov     incr2,bx
  1030.  
  1031. (* calc first pixel address *)
  1032.  
  1033.     push    cx
  1034.     mov     ax,y1
  1035.     mov     bx,x1
  1036.  
  1037.     mov     cl,bl          (* ModeXAddr *)
  1038.     push    dx
  1039.     mov     dx,ScrnLogicalByteWidth
  1040.     mul     dx
  1041.     pop     dx
  1042.     shr     bx,2
  1043.     add     bx,ax
  1044.     add     bx,ScreenOfs
  1045.     and     cl,3
  1046.  
  1047.     mov     di,bx
  1048.     mov     al,1
  1049.     shl     al,cl
  1050.     mov     ah,al           (* duplicate nybble *)
  1051.     shl     al,4
  1052.     add     ah,al
  1053.     mov     bl,ah
  1054.     pop     cx
  1055.     inc     cx
  1056.     jmp     routine
  1057.  
  1058. (* routine for verticle lines *)
  1059.  
  1060. @VertLine:
  1061.     mov     ax,y1
  1062.     mov     bx,y2
  1063.     mov     cx,bx
  1064.     sub     cx,ax
  1065.     jge     @L31
  1066.     neg     cx
  1067.     mov     ax,bx
  1068.  
  1069. @L31:
  1070.     inc     cx
  1071.     mov     bx,x1
  1072.     push    cx
  1073.  
  1074.     mov     cl,bl          (* ModeXAddr *)
  1075.     push    dx
  1076.     mov     dx,ScrnLogicalByteWidth
  1077.     mul     dx
  1078.     pop     dx
  1079.     shr     bx,2
  1080.     add     bx,ax
  1081.     add     bx,ScreenOfs
  1082.     and     cl,3
  1083.  
  1084.  
  1085.     mov     ah,1
  1086.     shl     ah,cl
  1087.     mov     al,02
  1088.     out     dx,ax
  1089.     pop     cx
  1090.     mov     ax, word ptr [Color]
  1091.  
  1092. (* draw the line *)
  1093.  
  1094. @L32:
  1095.     mov     es:[bx],al
  1096.     add     bx,si
  1097.     loop    @L32
  1098.     jmp     @Lexit
  1099.  
  1100. (* routine for horizontal line *)
  1101.  
  1102. @HorizLine:
  1103.     push    ds
  1104.  
  1105.     mov     ax,y1
  1106.     mov     bx,x1
  1107.  
  1108.     mov     cl,bl          (* ModeXAddr *)
  1109.     push    dx
  1110.     mov     dx,ScrnLogicalByteWidth
  1111.     mul     dx
  1112.     pop     dx
  1113.     shr     bx,2
  1114.     add     bx,ax
  1115.     add     bx,ScreenOfs
  1116.     and     cl,3
  1117.  
  1118.     mov     di,bx     (* set dl = first byte mask *)
  1119.     mov     dl,00fh
  1120.     shl     dl,cl
  1121.  
  1122.     mov     cx,x2   (* set dh = last byte mask *)
  1123.     and     cl,3
  1124.     mov     dh,00eh
  1125.     shl     dh,cl
  1126.     not     dh
  1127.  
  1128. (* determine byte offset of first and last pixel in line *)
  1129.  
  1130.     mov     ax,x2
  1131.     mov     bx,x1
  1132.  
  1133.     shr     ax,2     (* set ax = last byte column   *)
  1134.     shr     bx,2     (* set bx = first byte column  *)
  1135.     mov     cx,ax    (* cx = ax - bx                *)
  1136.     sub     cx,bx
  1137.  
  1138.     mov     ax,dx    (* mov end byte masks to ax    *)
  1139.     mov     dx,3c4h  (* setup dx for VGA outs       *)
  1140.     mov     bx, Color
  1141.  
  1142. (* set pixels in leftmost byte of line *)
  1143.  
  1144.     or      cx,cx      (* is start and end pt in same byte *)
  1145.     jnz     @L42       (* no !                             *)
  1146.     and     ah,al      (* combine start and end masks      *)
  1147.     jmp     @L44
  1148.  
  1149. @L42:   push    ax
  1150.     mov     ah,al
  1151.     mov     al,02
  1152.     out     dx,ax
  1153.     mov     al,bl
  1154.     stosb
  1155.     dec     cx
  1156.  
  1157. (* draw remainder of the line *)
  1158.  
  1159. @L43:
  1160.     mov     ah,0Fh
  1161.     mov     al,02
  1162.     out     dx,ax
  1163.     mov     al,bl
  1164.     rep     stosb
  1165.     pop     ax
  1166.  
  1167. (* set pixels in rightmost byte of line *)
  1168.  
  1169. @L44:
  1170.     mov     al,02
  1171.     out     dx, ax
  1172.     mov     byte ptr es:[di],bl
  1173.     pop     ds
  1174.     jmp     @Lexit
  1175.  
  1176.  
  1177. (* routine for dy >= dx (slope <= 1) *)
  1178.  
  1179. LoSlopeLine:
  1180.     mov     al,02
  1181.     mov     bh,byte ptr [Color]
  1182. @L10:
  1183.     mov     ah,bl
  1184.  
  1185. @L11:
  1186.     or      ah,bl
  1187.     rol     bl,1
  1188.     jc      @L14
  1189.  
  1190. (* bit mask not shifted out *)
  1191.  
  1192.     or      si,si
  1193.     jns     @L12
  1194.     add     si,incr1
  1195.     loop    @L11
  1196.  
  1197.     out     dx,ax
  1198.     mov     es:[di],bh
  1199.     jmp     @Lexit
  1200.  
  1201. @L12:
  1202.     add     si,incr2
  1203.     out     dx,ax
  1204.     mov     es:[di],bh
  1205.     add     di,vertincr
  1206.     loop    @L10
  1207.     jmp     @Lexit
  1208.  
  1209. (* bit mask shifted out *)
  1210.  
  1211. @L14:   out     dx,ax
  1212.     mov     es:[di],bh
  1213.     inc     di
  1214.     or      si,si
  1215.     jns     @L15
  1216.     add     si,incr1
  1217.     loop    @L10
  1218.     jmp     @Lexit
  1219.  
  1220. @L15:
  1221.     add     si,incr2
  1222.     add     di,vertincr
  1223.     loop    @L10
  1224.     jmp     @Lexit
  1225.  
  1226. (* routine for dy > dx (slope > 1) *)
  1227.  
  1228. HiSlopeLine:
  1229.     mov     bx,vertincr
  1230.     mov     al,02
  1231. @L21:   out     dx,ax
  1232.     push    ax
  1233.     mov     ax,Color
  1234.     mov     es:[di],al
  1235.     pop     ax
  1236.     add     di,bx
  1237.  
  1238. @L22:
  1239.     or      si,si
  1240.     jns     @L23
  1241.  
  1242.     add     si,incr1
  1243.     loop    @L21
  1244.     jmp     @Lexit
  1245.  
  1246. @L23:
  1247.     add     si,incr2
  1248.     rol     ah,1
  1249.     adc     di,0
  1250. @lx21:  loop    @L21
  1251.  
  1252. (* return to caller *)
  1253.  
  1254. @Lexit:
  1255. end;
  1256.  
  1257. procedure rectangle(x1,y1,x2,y2,Color:Word);
  1258. begin;
  1259.   Line(x1,y1,x2,y1,Color);
  1260.   Line(x1,y1,x1,y2,Color);
  1261.   Line(x1,y2,x2,y2,Color);
  1262.   Line(x2,y1,x2,y2,Color);
  1263. end;
  1264.  
  1265. procedure triangle(x1,y1,x2,y2,x3,y3,Color:Word);
  1266. begin;
  1267.   Line(x1,y1,x2,y2,Color);
  1268.   Line(x2,y2,x3,y2,Color);
  1269.   Line(x3,y3,x1,y1,Color);
  1270. end;
  1271.  
  1272. var my_X,my_Y:Integer;
  1273.  
  1274. procedure MoveTo(x,y:Integer);   (* doc in graph.tpu *)
  1275. begin;
  1276.   my_X:=X;
  1277.   my_Y:=Y;
  1278. end;
  1279.  
  1280. procedure LineTo(x,y,Color:Integer);   (* doc in graph.tpu *)
  1281. begin;
  1282.   Line(my_X,My_Y,x,y,Color);
  1283.   my_X:=X;
  1284.   my_Y:=Y;
  1285. end;
  1286.  
  1287.  
  1288. (* Draw a circle.                                                         *)
  1289. (*                                                                        *)
  1290. (* C near-callable as:                                                    *)
  1291. (* int x_circle (WORD Left, WORD Top, WORD Diameter,                      *)
  1292. (*                WORD Color, WORD ScreenOffs)(*                          *)
  1293. (*                                                                        *)
  1294. (* No clipping is performed.                                              *)
  1295. (*                                                                        *)
  1296. (* ax, bx, cx, and dx bite the dust, as Homer would say.                  *)
  1297.  
  1298. (* we plot into eight arcs at once:                                       *)
  1299. (*      4 0                                                               *)
  1300. (*    6 \|/ 2                                                             *)
  1301. (*     --*--                                                              *)
  1302. (*    7 /|\ 3                                                             *)
  1303. (*      5 1                                                               *)
  1304. (*                                                                        *)
  1305. (* 0, 1, 4, and 5 are considered x-major(* the rest, y-major.             *)
  1306. (*                                                                        *)
  1307. (* The x-major plots grow out from the top and bottom of the circle,      *)
  1308. (* while the y-major plots start at the left and right edges.             *)
  1309.  
  1310.  
  1311. const   ColumnMask:Array[0..3] of Byte = ($11,$22,$44,$88);
  1312.  
  1313. procedure x_circle(x,y,r,Color:Word); assembler;
  1314. var offset0,offset1,offset2,offset3,offset4,offset5,offset6,offset7,
  1315.     mask0n1,mask2n3,mask4n5,mask6n7,shrunk_radius,diameter_even,error:word;
  1316.     left,top,Diameter:Word;
  1317. asm
  1318.     push ds
  1319. (* convert x,y,r in left,top,Diameter *)
  1320.     mov bx,r
  1321.     mov ax,x
  1322.     sub ax,bx
  1323.     mov left,ax
  1324.     mov ax,y
  1325.     sub ax,bx
  1326.     mov top,ax
  1327.     shl bx,1
  1328.     mov Diameter,bx
  1329.  
  1330. (* find starting locations of plots 2, 3, 6, and 7                        *)
  1331.     mov di, ScrnLogicalByteWidth
  1332.     xor dx, dx
  1333.  
  1334.     mov ax, Diameter      (* find vertical midpoint          *)
  1335.     dec ax
  1336.     shr ax, 1
  1337.     adc dx, 0             (* remember if it's rounded        *)
  1338.     mov shrunk_radius, ax (* radius, rounded down for adding *)
  1339.     mov diameter_even, dx (* (diameter - 1) & 1, effectively *)
  1340.     add ax, Top
  1341.     mul di                (* vertical midpoint in bytes      *)
  1342.     add ax, ScreenOfs
  1343.  
  1344.     mov bx, Left
  1345.     mov cx, bx            (* save for later      *)
  1346.     mov si, bx
  1347.     shr si, 2
  1348.     add si, ax
  1349.     mov offset6, si
  1350.     and bx, 3             (* column of left side *)
  1351.     mov bl, ds:[offset ColumnMask+bx]
  1352.     mov mask6n7, bx
  1353.  
  1354.     add cx, Diameter
  1355.     dec cx
  1356.     mov bx, cx
  1357.     shr cx, 2
  1358.     add cx, ax
  1359.     mov offset2, cx
  1360.     and bx, 3             (* column of right side*)
  1361.     mov bl, ds:[offset ColumnMask+bx]
  1362.     mov mask2n3, bx
  1363.  
  1364.     cmp diameter_even, 1
  1365.     jne @@MiddlePlotsOverlap
  1366.     add si, di
  1367.     add cx, di
  1368. @@MiddlePlotsOverlap:
  1369.     mov offset7, si
  1370.     mov offset3, cx
  1371.  
  1372. (* starting locations of 0, 1, 4, and 5              *)
  1373.     mov bx, Left
  1374.     add bx, shrunk_radius (* find horizontal midpoint *)
  1375.  
  1376.     mov ax, Top           (* top in bytes        *)
  1377.     mul di
  1378.     add ax, ScreenOfs
  1379.     mov si, ax
  1380.  
  1381.     mov ax, Diameter      (* bottom in bytes     *)
  1382.     dec ax
  1383.     mul di
  1384.     add ax, si
  1385.  
  1386.     mov di, bx          (* horizontal midpoint in bytes *)
  1387.     shr di, 2
  1388.     add si, di              (* top midpoint in bytes    *)
  1389.     mov offset4, si
  1390.     add di, ax              (* bottom midpoint in bytes *)
  1391.     mov offset5, di
  1392.     and bx, 3           (* column of horizontal midpoint*)
  1393.     mov bl, ds:[offset ColumnMask+bx]
  1394.     mov mask4n5, bx
  1395.  
  1396.     cmp diameter_even, 1
  1397.     jne @@TopAndBottomPlotsOverlap
  1398.     rol bl, 1
  1399.     jnc @@TopAndBottomPlotsOverlap
  1400.     inc si
  1401.     inc di
  1402. @@TopAndBottomPlotsOverlap:
  1403.     mov offset0, si
  1404.     mov offset1, di
  1405.     mov mask0n1, bx
  1406.  
  1407. (* we've got our eight plots in their starting positions, so              *)
  1408. (* it's time to sort out the registers                                    *)
  1409.     mov bx, ScrnLogicalByteWidth
  1410.  
  1411.     mov dx, SCREEN_SEG
  1412.     mov ds, dx
  1413.  
  1414.     mov dx, SC_INDEX    (* set VGA to accept column masks *)
  1415.     mov al, MAP_MASK
  1416.     out dx, al
  1417.     inc dx              (* gun the engine...              *)
  1418.  
  1419.     mov si, Diameter    (* initial y is radius -- 2 #s per pixel *)
  1420.     inc si
  1421.  
  1422.     mov cx, si
  1423.     neg cx
  1424.     add cx, 2
  1425.     mov error, cx       (* error = -y + one pixel since we're a step ahead *)
  1426.  
  1427.     xor cx, cx          (* initial x = 0                              *)
  1428.     mov ah, byte ptr Color
  1429.     jmp @@CircleCalc        (* let's actually put something on the screen! *)
  1430.  
  1431. (* move the x-major plots horizontally and the y-major plots vertically   *)
  1432. @@NoAdvance:
  1433.     mov al, byte ptr mask0n1
  1434.     out dx, al
  1435.     mov di, offset0     (* plot 0                    *)
  1436.     mov [di], ah
  1437.     rol al, 1           (* advance 0 right           *)
  1438.     mov byte ptr mask0n1, al
  1439.     adc di, 0
  1440.     mov offset0, di
  1441.     mov di, offset1
  1442.     mov [di], ah        (* plot 1                    *)
  1443.     ror al, 1           (* what was that bit again?  *)
  1444.     adc di, 0           (* advance 1 right           *)
  1445.     mov offset1, di
  1446.  
  1447.     mov al, byte ptr mask2n3
  1448.     out dx, al
  1449.     mov di, offset2
  1450.     mov [di], ah        (* plot 2                    *)
  1451.     sub di, bx          (* advance 2 up              *)
  1452.     mov offset2, di
  1453.     mov di, offset3
  1454.     mov [di], ah        (* plot 3                    *)
  1455.     add di, bx          (* advance 3 down            *)
  1456.     mov offset3, di
  1457.  
  1458.     mov al, byte ptr mask4n5
  1459.     out dx, al
  1460.     mov di, offset4
  1461.     mov [di], ah
  1462.     ror al, 1
  1463.     mov byte ptr mask4n5, al
  1464.     sbb di, 0
  1465.     mov offset4, di
  1466.     mov di, offset5
  1467.     mov [di], ah
  1468.     rol al, 1
  1469.     sbb di, 0
  1470.     mov offset5, di
  1471.  
  1472.     mov al, byte ptr mask6n7
  1473.     out dx, al
  1474.     mov di, offset6
  1475.     mov [di], ah
  1476.     sub di, bx
  1477.     mov offset6, di
  1478.     mov di, offset7
  1479.     mov [di], ah
  1480.     add di, bx
  1481.     mov offset7, di
  1482.  
  1483.     jmp @@CircleCalc
  1484.  
  1485. (* move all plots diagonally *)
  1486. @@Advance:
  1487.     mov al, byte ptr mask0n1
  1488.     out dx, al
  1489.     mov di, offset0
  1490.     mov [di], ah        (* plot 0                    *)
  1491.     rol al, 1           (* advance 0 right and down  *)
  1492.     mov byte ptr mask0n1, al
  1493.     adc di, bx
  1494.     mov offset0, di
  1495.     mov di, offset1
  1496.     mov [di], ah        (* plot 1                    *)
  1497.     ror al, 1           (* what was that bit again?  *)
  1498.     adc di, 0           (* advance 1 right and up    *)
  1499.     sub di, bx
  1500.     mov offset1, di
  1501.  
  1502.     mov al, byte ptr mask2n3
  1503.     out dx, al
  1504.     mov di, offset2
  1505.     mov [di], ah        (* plot 2                    *)
  1506.     ror al, 1           (* advance 2 up and left     *)
  1507.     mov byte ptr mask2n3, al
  1508.     sbb di, bx
  1509.     mov offset2, di
  1510.     mov di, offset3
  1511.     mov [di], ah        (* plot 3                    *)
  1512.     rol al, 1
  1513.     sbb di, 0           (* advance 3 down and left   *)
  1514.     add di, bx
  1515.     mov offset3, di
  1516.  
  1517.     mov al, byte ptr mask4n5
  1518.     out dx, al
  1519.     mov di, offset4
  1520.     mov [di], ah
  1521.     ror al, 1
  1522.     mov byte ptr mask4n5, al
  1523.     sbb di, 0
  1524.     add di, bx
  1525.     mov offset4, di
  1526.     mov di, offset5
  1527.     mov [di], ah
  1528.     rol al, 1
  1529.     sbb di, bx
  1530.     mov offset5, di
  1531.  
  1532.     mov al, byte ptr mask6n7
  1533.     out dx, al
  1534.     mov di, offset6
  1535.     mov [di], ah
  1536.     rol al, 1
  1537.     mov byte ptr mask6n7, al
  1538.     adc di, 0
  1539.     sub di, bx
  1540.     mov offset6, di
  1541.     mov di, offset7
  1542.     mov [di], ah
  1543.     ror al, 1
  1544.     adc di, bx
  1545.     mov offset7, di
  1546.  
  1547. (* do you realize the entire function has been set up for this little jot? *)
  1548. (* keep in mind that radii values are 2 per pixel                          *)
  1549. @@CircleCalc:
  1550.     add cx, 2           (* x += 1                 *)
  1551.     mov di, error
  1552.     add di, cx          (* error += (2 * x) + 1   *)
  1553.     inc di
  1554.     jl @@CircleNoError
  1555.     cmp cx, si          (* x > y?                 *)
  1556.     ja @@FleeFlyFlowFum
  1557.     sub si, 2           (* y -= 1                 *)
  1558.     sub di, si          (* error -= (2 * y)       *)
  1559.     mov error, di
  1560.     jmp @@Advance
  1561. @@CircleNoError:
  1562.     mov error, di
  1563.     jmp @@NoAdvance
  1564.  
  1565. @@FleeFlyFlowFum:
  1566.     pop ds
  1567.  
  1568. end;
  1569.  
  1570.  
  1571. (*                                                                         *)
  1572. (* x_filled_circle                                                         *)
  1573. (*                                                                         *)
  1574. (* Draw a disc.                                                            *)
  1575. (*                                                                         *)
  1576. (* C near-callable as:                                                     *)
  1577. (* int x_filled_circle (WORD Left, WORD Top, WORD Diameter,                *)
  1578. (*                      WORD Color, WORD ScreenOffs);                      *)
  1579. (*                                                                         *)
  1580. (* No clipping is performed.                                               *)
  1581. (*                                                                         *)
  1582. (* ax, bx, cx, dx, and es bite the dust, as Homer would say.               *)
  1583. (* DF is set to 0 (strings go forward).                                    *)
  1584.  
  1585.  
  1586. (* the only entries of these tables which are used are positions           *)
  1587. (* 1, 2, 4, and 8                                                          *)
  1588. const LeftMaskTable :Array[0..8] of Byte=(0, $ff, $ee, 0, $cc, 0, 0, 0, $88);
  1589.       RightMaskTable:Array[0..8] of Byte=(0, $11, $33, 0, $77, 0, 0, 0, $ff);
  1590.  
  1591. procedure x_filled_circle(x,y,r,Color:Word); assembler;
  1592. var offset0,offset1,offset2,offset3,offset4,offset5,offset6,offset7,
  1593.     mask0n1,mask2n3,mask4n5,mask6n7,shrunk_radius,diameter_even,error,
  1594.     jump_vector:Word;
  1595.     left,top,Diameter:Word;
  1596.  
  1597. asm
  1598.     cld                                     (* strings march forward  *)
  1599. (* convert x,y,r in left,top,Diameter *)
  1600.     mov bx,r
  1601.     mov ax,x
  1602.     sub ax,bx
  1603.     mov left,ax
  1604.     mov ax,y
  1605.     sub ax,bx
  1606.     mov top,ax
  1607.     shl bx,1
  1608.     mov Diameter,bx
  1609.  
  1610.  
  1611. (* this first part is identical to the other function --                  *)
  1612. (* the only differences, in fact, are in the drawing and moving around    *)
  1613.  
  1614. (* find starting locations of plots 2, 3, 6, and 7                        *)
  1615.     mov di, ScrnLogicalByteWidth
  1616.     xor dx, dx
  1617.  
  1618.     mov ax, Diameter    (* find vertical midpoint            *)
  1619.     dec ax
  1620.     shr ax, 1
  1621.     adc dx, 0           (* remember if it's rounded          *)
  1622.     mov shrunk_radius, ax (* radius, rounded down for adding *)
  1623.     mov diameter_even, dx (* (diameter - 1) & 1, effectively *)
  1624.     add ax, Top
  1625.     mul di              (* vertical midpoint in bytes        *)
  1626.     add ax, ScreenOfs
  1627.  
  1628.     mov bx, Left
  1629.     mov cx, bx          (* save for later       *)
  1630.     mov si, bx
  1631.     shr si, 2
  1632.     add si, ax
  1633.     mov offset6, si
  1634.     and bx, 3           (* column of left side  *)
  1635.     mov bl, ds:[offset ColumnMask+bx]
  1636.     mov mask6n7, bx
  1637.  
  1638.     add cx, Diameter
  1639.     dec cx
  1640.     mov bx, cx
  1641.     shr cx, 2
  1642.     add cx, ax
  1643.     mov offset2, cx
  1644.     and bx, 3           (* column of right side *)
  1645.     mov bl, ds:[offset ColumnMask+bx]
  1646.     mov mask2n3, bx
  1647.  
  1648.     cmp diameter_even, 1
  1649.     jne @@MiddlePlotsOverlap
  1650.     add si, di
  1651.     add cx, di
  1652. @@MiddlePlotsOverlap:
  1653.     mov offset7, si
  1654.     mov offset3, cx
  1655.  
  1656. (* starting locations of 0, 1, 4, and 5                       *)
  1657.     mov bx, Left
  1658.     add bx, shrunk_radius (* find horizontal midpoint   *)
  1659.  
  1660.     mov ax, Top         (* top in bytes                 *)
  1661.     mul di
  1662.     add ax, ScreenOfs
  1663.     mov si, ax
  1664.  
  1665.     mov ax, Diameter    (* bottom in bytes              *)
  1666.     dec ax
  1667.     mul di
  1668.     add ax, si
  1669.  
  1670.     mov di, bx          (* horizontal midpoint in bytes  *)
  1671.     shr di, 2
  1672.     add si, di              (* top midpoint in bytes     *)
  1673.     mov offset4, si
  1674.     add di, ax              (* bottom midpoint in bytes  *)
  1675.     mov offset5, di
  1676.     and bx, 3           (* column of horizontal midpoint *)
  1677.     mov bl, ds:[offset ColumnMask+bx]
  1678.     mov mask4n5, bx
  1679.  
  1680.     cmp diameter_even, 1
  1681.     jne @@TopAndBottomPlotsOverlap
  1682.     rol bl, 1
  1683.     jnc @@TopAndBottomPlotsOverlap
  1684.     inc si
  1685.     inc di
  1686. @@TopAndBottomPlotsOverlap:
  1687.     mov offset0, si
  1688.     mov offset1, di
  1689.     mov mask0n1, bx
  1690.  
  1691. (* we've got our eight plots in their starting positions, so       *)
  1692. (* it's time to sort out the registers                             *)
  1693.     mov bx, ScrnLogicalByteWidth
  1694.  
  1695.     mov dx, SCREEN_SEG
  1696.     mov es, dx
  1697.  
  1698.     mov dx, SC_INDEX    (* set VGA to accept column masks        *)
  1699.     mov al, MAP_MASK
  1700.     out dx, al
  1701.     inc dx              (* gun the engine...                     *)
  1702.  
  1703.     mov si, Diameter    (* initial y is radius -- 2 #s per pixel *)
  1704.     inc si
  1705.  
  1706.     mov cx, si
  1707.     neg cx
  1708.     add cx, 2
  1709.     mov error, cx       (* error = -y + one pixel since we're a step ahead *)
  1710.  
  1711.     xor cx, cx          (* initial x = 0                         *)
  1712.     mov ah, byte ptr Color
  1713.     jmp @@FilledCircleCalc (* let's actually put something on the screen! *)
  1714.  
  1715.  
  1716. (* plotting is completely different from in the other function (naturally) *)
  1717. @@PlotLines:
  1718.     push cx                         (* we'll need cx for string stores
  1719.  
  1720. (* draw x-major horz. lines, from plot 4 to plot 0 and from plot 5 to plot 1 *)
  1721.     mov di, mask0n1
  1722.     and di, 0000fh          (* we only want the lower nybble for the mask table *)
  1723.     mov al, ds:[offset RightMaskTable+di]
  1724.     mov di, offset0         (* left and right offsets the same?       *)
  1725.     cmp di, offset4
  1726.     jne @@PlotXMajorNontrivial (* try and say this one 10 times fast! *)
  1727.     mov di, mask4n5
  1728.     and di, 0000fh
  1729.     and al, ds:[offset LeftMaskTable+di] (* intersection of left & right masks *)
  1730.     out dx, al                      (* set mask *)
  1731.     mov di, offset4
  1732.     mov es:[di], ah
  1733.     mov di, offset5
  1734.     mov es:[di], ah
  1735.     jmp @@PlotYMajor
  1736. @@PlotXMajorNontrivial:
  1737.     out dx, al          (* draw right edge      *)
  1738.     mov es:[di], ah
  1739.     mov di, offset1
  1740.     mov es:[di], ah
  1741.  
  1742.     mov di, mask4n5         (* draw left edge   *)
  1743.     and di, $000f
  1744.     mov al, ds:[offset LeftMaskTable+di]
  1745.     out dx, al
  1746.     mov di, offset4
  1747.     mov es:[di], ah
  1748.     mov di, offset5
  1749.     mov es:[di], ah
  1750.  
  1751.     mov al, 0ffh            (* set mask for middle chunks *)
  1752.     out dx, al
  1753.     mov al, ah                      (* ready to store two pixels at a time *)
  1754.     inc di                          (* move string start past left edge    *)
  1755.     mov cx, offset1         (* store line from plot 5 to plot 1, exclusive *)
  1756.     sub cx, di                      (* width of section in bytes           *)
  1757.     push cx
  1758.     shr cx, 1                       (* draw midsection eight pixels at a time *)
  1759.     rep stosw
  1760.     adc cx, 0                       (* draw last four pixels, if such there are *)
  1761.     rep stosb
  1762.  
  1763.     mov di, offset4         (* draw line from plot 4 to plot 0 *)
  1764.     inc di                          (* move past left edge     *)
  1765.     pop cx
  1766.     shr cx, 1
  1767.     rep stosw
  1768.     adc cx, 0
  1769.     rep stosb
  1770.  
  1771. @@PlotYMajor:
  1772. (* draw y-major horz. lines, from plot 6 to plot 2 and from plot 7 to plot 3 *)
  1773.     mov di, mask2n3
  1774.     and di, 0000fh          (* we only want the lower nybble for the mask table *)
  1775.     mov al, ds:[offset RightMaskTable+di]
  1776.     mov di, offset2         (* left and right offsets the same?         *)
  1777.     cmp di, offset6
  1778.     jne @@PlotYMajorNontrivial (* try and say this one 10 times fast!   *)
  1779.     mov di, mask6n7
  1780.     and di, $000f
  1781.     and al, ds:[offset LeftMaskTable+di] (* intersection of left & right masks *)
  1782.     out dx, al                      (* set mask *)
  1783.     mov di, offset6
  1784.     mov es:[di], ah
  1785.     mov di, offset7
  1786.     mov es:[di], ah
  1787.     jmp @@ClimaxOfPlot
  1788. @@PlotYMajorNontrivial:
  1789.     out dx, al          (* draw right edge      *)
  1790.     mov es:[di], ah
  1791.     mov di, offset3
  1792.     mov es:[di], ah
  1793.  
  1794.     mov di, mask6n7         (* draw left edge   *)
  1795.     and di, $000f
  1796.     mov al, ds:[offset LeftMaskTable+di]
  1797.     out dx, al
  1798.     mov di, offset6
  1799.     mov es:[di], ah
  1800.     mov di, offset7
  1801.     mov es:[di], ah
  1802.  
  1803.     mov al, $ff             (* set mask for middle chunks  *)
  1804.     out dx, al
  1805.     mov al, ah                      (* ready to store two pixels at a time *)
  1806.  
  1807.     inc di                          (* move string start past left edge *)
  1808.     mov cx, offset3         (* draw line from plot 7 to plot 3, exclusive *)
  1809.     sub cx, di                      (* width of section in bytes        *)
  1810.     push cx
  1811.     shr cx, 1                       (* store midsection                 *)
  1812.     rep stosw
  1813.     adc cx, 0
  1814.     rep stosb
  1815.  
  1816.     mov di, offset6         (* draw line from plot 6 to plot 2 *)
  1817.     inc di                          (* move past left edge     *)
  1818.     pop cx
  1819.     shr cx, 1
  1820.     rep stosw
  1821.     adc cx, 0
  1822.     rep stosb
  1823.  
  1824. @@ClimaxOfPlot:
  1825.     pop cx
  1826.     jmp [jump_vector]       (* either @@Advance or @@NoAdvance *)
  1827.  
  1828.  
  1829. (* unlike their counterparts in the other function, these do not draw -- *)
  1830. (* they only move the eight pointers                                     *)
  1831.  
  1832. (* move the x-major plots horizontally and the y-major plots vertically  *)
  1833. @@NoAdvance:
  1834.     mov al, byte ptr mask0n1 (* advance left x-major plots           *)
  1835.     mov di, offset0
  1836.     rol al, 1           (* advance 0 right                           *)
  1837.     mov byte ptr mask0n1, al
  1838.     adc di, 0
  1839.     mov offset0, di
  1840.     mov di, offset1
  1841.     ror al, 1           (* what was that bit again?                  *)
  1842.     adc di, 0           (* advance 1 right                           *)
  1843.     mov offset1, di
  1844.  
  1845.     mov al, byte ptr mask4n5 (* advance left x-major plots           *)
  1846.     mov di, offset4
  1847.     ror al, 1
  1848.     mov byte ptr mask4n5, al
  1849.     sbb di, 0
  1850.     mov offset4, di
  1851.     mov di, offset5
  1852.     rol al, 1
  1853.     sbb di, 0
  1854.     mov offset5, di
  1855.  
  1856.     mov al, byte ptr mask2n3
  1857.     mov di, offset2
  1858.     sub di, bx          (* advance 2 up   *)
  1859.     mov offset2, di
  1860.     mov di, offset3
  1861.     add di, bx          (* advance 3 down *)
  1862.     mov offset3, di
  1863.  
  1864.     mov al, byte ptr mask6n7
  1865.     mov di, offset6
  1866.     sub di, bx
  1867.     mov offset6, di
  1868.     mov di, offset7
  1869.     add di, bx
  1870.     mov offset7, di
  1871.  
  1872.     jmp @@FilledCircleCalc
  1873.  
  1874. (* move all plots diagonally                                 *)
  1875. @@Advance:
  1876.     mov al, byte ptr mask0n1
  1877.     mov di, offset0
  1878.     rol al, 1           (* advance 0 right and down *)
  1879.     mov byte ptr mask0n1, al
  1880.     adc di, bx
  1881.     mov offset0, di
  1882.     mov di, offset1
  1883.     ror al, 1           (* what was that bit again? *)
  1884.     adc di, 0           (* advance 1 right and up   *)
  1885.     sub di, bx
  1886.     mov offset1, di
  1887.  
  1888.     mov al, byte ptr mask2n3
  1889.     mov di, offset2
  1890.     ror al, 1           (* advance 2 up and left    *)
  1891.     mov byte ptr mask2n3, al
  1892.     sbb di, bx
  1893.     mov offset2, di
  1894.     mov di, offset3
  1895.     rol al, 1
  1896.     sbb di, 0           (* advance 3 down and left  *)
  1897.     add di, bx
  1898.     mov offset3, di
  1899.  
  1900.     mov al, byte ptr mask4n5
  1901.     mov di, offset4
  1902.     ror al, 1
  1903.     mov byte ptr mask4n5, al
  1904.     sbb di, 0
  1905.     add di, bx
  1906.     mov offset4, di
  1907.     mov di, offset5
  1908.     rol al, 1
  1909.     sbb di, bx
  1910.     mov offset5, di
  1911.  
  1912.     mov al, byte ptr mask6n7
  1913.     mov di, offset6
  1914.     rol al, 1
  1915.     mov byte ptr mask6n7, al
  1916.     adc di, 0
  1917.     sub di, bx
  1918.     mov offset6, di
  1919.     mov di, offset7
  1920.     ror al, 1
  1921.     adc di, bx
  1922.     mov offset7, di
  1923.  
  1924. (* do you realize the entire function has been set up around this little jot? *)
  1925. (* keep in mind that radii values are 2 per pixel                           *)
  1926. @@FilledCircleCalc:
  1927.     add cx, 2           (* x += 1                 *)
  1928.     mov di, error
  1929.     add di, cx          (* error += (2 * x) + 1   *)
  1930.     inc di
  1931.     jl @@FilledCircleNoError
  1932.     cmp cx, si          (* x > y?                 *)
  1933.     ja @@FleeFlyFlowFum
  1934.     sub si, 2           (* y -= 1                 *)
  1935.     sub di, si          (* error -= (2 * y)       *)
  1936.     mov error, di
  1937.     mov jump_vector, offset @@Advance
  1938.     jmp @@PlotLines
  1939. @@FilledCircleNoError:
  1940.     mov error, di
  1941.     mov jump_vector, offset @@NoAdvance
  1942.     jmp @@PlotLines
  1943.  
  1944. @@FleeFlyFlowFum:
  1945.  
  1946. end;
  1947.  
  1948. end.
  1949.