home *** CD-ROM | disk | FTP | other *** search
-
- * This file: brot version 1.00
-
- * (c) 1990 by H. Helminen
-
- * This program will draw Mandelbrot set.
- * It uses two advanced features:
-
- * 1) Contour Crawling
- * When this feature is enabled, I will follow the edge
- * of each area of same colour and assume the interior
- * is of same color. This is true for ideal set, but because
- * of digital sampling, some errors may occur.
- * NOTE: This method is very sensitive to errors that may occur
- * if you change the code, e.g.
- * o pixel colors must not be changed during draw
- * o draw must not go out of screen bounds
- * o if screen is not clear prior to drawing,
- * uncleared areas may be left untouched
- * o draw must start at an edge of the picture
-
- * If disabled, every single pixel is calculated individually
- * resulting a bit better accuracy, a lot slower computing time.
- * When drawing disconnected Julia sets, crawling should be
- * disabled since it would produce inaccurate pictures.
- * Setting the AUTOCRAWL bit in mb_flags will do that for you.
-
- * 2) 32-bit fixed point arithmetics
- * To speed this program up (standard A500 with 68000 and no
- * FP-processors) while keeping reasonable resolution, I used
- * signed 32-bit fixed point arithmetics, shifted left by 29
- * bits. Multiplication was somewhat cumbersome.
- * This format allows a resolution of about 1.9 x 10 ¯9.
- * When the resolution needed is much less accurate, one can use
- * only 16 bits in multiplication. Typically one would use
- * 16 bits when delta > 0.0001 .. 0.0005.
-
- * Setting the AUTOPREC flag in mb_flags will do that for you.
- * However, in order to produce accurate pictures of Julia sets
- * that have complex structure near origo, you may need to
- * set the HIGH flag by yourself.
-
- * Typical computing times for whole set with 100 iterations
- * (5-bitplane 320 x 256 lores screen, no competing 68000 activity)
-
- * crawl walk (=traditional pixel-by-pixel method)
- * 16-bit 0:49 2:12
- * 32-bit 1:29 5:33
-
- * And, of course, the author:
-
- * |_|_ _ _| _ _ _ _ _ _ _ _ ,|_ _ _
- * (_| )(/_ (_|(_|| )(_|(/_(_)| ) | ) )(_|/)(_(/_|
- * _)
- * Hannu Helminen so-dm@stekt.oulu.fi
-
- * This proggie is quite useless by itself.
- * You should (b)link it with pipe.o (by me, of course).
- * Or you could use stack.o, which may be visually more attractive
- * but uses more memory.
- * This proggie is full of references to "stack", please ignore.
-
- * You could use brot with your own programs. Just pass
- * a valid MandelBrot structure in a0 with all fields initialized.
- * (see mbrot.i) The RastPort's *must* have valid TmpRas and AreaInfo
- * structures attached to it.
-
- * Or, link it with gui.o (again by me)
-
- * BUGS: MANY, including:
-
- * - not very smart handling of AUTOCRAWL, since non-connected
- * set _could_ be crawled provided that before areafilling an
- * area, a few points in the interior were checked to make sure
- * that they are of same color.
- * - AUTOPREC will fail on Julia sets with complex structre near origo.
-
- NOLIST
- INCLUDE "macros.i"
- INCLUDE "mbrot.i"
-
- XREF _AbsExecBase
-
- * If you insist... poof, you can remove the equates and use includes.
- * I however prefer shorter compiles.
-
-
- * These are used to maintain a stack-like dynamically allocated structure.
- * (I like these functions ... only entry points are visible to this proggie)
-
- XREF f_push
- XREF f_pull
- XREF f_clear
-
- * Now make myself visible to others.
-
- XDEF MandelBrot
-
- LIST
-
-
-
- SECTION main,CODE
-
- MandelBrot:
- push d0-d7/a0-a6
-
- * Save mbrot structure to a4. It can stay there all the time...
- move.l a0,a4
-
- move.l _AbsExecBase,a6
- lea GfxName,a1
- moveq #0,d0
-
- Call OpenLibrary
- tst.l d0
- beq exit_mb
- move.l d0,a6
-
- * If precision is AUTOPREC, determine which precision we actually use.
- btst.b #MBB_AUTOPREC,mb_flags(a4)
- beq.s skip_low
- bset.b #MBB_HIGH,mb_flags(a4)
-
- cmp.l #DELTALIMIT,mb_dx(a4)
- blo.s skip_low
- cmp.l #DELTALIMIT,mb_dy(a4)
- blo.s skip_low
- bclr.b #MBB_HIGH,mb_flags(a4)
-
- skip_low:
-
- * If AUTOCRAWL is set, determine whether we should crawl or no.
- btst.b #MBB_AUTOCRAWL,mb_flags(a4)
- beq.s skip_crawl
- bset.b #MBB_CRAWL,mb_flags(a4)
-
- * Mandelbrot set is always connected, so it may be crawled
- btst.b #MBB_JULIA,mb_flags(a4)
- beq.s skip_crawl
-
- * Julia set should be crawled if and only if corresponding
- * c = jx + jy i belongs to Mandelbrot set.
- * LS: like that "if and only if"?
- move.l mb_jx(a4),d6
- move.l mb_jy(a4),d7
- move.w mb_i(a4),d3 ; use same number of iterations
-
- bsr iterate
- tst.w d3
- bmi.s skip_crawl ; inside the set!
-
- bclr.b #MBB_CRAWL,mb_flags(a4)
-
- skip_crawl:
-
- * clear area prior to drawing.
- move.l mb_RastPort(a4),a5
- move.l a5,a1
- move.w #CLEAR,d0
- Call SetAPen
- move.l a5,a1
- move.w mb_x1(a4),d0
- move.w mb_y1(a4),d1
- move.w mb_x2(a4),d2
- move.w mb_y2(a4),d3
- Call RectFill
-
- * start drawing...
- btst.b #MBB_CRAWL,mb_flags(a4)
- beq.s walk_mb
-
- bsr Crawling
- bra.s exit_mb
- walk_mb:
- bsr Walking
- exit_mb:
- move.l a6,a1
- move.l _AbsExecBase,a6
- Call CloseLibrary
- pull d0-d7/a0-a6
- no_gfx:
- rts
-
- Walking:
- move.w mb_x1(a4),d4
- move.w mb_y1(a4),d5
- move.w d4,d6
- move.w mb_x2(a4),d7
- move.w mb_y2(a4),d3
- 1$:
-
- bsr Pixel
- bsr Break
- bne.s 3$
- addq.w #1,d4
- cmp.w d7,d4
- blo.s 1$
- bsr Pixel
-
- addq.w #1,d5
- cmp.w d3,d5
- bhi.s 3$
- 2$:
- bsr Pixel
- bsr Break
- bne.s 3$
- subq.w #1,d4
- cmp.w d6,d4
- bhi.s 2$
- bsr Pixel
-
- addq.w #1,d5
- cmp.w d3,d5
- bls.s 1$
- 3$:
- rts
-
-
- Crawling:
- move.w mb_y1(a4),d0
- or.w #%1100000000000000,d0 ; initial direction down
- swap d0
- move.w mb_x1(a4),d0
- 1$:
- bsr.s Crawl ; return with Z clear if user issued break
- bne.s 2$
- bsr f_pull
- bne.s 1$ ; stack non-empty
-
- 2$:
- * Clear stack ... important in case someone used ^C
- bsr f_clear
- rts
-
-
- * "Crawl" is supposed to take care of the actual crawling.
- * When handed with a pixel & direction in d0, it will find
- * its way through the edge of area with same colour.
-
- * In addition, it will push all pixels _not_ in that area
- * to stack.
-
- * d0 format: ddyyyyyy yyyyyyyy xxxxxxxx xxxxxxxx
-
- * direction bits:
- * 00
- * 01 10
- * 11
-
-
- Crawl:
- push d0-d7
- move.w d0,d4 ; x
- swap d0
- move.w d0,d5
- and.w #%0011111111111111,d5 ; y
- move.w d0,d3
- and.w #%1100000000000000,d3 ; d (high 2 bits)
-
- * If all pixels are drawn, it seems to me this area has already been
- * crawled (if not so, there are other pixels in the stack...)
- bsr Test4
- tst.w d0
- bpl.s 1$ ; All pixels next to me were drawn
-
- move.w d4,d6 ; Save place & dir until come to same place again
- move.w d5,d7
- move.w d3,d2
-
- move.l a5,a1
- move.l d4,d0
- move.l d5,d1
- bsr AreaMove ; note: This is a subroutine, not library call
- 2$:
- bsr.s proceed
- move.l a5,a1
- move.l d4,d0
- move.l d5,d1
- bsr AreaDraw ; and so is this
- bsr Break
- bne.s 3$
- cmp.w d4,d6 ; Compare with initial place & direction
- bne.s 2$
- cmp.w d5,d7
- bne.s 2$
- cmp.w d3,d2
- bne.s 2$
-
- move.l a5,a1
- move.l d4,d0
- move.l d5,d1
- Call ReadPixel
- move.l a5,a1
- Call SetAPen ; Just in case no pixels were drawn above.
- move.l a5,a1
- bsr AreaEnd ; this
- 1$: moveq #0,d0
- bra.s 4$
- 3$:
- move.l a5,a1
- bsr AreaEnd ; This finishes any draw (subroutine)
- moveq #-1,d0
- 4$:
- pull d0-d7
- rts ; This routine returns same as Break
-
-
- * Proceed: This routine finds edge of an area of uniform color.
- * d4/d5 = pixel, d3 = direction. Returns next pixel & direction
- * along the edge.
- * Lets give an example: let's assume current pixel is A. (a colour)
- * X is known to be != A. b and c are yet unknown.
- * Last direction was up.
- *
- * b c
- * A X
- *
- * check b
- * if (A != b) then
- * direction = left
- * push b
- * else
- * check c
- * if (A != c) then
- * current pixel = b
- * push c
- * else
- * direction = right
- * current pixel = c
- *
-
- proceed:
- push d0/d2/d6-d7
- bsr Pixel
- move.w d0,d2 ; color of current pixel
-
- move.w d4,d6
- move.w d5,d7 ; save normal pixel so we can resume
-
- bsr.s front
- bsr Pixel ; check "b"
- cmp.w d0,d2
- beq.s 1$
-
- * Turn left.
- tst.w d3
- bpl.s 2$
- eor.w #%0100000000000000,d3
- 2$:
- add.w #%0100000000000000,d3
- bpl.s 3$
- eor.w #%0100000000000000,d3
- 3$:
- * Luckily, d3/d6/d7 now contain just right info for pushing.
- tst.w d0
- bmi.s 7$ ; do not push if pixel was outside
- tst.l d0
- bmi.s 7$ ; if pixel drawn, dont push it.
- move.w d5,d0
- or.w d3,d0
- eor.w #%1100000000000000,d0 ; opposite direction
- swap d0
- move.w d4,d0
- bsr f_push
- 7$:
- move.w d6,d4 ; resume pixel
- move.w d7,d5
- bra.s 4$ ; DONE...
-
- 1$:
- move.w d4,d6 ; save "forwarded" pixel so we can resume
- move.w d5,d7
-
- bsr.s right
- bsr Pixel ; check "c"
- cmp.w d0,d2
- beq.s 5$
-
- * Go forward
- * This is what I call luck: again the right components for pushing
- tst.w d0
- bmi.s 8$ ; again, if outside, dont push.
- tst.l d0
- bmi.s 8$ ; dont push drawn pixels either
- move.w d5,d0
- or.w d3,d0
- eor.w #%1100000000000000,d0
- swap d0
- move.w d4,d0
- bsr f_push
- 8$:
- move.w d6,d4 ; resumes pixel to what it was before 'bsr right'
- move.w d7,d5
- bra.s 4$ ; DONE
-
- 5$:
- * Turn to right
- tst.w d3
- bpl.s 6$
- eor.w #%0100000000000000,d3
- 6$:
- add.w #%1100000000000000,d3
- bpl.s 4$
- eor.w #%0100000000000000,d3
- 4$:
- pull d0/d2/d6-d7
- rts
-
- * move one pixel d3-wards.
- front:
- tst.w d3
- bmi.s 1$
- btst.w #14,d3
- bne.s 2$
-
- subq.w #1,d5 ; 00
- rts
- 2$: subq.w #1,d4 ; 01
- rts
- 1$:
- btst.w #14,d3
- bne.s 3$
- addq.w #1,d4 ; 10
- rts
- 3$: addq.w #1,d5 ; 11
- rts
-
- * move one pixel to the right of direction d3.
- right:
- tst.w d3
- bmi.s 1$
- btst.w #14,d3
- bne.s 2$
-
- addq.w #1,d4 ; 00
- rts
- 2$: subq.w #1,d5 ; 01
- rts
- 1$:
- btst.w #14,d3
- bne.s 3$
- addq.w #1,d5 ; 10
- rts
- 3$: subq.w #1,d4 ; 11
- rts
-
- * Test4 will test if all 4 pixels next to d4,d5 are drawn.
- * If so, a negative number will be returned in d0.
-
- Test4:
- move.l d3,-(a7)
- moveq #0,d3
-
- subq.w #1,d4
- bsr.s GetPixel
- or.w d0,d3 ; if any of these is negative ...
-
- addq.w #2,d4
- bsr.s GetPixel
- or.w d0,d3 ; (meaning pixel was not drawn) ...
- subq.w #1,d4
-
- subq.w #1,d5
- bsr.s GetPixel
- or.w d0,d3 ; -1 will get written all over d3
-
- addq.w #2,d5
- bsr.s GetPixel
- or.w d0,d3
- subq.w #1,d5
-
- move.w d3,d0
- move.l (a7)+,d3
- rts
-
- * This routine is also called with screen pixel in d4,d5.
- * (GfxBase = a6, RastPort = a5)
- * It will return pixel color in d0 (but NOT draw it)
- * If pixel is outside region, 0 will be returned.
- * If it is not drawn, -1 will be returned
-
- GetPixel:
- push d1/a0-a1
- moveq #0,d0 ; d0 will be ready just in case any
- cmp.w mb_x1(a4),d4 ; of the conditions below is met
- blo 1$
- cmp.w mb_x2(a4),d4
- bhi 1$
- cmp.w mb_y1(a4),d5
- blo 1$
- cmp.w mb_y2(a4),d5
- bhi 1$
-
- move.l a5,a1
- move.l d4,d0
- move.l d5,d1
- Call ReadPixel
-
- cmp.w #CLEAR,d0
- bne.s 1$
-
- moveq #-1,d0
- 1$:
- pull d1/a0-a1
- rts
-
- * This routine is called with screen pixel in d4,d5.
- * (GfxBase = a6, RastPort = a5)
- * It will return pixel color in d0 and draw it if required.
- * If pixel is outside drawing region, -1 will be returned.
-
- * (An undocumented feature: if pixel was drawn before this
- * routine was called, bit 31 will be set.)
-
- * Another feature: pixels right of y-axis are returned
- * with bit 14 set (unless color == interior).
- * This will make separate areas on both sides of y-axis,
- * thus making it impossible to accidentally crawl around
- * the set (without noticing the interior at all)...
-
- Pixel:
- push d1-d3/d6-d7/a0-a1
- moveq #0,d2
- moveq #-1,d0 ; d0 will be ready just in case any
- cmp.w mb_x1(a4),d4 ; of the conditions below is met
- blo pixel_outofbounds
- cmp.w mb_x2(a4),d4
- bhi pixel_outofbounds
- cmp.w mb_y1(a4),d5
- blo pixel_outofbounds
- cmp.w mb_y2(a4),d5
- bhi pixel_outofbounds
-
- move.w d4,d3
- move.w d3,d6
- mulu mb_dx(a4),d6 ; dx.hi * d2
- swap d6 ; calmly ignore any overflow
- move.w #0,d6
- mulu 2+mb_dx(a4),d3 ; dx.lo * d2
- add.l d3,d6
- add.l mb_x0(a4),d6
- bmi.s pixel_left
- move.w #%0100000000000000,d2
- pixel_left:
- move.l a5,a1
- move.l d4,d0
- move.l d5,d1
- Call ReadPixel
-
- bset #31,d0
- cmp.w #CLEAR,d0
- bne.s pixel_outofbounds ; not clear -> dont draw (OBS! d0 still has color)
-
- move.w d5,d3
- move.w d3,d7
- mulu mb_dy(a4),d7
- swap d7
- move.w #0,d7
- mulu 2+mb_dy(a4),d3
- add.l d3,d7
- neg.l d7 ; upwards increasing y coordinate
- add.l mb_y0(a4),d7
-
- move.w mb_i(a4),d3
- sub.w #2,d3
- bpl.s positive_i
- moveq #0,d3
- positive_i
- bsr.s iterate
-
- cmp.w #-1,d3
- beq.s pixel_inside_set
-
- and.l #$ffff,d3
- divu mb_colors(a4),d3
- swap d3 ; remainder
- add.w #FIRST,d3
- bra.s pixel_outside_set
- pixel_inside_set:
- move.w #INTERIOR,d3
- pixel_outside_set:
- move.w d3,d0
- move.l a5,a1
- Call SetAPen
- move.w d4,d0
- move.w d5,d1
- move.l a5,a1
- Call WritePixel
- move.w d3,d0
- bclr #31,d0
- pixel_outofbounds:
- cmp.w #INTERIOR,d0
- beq.s pixel_dontOR
- or.w d2,d0
- pixel_dontOR:
- pull d1-d3/d6-d7/a0-a1
- rts
-
-
- * This is the soul of the MandelBrot set.
- * We iterate a point represented by x=d6 and y=d7 in our
- * numerical system. d3 is set to maximum number of iterations,
- * and will be decremented until -1 reached unless point is
- * found to be outside the set.
- * We find the point to be outside when |z| > 2
-
- * There are two versions of this routine, the former for 32 bits,
- * the latter for 16 bits.
-
- * For those who don't know the formula of Mandelbrot set:
- *
- * Point c = x + yi {x,y E R, i^2 = -1} is said to be in the M. set if
- * 2
- * z = z + c , z = c,
- * n+1 n 0
- *
- * doesnt -> oo as n -> oo. (This routine is only approximation, n -> d3)
-
- * NEW: If client wants the user to see Julia sets, we handle them here.
- * The formula is the same, except: z0 is point and c is constant
- * throughout the set (it corresponds to a point in the M. set).
- * Hope you can complex math!
-
-
- iterate:
- btst.b #MBB_HIGH,mb_flags(a4)
- beq iterate16
-
- push d0-d2/d4-d7
-
- * z is initialized with c
- move.l d6,d4 ; x0 -> x
- move.l d7,d5 ; y0 -> y
-
- * Julia stuff!
- btst.b #MBB_JULIA,mb_flags(a4)
- beq.s 1$
- move.l mb_jx(a4),d6
- move.l mb_jy(a4),d7
- 1$:
- * real part
- * (And as an intermission, find out if x² + y² > 2² or |z| > 2.
- * Because our multiplication routine does not monitor overflow,
- * we check the arguments first.)
-
- move.l d4,d0
- bsr square
- move.l d1,d2 ; x²
- add.l d0,d0 ; |x| > 2 ? d0 was reserved
- bvs.s 3$
-
- move.l d5,d0
- bsr square ; y²
- add.l d0,d0 ; |y| > 2 ?
- bvs.s 3$
- move.l d1,d0 ; |z| > 2 ?
- add.l d2,d0
- bvs.s 3$
-
- sub.l d1,d2 ; x² - y²
- add.l d6,d2 ; + x0
- bvs.s 2$
-
- * imaginary part
- move.l d4,d0
- move.l d5,d1
- bsr multi
- add.l d1,d1 ; 2 * x * y
- bvs.s 2$
- add.l d7,d1 + y0
- bvs.s 2$
-
- * get ready for next iteration:
- move.l d1,d5
- move.l d2,d4
-
- dbf d3,1$
-
- * This is more or less a kludge!
- * Testing if |z| < 2 should be last in our loop, before
- * dbf. Because it was first, low-level iterations
- * would show some sharp edges on the interior.
- * We need one more |z| < 2 here.
- * (The kludge is not removed because of speed reasons.)
-
- move.l d4,d0
- bsr square
- move.l d1,d2 ; x²
- add.l d0,d0 ; |x| > 2 ?
- bvs.s 3$
-
- move.l d5,d0
- bsr square ; y²
- add.l d0,d0 ; |y| > 2 ?
- bvs.s 3$
- add.l d2,d1 ; |z| > 2 ?
- bvc.s 2$
-
- * Thanks to our kludge, d3 has been decremented too much if
- * branched here. This would result in sharp edges on areas
- * outside the set as well. This time we have an easy fix:
-
- 3$: addq.w #1,d3
- 2$:
- pull d0-d2/d4-d7
- rts
-
- * Square and multi are primary operations of signed fixed-point math.
- * Addition can be done using normal add.l instruction.
-
- * This routine does not monitor overflowing.
- * Its arguments are expected to be within the range -2 .. 2.
-
- * NOTE: all registers except d1 are preserved (including d0!)
-
- * square : d0^2 -> d1
- * multi: d0*d1 -> d1
-
- square: move.l d0,d1
- multi: push d2-d5
-
- * We can only multiply with unsigned numbers.
- * So we calculate the sign of the result ahead of time.
-
- move.l d0,d2
- bpl.s 1$
- neg.l d0 ; fix d0
- 1$:
- tst.l d1
- bpl.s 2$
- neg.l d1 ; fix d1
- not.l d2 ; but d2 has the sign of final result
- 2$:
- move.w d1,d3
- mulu d0,d3 ; d3 = d0lo * d1lo
- moveq #29,d5 ; strip this much bits out of d3
- lsr.l d5,d3 ; (introduces rounding error of max. 1 bits)
-
- swap d0
- move.w d1,d4
- mulu d0,d4 ; d4 = d0h1 * d1lo
- moveq #13,d5 ; again some strip-tease
- lsr.l d5,d4 ; (and rounding errors)
- add.l d4,d3
-
- swap d1
- move.w d1,d4
- mulu d0,d4 ; d4 = d0hi * d1hi
- lsl.l #3,d4 ; now shift the other way up
- add.l d4,d3 ; if (-2)*(-2) this will overflow .. who cares?
-
- swap d0
- mulu d0,d1 ; d1 = d0lo * d1hi
- lsr.l d5,d1 ; shift .. d5 still has #13
- add.l d1,d3 ; all summed in d3
-
- tst.l d2
- bpl.s 3$ ; test & fix sign of product
- neg.l d3
- 3$:
- move.l d3,d1 ; result will be carried back in d1 (!)
- pull d2-d5
- rts
-
- * The same routine with .w and with no bsr's to multi/square.
- * Comments have been stripped out, only changed parts are recommented.
-
- MULTI macro
- muls d0,d1
- asl.l #3,d1
- swap d1
- endm
- SQUARE macro
- move.w d0,d1
- muls d0,d1
- asl.l #3,d1
- swap d1
- endm
-
- iterate16:
- push d0-d2/d4-d7
- swap d6 ; long -> word
- swap d7
-
- move.w d6,d4
- move.w d7,d5
-
- btst.b #MBB_JULIA,mb_flags(a4)
- beq.s 1$
- move.w mb_jx(a4),d6 ; always remember: we want HIGH order bits
- move.w mb_jy(a4),d7
- 1$:
- move.w d4,d0
- SQUARE
- move.w d1,d2
- add.w d0,d0
- bvs.s 3$
- move.w d5,d0
- SQUARE
- add.w d0,d0
- bvs.s 3$
- move.w d1,d0
- add.w d2,d0
- bvs.s 3$
- sub.w d1,d2
- add.w d6,d2
- bvs.s 2$
-
- move.w d4,d0
- move.w d5,d1
- MULTI
- add.w d1,d1
- bvs.s 2$
- add.w d7,d1
- bvs.s 2$
- move.w d1,d5
- move.w d2,d4
- dbf d3,1$
-
- muls d5,d5 ; This part is slightly different
- muls d4,d4
- add.l d5,d4
- bvs.s 3$
- add.l d4,d4
- add.l d4,d4
- bvs.s 3$
- add.l d4,d4
- bvc.s 2$
-
- 3$: addq.w #1,d3
- 2$:
- pull d0-d2/d4-d7
- rts
-
- * General-purpose break-condition check.
- * Current version uses call-back procedures, because I could
- * not make it general enough.
- Break:
- push a0/d0
- move.l mb_break(a4),d0
- beq.s 1$
- move.l d0,a0
- jsr (a0)
- 1$:
- pull a0/d0
- rts
-
- * This group of routines essentially remove unnecessary points
- * and then call the real AreaXXXX routines.
- * Just because 6553 vectors seems to be a maximum.
-
- * One could code this by allocating one bitplane, setting bits accorging
- * to what is fed to AreaDraw, filling it with one raw blitter operation
- * and then BlitPattern()ing it to RastPort. This would save allocating
- * TmpRas and AreaInfo structures.
-
- * I am a perfectionist, but I aint a fool. This is a kludge, but so what?
-
- AreaMove:
- move.w d0,startx
- move.w d1,starty
- move.w d0,prevx
- move.w d1,prevy
- clr.b dir
- Call AreaMove
- rts
- AreaDraw:
- push d2/d3
- bsr.s which_dir
-
- tst.b dir
- bpl.s skip_it
-
- * Now! All bits are not on same line.
- * More accurately, since we test this on every point, the current
- * point is not on same line as the previous ones. So:
- move.w d0,d2
- move.w d1,d3
- move.w prevx,d0 ; The previous was the last in line
- move.w prevy,d1
- move.w d0,startx ; starting point of the new line
- move.w d1,starty
- Call AreaDraw
- move.w d2,d0 ; one-stage pipelining
- move.w d3,d1
- clr.b dir
- bsr.s which_dir ; right direction for these first 2 bits.
- skip_it:
- move.w d0,prevx
- move.w d1,prevy
- draw_done:
- pull d2/d3
- rts
-
- * This routine keeps track of our heading.
- * dir carries the direction from previous stages, all 8 directions
- * are mapped to numbers 1..4 (opposite directions get same number).
- * If directions is undetermined so far, dir is 0.
- * -1 means pixels are no more on same line (requires AreaDraw.)
- which_dir:
- move.w startx,d2
- move.w starty,d3
- sub.w d0,d2
- sub.w d1,d3
-
- tst.w d2 ; normalize (make opposite dirs equal)
- bpl.s pos_1
- neg.w d2
- neg.w d3
- pos_1
- tst.w d3
- bpl.s pos_2
- neg.w d2
- neg.w d3
- pos_2
-
- tst.w d2 ; now determine direction.
- beq.s dir_03
- bpl.s dir_12
- ;dir4
- add.w d2,d3
- bne.s dir_illegal ; not diagonal!
- moveq #4,d2
- bra.s dir_proc
- dir_12
- tst.w d3
- beq.s dir_1
- ;dir_2
- cmp.w d2,d3
- bne.s dir_illegal ; not diagonal!
- moveq #2,d2
- bra.s dir_proc
- dir_1
- moveq #1,d2
- bra.s dir_proc
- dir_03
- tst.w d3
- beq.s dir_0
- ;dir_3
- moveq #3,d2
- bra.s dir_proc
- dir_0
- moveq #0,d2
- bra.s dir_proc
- dir_illegal
- moveq #-1,d2
- dir_proc
- move.b dir,d3
- beq.s dir_valid
- tst.b d2
- beq.s dir_OK
- cmp.b d2,d3
- beq.s dir_OK
- ;neither valid!
- move.b #-1,dir
- rts
- dir_valid
- move.b d2,dir
- dir_OK
- rts
-
-
- AreaEnd:
- move.l a1,-(a7)
- move.w prevx,d0
- move.w prevy,d1
- Call AreaDraw ; force dirty buffers out
- move.l (a7)+,a1
- Call AreaEnd
- rts
-
- * Needed by my Area routines
-
- prevx ds.w 1
- prevy ds.w 1
- startx ds.w 1
- starty ds.w 1
- dir ds.b 1
-
- * perhaps this should be a section of its own.
-
- GfxName dc.b 'graphics.library',0
-
- end
-
-