Article View: comp.sources.atari.st
Article #77v03i001: fract -- Monochrome Mandelbrot generator
From: Steven Grimm
Date: Tue, 31 Oct 1989 21:12
Date: Tue, 31 Oct 1989 21:12
1896 lines
42859 bytes
42859 bytes
Submitted-by: rosenkra@hall.cray.com (Bill Rosenkranz)
Posting-number: Volume 3, Issue 1
Archive-name: fract
this is just something i wipped up one day. i don't remember ever seeing
a mono mandelbrot generator (i dislike color :-), so here goes...enjoy.
it uses line A to plot pixels. should be portable to any bitmap computer
(i.e. sun, apollo, sgi, amiga, mac, pc, X11, ...). i tried to make the
portability things seperated for relative ease. i plan on doing an
X11 port soon (on a cray-2, to get some SPEED). i'd like to be able to
generate and display an image every few seconds (network is the limiting
factor :^). yafttms (yet another fly thru the mandelbrot set)...i will
also change the file to use the RLE-like scheme i mention somewhere...
in the spirit of a recent c.lang.c thread, the program uses some goto's!
included are some atari-specific line-A calls (like MWC libraries, i
think) which might be of general interest. written in alcyon as68.
i did not spend any time at all on the algorithm so expect 500+ second
runs. use "-i 50" for most everything (unless u run overnite). no
mouse support (you specify coord on command line).
-bill rosenkranz 10/2/89
rosenkra%boston@hall.cray.com
(binaries in c.b.atari.st)
------- cut here -------------------------
#! /bin/sh
# This is a shar archive. Extract with sh, not csh.
echo x - Readme
cat > Readme << '22842!Funky!Stuff!'
NAME
fract - Generate monochrome Mandelbrot set
USAGE
fract [options]
-i iterations (1000) defines "convergence"
-x xcenter (-1.0) center of viewport
-y ycenter (0.0)
-r range (3.0) size of viewport (width=height)
-s scale (3) 0 to 3, 0=coarse 3=fine
-v invert colors
-a add contours
-h hold screen before exit
-o outfile write results
-f infile view existing file (ignores -i,-x,-y,
-r,-s)
[defaults in parentheses. more help in man page, fract.6 -wjr]
this is a monochrome mandelbrot generator. it was originally written for
atari ST, but should port easily to amiga, pc, mac, sun, and X11. all you
really need is to be able to address and color a pixel. it may work on
color (med rez, i have not tried it) but you will only get the top half of
the image.
it generates images in a square only. on the st, this is 360x360 pixels
or about 129,000 pixels. it can take a while to generate an image so
it does it in 2 passes. the first pass is very coarse (45x45 "big" pixels).
you can break out of the calculation at any time with any keystroke.
you can also dump the binary data to a file (probably not portable for
non-680x0 systems because of byte order of shorts).
it works from a command line. you can set the iterations limit (default
is 1000 - much to large for most hacking). try "-i 50" for most work.
the default scaling is for finest image (single pixel). for a quicker
scan, try "-s 2" (arg for -s is 0 to 3, 0 is coarse, 3 is fine).
there are a couple of files to play with. these are binary data files
and unarc to around 250kB each. they are setup for atari ST using ffp
floats. there are only 3 floats stored and they are only used for annotation
so just skip them if you like. the files are in M0.ARC and M1.ARC. m0
is the full Mandelbrot set and m1 is a blowup of the area near the
tangency of the 2 big circles in the set. generate them with:
fract -o m0 -i 50
fract -o m1 -i 50 -x -0.9 -y -0.3 -r 0.13
Feel free to copy. Leave this file alone! No other restrictions on copying
or hacking. Use as you like.
(c) 1989 Bill Rosenkranz
net: rosenkra%boston@hall.cray.com
CIS: 71460,17
GENIE: W.ROSENKRANZ
22842!Funky!Stuff!
echo x - Manifest
cat > Manifest << '22842!Funky!Stuff!'
total 42
-rw-r--r-- 1 rosenkra 526 Oct 2 10:33 Makefile
-rw-r--r-- 1 rosenkra 601 Oct 2 17:09 Manifest
-rw-r--r-- 1 rosenkra 2242 Oct 2 10:33 Readme
-rw-r--r-- 1 rosenkra 4667 Oct 2 17:07 fract.6
-rw-r--r-- 1 rosenkra 20973 Oct 2 10:33 fract.c
-rw-r--r-- 1 rosenkra 5706 Oct 2 17:03 fract.man
-rw-r--r-- 1 rosenkra 690 Oct 2 10:33 linea0.s
-rw-r--r-- 1 rosenkra 774 Oct 2 10:33 linea1.s
-rw-r--r-- 1 rosenkra 685 Oct 2 10:33 linea2.s
-rw-r--r-- 1 rosenkra 1168 Oct 2 10:33 linea3.s
-rw-r--r-- 1 rosenkra 155 Oct 2 10:33 version.h
22842!Funky!Stuff!
echo x - fract.man
cat > fract.man << '22842!Funky!Stuff!'
fract(6) GAMES AND DEMOS fract(6)
NAME
fract - draw Mandelbrot fractals
SYNOPSIS
fract [options]
DESCRIPTION
Fract generates, stores, and displays fractal images from
the Mandelbrot set. Fract was originally written for the
Atari ST but it should be very easy to port to other hosts
like Macintosh, Amiga, PC, Sun, and X. All you really need
is to address a pixel and color it. It is meant for mono-
chrome displays but can be made to work on color systems as
well. On the Atari ST, it is meant for a shell but also
works from the desktop.
Fract was designed to vary both the threshhold for conver-
gence (or divergence) as well as the resolution of the
display. The default is maximum for both which can take a
long time to process. For most cases, you should be able to
get by with iteration count of 50 to 100. The default coor-
dinates plots the entire set. Use -x, -y, and -r to zoom in.
Other default values will simply plot the values in the set
black, outside white. The -a option allows you to alternate
black and white contours for those values outside the set
(where color displays make the pretty pictures).
For resolutions higher than the lowest (-s 0), fract first
calculates and plots the image for -s 0 -i 50, then calcu-
lates and plots the desired image. The first image is
fairly fast on the Atari ST (about 30 seconds) and looks
like "fat" pixels 8x8. This allows you to break the calcu-
lation if the image is not in range (with any key press). On
non-unix systems with no interrupt signals, you can break
the calculation with a keystroke after any pixel is done.
This program was based on an article in the December 1986
BYTE.
OPTIONS
The following command-line options are available:
-a Causes every other contour value to be drawn black. The
default is to just plot the threshhold (-i value) and
above.
-i iter
The default number of iterations dividing values in the
set versus values outside the set. The default is 1000
though 50 or 100 should be sufficient for most things.
Sun Release 3.5 Last change: 1
fract(6) GAMES AND DEMOS fract(6)
-x xcenter
The x coordinate of the viewing window. The default is
-1.0.
-y ycenter
The y coordinate of the viewing window. The default is
0.0.
-r range
The x and y range of the viewing window. The default is
3.0.
-s scale
The scale factor. Possible values currently are 0, 1,
2, and 3. 0 is for coarse and 3 is for fine grain.
-v This toggles the "colors" (black to white and visa
versa).
-h Hold display after plot (before return to the Atari
desktop, for example).
-o outfile
Write results to file outfile.
-f infile
Display previous results from file infile.
PORTING
Fract was designed to be ported to other environments. Most
of the code follows "normal" Unix conventions. The file I/O
needs changing for porting to non-680x0 architectures,
though it has even run on a Cray!
The following funtions are non-portable:
int init () - initialize things
int finish () - finish up
int check_key () - check for a key press (interrupt)
int wait_key () - wait for a key press
int do_pixel () - plot a pixel of some color
int do_line () - draw a line
int cursor () - toggle cursor on/off
int mv_cursor () - move cursor on screen
int clr_screen () - clear screen, home cursor
long do_time () - for elapsed times
FILE FORMAT
The binary file format for saved images uses non-portable
Sun Release 3.5 Last change: 2
fract(6) GAMES AND DEMOS fract(6)
formats (no binary data file is portable). Binary data is
much more compact, however. It is a simple matter to write
a simple program to convert to ASCII, however.
In general, words are 16-bit. Most of the data is integer
words. The byte order is normal 68000 order (first byte read
is most significant byte of word). The floating point data
was originally using the Motorola Fast Floating Point format
(FFP) largely because the development compiler is twice as
fast with FFP versus IEEE. Note that the floating point
data in the file is only for the textural display on the
image and will not effect image display at all.
Here is the data format:
magic (8 char, !<fract>)
machine (1 16-bit word, 0=Atari, 1=Amiga, 2=PC,
3=Mac, 4=Sun,...)
version (1 16-bit word, e.g. 100 or 0x00C8)
iter (1 16-bit word)
scale (1 16-bit word, 45, 90, 180, 360 pixels
per unit)
x (1 32-bit FFP float)
y (1 32-bit FFP float)
range (1 32-bit FFP float)
data (scale * scale 16-bit words)
...
AUTHOR
Version 1.0 October 1989 (c) 1989 Bill Rosenkranz
net: rosenkra%boston@hall.cray.com
CIS: 71460,17
GENIE: W.ROSENKRANZ
Sun Release 3.5 Last change: 3
22842!Funky!Stuff!
echo x - fract.6
cat > fract.6 << '22842!Funky!Stuff!'
.TH FRACT 6
.SH NAME
fract - draw Mandelbrot fractals
.SH SYNOPSIS
fract [options]
.SH DESCRIPTION
Fract generates, stores, and displays fractal images from the Mandelbrot set.
Fract was originally written for the Atari ST but it should be very easy
to port to other hosts like Macintosh, Amiga, PC, Sun, and X.
All you really need is to address a pixel and color it.
It is meant for monochrome displays but can be made to work on color
systems as well.
On the Atari ST, it is meant for a shell but also works from the desktop.
.PP
Fract was designed to vary both the threshhold for convergence (or divergence)
as well as the resolution of the display.
The default is maximum for both which can take a long time to process.
For most cases, you should be able to get by with iteration count of 50 to 100.
The default coordinates plots the entire set. Use -x, -y, and -r to zoom in.
Other default values will simply plot the values in the set black, outside
white.
The -a option allows you to alternate black and white contours for those
values outside the set (where color displays make the pretty pictures).
.PP
For resolutions higher than the lowest (-s 0), fract first calculates and
plots the image for -s 0 -i 50, then calculates and plots the desired image.
The first image is fairly fast on the Atari ST (about 30 seconds) and looks
like "fat" pixels 8x8.
This allows you to break the calculation if the image is not in range (with
any key press).
On non-unix systems with no interrupt signals, you can break the calculation
with a keystroke after any pixel is done.
.PP
This program was based on an article in the December 1986 BYTE.
.SH OPTIONS
The following command-line options are available:
.IP -a
Causes every other contour value to be drawn black. The default is to just
plot the threshhold (-i value) and above.
.IP "-i iterations"
The default number of iterations dividing values in the set versus values
outside the set. The default is 1000 though 50 or 100 should be sufficient
for most things.
.IP "-x xcenter"
The x coordinate of the viewing window. The default is -1.0.
.IP "-y ycenter"
The y coordinate of the viewing window. The default is 0.0.
.IP "-r range"
The x and y range of the viewing window. The default is 3.0.
.IP "-s scale"
The scale factor. Possible values currently are 0, 1, 2, and 3. 0 is for
coarse and 3 is for fine grain.
.IP -v
This toggles the "colors" (black to white and visa versa).
.IP -h
Hold display after plot (before return to the Atari desktop, for example).
.IP "-o outfile"
Write results to file outfile.
.IP "-f infile"
Display previous results from file infile.
.SH PORTING
Fract was designed to be ported to other environments. Most of the code
follows "normal" Unix conventions. The file I/O needs changing for porting
to non-680x0 architectures, though it has even run on a Cray!
.PP
The following funtions are non-portable:
.nf
int init () - initialize things
int finish () - finish up
int check_key () - check for a key press (interrupt)
int wait_key () - wait for a key press
int do_pixel () - plot a pixel of some color
int do_line () - draw a line
int cursor () - toggle cursor on/off
int mv_cursor () - move cursor on screen
int clr_screen () - clear screen, home cursor
long do_time () - for elapsed times
.fi
.SH FILE FORMAT
The binary file format for saved images uses non-portable formats (no binary
data file is portable).
Binary data is much more compact, however.
It is a simple matter to write a simple program to convert to ASCII, however.
.PP
In general, words are 16-bit. Most of the data is integer words. The byte
order is normal 68000 order (first byte read is most significant byte of
word).
The floating point data was originally using the Motorola Fast Floating
Point format (FFP) largely because the development compiler is twice as
fast with FFP versus IEEE.
Note that the floating point data in the file is only for the textural
display on the image and will not effect image display at all.
.PP
Here is the data format:
.nf
magic (8 char, !<fract>)
machine (1 16-bit word, 0=Atari, 1=Amiga, 2=PC,
3=Mac, 4=Sun,...)
version (1 16-bit word, e.g. 100 or 0x00C8)
iter (1 16-bit word)
scale (1 16-bit word, 45, 90, 180, 360 pixels
per unit)
x (1 32-bit FFP float)
y (1 32-bit FFP float)
range (1 32-bit FFP float)
data (scale * scale 16-bit words)
\&...
.fi
.SH AUTHOR
.nf
Version 1.0 October 1989 (c) 1989 Bill Rosenkranz
net: rosenkra%boston@hall.cray.com
CIS: 71460,17
GENIE: W.ROSENKRANZ
.fi
22842!Funky!Stuff!
echo x - Makefile
cat > Makefile << '22842!Funky!Stuff!'
# makefile for atari TOS version of fract (alcyon 4.14)
#
# [flags are for my custom cc(1) and make(1). yours may vary. -wjr]
FP_FLAG = # use -e for ieee
CFLAGS = -new # -new for alcyon 4.14
LDFLAGS = -new -s $(FP_FLAG) # -s for no symbols
LIBS =
FR_OBJS = fract.o linea0.o linea1.o linea3.o
TARGET = fract.ttp
$(TARGET): $(FR_OBJS)
$(CC) $(LDFLAGS) -o $(TARGET) $(FR_OBJS) $(LIBS)
fract.o: fract.c version.h
linea0.o: linea0.s
$(CC) -c $(CFLAGS) linea0.s
linea1.o: linea1.s
$(CC) -c $(CFLAGS) linea1.s
linea3.o: linea3.s
$(CC) -c $(CFLAGS) linea3.s
22842!Funky!Stuff!
echo x - fract.c
cat > fract.c << '22842!Funky!Stuff!'
#define atarist /* machine (atarist, amiga, ibmpc, mac, sun, x11) */
#define alcyon /* specific compiler, if any */
/*
* NAME: fract - Generate monochrome Mandelbrot set
*
* AUTHOR: (c) 1989 Bill Rosenkranz
*
* net: rosenkra%boston@hall.cray.com
* CIS: 71460,17
* GENIE: W.ROSENKRANZ
*
* Feel free to copy. Leave this comment alone! No other
* restrictions on copying or hacking. Use as you like.
*
* MOTIVATION: I don't ever remember seeing a monochrome fractal
* generator. I like this "zebra" effect with -a. Try:
*
* fract -a -i 50 -x -0.9 -y 0.3 -r 0.5
*
* or unpack m1.arc and do:
*
* fract -a -f m1
*
* COMPILE (ST): cc -o fract.ttp fract.c linea0.s linea1.s linea3.s
*
* PORTABILITY: Works with Alcyon 4.14 (Atari ST), should port easily
* to Mac, Amiga, Sun, PC, X, etc. except for file
* formats on non-680x0 architectures.
*
* Floats in the files are only for text annotation.
* Uses FFP floats not IEEE in files (3 numbers, stored
* with putl). FFP is almost 2x faster. Here are formats
* for FFP and IEEE:
*
* FFP binary representation of 1.000000 is:
*
* /---------------------------- mantissa (24 bits)
* | /------- sign (1 bit)
* | | /--- exponent (7 bits)
* | | |
* mmmmmmmmmmmmmmmmmmmmmmmmseeeeeee
* 10000000000000000000000001000001
* ^
* MSbit
*
* mantissa: 100000000000000000000000
* sign: 0
* exponent: 1000001
*
*
* IEEE binary representation of 1.000000 is:
*
* /----------------- sign (1 bit)
* | /------------- exponent (8 bits)
* | | /--- mantissa (23 bits)
* | | |
* seeeeeeeemmmmmmmmmmmmmmmmmmmmmmm
* 00111111100000000000000000000000
* ^
* MSbit
*
* sign: 0
* exponent: 01111111(127)
* mantissa: 00000000000000000000000(0)
*
*
* Note: getw() must read 16-bit int and getl() must
* read 32-bit int from stream. putw() and putl() should
* work with the same sizes, respectively.
*
* For anyone hacking on the file stuff, do us all a
* favor and not try to write structures to the file.
* binary is bad enough. Binary structures is impossible.
*
* NOTES: Rough timings for scale=FINE, default x,y,range
* (8 Mhz atari ST):
*
* -i time
* ----- -------
* 10 560 sec
* 50 1350 sec
* 100 2280 sec
* (-i 100 on a cray-2 is about 2 sec, no hand opt *8^)
*
* The more points in the set in the zoom range, the
* longer it takes because it has to go to max_iter.
* The algorithm is pretty week and could be beefed up.
* This was a one day hack.
*
* I was thinking of some sort of RLE-like encoding of
* data. How about if MSbit set, that word tells now
* many of the next word gets repeated? So rather than:
*
* .... 0001 0001 0001 0001 0001 0001 0005 ....
*
* you use:
*
* .... 8006 0001 0005 ....
*
* This takes much longer to read and write a file.
*
* Make as a .ttp and use -h to hold for desktop or to
* take a snapshot.
*/
#include <stdio.h>
#include <math.h>
#include "version.h"
/*
* for portability of binary file (ha!)
*/
#undef WORD
#define WORD int /* 16-bit required */
#undef REAL
#define REAL float /* 32-bit required */
#undef LONG
#define LONG long /* 32-bit required */
#undef BYTE_WORD
#define BYTE_WORD 2 /* bytes per word */
#define BLACK 1 /* pixel colors */
#define WHITE 0
#define COARSE 45 /* ok for mono ST (pixels size) */
#define MED_COARSE 90 /* 360x360 pixel display */
#define MED_FINE 180
#define FINE 360
#define F_ATARIST 0 /* for file formats. all 680x0 */
#define F_AMIGA 1 /* should be the same. */
#define F_IBMPC 2
#define F_MACINTOSH 3
#define F_SUN 4
/*
* forward references and externals. non-portable are indicated...
*/
extern long getl ();
extern int getw (); /* MUST read 16-bit (short) */
int do_mandel ();
int plt_mandel ();
int plot_logic ();
int pr_params ();
int usage ();
int init (); /* atari ST */
int finish (); /* atari ST */
int check_key (); /* atari ST (BIOS) */
int wait_key (); /* atari ST (BIOS) */
int do_pixel (); /* atari ST (line A) */
int do_line (); /* atari ST (line A) */
int cursor (); /* atari ST (gemdos, vt52) */
int mv_cursor (); /* atari ST (vt52) */
int clr_screen (); /* atari ST (gemdos, vt52) */
long do_time (); /* atari ST (gemdos, sysvar) */
WORD array_G[FINE][FINE]; /* storage for the set (~250 kB) */
/*------------------------------*/
/* main */
/*------------------------------*/
main (argc, argv)
int argc;
char *argv[];
{
int max_iter; /* the threshold (normally 1000) */
int scale; /* pixels per unit */
int oset; /* offset of plot from scrn corner */
int normcolor; /* 1=normal, 0=reverse colors */
int alternate; /* 0=no contours, 1=use alt cont */
int hold_scrn; /* for hold before return to desktop */
int save_it; /* to save as file */
int load_it; /* to load from file */
int ret;
int this_vers = VERSION;
int file_vers;
int this_format = F_ATARIST;
int file_format;
long elapsed; /* elapsed seconds */
float x, /* coord of view center */
y;
float range; /* view width,height */
char fname[256];
char this_magic[10];
char file_magic[10]; /* magic for file */
FILE *stream;
union F_TO_L /* for float<-->long (i/o only) */
{
LONG _l;
REAL _f;
} f_to_l;
/*
* set defaults, initialize...
*/
strcpy (this_magic, "!<fract>");
normcolor = 1;
alternate = 0;
max_iter = 1000;
scale = FINE;
oset = 20;
hold_scrn = 0;
save_it = 0;
load_it = 0;
x = -0.5; /* image of full set... */
y = 0.0;
range = 3.0;
init ();
/*
* parse args...
*/
argc--, argv++;
while (argc)
{
if (**argv == '-')
{
switch (*(*argv+1))
{
case 'i': /* iterations */
case 'I':
argc--, argv++;
if (argc < 1)
usage ();
max_iter = atoi (*argv);
if (max_iter < 1 || max_iter > 1000)
max_iter = 1000;
break;
case 'x': /* x coord of center */
case 'X':
argc--, argv++;
if (argc < 1)
usage ();
x = atof (*argv);
break;
case 'y': /* y coord of center */
case 'Y':
argc--, argv++;
if (argc < 1)
usage ();
y = atof (*argv);
break;
case 'r': /* range */
case 'R':
argc--, argv++;
if (argc < 1)
usage ();
range = atof (*argv);
break;
case 's': /* scale */
case 'S':
argc--, argv++;
if (argc < 1)
usage ();
scale = atoi (*argv);
switch (scale)
{
case FINE:
case COARSE:
case MED_FINE:
case MED_COARSE:
break;
case 0:
scale = COARSE;
break;
case 1:
scale = MED_COARSE;
break;
case 2:
scale = MED_FINE;
break;
default:
scale = FINE;
break;
}
break;
case 'v': /* reverse video */
case 'V':
normcolor = 0;
break;
case 'a': /* alternate even/odd */
case 'A':
alternate = 1;
break;
case 'h': /* hold screen */
case 'H':
hold_scrn = 1;
break;
case 'o': /* save */
case 'O':
argc--, argv++;
if (argc < 1)
usage ();
strcpy (fname, *argv);
save_it = 1;
break;
case 'f': /* load file */
case 'F':
argc--, argv++;
if (argc < 1)
usage ();
strcpy (fname, *argv);
load_it = 1;
break;
default:
usage ();
}
}
else
usage ();
argc--, argv++;
}
if (alternate)
normcolor = (normcolor) ? 0 : 1;
/*
* if loading, read in data...
*/
if (load_it)
{
/*
* file format (words are 16-bit):
*
* magic (8 bytes)
* file format (word)
* program version (word)
* iter (word)
* scale (word)
* x (32-bit ffp float)
* y (32-bit ffp float)
* range (32-bit ffp float)
* data (scale * scale 16-bit words)
*
* (yes, i know binary data is NOT portable...)
*
* BTW: the union is used because a cast to long would
* convert (say) 1.789 to 1. the union unsures we store
* it with bits unchanged...
*/
int i;
int j;
#ifdef alcyon
if ((stream = fopenb (fname, "r")) == (FILE *) 0)
#else
if ((stream = fopen (fname, "rb")) == (FILE *) 0)
#endif
{
mv_cursor (51, 22);
fprintf (stderr,
"open input err, %s",
fname);
goto xit;
}
for (i = 0; i < 8; i++)
file_magic[i] = (char) getc (stream);
file_format = getw (stream);
file_vers = getw (stream);
max_iter = getw (stream);
scale = getw (stream);
f_to_l._l = (LONG) getl (stream); x = (float) f_to_l._f;
f_to_l._l = (LONG) getl (stream); y = (float) f_to_l._f;
f_to_l._l = (LONG) getl (stream); range = (float) f_to_l._f;
for (i = 0; i < scale; i++)
{
#ifdef alcyon
fread (array_G[i], BYTE_WORD, scale, stream);
/* read (stream->_fd, array_G[i], scale * 2);
this was significantly fast but did not work
properly. hmmm...*/
#else
for (j = 0; j < scale; j++)
array_G[i][j] = (WORD) getw (stream);
#endif
}
fclose (stream);
/*
* print parameters...
*/
pr_params (max_iter, scale, oset, x, y, range);
/*
* ...and just plot the set...
*/
plt_mandel (max_iter, scale, oset, normcolor, alternate, x, y, range);
goto xit;
}
/*
* this could eventually be a loop to allow users to pick new
* zoom area (here to xit:)
*/
/*
* print parameters...
*/
pr_params (max_iter, scale, oset, x, y, range);
/*
* do coarse grain (if interupted, proceed to fine grain)...
*/
do_time (1);
ret = do_mandel (((max_iter > 50) ? 50 : max_iter), COARSE, oset,
normcolor, alternate, x, y, range);
elapsed = do_time (2);
mv_cursor (51, 18); printf ("time = %ld (sec)", elapsed);
/*
* ...now do fine grain...
*/
if (scale != COARSE)
{
do_time (1);
ret = do_mandel (max_iter, scale, oset, normcolor, alternate,
x, y, range);
elapsed = do_time (2);
mv_cursor (51, 18); printf ("time = %ld (sec)", elapsed);
if (ret)
{
mv_cursor (51, 22); printf ("aborted!");
goto xit;
}
}
/*
* save file if needed...
*/
if (save_it)
{
int i;
int j;
#ifdef alcyon
if ((stream = fopenb (fname, "w")) == (FILE *) 0)
#else
if ((stream = fopen (fname, "wb")) == (FILE *) 0)
#endif
{
mv_cursor (51, 22);
fprintf (stderr,
"open output err, %s\n",
fname);
goto xit;
}
for (i = 0; i < 8; i++)
putc (this_magic[i], stream);
putw (this_format, stream);
putw (this_vers, stream);
putw (max_iter, stream);
putw (scale, stream);
f_to_l._f = (REAL) x; putl ((long) (f_to_l._l), stream);
f_to_l._f = (REAL) y; putl ((long) (f_to_l._l), stream);
f_to_l._f = (REAL) range; putl ((long) (f_to_l._l), stream);
for (i = 0; i < scale; i++)
{
#ifdef alcyon
fwrite (array_G[i], BYTE_WORD, scale, stream);
#else
for (j = 0; j < scale; j++)
putw (array_G[i][j], stream);
#endif
}
fclose (stream);
}
xit:
/*
* clean up and exit (no return)
*/
finish (hold_scrn);
}
/*------------------------------*/
/* usage */
/*------------------------------*/
usage ()
{
fprintf (stderr, "fract [options]\n");
fprintf (stderr, "\n");
fprintf (stderr, " -i iterations (1000)\n");
fprintf (stderr, " -x xcenter (-1.0)\n");
fprintf (stderr, " -y ycenter (0.0)\n");
fprintf (stderr, " -r range (3.0)\n");
fprintf (stderr, " -s scale (360 or 3)\n");
fprintf (stderr, " -v\n");
fprintf (stderr, " -a\n");
fprintf (stderr, " -h\n");
fprintf (stderr, " -o outfile\n");
fprintf (stderr, " -f infile\n");
cursor (1);
exit (1);
}
/*------------------------------*/
/* pr_params */
/*------------------------------*/
pr_params (max_iter, scale, oset, x, y, range)
int max_iter;
int scale;
int oset;
float x;
float y;
float range;
{
/*
* print parameters off to the side and make a box for the set.
*/
int l_scale = FINE;
int x1, x2, y1, y2;
mv_cursor (49, 1); printf ("%s", version_G);
mv_cursor (51, 3); printf ("iter = %d", max_iter);
mv_cursor (51, 4); printf ("xcenter = %f", x);
mv_cursor (51, 5); printf ("ycenter = %f", y);
mv_cursor (51, 6); printf ("range = %f", range);
mv_cursor (51, 7); printf ("scale = %d", scale);
mv_cursor (51, 9); printf ("xmin = %f", x - range/2.0);
mv_cursor (51, 10); printf ("xmax = %f", x + range/2.0);
mv_cursor (51, 11); printf ("ymin = %f", y - range/2.0);
mv_cursor (51, 12); printf ("ymax = %f", y + range/2.0);
fflush (stdout);
/*
* draw box...
*/
x1 = oset-1; x2 = oset+l_scale; /* top */
y1 = oset-1; y2 = y1;
do_line (x1, y1, x2, y2);
x1 = oset-1; x2 = oset+l_scale; /* bottom */
y1 = oset+l_scale; y2 = y1;
do_line (x1, y1, x2, y2);
x1 = oset-1; x2 = x1; /* left */
y1 = oset-1; y2 = oset+l_scale;
do_line (x1, y1, x2, y2);
x1 = oset+l_scale; x2 = x1; /* right */
y1 = oset-1; y2 = oset+l_scale;
do_line (x1, y1, x2, y2);
}
/*------------------------------*/
/* do_mandel */
/*------------------------------*/
int do_mandel (iter, scale, oset, normcolor, alternate, x, y, range)
int iter;
int scale;
int oset;
int normcolor;
int alternate;
float x,
y;
float range;
{
/*
* calculate the set and plot it as it is generated
*/
register int max_iter = iter;
register int ix, /* pixel number */
iy; /* row number */
register int count; /* count is the contour level */
float size; /* thing to compare for convergence */
float a, /* intermediates... */
b,
ac,
bc,
b1;
float gap; /* units for each pixel */
gap = range / (float) scale;
/*
* each row...
*/
for (iy = 0; iy < scale; iy++)
{
bc = y + (range / 2.0) - (float) iy * gap;
/*
* each pixel in row...
*/
for (ix = 0; ix < scale; ix++)
{
ac = x - (range / 2.0) + (float) ix * gap;
a = ac;
b = bc;
size = 0.0;
count = 0;
/*
* iterate...
*/
while (size < 4.0 && count < max_iter)
{
b1 = 2 * a * b;
a = a * a - b * b + ac;
b = b1 + bc;
size = a * a + b * b;
/*
* this is what we are after: the number
* of iterations to convergence/divergence
*/
count++;
}
/*
* store it...
*/
array_G[ix][iy] = (WORD) count;
/*
* if in set, plot pixel
*/
plot_logic (normcolor, alternate, count, max_iter,
scale, ix, iy, oset);
/*
* was a key pressed? if so, exit for now...
*/
if (check_key ())
return (1);
}
}
return (0);
}
/*------------------------------*/
/* plt_mandel */
/*------------------------------*/
plt_mandel (iter, scale, oset, normcolor, alternate, x, y, range)
int iter;
int scale;
int oset;
int normcolor;
int alternate;
float x,
y;
float range;
{
/*
* just plot a set in global array_G
*/
register int max_iter = iter;
register int ix, /* pixel number */
iy; /* row number */
register int count;
/*
* each row...
*/
for (iy = 0; iy < scale; iy++)
{
/*
* each pixel in row...
*/
for (ix = 0; ix < scale; ix++)
{
/*
* get count from array...
*/
count = (int) array_G[ix][iy];
/*
* if in set, plot pixel
*/
plot_logic (normcolor, alternate, count, max_iter,
scale, ix, iy, oset);
}
}
}
/*------------------------------*/
/* plot_logic */
/*------------------------------*/
plot_logic (normcolor, alternate, count, max_iter, scale, ix, iy, oset)
int normcolor;
int alternate;
int count;
int max_iter;
int scale;
int ix;
int iy;
int oset;
{
/*
* logic to figure if point is in set or not and what color to plot it
*/
if (normcolor)
{
if (alternate)
{
if ((count % 2) && (count < max_iter))
do_pixel (scale, ix, iy, oset, BLACK);
else
do_pixel (scale, ix, iy, oset, WHITE);
}
else if (count >= max_iter)
{
do_pixel (scale, ix, iy, oset, BLACK);
}
else
{
do_pixel (scale, ix, iy, oset, WHITE);
}
}
else
{
if (alternate)
{
if (!((count % 2) && (count < max_iter)))
do_pixel (scale, ix, iy, oset, BLACK);
else
do_pixel (scale, ix, iy, oset, WHITE);
}
else if (count < max_iter)
{
do_pixel (scale, ix, iy, oset, BLACK);
}
else
{
do_pixel (scale, ix, iy, oset, WHITE);
}
}
}
/*
* these functions are all required but these are atari-specific
*/
#ifdef atarist
#include <osbind.h> /* atari ST (BIOS) */
#endif
/*------------------------------*/
/* init */
/*------------------------------*/
init ()
{
/*
* start up thingies (open windows, clear screens, etc)
*/
#ifdef atarist
/*
* clear screen, hide cursor, init timer...
*/
clr_screen ();
cursor (0);
do_time (0);
#endif
}
/*------------------------------*/
/* finish */
/*------------------------------*/
finish (hold_scrn)
int hold_scrn;
{
/*
* finish up...
*/
#ifdef atarist
if (hold_scrn)
{
wait_key ();
}
cursor (1);
exit (0);
#endif
}
/*------------------------------*/
/* check_key */
/*------------------------------*/
check_key ()
{
/*
* ckecks for a key and flushes keyboard buffer.
*/
#ifdef atarist
/*
* this is for atari ST using BIOS.
*/
if (Bconstat (2)) /* if CONSOLE has a char... */
{
while (Bconstat (2)) /* read char while there are */
Bconin (2); /* chars to read (flush) */
return (1); /* yes, there was a key */
}
return (0); /* no key */
#endif /*atarist*/
}
/*------------------------------*/
/* wait_key */
/*------------------------------*/
wait_key ()
{
/*
* waits for a key and flushes keyboard buffer.
*/
#ifdef atarist
/*
* this is for atari ST using BIOS.
*/
while (!Bconstat (2)) /* wait for a key... */
;
while (Bconstat (2)) /* keep reading while there */
Bconin (2); /* are key inputs... */
#endif /*atarist*/
}
/*------------------------------*/
/* do_pixel */
/*------------------------------*/
do_pixel (scale, ix, iy, oset, color)
int scale;
int ix;
int iy;
int oset;
int color;
{
/*
* put a pixel or BIG pixel.
*/
#ifdef atarist
/*
* this is for atari ST using line A.
*/
extern long linea0 ();
extern int linea1 ();
static long A_ptr = 0L; /* to line-A struct */
int i,
j;
int num;
/*
* init line A if needed...
*/
if (!A_ptr)
A_ptr = linea0 ();
/*
* if not fine scale, we need to plot BIG pixels
*/
if (scale < FINE)
{
num = FINE / scale;
for (i = 0; i < num; i++)
{
for (j = 0; j < num; j++)
{
linea1 (A_ptr, oset+(ix*num+i), oset+(iy*num+j), color);
}
}
}
else
{
linea1 (A_ptr, oset + ix, oset + iy, color);
}
#endif /*atarist*/
}
/*------------------------------*/
/* do_line */
/*------------------------------*/
do_line (x1, y1, x2, y2)
int x1, y1, x2, y2;
{
/*
* draw a line.
*/
#ifdef atarist
/*
* this is for atari ST using line A.
*/
extern long linea0 ();
extern int linea3 ();
static long A_ptr = 0L;
/*
* line A init first, if needed
*/
if (!A_ptr)
A_ptr = linea0 ();
linea3 (A_ptr, x1, y1, x2, y2, 0, 0xFFFF, 0);
#endif /*atarist*/
}
/*------------------------------*/
/* cursor */
/*------------------------------*/
cursor (visible)
int visible;
{
/*
* turn cursor on/off
*/
#ifdef atarist
/*
* for atari ST. uses gemdos string output and vt52 escapes
*/
if (visible)
Cconws ("\33e");
else
Cconws ("\33f");
#endif /*atarist*/
}
/*------------------------------*/
/* mv_cursor */
/*------------------------------*/
mv_cursor (col, row)
int col;
int row;
{
/*
* move cursor to row,col (0,0 is UL corner). for printing
*/
#ifdef atarist
/*
* for atari ST. uses vt52 escapes
*/
printf ("\33Y%c%c", (char) (row + ' '), (char) (col + ' '));
fflush (stdout);
#endif /*atarist*/
}
/*------------------------------*/
/* clr_screen */
/*------------------------------*/
clr_screen ()
{
/*
* clear screen, home cursor
*/
#ifdef atarist
/*
* for atari ST. uses gemdos string output and vt52 escapes
*/
Cconws ("\33E");
#endif /*atarist*/
}
/*------------------------------*/
/* do_time */
/*------------------------------*/
long do_time (opt)
int opt; /* 0=init,1=start,2=end (ret elapsed)*/
{
/*
* timing functions
*/
#ifdef atarist
/*
* for atari ST. uses gemdos and sys variables (200 hz timer).
*/
static unsigned long start;
static unsigned long stop;
long savessp;
unsigned long elapsed; /* seconds */
switch (opt)
{
case 0: /* reset clock */
case 1: /* start clock */
savessp = Super (0L);
start = *(long *) (0x4ba);
Super (savessp);
break;
case 2: /* stop and elapsed */
savessp = Super (0L);
stop = *(long *) (0x4ba);
Super (savessp);
if (stop < start)
elapsed = (long) (stop - start + 0x7FFFFFFFL) / 200L;
else
elapsed = (long) (stop - start) / 200L;
return ((long) elapsed);
}
return (0L);
#endif /*atarist*/
}
22842!Funky!Stuff!
echo x - version.h
cat > version.h << '22842!Funky!Stuff!'
/*
* version.h for fract
*/
#define VERSION 100
char version_G[] = "fract v1.0 (mono) wjr 10/89";
char copyrite[] = "(c) 1989 Bill Rosenkranz";
22842!Funky!Stuff!
echo x - linea0.s
cat > linea0.s << '22842!Funky!Stuff!'
*
* NAME: linea0 - return pointer to line A struct
*
*
* SYNOPSIS: ptr = (struct line_a *) linea0 ();
*
*
* AUTHOR: (c) 1989 Bill Rosenkranz
*
* net: rosenkra%boston@hall.cray.com
* CIS: 71460,17
* GENIE: W.ROSENKRANZ
*
* Feel free to copy. Leave this comment alone! No other
* restrictions on copying or hacking. Use as you like.
*
Init=$A000
.globl _linea0
.text
_linea0:
link a6,#0 * stack frame
movem.l a0-a2,-(a7) * save regs we clobber (except d0)
dc.w Init
* pointer to struct now in d0 and a0. a1 -> array of font headers, a2 -> array
* of linea functions
movem.l (a7)+,a0-a2 * restore regs
unlk a6 * fix stack frame
rts * d0 is pointer
.end
22842!Funky!Stuff!
echo x - linea1.s
cat > linea1.s << '22842!Funky!Stuff!'
*
* NAME: linea1 - put pixel
*
*
* SYNOPSIS: void linea1 (struct line_a *ptr, int x, int y,
* int color);
*
*
* AUTHOR: (c) 1989 Bill Rosenkranz
*
* net: rosenkra%boston@hall.cray.com
* CIS: 71460,17
* GENIE: W.ROSENKRANZ
*
* Feel free to copy. Leave this comment alone! No other
* restrictions on copying or hacking. Use as you like.
*
* linea struct offsets:
INTIN=8
PTSIN=12
* args: (wrt stack frame ptr a6)
ptr=8
x=12
y=14
color=16
.globl _linea1
.text
_linea1:
link a6,#0
* movem.l a0,-(a7)
move.l ptr(a6),a0 * linea struct ptr
move.l INTIN(a0),a1
move.l PTSIN(a0),a2
move.w color(a6),(a1) * put color in intin table
move.l x(a6),(a2) * put coord in ptsin table
dc.w $A001 * draw pixel
* movem.l (a7)+,a0
unlk a6
rts
.end
22842!Funky!Stuff!
echo x - linea2.s
cat > linea2.s << '22842!Funky!Stuff!'
*
* NAME: linea2 - get pixel
*
*
* SYNOPSIS: int linea2 (struct line_a *ptr, int x, int y);
*
*
* AUTHOR: (c) 1989 Bill Rosenkranz
*
* net: rosenkra%boston@hall.cray.com
* CIS: 71460,17
* GENIE: W.ROSENKRANZ
*
* Feel free to copy. Leave this comment alone! No other
* restrictions on copying or hacking. Use as you like.
*
* linea struct offsets:
PTSIN=12
* args: (wrt stack frame ptr a6)
ptr=8
x=12
y=14
.globl _linea2
.text
_linea2:
link a6,#0
movem.l a0-a1,-(a7)
move.l ptr(a6),a0 * linea struct ptr
move.l PTSIN(a0),a1
move.l x(a6),(a1) * put coord in ptsin table
dc.w $A002 * get pixel. returns d0.w
movem.l (a7)+,a0-a1
unlk a6
rts
.end
22842!Funky!Stuff!
echo x - linea3.s
cat > linea3.s << '22842!Funky!Stuff!'
*
* NAME: linea3 - draw line from x1,y1 to x2,y2
*
*
* SYNOPSIS: void linea3 (struct line_a *ptr, int x1, int y1,
* int x2, int y2, int mode, int mask, int opt);
*
*
* AUTHOR: (c) 1989 Bill Rosenkranz
*
* net: rosenkra%boston@hall.cray.com
* CIS: 71460,17
* GENIE: W.ROSENKRANZ
*
* Feel free to copy. Leave this comment alone! No other
* restrictions on copying or hacking. Use as you like.
*
* linea struct offsets:
CBIT0=24
CBIT1=26
CBIT2=28
CBIT3=30
LSTLIN=32
LNMASK=34
WMODE=36
X1=38
Y1=40
X2=42
Y2=44
* args: (wrt stack frame ptr a6)
ptr=8
x_1=12
y_1=14
x_2=16
y_2=18
mode=20
mask=22
opt=24
.globl _linea3
.text
_linea3:
link a6,#0
move.l ptr(a6),a0 * line A init (a0 -> structure)
move.w #1,CBIT0(a0) * plane 0 (all)
move.w #1,CBIT1(a0) * plane 1 (color only)
move.w #1,CBIT2(a0) * plane 2 (lo res only)
move.w #1,CBIT3(a0) * plane 3 (lo res only)
move.w opt(a6),LSTLIN(a0) * draw last pixel of line?
move.w mask(a6),LNMASK(a0) * line mask (solid=FFFF)
move.w mode(a6),WMODE(a0) * write mode (replace=0)
move.l x_1(a6),X1(a0) * coord of points
move.l x_2(a6),X2(a0)
dc.w $A003 * draw line
unlk a6
rts
.end
22842!Funky!Stuff!
Technical Details
Message-ID:
<34653@grapevine.uucp>Path:
arc1-ca.pugleaf.net!wuarchive!brutus.cs.uiuc.edu!apple!sun-barr!newstop!sun!sunfedcomm!grapevine!koreth@panarthea.ebay.sun.comShow Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!wuarchive!brutus.cs.uiuc.edu!apple!sun-barr!newstop!sun!sunfedcomm!grapevine!koreth@panarthea.ebay.sun.com From: koreth@panarthea.ebay.sun.com (Steven Grimm) Newsgroups: comp.sources.atari.st Subject: v03i001: fract -- Monochrome Mandelbrot generator Keywords: shar, C, high Message-ID: <34653@grapevine.uucp> Date: 31 Oct 89 21:12:12 GMT Sender: daemon@sunfedcomm Reply-To: rosenkra@hall.cray.com (Bill Rosenkranz) Lines: 1896 Approved: koreth@panarthea.ebay.sun.com