home *** CD-ROM | disk | FTP | other *** search
/ AMIGA PD 1 / AMIGA-PD-1.iso / Programme_zum_Heft / Programmieren / Kurztests / ACE / Prgs / Gfx / BezierLab.lha / BezierLab.b < prev    next >
Text File  |  1994-12-03  |  19KB  |  742 lines

  1. {*
  2. ** Bezier Curve Laboratory.
  3. **
  4. ** Author: David J Benn
  5. **   Date: 29th-31st October 1994,
  6. **       1st-5th,13th,14th,21st,22nd November 1994,
  7. **       3rd December 1994
  8. **
  9. ** Algorithm for CreateBezierSpline subprogram taken (and modified) from a C
  10. ** implementation by Doug McKenna in MacTech magazine, September 1994.  
  11. *}
  12.  
  13. STRING version SIZE 20
  14. version = "$VER: BezierLab 1.1 (03.12.94)"
  15.  
  16. {*
  17. ** Misc. Constants.
  18. *}
  19. CONST nominalIndex = 1
  20. CONST default = -1&
  21. CONST NULL = 0&
  22. CONST true = -1&, false = 0&
  23.  
  24. CONST maxPoints = 16
  25. CONST xmin = 10, xmax = 620
  26. CONST ymin = 5, ymax = 170
  27.  
  28. {*
  29. ** Menu constants.
  30. *}
  31. CONST sDisable    = 0
  32. CONST sEnable    = 1
  33. CONST sCheck    = 2
  34.  
  35. CONST mProject        = 1
  36. CONST iNew        = 1
  37. CONST iOpen        = 2
  38. CONST iSave        = 3
  39. CONST iAnimate        = 4
  40. CONST iStop        = 5
  41. CONST iFast        = 6
  42. CONST iReposition    = 7
  43. CONST iSep1.1        = 8
  44. CONST iAbout        = 9
  45. CONST iQuit        = 10
  46.  
  47. {*
  48. ** Types.
  49. *}
  50. STRUCT Point2D
  51.   SHORTINT x
  52.   SHORTINT y
  53. END STRUCT
  54.  
  55. {*
  56. ** Globals.
  57. *}
  58. DIM ADDRESS path(maxPoints)
  59. DECLARE STRUCT Point2D p0, c1, c2, p3
  60. SHORTINT theMenu, theItem
  61. SHORTINT c1_deltaX, c1_deltaY, c2_deltaX, c2_deltaY 
  62. LONGINT animate, finished, fast_mode, reposition
  63. ADDRESS Rp
  64.  
  65. {*
  66. ** Events.
  67. *}
  68. ON MENU GOSUB handle_menu : MENU ON
  69.  
  70. {*
  71. ** Library functions.
  72. *}
  73. LIBRARY "graphics.library"
  74. DECLARE FUNCTION SetAPen(ADDRESS Rp, SHORTINT color_id) LIBRARY graphics
  75. DECLARE FUNCTION Move(ADDRESS Rp, SHORTINT x, SHORTINT y) LIBRARY graphics
  76. DECLARE FUNCTION Draw(ADDRESS Rp, SHORTINT x, SHORTINT y) LIBRARY graphics
  77.  
  78. {*
  79. ** Subprograms.
  80. *}
  81. SUB SetUpMenus
  82.     MENU mProject,0,sEnable,        "Project"
  83.     MENU mProject,iNew,sEnable,        "  New",     "N"
  84.     MENU mProject,iOpen,sEnable,        "  Open..."
  85.     MENU mProject,iSave,sEnable,        "  Save..."
  86.     MENU mProject,iAnimate,sEnable,        "  Animate",     "A"
  87.     MENU mProject,iStop,sEnable,        "  Stop",     "S"
  88.     MENU mProject,iFast,sCheck,        "  Fast",     "F"
  89.     MENU mProject,iReposition,sEnable,    "  Reposition",    "R"
  90.     MENU mProject,iSep1.1,sDisable,        "-------------------"
  91.     MENU mProject,iAbout,sEnable,        "  About..."
  92.     MENU mProject,iQuit,sEnable,        "  Quit",     "Q"
  93. END SUB
  94.  
  95. SUB SetUpPathArray(ADDRESS path_array, SHORTINT numPoints)
  96. {*
  97. ** Allocate memory for numPoints Point2D structures
  98. ** and initialise each array element with these.
  99. *}
  100. DIM ADDRESS path(nominalIndex) ADDRESS path_array 
  101. DECLARE STRUCT Point2D *the_point
  102. SHORTINT i
  103.  
  104.     FOR i=0 TO numPoints
  105.       the_point = ALLOC(SIZEOF(Point2D))
  106.       IF the_point <> NULL THEN 
  107.           path(i) = the_point
  108.       ELSE
  109.         MsgBox "Memory allocation failure. Aborting.", "Continue"
  110.         EXIT SUB
  111.       END IF
  112.     NEXT
  113. END SUB
  114.  
  115. SUB SetInitialCurve(ADDRESS p0_struct, ADDRESS c1_struct, ~
  116.                    ADDRESS c2_struct, ADDRESS p3_struct)
  117. {*
  118. ** Randomly determine curve end points, tension points and
  119. ** motion direction values.
  120. *}
  121. SHARED c1_deltaX, c2_deltaX, c1_deltaY, c2_deltaY 
  122. DECLARE STRUCT Point2D *p0, *c1, *c2, *p3
  123.  
  124.     '..Initialise point2D structures
  125.     p0 = p0_struct
  126.     c1 = c1_struct
  127.     c2 = c2_struct
  128.     p3 = p3_struct
  129.  
  130.     '..Set curve end-points.
  131.     p0->x = CINT(RND*(xmax-xmin))+xmin : p0->y = CINT(RND*(ymax-ymin))+ymin
  132.     p3->x = CINT(RND*(xmax-xmin))+xmin : p3->y = CINT(RND*(ymax-ymin))+ymin
  133.  
  134.     '..Set tension (control) points.
  135.     c1->x = CINT(RND*(xmax-xmin))+xmin : c1->y = CINT(RND*(ymax-ymin))+ymin
  136.     c2->x = CINT(RND*(xmax-xmin))+xmin : c2->y = CINT(RND*(ymax-ymin))+ymin
  137.  
  138.     '..Set random motion directions for each tension point.
  139.     IF RND < .5 THEN c1_deltaX = -1 ELSE c1_deltaX = 1
  140.     IF RND < .5 THEN c2_deltaX = -1 ELSE c2_deltaX = 1
  141.     IF RND < .5 THEN c1_deltaY = -1 ELSE c1_deltaY = 1
  142.     IF RND < .5 THEN c2_deltaY = -1 ELSE c2_deltaY = 1
  143. END SUB
  144.  
  145. SUB CreateBezierSpline(ADDRESS p0_struct, ADDRESS c1_struct, ~
  146.                ADDRESS c2_struct, ADDRESS p3_struct, ~
  147.                ADDRESS path_array, SHORTINT numPoints)
  148. {*
  149. ** Compute the path of a Bezier spline whose starting 
  150. ** and ending knot points are p0 and p3, and whose control 
  151. ** (tension) points are c1 and c2. The path should be stored
  152. ** in the array "path", which is expected to be able to hold
  153. ** (numPoints+1) elements, from 0 to numPoints inclusive. 
  154. ** numPoints should be a power of 2 between 2 and 32, inclusive.
  155. ** This routine can be easily generalised to 3D coordinates, and 
  156. ** is optimised for fast computation in (long) integers. 
  157. ** [Doug McKenna, MacTech, Sept. 1994, pg 72]
  158. *}
  159. SHARED Rp
  160. DECLARE STRUCT Point2D *p0, *c1, *c2, *p3, *the_point
  161. DIM ADDRESS path(nominalIndex) ADDRESS path_array
  162. LONGINT i, ax,ay, bx,by, cx,cy, curx,cury
  163. SHORTINT s1,s2,s3
  164. SHORTINT old_lastX,old_lastY, new_lastX,new_lastY
  165. SHORTINT old_currX, old_currY
  166.  
  167.     '..Deactivate event trapping.
  168.     MENU STOP
  169.  
  170.     '..Initialise point2D structures.
  171.     p0 = p0_struct
  172.     c1 = c1_struct
  173.     c2 = c2_struct
  174.     p3 = p3_struct
  175.  
  176.     curx = p0->x : cury = p0->y    '..Convert to longints
  177.     
  178.     '..Compute the integer Bezier spline cefficients, a, b and c
  179.     cx = (c1->x - curx) : cx = cx + SHL(cx,1)  '..c=3*(c1-p0) 
  180.     cy = (c1->y - cury) : cy = cy + SHL(cy,1)
  181.  
  182.     bx = (c2->x - c1->x)
  183.     bx = bx + (SHL(bx,1) - cx)  '..b=3*(c2-c1)-c
  184.     by = (c2->y - c1->y)
  185.     by = by + (SHL(by,1) - cy)
  186.  
  187.     ax = (p3->x - curx) - cx - bx  '..a=(p3-p0)-c-b
  188.     ay = (p3->y - cury) - cy - by
  189.     
  190.     CASE
  191.       numPoints = 32 : s1 = 5
  192.       numPoints = 16 : s1 = 4
  193.       numPoints =  8 : s1 = 3
  194.       numPoints =  4 : s1 = 2
  195.       default     : s1 = 1
  196.     END CASE
  197.  
  198.     s2 = s1+s1 : s3 = s2+s1  '..s2=2*s1 : s3=3*s1        
  199.  
  200.     {*
  201.     ** Scale operands up for later,
  202.     ** according to the degree in i 
  203.     ** in loop below.
  204.     *}
  205.     bx = SHL(bx,s1) : by = SHL(by,s1)
  206.     cx = SHL(cx,s2) : cy = SHL(cy,s2)
  207.  
  208.     '..s3 is up to 15 bits worth of scaling.
  209.     curx = SHL(curx,s3) : cury = SHL(cury,s3)
  210.  
  211.     {* 
  212.     ** Get i'th path point along curve from p0 to p3
  213.     ** (inclusive) and plot line segment from (i-1)'th 
  214.     ** point to i'th. Line segments associated with the
  215.     ** old curve are erased before each new segment is
  216.     ** plotted.
  217.     *}
  218.     '..Starting point.
  219.     the_point = path(0) : the_point->x = p0->x : the_point->y = p0->y
  220.     old_lastX = the_point->x : old_lastY = the_point->y
  221.     new_lastX = the_point->x : new_lastY = the_point->y
  222.  
  223.     '..Create new curve while erasing old one.
  224.     FOR i=1 TO numPoints
  225.       '..Get address of current point.
  226.       the_point = path(i)
  227.       '..Store current X and Y values.
  228.       old_currX = the_point->x : old_currY = the_point->y  
  229.       '..Calculate new coordinates.
  230.       the_point->x = SHR((i * (i * (i * ax + bx) + cx) + curx),s3)
  231.       the_point->y = SHR((i * (i * (i * ay + by) + cy) + cury),s3)
  232.       '..Erase old and draw new segment?    
  233.       IF old_currX <> the_point->x OR old_currY <> the_point->y OR ~
  234.          old_lastX <> new_lastX OR old_lastY <> new_lastY THEN
  235.         {*
  236.         ** We want raw speed, so let's use library functions rather 
  237.         ** than LINE or SETXY. These work fine, but the code below 
  238.         ** is a little faster.
  239.         *}
  240.         SetAPen(Rp, 0)
  241.         Move(Rp, old_lastX, old_lastY) : Draw(Rp, old_currX, old_currY)
  242.         SetAPen(Rp, 1)
  243.         Move(Rp, new_lastX, new_lastY) : Draw(Rp, the_point->x, the_point->y)
  244.       END IF
  245.       '..Store old coord's for start of next segment removal.
  246.           old_lastX = old_currX : old_lastY = old_currY
  247.       '..Store new coord's for start of next new segment.
  248.       new_lastX = the_point->x : new_lastY = the_point->y
  249.     NEXT
  250.  
  251.     '..Reactivate event trapping.
  252.     MENU ON
  253. END SUB
  254.  
  255. SUB PlotCurve(ADDRESS p0_struct, ADDRESS path_array, SHORTINT numPoints, ~
  256.           SHORTINT color_id)
  257. {*
  258. ** Plot current curve in the specified color.
  259. *}
  260. DECLARE STRUCT Point2D *p0, *the_point
  261. DIM ADDRESS path(nominalIndex) ADDRESS path_array
  262. SHORTINT i, lastX, lastY
  263.  
  264.     p0 = p0_struct
  265.  
  266.     COLOR color_id
  267.     lastX = p0->x : lastY = p0->y
  268.  
  269.     FOR i=1 TO numPoints
  270.       the_point = path(i)
  271.       PENUP:SETXY lastX,lastY : PENDOWN:SETXY the_point->x,the_point->y
  272.       lastX = the_point->x : lastY = the_point->y
  273.     NEXT
  274. END SUB
  275.  
  276. SUB ModifyTension(ADDRESS c1_struct, ADDRESS c2_struct)
  277. {*
  278. ** Move both tension points to next location, possibly 
  279. ** changing the direction of motion of one or both
  280. ** tension points (horizontally and/or vertically).
  281. *}
  282. SHARED c1_deltaX, c1_deltaY, c2_deltaX, c2_deltaY 
  283. DECLARE STRUCT Point2D *c1, *c2
  284.  
  285.     c1 = c1_struct
  286.     c2 = c2_struct
  287.  
  288.     '..Move tension points.
  289.     c1->x = c1->x + c1_deltaX
  290.     c2->x = c2->x + c2_deltaX
  291.     c1->y = c1->y + c1_deltaY
  292.     c2->y = c2->y + c2_deltaY
  293.  
  294.     '..Reached a minimum or maximum?
  295.     IF c1->x < xmin OR c1->x > xmax THEN c1_deltaX = -c1_deltaX
  296.     IF c2->x < xmin OR c2->x > xmax THEN c2_deltaX = -c2_deltaX
  297.     IF c1->y < ymin OR c1->y > ymax THEN c1_deltaY = -c1_deltaY
  298.     IF c2->y < ymin OR c2->y > ymax THEN c2_deltaY = -c2_deltaY
  299. END SUB
  300.  
  301. SUB MarkPoints(ADDRESS p0_struct, ADDRESS c1_struct, ~
  302.            ADDRESS c2_struct, ADDRESS p3_struct, ~
  303.            SHORTINT color_id)
  304. {*
  305. ** Mark end and tension points.
  306. *}
  307. DECLARE STRUCT Point2D *p0, *c1, *c2, *p3
  308.  
  309.       p0 = p0_struct
  310.     c1 = c1_struct
  311.     c2 = c2_struct
  312.     p3 = p3_struct
  313.  
  314.       PSET (p0->x,p0->y),color_id
  315.       PSET (c1->x,c1->y),color_id
  316.       PSET (c2->x,c2->y),color_id
  317.       PSET (p3->x,p3->y),color_id
  318. END SUB
  319.  
  320. SUB AnimateMode(LONGINT activate)
  321. {*
  322. ** Set or reset animate mode.
  323. *}
  324. SHARED animate
  325. SHARED p0, c1, c2, p3
  326.  
  327.     IF activate THEN 
  328.         '..Enable Animation Mode.
  329.         animate = true
  330.         MarkPoints(p0, c1, c2, p3, 0)
  331.         MENU mProject,iAnimate,sDisable
  332.         MENU mProject,iStop,sEnable
  333.     ELSE
  334.         '..Disable Animation Mode.
  335.         animate = false
  336.         MarkPoints(p0, c1, c2, p3, 2)
  337.         MENU mProject,iAnimate,sEnable
  338.         MENU mProject,iStop,sDisable
  339.     END IF        
  340. END SUB
  341.  
  342. SUB MakeNewCurve(ADDRESS p0_struct, ADDRESS c1_struct, ~
  343.          ADDRESS c2_struct, ADDRESS p3_struct, ~
  344.          ADDRESS path_array, SHORTINT numPoints)
  345. {*
  346. ** Initialise and plot new Bezier curve and tension/end points.
  347. *}
  348.  
  349.     AnimateMode(false)
  350.  
  351.     CLS
  352.  
  353.     SetInitialCurve(p0_struct, c1_struct, c2_struct, p3_struct)
  354.  
  355.     CreateBezierSpline(p0_struct, c1_struct, c2_struct, p3_struct, ~
  356.                path_array, numPoints)
  357.  
  358.     MarkPoints(p0_struct, c1_struct, c2_struct, p3_struct, 2)
  359. END SUB
  360.  
  361. SUB LoadCurve(ADDRESS p0_struct, ADDRESS c1_struct, ~
  362.           ADDRESS c2_struct, ADDRESS p3_struct, ~
  363.           ADDRESS path_array, SHORTINT numPoints)
  364. {*
  365. ** Load and plot an existing Bezier curve and tension/end points
  366. ** setting animation delta values as well.
  367. *}
  368. STRING theFile SIZE 80
  369. STRING id
  370. SHORTINT x,y
  371. SHARED c1_deltaX, c2_deltaX, c1_deltaY, c2_deltaY 
  372. DECLARE STRUCT Point2D *p0, *c1, *c2, *p3
  373.  
  374.     theFile = FileBox$("Load a Curve...")
  375.  
  376.     IF theFile = "" THEN 
  377.       MsgBox "No file selected.","Continue"
  378.       EXIT SUB
  379.     END IF
  380.  
  381.     OPEN "I",#1,theFile
  382.     IF HANDLE(1) = NULL THEN
  383.       MsgBox "File open error.","Continue"
  384.       EXIT SUB
  385.     ELSE    
  386.       '..Initialise point2D structures.
  387.       p0 = p0_struct
  388.       c1 = c1_struct
  389.       c2 = c2_struct
  390.       p3 = p3_struct
  391.  
  392.       '..Sanity checks.
  393.       IF EOF(1) THEN 
  394.         MsgBox "File empty!","Continue"
  395.         CLOSE #1
  396.         EXIT SUB
  397.       END IF
  398.       INPUT #1,id
  399.       IF id<>"BEZ" THEN 
  400.         MsgBox "Incorrect file type!","Continue" 
  401.         CLOSE #1
  402.         EXIT SUB
  403.       END IF
  404.  
  405.       '..Read data (assume correct format).
  406.       INPUT #1,x,y
  407.       p0->x = x : p0->y = y      
  408.       INPUT #1,x,y
  409.       c1->x = x : c1->y = y      
  410.       INPUT #1,x,y
  411.       c2->x = x : c2->y = y      
  412.       INPUT #1,x,y
  413.       p3->x = x : p3->y = y
  414.       INPUT #1,c1_deltaX
  415.       INPUT #1,c1_deltaY
  416.       INPUT #1,c2_deltaX
  417.       INPUT #1,c2_deltaY
  418.       CLOSE #1
  419.  
  420.       '..Render curve.
  421.       AnimateMode(false)
  422.       CLS
  423.       CreateBezierSpline(p0, c1, c2, p3, path_array, numPoints)
  424.       MarkPoints(p0, c1, c2, p3, 2)
  425.     END IF
  426. END SUB
  427.  
  428. SUB StoreCurve(ADDRESS p0_struct, ADDRESS c1_struct, ~
  429.            ADDRESS c2_struct, ADDRESS p3_struct)
  430. {*
  431. ** Store current Bezier curve tension/end points and
  432. ** animation delta values.
  433. *}
  434. STRING theFile SIZE 80
  435. SHARED c1_deltaX, c2_deltaX, c1_deltaY, c2_deltaY 
  436. DECLARE STRUCT Point2D *p0, *c1, *c2, *p3
  437.  
  438.     theFile = FileBox$("Store Current Curve...")
  439.  
  440.     IF theFile = "" THEN 
  441.       MsgBox "No file selected.","Continue"
  442.       EXIT SUB
  443.     END IF
  444.  
  445.     OPEN "O",#1,theFile
  446.     IF HANDLE(1) = NULL THEN
  447.       MsgBox "File open error.","Continue"
  448.       EXIT SUB
  449.     ELSE    
  450.       '..Initialise point2D structures.
  451.       p0 = p0_struct
  452.       c1 = c1_struct
  453.       c2 = c2_struct
  454.       p3 = p3_struct
  455.  
  456.       '..Write data.
  457.       WRITE #1,"BEZ"
  458.       WRITE #1,p0->x,p0->y
  459.       WRITE #1,c1->x,c1->y
  460.       WRITE #1,c2->x,c2->y
  461.       WRITE #1,p3->x,p3->y
  462.       WRITE #1,c1_deltaX
  463.       WRITE #1,c1_deltaY
  464.       WRITE #1,c2_deltaX
  465.       WRITE #1,c2_deltaY
  466.       CLOSE #1
  467.         END IF
  468. END SUB
  469.  
  470. SUB ToggleFastMode
  471. {*
  472. ** Switch between fast and slow modes.
  473. *}
  474. SHARED fast_mode
  475.  
  476.     IF fast_mode THEN 
  477.         fast_mode=false 
  478.         MENU mProject,iFast,sEnable
  479.     ELSE 
  480.         fast_mode=true
  481.         MENU mProject,iFast,sCheck
  482.     END IF
  483. END SUB
  484.  
  485. SUB plotHandles(SHORTINT color_id)
  486. {*
  487. ** Plot end and tension point handles in the specified color.
  488. *}
  489. SHARED p0, c1, c2, p3
  490.  
  491.     LINE (p0->x-4,p0->y-2)-(p0->x+4,p0->y+2),color_id,b
  492.     LINE (c1->x-4,c1->y-2)-(c1->x+4,c1->y+2),color_id,b
  493.     LINE (c2->x-4,c2->y-2)-(c2->x+4,c2->y+2),color_id,b
  494.     LINE (p3->x-4,p3->y-2)-(p3->x+4,p3->y+2),color_id,b
  495. END SUB
  496.  
  497. SUB LONGINT inHandle(ADDRESS point_struct, SHORTINT point_num, ~
  498.              SHORTINT x, SHORTINT y)
  499. {*
  500. ** Is x,y coordinate inside a handle?
  501. *}
  502. DECLARE STRUCT Point2D *the_point
  503.  
  504.     the_point = point_struct
  505.  
  506.     IF x >= the_point->x-4 AND x <= the_point->x+4 AND ~
  507.        y >= the_point->y-2 AND y <= the_point->y+2 THEN
  508.         inHandle = point_num+1
  509.     ELSE
  510.         inHandle = 0
  511.     END IF 
  512. END SUB
  513.  
  514. SUB ToggleRepositionMode
  515. {*
  516. ** Toggle repositioning mode.
  517. *}
  518. SHARED reposition, animate, fast_mode
  519. SHARED p0, c1, c2, p3, path
  520. SHORTINT n
  521.  
  522.     IF reposition THEN
  523.         '..Switch off repositioning mode.
  524.         reposition = false
  525.  
  526.         '..Reconfigure menu after leaving Reposition Mode.
  527.         FOR n = iNew TO iQuit
  528.           MENU mProject,n,sEnable
  529.         NEXT
  530.         MENU mProject,iStop,sDisable
  531.         IF fast_mode THEN MENU mProject,iFast,sCheck        
  532.         MENU mProject,iSep1.1,sDisable
  533.         
  534.         '..Erase end and tension points/handles.
  535.         PlotHandles(0)    
  536.         PlotCurve(p0, @path, maxPoints, 1)
  537.         MarkPoints(p0, c1, c2, p3, 2)    
  538.     ELSE
  539.         '..Switch on repositioning mode.
  540.         reposition = true
  541.         animate = false
  542.  
  543.         '..Disable all menu items except one.
  544.         FOR n = iNew TO iQuit
  545.             MENU mProject,n,sDisable
  546.         NEXT
  547.         MENU mProject,iReposition,sCheck
  548.  
  549.         '..Draw end and tension points/handles.
  550.         plotHandles(3)
  551.         MarkPoints(p0, c1, c2, p3, 2)
  552.     END IF
  553. END SUB
  554.  
  555. SUB RepositionPoints(ADDRESS p0_struct, ADDRESS c1_struct, ~
  556.              ADDRESS c2_struct, ADDRESS p3_struct, ~
  557.              ADDRESS path_array, SHORTINT numPoints)
  558. {*
  559. ** Allow user to reposition the end and tension points.
  560. *}
  561. SHARED reposition
  562. DECLARE STRUCT Point2D *p0, *c1, *c2, *p3, *second_point, last_p0
  563. DIM ADDRESS path(nominalIndex) ADDRESS path_array
  564. SHORTINT n, mouseX,mouseY, oldMouseX,oldMouseY, pt
  565. SINGLE time0
  566.  
  567.     '..Initialise structure variables.
  568.       p0 = p0_struct
  569.     c1 = c1_struct
  570.     c2 = c2_struct
  571.     p3 = p3_struct
  572.  
  573.     '..Await left mouse button click.
  574.     WHILE reposition AND NOT MOUSE(0):WEND
  575.     '..Debounce button press.
  576.     time0 = TIMER : WHILE reposition AND TIMER < time0+.1:WEND  
  577.         
  578.     oldMouseX = MOUSE(1) : oldMouseY = MOUSE(2)
  579.     
  580.       IF reposition AND MOUSE(0) THEN
  581.       '..Is mouse pointer inside a handle?
  582.       pt = inHandle(p0, 0, oldMouseX, oldMouseY)
  583.       IF pt = 0 THEN pt = inHandle(c1, 1, oldMouseX, oldMouseY)
  584.       IF pt = 0 THEN pt = inHandle(c2, 2, oldMouseX, oldMouseY)
  585.       IF pt = 0 THEN pt = inHandle(p3, 3, oldMouseX, oldMouseY)
  586.  
  587.       IF pt THEN
  588.         '..Remove end/tension points and handles then redraw curve.
  589.         PlotHandles(0)
  590.         MarkPoints(p0, c1, c2, p3, 0)
  591.         PlotCurve(p0, path_array, numPoints, 1)
  592.       END IF
  593.  
  594.       WHILE reposition AND MOUSE(0) 
  595.         '..Compare new mouse position with old.
  596.         mouseX = MOUSE(1) : mouseY = MOUSE(2)
  597.  
  598.         IF mouseX <> oldMouseX OR mouseY <> oldMouseY THEN
  599.         '..Reached any limits?
  600.         IF mouseX < xmin THEN mouseX = xmin
  601.         IF mouseX > xmax THEN mouseX = xmax
  602.         IF mouseY < ymin THEN mouseY = ymin
  603.         IF mouseY > ymax THEN mouseY = ymax
  604.  
  605.         '..Save p0 (see below).
  606.         last_p0->x = p0->x
  607.         last_p0->y = p0->y
  608.  
  609.               '..Change coordinates?
  610.             CASE
  611.                   pt = 1 : p0->x = mouseX : p0->y = mouseY
  612.                   pt = 2 : c1->x = mouseX : c1->y = mouseY
  613.                   pt = 3 : c2->x = mouseX : c2->y = mouseY
  614.                   pt = 4 : p3->x = mouseX : p3->y = mouseY
  615.             END CASE
  616.  
  617.           '..Remove end/tension points and handles then redraw curve.
  618.           PlotHandles(0)
  619.           MarkPoints(p0, c1, c2, p3, 0)
  620.           PlotCurve(p0, path_array, numPoints, 1)
  621.  
  622.         {* 
  623.         ** Since p0 is treated as a special case by CreateBezierSpline
  624.         ** check to see whether it has been moved. If so, erase first curve
  625.         ** segment as it would otherwise be missed (by CreateBezierCurve).
  626.         *}
  627.         IF p0->x <> last_p0->x OR p0->y <> last_p0->y THEN
  628.           second_point = path(1)
  629.           LINE (last_p0->x,last_p0->y)-(second_point->x,second_point->y),0
  630.         END IF
  631.  
  632.               '..Redraw curve.
  633.               CreateBezierSpline(p0, c1, c2, p3, path_array, numPoints)
  634.  
  635.         '..Save last (used) mouse position.
  636.         oldMouseX = mouseX : oldMouseY = mouseY
  637.         END IF
  638.       WEND
  639.  
  640.       '..Refresh curve and redraw end and tension points/handles.
  641.       PlotCurve(p0, path_array, numPoints, 1)
  642.       plotHandles(3)
  643.       MarkPoints(p0, c1, c2, p3, 2)
  644.     END IF    
  645. END SUB
  646.  
  647. SUB AboutBox
  648. SHORTINT buttonX, buttonY
  649.  
  650.     WINDOW 9,"About this program...",(220,25)-(420,175),2
  651.     buttonX = SCREEN(5) : buttonY = SCREEN(6)
  652.     buttonTxt$ = "Continue"
  653.     GADGET 255,ON,buttonTxt$,(100-(buttonX*LEN(buttonTxt$))\2-4,125-buttonY\2-2)- ~
  654.                         (100+(buttonX*LEN(buttonTxt$))\2+4,125+buttonY\2+2), ~
  655.                  BUTTON
  656.     COLOR 1
  657.     LOCATE 2
  658.     RESTORE
  659.     REPEAT
  660.       READ text$
  661.       IF text$ <> "END" THEN 
  662.         CASE
  663.         text$ = "BezierLab" : FONT "diamond",20 : STYLE 4
  664.         text$ = "for Karen"     : FONT "ruby",8 : STYLE 2
  665.         default           : FONT "opal",12 : STYLE 0
  666.         END CASE
  667.         PRINT PTAB(100-(WINDOW(12)*LEN(text$))\2);text$
  668.       END IF
  669.     UNTIL text$ = "END"
  670.     DATA "BezierLab","","","version 1.1","","by David J Benn"
  671.     DATA "","for Karen","END"
  672.     GADGET WAIT 255
  673.     GADGET CLOSE 255
  674.     WINDOW CLOSE 9
  675. END SUB
  676.  
  677. SUB Quit
  678. {*
  679. ** Exit program? 
  680. *}
  681. SHARED finished
  682.  
  683.   IF MsgBox("Really leave BezierLab?","Yes","No") THEN finished = true
  684. END SUB
  685.  
  686. {*
  687. ** Main.
  688. *}
  689. WINDOW 1,"Bezier Curve Laboratory",(0,10)-(640,200),22
  690. Rp = WINDOW(8)
  691.  
  692. SetUpMenus
  693. SetUpPathArray(@path, maxPoints)
  694.  
  695. RANDOMIZE TIMER
  696.  
  697. MakeNewCurve(p0, c1, c2, p3, @path, maxPoints)
  698.  
  699. finished = false
  700. fast_mode = true
  701. reposition = false
  702.  
  703. REPEAT
  704.   IF animate THEN 
  705.       ModifyTension(c1, c2)
  706.       CreateBezierSpline(p0, c1, c2, p3, @path, maxPoints)
  707.   ELSE
  708.     IF reposition THEN
  709.         RepositionPoints(p0, c1, c2, p3, @path, maxPoints)
  710.     END IF    
  711.   END IF
  712.  
  713.   IF NOT fast_mode THEN SLEEP FOR .02
  714. UNTIL finished
  715.  
  716. MENU OFF
  717.  
  718. WINDOW CLOSE 1
  719. END
  720.  
  721. {*
  722. ** Event handlers.
  723. *}
  724. handle_menu:
  725.   theMenu = MENU(0)
  726.   theItem = MENU(1)
  727.   
  728.   IF theMenu = mProject THEN
  729.         CASE 
  730.         theItem = iNew           : MakeNewCurve(p0, c1, c2, p3, @path, maxPoints)
  731.         theItem = iOpen        : LoadCurve(p0, c1, c2, p3, @path, maxPoints)
  732.         theItem = iSave        : StoreCurve(p0, c1, c2, p3)
  733.         theItem = iAnimate     : AnimateMode(true)
  734.         theItem = iStop        : AnimateMode(false)
  735.         theItem = iFast        : ToggleFastMode
  736.         theItem = iReposition     : ToggleRepositionMode
  737.         theItem = iAbout       : AboutBox
  738.         theItem = iQuit           : Quit 
  739.       END CASE
  740.   END IF
  741. RETURN
  742.