amiga-request@ab20.larc.nasa.gov (Amiga Sources/Binaries Moderator) (02/19/91)
Submitted-by: dm@stekt.oulu.fi (Hannu Helminen ti)
Posting-number: Volume 91, Issue 019
Archive-name: applications/mandel-1.0/part03
#!/bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 3 (of 4)."
# Contents: source/brot.asm source/gui.asm.aa
# Wrapped by tadguy@ab20 on Mon Feb 18 17:25:40 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'source/brot.asm' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'source/brot.asm'\"
else
echo shar: Extracting \"'source/brot.asm'\" \(26440 characters\)
sed "s/^X//" >'source/brot.asm' <<'END_OF_FILE'
X
X* This file: brot version 1.00
X
X* (c) 1990 by H. Helminen
X
X* This program will draw Mandelbrot set.
X* It uses two advanced features:
X
X* 1) Contour Crawling
X* When this feature is enabled, I will follow the edge
X* of each area of same colour and assume the interior
X* is of same color. This is true for ideal set, but because
X* of digital sampling, some errors may occur.
X* NOTE: This method is very sensitive to errors that may occur
X* if you change the code, e.g.
X* o pixel colors must not be changed during draw
X* o draw must not go out of screen bounds
X* o if screen is not clear prior to drawing,
X* uncleared areas may be left untouched
X* o draw must start at an edge of the picture
X
X* If disabled, every single pixel is calculated individually
X* resulting a bit better accuracy, a lot slower computing time.
X* When drawing disconnected Julia sets, crawling should be
X* disabled since it would produce inaccurate pictures.
X* Setting the AUTOCRAWL bit in mb_flags will do that for you.
X
X* 2) 32-bit fixed point arithmetics
X* To speed this program up (standard A500 with 68000 and no
X* FP-processors) while keeping reasonable resolution, I used
X* signed 32-bit fixed point arithmetics, shifted left by 29
X* bits. Multiplication was somewhat cumbersome.
X* This format allows a resolution of about 1.9 x 10^(-9).
X* When the resolution needed is much less accurate, one can use
X* only 16 bits in multiplication. Typically one would use
X* 16 bits when delta > 0.0001 .. 0.0005.
X
X* Setting the AUTOPREC flag in mb_flags will do that for you.
X* However, in order to produce accurate pictures of Julia sets
X* that have complex structure near origo, you may need to
X* set the HIGH flag by yourself.
X
X* Typical computing times for whole set with 100 iterations
X* (5-bitplane 320 x 256 lores screen, no competing 68000 activity)
X
X* crawl walk (=traditional pixel-by-pixel method)
X* 16-bit 0:49 2:12
X* 32-bit 1:29 5:33
X
X* And, of course, the author:
X
X* |_|_ _ _| _ _ _ _ _ _ _ _ ,|_ _ _
X* (_| )(/_ (_|(_|| )(_|(/_(_)| ) | ) )(_|/)(_(/_|
X* _)
X* Hannu Helminen so-dm@stekt.oulu.fi
X
X* This proggie is quite useless by itself.
X* You should (b)link it with pipe.o (by me, of course).
X* Or you could use stack.o, which may be visually more attractive
X* but uses more memory.
X* This proggie is full of references to "stack", please ignore.
X
X* You could use brot with your own programs. Just pass
X* a valid MandelBrot structure in a0 with all fields initialized.
X* (see mbrot.i) The RastPort's *must* have valid TmpRas and AreaInfo
X* structures attached to it.
X
X* Or, link it with gui.o (again by me)
X
X* BUGS: MANY, including:
X
X* - not very smart handling of AUTOCRAWL, since non-connected
X* set _could_ be crawled provided that before areafilling an
X* area, a few points in the interior were checked to make sure
X* that they are of same color.
X* - AUTOPREC will fail on Julia sets with complex structre near origo.
X
X NOLIST
X INCLUDE "macros.i"
X INCLUDE "mbrot.i"
X
X XREF _AbsExecBase
X
X* If you insist... poof, you can remove the equates and use includes.
X* I however prefer shorter compiles.
X
X
X* These are used to maintain a stack-like dynamically allocated structure.
X* (I like these functions ... only entry points are visible to this proggie)
X
X XREF f_push
X XREF f_pull
X XREF f_clear
X
X* Now make myself visible to others.
X
X XDEF MandelBrot
X
X LIST
X
X
X
X SECTION main,CODE
X
XMandelBrot:
X push d0-d7/a0-a6
X
X* Save mbrot structure to a4. It can stay there all the time...
X move.l a0,a4
X
X move.l _AbsExecBase,a6
X lea GfxName,a1
X moveq #0,d0
X
X Call OpenLibrary
X tst.l d0
X beq exit_mb
X move.l d0,a6
X
X* If precision is AUTOPREC, determine which precision we actually use.
X btst.b #MBB_AUTOPREC,mb_flags(a4)
X beq.s skip_low
X bset.b #MBB_HIGH,mb_flags(a4)
X
X cmp.l #DELTALIMIT,mb_dx(a4)
X blo.s skip_low
X cmp.l #DELTALIMIT,mb_dy(a4)
X blo.s skip_low
X bclr.b #MBB_HIGH,mb_flags(a4)
X
Xskip_low:
X
X* If AUTOCRAWL is set, determine whether we should crawl or no.
X btst.b #MBB_AUTOCRAWL,mb_flags(a4)
X beq.s skip_crawl
X bset.b #MBB_CRAWL,mb_flags(a4)
X
X* Mandelbrot set is always connected, so it may be crawled
X btst.b #MBB_JULIA,mb_flags(a4)
X beq.s skip_crawl
X
X* Julia set should be crawled if and only if corresponding
X* c = jx + jy i belongs to Mandelbrot set.
X* LS: like that "if and only if"?
X move.l mb_jx(a4),d6
X move.l mb_jy(a4),d7
X move.w mb_i(a4),d3 ; use same number of iterations
X
X bsr iterate
X tst.w d3
X bmi.s skip_crawl ; inside the set!
X
X bclr.b #MBB_CRAWL,mb_flags(a4)
X
Xskip_crawl:
X
X* clear area prior to drawing.
X move.l mb_RastPort(a4),a5
X move.l a5,a1
X move.w #CLEAR,d0
X Call SetAPen
X move.l a5,a1
X move.w mb_x1(a4),d0
X move.w mb_y1(a4),d1
X move.w mb_x2(a4),d2
X move.w mb_y2(a4),d3
X Call RectFill
X
X* start drawing...
X btst.b #MBB_CRAWL,mb_flags(a4)
X beq.s walk_mb
X
X bsr Crawling
X bra.s exit_mb
Xwalk_mb:
X bsr Walking
Xexit_mb:
X move.l a6,a1
X move.l _AbsExecBase,a6
X Call CloseLibrary
X pull d0-d7/a0-a6
Xno_gfx:
X rts
X
XWalking:
X move.w mb_x1(a4),d4
X move.w mb_y1(a4),d5
X move.w d4,d6
X move.w mb_x2(a4),d7
X move.w mb_y2(a4),d3
X1$:
X
X bsr Pixel
X bsr Break
X bne.s 3$
X addq.w #1,d4
X cmp.w d7,d4
X blo.s 1$
X bsr Pixel
X
X addq.w #1,d5
X cmp.w d3,d5
X bhi.s 3$
X2$:
X bsr Pixel
X bsr Break
X bne.s 3$
X subq.w #1,d4
X cmp.w d6,d4
X bhi.s 2$
X bsr Pixel
X
X addq.w #1,d5
X cmp.w d3,d5
X bls.s 1$
X3$:
X rts
X
X
XCrawling:
X move.w mb_y1(a4),d0
X or.w #%1100000000000000,d0 ; initial direction down
X swap d0
X move.w mb_x1(a4),d0
X1$:
X bsr.s Crawl ; return with Z clear if user issued break
X bne.s 2$
X bsr f_pull
X bne.s 1$ ; stack non-empty
X
X2$:
X* Clear stack ... important in case someone used ^C
X bsr f_clear
X rts
X
X
X* "Crawl" is supposed to take care of the actual crawling.
X* When handed with a pixel & direction in d0, it will find
X* its way through the edge of area with same colour.
X
X* In addition, it will push all pixels _not_ in that area
X* to stack.
X
X* d0 format: ddyyyyyy yyyyyyyy xxxxxxxx xxxxxxxx
X
X* direction bits:
X* 00
X* 01 10
X* 11
X
X
XCrawl:
X push d0-d7
X move.w d0,d4 ; x
X swap d0
X move.w d0,d5
X and.w #%0011111111111111,d5 ; y
X move.w d0,d3
X and.w #%1100000000000000,d3 ; d (high 2 bits)
X
X* If all pixels are drawn, it seems to me this area has already been
X* crawled (if not so, there are other pixels in the stack...)
X bsr Test4
X tst.w d0
X bpl.s 1$ ; All pixels next to me were drawn
X
X move.w d4,d6 ; Save place & dir until come to same place again
X move.w d5,d7
X move.w d3,d2
X
X move.l a5,a1
X move.l d4,d0
X move.l d5,d1
X bsr AreaMove ; note: This is a subroutine, not library call
X2$:
X bsr.s proceed
X move.l a5,a1
X move.l d4,d0
X move.l d5,d1
X bsr AreaDraw ; and so is this
X bsr Break
X bne.s 3$
X cmp.w d4,d6 ; Compare with initial place & direction
X bne.s 2$
X cmp.w d5,d7
X bne.s 2$
X cmp.w d3,d2
X bne.s 2$
X
X move.l a5,a1
X move.l d4,d0
X move.l d5,d1
X Call ReadPixel
X move.l a5,a1
X Call SetAPen ; Just in case no pixels were drawn above.
X move.l a5,a1
X bsr AreaEnd ; this
X1$: moveq #0,d0
X bra.s 4$
X3$:
X move.l a5,a1
X bsr AreaEnd ; This finishes any draw (subroutine)
X moveq #-1,d0
X4$:
X pull d0-d7
X rts ; This routine returns same as Break
X
X
X* Proceed: This routine finds edge of an area of uniform color.
X* d4/d5 = pixel, d3 = direction. Returns next pixel & direction
X* along the edge.
X* Lets give an example: let's assume current pixel is A. (a colour)
X* X is known to be != A. b and c are yet unknown.
X* Last direction was up.
X*
X* b c
X* A X
X*
X* check b
X* if (A != b) then
X* direction = left
X* push b
X* else
X* check c
X* if (A != c) then
X* current pixel = b
X* push c
X* else
X* direction = right
X* current pixel = c
X*
X
Xproceed:
X push d0/d2/d6-d7
X bsr Pixel
X move.w d0,d2 ; color of current pixel
X
X move.w d4,d6
X move.w d5,d7 ; save normal pixel so we can resume
X
X bsr.s front
X bsr Pixel ; check "b"
X cmp.w d0,d2
X beq.s 1$
X
X* Turn left.
X tst.w d3
X bpl.s 2$
X eor.w #%0100000000000000,d3
X2$:
X add.w #%0100000000000000,d3
X bpl.s 3$
X eor.w #%0100000000000000,d3
X3$:
X* Luckily, d3/d6/d7 now contain just right info for pushing.
X tst.w d0
X bmi.s 7$ ; do not push if pixel was outside
X tst.l d0
X bmi.s 7$ ; if pixel drawn, dont push it.
X move.w d5,d0
X or.w d3,d0
X eor.w #%1100000000000000,d0 ; opposite direction
X swap d0
X move.w d4,d0
X bsr f_push
X7$:
X move.w d6,d4 ; resume pixel
X move.w d7,d5
X bra.s 4$ ; DONE...
X
X1$:
X move.w d4,d6 ; save "forwarded" pixel so we can resume
X move.w d5,d7
X
X bsr.s right
X bsr Pixel ; check "c"
X cmp.w d0,d2
X beq.s 5$
X
X* Go forward
X* This is what I call luck: again the right components for pushing
X tst.w d0
X bmi.s 8$ ; again, if outside, dont push.
X tst.l d0
X bmi.s 8$ ; dont push drawn pixels either
X move.w d5,d0
X or.w d3,d0
X eor.w #%1100000000000000,d0
X swap d0
X move.w d4,d0
X bsr f_push
X8$:
X move.w d6,d4 ; resumes pixel to what it was before 'bsr right'
X move.w d7,d5
X bra.s 4$ ; DONE
X
X5$:
X* Turn to right
X tst.w d3
X bpl.s 6$
X eor.w #%0100000000000000,d3
X6$:
X add.w #%1100000000000000,d3
X bpl.s 4$
X eor.w #%0100000000000000,d3
X4$:
X pull d0/d2/d6-d7
X rts
X
X* move one pixel d3-wards.
Xfront:
X tst.w d3
X bmi.s 1$
X btst.w #14,d3
X bne.s 2$
X
X subq.w #1,d5 ; 00
X rts
X2$: subq.w #1,d4 ; 01
X rts
X1$:
X btst.w #14,d3
X bne.s 3$
X addq.w #1,d4 ; 10
X rts
X3$: addq.w #1,d5 ; 11
X rts
X
X* move one pixel to the right of direction d3.
Xright:
X tst.w d3
X bmi.s 1$
X btst.w #14,d3
X bne.s 2$
X
X addq.w #1,d4 ; 00
X rts
X2$: subq.w #1,d5 ; 01
X rts
X1$:
X btst.w #14,d3
X bne.s 3$
X addq.w #1,d5 ; 10
X rts
X3$: subq.w #1,d4 ; 11
X rts
X
X* Test4 will test if all 4 pixels next to d4,d5 are drawn.
X* If so, a negative number will be returned in d0.
X
XTest4:
X move.l d3,-(a7)
X moveq #0,d3
X
X subq.w #1,d4
X bsr.s GetPixel
X or.w d0,d3 ; if any of these is negative ...
X
X addq.w #2,d4
X bsr.s GetPixel
X or.w d0,d3 ; (meaning pixel was not drawn) ...
X subq.w #1,d4
X
X subq.w #1,d5
X bsr.s GetPixel
X or.w d0,d3 ; -1 will get written all over d3
X
X addq.w #2,d5
X bsr.s GetPixel
X or.w d0,d3
X subq.w #1,d5
X
X move.w d3,d0
X move.l (a7)+,d3
X rts
X
X* This routine is also called with screen pixel in d4,d5.
X* (GfxBase = a6, RastPort = a5)
X* It will return pixel color in d0 (but NOT draw it)
X* If pixel is outside region, 0 will be returned.
X* If it is not drawn, -1 will be returned
X
XGetPixel:
X push d1/a0-a1
X moveq #0,d0 ; d0 will be ready just in case any
X cmp.w mb_x1(a4),d4 ; of the conditions below is met
X blo 1$
X cmp.w mb_x2(a4),d4
X bhi 1$
X cmp.w mb_y1(a4),d5
X blo 1$
X cmp.w mb_y2(a4),d5
X bhi 1$
X
X move.l a5,a1
X move.l d4,d0
X move.l d5,d1
X Call ReadPixel
X
X cmp.w #CLEAR,d0
X bne.s 1$
X
X moveq #-1,d0
X1$:
X pull d1/a0-a1
X rts
X
X* This routine is called with screen pixel in d4,d5.
X* (GfxBase = a6, RastPort = a5)
X* It will return pixel color in d0 and draw it if required.
X* If pixel is outside drawing region, -1 will be returned.
X
X* (An undocumented feature: if pixel was drawn before this
X* routine was called, bit 31 will be set.)
X
X* Another feature: pixels right of y-axis are returned
X* with bit 14 set (unless color == interior).
X* This will make separate areas on both sides of y-axis,
X* thus making it impossible to accidentally crawl around
X* the set (without noticing the interior at all)...
X
XPixel:
X push d1-d3/d6-d7/a0-a1
X moveq #0,d2
X moveq #-1,d0 ; d0 will be ready just in case any
X cmp.w mb_x1(a4),d4 ; of the conditions below is met
X blo pixel_outofbounds
X cmp.w mb_x2(a4),d4
X bhi pixel_outofbounds
X cmp.w mb_y1(a4),d5
X blo pixel_outofbounds
X cmp.w mb_y2(a4),d5
X bhi pixel_outofbounds
X
X move.w d4,d3
X move.w d3,d6
X mulu mb_dx(a4),d6 ; dx.hi * d2
X swap d6 ; calmly ignore any overflow
X move.w #0,d6
X mulu 2+mb_dx(a4),d3 ; dx.lo * d2
X add.l d3,d6
X add.l mb_x0(a4),d6
X bmi.s pixel_left
X move.w #%0100000000000000,d2
Xpixel_left:
X move.l a5,a1
X move.l d4,d0
X move.l d5,d1
X Call ReadPixel
X
X bset #31,d0
X cmp.w #CLEAR,d0
X bne.s pixel_outofbounds ; not clear -> dont draw (OBS! d0 still has color)
X
X move.w d5,d3
X move.w d3,d7
X mulu mb_dy(a4),d7
X swap d7
X move.w #0,d7
X mulu 2+mb_dy(a4),d3
X add.l d3,d7
X neg.l d7 ; upwards increasing y coordinate
X add.l mb_y0(a4),d7
X
X move.w mb_i(a4),d3
X sub.w #2,d3
X bpl.s positive_i
X moveq #0,d3
Xpositive_i
X bsr.s iterate
X
X cmp.w #-1,d3
X beq.s pixel_inside_set
X
X and.l #$ffff,d3
X divu mb_colors(a4),d3
X swap d3 ; remainder
X add.w #FIRST,d3
X bra.s pixel_outside_set
Xpixel_inside_set:
X move.w #INTERIOR,d3
Xpixel_outside_set:
X move.w d3,d0
X move.l a5,a1
X Call SetAPen
X move.w d4,d0
X move.w d5,d1
X move.l a5,a1
X Call WritePixel
X move.w d3,d0
X bclr #31,d0
Xpixel_outofbounds:
X cmp.w #INTERIOR,d0
X beq.s pixel_dontOR
X or.w d2,d0
Xpixel_dontOR:
X pull d1-d3/d6-d7/a0-a1
X rts
X
X
X* This is the soul of the MandelBrot set.
X* We iterate a point represented by x=d6 and y=d7 in our
X* numerical system. d3 is set to maximum number of iterations,
X* and will be decremented until -1 reached unless point is
X* found to be outside the set.
X* We find the point to be outside when |z| > 2
X
X* There are two versions of this routine, the former for 32 bits,
X* the latter for 16 bits.
X
X* For those who don't know the formula of Mandelbrot set:
X*
X* Point c = x + yi {x,y E R, i^2 = -1} is said to be in the M. set if
X* 2
X* z = z + c , z = c,
X* n+1 n 0
X*
X* doesnt -> oo as n -> oo. (This routine is only approximation, n -> d3)
X
X* NEW: If client wants the user to see Julia sets, we handle them here.
X* The formula is the same, except: z0 is point and c is constant
X* throughout the set (it corresponds to a point in the M. set).
X* Hope you can complex math!
X
X
Xiterate:
X btst.b #MBB_HIGH,mb_flags(a4)
X beq iterate16
X
X push d0-d2/d4-d7
X
X* z is initialized with c
X move.l d6,d4 ; x0 -> x
X move.l d7,d5 ; y0 -> y
X
X* Julia stuff!
X btst.b #MBB_JULIA,mb_flags(a4)
X beq.s 1$
X move.l mb_jx(a4),d6
X move.l mb_jy(a4),d7
X1$:
X* real part
X* (And as an intermission, find out if x^2 + y^2 > 2^2 or |z| > 2.
X* Because our multiplication routine does not monitor overflow,
X* we check the arguments first.)
X
X move.l d4,d0
X bsr square
X move.l d1,d2 ; x^2
X add.l d0,d0 ; |x| > 2 ? d0 was reserved
X bvs.s 3$
X
X move.l d5,d0
X bsr square ; y^2
X add.l d0,d0 ; |y| > 2 ?
X bvs.s 3$
X move.l d1,d0 ; |z| > 2 ?
X add.l d2,d0
X bvs.s 3$
X
X sub.l d1,d2 ; x^2 - y^2
X add.l d6,d2 ; + x0
X bvs.s 2$
X
X* imaginary part
X move.l d4,d0
X move.l d5,d1
X bsr multi
X add.l d1,d1 ; 2 * x * y
X bvs.s 2$
X add.l d7,d1 + y0
X bvs.s 2$
X
X* get ready for next iteration:
X move.l d1,d5
X move.l d2,d4
X
X dbf d3,1$
X
X* This is more or less a kludge!
X* Testing if |z| < 2 should be last in our loop, before
X* dbf. Because it was first, low-level iterations
X* would show some sharp edges on the interior.
X* We need one more |z| < 2 here.
X* (The kludge is not removed because of speed reasons.)
X
X move.l d4,d0
X bsr square
X move.l d1,d2 ; x^2
X add.l d0,d0 ; |x| > 2 ?
X bvs.s 3$
X
X move.l d5,d0
X bsr square ; y^2
X add.l d0,d0 ; |y| > 2 ?
X bvs.s 3$
X add.l d2,d1 ; |z| > 2 ?
X bvc.s 2$
X
X* Thanks to our kludge, d3 has been decremented too much if
X* branched here. This would result in sharp edges on areas
X* outside the set as well. This time we have an easy fix:
X
X3$: addq.w #1,d3
X2$:
X pull d0-d2/d4-d7
X rts
X
X* Square and multi are primary operations of signed fixed-point math.
X* Addition can be done using normal add.l instruction.
X
X* This routine does not monitor overflowing.
X* Its arguments are expected to be within the range -2 .. 2.
X
X* NOTE: all registers except d1 are preserved (including d0!)
X
X* square : d0^2 -> d1
X* multi: d0*d1 -> d1
X
Xsquare: move.l d0,d1
Xmulti: push d2-d5
X
X* We can only multiply with unsigned numbers.
X* So we calculate the sign of the result ahead of time.
X
X move.l d0,d2
X bpl.s 1$
X neg.l d0 ; fix d0
X1$:
X tst.l d1
X bpl.s 2$
X neg.l d1 ; fix d1
X not.l d2 ; but d2 has the sign of final result
X2$:
X move.w d1,d3
X mulu d0,d3 ; d3 = d0lo * d1lo
X moveq #29,d5 ; strip this much bits out of d3
X lsr.l d5,d3 ; (introduces rounding error of max. 1 bits)
X
X swap d0
X move.w d1,d4
X mulu d0,d4 ; d4 = d0h1 * d1lo
X moveq #13,d5 ; again some strip-tease
X lsr.l d5,d4 ; (and rounding errors)
X add.l d4,d3
X
X swap d1
X move.w d1,d4
X mulu d0,d4 ; d4 = d0hi * d1hi
X lsl.l #3,d4 ; now shift the other way up
X add.l d4,d3 ; if (-2)*(-2) this will overflow .. who cares?
X
X swap d0
X mulu d0,d1 ; d1 = d0lo * d1hi
X lsr.l d5,d1 ; shift .. d5 still has #13
X add.l d1,d3 ; all summed in d3
X
X tst.l d2
X bpl.s 3$ ; test & fix sign of product
X neg.l d3
X3$:
X move.l d3,d1 ; result will be carried back in d1 (!)
X pull d2-d5
X rts
X
X* The same routine with .w and with no bsr's to multi/square.
X* Comments have been stripped out, only changed parts are recommented.
X
XMULTI macro
X muls d0,d1
X asl.l #3,d1
X swap d1
X endm
XSQUARE macro
X move.w d0,d1
X muls d0,d1
X asl.l #3,d1
X swap d1
X endm
X
Xiterate16:
X push d0-d2/d4-d7
X swap d6 ; long -> word
X swap d7
X
X move.w d6,d4
X move.w d7,d5
X
X btst.b #MBB_JULIA,mb_flags(a4)
X beq.s 1$
X move.w mb_jx(a4),d6 ; always remember: we want HIGH order bits
X move.w mb_jy(a4),d7
X1$:
X move.w d4,d0
X SQUARE
X move.w d1,d2
X add.w d0,d0
X bvs.s 3$
X move.w d5,d0
X SQUARE
X add.w d0,d0
X bvs.s 3$
X move.w d1,d0
X add.w d2,d0
X bvs.s 3$
X sub.w d1,d2
X add.w d6,d2
X bvs.s 2$
X
X move.w d4,d0
X move.w d5,d1
X MULTI
X add.w d1,d1
X bvs.s 2$
X add.w d7,d1
X bvs.s 2$
X move.w d1,d5
X move.w d2,d4
X dbf d3,1$
X
X muls d5,d5 ; This part is slightly different
X muls d4,d4
X add.l d5,d4
X bvs.s 3$
X add.l d4,d4
X add.l d4,d4
X bvs.s 3$
X add.l d4,d4
X bvc.s 2$
X
X3$: addq.w #1,d3
X2$:
X pull d0-d2/d4-d7
X rts
X
X* General-purpose break-condition check.
X* Current version uses call-back procedures, because I could
X* not make it general enough.
XBreak:
X push a0/d0
X move.l mb_break(a4),d0
X beq.s 1$
X move.l d0,a0
X jsr (a0)
X1$:
X pull a0/d0
X rts
X
X* This group of routines essentially remove unnecessary points
X* and then call the real AreaXXXX routines.
X* Just because 6553 vectors seems to be a maximum.
X
X* One could code this by allocating one bitplane, setting bits accorging
X* to what is fed to AreaDraw, filling it with one raw blitter operation
X* and then BlitPattern()ing it to RastPort. This would save allocating
X* TmpRas and AreaInfo structures.
X
X* I am a perfectionist, but I aint a fool. This is a kludge, but so what?
X
XAreaMove:
X move.w d0,startx
X move.w d1,starty
X move.w d0,prevx
X move.w d1,prevy
X clr.b dir
X Call AreaMove
X rts
XAreaDraw:
X push d2/d3
X bsr.s which_dir
X
X tst.b dir
X bpl.s skip_it
X
X* Now! All bits are not on same line.
X* More accurately, since we test this on every point, the current
X* point is not on same line as the previous ones. So:
X move.w d0,d2
X move.w d1,d3
X move.w prevx,d0 ; The previous was the last in line
X move.w prevy,d1
X move.w d0,startx ; starting point of the new line
X move.w d1,starty
X Call AreaDraw
X move.w d2,d0 ; one-stage pipelining
X move.w d3,d1
X clr.b dir
X bsr.s which_dir ; right direction for these first 2 bits.
Xskip_it:
X move.w d0,prevx
X move.w d1,prevy
Xdraw_done:
X pull d2/d3
X rts
X
X* This routine keeps track of our heading.
X* dir carries the direction from previous stages, all 8 directions
X* are mapped to numbers 1..4 (opposite directions get same number).
X* If directions is undetermined so far, dir is 0.
X* -1 means pixels are no more on same line (requires AreaDraw.)
Xwhich_dir:
X move.w startx,d2
X move.w starty,d3
X sub.w d0,d2
X sub.w d1,d3
X
X tst.w d2 ; normalize (make opposite dirs equal)
X bpl.s pos_1
X neg.w d2
X neg.w d3
Xpos_1
X tst.w d3
X bpl.s pos_2
X neg.w d2
X neg.w d3
Xpos_2
X
X tst.w d2 ; now determine direction.
X beq.s dir_03
X bpl.s dir_12
X;dir4
X add.w d2,d3
X bne.s dir_illegal ; not diagonal!
X moveq #4,d2
X bra.s dir_proc
Xdir_12
X tst.w d3
X beq.s dir_1
X;dir_2
X cmp.w d2,d3
X bne.s dir_illegal ; not diagonal!
X moveq #2,d2
X bra.s dir_proc
Xdir_1
X moveq #1,d2
X bra.s dir_proc
Xdir_03
X tst.w d3
X beq.s dir_0
X;dir_3
X moveq #3,d2
X bra.s dir_proc
Xdir_0
X moveq #0,d2
X bra.s dir_proc
Xdir_illegal
X moveq #-1,d2
Xdir_proc
X move.b dir,d3
X beq.s dir_valid
X tst.b d2
X beq.s dir_OK
X cmp.b d2,d3
X beq.s dir_OK
X;neither valid!
X move.b #-1,dir
X rts
Xdir_valid
X move.b d2,dir
Xdir_OK
X rts
X
X
XAreaEnd:
X move.l a1,-(a7)
X move.w prevx,d0
X move.w prevy,d1
X Call AreaDraw ; force dirty buffers out
X move.l (a7)+,a1
X Call AreaEnd
X rts
X
X* Needed by my Area routines
X
Xprevx ds.w 1
Xprevy ds.w 1
Xstartx ds.w 1
Xstarty ds.w 1
Xdir ds.b 1
X
X* perhaps this should be a section of its own.
X
XGfxName dc.b 'graphics.library',0
X
X end
X
END_OF_FILE
if test 26440 -ne `wc -c <'source/brot.asm'`; then
echo shar: \"'source/brot.asm'\" unpacked with wrong size!
fi
# end of 'source/brot.asm'
fi
if test -f 'source/gui.asm.aa' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'source/gui.asm.aa'\"
else
echo shar: Extracting \"'source/gui.asm.aa'\" \(26145 characters\)
sed "s/^X//" >'source/gui.asm.aa' <<'END_OF_FILE'
X
X* This file: gui v1.00
X
X* (c) 1990 by H. Helminen
X
X* linkage information:
X* blink gui.o brot.o pipe.o to mandel lib amiga.lib
X
X* And now for something completely different:
X* A graphical user interface for MandelBrot.
X
X* of course by The DM (Hannu Helminen, dm@stekt.oulu.fi)
X
X* BUGS: many, including
X* - coordinates in screen title may trash window title bar
X* - if not enough memory, 56 bytes will disappear.
X
X NOLIST
X INCLUDE "macros.i"
X INCLUDE "mbrot.i"
X INCLUDE "iff.i"
X INCLUDE "exec/lists.i"
X INCLUDE "exec/memory.i"
X INCLUDE "exec/ports.i"
X INCLUDE "exec/alerts.i"
X INCLUDE "devices/timer.i"
X INCLUDE "libraries/dos.i"
X INCLUDE "libraries/dosextens.i"
X INCLUDE "intuition/screens.i"
X INCLUDE "intuition/intuition.i"
X INCLUDE "workbench/workbench.i"
X INCLUDE "workbench/startup.i"
X
X XREF _LVOAlert
X
X* Misc defines
X
XDEPTH EQU 5 ; # of bitplanes (use at least 3 (2 is minimum))
XSCREEN EQU 0
X
X* SCREEN: Select one of the following:
X
X* non-lace lace
X* lores 0 2
X* hires 1 3
X
X* SCREEN determines VIEWMODE, screen size and mb_dx/mb_dy scaling.
X* NOTE: if SCREEN > 0, max. magnification will be 28
X
X ifeq SCREEN-0
XVIEWMODE EQU 0
XXSIZE EQU 320 ; Size of screen
XYSIZE EQU 256
X endc
X ifeq SCREEN-1
XVIEWMODE EQU V_HIRES
XXSIZE EQU 640
XYSIZE EQU 256
X endc
X ifeq SCREEN-2
XVIEWMODE EQU V_LACE
XXSIZE EQU 320
XYSIZE EQU 512
X endc
X ifeq SCREEN-3
XVIEWMODE EQU V_HIRES|V_LACE
XXSIZE EQU 640
XYSIZE EQU 512
X endc
X
XWINX EQU 20 ; Place & size of info window
XWINY EQU 20
XWINW EQU 148
XWINH EQU 80
X
XRASSIZE EQU ((XSIZE+15)/16*2)*YSIZE
XMAXVECT EQU 6553 ; Cant get bigger than this. (Sigh.)
X
XNORMAL_X EQU 0
XNORMAL_Y EQU 0
XNORMAL_JX EQU 0
XNORMAL_JY EQU 0
XNORMAL_I EQU 100
XNORMAL_ZOOM EQU $010000
XNORMAL_M EQU $060000
XMIN_M EQU $050000
X
X ifeq SCREEN
XMAX_M EQU $1d0000
X endc
X ifgt SCREEN
XMAX_M EQU $1c0000
X endc
X
XFLAGS1 EQU ACTIVATE|BACKDROP|BORDERLESS|REPORTMOUSE|RMBTRAP|NOCAREREFRESH
XFLAGS2 EQU WINDOWCLOSE|WINDOWDRAG|RMBTRAP|NOCAREREFRESH
X
XIDCMP1 EQU MOUSEMOVE|MOUSEBUTTONS|RAWKEY
XIDCMP2 EQU GADGETUP|GADGETDOWN|CLOSEWINDOW|RAWKEY
X
XFAKECLASS EQU 3 ; This pretends to be one of IDCMP classes
X
XZOOM EQU 0 ; these internal tokens represent method of zooming
XREDRAW EQU 1
XRESET EQU 2
X
XTRUE EQU 1
XFALSE EQU 0
X
X* Import brot entry point
X XREF MandelBrot
X
X* A simple macro that converts letters to upper case
Xtoupper macro
X cmp.b #'a',\1
X blo.s no\@
X sub.b #'a'-'A',\1
Xno\@: ds.w 0 ; needed for assembler's sake.
X endm
X
X
X LIST
X
X
X SECTION main,CODE
X
X* This is where the actual code begins.
X push d1-d7/a0-a6
X
X move.l a0,a3
X move.w d0,d3
X
X* We need to find out whether we have been invoked from CLI or WorkBench
X sub.l a1,a1
X Base Exec
X Call FindTask
X move.l d0,a0 ; This is a process, right?
X move.l pr_CLI(a0),d0
X beq.s from_WB
X
X clr.b -1(a3,d3.w)
X clr.l WBmessage ; from CLI
X move.l d0,a0
X add.l a0,a0 ; BPTR conversion
X add.l a0,a0
X move.l cli_CommandName(a0),a0 ; BSTR
X add.l a0,a0 ; BPTR conversion
X add.l a0,a0 ; now here we'll find a BCPL string...
X move.b (a0)+,d0 ; get len and goto first character
X move.l a0,MyName ; save name
X ext.w d0
X move.w d0,MyNameLen ; and length
X
X bra.s common_code
Xfrom_WB:
X lea pr_MsgPort(a0),a3
X move.l a3,a0
X Call WaitPort
X move.l a3,a0
X Call GetMsg
X move.l d0,WBmessage ; Do not reply until ready to exit.
X
X move.l d0,a0
X move.l sm_ArgList(a0),d0 ; Argument list
X beq.s common_code
X move.l d0,a0
X move.l wa_Lock(a0),d2 ; lock to current directory
X move.l wa_Name(a0),a0
X move.l a0,MyName ; save name
X moveq #-1,d1
X1$
X addq.w #1,d1
X tst.b (a0)+
X bne.s 1$
X move.w d1,MyNameLen ; and length
X
Xcommon_code:
X
X* Open some libraries
X lea _DosLib,a1
X moveq #0,d0
X Call OpenLibrary
X move.l d0,_DosBase
X bne.s dos_ok
X ALERT AG_OpenLib|AO_DOSLib
X bra nodos
Xdos_ok:
X tst.l WBmessage
X beq.s 1$
X move.l d2,d1
X Base Dos
X Call CurrentDir
X Base Exec
X1$
X lea _IntuitionLib,a1
X moveq #0,d0
X Call OpenLibrary
X move.l d0,_IntuitionBase
X bne.s intui_ok
X ALERT AG_OpenLib|AO_Intuition
X bra nointui
Xintui_ok:
X lea _GfxLib,a1
X moveq #0,d0
X Call OpenLibrary
X move.l d0,_GfxBase
X bne.s gfx_ok
X ALERT AG_OpenLib|AO_GraphicsLib
X bra nogfx
Xgfx_ok:
X
X* Open timer.device
X lea _TimerDev,a0
X moveq #UNIT_VBLANK,d0
X lea IOreq,a1
X moveq #0,d1
X Call OpenDevice
X tst.b d0
X beq.s timer_ok
X ALERT AG_OpenDev|AO_TimerDev
X bra timererr
Xtimer_ok:
X* initialize msgport
X lea MsgPort,a2
X move.b #NT_MSGPORT,LN_TYPE(a2)
X clr.b LN_PRI(a2)
X clr.l LN_NAME(a2)
X move.b #PA_SIGNAL,MP_FLAGS(a2) ; signal me when done
X
X moveq #-1,d0
X move.b #ERROR_nosignal,error
X Call AllocSignal ; get a signal bit
X tst.b d0
X bmi nosignal
X move.b d0,MP_SIGBIT(a2)
X
X sub.l a1,a1
X Call FindTask
X move.l d0,MP_SIGTASK(a2)
X ; task to be signalled
X lea MP_MSGLIST(a2),a0
X NEWLIST a0 ; init link fields
X lea IOreq,a0
X move.l a2,MN_REPLYPORT(a0)
X clr.l UseReq ; mark it as not being in use
X
X move.l a3,a0
X
X lea MyMandelBrot,a4
X
X move.w #0,mb_x1(a4)
X move.w #0,mb_y1(a4)
X move.w #XSIZE-1,mb_x2(a4)
X move.w #YSIZE-1,mb_y2(a4)
X
X* Defaults
X move.b #ERROR_none,error
X move.w #NORMAL_I,mb_i(a4)
X move.b #MBF_AUTOPREC|MBF_AUTOCRAWL,mb_flags(a4)
X move.b #TRUE,inter
X move.b #ZOOM,method
X clr.b isdrawn
X clr.w Counter
X clr.b saveit
X
X move.l #NORMAL_ZOOM,Zoom ; 2^(-1) = 50%
X move.l #NORMAL_M,Magnify ; 2^(-6) = 1/64
X move.l #NORMAL_X,CurrentX
X move.l #NORMAL_Y,CurrentY
X move.l #NORMAL_JX,mb_jx(a4)
X move.l #NORMAL_JY,mb_jy(a4)
X
X lea CtrlC,a1
X move.l a1,mb_break(a4) ; Call-back procedure
X
X move.w #(1<<DEPTH)-2,mb_colors(a4)
X
X* This is again WB/CLI specific code, option processing
X tst.l WBmessage
X beq CLI_1
X
X* WB option stuff
X Base Exec
X lea _IconLib,a1
X moveq #0,d0
X Call OpenLibrary
X tst.l d0
X bne.s iconlib_ok
X* Currently this error is not reported...
X move.b #ERROR_iconlib,error
X bra options_done
Xiconlib_ok
X move.l d0,a6
X move.l MyName,a0
X Call GetDiskObject
X tst.l d0
X bne.s diskobject_ok
X move.b #ERROR_noicon,error
X bra.s close_icon_lib
Xdiskobject_ok
X move.l d0,a5 ; disk object
X lea WBjumptable,a2
X lea WBoptions,a3
Xbrowse_tools
X tst.b (a3) ; The last in line?
X beq.s icons_done
X move.l do_ToolTypes(a5),a0
X move.l a3,a1
X Call FindToolType
X move.l (a2)+,a1 ; The actual address to jump to
X tst.l d0
X beq.s tool_notfound
X move.l d0,a0
X jsr (a1)
X beq.s wrong_option
Xtool_notfound
X tst.b (a3)+
X bne.s tool_notfound ; Find next tool type
X bra.s browse_tools
Xwrong_option
X move.b #ERROR_tooltype,error
Xicons_done
X move.l a5,a0
X Call FreeDiskObject
Xclose_icon_lib
X move.l a6,a1
X Base Exec
X Call CloseLibrary
X tst.b error
X bne nosignal
X bra.s options_done
X
XCLI_1
X lea LongUsage,a3
X move.l #LongLen,d3
X tst.b (a0)
X beq.s options_done
X cmp.b #'?',(a0)
X beq.s usage
X
X move.b #ERROR_cmdline,error
X lea ShortUsage,a3
X move.l #ShortLen,d3
Xgetnext:
X move.b (a0)+,d0
X beq.s options_done
X cmp.b #' ',d0
X beq.s getnext
X cmp.b #8,d0
X beq.s getnext
X cmp.b #'-',d0
X bne.s usage
X
X move.b (a0)+,d0
X lea options,a1
X lea jumptable,a2
X
X toupper d0
Xgetopt:
X move.l (a2)+,a5
X cmp.b (a1)+,d0
X bne.s next
X jsr (a5)
X beq.s usage ; a result of zero means wrong option
X bra.s getnext
Xnext:
X tst.b (a1)
X bne.s getopt
Xusage:
X Base Dos
X Call Output
X move.l d0,d1
X move.l a3,d2
X Call Write
X bra noscreen ; draw nothing
Xoptions_done:
X
X* Screen to display the new map.
X lea MyNewScreen,a0
X Base Intuition
X Call OpenScreen
X move.b #ERROR_noscreen,error
X move.l d0,MyScreen
X beq noscreen
X move.l d0,a2
X
X move.l a2,InsertScreen1
X move.l a2,InsertScreen2
X
X lea sc_ViewPort(a2),a3
X
X* First window that takes over entire screen
X lea MyNewWindow1,a0
X Call OpenWindow
X move.b #ERROR_nowindow,error
X move.l d0,MyWindow1
X beq nowindow
X
X* This version fetches windows rastport.
X move.l d0,a0
X move.l wd_RPort(a0),a2
X move.l a2,mb_RastPort(a4)
X
X move.l a3,a0
X lea Colors,a1
X moveq #(1<<DEPTH),d0
X Base Gfx
X Call LoadRGB4
X
X* Now get a TmpRas to screen
X move.l #RASSIZE,d0
X moveq #MEMF_CHIP,d1
X move.l d1,d2
X Base Exec
X Call AllocMem
X move.b #ERROR_nomem,error
X move.l d0,Mem1
X beq nomem1
X lea MyTmpRas,a3
X move.l d0,a1
X move.l a3,a0
X move.l d2,d0
X Base Gfx
X Call InitTmpRas
X move.l a3,rp_TmpRas(a2)
X
X move.l #MAXVECT*5,d0
X moveq #0,d1
X Base Exec
X Call AllocMem
X move.l d0,Mem2
X beq nomem2
X lea MyAreaInfo,a3
X move.l a3,a0
X move.l d0,a1
X move.l #MAXVECT,d0
X Base Gfx
X Call InitArea
X move.l a3,rp_AreaInfo(a2)
X
X move.b #ERROR_none,error
X* main loop if 'interactive'
Xloop:
X move.l Magnify,d0
X move.l #MAX_M,d1
X cmp.l d1,d0
X bls.s 1$
X move.l d1,d0
X1$:
X move.l #MIN_M,d1
X cmp.l d1,d0
X bhs.s 2$
X move.l d1,d0
X2$:
X move.l d0,Magnify
X bsr Transform
X move.l Magnify,OldMagnify
X
X* This is why we did all the above... and will be doing all the below...
X* Draw mandelbrot!
X move.l a4,a0
X jsr MandelBrot
X
X tst.b inter
X beq exit ; user didnt want us to be interactive.
X
X* A friend of mine once pointed out that the doings of my
X* programs are often commented to be done by "we". Don't know why.
X
X* Perhaps I think my program is a person, and we are doing the
X* thing together, I by designing the program, and the program
X* in turn by running it.
X
X* One of these days, I may actually begin to talk to my programs.
X* Is that all right to you, my tiny little proggie?
X
X bsr calculate
Xreopen:
X* Open another window
X lea MyNewWindow2,a0
X Base Intuition
X Call OpenWindow
X move.l d0,MyWindow2
X beq exit_dont_save ; could not get memory
X* Thenafter, refresh allll gadgets.
X
X* This gives refresh_m and refresh_z a hassle-free operation
X move.b method,d7
X move.b #RESET,method
X
X move.l CurrentX,d0
X bsr refresh_x
X move.l CurrentY,d0
X bsr refresh_y
X move.l Magnify,d0
X bsr refresh_m
X move.w mb_i(a4),d0
X bsr refresh_i
X move.l Zoom,d0
X bsr refresh_z
X
X move.b d7,method
X
X bsr refresh_set
X bsr refresh_zoom ; this does also DrawGrid
X
Xmsgloop:
X bsr GetMessage
X bne exitloop ; nonzero if user issued break
Xgotmessage:
X Base Intuition
X cmp.l #CLOSEWINDOW,d2
X bne.s no_close
X
X
X* Info window is about to be closed. Hide also title bar.
X move.l MyWindow2,a0
X
X* This copies both LeftEdge and TopEdge to NewWindow structure
X* This way when the window is opened again, it will be in same place.
X move.l wd_LeftEdge(a0),MyNewWindow2
X Call CloseWindow
X clr.l MyWindow2 ; This window is closed
X move.l MyScreen,a0
X moveq #FALSE,d0
X Call ShowTitle
X bsr RemoveGrid
X
X* Resume when either button pressed
Xget_it: bsr GetMessage
X bne exit ; break, no need to close window
X cmp.l #MOUSEBUTTONS,d2
X bne.s get_it ; wait for it to happen
X
X* Restore all
X bsr DrawGrid
X move.l MyScreen,a0
X moveq #TRUE,d0
X Base Intuition
X Call ShowTitle
X bra reopen ; resume window
X
X
Xno_close:
X cmp.l #MOUSEMOVE,d2
X bne.s no_move
X bsr dispCoords ; All we do here is to display current
X bra.s msgloop ; coordinates
X
X
Xno_move:
X cmp.l #MOUSEBUTTONS,d2
X bne.s no_buttons
X cmp.w #SELECTDOWN,d3
X bne.s no_left_button
X bsr LeftButton ; 3 things might get returned:
X beq msgloop ; finished
X bmi exitloop ; ^C
X bra zoom_draw ; There has been a double-click -> Draw!
Xno_left_button:
X cmp.w #MENUDOWN,d3
X bne.s no_buttons
X bsr RightButton
X bne exitloop
X bra msgloop
Xno_buttons:
X
X cmp.w #GADGETDOWN,d2
X bne.s no_gadg_down
X move.w gg_GadgetID(a5),d1 ; Gadget's ID.
X move.w d1,d0
X and.w #STRING,d0
X beq.s not_string_gadget
X
X bsr StringGadgetDown ; we also get one message here.
X bne exitloop ; sigh. (l)user wants to get rid of us
X bra gotmessage ; yeah, we've already got one.
Xnot_string_gadget:
X bsr OtherGadgetDown ; Three things might return from this:
X bmi.s zoom_draw ; negative if zoom
X bne exitloop ; positive if exit
X
Xno_gadg_down:
X cmp.l #RAWKEY,d2
X bne.s no_rawkey
X cmp.w #$21,d3 ; RAW key code for 'S'
X bne.s no_rawkey
X btst #IEQUALIFIERB_CONTROL,d4
X beq.s no_rawkey
X move.l MyWindow2,a0
X move.l wd_LeftEdge(a0),MyNewWindow2 ; See previous CloseWindow
X Call CloseWindow
X clr.l MyWindow2 ; This window is closed
X move.l MyScreen,a0
X moveq #FALSE,d0
X Call ShowTitle
X bsr RemoveGrid
X
X bsr SavePicture
X
X bsr DrawGrid
X move.l MyScreen,a0
X moveq #TRUE,d0
X Base Intuition
X Call ShowTitle
X bra reopen ; open window again
X
Xno_rawkey:
X bra msgloop ; and zero if nothing
X
Xzoom_draw:
X move.l MyWindow2,a0
X Base Intuition
X move.l wd_LeftEdge(a0),MyNewWindow2 ; See previous CloseWindow
X Call CloseWindow
X bsr RemoveGrid
X cmp.b #ZOOM,method
X beq.s 1$
X cmp.b #REDRAW,method
X beq.s 2$
X move.l #NORMAL_M,Magnify
X move.l #NORMAL_X,CurrentX
X move.l #NORMAL_Y,CurrentY
X bra loop
X1$:
X move.l Zoom,d0
X add.l d0,Magnify
X2$:
X bra loop
X
X
X
X
Xexitloop:
X* Close window
X move.l MyWindow2,a0
X Base Intuition
X Call CloseWindow
X bsr RemoveGrid
X
X* Leave ship
Xexit:
X* If non-interactive and user explicitely set -s option, save picture.
X tst.b inter
X bne.s exit_dont_save
X tst.b saveit
X beq.s exit_dont_save
X bsr SavePicture
Xexit_dont_save
X move.l MyScreen,a0
X moveq #FALSE,d0
X Base Intuition
X Call ShowTitle
X
X move.l Mem2,a1
X move.l #5*MAXVECT,d0
X Base Exec
X Call FreeMem
Xnomem2:
X move.l Mem1,a1
X move.l #RASSIZE,d0
X Base Exec
X Call FreeMem
Xnomem1:
X Base Intuition
X move.l MyWindow1,a0
X Call CloseWindow
Xnowindow:
X move.l MyScreen,a0
X Call CloseScreen
Xnoscreen:
X lea MsgPort,a0
X move.b MP_SIGBIT(a0),d0
X Base Exec
X Call FreeSignal
Xnosignal:
X lea IOreq,a1
X Call CloseDevice
Xtimererr:
X move.l _GfxBase,a1
X Call CloseLibrary
Xnogfx:
X move.l _IntuitionBase,a1
X Call CloseLibrary
Xnointui:
X tst.b error
X beq.s close_dos ; no error
X
X Base Dos
X tst.l WBmessage
X beq.s CLI_2
X lea stdout_name,a0
X move.l a0,d1
X move.l #MODE_NEWFILE,d2
X Call Open
X tst.l d0
X beq.s close_dos
X bra.s common_code2
XCLI_2
X Call Output
Xcommon_code2
X move.l d0,d4 ; save file handle for further use
X
X* First, output our name.
X move.l d4,d1
X move.l MyName,d2
X move.w MyNameLen,d3
X ext.l d3
X Call Write
X
X* Then, the error message.
X move.l d4,d1
X move.b error,d0
X ext.w d0
X lsl.w #2,d0
X lea errors,a0
X move.l 0(a0,d0.w),a0
X move.l a0,d2
X moveq #-1,d3
X1$
X addq.l #1,d3
X tst.b (a0)+
X bne.s 1$
X Call Write
X
X tst.l WBmessage
X beq.s close_dos
X move.l #2*TICKS_PER_SECOND,d1
X* REM ALLOW TIME FOR USER TO RELEASE BUTTON FROM LAST PUSH
X Call Delay
X move.l d4,d1
X Call Close ; close stdout window
Xclose_dos
X Base Exec
X move.l _DosBase,a1
X Call CloseLibrary
X move.l WBmessage,d0
X beq.s nodos
X Call Forbid
X move.l d0,a1
X Call ReplyMsg ; Now WB knows we are safe to get rid of
Xnodos:
X moveq #0,d0
X move.b error,d0
X beq.s 2$
X moveq #RETURN_FAIL,d0
X2$:
X pull d1-d7/a0-a6
X rts
X
XRemoveGrid:
X tst.b isdrawn
X beq nothing_to_remove
X
X push d0-d2/a0-a2/a6
X
X Base Intuition
X move.l MyWindow1,a0
X move.l wd_RPort(a0),a2
X
X* DrawGrid has conveniently set up some values for me. How nice of him!
X move.w centerx,d0
X move.w centery,d1
X move.l pic_c,a1
X bsr.s remove_1
X
X move.w lowx,d0
X move.w lowy,d1
X move.l pic_tl,a1
X bsr.s remove_1
X
X move.w lowx,d0
X move.w highy,d1
X move.l pic_bl,a1
X bsr.s remove_1
X
X move.w highx,d0
X move.w lowy,d1
X move.l pic_tr,a1
X bsr.s remove_1
X
X move.w highx,d0
X move.w highy,d1
X move.l pic_br,a1
X bsr.s remove_1
X
X clr.b isdrawn
X pull d0-d2/a0-a2/a6
Xnothing_to_remove:
X rts
X
Xremove_1:
X move.l a2,a0
X move.l a1,d2
X beq.s 1$
X Call DrawBorder
X1$: rts
X
X
XDrawGrid:
X bsr RemoveGrid
X cmp.b #ZOOM,method
X beq.s draw_yes
X cmp.b #RESET,method
X beq draw_over
X move.l Magnify,d0
X cmp.l OldMagnify,d0
X bne draw_over
Xdraw_yes:
X push a0-a2/a6/d0-d7
X move.l prex,d0
X move.l prey,d1
X move.b #TRUE,isdrawn
X
X move.l d0,prex
X move.l d1,prey
X move.l #$8000,d2 ; round
X add.l d2,d0
X add.l d2,d1
X
X move.l d0,d4
X move.l d1,d5
X
X swap d0
X swap d1
X
X moveq #0,d2 ; record # of crossings
X Base Intuition
X lea Cross,a1
X move.l MyWindow1,a0
X move.l wd_RPort(a0),a2
X
X cmp.w mb_x1(a4),d0
X bge.s 1$
X move.w mb_x1(a4),d0
X lea LeftLeft,a1
X addq.w #1,d2
X1$:
X cmp.w mb_x2(a4),d0
X ble.s 2$
X move.w mb_x2(a4),d0
X lea RightRight,a1
X addq.w #1,d2
X2$:
X cmp.w mb_y1(a4),d1
X bge.s 3$
X move.w mb_y1(a4),d1
X lea UpUp,a1
X addq.w #1,d2
X3$:
X cmp.w mb_y2(a4),d1
X ble.s 4$
X move.w mb_y2(a4),d1
X lea DownDown,a1
X addq.w #1,d2
X4$:
X cmp.w #1,d2 ; only 1 crossing allowed
X bls.s ok_to_disp
X clr.l pic_c
X bra.s cross_over
Xok_to_disp:
X move.w d0,centerx
X move.w d1,centery
X
X move.l a2,a0
X move.l a1,pic_c
X Call DrawBorder
Xcross_over:
X move.w mb_x2(a4),d0
X sub.w mb_x1(a4),d0
X move.l Zoom,d3
X
X cmp.b #REDRAW,method ; if redraw, grid has size of screen
X bne.s revolution
X moveq #0,d3
Xrevolution:
X add.l #$10000,d3
X bmi pig_big
X
X moveq #0,d1
X moveq #0,d2
X bsr Power2
X* Hey! What are you doing?
X* We will find how long the side of the grid should be.
X* If Zoom < -$10000, it wont fit on the screen same time as
X* crosshairs. And adding $10000 means halving the distance,
X* and as it happens, that is just what we want!
X move.l d0,d6
X
X move.w mb_y2(a4),d0
X sub.w mb_y1(a4),d0
X bsr Power2 ; d1-d3 remain!
X move.l d0,d7
X
X move.l d4,d2
X move.l d5,d3
X sub.l d6,d2 ; note! d7 has a remainder similar to
X sub.l d7,d3 ; that of d4
X add.l d6,d4
X add.l d7,d5
X swap d2
X swap d3
X swap d4
X swap d5
X
X moveq #0,d6
X move.w mb_x1(a4),d0
X move.w mb_x2(a4),d1
X cmp.w d0,d2
X bge.s 1$
X move.w d0,d2
X bset #0,d6
X1$:
X cmp.w d1,d2
X bgt pig_big
X cmp.w d1,d4
X ble.s 2$
X move.w d1,d4
X bset #1,d6
X2$:
X cmp.w d0,d4
X blt pig_big
X move.w mb_y1(a4),d0
X move.w mb_y2(a4),d1
X cmp.w d0,d3
X bge.s 3$
X move.w d0,d3
X bset #2,d6
X3$:
X cmp.w d1,d3
X bgt pig_big
X cmp.w d1,d5
X ble.s 4$
X move.w d1,d5
X bset #3,d6
X4$:
X cmp.w d0,d5
X blt pig_big
X
X move.w d2,lowx
X move.w d3,lowy
X move.w d4,highx
X move.w d5,highy
X
X* process the corners.
X push a3-a5 ; NEED some workspace
X lea TopLeft,a1
X lea BottomLeft,a3
X lea TopRight,a4
X lea BottomRight,a5
X btst.b #0,d6
X beq no_left
X lea LeftLeft,a1
X move.l a1,a3
Xno_left:
X btst.b #1,d6
X beq.s no_right
X lea RightRight,a4
X move.l a4,a5
Xno_right:
X btst.b #2,d6
X beq.s no_up
X lea UpUp,a1
X move.l a1,a4
Xno_up:
X btst.b #3,d6
X beq.s no_down
X lea DownDown,a3
X move.l a3,a5
Xno_down:
X not.b d6
X move.b d6,d0
X and.b #%0101,d0
X bne.s skip_tl
X sub.l a1,a1
Xskip_tl:
X move.b d6,d0
X and.b #%1001,d0
X bne.s skip_bl
X sub.l a3,a3
Xskip_bl:
X move.b d6,d0
X and.b #%0110,d0
X bne.s skip_tr
X sub.l a4,a4
Xskip_tr:
X and.b #%1010,d6
X bne.s skip_br
X sub.l a5,a5
Xskip_br:
X move.l a2,a0
X move.l a1,pic_tl
X beq.s no_tl
X move.w d2,d0
X move.w d3,d1
X Call DrawBorder
Xno_tl:
X move.l a3,a1
X move.l a2,a0
X move.l a1,pic_bl
END_OF_FILE
if test 26145 -ne `wc -c <'source/gui.asm.aa'`; then
echo shar: \"'source/gui.asm.aa'\" unpacked with wrong size!
fi
# end of 'source/gui.asm.aa'
fi
echo shar: End of archive 3 \(of 4\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 4 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 4 archives.
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
--
Mail submissions (sources or binaries) to <amiga@uunet.uu.net>.
Mail comments to the moderator at <amiga-request@uunet.uu.net>.
Post requests for sources, and general discussion to comp.sys.amiga.misc.