; Processes: ; o do not have to save any registers except A5 and A7, which will make the ; Mac system crash if you change them. (Note expecially that this means ; you can't leave things on the stack.) ; o should use the check_tasks macro at exactly one place inside their main ; loop. If the routine is pre-empted, this macro will automatically save ; and restore the registers and Quickdraw pen state in a way which is ; completely transparent to the programmer. ; o should use the set_state macro to start or abort any other processes ; as required, before finishing. old_ticks dc.l 0 ; Value of Ticks last time we checked. ; Check_tasks automatically performs the work necessary to make a subroutine ; into a fully functional process for use under _exec. This macro should ; be used exactly once in the subroutine, somewhere in the innermost loop ; of the routine (or, if the innermost loop is always less than about 0.2 ; seconds, in the next-innermost loop) The only restrictions are: ; 1. The process must not have any temporary things on the stack at the ; point where the macro is used. If it does, the thing will BOMB!!!!! ; 2. The macro must only be used once per process name. If you find that ; your process has more than one main loop you should break the process ; up into two (or more) processes with consecutive priority numbers, so ; the second (third, etc) main loop part will get run by _exec when the ; first is finished. ; macro check_tasks myprocname,regsave,pensave = move.l a0,-(sp) lea {regsave},a0 movem.l d0-d2/a1,(a0) move.l (sp)+,16(a0) lea old_ticks,a0 move.l Ticks,d0 asr.l #2,d0 compare_l d0,(a0) beq {myprocname}zq move.l d0,(a0) EventAvail #my_events,my_event move (sp)+,d0 or time_share,d0 beq {myprocname}zq lea {regsave},a0 movem.l d3-d7/a2-a4/a6,20(a0) GetPenState {pensave} set_state {myprocname},paused rts c{myprocname} SetPenState {pensave} lea {regsave},a0 movem.l 20(a0),d3-d7/a2-a4/a6 {myprocname}zq lea {regsave},a0 movem.l (a0),d0-d2/a1 move.l 16(a0),a0 | ; Routine to start the Julia-set program. ; s_julia PenSize #1,#1 PenMode #PatCopy PenPat black16 EraseRect pic_rect lea mousepoint,a0 ; Get mouse pos move (a0),d1 move 2(a0),d0 sub #pic_h,d0 sub #pic_v,d1 jsr _get_coords ; Convert to real and imaginary coords. swap d0 swap d1 move d0,d6 move d1,d7 _j_start EventAvail #my_events,my_event move (sp)+,d0 bne _j_end jsr _j_rand ; Init d4,d5 to random values move d0,d4 asr #3,d4 jsr _j_rand move d0,d5 asr #3,d5 jsr _j_nextone ; Iterate 4 times to converge fairly close bvs _j_start ; to the curve. jsr _j_nextone bvs _j_start jsr _j_nextone bvs _j_start jsr _j_nextone bvs _j_start _j_loop EventAvail #my_events,my_event move (sp)+,d0 bne _j_end jsr _j_nextone bvs _j_start move d4,d0 ; compute coords. asr #8,d0 add #pic_h+128,d0 move d5,d1 asr #8,d1 add #pic_v+128,d1 move d4,d2 ; compare to last time's coords. swap d2 move d5,d2 cmp.l a4,d2 beq _j_start ; Same coords again - infinite loop, start over. move.l d2,a4 MoveTo d0,d1 Line #0,#0 bra _j_loop _j_end move.l #MouseDownMask,d0 ; Make sure this mouse click is ignored. _FlushEvents set_state _julia,finished set_state _refill,waiting rts ; Subroutine to compute the next point on the Julia curve. There are lots ; of error checks here because the math can overflow, underflow, etc. in ; lots of ways. ; The formula used here is the inverse of the iterated function used in ; the normal Mandelbrot set computations. That is, we want to compute Z ; given Z' and C. ; ; Z = a + b i Z' = a' + b' i C = Cr + Ci i ; ; 2 ; Z' = Z + C <--- Solve for Z in terms of Z' and C ; ; Solution (after a lot of algebra:) b = +-sqr(.5*(sqr(c^2+d^2)-c)) and ; a = d/2b, where c = a'-Cr and d = b'-Ci. ; _j_nextone move d4,d2 ; Compute c = a' - Cr sub d6,d2 bvs _jn_err move d5,d3 ; Compute d = b' - Ci sub d7,d3 bvs _jn_err move d2,d1 muls d2,d1 ; d1 = c^2 move d3,d0 muls d3,d0 ; d0 = d^2 add.l d1,d0 ; d0 = c^2 + d^2 bvs _jn_err jsr _j_sqrt ; d0 = sqr(c^2+d^2) tst d0 bmi _jn_err sub d2,d0 ; d0 = sqr(c^2+d^2) - c swap d0 asr.l #3,d0 ; d0 = sqr(c^2+d^2) - c (26 fractional bits) asr.l #1,d0 ; d0 = .5*(sqr(c^2+d^2)-c) jsr _j_sqrt ; d0 = sqr(.5*(sqr(c^2+d^2)-c)) tst d0 bmi _jn_err move d0,d5 ; set new value for b. jsr _j_rand ; half the time, make it negative. tst d0 bpl @1 neg d5 @1 move d3,d0 swap d0 clr d0 asr.l #3,d0 ; d0 = d (26 frac bits) move d5,d1 add d1,d1 ; d1 = 2*b bvs _jn_err tst d1 beq _jn_err divs d1,d0 ; d0 = d/2b bvs _jn_err move d0,d4 bra _jn_end _jn_err clr d0 ; set overflow not d0 add #1,d0 _jn_end rts ; Put random number in d0 ; _j_rand movem.l d1-d2/a0-a1,-(sp) clr -(sp) Random move (sp)+,d0 movem.l (sp)+,d1-d2/a0-a1 rts ; Compute the square root of the number in d0. ; _j_sqrt movem.l d3-d5,-(sp) move.l d0,d3 move.w #$8000,d0 move d0,d5 @1 move d5,d4 mulu d5,d4 cmp.l d4,d3 bhi @2 sub.w d0,d5 @2 lsr.w #1,d0 add.w d0,d5 tst d0 bne @1 clr.l d0 move d5,d0 movem.l (sp)+,d3-d5 rts ; Routine to do _draw_pic. ; dp_regs regbuf dp_pen penbuf s_draw_pic move.l watch_cursor,a0 move.l (a0),-(sp) _SetCursor PenSize #32,#32 move #0,d0 ; min_real move #0,d1 ; min_imag _xdp_loop jsr _get_point tst.b d2 bne @1 ; If point has been evaluated already, skip plotting ; it, because this routine is only called after scrolling ; and no updating is necessary (unless a DA is active, in ; which case _refill is made pending.) jsr _eval_point jsr _store_point jsr _plot_point @1 check_tasks _draw_pic,dp_regs,dp_pen add #32,d0 compare d0,#255 ; max_real ble _xdp_loop move #0,d0 ; min_real add #32,d1 compare d1,#255 ; max_imag ble _xdp_loop move.l plus_cursor,a1 cmp_var command,#selzoom_cmd bne @2 move.l selzoom_cursor,a1 @2 move.l (a1),-(sp) _SetCursor set_state _draw_pic,finished rts ; Routine to draw the filament structure. A point is plotted if: ; ; * Any of its eight neighbors is in the Mandelbrot Set OR ; * At least five of its eight neighbors have lower count values ; than it does. ; s_filaments move.l watch_cursor,a0 move.l (a0),-(sp) _SetCursor PenSize #1,#1 PenMode #PatCopy PenPat black16 EraseRect pic_rect move #127,d3 ; frequently used constant move #1,d0 ; Start at 1,1 and go to 254,254 to avoid move #1,d1 ; problems at edges. _fil_loop move d0,d4 ; save d0 and d1 to restore later move d1,d5 jsr _get_point and d3,d2 ; Mask out flag bit beq _f_fail ; If point itself is undefined, fail compare d2,d3 beq _f_fail ; Points in the Set always fail. move d2,d7 ; Save center point in d7 for comparison with ; neighbors moveq #0,d6 ; Initial count is zero. addq #1,d0 ; get first neighbor point in d2 jsr _get_point and d3,d2 ; Mask out flag bit beq @2 ; If this neighbor is undefined, assume equal compare d2,d3 ; If this neighbor is in the Set, succeed beq _f_plot compare d2,d7 ; Compare to the center point blt @1 @2 addq #1,d6 ; Greater than or equal: increment count. @1 _fil1 addq #1,d1 ; Get next neighbor, perform same operations jsr _get_point and d3,d2 beq @2 compare d2,d3 beq _f_plot compare d2,d7 blt @1 @2 addq #1,d6 @1 _fil2 subq #1,d0 jsr _get_point and d3,d2 beq @2 compare d2,d3 beq _f_plot compare d2,d7 blt @1 @2 addq #1,d6 @1 _fil3 subq #1,d0 jsr _get_point and d3,d2 beq @2 compare d2,d3 beq _f_plot compare d2,d7 blt @1 @2 addq #1,d6 @1 _fil4 subq #1,d1 jsr _get_point and d3,d2 beq @2 compare d2,d3 beq _f_plot compare d2,d7 blt @1 @2 addq #1,d6 @1 _fil5 subq #1,d1 jsr _get_point and d3,d2 beq @2 compare d2,d3 beq _f_plot compare d2,d7 blt @1 @2 addq #1,d6 @1 _fil6 addq #1,d0 jsr _get_point and d3,d2 beq @2 compare d2,d3 beq _f_plot compare d2,d7 blt @1 @2 addq #1,d6 @1 _fil7 addq #1,d0 jsr _get_point and d3,d2 beq @2 compare d2,d3 beq _f_plot compare d2,d7 blt @1 @2 addq #1,d6 @1 compare d6,#3 ; More than three >= ctr. point => fail bgt _f_fail _f_plot move d4,d0 ; restore d0 and d1 move d5,d1 move d3,d2 ; Tell _plot_point that this point is ; in the Set. jsr _plot_point _f_fail move d4,d0 ; restore d0 and d1 move d5,d1 add #1,d0 compare d0,#254 ; max_real ble _fil_loop movem d0-d2,-(sp) ; Once per row, check for events. EventAvail #my_events,my_event move (sp)+,d7 movem (sp)+,d0-d2 tst d7 bne _fil_done move #1,d0 ; min_real add #1,d1 compare d1,#254 ; max_imag ble _fil_loop move #1,d1 ; We loop forever, drawing it over and over again bra _fil_loop ; until they hit the button. (Sort of a kludge) _fil_done move.l plus_cursor,a1 cmp_var command,#selzoom_cmd bne @2 move.l selzoom_cursor,a1 @2 move.l (a1),-(sp) _SetCursor move.l #MouseDownMask,d0 ; Make sure the mouse click (if any) is ignored. _FlushEvents set_state _filaments,finished set_state _refill,waiting rts ; Subroutine to do the query command. ; q_z1 dc.l 0 q_z2 dc.l 0 q_its equ 2000 ; Number of iterations s_query PenSize #1,#1 PenMode #PatCopy PenPat black16 TextFont #20 TextSize #10 EraseRect edit_edge EraseRect qry_data_rect MoveTo #310+pic_h,#326 ; Display current position of mouse DrawString 'Point = ' lea mousepoint,a0 ; Get mouse pos move (a0),d1 move 2(a0),d0 sub #pic_h,d0 sub #pic_v,d1 jsr _get_coords ; Convert to real and imaginary coords. jsr _draw_point moveq #0,d2 moveq #0,d3 move #q_its,d7 move.l d0,a0 move.l d1,a1 _q_loop jsr _z_prime_32 ; Z = Z^2 + C bvs _q_exit _q_next dbf d7,_q_loop bra _q_inset ; It gets here if the loop falls through _q_exit sub #q_its,d7 ; Compute n = n_max - d7 neg d7 move.l a2,d2 ; Get old a and b move.l a3,d3 _q_z1 ; Compute a^2 + b^2 for Z square_32 d3,d0,d1,d5 ; d0,d1 = b^2 (60 frac. bits) _q_z2 square_32 d2,d3,d4,d5 ; d3,d4 = a^2 (60 frac. bits) _q_z3 add.l d3,d0 ; d0 = MS word of a^2 + b^2, 28 frac. bits compare_l d0,#$40000000 ; Is it less than 4.0000 ? blt.s _q_rts ; If so, it was still inside the circle. subq #1,d7 ; Otherwise Z was outside the circle; adjust count ; to make countour lines smooth. _q_rts ; MoveTo #310+pic_h,#336 ; Point isn't in set: show count. DrawString 'Count = ' move d7,d0 jsr _draw_number MoveTo #396+pic_h,#336 DrawString 'Period Undefined' lea _count_conv,a0 ; Show which table entry cooresponds adda d7,a0 ; to this count value. move.b (a0),d7 ext.w d7 ; Convert modified count to vert. posn. add d7,d7 add #pic_v,d7 MoveTo #edit_h-7,d7 TextFont #20 TextSize #18 DrawChar #254 bra _q_end _q_inset ; Point is in set: find the period. lea q_z1,a6 ; Save current Z move.l d2,(a6) move.l d3,4(a6) move #q_its,d7 _qis_loop jsr _z_prime_32 bvs _qis_exit move.l d2,d4 move.l d3,d5 sub.l (a6),d4 sub.l 4(a6),d5 tst.l d4 bpl @1 neg.l d4 @1 tst.l d5 bpl _q_test neg.l d5 _q_test compare_l d4,#2 bgt @3 compare_l d5,#2 bgt @3 bra _qis_found @3 compare_l d4,#5 bgt _qis_next compare_l d5,#5 bgt _qis_next bra _qis_found2 _qis_next dbf d7,_qis_loop ; Iteration still proceeding after q_its*2: ; inset status unknown, count>q_its*2 MoveTo #310+pic_h,#336 DrawString 'Count > ' move #q_its+q_its,d0 jsr _draw_number MoveTo #396+pic_h,#336 DrawString 'Period Unknown' bra _q_end _qis_exit ; Iteration overflowed during search for period: ; Point not in set, count>q_its MoveTo #310+pic_h,#336 DrawString 'Count = ' sub #q_its+q_its+1,d7 ; Compute n = n_max - d7 neg d7 move d7,d0 jsr _draw_number DrawString '+-1' MoveTo #396+pic_h,#336 DrawString 'Period Undefined' bra _q_end _qis_found ; Period found MoveTo #310+pic_h,#336 DrawString 'Count = infinity' MoveTo #396+pic_h,#336 DrawString 'Period = ' sub #q_its+1,d7 ; Compute period = q_its+1 - d7 neg d7 move d7,d0 jsr _draw_number bra _q_end _qis_found2 ; Period found but questionable MoveTo #310+pic_h,#336 DrawString 'Count = infinity' MoveTo #396+pic_h,#336 DrawString 'Period = ' sub #q_its+1,d7 ; Compute period = q_its+1 - d7 neg d7 move d7,d0 jsr _draw_number DrawString '(?)' bra _q_end _q_end set_state _query,finished rts ; Subroutine to do the "Mouse Point tracker" routine ; mp_point dc.w 0,0 old_mp_point dc.w 0,0 mp_regs regbuf mp_pen penbuf s_mouse_pt MoveTo #pic_h+366,#310 TextFont #20 TextSize #10 GetMouse mp_point PtInRect mp_point,pic_rect tst (sp)+ beq _mp_check lea old_mp_point,a0 ; Compare to old point move.l mp_point,d0 compare_l d0,(a0) beq _mp_check move.l d0,(a0) ; Update old point EraseRect mouseloc_rect move mp_point,d1 ; Get coords and normalize move mp_point+2,d0 sub #pic_h,d0 sub #pic_v,d1 jsr _get_coords ; Convert to real and imaginary coords. jsr _draw_point _mp_check check_tasks _mouse_pt,mp_regs,mp_pen bra s_mouse_pt ; Loop forever (this process has to be ; aborted by someone else) ; Subroutine to redraw all points in the picture using a new shading table. ; This subroutine is similar to _idle_mode* but not identical. ; ; Reg. Input Output ; ---- ------------------------- ------ ; D0.w Used for horizontal coord of neighbor Nonzero if aborted ; D1.w Used for vertical coord of neighbor ; D2.b Used for value of neighbor ; D3.w Used for horizontal coord of current point ; D4.w Used for vertical coord of current point ; D5.b Used for value of current point ; D6.w Used for parent pen size ; D7.w Used for pen size of children points ; refill_regs regbuf refill_pen penbuf refill_zot dc.w 0 ; non-zero whenever the array is essentially empty; i.e. ; when it's OK to skip _idle_mode during update events. s_refill ; _refill gets run immediately on startup because the window gets ; an update event. Since there is nothing to draw, we avoid running ; if it's the first time. lea refill_zot,a0 tst (a0) beq @1 clr (a0) bra _r_finish @1 move #256,d6 ; Start with parent-size of 256 move d6,d1 jsr _set_pensize clr d0 ; Get and plot the first point. clr d1 jsr _get_point jsr _plot_point _r_bigloop compare d6,#1 ; If resolution is down to 1, finish ble _r_finish move d6,d7 ; Set pen size to half of this resolution. lsr #1,d7 move d7,d1 jsr _set_pensize move #0,d3 ; Start in the corner. move #0,d4 _r_loop move d3,d0 move d4,d1 jsr _get_point ; Get the point. move d2,d5 tst.b d5 ; If it hasn't been evaluated yet, skip it. beq _r_event _r_split add d7,d0 jsr _r_add_one add d7,d1 jsr _r_add_one sub d7,d0 jsr _r_add_one _r_event add d6,d3 ; Inner loop control compare d3,#255 ble _r_loop check_tasks _refill,refill_regs,refill_pen ; Deal with _exec move #0,d3 ; Outer loop control add d6,d4 compare d4,#255 ble _r_loop lsr #1,d6 ; Now go to half resolution and return to bra _r_bigloop ; top to start again! _r_finish set_state _refill,finished ; Tell _exec we're done. rts ; Subroutine evaluates and draws a child point ; _r_add_one movem.l d5/a0,-(sp) jsr _get_point ; Get the point - perhaps it's been ; evaluated already. tst.b d2 beq _rao_exit cnt_2_shade d5,d5,a0 cnt_2_shade d2,d2,a0 compare d2,d5 ; Skip plotting if it's the same pattern beq _rao_exit ; as the parent point. _rao_plot jsr _get_point ; Get value back (cnt_2_shade destroyed it) jsr _plot_point ; Draw point on the screen. _rao_exit movem.l (sp)+,d5/a0 rts ; Subroutine to get the parent of the current point. ; ; Reg. Input Output ; ---- ------------------------- ------ ; D0.w Horizontal coord of point Horizontal coord of parent ; D1.w Vertical coord of point Vertical coord of parent ; D3.w Pen size Pen size of parent ; _parent not d3 ; Mask out the least significant bit and d3,d0 and d3,d1 not d3 add d3,d3 ; go to next pen size rts ; Subroutine to handle the detail command. ; This subroutine is similar to _idle_mode* and _refill* but not identical. ; ; Reg. Input Output ; ---- ------------------------- ------ ; D0.w Used for horizontal coord of anscestor/neighbors ; D1.w Used for vertical coord of anscestor/neighbors ; D2.b Used for value of neighbor ; D3.w Used for pen size of anscestor point ; D4.w Used for horizontal coord of current point ; D5.w Used for vertical coord of current point ; det_min_real dc.w 0 det_min_imag dc.w 0 det_max_real dc.w 0 det_max_imag dc.w 0 detail_regs regbuf detail_pen penbuf s_detail set_var refill_zot,#0 ; Now that _detail is starting, it is no ; longer OK to skip _refill on update events. PenMode #PatCopy jsr _ceb_array ; Clear flag bits move det_min_real,d4 move det_min_imag,d5 _d_loop1 move d4,d0 ; Start with current point. move d5,d1 moveq #1,d3 ; Start with pen size of 1. @2 jsr _get_point ; get point tst.b d2 ; is it defined? bne @1 ; if so, we've found it jsr _parent ; Get point's parent compare d3,#256 beq @1 ; exit if reached 256 bra @2 ; loop back @1 tst.b d2 ; Is flag bit set? bmi _d_next ; If so, already been done, go to next point ; Skip check for events because it doesn't take ; any calls to _in_set to go through lots of points ; with flag bit set. @3 eor d3,d0 ; Check sibling diagonally opposite this point jsr _get_point tst.b d2 ; If defined, we have correct pen size bne _d_zot eor d3,d0 add d3,d3 ; Otherwise, need bigger pen size compare d3,#256 bge _d_zot2 bra @3 _d_zot eor d3,d0 ; fix up after loop _d_zot2 jsr _get_point _d_cmp compare d3,#1 ; If pen size is 1, skip it (can't do better than ; this) beq _d_check lsr #1,d3 ; Halve pen size - this is size children will have move d1,-(sp) ; Save d1 move d3,d1 ; Set pen size jsr _set_pensize move (sp)+,d1 ; Restore d1 jsr _d_add_child ; Draw and set flag bit for parent add d3,d0 ; Go to right child jsr _d_add_child add d3,d1 ; Go to right-bottom child jsr _d_add_child sub d3,d0 ; Go to bottom child jsr _d_add_child _d_check check_tasks _detail,detail_regs,detail_pen ; Deal with _exec _d_next addq #1,d4 compare d4,det_max_real ble _d_loop1 move det_min_real,d4 addq #1,d5 compare d5,det_max_imag ble _d_loop1 _d_finish set_state _detail,finished ; Tell _exec we're finished. rts ; Subroutine to add a child (used by Detail) ; _d_add_child jsr _get_point ; See if point has been evaluated. tst.b d2 bne @1 jsr _eval_point ; Evaluate the point. @1 jsr _plot_point ; Plot it. or.b #$80,d2 ; Set flag bit. jsr _store_point rts ; Subroutine to do the rectangle animation for Detail. Results are ; stored in det_min_real, det_min_imag, etc. ; dtrack_regs regbuf dtrack_pen penbuf dt_rect dc.w 0,0,0,0 dt_rect_on dc.w 0 s_d_track moveq #1,d1 jsr _set_pensize PenMode #PatXor PenPat black16 lea dt_rect,a0 ; Initialize rect to nothing clr.l (a0) clr.l 4(a0) set_var dt_rect_on,#true ; Let time-shared procs know we're ; drawing the rect now. _dt_loop lea mousepoint,a0 ; Get original loc. move (a0),d5 move 2(a0),d4 _dt_gm clr -(sp) ; If mouse isn't down anymore, exit loop StillDown tst (sp)+ beq _dt_loopend check_tasks _d_track,dtrack_regs,dtrack_pen ; Deal with _exec GetMouse tr_point ; Get current coordinates of mouse. lea tr_point,a0 lea old_tr_point,a1 move.l (a1),d7 cmp.l (a0),d7 ; Wait until different from old beq _dt_gm move.l (a0),(a1) move (a0),d7 move 2(a0),d6 compare d6,#pic_h ; Make sure point is kept within picture. bge @1 move #pic_h,d6 @1 compare d6,#pic_h+254 ; (254 to avoid conflict with zerorect test) ble @2 move #pic_h+254,d6 @2 compare d7,#pic_v bge @3 move #pic_v,d7 @3 compare d7,#pic_v+254 ble _dt_1 move #pic_v+254,d7 _dt_1 compare d5,d7 ; Make sure top-bottom are in correct order. ble @1 exg d5,d7 @1 compare d4,d6 ; Make sure left-right are in correct order. ble _dt_2 exg d4,d6 _dt_2 compare d5,d7 ; Make sure rect is not empty bne @1 addq #1,d7 @1 compare d4,d6 bne _dt_3 addq #1,d6 _dt_3 FrameRect dt_rect ; Un-frame old rect. lea dt_rect,a0 ; Set rect to new values. move d5,(a0) ;top move d4,2(a0) ;left move d7,4(a0) ;bottom move d6,6(a0) ;right FrameRect dt_rect ; Frame new version of rect. bra _dt_loop _dt_loopend FrameRect dt_rect ; Un-frame old rect. set_var dt_rect_on,#false lea dt_rect,a0 ; Get values of limits. move (a0),d5 ;top move 2(a0),d4 ;left move 4(a0),d7 ;bottom move 6(a0),d6 ;right sub #pic_h,d4 ;left sub #pic_v,d5 ;top sub #pic_h,d6 ;right sub #pic_v,d7 ;bottom lea det_min_real,a0 ;left move d4,(a0) lea det_min_imag,a0 ;top move d5,(a0) lea det_max_real,a0 ;right move d6,(a0) lea det_max_imag,a0 ;bottom move d7,(a0) move small_mac,d0 ; If small mac, don't worry about _q_search. bne @2 test_state _q_search,waiting ; If q_search has started, don't bne @1 ; run _detail. @2 set_state _detail,waiting @1 set_state _d_track,finished rts ; _idle_mode* is the main drawing routine in MANDELZOOM. It goes through ; the array looking for points that are {pensize} away from another point ; with a different computed value. When such points are found, this ; routine evaluates the three points to the right, below, and below-right ; at a distance of {pensize}/2 from the base point. ; ; Reg. Input Output ; ---- ------------------------- ------ ; D0.w Used for horizontal coord of neighbor ; D1.w Used for vertical coord of neighbor ; D2.b Used for value of neighbor ; D3.w Used for horizontal coord of current point ; D4.w Used for vertical coord of current point ; D5.b Used for value of current point ; D6.w Used for parent pen size ; D7.w Used for pen size of children points ; im_arrow_rect dc.w pic_v-5,0,pic_v+260,pic_h-1 idle_regs regbuf idle_pen penbuf s_idle_mode set_var refill_zot,#0 ; Now that _idle_mode is starting, it is no ; longer OK to skip _refill on update events. PenMode #PatCopy move #32,d6 ; Always starts with 32 bit pixels _im_bigloop compare d6,#1 ; If resolution is down to 1, finish ble _im_finish move d6,d7 ; Set pen size to half of this resolution lsr #1,d7 move d7,d1 jsr _set_pensize move #0,d3 move #0,d4 _im_loop move d3,d0 move d4,d1 jsr _get_point ; Get the point. move d2,d5 tst.b d5 ; If it hasn't been evaluated yet, skip it. beq _im_next compare d6,#8 ; If parent size is 8 or more, split bge _im_split compare d0,#0 ; If it's on the border do it beq _im_split add d6,d0 subq #1,d0 compare d0,#255 beq _im_split compare d1,#0 beq _im_split add d6,d1 subq #1,d1 compare d1,#255 beq _im_split move d3,d0 move d4,d1 sub d6,d1 jsr _im_checkone bne _im_split add d6,d0 jsr _im_checkone bne _im_split add d6,d1 jsr _im_checkone bne _im_split add d6,d1 jsr _im_checkone bne _im_split sub d6,d0 jsr _im_checkone bne _im_split sub d6,d0 jsr _im_checkone bne _im_split sub d6,d1 jsr _im_checkone bne _im_split sub d6,d1 jsr _im_checkone bne _im_split bra _im_next _im_split move d3,d0 move d4,d1 add d7,d0 jsr _im_add_one add d7,d1 jsr _im_add_one sub d7,d0 jsr _im_add_one _im_next check_tasks _idle_mode,idle_regs,idle_pen ; Deal with _exec. _im_next2 add d6,d3 ; Increment horiz. position and loop compare d3,#255 ble _im_loop move #0,d3 ; Increment vert. position add d6,d4 save_all ; Indicate vert. pos'n with an arrow. add #pic_v,d4 MoveTo #1,d4 EraseRect im_arrow_rect TextFont #20 TextSize #18 DrawChar #254 restore_all compare d4,#255 ; Loop back for this vert. position ble _im_loop lsr #1,d6 ; Now go to next higher resolution and bra _im_bigloop ; return to top to start again! _im_finish set_state _idle_mode,finished ; Now tell Exec we're finished. EnableItem my_options_menu,#1 rts ; Subroutine evaluates and draws a child point ; _im_add_one jsr _get_point ; Get the point tst.b d2 ; If it's been evaluated, it's been drawn bne _iao_exit ; by _refill* - so skip it. jsr _eval_point ; This will put value in d2 jsr _store_point ; Store its value in the array. cmp.b d2,d5 ; Skip the plotting if it's the same count beq _iao_exit ; as the parent point. _iao_plot jsr _plot_point ; Draw it on the screen. _iao_exit rts ; Subroutine gets a neighbor point and returns with not-equal condition ; true if point has been evaluated and is different from parent. ; _im_checkone tst.b $7009(a0) jsr _get_point ; Get this point ; If it's out-of-range make it the same as the parent point so ; the compare will come out equal. compare d0,#0 blt @2 compare d0,#255 bgt @2 compare d1,#0 blt @2 compare d1,#255 bgt @2 ; If it's zero pretend it's the same as the parent point so the ; compare will come out equal. tst.b d2 bne @1 @2 move.b d5,d2 @1 cmp.b d5,d2 ; Compare point to its parent rts ; Breadth-first search for all pixels which are adjacent to another pixel ; of a different color. This process is run after everything else has been ; aborted or finished. It finds any cusps which were missed by _idle_mode. ; q_size equ 1024*4 the_queue ds.b q_size q_head dc.w 0 q_tail dc.w 0 qs_regs regbuf qs_pen penbuf s_q_search cmp_var small_mac,#true beq _dp2_done jsr _ceb_array moveq #1,d6 PenSize d6,d6 lea q_head,a0 clr (a0) lea q_tail,a0 clr (a0) move #0,d0 move #0,d1 move.b #0,d2 jsr _check_and_add ; Add first point to the queue. _dp2_loop move q_head,d0 compare d0,q_tail beq _dp2_done jsr _dequeue move d3,d0 move d4,d1 jsr _get_point cnt_2_shade d2,d3,a0 lea mask_table,a0 ; Add mask to color to insure that enough adda.w d2,a0 ; "countours" are followed. add.b (a0),d3 move.b d3,d2 sub d6,d1 jsr _check_and_add add d6,d0 jsr _check_and_add add d6,d1 jsr _check_and_add add d6,d1 jsr _check_and_add sub d6,d0 jsr _check_and_add sub d6,d0 jsr _check_and_add sub d6,d1 jsr _check_and_add sub d6,d1 jsr _check_and_add check_tasks _q_search,qs_regs,qs_pen bra _dp2_loop _dp2_done set_state _q_search,finished rts ; Subroutine to check a point and add it to the queue (if appropriate) ; If the point has been enqueued before or if it's off-screen, this ; routine does nothing; otherwise, the point is evaluated, drawn on the ; screen and enqueued if appropriate. ; ; Reg. Input Output ; ---- ------------------------- ------ ; D0.w Horizontal coordinate Unchanged. ; D1.w Vertical coordinate Unchanged. ; D2.b Parent's value Unchanged. ; D3 (used for temp parent's value) ; D4 (used for temp horiz coord) ; D5 (used for temp vert coord) ; D6.w Pen size Unchanged. ; D7 (used for temp during color lookup) ; _check_and_add tst.b $7002(a0) movem.l d0-d5/d7,-(sp) move d2,d3 ; Save parent's value. ; if it's off the screen, forget it compare d0,#0 blt _caa_exit compare d0,#255 bgt _caa_exit compare d1,#0 blt _caa_exit compare d1,#255 bgt _caa_exit jsr _get_point ; If it's been enqueued before, skip it tst.b d2 bmi _caa_exit bne _caa_test ; If it's been evaluated already, skip ; evaluation. ; evaluate it jsr _eval_point ; This will put value in d2 ; store its value in the array jsr _store_point _caa_test move d0,d4 move d1,d5 ; if it's on the border add it compare d0,#0 beq _caa_enq add d6,d0 subq #1,d0 compare d0,#255 beq _caa_enq compare d1,#0 beq _caa_enq add d6,d1 subq #1,d1 compare d1,#255 beq _caa_enq ; If its value is different from parent's value, add it ; cnt_2_shade d2,d7,a0 ; Get color. lea mask_table,a0 ; Add mask to color to insure that enough adda.w d2,a0 ; "countours" are followed. add.b (a0),d7 move.b d7,d2 cmp.b d2,d3 bne _caa_enq bra _caa_exit _caa_enq move d4,d0 move d5,d1 jsr _enqueue jsr _get_point or.b #$80,d2 ; Mark point as having been enqueued. jsr _store_point jsr _plot_point ; Draw it on the screen. _caa_exit movem.l (sp)+,d0-d5/d7 rts ; Subroutine to put a point on the queue. ; ; Reg. Input Output ; ---- ------------------------- ------ ; D0.w Horizontal coordinate Unchanged. ; D1.w Vertical coordinate Unchanged. ; _enqueue tst.b $7007(a0) move.l d3,-(sp) lea the_queue(a5),a0 lea q_head,a1 move (a1),d3 adda d3,a0 move d0,(a0)+ move d1,(a0) addq #4,d3 compare d3,#q_size blt @1 moveq #0,d3 @1 move d3,(a1) move.l (sp)+,d3 rts ; Subroutine to get a point from the queue. ; ; Reg. Input Output ; ---- ------------------------- ------ ; D3.w (ignored) Horizontal coordinate ; D4.w (ignored) Vertical coordinate ; _dequeue tst.b $7008(a0) move.l d0,-(sp) lea the_queue(a5),a0 lea q_tail,a1 move (a1),d0 adda d0,a0 move (a0)+,d3 move (a0),d4 addq #4,d0 compare d0,#q_size blt @1 moveq #0,d0 @1 move d0,(a1) move.l (sp)+,d0 rts ; Subroutine to select part of the display for enlargement (with the mouse) ; Mousepoint contains the point where the mouse was pressed down. ; ; Reg. Input Output ; ---- ------------------------- -------------------------- ; D4 Horiz ; D5 Vert ; D6 Horiz part of current point ; D7 Vert part of current point ; tr_rect dc.w 0,0,0,0 tr_center dc.w 0,0 tr_zoom dc.w 0 tr_point dc.w 0,0 old_tr_point dc.w 0,0 _track_rect movem.l a0-a4/d0-d7,-(sp) lea mousepoint,a0 move (a0),d5 move 2(a0),d4 lea tr_center,a0 move d5,(a0) move d4,2(a0) move.l tr_center,d0 ; Set rect to empty rect centered on old lea tr_rect,a0 ; mouse point (default size is 8 x 8) move.l d0,(a0) move.l d0,4(a0) InsetRect tr_rect,#-8,#-8 lea tr_zoom,a0 move #8,(a0) moveq #1,d1 jsr _set_pensize PenMode #PatXor PenPat black16 FrameRect tr_rect _tr_mainloop GetMouse tr_point move tr_point,d7 move tr_point+2,d6 sub d5,d7 ; Take difference of vert. coordinates bge @1 neg d7 @1 sub d4,d6 ; Take difference of horiz. coordinates bge @2 neg d6 @2 compare d6,d7 ; Take larger of d6,d7 and put in d6 bge @3 move d7,d6 @3 compare d6,#256 ; Take the smaller of d6 and 256 ble @4 move #256,d6 @4 compare d6,#8 ; Take the larger of d6 and 8 bge @5 move #8,d6 @5 moveq #1,d7 ; Round it down to the lext lower power of two. _tr_loop lsr #1,d6 beq @1 add d7,d7 bra _tr_loop compare d7,tr_zoom ; Is it different from old size? beq _tr_stilldown @1 FrameRect tr_rect ; Un-frame old rect move.l tr_center,d0 ; Set rect to empty rect centered on old lea tr_rect,a0 ; mouse point move.l d0,(a0) move.l d0,4(a0) lea tr_zoom,a0 move d7,(a0) neg d7 InsetRect tr_rect,d7,d7 FrameRect tr_rect ; Frame new rect _tr_stilldown clr -(sp) StillDown ; If mouse is still down, repeat loop. tst (sp)+ bne _tr_mainloop FrameRect tr_rect moveq #-2,d6 ; Set d6 = number of times to zoom in. move tr_zoom,d7 _tr_l3 add d7,d7 addq #1,d6 compare d7,#512 blt _tr_l3 add zoom_factor,d6 ; Add old zoom factor to d6 bpl @2 clr d6 ; New zoom factor must be >= 0 @2 ; lea tr_center,a0 ; Get center pos move (a0),d1 move 2(a0),d0 sub #pic_h,d0 sub #pic_v,d1 jsr _get_coords lea pic_center,a2 move.l d0,(a2) move.l d1,4(a2) lea zoom_factor,a0 ; Set new zoom factor (must do this after ; call to _get_coords) move d6,(a0) PenMode #PatCopy movem.l (sp)+,a0-a4/d0-d7 rts ; Routine to do _tiff. ; tf_regs regbuf tf_pen penbuf s_tiff move.l watch_cursor,a0 move.l (a0),-(sp) _SetCursor PenSize #1,#1 EraseRect pic_rect move #0,d0 ; min_real move #0,d1 ; min_imag _xtf_loop jsr _get_point tst.b d2 bne @1 jsr _eval_point jsr _store_point jsr _plot_point @1 check_tasks _tiff,tf_regs,tf_pen add #1,d0 compare d0,#255 ; max_real ble _xtf_loop move #0,d0 ; min_real add #1,d1 compare d1,#255 ; max_imag ble _xtf_loop move.l plus_cursor,a1 cmp_var command,#selzoom_cmd bne @2 move.l selzoom_cursor,a1 @2 move.l (a1),-(sp) _SetCursor set_state _tiff,finished rts