[comp.sources.amiga] v91i019: Mandel 1.0 - yet another mandelbrot, Part03/04

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.