home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / mbug / mbug117.arc / TURBO.LBR / LORES.LZB / LORES.LIB
Text File  |  1979-12-31  |  12KB  |  471 lines

  1. { GENERALITY          : CP/M
  2.   APPLICATION AREA    : TURBO utility
  3.   PROGRAM DESCRIPTION : Lores Graphics from TURBO
  4.   PROGRAM NAME        : LOGCOUNT.PAS
  5.   NECESSARY MODULES   : None
  6.   SOURCE LANGUAGE     : Borland turbo pascal (ver 3)
  7.   WRITTEN             : G. Irlam 1985
  8.   LAST MODIFIED       : G. Irlam 1985
  9.   COMMENTS            : See LORES.DOC }
  10.  
  11. {$R+}
  12.   CONST
  13.     max_reg = 15;
  14.     rom_read_latch = $0B;
  15.     latch_on = 1;
  16.     latch_off = 0;
  17.     address_port = $0C;
  18.     register_port = $0D;
  19.     max_pcg_height = $0F;
  20.     max_pcg_height_plus_one = $10;
  21.     first_pcg_code = $80;
  22.     max_pcg = $7F;
  23.     max_pcg_used = $3F;
  24.  
  25.   TYPE
  26.     register = 0 .. max_reg;
  27.     screen_reg = ARRAY [register] OF byte;
  28.     char_number = 0 .. $7FF;
  29.     character_code = byte;
  30.     pcg_line_no = 0 .. max_pcg_height;
  31.     char_range = 0 .. max_pcg;
  32.     bit_value = 1 .. $20;
  33.     pt = RECORD
  34.       x, y : byte
  35.     END;
  36.     address = RECORD
  37.       ch_no : char_number;
  38.       value : bit_value
  39.     END;
  40.     mode = (draw, rub_out, invert);
  41.     fill_mode = draw .. rub_out;
  42.     state = (on, off, ascii_character, out_of_range);
  43.  
  44.   CONST
  45.     s80_24 : screen_reg = ($6B, $50, $58, $37, $1B, $05, $18, $1A, $48, $0A, $2A, $0A, $20, $00, $00, $00);
  46.     s64_16 : screen_reg = ($6B, $40, $51, $37, $12, $09, $10, $12, $48, $0F, $2F, $0F, $00, $00, $00, $00);
  47.     s75_23 : screen_reg = ($6B, 75, 87, $37, 25, 1, 23, $18, $48, 11, $2B, $2B, $20, $00, $00, $00);
  48.  
  49.   VAR
  50.     screen : RECORD
  51.       char_wide : 0 .. $7F;
  52.       char_high : 0 .. $7F;
  53.       pcg_height : 0 .. $3F;
  54.       cols : 0 .. $FF;
  55.       rows : 0 .. $17F
  56.     END;
  57.     vdu_ram : ARRAY [char_number] OF character_code ABSOLUTE $F000;
  58.     char_rom : ARRAY [char_range, pcg_line_no] OF byte ABSOLUTE $F000;
  59.     pcg_ram : ARRAY [char_range, pcg_line_no] OF byte ABSOLUTE $F800;
  60.     max_col, max_row : byte;
  61.     error : boolean;
  62.     char_addr : address;
  63.     ch_code : character_code;
  64.  
  65.   PROCEDURE set_screen (new_screen : screen_reg);
  66.  
  67.     VAR
  68.       reg : register;
  69.  
  70.     BEGIN
  71.       FOR reg := 0 TO max_reg DO
  72.         BEGIN
  73.           port [address_port] := reg;
  74.           port [register_port] := new_screen [reg]
  75.         END;
  76.       WITH screen DO
  77.         BEGIN
  78.           char_wide := new_screen [1];
  79.           char_high := new_screen [6];
  80.           pcg_height := new_screen [9] + 1;
  81.           cols := char_wide * 2;
  82.           rows := char_high * 3;
  83.           max_col := cols - 1;
  84.           max_row := rows - 1
  85.         END
  86.     END;
  87.  
  88.   PROCEDURE init_pcg;
  89.  
  90.     VAR
  91.       pcg : 0 .. max_pcg_used;
  92.       block : 1 .. 3;
  93.       first : pcg_line_no;
  94.       last : 0 .. max_pcg_height_plus_one;
  95.       bit_value : 1 .. 8;
  96.  
  97.     PROCEDURE set_row (right, left : byte);
  98.  
  99.       VAR
  100.         line_value : byte;
  101.         line : pcg_line_no;
  102.  
  103.       BEGIN
  104.         line_value := 0;
  105.         IF right <> 0 THEN
  106.           line_value := line_value OR $F0;
  107.         IF left <> 0 THEN
  108.           line_value := line_value OR $0F;
  109.         FOR line := first TO last - 1 DO
  110.           pcg_ram [pcg, line] := line_value
  111.       END;
  112.  
  113.     BEGIN
  114.       last := screen . pcg_height;
  115.       bit_value := 1;
  116.       FOR block := 3 DOWNTO 1 DO
  117.         BEGIN
  118.           first := last - last DIV block;
  119.           FOR pcg := 0 TO max_pcg_used DO
  120.             set_row (pcg AND bit_value, pcg AND (8 * bit_value));
  121.           bit_value := 2 * bit_value;
  122.           last := first
  123.         END
  124.     END;
  125.  
  126.   PROCEDURE inverse_init;
  127.  
  128.     VAR
  129.       ch : char_range;
  130.       line : pcg_line_no;
  131.  
  132.     BEGIN
  133.       port [rom_read_latch] := latch_on;
  134.       FOR ch := 0 TO max_pcg DO
  135.         FOR line := 0 TO max_pcg_height DO
  136. {$R-}
  137.           pcg_ram [ch, line] := NOT char_rom [ch, line];
  138. {$R+}
  139.       port [rom_read_latch] := latch_off
  140.     END;
  141.  
  142.   FUNCTION range_check (p : pt) : boolean;
  143. { range_check := (p . x >= 0) AND (p . x <= max_col) AND (p . y >= 0) AND (p . y <= max_row) }
  144.  
  145.     VAR
  146.       result : boolean;
  147.  
  148.     BEGIN
  149.       INLINE ($21/ p/
  150.               $3A/ max_col/
  151.               $BE/
  152.               $DA/ * + 15/
  153.               $23/
  154.               $3A/ max_row/
  155.               $BE/
  156.               $DA/ * + 7/
  157.               $3E/ $01/
  158.               $C3/ * + 3/
  159.               $AF/
  160.               $32/ result);
  161.       range_check := result
  162.     END;
  163.  
  164.   PROCEDURE location (p : pt; VAR address : address);
  165.  
  166.     VAR
  167.       ch_up, ch_right : byte;
  168.       value : byte;
  169.  
  170.     BEGIN
  171.       WITH p DO
  172.         BEGIN
  173.           ch_right := x SHR 1;
  174.           ch_up := y DIV 3;
  175.           address . ch_no := (screen . char_high - ch_up - 1) * screen . char_wide + ch_right;
  176.           value := y - (ch_up + (ch_up SHL 1));
  177.           IF value = 0 THEN
  178.             value := 1
  179.           ELSE
  180.             value := value SHL 1;
  181.           IF odd (x) THEN
  182.             value := value SHL 3;
  183.           address . value := value
  184.         END
  185.     END;
  186.  
  187.   FUNCTION status (p : pt) : state;
  188.  
  189.     BEGIN
  190.       IF range_check (p) THEN
  191.         WITH char_addr DO
  192.           BEGIN
  193.             location (p, char_addr);
  194.             ch_code := vdu_ram [ch_no];
  195.             IF ch_code < first_pcg_code THEN
  196.               status := ascii_character
  197.             ELSE
  198.               IF ch_code AND value = 0 THEN
  199.                 status := off
  200.               ELSE
  201.                 status := on
  202.           END
  203.       ELSE
  204.         status := out_of_range
  205.     END;
  206.  
  207.   PROCEDURE point (p : pt; mode : mode);
  208.  
  209.     VAR
  210.       ch_code : character_code;
  211.       char_addr : address;
  212.  
  213.     BEGIN
  214.       IF range_check (p) THEN
  215.         WITH char_addr DO
  216.           BEGIN
  217.             location (p, char_addr);
  218.             ch_code := vdu_ram [ch_no];
  219.             IF ch_code < first_pcg_code THEN
  220.               ch_code := first_pcg_code;
  221.             CASE mode OF
  222.               draw :
  223.                 ch_code := ch_code OR value;
  224.               rub_out :
  225.                 ch_code := ch_code AND NOT value;
  226.               invert :
  227.                 ch_code := ch_code XOR value
  228.             END;
  229.             vdu_ram [ch_no] := ch_code;
  230.             error := false
  231.           END
  232.       ELSE
  233.         error := true
  234.     END;
  235.  
  236.   PROCEDURE line (p0, p1 : pt; mode : mode);
  237.  
  238.     VAR
  239.       x_inc, y_inc : - 1 .. 1;
  240.       x_step, y_step : byte;
  241.       remainder : integer;
  242.  
  243.     BEGIN
  244.       IF range_check (p0) AND range_check (p1) THEN
  245.         WITH p0 DO
  246.           BEGIN
  247.             x_step := abs (p1 . x - x);
  248.             y_step := abs (p1 . y - y);
  249.             IF p1 . x > x THEN
  250.               x_inc := 1
  251.             ELSE
  252.               IF p1 . x < x THEN
  253.                 x_inc := - 1
  254.               ELSE
  255.                 x_inc := 0;
  256.             IF p1 . y > y THEN
  257.               y_inc := 1
  258.             ELSE
  259.               IF p1 . y < y THEN
  260.                 y_inc := - 1
  261.               ELSE
  262.                 y_inc := 0;
  263.             remainder := 0;
  264.             point (p0, mode);
  265.             IF y_step <= x_step THEN
  266.               WHILE x <> p1 . x DO
  267.                 BEGIN
  268.                   x := x + x_inc;
  269.                   remainder := remainder + y_step;
  270.                   IF remainder SHL 1 >= x_step THEN
  271.                     BEGIN
  272.                       y := y + y_inc;
  273.                       remainder := remainder - x_step
  274.                     END;
  275.                   point (p0, mode)
  276.                 END
  277.             ELSE
  278.               WHILE y <> p1 . y DO
  279.                 BEGIN
  280.                   y := y + y_inc;
  281.                   remainder := remainder + x_step;
  282.                   IF remainder SHL 1 >= y_step THEN
  283.                     BEGIN
  284.                       x := x + x_inc;
  285.                       remainder := remainder - y_step
  286.                     END;
  287.                   point (p0, mode)
  288.                 END;
  289.             error := false
  290.           END
  291.       ELSE
  292.         error := true
  293.     END;
  294.  
  295.   PROCEDURE ellipse (p : pt; x_radius, y_radius : byte; mode : mode);
  296.  
  297.     VAR
  298.       x_sin, x_cos, y_sin, y_cos, step : real;
  299.       max_radius, count : integer;
  300.       q, r, s : pt;
  301.  
  302.     BEGIN
  303. {$R-}
  304.       q . x := p . x + x_radius;
  305.       q . y := p . y + y_radius;
  306.       r . x := p . x - x_radius;
  307.       r . y := p . y - y_radius;
  308. {$R+}
  309.       IF range_check (q) AND range_check (r) THEN
  310.         BEGIN
  311.           IF y_radius > x_radius THEN
  312.             max_radius := y_radius
  313.           ELSE
  314.             max_radius := x_radius;
  315.           step := 0.9 / max_radius;
  316.           x_sin := 0;
  317.           x_cos := x_radius;
  318.           y_sin := 0;
  319.           y_cos := y_radius;
  320.           s . x := p . x + round (x_cos);
  321.           s . y := p . y + round (y_sin);
  322.           point (s, mode);
  323.           q := s;
  324.           FOR count := 0 TO trunc (2 * PI / step - 1) DO
  325.             BEGIN
  326.               x_sin := x_sin + x_cos * step;
  327.               x_cos := x_cos - x_sin * step;
  328.               y_sin := y_sin + y_cos * step;
  329.               y_cos := y_cos - y_sin * step;
  330.               r . x := p . x + round (x_cos);
  331.               r . y := p . y + round (y_sin);
  332.               IF (r . x <> q . x) OR (r . y <> q . y) THEN
  333.                 BEGIN
  334.                   IF (r . x <> s . x) OR (r . y <> s . y) THEN
  335.                     point (r, mode);
  336.                   q := r
  337.                 END
  338.             END;
  339.           error := false
  340.         END
  341.       ELSE
  342.         error := true
  343.     END;
  344.  
  345.   PROCEDURE fill (p : pt; mode : fill_mode);
  346.  
  347.     VAR
  348.       st : state;
  349.  
  350.   FUNCTION can_go (p : pt; x, y : integer; mode : fill_mode) : boolean;
  351.  
  352.     VAR
  353.       st : state;
  354.  
  355.     BEGIN
  356. {$R-}
  357.       p . x := p . x + x;
  358.       p . y := p . y + y;
  359. {$R+}
  360.       st := status (p);
  361.       IF st = ascii_character THEN
  362.         st := off;
  363.       can_go := NOT ((st = out_of_range) OR (st = state (mode)))
  364.     END;
  365.  
  366.   PROCEDURE quick_point;
  367.  
  368.     BEGIN
  369.       IF ch_code < first_pcg_code THEN
  370.         ch_code := first_pcg_code;
  371.       CASE mode OF
  372.         draw :
  373.           ch_code := ch_code OR char_addr . value;
  374.         rub_out :
  375.           ch_code := ch_code AND NOT char_addr . value;
  376.       END;
  377.       vdu_ram [char_addr . ch_no] := ch_code
  378.     END;
  379. {$A-}
  380.  
  381.   PROCEDURE v_line (p : pt);
  382.  
  383.     forward;
  384.  
  385.   PROCEDURE h_line (p : pt);
  386.  
  387.     VAR
  388.       q, r : pt;
  389.       a : integer;
  390.  
  391.     BEGIN
  392.       q := p;
  393.       WHILE can_go (q, 1, 0, mode) DO
  394.         BEGIN
  395.           quick_point;
  396. {$R-}
  397.           q.x := q.x + 1
  398. {$R+}
  399.         END;
  400.       r := p;
  401.       WHILE can_go (r, -1, 0, mode) DO
  402.         BEGIN
  403.           quick_point;
  404. {$R-}
  405.           r.x := r.x - 1
  406. {$R+}
  407.         END;
  408.       FOR a := r.x TO p.x - 1 DO
  409.        BEGIN
  410.         p.x := a;
  411.         v_line (p)
  412.        END;
  413.       FOR a := p.x + 1 TO q.x DO
  414.        BEGIN
  415.         p.x := a;
  416.         v_line (p)
  417.        END
  418.     END;
  419.  
  420.   PROCEDURE v_line;
  421.  
  422.     VAR
  423.       q, r : pt;
  424.       a : integer;
  425.  
  426.     BEGIN
  427.       q := p;
  428.       WHILE can_go (q, 0, 1, mode) DO
  429.         BEGIN
  430.           quick_point;
  431. {$R-}
  432.           q.y := q.y + 1
  433. {$R+}
  434.         END;
  435.       r := p;
  436.       WHILE can_go (r, 0, -1, mode) DO
  437.         BEGIN
  438.           quick_point;
  439. {$R-}
  440.           r.y := r.y - 1
  441. {$R+}
  442.         END;
  443.       FOR a := r.y TO p.y - 1 DO
  444.        BEGIN
  445.         p.y := a;
  446.         h_line (p)
  447.        END;
  448.       FOR a := p.y + 1 TO q.y DO
  449.        BEGIN
  450.         p.y := a;
  451.         h_line (p)
  452.        END
  453.     END;
  454. {$A+}
  455.  
  456.     BEGIN
  457.       st := status (p);
  458.       IF st = ascii_character THEN
  459.         st := off;
  460.       IF NOT ((st = out_of_range) OR (st = state (mode))) THEN
  461.         BEGIN
  462.           quick_point;
  463.           h_line (p);
  464.           v_line (p);
  465.           error := false
  466.         END
  467.       ELSE
  468.         error := true
  469.     END;
  470. {$R-}
  471.