home *** CD-ROM | disk | FTP | other *** search
/ 17 Bit Software 2: Collection B / 17Bit_Collection_B.iso / files / 1843.dms / in.adf / Mandelbrot / mandedge3.jf < prev    next >
Encoding:
Text File  |  1992-03-31  |  18.7 KB  |  620 lines

  1. \ Copyright 1989 NerveWare
  2. \ No portion of this code may used for commercial purposes,
  3. \ nor may any executable version of this code be disributed for 
  4. \ commercial purposes without the author's express written permission.
  5. \ This code is shareware, all rights reserved.
  6. \ Nick Didkovsky                                                    1/25/89
  7.  
  8. \                             MandEdge3.JF
  9.  
  10. \ Main File
  11. \ written in JForth v2.0
  12.  
  13. \ This approach to generating the Mandelbrot set relies on the fact that
  14. \ the set is connected.  
  15. \ The connectedness of the Mandelbrot set guarantees
  16. \ that an area surrounded by Mandelbrot pixels will be filled
  17. \ with Mandelbrot pixels.
  18. \ This program uses edge detection on the set whenever it is 
  19. \ encountered: surrounds the set, marks the interior, and thereby
  20. \ protects the algorithm (and your valuable time) from having to 
  21. \ calculate costly interior points!
  22. \ None of these interior points will be calculated.  
  23. \ The amount of time this saves is tremendous, 
  24. \ as it is exactly these points that would take the most computation time.
  25.  
  26.  
  27. \ A requested region is first padded with a one-pixel wide frame on top, 
  28. \ bottom, left, and right, to prevent edge detection from running off the 
  29. \ screen.
  30.  
  31. \ Full 640x400 screen stored in two 32k tables. One table to bit-mark a pixel
  32. \ whether it was calculated yet or not, and one table to bit-mark a pixel 
  33. \ whether it is in the mandelbrot set or not.
  34.  
  35. \ MOD: added "screen" menu strip.                ND 2/16/89
  36. \ MOD: checking for new-screen? flag to change resolutions      ND 2/16/89
  37. \ MOD: fixed bug in singleton? check if point already calc'ed   ND 2/17/89
  38. \ MOD: logto ram:MandelbrotSession for fun            ND 2/17/89
  39. \ MOD: slight speedup, including MandelBitMasks.ASM        ND 2/18/89
  40. \ MOD: ONLY marking edge and interior points!            ND 2/18/89
  41. \ MOD: Checking for events in PadRegion also            ND 2/20/89
  42. \ MOD: includes small-buffered iff-save code                    4/6/89
  43. \ MOD: adding final text credits                        4/6/89
  44. \ MOD: using Fast.Draw ( x y color -- ) to draw lines for color runs    6/10/89
  45. \ MOD: only checking ev.getclass once every 8 inner loops        6/10/89
  46. \ MOD: using color lookup table                     6/10/89
  47. \ MOD: changed 8 MOD to 7 AND in markinterior            6/13/89
  48. \ MOD: eliminated num-skipped in markinterior            6/13/89
  49. \ MOD: using MandelBitMasks2.ASM now                6/13/89
  50. \ MOD: Code body of SetNewNeighborStart, NextNeighbor, SetXYcurrent moved
  51. \     into FindEdge directly - saves a few jsr's         6/13/89
  52.  
  53. include? mandelbrot.ev.loop MandelEvMenus.JF
  54. include? mark.point MandelBitMasks2.ASM
  55. include? $logto ju:logto
  56. include? report.mandel.time MandelMeasure.jf
  57. include? byetext byetext.jf
  58. include? fast.draw FastLine.jf
  59. include? build.lookup ColorLookup.jf
  60.  
  61. anew task-mandeledge
  62.  
  63.  
  64. decimal
  65.  
  66.  
  67. \ ************* FIND A MANDELBROT EDGE STARTING AT A GIVEN PIXEL **********
  68. \ The 8-neighbors of pixel P are coded as shown below:
  69. \
  70. \                  5 6 7      
  71. \                  4 P 0
  72. \                  3 2 1      
  73. \
  74. \ Given a mandelbrot set edge pixel P, we find the next edge pixel
  75. \ by checking its 8-neighbors for mandelbrot set membership.  
  76. \ Start at neighbor 0 and continue
  77. \ clockwise until the first 8-neighbor is found to be in the set.
  78. \ Jump to this new pixel Q ... search for the next edge pixel by starting
  79. \ with 5+NeighborNumber modulo 8.  That is, if Q was discovered at 2,
  80. \ jump to Q and search for the next at Q's 8-neighbor#7
  81. \ We're sort of rolling around the edge with a clockwise spin.
  82.  
  83. variable CurrentNeighbor
  84. variable Xstart
  85. variable Ystart
  86. variable Xneighbor
  87. variable Yneighbor
  88. variable Xcurrent
  89. variable Ycurrent
  90. variable Ymax           \ these three used to limit interior point marking
  91. variable Xmax
  92. variable Xmin
  93. variable last-iteration
  94. variable inside-flag
  95.  
  96. \ MOD: moved body of this code into FindEdge        6/13/89
  97. \ : NEXTNEIGHBOR ( -- )
  98. \   CurrentNeighbor @ 1+ 7 and CurrentNeighbor !
  99. \ ;
  100.  
  101. \ MOD: moved body of this code into FindEdge        6/13/89
  102. \ : SETNEWNEIGHBORSTART ( --  )
  103. \   CurrentNeighbor @ 5 + 7 and CurrentNeighbor !
  104. \ ;
  105.  
  106. : PN ( -- )
  107.   Xneighbor @ . space Yneighbor @ . cr
  108. ;
  109.  
  110. : SETXYNEIGHBOR ( CurrentNeighbor -- )
  111.   case 0 of Xcurrent @ 1+ Xneighbor ! Ycurrent @    Yneighbor ! endof
  112.        1 of Xcurrent @ 1+ Xneighbor ! Ycurrent @ 1+ Yneighbor ! endof
  113.        2 of Xcurrent @    Xneighbor ! Ycurrent @ 1+ Yneighbor ! endof
  114.        3 of Xcurrent @ 1- Xneighbor ! Ycurrent @ 1+ Yneighbor ! endof
  115.        4 of Xcurrent @ 1- Xneighbor ! Ycurrent @    Yneighbor ! endof
  116.        5 of Xcurrent @ 1- Xneighbor ! Ycurrent @ 1- Yneighbor ! endof
  117.        6 of Xcurrent @    Xneighbor ! Ycurrent @ 1- Yneighbor ! endof
  118.        7 of Xcurrent @ 1+ Xneighbor ! Ycurrent @ 1- Yneighbor ! endof
  119.   endcase
  120. ;
  121.  
  122. \ MOD: moved body of this code into FindEdge        6/13/89
  123. \ Set the current edge pixel, and update Ymax if necessary
  124. \ : SetXYcurrent ( -- )
  125. \  Xneighbor @ dup dup Xcurrent ! Xmax @ max Xmax ! Xmin @ min Xmin !
  126. \  Yneighbor @ dup Ycurrent ! Ymax @ max Ymax !
  127. \ ;
  128.  
  129. \ 64000 calls to 0 0 SETABCONST take 10.56 sec. 256000 calls take 42.00 sec
  130. \ ASM version below takes:            7.22 sec. and               29.08 sec
  131. \ : SETABCONST ( x y -- )
  132. \  ygap @ * bcorner @ swap - bconst !
  133. \  xgap @ * acorner @ + aconst !
  134. \ ;
  135.  
  136. ASM SetABconst ( x y -- )
  137. \ bconst first
  138. callcfa     ygap            ( -- x y ^ygap )
  139. move.l        $0(org,tos.l),tos    ( -- x y ygap )
  140. move.l        (dsp)+,d0        ( -- x ygap)
  141. muls.l        d0,tos            ( -- x y*ygap )
  142. callcfa        bcorner            ( -- x y*ygap ^bcorner )
  143. move.l        $0(org,tos.l),tos    ( -- x y*ygap bcorner )
  144. move.l         (dsp)+,d0        ( -- x bcorner , y*ygap in d0 )
  145. neg.l        d0            ( -- x bcorner , -y*ygap in d0 )
  146. add.l        d0,tos            ( -- x bcorner-y*ygap )
  147. callcfa        bconst            ( -- x bcorner-y*ygap ^bconst )
  148. move.l        (dsp)+,$0(org,tos.l)    ( -- x ^bconst )
  149. move.l        (dsp)+,tos        ( -- x )
  150. \ aconst now
  151. callcfa        xgap            ( -- x ^xgap)
  152. move.l        $0(org,tos.l),tos    ( -- x    xgap)
  153. move.l        (dsp)+,d0        ( -- xgap)
  154. muls.l        d0,tos            ( -- x*xgap)    
  155. callcfa        acorner            ( -- x*xgap ^acorner)
  156. move.l        $0(org,tos.l),tos    ( -- x*xgap acorner)
  157. add.l        (dsp)+,tos        ( -- x*xgap+acorner)
  158. callcfa     aconst            ( -- x*xgap+acorner ^aconst)
  159. move.l        (dsp)+,$0(org,tos.l)    ( -- ^aconst)
  160. move.l        (dsp)+,tos        ( -- )
  161. end-code
  162.  
  163. \ returns true if a pixel has no NEW mandelbrot 8-neighbors
  164.  
  165. : SINGLETON? ( x y -- true | false, sets CurrentNeighbor if false )
  166.   2dup 0 FastWritePixel
  167.   2dup mark.mandelbrot.point
  168.   2dup SetABconst
  169.   dup Ystart ! Ycurrent !
  170.   dup Xstart ! Xcurrent !
  171.   true              (  -- true)
  172.   8 0 do
  173.     i SetXYneighbor
  174.       Xneighbor @ Yneighbor @ 2dup get.point
  175.     IF-NOT
  176.         2dup 2dup SetABconst
  177.     quick.guts     ( -- true x y x y iter)
  178.     dup>r color-lookup + c@ FastWritePixel
  179.     r> mandelmax = IF mark.mandelbrot.point 
  180.                           i CurrentNeighbor ! 
  181.                           drop false leave
  182.                        ELSE mark.non.point 
  183.                        THEN
  184.        ELSE 2drop
  185.        THEN ( if neighbor not already marked)
  186.   loop
  187. \  blacken.last.xy
  188. ;
  189.  
  190. \ CurrentNeighbor value set by a call to singleton? that returned false.
  191.  
  192. : FINDEDGE ( -- )
  193.   BEGIN
  194.      CurrentNeighbor @ SetXYneighbor
  195.      Xneighbor @ Yneighbor @ get.point  ( -- false | mask )
  196.      IF-NOT                          ( if not marked, do quick.guts)
  197.         Xneighbor @ Yneighbor @ 2dup SetABconst ( -- x y)
  198.             quick.guts             ( -- x y iter)
  199.                 >r 2dup r@                       ( -- x y x y iter) ( -R- iter)
  200.                 color-lookup + c@ FastWritePixel ( -- x y)
  201.                 r@ mark.point  r> MandelMax =      ( -- mandelflag )
  202.       ELSE                              ( else check if it's mandelbrot point)
  203.                 Xneighbor @ Yneighbor @ get.mandelbrot.point  ( -- mandelflag )
  204.     THEN
  205.     IF              \ if it is a mandelbrot point
  206.         ( SetXYcurrent)
  207.           Xneighbor @ dup dup Xcurrent ! 
  208.         Xmax @ max Xmax ! 
  209.         Xmin @ min Xmin !
  210.           Yneighbor @ dup Ycurrent ! 
  211.         Ymax @ max Ymax !
  212.         ( SetNewNeighborStart)
  213.           CurrentNeighbor @ 5 + 7 and CurrentNeighbor !
  214.     ELSE            \ otherwise repeat with the next neighbor
  215.         ( NextNeighbor)
  216.           CurrentNeighbor @ 1+ 7 and CurrentNeighbor !
  217.     THEN
  218. \ arbitrarily check mouse event every so often, not always
  219.  CurrentNeighbor @ 0= IF
  220.           gr-curwindow @ ev.getclass ?dup
  221.          IF handle.mandelbrot.event
  222.          THEN
  223.     THEN
  224.   restart? @ quit? @ OR new-values? @ OR new-screen? @ OR  ( exit mouse signal)
  225.   Xcurrent @ Xstart @ = Ycurrent @ Ystart @ = AND ( exit from edge finished)
  226.   OR
  227. \ how's that for a disgusting sequence of exit conditions?        
  228.   UNTIL 
  229. \  blacken.last.xy
  230. ;
  231.  
  232. \ *************************** IsoMandelPlot **********************************
  233. \ Plot region, call FindEdge whenever a non-singleton mandelbrot pixel
  234. \ is discovered. 
  235.  
  236. variable NumSkipped
  237.  
  238. \ counts from xstart through MandelPixels on that row.  Used to
  239. \ increment +loop in IsoMandelPlot
  240. : COUNTNUMSKIPPED ( -- )
  241.   Xstart @ Xcurrent !
  242.   BEGIN
  243.     Xcurrent @ Ystart @ get.mandelbrot.point
  244.   WHILE
  245.     1 Xcurrent +!
  246.   REPEAT
  247.   Xcurrent @ Xstart @ - 1+ NumSkipped !
  248. ;
  249.     
  250.     
  251. \ Starts at Yth row to Ymax'th row 
  252. \ marks all pixels between mandelbrot set boundaries.
  253.  
  254. \ variable interior-skipped - no longer used -
  255.  
  256. \ old code: 19.63 sec for full lores mandelbrot screen (pure black) 
  257. \ new code: 17.43 sec for full lores mandelbrot screen
  258. \ with MandelBitMasks3.ASM: 16.06 sec
  259.  
  260. : MARKINTERIOR ( y -- )
  261.   wait.pointer
  262.   >r Xmin @ r@ Xmax @ Ymax @ gr.highlight
  263.   Ymax @ r@ do
  264.       Xmax @ 1+ Xmin @ do
  265.           i j get.mandelbrot.point
  266.       IF
  267.          0            ( -- 0, init interior-skipped counter)
  268.         BEGIN
  269.            dup i + j mark.non.point    ( -- int-skip)
  270.            1+            ( -- int-skip+1)
  271.            dup i + j
  272.           2dup get.point    ( -- int-skip x y marked-flag)
  273.  
  274. \ ************** OLD CODE START ****************
  275. \ 0 interior-skipped !                 
  276. \ BEGIN
  277. \ i interior-skipped @ + j MARK.NON.POINT      
  278. \ 1 interior-skipped +!                   
  279. \ i interior-skipped @ + j ( check next pixel)     
  280. \ 2dup get.point           ( -- x y marked-flag)     
  281. \ ************ OLD CODE END *****************
  282.  
  283. \ next IF-THEN-ELSE sets up UNTIL's exit flag
  284.                        IF  get.mandelbrot.point not ( -- flag )
  285.                        ELSE 2drop false             ( -- false)
  286.                        THEN
  287. \ escape when a marked point is found that is not a mandelbrot point
  288.         UNTIL    ( -- int-skipped)
  289.  
  290. \ interior-skipped @ ( leave skipped amount on stack for +loop)
  291.  
  292.       ELSE 1           ( leave 1 on stack for +loop)
  293.       THEN
  294.        +loop
  295.    loop
  296. Xmin @ r> Xmax @ Ymax @ gr.dehighlight
  297. crosshairs.pointer
  298. ;
  299.  
  300. \ This routine plots a pixel-width border around region.  Pixels are marked
  301. \ as being non-mandelbrot points regardless of whether they are or not,
  302. \ so as to stop future edge detection from running off the screen.
  303. \ MOD: added checking for mouse events.  This routine looks disgusting now.
  304.  
  305. : PADREGION.HANDLE.LINE ( x y iter -- )
  306.   dup>r last-iteration @ = IF-NOT        \ if new iteration value
  307.      2dup ( -- x y x y) ( -r- iter)
  308.     last-iteration @ mandelmax = 
  309.         IF-NOT
  310.          last-iteration @ color-lookup + c@
  311.          ( -- x y x y colornum)     ( -r- iter)
  312.          fast.draw     ( -- x y)     ( -r- iter)
  313.         ELSE 2drop
  314.         THEN
  315.             fast.move    ( -- )         ( -r- iter)
  316.         r> last-iteration !
  317.     ELSE 2drop rdrop    ( -- )         ( -r-)
  318.     THEN
  319. ;
  320.  
  321. : PADREGION ( -- )
  322.  
  323. \ TOP ROW LEFT TO RIGHT
  324.   0 0 fast.move 0 0 mark.non.point
  325.   bcorner @ bconst !
  326.   acorner @ aconst !
  327.   quick.guts last-iteration !
  328.   mandel-width @ 1 do
  329.         i xgap @ * acorner @ + aconst !
  330.     i 0 quick.guts ( -- x y iter )
  331.     padregion.handle.line
  332.         i 0 mark.non.point
  333.             gr-curwindow @ ev.getclass ?dup
  334.             IF handle.mandelbrot.event
  335.                 THEN
  336.                 restart? @ quit? @ or new-values? @ or new-screen? @ or 
  337.         IF leave 
  338.         THEN
  339.   loop
  340.   last-iteration @ mandelmax = IF-NOT
  341.     mandel-width @ 0 last-iteration @ color-lookup + c@
  342.     fast.draw
  343.     THEN
  344.  
  345. \ RIGHT COLUMN TOP TO BOTTOM
  346.   mandel-width @ 1- 0 2dup fast.move mark.non.point
  347.   acorner @ mandel-width @ 1- xgap @ * + aconst !
  348.   bcorner @ bconst !
  349.   quick.guts last-iteration !
  350.   mandel-height @ ( 1- ) 1 do
  351.         bcorner @ i ygap @ * - bconst !
  352.     mandel-width @ 1- i quick.guts ( -- x y iter )
  353.     padregion.handle.line
  354.     mandel-width @ 1- i  mark.non.point
  355.             gr-curwindow @ ev.getclass ?dup
  356.             IF handle.mandelbrot.event
  357.                 THEN
  358.                 restart? @ quit? @ or new-values? @ or new-screen? @ or 
  359.         IF leave 
  360.         THEN
  361.   loop
  362.  
  363.   last-iteration @ mandelmax = IF-NOT
  364.     mandel-width @ 1- mandel-height @
  365.     last-iteration @ color-lookup + c@ 
  366.     fast.draw
  367.     THEN
  368.  
  369. \ BOTTOM ROW RIGHT TO LEFT
  370.   mandel-width @ 1- mandel-height @ 1- 2dup fast.move mark.non.point
  371.   bcorner @ mandel-height @ 1- ygap @ * - bconst !
  372.   acorner @ mandel-width @ 1- xgap @ * + aconst !
  373.   quick.guts last-iteration !
  374.   0 mandel-width @ 2 - -do
  375.         i xgap @ * acorner @ + aconst !
  376.     i mandel-height @ 1- quick.guts 
  377.         padregion.handle.line
  378.         i mandel-height @ 1-  mark.non.point  
  379.             gr-curwindow @ ev.getclass ?dup
  380.             IF handle.mandelbrot.event
  381.                 THEN
  382.                 restart? @ quit? @ or new-values? @ or new-screen? @ or 
  383.         IF leave 
  384.         THEN       
  385.   1 -loop
  386.  
  387.   last-iteration @ mandelmax = IF-NOT
  388.     0 mandel-height @ 1-
  389.     last-iteration @ color-lookup + c@
  390.     fast.draw
  391.     THEN
  392.  
  393. \ LEFT COLUMN BOTTOM TO TOP
  394.   0 mandel-height @ 1- 2dup fast.move mark.non.point
  395.   acorner @ aconst !
  396.   bcorner @ mandel-height @ 1- ygap @ * - bconst !
  397.   quick.guts last-iteration !
  398.   0 mandel-height @ 2 - -do    
  399.         bcorner @ i ygap @ * - bconst !
  400.         acorner @ aconst !
  401.         0 i quick.guts 
  402.         padregion.handle.line
  403.     0 i mark.non.point
  404.             gr-curwindow @ ev.getclass ?dup
  405.             IF handle.mandelbrot.event
  406.                 THEN
  407.                 restart? @ quit? @ or new-values? @ or new-screen? @ or 
  408.         IF leave 
  409.         THEN
  410.   1 -loop
  411.  
  412.   last-iteration @ mandelmax = IF-NOT
  413.     0 0
  414.     last-iteration @ color-lookup + c@
  415.     fast.draw
  416.     THEN
  417. ;
  418.  
  419. \ close old screen, open new screen, attach menus, used when changing resolution
  420. : CLOSE.AND.OPEN ( -- )
  421.   close.mandelscreen
  422.   open.mandelscreen
  423.   show-title? on
  424.   gr-curwindow @ Mandelbrot-Menu-1 SetMenuStrip()
  425.   crosshairs.pointer
  426.   build.lookup
  427. ;
  428.  
  429. \ IsoMandelPlot plots the entire region, vigilant for mandelbrot pixels, 
  430. \ in which case it will branch off and surround the set by edge detecting.
  431. \ Then it marks all interior points as though already calculated.
  432.  
  433. \ MOD: Accumulates runs of the same iteration, plotting LINES of same color
  434. \ instead of pixel-by-pixel POINTS (very fast - saves 2 mins in 640x400 res).
  435.  
  436. : ISOMANDELPLOT ( -- )
  437.  
  438. \ Initialize a new region
  439.    set.mandel.start.time
  440.    show-title? @ IF toggle.title THEN ( no title bar when calc new region)
  441.    gr.clear
  442.    clear.tables
  443.    PadRegion
  444.  
  445. \ Y loop starts
  446.    mandel-height @ 1- 1 DO
  447.      1 i fast.move
  448.          1 i SetABconst
  449.      1 i quick.guts dup last-iteration ! color-lookup + c@ FastWritePixel
  450. \       blacken.last.xy
  451.      1 i last-iteration @ mark.point
  452.      -1 inside-flag !
  453. \ X loop starts    
  454.      mandel-width @ 1- 2 DO
  455.           1 NumSkipped ! \ +loop default, may be changed by CountNumSkipped
  456.       i j get.point
  457.         IF-NOT    ( if not already calculated ... )
  458.         \ if scan was inside precalced region, reset starting pos
  459.              inside-flag @ IF i j fast.move THEN
  460.             0 inside-flag !
  461.                   i j 2dup SetABconst
  462.                 quick.guts        ( -- x y iter)
  463.                    dup>r        ( -- x y iter) ( -r- iter)
  464.  
  465. \ Handle line
  466.             last-iteration @ =  ( -- x y )     ( -r- iter)
  467.              IF-NOT         \ if new iteration value
  468.               2dup ( -- x y x y)     ( -r- iter)
  469.               last-iteration @ color-lookup + c@
  470.             ( -- x y x y colornum)     ( -r- iter)
  471.               fast.draw     ( -- x y)     ( -r- iter)
  472.                   fast.move        ( -- )         ( -r- iter)
  473.               r@ last-iteration !
  474.                  ELSE 2drop        ( -- )         ( -r- iter)
  475.              THEN    \ if-not same iteration value
  476.  
  477. \ Check for beginning of mandelbrot edge
  478.                   r> mandelmax = 
  479.                 IF
  480.                     i j Singleton?  
  481.              IF-NOT
  482.                  j Ymax !
  483.                              i dup Xmax ! Xmin !
  484.                      FindEdge
  485.                              restart? @ quit? @ OR 
  486.                              new-values? @ OR new-screen? @ OR 
  487.                              IF leave THEN
  488.                  j MarkInterior
  489.                          CountNumSkipped
  490. \ Jump the pen ahead if just skipped over more than one pixel
  491.                     NumSkipped @ 1 > 
  492. \ 1+ ???
  493.                 IF i ( 1+) NumSkipped @ + j fast.move  
  494.                 THEN
  495.  
  496.              THEN      \ if-not singleton?
  497.                 THEN      \ if mandelmax
  498.                   ELSE         \ else if already calculated
  499.             inside-flag @ IF-NOT \ if we were just accumulating...
  500.                 i 1- j
  501.                       last-iteration @ color-lookup + c@
  502.                         ( -- x y colornum)
  503.                       fast.draw     ( -- )
  504.                 THEN    \ ...then draw line before going inside
  505.             -1 inside-flag !
  506.           THEN        \ if-not already calculated
  507.  
  508. \ Check for mouse event once every 8 inner loops
  509.         i 7 and 0= 
  510.         IF 
  511.               gr-curwindow @ ev.getclass ?dup
  512.               IF handle.mandelbrot.event
  513.                   THEN
  514.         THEN
  515.  
  516. \ check for exit
  517.                 restart? @ quit? @ or new-values? @ or new-screen? @ or 
  518.         IF leave 
  519.         THEN
  520.            NumSkipped @ +loop
  521.  
  522. \ Finish row with a line
  523. \          mandel-width @ 2 - i 2dup get.mandelbrot.point IF-NOT
  524. inside-flag @ 
  525.     IF-NOT
  526.       mandel-width @ 2 - i
  527.       last-iteration @ color-lookup + c@
  528.           fast.draw     ( -- )
  529. \    ELSE 2drop
  530.     THEN
  531.   0 inside-flag !
  532.   restart? @ quit? @ OR new-values? @ OR new-screen? @ OR IF leave THEN
  533.   loop
  534.   new-values? @ IF calc.new.values THEN
  535.   new-screen? @ IF close.and.open THEN
  536.   new-values? @ new-screen? @ OR IF new-screen? off new-values? off recurse 
  537.                  THEN ( harmless tail recursion)
  538. ;
  539.  
  540.  
  541.  
  542. \ allocate resources and open screen
  543.  
  544. : INIT.AND.OPEN ( -- )
  545.   set.320x200
  546.   init.file.next
  547.   init.tables
  548.   load.bm.to.screen
  549.   init.link.menus
  550.   gr-curwindow @ Mandelbrot-Menu-1 SetMenuStrip()
  551.   restart.mandel
  552.   restart? off
  553.   new-screen? off
  554.   build.lookup
  555.  ;
  556.  
  557. DEFER ..OLDABORT
  558.  
  559.  
  560. : RESET.OLD.ABORT ( -- )
  561.   what's ..oldabort is abort
  562. ;
  563.  
  564. : NEWABORT ( -- )
  565.   ." Mandelbrot ABORTing!!!" cr
  566. \ these routines check whether what they free was in fact allocated  
  567.   close.mandelscreen
  568.   free.mandelbitmap
  569.   free.tables 
  570.   iff-fileid @ ?dup IF fclose THEN
  571.   ." A log of your session is in RAM:MandelbrotSession" cr
  572.   logend
  573.   reset.old.abort
  574.   ABORT
  575. ;
  576.  
  577. : SET.NEW.ABORT
  578.   what's abort is ..oldabort
  579.   'c newabort is abort
  580. ;
  581.  
  582. : MANDELBROT ( -- )
  583.   set.new.abort
  584.   mouse.ptr.init
  585. \  init.last.xy
  586.   init.and.open
  587.   crosshairs.pointer
  588.   " ram:MandelbrotSession" $logto
  589.   begin
  590.       mandelbrot.ev.loop 
  591.       new-values? @ IF calc.new.values new-values? off 
  592.                        IsoMandelPlot
  593.             quit? @ restart? @ or IF-NOT report.mandel.time cr 
  594.                       THEN
  595.                     THEN
  596.       new-screen? @ IF new-screen? off 
  597.             close.and.open 
  598.             IsoMandelPlot 
  599.             quit? @ restart? @ or IF-NOT report.mandel.time cr 
  600.                        THEN 
  601.             THEN
  602.       restart? @ if Starting.Image restart? off then
  603.       new-values? @ restart? @ and not quit? @ and 
  604.   until
  605.   byetext
  606.   cr ." Don't forget to rename any IFF images you've saved!" cr
  607.   logend
  608.   ." A log of your session is in RAM:MandelSession" cr
  609.   restore.color.table
  610.   normal.pointer
  611.   cleanup
  612.   free.tables
  613.   free.mouse.data
  614.   reset.old.abort
  615. ;
  616.  
  617. cr cr ." type Mandelbrot to enter super quick edge-detectin' generator!" cr cr
  618.  
  619.  
  620.