home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 300-399 / ff339.lzh / PCQ / Examples / Bezier2.p < prev    next >
Text File  |  1990-03-19  |  7KB  |  287 lines

  1. Program Bezier;
  2.  
  3. {
  4.    This program draws Bezier curves using the degree elevation
  5.    method.  For large numbers of points (more than 10, for
  6.    example) this is faster than the recursive way.
  7. }
  8.  
  9. {$I ":Include/Exec.i" for Forbid, Permit and library things }
  10. {$I ":Include/Ports.i" for the Message stuff }
  11. {$I ":Include/Intuition.i" for window & screen structures and functions }
  12. {$I ":Include/Graphics.i" for drawing stuff }
  13. {$I ":Include/Text.i" just for GText}
  14.  
  15. type
  16.     PointRec = Record
  17.         X, Y : Real;
  18.     end;
  19.     
  20. Const
  21.     w  : WindowPtr = Nil;
  22.     s  : ScreenPtr = Nil;
  23.  
  24. {  The following definitions mean that the start-up code will
  25.    not create an output window for this program if it is run
  26.    from the Workbench.  Therefore this program should NOT use
  27.    ReadLn and WriteLn. }
  28.  
  29.     StdInName : Address = Nil;
  30.     StdOutName: Address = Nil;
  31.  
  32. Var
  33.     m  : MessagePtr;
  34.     rp : RastPortPtr;
  35.  
  36.     PointCount : Short;
  37.     Points : Array [1..200] of PointRec;
  38.  
  39.     t, tprime : Real;
  40.  
  41.     LastX, LastY : Short;
  42.  
  43. Procedure CleanUpAndDie;
  44. begin
  45.     if w <> Nil then begin
  46.     Forbid;
  47.     repeat until GetMsg(w^.UserPort) = Nil;
  48.     CloseWindow(w);
  49.     Permit;
  50.     end;
  51.     if s <> Nil then
  52.     CloseScreen(s);
  53.     CloseLibrary(GfxBase);
  54.     Exit(0);
  55. end;
  56.  
  57. Function OpenTheScreen() : Boolean;
  58. var
  59.     ns : NewScreenPtr;
  60. begin
  61.     new(ns);
  62.     with ns^ do begin
  63.     LeftEdge := 0;
  64.     TopEdge  := 0;
  65.     Width    := 640;
  66.     Height   := 200;
  67.     Depth    := 2;
  68.     DetailPen := 3;
  69.     BlockPen  := 2;
  70.     ViewModes := 32768;
  71.     SType     := CUSTOMSCREEN_f;
  72.     Font      := nil;
  73.     DefaultTitle := "Simple Bezier Curves";
  74.     Gadgets   := nil;
  75.     CustomBitMap := nil;
  76.     end;
  77.     s := OpenScreen(ns);
  78.     dispose(ns);
  79.     OpenTheScreen := s <> nil;
  80. end;
  81.  
  82. Function OpenTheWindow() : Boolean;
  83. var
  84.     nw : NewWindowPtr;
  85. begin
  86.     new(nw);
  87.     with nw^ do begin
  88.     LeftEdge := 0;
  89.     TopEdge := 11;
  90.     Width := 640;
  91.     Height := 189;
  92.  
  93.     DetailPen := -1;
  94.     BlockPen  := -1;
  95.     IDCMPFlags := CLOSEWINDOW_f;
  96.     Flags := WINDOWDRAG_f + WINDOWDEPTH_f + REPORTMOUSE_f +
  97.          WINDOWCLOSE_f + SMART_REFRESH_f + ACTIVATE_f;
  98.     FirstGadget := nil;
  99.     CheckMark := nil;
  100.     Title := "Close the Window to Quit";
  101.     Screen := s;
  102.     BitMap := nil;
  103.     MinWidth := 50;
  104.     MaxWidth := -1;
  105.     MinHeight := 20;
  106.     MaxHeight := -1;
  107.     WType := CUSTOMSCREEN_f;
  108.     end;
  109.  
  110.     w := OpenWindow(nw);
  111.     dispose(nw);
  112.     OpenTheWindow := w <> nil;
  113. end;
  114.  
  115. Procedure DrawLine;
  116. begin
  117.     Move(rp, Trunc(Points[PointCount].X), Trunc(Points[PointCount].Y));
  118.     Draw(rp, LastX, LastY);
  119. end;
  120.  
  121. Procedure GetPoints;
  122. var
  123.     LastSeconds,
  124.     LastMicros    : Integer;
  125.     IM : IntuiMessagePtr;
  126.     StoreMsg : IntuiMessage;
  127.     Leave : Boolean;
  128.     OutOfBounds : Boolean;
  129.     BorderLeft, BorderRight,
  130.     BorderTop, BorderBottom : Short;
  131.  
  132.     Procedure AddPoint;
  133.     begin
  134.     Inc(PointCount);
  135.     with Points[PointCount] do begin
  136.         X := Float(StoreMsg.MouseX);
  137.         Y := Float(StoreMsg.MouseY);
  138.     end;
  139.     with StoreMsg do begin
  140.         LastX := MouseX;
  141.         LastY := MouseY;
  142.         LastSeconds := Seconds;
  143.         LastMicros := Micros;
  144.     end;
  145.     SetAPen(rp, 2);
  146.     SetDrMd(rp, JAM1);
  147.     DrawEllipse(rp, LastX, LastY, 5, 3);
  148.     SetAPen(rp, 3);
  149.     SetDrMd(rp, COMPLEMENT);
  150.     DrawLine;
  151.     end;
  152.  
  153.     Function CheckForExit : Boolean;
  154.     {   This function determines whether the user wanted to stop
  155.     entering points.  I added the position tests because my
  156.     doubleclick time is too long, and I was too lazy to dig
  157.     out Preferences to change it. }
  158.     begin
  159.     with StoreMsg do
  160.         CheckForExit := DoubleClick(LastSeconds, LastMicros,
  161.                     Seconds, Micros) and
  162.                 (Abs(MouseX - Trunc(Points[PointCount].X)) < 5) and
  163.                 (Abs(MouseY - TRunc(Points[PointCount].Y)) < 3);
  164.     end;
  165.  
  166.     Procedure ClearIt;
  167.     {  This just clears the screen when you enter your first point }
  168.     begin
  169.     SetDrMd(rp, JAM1);
  170.     SetAPen(rp, 0);
  171.     RectFill(rp, BorderLeft, BorderTop,
  172.              BorderRight, BorderBottom);
  173.     SetDrMd(rp, COMPLEMENT);
  174.     SetAPen(rp, 3);
  175.     end;
  176.  
  177. begin
  178.     ModifyIDCMP(w, CLOSEWINDOW_f + MOUSEBUTTONS_f + MOUSEMOVE_f);
  179.     SetDrMd(rp, COMPLEMENT);
  180.     PointCount := 0;
  181.     Leave := False;
  182.     OutOfBounds := False;
  183.     BorderLeft := w^.BorderLeft;
  184.     BorderRight := 639 - w^.BorderRight;
  185.     BorderTop := w^.BorderTop;
  186.     BorderBottom := 189 - w^.BorderBottom;
  187.     repeat
  188.         IM := IntuiMessagePtr(WaitPort(w^.UserPort));
  189.         IM := IntuiMessagePtr(GetMsg(w^.UserPort));
  190.         StoreMsg := IM^;
  191.         ReplyMsg(MessagePtr(IM));
  192.         case StoreMsg.Class of
  193.            MOUSEMOVE_f : if PointCount > 0 then begin
  194.                  if not OutOfBounds then
  195.                  DrawLine;
  196.                         LastX := StoreMsg.MouseX;
  197.                         LastY := StoreMsg.MouseY;
  198.                  if (LastX > BorderLeft) and
  199.                 (LastX < BorderRight) and
  200.                 (LastY > BorderTop) and
  201.                 (LastY < BorderBottom) then begin
  202.                  DrawLine;
  203.                  OutOfBounds := False;
  204.                  end else
  205.                  OutOfBounds := True;
  206.                     end;
  207.            MOUSEBUTTONS_f : if StoreMsg.Code = SELECTUP then begin
  208.                        if PointCount > 0 then
  209.                     Leave := CheckForExit
  210.                 else
  211.                     ClearIt;
  212.                        if (not Leave) and (not OutOfBounds) then
  213.                     AddPoint;
  214.                        end;
  215.            CLOSEWINDOW_f : CleanUpAndDie;
  216.         end;
  217.     until Leave or (PointCount > 50);
  218.     if not Leave then
  219.         DrawLine;
  220.     ModifyIDCMP(w, CLOSEWINDOW_f);
  221.     SetDrMd(rp, JAM1);
  222.     SetAPen(rp, 1);
  223. end;
  224.  
  225. Procedure Elevate;
  226. var
  227.     t, tprime,
  228.     RealPoints : Real;
  229.     i : Integer;
  230. begin
  231.     Inc(PointCount);
  232.     RealPoints := Float(PointCount);
  233.     Points[PointCount] := Points[Pred(PointCount)];
  234.     for i := Pred(PointCount) downto 2 do
  235.     with Points[i] do begin
  236.         t := Float(i) / RealPoints;
  237.         tprime := 1.0 - t;
  238.         X := t * Points[Pred(i)].X + tprime * X;
  239.         Y := t * Points[Pred(i)].Y + tprime * Y;
  240.     end;
  241. end;
  242.  
  243. Procedure DrawCurve;
  244. var
  245.     i : Integer;
  246. begin
  247.     Move(rp, Trunc(Points[1].X), Trunc(Points[1].Y));
  248.     for i := 2 to PointCount do
  249.     Draw(rp, Round(Points[i].X), Round(Points[i].Y));
  250. end;
  251.  
  252. Procedure DrawBezier;
  253. var
  254.     i : Short;
  255. begin
  256.     SetAPen(rp, 2);
  257.     while PointCount < 100 do begin
  258.     Elevate;
  259.     DrawCurve;
  260.     if GetMsg(w^.UserPort) <> Nil then
  261.         CleanUpAndDie;
  262.     end;
  263.     SetAPen(rp, 1);
  264.     DrawCurve;
  265. end;
  266.  
  267. begin
  268.     GfxBase := OpenLibrary("graphics.library", 0);
  269.     if GfxBase <> nil then begin
  270.     if OpenTheScreen() then begin
  271.         if OpenTheWindow() then begin
  272.             rp := w^.RPort;
  273.         Move(rp, 252, 20);
  274.         GText(rp, "Enter points by pressing the left mouse button", 46);
  275.         Move(rp, 252, 30);
  276.         GText(rp, "Double click on the last point to begin drawing", 47);
  277.         repeat
  278.             GetPoints;  { Both these routines will quit if }
  279.             DrawBezier; { the window is closed. }
  280.         until False;
  281.         end;
  282.         CloseScreen(s);
  283.     end;
  284.     CloseLibrary(GfxBase);
  285.     end;
  286. end.
  287.