home *** CD-ROM | disk | FTP | other *** search
/ The Unsorted BBS Collection / thegreatunsorted.tar / thegreatunsorted / programming / misc_programming / AGUL / DRAW.ADB < prev    next >
Encoding:
Text File  |  1990-10-25  |  15.4 KB  |  455 lines

  1. --        ╔═════════════════════════════════════════════════════════════╗
  2. --        ║█▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀█║
  3. --        ║█                                                           █║
  4. --        ║█                 Meridian Software Systems                 █║
  5. --        ║█                                                           █║
  6. --        ║█                    Copyright (C)  1990                    █║
  7. --        ║█                                                           █║
  8. --        ║█                    ALL RIGHTS RESERVED                    █║
  9. --        ║█                                                           █║
  10. --        ║█▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄█║
  11. --        ╚═════════════════════════════════════════════════════════════╝
  12.  
  13. ------------------------------------------------------------------------------
  14. --
  15. --   Unit Name:   DRAW           - package body
  16. --
  17. --   Purpose of unit:   This package is called to display the geometric
  18. --                      shapes including lines, circles, circle segments,
  19. --                      arcs, rectangles, and ellipses.  This package also
  20. --                      handles setting the foreground and background colors.
  21. --                      Additional functions include clearscreen and object
  22. --                      fill.
  23. --
  24. ------------------------------------------------------------------------------
  25.  
  26. with COMMON_DISPLAY_TYPES, INTERRUPT;
  27. with COMMON_GRAPHIC_TYPES, MATH_LIB, ASMPAK;
  28. use  COMMON_GRAPHIC_TYPES, MATH_LIB, ASMPAK;
  29.  
  30. package body DRAW is
  31.  
  32.   procedure SET4PIXELS (X, Y, XC, YC : integer) is
  33.     X_RIGHT_HALF : integer := integer(float(XC + X) * SCREEN_WORLD_RATIO_X);
  34.     X_LEFT_HALF  : integer := integer(float(XC - X) * SCREEN_WORLD_RATIO_X);
  35.     Y_UPPER_HALF : integer := integer(float(YC - Y) * SCREEN_WORLD_RATIO_Y);
  36.     Y_LOWER_HALF : integer := integer(float(YC + Y) * SCREEN_WORLD_RATIO_Y);
  37.     QUAD1_PLOT   : boolean := true;
  38.     QUAD2_PLOT   : boolean := true;
  39.     QUAD3_PLOT   : boolean := true;
  40.     QUAD4_PLOT   : boolean := true;
  41.  
  42.   begin
  43.     -- check and limit circle drawing to within active screen boundaries
  44.     if X_RIGHT_HALF > SCREEN_DIMENSION_LOWER_RIGHT_X then
  45.       QUAD1_PLOT := false;
  46.       QUAD4_PLOT := false;
  47.     end if;
  48.     if X_LEFT_HALF  < SCREEN_DIMENSION_UPPER_LEFT_X then
  49.       QUAD2_PLOT := false;
  50.       QUAD3_PLOT := false;
  51.     end if;
  52.     if Y_UPPER_HALF < SCREEN_DIMENSION_UPPER_LEFT_Y then
  53.       QUAD1_PLOT := false;
  54.       QUAD2_PLOT := false;
  55.     end if;
  56.     if Y_LOWER_HALF > SCREEN_DIMENSION_LOWER_RIGHT_Y then
  57.       QUAD3_PLOT := false;
  58.       QUAD4_PLOT := false;
  59.     end if;
  60.  
  61.     if CLIP_ENABLE then
  62.       -- check and limit circle drawing to within window boundaries
  63.       if X_RIGHT_HALF > CURRENT_WINDOW_LOWER_RIGHT_X then
  64.     QUAD1_PLOT := false;
  65.     QUAD4_PLOT := false;
  66.       end if;
  67.       if X_LEFT_HALF  < CURRENT_WINDOW_UPPER_LEFT_X then
  68.     QUAD2_PLOT := false;
  69.     QUAD3_PLOT := false;
  70.       end if;
  71.       if Y_UPPER_HALF < CURRENT_WINDOW_UPPER_LEFT_Y then
  72.     QUAD1_PLOT := false;
  73.     QUAD2_PLOT := false;
  74.       end if;
  75.       if Y_LOWER_HALF > CURRENT_WINDOW_LOWER_RIGHT_Y then
  76.     QUAD3_PLOT := false;
  77.     QUAD4_PLOT := false;
  78.       end if;
  79.     end if;
  80.  
  81.     -- now plot pixels on four quadrants
  82.     if QUAD1_PLOT then
  83.       PLOTXY (ABS(X_RIGHT_HALF), ABS(Y_UPPER_HALF),     -- first  quadrant
  84.           COMMON_DISPLAY_TYPES.COLOR'pos(FORE_COLOR),
  85.           CURRENT_VIDEO_PAGE);
  86.     end if;
  87.  
  88.     if QUAD2_PLOT then
  89.       PLOTXY (ABS(X_LEFT_HALF), ABS(Y_UPPER_HALF),      -- second quadrant
  90.           COMMON_DISPLAY_TYPES.COLOR'pos(FORE_COLOR),
  91.           CURRENT_VIDEO_PAGE);
  92.     end if;
  93.  
  94.     if QUAD3_PLOT then
  95.       PLOTXY (ABS(X_LEFT_HALF), ABS(Y_LOWER_HALF),      -- third quadrant
  96.           COMMON_DISPLAY_TYPES.COLOR'pos(FORE_COLOR),
  97.           CURRENT_VIDEO_PAGE);
  98.     end if;
  99.  
  100.     if QUAD4_PLOT then
  101.       PLOTXY (ABS(X_RIGHT_HALF), ABS(Y_LOWER_HALF),     -- fourth quadrant
  102.           COMMON_DISPLAY_TYPES.COLOR'pos(FORE_COLOR),
  103.           CURRENT_VIDEO_PAGE);
  104.     end if;
  105.  
  106.   end SET4PIXELS;
  107.  
  108.   procedure SCAN_LEFT ( X : in out integer;
  109.             Y, BorderC, FillC : integer ) is
  110.     ATTR : integer := -1;
  111.   begin
  112.     while (ATTR /= BorderC) and (ATTR /= FillC) loop
  113.       ATTR := READ_PIXEL_ATTR (X, Y);
  114.       X := X - 1;
  115.     end loop;
  116.  
  117.     X := X + 2;
  118.   end SCAN_LEFT;
  119.  
  120.   procedure SCAN_RIGHT (X : in out integer;
  121.             Y, BorderC, FillC : integer ) is
  122.     ATTR : integer := -1;
  123.   begin
  124.     while (ATTR /= BorderC) and (ATTR /= FillC) loop
  125.       ATTR := READ_PIXEL_ATTR ( X,Y);
  126.       X := X + 1;
  127.     end loop;
  128.  
  129.     X := X - 1;
  130.   end SCAN_RIGHT;
  131.  
  132.   function LINE_ADJ_FILL (SEEDX, SEEDY, D,
  133.               PREVXL, PREVXR,
  134.               BorderC, FillC : integer) return integer is
  135.     XL      : integer := SEEDX;
  136.     XR      : integer := SEEDX;
  137.     Y       : integer := SEEDY;
  138.     ATTR    : integer;
  139.     X_COUNT : integer;
  140.   begin
  141.     SCAN_LEFT  (XL, Y, BorderC, FillC);    -- determine left  most pixel on row to be filled
  142.     SCAN_RIGHT (XR, Y, BorderC, FillC);    -- determine right most pixel on row to be filled
  143.  
  144.     DRAW_BASIC_LINE (XL, Y, XR, Y, FillC, 1, 1, 640, 350, 0, CURRENT_VIDEO_PAGE);
  145.  
  146.     X_COUNT := XL;
  147.     while X_COUNT < XR loop
  148.       ATTR := READ_PIXEL_ATTR ( X_COUNT, Y + D );
  149.       if (ATTR /= BorderC) and (ATTR /= FillC) then
  150.     X_COUNT := LINE_ADJ_FILL (X_COUNT, Y + D, D, XL, XR, BorderC, FillC);
  151.       end if;
  152.       X_COUNT := X_COUNT + 1;
  153.     end loop;
  154.  
  155.     X_COUNT := XL;
  156.     while X_COUNT < PREVXL loop
  157.       ATTR := READ_PIXEL_ATTR (X_COUNT, Y - D);
  158.       if (ATTR /= Borderc) and (ATTR /= FillC) then
  159.     X_COUNT := LINE_ADJ_FILL (X_COUNT, Y - D, -D, XL, XR, BorderC, FillC);
  160.       end if;
  161.       X_COUNT := X_COUNT + 1;
  162.     end loop;
  163.  
  164.     X_COUNT := PREVXR;
  165.     while X_COUNT < PREVXR loop
  166.       ATTR := READ_PIXEL_ATTR (X_COUNT, Y - D);
  167.       if (ATTR /= BorderC) and (ATTR /= FillC) then
  168.     X_COUNT := LINE_ADJ_FILL (X_COUNT, Y - D, -D, XL, XR, BorderC, FillC);
  169.       end if;
  170.       X_COUNT := X_COUNT + 1;
  171.     end loop;
  172.  
  173.     return XR;
  174.   end LINE_ADJ_FILL;
  175.  
  176.   procedure ELLIPSE (XC, YC, A0, B0 : natural) is
  177.     -- This procedure draws an ellipse defined by:
  178.     --
  179.     --   XC, YC:   coordinate of the ellipse center
  180.     --   A0:       length of the X axis (measured from center to the vertex)
  181.     --   B0:       length of the Y axis (measured from center to the vertex)
  182.     --
  183.     -- Bresenham's algorithm is used to draw the ellipse.
  184.  
  185.     X           : integer      := 0;
  186.     Y           : integer      := B0;
  187.     A           : long_integer := long_integer (float (A0) * ASPECT_RATIO);
  188.     B           : long_integer := long_integer (B0);
  189.     ASQUARED    : long_integer := A * A;
  190.     TWOASQUARED : long_integer := 2 * ASQUARED;
  191.     BSQUARED    : long_integer := B * B;
  192.     TWOBSQUARED : long_integer := 2 * BSQUARED;
  193.     D, DX, DY   : long_integer;
  194.  
  195.   begin
  196.     D  := BSQUARED - ASQUARED * B + ASQUARED / 4;  -- initial midpoint value
  197.     DX := 0;                                       -- initial delta X
  198.     DY := TWOASQUARED * B;                         -- initial delta Y
  199.  
  200.     while DX < DY loop
  201.       SET4PIXELS (X, Y, integer(XC), integer(YC));
  202.       -- Plot all four quadrants
  203.       if D > 0 then
  204.     Y  := Y - 1;
  205.     DY := DY - TWOASQUARED;
  206.     D  := D - DY;
  207.       end if;
  208.       X  := X + 1;
  209.       DX := DX + TWOBSQUARED;
  210.       D  := D + BSQUARED + DX;   -- Until DY/DX reaches -1
  211.     end loop;
  212.  
  213.     -- Adjust new midpoint value
  214.     D := D + (3 * (ASQUARED - BSQUARED) / 2 - (DX + DY)) / 2;
  215.  
  216.     while Y >= 0 loop          -- Continue ploting in all four quadrants
  217.       SET4PIXELS (X, Y, integer(XC), integer(YC));
  218.       if D < 0 then
  219.     X  := X + 1;
  220.     DX := DX + TWOBSQUARED;
  221.     D  := D + DX;
  222.       end if;
  223.       Y  := Y - 1;
  224.       DY := DY - TWOASQUARED;
  225.       D  := D + ASQUARED - DY;
  226.     end loop;                  -- Until X-axis is reached
  227.  
  228.   end ELLIPSE;
  229.  
  230.   procedure CIRCLE (XC, YC, R: natural) is
  231.  
  232.     --  This procedure draws a circle defined by:
  233.     --
  234.     --        XC, YC:    coordinate of the circle center
  235.     --        R:         radius of the circle
  236.     --
  237.     --  Ellipse algorithm is used for the circle,
  238.     --    where major and minor axes are equal
  239.  
  240.   begin
  241.     ELLIPSE (XC, YC, R, R);   -- Circle is a degenerated ellipse
  242.   end CIRCLE;
  243.  
  244.   procedure CIRCLE_SEGMENT (XC, YC, SA, EA, R: natural) is
  245.     START_A          : float := float (SA);
  246.     END_A            : float := float (EA);
  247.     POINT_X, POINT_Y : integer;
  248.   begin
  249.  
  250.     -- Calculate coordinate of arc starting position
  251.     POINT_X := integer(XC + integer(float(R) *
  252.                 COS(float(START_A)/57.29578) * ASPECT_RATIO));
  253.     POINT_Y := integer(YC - integer(float(R) *
  254.                 SIN(float(START_A)/57.29578)));
  255.  
  256.     -- Draw a line from center of circle to it
  257.     DRAW_BASIC_LINE (XC, YC, POINT_X, POINT_Y,
  258.              COMMON_DISPLAY_TYPES.COLOR'pos(FORE_COLOR),
  259.              CURRENT_WINDOW_UPPER_LEFT_X,
  260.              CURRENT_WINDOW_UPPER_LEFT_Y,
  261.              CURRENT_WINDOW_LOWER_RIGHT_X,
  262.              CURRENT_WINDOW_LOWER_RIGHT_Y,
  263.              boolean'pos (CLIP_ENABLE),
  264.              CURRENT_VIDEO_PAGE);
  265.  
  266.     -- Draw an arc from starting position to ending position
  267.     ARC ( XC, YC, SA, EA, R);
  268.  
  269.     -- Calculate coordinate of arc ending position
  270.     POINT_X := integer(XC + integer(float(R) *
  271.                 COS(float(END_A)/57.29578) * ASPECT_RATIO));
  272.     POINT_Y := integer(YC - integer(float(R) *
  273.                 SIN(float(END_A)/57.29578)));
  274.  
  275.     -- Draw a line from it to center of circle to close circle segment
  276.     DRAW_BASIC_LINE (POINT_X, POINT_Y, XC, YC,
  277.              COMMON_DISPLAY_TYPES.COLOR'pos (FORE_COLOR),
  278.              CURRENT_WINDOW_UPPER_LEFT_X,
  279.              CURRENT_WINDOW_UPPER_LEFT_Y,
  280.              CURRENT_WINDOW_LOWER_RIGHT_X,
  281.              CURRENT_WINDOW_LOWER_RIGHT_Y,
  282.              boolean'pos (CLIP_ENABLE),
  283.              CURRENT_VIDEO_PAGE);
  284.   end CIRCLE_SEGMENT;
  285.  
  286.   procedure ARC (XC,YC,SA,EA,R: natural) is
  287.  
  288.     -- This procedure draws an arc of a circle defined by:
  289.     --
  290.     --        XC,YC:    coordinate of the circle center
  291.     --        SA:       starting angle in degrees
  292.     --        EA:       ending angle in degrees
  293.     --        R:        radius of the circle
  294.     --
  295.     -- Transcendental calculation of points on the circle form the arc
  296.  
  297.     START_A    : float := float (SA);
  298.     END_A      : float := float (EA);
  299.     DEG_INC    : float := START_A;
  300.     POINT_X    : integer;
  301.     POINT_Y    : integer;
  302.     PLOT_VALID : boolean;
  303.  
  304.   begin
  305.     if START_A > END_A then     -- to guarantee that can draw Theta > 360 deg.
  306.       END_A := END_A + 360.0;
  307.     end if;
  308.  
  309.     while DEG_INC <= END_A loop -- transcendental loop drawing
  310.       POINT_X := integer(SCREEN_WORLD_RATIO_X *
  311.              (float(XC) +
  312.               float(R) * COS(DEG_INC/57.29578) * ASPECT_RATIO));
  313.       POINT_Y := integer(SCREEN_WORLD_RATIO_Y *
  314.              (float(YC) -
  315.               float(R) * SIN(DEG_INC/57.29578)));
  316.  
  317.       -- check for screen boundaries
  318.       if (POINT_X > SCREEN_DIMENSION_UPPER_LEFT_X ) and
  319.      (POINT_X < SCREEN_DIMENSION_LOWER_RIGHT_X) and
  320.      (POINT_Y > SCREEN_DIMENSION_UPPER_LEFT_Y ) and
  321.      (POINT_Y < SCREEN_DIMENSION_LOWER_RIGHT_Y) then
  322.     PLOT_VALID := true;
  323.       else
  324.     PLOT_VALID := false;
  325.       end if;
  326.  
  327.       -- only draw inside the window if clipping is on
  328.       if PLOT_VALID and CLIP_ENABLE then
  329.     if (POINT_X > CURRENT_WINDOW_UPPER_LEFT_X ) and
  330.        (POINT_X < CURRENT_WINDOW_LOWER_RIGHT_X) and
  331.        (POINT_Y > CURRENT_WINDOW_UPPER_LEFT_Y ) and
  332.        (POINT_Y < CURRENT_WINDOW_LOWER_RIGHT_Y) then
  333.       PLOT_VALID := true;
  334.         else
  335.       PLOT_VALID := false;
  336.         end if;
  337.       end if;
  338.  
  339.       -- after all conditions are met, plot the point
  340.       if PLOT_VALID then
  341.     PLOTXY (POINT_X, POINT_Y,
  342.         COMMON_DISPLAY_TYPES.COLOR'pos (FORE_COLOR),
  343.         CURRENT_VIDEO_PAGE);
  344.       end if;
  345.  
  346.       DEG_INC := DEG_INC + 0.4;   -- increment by 0.2 degree for nice plot
  347.  
  348.     end loop;
  349.   end ARC;
  350.  
  351.   procedure RECTANGLE (X1, Y1, X2, Y2 : natural) is
  352.  
  353.     -- This procedure draws a rectangle defined by:
  354.     --
  355.     --        X1, Y1:    coordinate of the upper left  corner
  356.     --        X2, Y2:    coordinate of the lower right corner
  357.     --
  358.     -- Line drawing routine is used to complete the rectangle
  359.  
  360.   begin
  361.     LINE (X1, Y1, X2, Y1);       -- from upper left  to upper right
  362.     LINE (X2, Y1, X2, Y2);       -- from upper right to lower right
  363.     LINE (X2, Y2, X1, Y2);       -- from lower right to lower left
  364.     LINE (X1, Y2, X1, Y1);       -- from lower left  to upper left
  365.   end RECTANGLE;
  366.  
  367.   procedure LINE (X1, Y1, X2, Y2 : natural) is
  368.  
  369.     --  This procedure draws a line defined by:
  370.     --
  371.     --        X1, Y1:    coordinate of the starting point
  372.     --        X2, Y2:    coordinate of the ending point
  373.     --
  374.     --  Bresenham's algorithm is used to draw the line
  375.  
  376.     XSTART : integer := integer(float(X1) * SCREEN_WORLD_RATIO_X);
  377.     XEND   : integer := integer(float(X2) * SCREEN_WORLD_RATIO_X);
  378.     YSTART : integer := integer(float(Y1) * SCREEN_WORLD_RATIO_Y);
  379.     YEND   : integer := integer(float(Y2) * SCREEN_WORLD_RATIO_Y);
  380.     UPPERX : integer := SCREEN_DIMENSION_UPPER_LEFT_X;
  381.     UPPERY : integer := SCREEN_DIMENSION_UPPER_LEFT_Y;
  382.     LOWERX : integer := SCREEN_DIMENSION_LOWER_RIGHT_X;
  383.     LOWERY : integer := SCREEN_DIMENSION_LOWER_RIGHT_Y;
  384.  
  385.   begin
  386.     -- limit line x-coordinate to within screen x-boundary
  387.     if XSTART < SCREEN_DIMENSION_UPPER_LEFT_X then
  388.       XSTART :=  SCREEN_DIMENSION_UPPER_LEFT_X;
  389.     end if;
  390.     if XSTART > SCREEN_DIMENSION_LOWER_RIGHT_X then
  391.       XSTART := SCREEN_DIMENSION_LOWER_RIGHT_X;
  392.     end if;
  393.     if XEND > SCREEN_DIMENSION_LOWER_RIGHT_X then
  394.       XEND := SCREEN_DIMENSION_LOWER_RIGHT_X;
  395.     end if;
  396.     if XEND < SCREEN_DIMENSION_UPPER_LEFT_X then
  397.       XEND := SCREEN_DIMENSION_UPPER_LEFT_X;
  398.     end if;
  399.  
  400.     -- limit line y-coordinate to within screen y-boundary
  401.     if YSTART > SCREEN_DIMENSION_LOWER_RIGHT_Y then
  402.       YSTART := SCREEN_DIMENSION_LOWER_RIGHT_Y;
  403.     end if;
  404.     if YSTART < SCREEN_DIMENSION_UPPER_LEFT_Y then
  405.       YSTART := SCREEN_DIMENSION_UPPER_LEFT_Y;
  406.     end if;
  407.     if YEND > SCREEN_DIMENSION_LOWER_RIGHT_Y then
  408.       YEND := SCREEN_DIMENSION_LOWER_RIGHT_Y;
  409.     end if;
  410.     if YEND < SCREEN_DIMENSION_UPPER_LEFT_Y then
  411.       YEND := SCREEN_DIMENSION_UPPER_LEFT_Y;
  412.     end if;
  413.  
  414.     if CLIP_ENABLE then
  415.       -- limit line x-coordinate to within window x-boundary
  416.       UPPERX := CURRENT_WINDOW_UPPER_LEFT_X;
  417.       UPPERY := CURRENT_WINDOW_UPPER_LEFT_Y;
  418.       LOWERX := CURRENT_WINDOW_LOWER_RIGHT_X;
  419.       LOWERY := CURRENT_WINDOW_LOWER_RIGHT_Y;
  420.     end if;
  421.  
  422.     DRAW_BASIC_LINE (XSTART, YSTART, XEND, YEND,
  423.              COMMON_DISPLAY_TYPES.COLOR'pos (FORE_COLOR),
  424.              UPPERX, UPPERY, LOWERX, LOWERY,
  425.              boolean'pos (CLIP_ENABLE),
  426.              CURRENT_VIDEO_PAGE);
  427.   end LINE;
  428.  
  429.   procedure OBJECT_FILL (X, Y : natural;
  430.              FIL_C, BRD_C : COMMON_DISPLAY_TYPES.COLOR) is
  431.     DUMMY : integer;
  432.   begin
  433.     DUMMY := LINE_ADJ_FILL (X, Y, -1, X, Y,
  434.                 COMMON_DISPLAY_TYPES.COLOR'pos (BRD_C),
  435.                 COMMON_DISPLAY_TYPES.COLOR'pos (FIL_C));
  436.   end OBJECT_FILL;
  437.  
  438.   procedure FOREGROUND_COLOR (COLOR : COMMON_DISPLAY_TYPES.COLOR) is
  439.   begin
  440.     FORE_COLOR := COLOR;    -- Set foreground color for all future draws
  441.   end FOREGROUND_COLOR;
  442.  
  443.  
  444.   procedure BACKGROUND_COLOR (COLOR : COMMON_DISPLAY_TYPES.COLOR) is
  445.   begin
  446.     BACK_COLOR := COLOR;    -- Set background color for all future draws
  447.   end BACKGROUND_COLOR;
  448.  
  449.   procedure CLEAR_SCREEN is
  450.   begin
  451.     ASMPAK.CLEAR_SCREEN;
  452.   end CLEAR_SCREEN;
  453.  
  454. end DRAW;
  455.