home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / GRAPHICS / PLOT / SURFUTI3.ZIP / GX2DE.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1988-02-10  |  24.1 KB  |  830 lines

  1. {$U-$V-}   {disable CNTRL C, disable strict string length type checking}
  2.  
  3.             { Basic Graphics Package.     Version 2.0  07 Nov 87}
  4.  
  5. const
  6.   GxC80       = $03;            {colour 80-column text mode}
  7.   GxEga       = $10;            {colour EGA mode}
  8.   GxVga       = $12;            {colour VGA mode - PS/2 systems only}
  9.   GxMaxRow    = 349;            {row addresses are 0-349, (0-479 for PS/2}
  10.   GxMaxCol    = 639;            {col addresses are 0-639}
  11.   GxIndent    =  78;            {to give square default viewport}
  12.   GxIndexRng  =  15;            {colour index range; 0 is index of background}
  13.   GxColourRng =  63;            {colour palette range}
  14.   GxSet       =   0;            {write in overwrite (set) mode}
  15.   GxXor       =   1;            {write using xor mode}
  16.   BELL        =  ^G;
  17.   EgaBase     = $A000;          {base address of EGA board}
  18.  
  19. var
  20.   GxBeamX, GxBeamY: real;              {current beam position - world coords}
  21.   GxPage:       integer;
  22.   GxPalette:    array [0..GxIndexRng] of integer;
  23.   GxBackground: integer;               {background index for all palettes}
  24.   GxIndex:      integer;               {current colour index}
  25.   GxText:       integer;               {current colour for text}
  26.   GxTextBack:   integer;               {current background colour for text}
  27.   GxBorderIndex:integer;               {current border index}
  28.   GxClip2d:     boolean;               {true if clipping, false otherwise}
  29.   GxMode:       integer;               {current writing mode:
  30.                                         0 = overwrite, 1 = xor write}
  31.  
  32.   GxWxt, GxWyt, GxWxb, GxWyb:  real;     {Current Window's coordinates}
  33.   GxVxt, GxVyt, GxVxb, GxVyb:  integer;  {Current Viewport's coordinates}
  34.   GxSx, GxSy: real;                      {Current View's scale factors}
  35.   GxTx, GxTy: real;                      {Current View's translation constants}
  36.  
  37.   GxResult: record
  38.               ax, bx, cx, dx, bp,
  39.               si, di, ds, es, flags: integer;   {record for DOS interface}
  40.             end;
  41.  
  42.             { Graphics Segment Sub-Picture Package. }
  43.  
  44. const
  45.   GxSegNoMax = 100;
  46.   GxScribe   =   0;
  47.   GxDisplay  =   1;
  48.   GxErase    =   2;
  49.  
  50. type
  51.   GxName     = string [15];
  52.   GxSegRng   = 1 .. GxSegNoMax;
  53.  
  54.   GxDrawOp   = (GxNoOp, GxOpMoveTo, GxOpPlotAt, GxOpDrawTo,
  55.                 GxOpRelMoveTo, GxOpRelDrawTo,
  56.                 GxOpRelPlotAt, GxOpLineIndex);
  57.   GxLine     = ^GxLinRcd;
  58.   GxLinRcd = record                    {line record within a segment}
  59.                op: GxDrawOp;
  60.                x1, y1: real;
  61.                next: GxLine;
  62.              end;
  63.  
  64.   GxSegAttribute = ^GxSegRcd;
  65.   GxSegRcd = record                    {segment attribute record}
  66.                visible: boolean;
  67.                mode:    integer;       {GxSet or GxXor}
  68.                priority: integer;
  69.                pivotX, pivotY: real;
  70.                first, last: GxLine;
  71.              end;
  72.   GxSegTable    = array [GxSegRng] of GxSegAttribute;  {seg list by name}
  73.   GxPrioTable   = array [GxSegRng] of integer;         {seg list by priority}
  74.  
  75. var
  76.  
  77. {Segments and their attributes}
  78.  
  79.   GxSegOpen: boolean;                  {flag set true if a segment is open}
  80.   GxSegCount: integer;                 {total number of segments defined}
  81.   GxSegment: GxSegTable;               {segment list by name}
  82.   GxPrioList: GxPrioTable;             {segment list by priority}
  83.   GxPriority: integer;                 {Priority for all newly created segs.}
  84.   GxVisibility: boolean;               {Visibility for all new segments}
  85.  
  86. {the currently open segment's attributes}
  87.  
  88.   GxSegNo:   integer;
  89.   GxCurrSeg: GxSegAttribute;
  90.   GxPivotX, GxPivotY: real;            {pivot point coords for rotations}
  91.  
  92. procedure GxNormalize;
  93.   begin
  94.   Port [$03CE] := 5;                   {select Mode register}
  95.   Port [$03CF] := 0;                   {write mode = 0, as expected by BIOS}
  96.   Port [$03CE] := 8;                   {select Bit Mask register}
  97.   Port [$03CF] := $FF;                 {all points writeable}
  98.   end {GxNormalize};
  99.  
  100. procedure WritePixel (x, y: integer);
  101.  
  102.   {write pixel in current line index colour at x, y in IBM (top-down) coords.}
  103.  
  104.   var
  105.     offset: integer;
  106.     latch: byte;
  107.   begin
  108.   Port [$03CE] := 8;                     {select Bit Mask register}
  109.   Port [$03CF] := $80 shr (x and 7);     {set Bit Mask register}
  110.   offset := y * 80 + x div 8;
  111.   latch := Mem [EgaBase: offset];        {set processor latches}
  112.   Mem [EgaBase: offset] := GxIndex;
  113.   Port [$03CF] := $FF;                   {reset all points writeable}
  114.   end {WritePixel};
  115.  
  116. procedure DrawLine (x1, y1, x2, y2: integer);
  117.   {Bresenham's Algorithm for drawing lines in raster graphics.  See
  118.    Foley and van Dam, "Fundamentals of Interactive Computer Graphics"
  119.    Addison-Wesley, 1982, pp433-436.  Generalized for lines of all slopes.}
  120.  
  121.             {This version written for maximum speed}
  122.   var
  123.     x, y: integer;               {current pixel coords}
  124.     stepx, stepy: integer;
  125.     dx, dy: integer;
  126.     d, incr1, incr2: integer;
  127.     offset: integer;
  128.     latch: byte;
  129.  
  130.   begin
  131.  
  132.  {initialize starting values for frame buffer and x, y}
  133.  
  134.   x := x1;  y := y1;
  135.  {write initial entry into frame buffer for x1, y1}
  136.  
  137.   Port [$03CE] := 5;  {select Mode register and ...}
  138.   Port [$03CF] := 2;  {... set to write}
  139.   Port [$03CE] := 8;  {select Bit Mask register}
  140.     {draw point at x, y}
  141.   Port [$03CF] := $80 shr (x and 7);     {set Bit Mask register}
  142.   offset := y * 80 + x div 8;
  143.   latch := Mem [EgaBase: offset];
  144.   Mem [EgaBase: offset] := GxIndex;
  145.  
  146.   {compute constants for the Algorithm}
  147.  
  148.   dx := x2 - x1;  dy := y2 - y1;
  149.   if dx < 0 then
  150.     begin
  151.     stepx := -1;  dx := - dx;
  152.     end
  153.   else
  154.     stepx := 1;
  155.   if dy < 0 then
  156.     begin
  157.     stepy := -1;  dy := - dy;
  158.     end
  159.   else
  160.     stepy := 1;
  161.  
  162.   {Compute the points and write their images into the frame buffer}
  163.  
  164.   if dy < dx then
  165.     begin
  166.     incr2 := (dy - dx) shl 1;
  167.     d     := incr2 + dx;
  168.     incr1 := d + dx;
  169.     while x <> x2 do
  170.       begin
  171.       x := x + stepx;
  172.       if d < 0 then
  173.         d := d + incr1
  174.       else
  175.         begin
  176.         d := d + incr2;
  177.         y := y + stepy;
  178.         end { d >= 0};
  179.          {draw point at x, y}
  180.       Port [$03CF] := $80 shr (x and 7);     {set Bit Mask register}
  181.       offset := y * 80 + x div 8;
  182.       latch := Mem [EgaBase: offset];
  183.       Mem [EgaBase: offset] := GxIndex;
  184.       end { while x <> x2};
  185.     end {dy < dx}
  186.   else
  187.     begin
  188.     incr2 := (dx - dy) shl 1;
  189.     d     := incr2 + dy;
  190.     incr1 := d + dy;
  191.     while y <> y2 do
  192.       begin
  193.       y := y + stepy;
  194.       if d < 0 then
  195.         d := d + incr1
  196.       else
  197.         begin
  198.         d := d + incr2;
  199.         x := x + stepx;
  200.         end { d >= 0};
  201.         {draw point at x, y}
  202.       Port [$03CF] := $80 shr (x and 7);     {set Bit Mask register}
  203.       offset := y * 80 + x div 8;
  204.       latch := Mem [EgaBase: offset];
  205.       Mem [EgaBase: offset] := GxIndex;
  206.       end { while y <> y2};
  207.     end {dy >= dx};
  208.   GxNormalize;
  209.   end {DrawLine};
  210.  
  211. procedure clip2D (x1, y1, x2, y2: real);
  212.  
  213. {If any portion of the line is visible then clip the input line against
  214.  the current window, and draw it}
  215.  
  216.   label 99;
  217.   const
  218.     left = 1;  right = 2; bottom = 4; top = 8;
  219.   var
  220.     c, c1, c2: byte;
  221.     x, y: real;
  222.  
  223.   begin
  224.     c1 := 0;
  225.     if x1 < GxWxb then c1 := c1 + left else
  226.     if x1 > GxWxt then c1 := c1 + right;
  227.     if y1 < GxWyb then c1 := c1 + bottom else
  228.     if y1 > GxWyt then c1 := c1 + top;
  229.     c2 := 0;
  230.     if x2 < GxWxb then c2 := c2 + left else
  231.     if x2 > GxWxt then c2 := c2 + right;
  232.     if y2 < GxWyb then c2 := c2 + bottom else
  233.     if y2 > GxWyt then c2 := c2 + top;
  234.   while (c1 <> 0) or (c2 <> 0) do
  235.     begin
  236.     if (c1 and c2) <> 0 then     {line is completely invisible}
  237.       goto 99;
  238.         {clipping is necessary}
  239.     c := c1;
  240.     if c = 0 then c := c2;
  241.     if (left and c) <> 0 then          {crosses x = GxWxb}
  242.       begin
  243.       x := GxWxb;
  244.       y := y1 + (GxWxb - x1) * (y2 - y1) / (x2 - x1);
  245.       end
  246.     else if (right and c) <> 0 then     {crosses x =  GxWxt}
  247.       begin
  248.       x := GxWxt;
  249.       y := y1 + (GxWxt - x1) * (y2 - y1) / (x2 - x1);
  250.       end
  251.     else if (bottom and c) <> 0 then     {crosses y = GxWyb}
  252.       begin
  253.       x := x1 + (GxWyb - y1) * (x2 - x1) / (y2 - y1);
  254.       y := GxWyb;
  255.       end
  256.      else if (top and c) <> 0 then     {crosses y = GxWyt}
  257.        begin
  258.        x := x1 + (GxWyt - y1) * (x2 - x1) / (y2 - y1);
  259.        y := GxWyt;
  260.        end;
  261.     if c = c1 then
  262.       begin
  263.       x1 := x; y1 := y;
  264.       c1 := 0;
  265.       if x1 < GxWxb then c1 := c1 + left else
  266.       if x1 > GxWxt then c1 := c1 + right;
  267.       if y1 < GxWyb then c1 := c1 + bottom else
  268.       if y1 > GxWyt then c1 := c1 + top;
  269.       end
  270.     else
  271.       begin
  272.       x2 := x; y2 := y;
  273.       c2 := 0;
  274.       if x2 < GxWxb then c2 := c2 + left else
  275.       if x2 > GxWxt then c2 := c2 + right;
  276.       if y2 < GxWyb then c2 := c2 + bottom else
  277.       if y2 > GxWyt then c2 := c2 + top;
  278.       end;
  279.     end;
  280.  
  281.       { draw line }
  282.  
  283.   DrawLine (round (x1 * GxSx + GxTx),
  284.               round (y1 * GxSy + GxTy),
  285.               round (x2 * GxSx + GxTx),
  286.               round (y2 * GxSy + GxTy));
  287.   99:
  288.   end {clip2D};
  289.  
  290. procedure GxMakeEntry (operator: GxDrawOp; x, y: real);
  291.   const
  292.     MinMem = 200.0;                   {200 paragraphs of 16 bytes each}
  293.   var
  294.     entry:    GxLine;
  295.     TrueFree: real;
  296.   begin
  297.   TrueFree := MaxAvail;
  298.   if TrueFree < 0.0 then
  299.     TrueFree := TrueFree + 65536.0;   {No. of free paragraphs (16 bytes) of
  300.                                        free memory left}
  301.   if TrueFree > MinMem then
  302.     begin
  303.     new (entry);
  304.     with entry^ do
  305.       begin
  306.       op     := operator;
  307.       x1     := x;  y1 := y;
  308.       next   := nil;
  309.       end;
  310.     with GxCurrSeg^ do
  311.       begin
  312.       last^.next := entry;
  313.       last := last^.next;
  314.       end;
  315.     end;
  316.   end {GxMakeEntry};
  317.  
  318. procedure GxMoveTo(x, y: real);
  319.  
  320.   {Absolute move in world coordinates}
  321.  
  322.   begin
  323.   GxBeamX := x;
  324.   GxBeamY := y;
  325.   end {GxMoveTo};
  326.  
  327. procedure GxPlotAt (x, y: real);
  328.   var
  329.     Vx, Vy: integer;
  330.     visible: boolean;
  331.     offset: integer;
  332.     latch: byte;
  333.  
  334.   begin
  335.  
  336.   GxBeamX := x;
  337.   GxBeamY := y;
  338.  
  339.     {Test visibility against window.}
  340.  
  341.   if GxClip2d then
  342.     if (x <= GxWxb) then visible := false
  343.     else visible := (x <= GxWxt);
  344.     if visible then
  345.       if (y <= GxWyb) then visible := false
  346.       else visible := (y <= GxWyt)
  347.   else visible := true;
  348.  
  349.   if visible then
  350.     begin
  351.     Vx := round (x * GxSx + GxTx);
  352.     Vy := round (y * GxSy + GxTy);
  353.     Port [$03CE] := 5;  {select Mode register and ...}
  354.     Port [$03CF] := 2;  {... set to write}
  355.     Port [$03CE] := 8;
  356.  
  357.       {draw point at Vx, Vy}
  358.  
  359.     Port [$03CF] := $80 shr (Vx and 7);     {set Bit Mask register}
  360.     offset := Vy * 80 + Vx div 8;
  361.     latch := Mem [EgaBase: offset];
  362.     Mem [EgaBase: offset] := GxIndex;
  363.     GxNormalize;
  364.     end;
  365.   end {GxPlotAt};
  366.  
  367. procedure GxDrawTo (x, y: real);
  368.  
  369.   {absolute draw in world coordinates}
  370.  
  371.   begin
  372.   if GxClip2d then
  373.     Clip2D (GxBeamX, GxBeamY, x, y)
  374.   else
  375.     DrawLine (round (GxBeamX * GxSx + GxTx),
  376.                 round (GxBeamY * GxSy + GxTy),
  377.                 round (x * GxSx + GxTx),
  378.                 round (y * GxSy + GxTy));
  379.   GxBeamX := x;  GxBeamY := y;
  380.   end {GxDrawTo};
  381.  
  382. procedure GxRelMoveTo (x, y: real);
  383.   begin
  384.   GxMoveTo (GxBeamX + x, GxBeamY + y);
  385.   end {GxRelMoveTo};
  386.  
  387. procedure GxRelPlotAt (x, y: real);
  388.   begin
  389.   GxPlotAt (GxBeamX + x, GxBeamY + y);
  390.   end {GxRelPlotAt};
  391.  
  392. procedure GxRelDrawTo (x, y: real);
  393.   begin
  394.   GxDrawTo (GxBeamX + x, GxBeamY + y);
  395.   end {GxRelDrawTo};
  396.  
  397.  
  398. {
  399. *****************************************************************************
  400.               THE USER'S PACKAGE OF 2-D ROUTINES STARTS HERE.
  401. }
  402.  
  403. procedure pause;
  404.   begin
  405.   write (BELL);  readln;
  406.   end {pause};
  407.  
  408. procedure ColourMap (reg, colour: integer);
  409.   begin
  410.   reg := reg and GxIndexRng;
  411.   colour := colour and GxColourRng;
  412.   with GxResult do
  413.     begin
  414.     ax := $1000;
  415.     bx := (colour shl 8) or reg;
  416.     end;
  417.   Intr ($10, GxResult);
  418.   GxPalette [reg] := colour;
  419.   end {ColourMap};
  420.  
  421. procedure DefaultMap;
  422.   {set up the default colour map -
  423.    0: black;      1: dark blue;     2: dark green;   3: dark cyan;
  424.    4: dark red;   5: dark magenta;  6: dark yellow;  7: dark grey;
  425.    8: light grey; 9: full blue;    10: full green;  11: full cyan;
  426.   12: full red   13: full magenta; 14: full yellow; 15: white.}
  427.  
  428.   var
  429.     k: integer;
  430.  
  431.   begin
  432.   for k := 0 to 6 do
  433.     ColourMap (k, k); {black, dark: blue, green, cyan, red, magenta, yellow}
  434.   ColourMap (7, 56);                   {dark grey}
  435.   ColourMap (8, 7);                    {light grey}
  436.   for k := 1 to 7 do
  437.     ColourMap (k+8, 9*k);  {full: blue, green, cyan, red, magenta, yellow;
  438.                             white}
  439.   end {DefaultMap};
  440.  
  441. procedure Border (colour: integer);
  442.  
  443.   {draw the current viewport outline in the index 'colour'}
  444.   var
  445.     index: integer;
  446.   begin
  447.   if colour <> GxBackground then
  448.     begin
  449.     index := GxIndex;  GxIndex := colour;
  450.     DrawLine (GxVxb, GxVyb, GxVxb, GxVyt);
  451.     DrawLine (GxVxb, GxVyt, GxVxt, GxVyt);
  452.     DrawLine (GxVxt, GxVyt, GxVxt, GxVyb);
  453.     DrawLine (GxVxt, GxVyb, GxVxb, GxVyb);
  454.     GxIndex := index;
  455.     GxBorderIndex := colour;
  456.     end;
  457.   end {border};
  458.  
  459. procedure Window (xb, yb, xt, yt: real);
  460.  
  461.   {define the user's window boundaries}
  462.  
  463.   begin
  464.   if xb > xt then window (xt, yb, xb, yt)  else
  465.   if yb > yt then window (xb, yt, xt, yb)  else
  466.   if xb = xt then window (0.0, yb, 1.0, yt) else
  467.   if yb = yt then window (xb, 0.0, xt, 1.0)
  468.   else
  469.     begin
  470.     GxWxb := xb;  GxWxt := xt;
  471.     GxWyb := yb;  GxWyt := yt;
  472.     GxSx := (GxVxt - GxVxb) / (GxWxt - GxWxb);
  473.     GxSy := (GxVyt - GxVyb) / (GxWyt - GxWyb);
  474.     GxTx := GxVxb - GxWxb * GxSx;
  475.     GxTy := GxVyb - GxWyb * GxSy;
  476.     end;
  477.   end {Window};
  478.  
  479. procedure Viewport (xb, yb, xt, yt: integer);
  480.  
  481.   {define the user's viewport boundaries.  (xb, yb), (xt, yt) are bottom left
  482.    and top right corners respectively.}
  483.  
  484.   begin
  485.   if xb > xt then viewport (xt, yb, xb, yt) else
  486.   if yb > yt then viewport (xb, yt, xt, yb) else
  487.   if xb = xt then viewport (0, yb, GxMaxCol, yt) else
  488.   if yb = yt then viewport (xb, 0, xt, GxMaxRow) else
  489.   if xb < 0  then viewport (0, yb, xt, yt)  else
  490.   if xt > GxMaxCol then viewport (xb, yb, GxMaxCol, yt) else
  491.   if yb < 0  then viewport (xb, 0, xt, yt)  else
  492.   if yt > GxMaxRow then viewport (xb, yb, xt, GxMaxRow) else
  493.     begin
  494.     yb := GxMaxRow - yb; yt := GxMaxRow - yt;    {invert IBM's y-direction, that
  495.     is,
  496.                                     shift origin to lower left from top left}
  497.     GxVxb := xb;  GxVxt := xt;
  498.     GxVyb := yb;  GxVyt := yt;
  499.     GxSx := (GxVxt - GxVxb) / (GxWxt - GxWxb);
  500.     GxSy := (GxVyt - GxVyb) / (GxWyt - GxWyb);
  501.     GxTx := GxVxb - GxWxb * GxSx;
  502.     GxTy := GxVyb - GxWyb * GxSy;
  503.     Border (GxBorderIndex);
  504.     end;
  505.   end {Viewport};
  506.  
  507. procedure GraphicsOpen;
  508.   var
  509.     colour: integer;
  510.     k: integer;
  511.  
  512.   begin
  513.   with GxResult do
  514.       ax := GxEga;        {ah = 0, al = $10;  640x350, 80x25, colour}
  515.                           {ah = 0, al = $12;  640x480, PS/2 colour}
  516.   intr ($10, GxResult);
  517.  
  518.   GxPage := 0;
  519.   GxBeamX := 0.0;  GxBeamY := 0.0;
  520.   GxClip2d := true;
  521.  
  522.     {write mode - overwrite}
  523.  
  524.   GxMode := GxSet;
  525.   Port [$03CE] := 3;   {select data rotate and function register...}
  526.   Port [$03CF] := 0;   {... and set it to 'No Change' mode}
  527.  
  528.     {colours}
  529.  
  530.   DefaultMap;
  531.   GxIndex       := GxIndexRng;          {White lines}
  532.   GxBackGround  := GxPalette [0];       {black background}
  533.   GxText        := GxIndexRng;          {white text}
  534.   GxTextBack    := GxBackground;        {black background}
  535.   GxBorderIndex := GxBackground;        {do not draw viewport boundary}
  536.  
  537.     {windows and viewports}
  538.  
  539.   window (0.0, 0.0, 1.0, 1.0);
  540.   viewport (0, GxIndent, GxMaxCol-GxIndent, GxMaxRow);
  541.  
  542.   {Initialize segments}
  543.  
  544.   GxSegCount:=   0;              {total no. of defined segments}
  545.   GxSegNo   :=  -1;              {currently open segment no. (-1 = none)}
  546.   GxCurrSeg := nil;
  547.   GxSegOpen := false;
  548.   GxPivotX  := 0.0;  GxPivotY := 0.0;
  549.   for k := 1 to GxSegNoMax do
  550.     GxSegment [k] := nil;
  551.   GxPriority      := 0;          {default priority for next segment to be
  552.                                   opened}
  553.   GxVisibility    := true;       {default visibility is VISIBLE for next
  554.                                   segment to be opened}
  555.  
  556.   end {GraphicsOpen};
  557.  
  558. procedure GraphicsClose;
  559.   begin
  560.   Port [$03CE] := 3;   {select data rotate and function register...}
  561.   Port [$03CF] := 0;   {... and set it to 'No Change' mode}
  562.   with GxResult do
  563.     begin
  564.     ax := GxC80;
  565.     intr ($10, GxResult);
  566.     end;
  567.   end {GraphicsClose};
  568.  
  569. procedure WriteModeSet;
  570.  
  571.   {Define the current graphics writing mode to SET or overwrite mode}
  572.  
  573.   begin
  574.   GxMode := GxSet;
  575.   Port [$03CE] := 3;   {select data rotate and function register...}
  576.   Port [$03CF] := 0;   {... and set it to overwrite mode}
  577.   end {WriteModeSet};
  578.  
  579. procedure WriteModeXor;
  580.  
  581.   {Define the current graphics writing mode to XOR or see-through mode}
  582.  
  583.   begin
  584.   GxMode := GxXor;
  585.   Port [$03CE] := 3;   {select data rotate and function register...}
  586.   Port [$03CF] := $18;   {... and set it to XOR mode}
  587.   end {WriteModeXor};
  588.  
  589. procedure Transform (x, y, xscale, yscale, theta: real;
  590.                      var x1, y1: real);
  591.  
  592.   {Scale, and rotate (x, y) theta radians clockwise about origin, returning new
  593.    coordinates in (xpos, ypos)}
  594.  
  595.   var
  596.     SinTheta, CosTheta: real;
  597.     xa, ya:   real;
  598.   begin
  599.     SinTheta := sin (theta);
  600.     CosTheta := cos (theta);
  601.  
  602.     xa := xscale * x;
  603.     ya := yscale * y;
  604.     x1 := (  xa * CosTheta + ya * SinTheta);
  605.     y1 := (- xa * SinTheta + ya * CosTheta);
  606.   end {Transform};
  607.  
  608. procedure LineIndex (colour: integer);
  609.  
  610. {select a colour within the current palette for drawing}
  611.  
  612.   begin
  613.   if colour in [0..GxIndexRng] then
  614.     GxIndex := colour
  615.   else
  616.     GxIndex := 0;
  617.   if GxSegOpen then
  618.     GxMakeEntry (GxOpLineIndex, colour, 0);
  619.   end {LineIndex};
  620.  
  621. procedure SetCursor (x, y, colour, background: integer);
  622.  
  623.   {Move the alpha mode cursor to (x, y) in lower left origin coordinates,
  624.    and set the text and background colours.  A negative value for x will
  625.    leave the x-coordinate of the cursor unchanged, similarly for y.
  626.  
  627.    'Colour' can be:
  628.        black, blue, green, cyan, red, magenta, brown, lightgray,
  629.        darkgray, lightblue, lightgreen, lightcyan, lightred, lightmagenta,
  630.        yellow, white.  'blink' can be added to colour:  red + blink.
  631.  
  632.     'Background' can be any of the first eight of the above.
  633.  
  634.    Setting colour or background parameters to -1 will leave the last setting
  635.    of the parameter(s) unchanged.}
  636.  
  637.   begin
  638.   if x < 1 then x := WhereX;  if x > 80 then x := 1 + (x mod 80);
  639.   if y < 1 then y := WhereY;  if y > 25 then y := 1 + (y mod 25);
  640.  
  641.   if colour in [black .. white] then
  642.     GxText := colour;
  643.   TextColor (GxText);
  644.   if background in [black .. lightgray] then
  645.     GxTextBack := background;
  646.   TextBackGround (GxTextBack);
  647.   GoToXY (x, 26 - y);   {convert user's y to IBM's top left origin}
  648.   end {SetCursor};
  649.  
  650.  
  651. procedure Alpha (x, y: integer; colour, background: integer);
  652.  
  653.   {clear the screen and change to text mode 80 x 25 of character colour
  654.    'colour' with background colour 'background', placing the cursor at x, y
  655.    in lower left origin coordinates.  For negative values of x, y the
  656.    corresponding coordinate is left unchanged.
  657.  
  658.    For permitted colours see 'SetCursor' above.}
  659.  
  660.   begin
  661.   with GxResult do
  662.     begin
  663.     ax := GxC80;
  664.     intr ($10, GxResult);
  665.     end;
  666.  
  667.   SetCursor (x, y, colour, background);
  668.   end {Alpha};
  669.  
  670. procedure Graphics (Pal, Index: integer);
  671.  
  672.   {clear the screen and change to graphics mode.
  673.    Pal= -1:  select current colour map;
  674.    Pal = 0:  select default colour map;
  675.  
  676.    Index =  n:  (n in 0..15)  set line colour index to n in palette Pal
  677.    Index = -1;  set line colour index to current value}
  678.  
  679.   {NOTE: In the CGA package, Pal is used to select a palette, in which case
  680.          -1 <= Pal, Index <= 3}
  681.   var
  682.     reg: integer;
  683.     k: integer;
  684.   begin
  685.   with GxResult do
  686.     ax := GxEga;        {ah = 0, al = $10;  640x350, 80x25, colour}
  687.   intr ($10, GxResult);
  688.   if pal = -1 then
  689.     for reg := 0 to GxIndexRng do
  690.       ColourMap (reg, GxPalette [reg])   {restore user's colour map after
  691.                                           screen reset}
  692.   else
  693.     begin  {restore default colour map}
  694.     for k := 0 to 6 do
  695.       ColourMap (k, k);
  696.     ColourMap (7, 56);  ColourMap (8, 7);
  697.     for k := 1 to 7 do
  698.       ColourMap (k+8, k*9);
  699.     end;
  700.   if Index = -1 then Index := GxIndex;
  701.   LineIndex (Index);
  702.   Border (GxBorderIndex);
  703.   end {graphics};
  704.  
  705. procedure GraphicsMode;
  706.  
  707.   {return to graphics mode - ONLY after calling AlphaMode for text output in
  708.    EGA graphics mode.
  709.    This is NOT equivalent to GraphicsOpen.  It will FAIL unpredictably if
  710.    called after SetCursor or Alpha have been invoked!}
  711.  
  712.   begin
  713.   Port [$03CE] := 3;      {select data rotate and function register...}
  714.   if GxMode = GxSet then
  715.     Port [$03CF] := 0     {... set it to 'No Change' mode}
  716.   else
  717.     Port [$03CF] := $18;  {... set it to 'Xor' mode}
  718.   Port [$03CE] := 5;      {select Mode register and ...}
  719.   Port [$03CF] := 2;      {... set to write mode 2}
  720.   end {GraphicsMode};
  721.  
  722. procedure AlphaMode;
  723.   {enable text output in EGA Graphics mode.  Note:  GraphicsMode must be
  724.    called after text output completed before any more drawing can done}
  725.   begin
  726.   Port [$03CE] := 5;   {select Mode register and ...}
  727.   Port [$03CF] := 0;   {... set to write mode 0}
  728.   end {AlphaMode};
  729.  
  730.   { BASIC 2-D DRAWING ROUTINES }
  731.  
  732. procedure ClipOn2d;
  733.   {Apply 2D clipping to all drawing operations using the current window.  If
  734.    it is known that ALL of the drawing will be in the window then it is much
  735.    faster to turn clipping off - see ClipOff2d below.}
  736.   begin
  737.   GxClip2d := true;
  738.   end {ClipOn2d};
  739.  
  740. procedure ClipOff2d;
  741.   {Turn off 2D clipping for all drawing operations. If it is known that ALL
  742.    of the drawing will be in the window then it will be done much faster if
  743.    clipping is turned off.}
  744.   begin
  745.   GxClip2d := false;
  746.   end {ClipOn2d};
  747.  
  748. procedure MoveTo (xb, yb: real);
  749.  
  750.   {Move the current beam position to (xb, yb) in the current GxIndex colour.
  751.    If a segment is currently open then add the move to the segment.}
  752.  
  753.   var
  754.     lin: GxLine;
  755.  
  756.   begin
  757.   GxMoveTo (xb, yb);
  758.   if GxSegOpen then
  759.     with GxCurrSeg^ do
  760.       GxMakeEntry (GxOpMoveTo, xb - PivotX, yb - PivotY);
  761.   end {MoveTo};
  762.  
  763. procedure DrawTo (xb, yb: real);
  764.  
  765.   {draw a line from current beam position to (xb, yb) in the current GxIndex
  766.    colour, using the current GxMode of writing.
  767.    If a segment is currently open then add the line to the segment, and draw
  768.    to the screen if segment is marked visible.  Draw to the screen if no
  769.    segment currently open.}
  770.  
  771.   var
  772.     lin: GxLine;
  773.  
  774.   begin
  775.   if not GxSegOpen then
  776.     GxDrawTo (xb, yb)
  777.   else
  778.     with GxCurrSeg^ do
  779.     begin
  780.     if visible then
  781.       GxDrawTo (xb, yb)
  782.     else
  783.       GxMoveTo (xb, yb);
  784.  
  785.     GxMakeEntry (GxOpDrawTo, xb - PivotX, yb - PivotY);
  786.     end;
  787.   end {DrawTo};
  788.  
  789. procedure PlotAt (xb, yb: real);
  790.  
  791.   {Plot a point at (xb, yb) in the current GxIndex colour, using the current
  792.    GxMode of writing.
  793.    If a segment is currently open then add the point to the segment, and draw
  794.    to the screen if segment is marked visible.  Draw to the screen if no
  795.    segment currently open.}
  796.  
  797.   var
  798.     lin: GxLine;
  799.  
  800.   begin
  801.   if not GxSegOpen then
  802.     GxPlotAt (xb, yb)
  803.   else
  804.     with GxCurrSeg^ do
  805.     begin
  806.     if visible then
  807.       GxPlotAt (xb, yb)
  808.     else
  809.       GxMoveTo (xb, yb);
  810.  
  811.     GxMakeEntry (GxOpPlotAt, xb - PivotX, yb - PivotY);
  812.     end;
  813.   end {PlotAt};
  814.  
  815. procedure RelMoveTo (x, y: real);
  816.   begin
  817.   MoveTo (GxBeamX + x, GxBeamY + y);
  818.   end {RelMoveTo};
  819.  
  820. procedure RelPlotAt (x, y: real);
  821.   begin
  822.   PlotAt (GxBeamX + x, GxBeamY + y);
  823.   end {RelPlotAt};
  824.  
  825. procedure RelDrawTo (x, y: real);
  826.   begin
  827.   DrawTo (GxBeamX + x, GxBeamY + y);
  828.   end {RelDrawTo};
  829.  
  830.