program AcidFX;

{$N+}

uses
  Dos, Crt, Graph;

var
  DefInt8: Pointer;
  Tick: Word;

{ Процедура обработки Int 8 (IRQ0) }
procedure Int8; interrupt;
begin
  Inc(Tick);
  if Tick and 3 = 0 then
    asm
      pushf          { вызов стандартного обработчика каждый 4 тик }
      call DefInt8
    end
  else
    asm
      mov al,20h     { сброс PIC }
      out 20h,al
    end;
end;

{ Инициализация таймера }
procedure InitTimer;
begin
  GetIntVec(8, DefInt8);
  SetIntVec(8, @Int8);
  Port[$43] := $36; { режим работы: канал 0 - генератор меандера }
  Port[$40] := $40; { младший байт коэффициента деления канала 0 }
  Port[$40] := 0;   { младший байт коэффициента деления канала 0 }
  { частота таймера ~= 72.83 Гц - в 4 раза выше стандартной }
end;

{ Финализация таймера }
procedure DoneTimer;
begin
  SetIntVec(8, DefInt8);
  Port[$43] := $36;
  Port[$40] := 0;
  Port[$40] := 0;
end;

const
  MaxRadius = 100;

const
  gd: Integer = EGA;
  gm: Integer = EGAHI;

var
  nt: Word;
  Page,
  ym, xm, x, y,
  r, dr,
  k1, k2, k3: Integer;
  a, k: Double;

procedure SetCoef;
begin
  k1 := 1 + Random(20);
  k2 := 1 + Random(20);
  k3 := 1 + Random(20);
end;

begin
  Randomize;

  InitGraph(gd, gm, 'd:\lang\bp\bgi');
  InitTimer;

  xm := GetMaxX;
  ym := GetMaxY;
  Page := 0;

  a := 0;
  r := 0;
  dr := 1;
  SetCoef;
  repeat
    nt := Tick + 1;

    SetActivePage(Page);
    Page := Page xor 1;
    SetVisualPage(Page);

    ClearViewport;

    x := MaxRadius;
    while x < xm - MaxRadius do
      begin
        k := x / xm;
        y := MaxRadius + Round(Sin(a + k1 * k) * r);
        MoveTo(x + Round(Sin(a + k2 * k) * r), y);
        LineTo(x + Round(Cos(a + k3 * k) * r), ym - y);
        Inc(x, 16);
      end;
    Inc(r, dr);
    if r < 0 then
      begin
        r := 0;
        dr := 1;
        SetCoef;
      end
    else
      if r > MaxRadius then
        begin
          r := MaxRadius;
          dr := -1;
        end;
    a := a + 0.1;

    while Tick < nt do;
  until KeyPressed;
  ReadKey;

  DoneTimer;
  CloseGraph;
end.