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