Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: version Tektronix Network News Daemon (B 2.10.2 based); site lumiere.UUCP Path: utzoo!linus!decvax!tektronix!lumiere!mikee From: mikee@lumiere.UUCP Newsgroups: net.sources Subject: Mandelbrot sources Message-ID: <1174@lumiere.UUCP> Date: Thu, 19-Sep-85 18:32:13 EDT Article-I.D.: lumiere.1174 Posted: Thu Sep 19 18:32:13 1985 Date-Received: Sat, 21-Sep-85 11:55:08 EDT Sender: mikee@lumiere.UUCP Organization: Tektronix, Beaverton OR Lines: 3503 The enclosed programs generate and display mandelbrot images. They're "slightly" modified versions of the original from Martin Minow. My main additions were a compressed pixel-file format and support for Tek 4105, 4107 and 4115 terminals. See the readme (and the source) for details. Mike Edmonds -- cut here ------ cut here ------ cut here ------ cut here ------ cut here -- #!/bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #!/bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # readme.txt # Makefile # mandefs.h # mancomp.c # mandisp.c # man4100.c # man4105.c # man4107.c # man4115.c # mancompress.c # manscreen.c # maniter.c # manfiles.c # manregis.c # This archive created: Thu Sep 19 15:10:15 1985 export PATH; PATH=/bin:$PATH if test -f 'readme.txt' then echo shar: over-writing existing file "'readme.txt'" fi cat << \SHAR_EOF > 'readme.txt' From Martin Minow: >> This is a very quick hack to compute the Mandelbrot Set as described >> in Scientific American, August 1985. The program is presented only >> as a stepping-stone for your own improvements. >> >> There are four source files: >> >> mancomp.c Compute the Mandelbrot Set, writing a "pixel" >> and "histogram" file. >> >> mandisp.c Read the files produced by mancomp.c, displaying the >> computed values. This program is -- hopefully -- >> independent of the display hardware/firmware. >> >> manscreen.c Screen I/O for operator interaction. Assumes a >> VT100 or similar terminal (with ANSI display controls), >> but should be easy to adapt to other uses. Used only >> to get parameters and display program status. >> >> manregis.c Display output routines for Regis terminals, such as >> the VT125, VT241, and PRO-350. Tested only on the >> PRO-350. >> >> Note: >> >> The programs have had only minimal testing. They are quite slow. >> You should redo the display routine (and adjust the size of the >> Mandelbrot set) to take best advantage of your display hardware. >> For example, you should compute an image that fills the screen. >> >> You can generate spectacular color images on the PRO if you do >> a little work. >> >> Someone with better graphics and numerical analysis skills should >> redo the computation in terms of scaled fixed-point arithmetic. >> >> Exploration of the Mandelbrot Set and its effective display would >> make a nice project for an introductory computer programming course. >> >> Martin Minow >> decvax!minow I've made the following changes: 1. Converted the pixel file to a pseudo-compressed format. Usual results are a 75 to 85% decrease in space requirements over the original. Added a new program called "mancompress" to convert from one format to the other. 2. Improved the pixel-addressing accuracy and speed of the various display programs. Added support for Tek 4105, 4107 and 4115 terminals. (Didn't retrofit the changes back to the regis code, so its broke.) 3. Added three new flags for output formatting: -nb gets rid of the reticular border around the display and scales it to fill the extra space, -fs enlarges the display to the width of whichever axis is largest and lops off portions of the other axis (thereby filling the screen without distorting the image), and -fi causes gaps between lines in the display to be filled by displaying rectangles rather than lines (for low- resolution images). 4. Massive quantities of random hacking to clean and speed up the code. To Do: 1. Martin's note re numerical analysis techniques is still true. The basic method of computing a pixel's value hasn't changed. 2. The color-spectrum algorithm for the 4115 is poor. If anybody has a decent one, I'd appreciate a copy. Enjoy! Mike Edmonds Tektronix, Inc. S3G Unix Support UUCPnet: {ucbvax,ihnp4,allegra,uw-beaver,...}!tektronix!mikee CSnet: mikee@tek ARPAnet: mikee.tek@csnet-relay Snail Mail: Tektronix, Inc., S3G Unix Support Del.Sta. 19-333 PO Box 500, Beaverton, OR 97077 MaBell: (503) 627-5340 SHAR_EOF if test -f 'Makefile' then echo shar: over-writing existing file "'Makefile'" fi cat << \SHAR_EOF > 'Makefile' # # $Header: Makefile,v 1.2 85/09/17 10:46:50 mikee Exp $ # # $Log: Makefile,v $ # Revision 1.2 85/09/17 10:46:50 mikee # Massive hacking. # # Revision 1.1 85/08/26 15:28:51 mikee # Cleaned up, changed mandisp refs to man4105/7, etc. # CFLAGS = -O LDFLAGS= -s LDLIBS = -lm CCOMP= mancomp.c OCOMP= mancomp.o DCOMP= $(OCOMP) misc.a C4105= mandisp.c man4100.c man4105.c O4105= mandisp.o man4105.o D4105= $(O4105) misc.a C4107= man4107.c O4107= mandisp.o man4107.o D4107= $(O4107) misc.a C4115= man4115.c O4115= mandisp.o man4115.o D4115= $(O4115) misc.a CPRESS= mancompress.c OPRESS= mancompress.o DPRESS= $(OPRESS) misc.a CMISC= manscreen.c maniter.c manfiles.c OMISC= manscreen.o maniter.o manfiles.o HDRS= mandefs.h SRCS= $(CCOMP) $(C4105) $(C4107) $(C4115) $(CPRESS) $(CMISC) OBJS= $(OCOMP) $(O4105) $(O4107) $(O4115) $(OPRESS) $(OMISC) BINS= mancomp man4105 man4107 man4115 all: $(BINS) mancomp:$(DCOMP) cc $(LDFLAGS) -o $@ $(DCOMP) $(LDLIBS); size $@ man4105:$(D4105) cc $(LDFLAGS) -o $@ $(D4105) $(LDLIBS); size $@ man4107:$(D4107) cc $(LDFLAGS) -o $@ $(D4107) $(LDLIBS); size $@ man4115:$(D4115) cc $(LDFLAGS) -o $@ $(D4115) $(LDLIBS); size $@ mancompress:$(DPRESS) cc $(LDFLAGS) -o $@ $(DPRESS) $(LDLIBS); size $@ misc.a: $(OMISC) ar rv misc.a $? ranlib misc.a $(OBJS): $(HDRS) man4105.o: man4100.c man4107.o: man4100.c man4115.o: man4100.c print:; pr -f -n Makefile | lpr cref $(HDRS) $(SRCS) | lpr shar:; shar readme.txt Makefile $(HDRS) $(SRCS) manregis.c > shar.out clean:; rm -f $(OBJS) misc.a a.out core tags make.log empty:; rm -f $(BINS) $(OBJS) misc.a a.out core tags make.log SHAR_EOF if test -f 'mandefs.h' then echo shar: over-writing existing file "'mandefs.h'" fi cat << \SHAR_EOF > 'mandefs.h' /* $Header: mandefs.h,v 1.4 85/09/16 15:46:49 mikee Exp $ * * $Log: mandefs.h,v $ * Revision 1.4 85/09/16 15:46:49 mikee * Removed decus C stuff, standardized global variable names * and eliminated PIXREC definition. * * Revision 1.3 85/09/09 00:43:21 mikee * Moved hist. and pixel file functions to manfiles. * * Revision 1.2 85/08/27 00:34:31 mikee * Converted to packed-pixel file format. * * Revision 1.1 85/08/26 15:10:42 mikee * Initial revision * */ /* * Mandelzoom (from Scientific American, August 1985). * * Global definitions, etc. */ #include #include #include #define FALSE 0 #define TRUE 1 #define EOS '\0' #define MAX_NPIXEL 1280 /* Max. pixels in image */ #define MAX_NITER 1000 /* Max. iterations per pixel */ /* * Global variables. */ extern int Niter; /* Maximum iterations */ extern int Npixel; /* Number pixels on each side */ extern double RealOrigin; /* Corner of the picture */ extern double ImagOrigin; extern double SideLength; /* Length of each side */ extern int Histogram[]; /* Pixel density histogram */ extern int HistTotal; /* Sum of histogram values */ extern int HistMin; /* First count in histogram */ extern int HistMax; /* Last count in histogram */ extern int PixValue; /* Current pixel value */ extern int PixCount; /* Current pixel count (run length) */ /* * Macros. */ #define pixwrite(value) ( ((value) == PixValue)? PixCount++ : _pixwrite(value) ) #define ison(bits, word) ( ((word) & (bits)) != 0 ) #define isoff(bits, word) ( ((word) & (bits)) == 0 ) #define turnon(bits, word) (word) |= (bits) #define turnoff(bits, word) (word) &= ~(bits) #ifndef min #define min(a,b) ( ((a) < (b))? (a) : (b) ) #define max(a,b) ( ((a) > (b))? (a) : (b) ) #endif min #define dbltoint(val) (int)( (val) + (((val) < 0.0)? -0.5 : 0.5) ) SHAR_EOF if test -f 'mancomp.c' then echo shar: over-writing existing file "'mancomp.c'" fi cat << \SHAR_EOF > 'mancomp.c' #ifndef lint static char *RCSid = "$Header: mancomp.c,v 1.7 85/09/16 18:22:31 mikee Exp $"; #endif /* $Log: mancomp.c,v $ * Revision 1.7 85/09/16 18:22:31 mikee * Changed global variable names and converted progress logger * function from a paragraph inside the inner loop to a function * called on an alarm. * * Revision 1.6 85/09/09 00:39:08 mikee * Moved hist. and pixel file functions to manfiles. * * Revision 1.5 85/09/05 12:47:22 mikee * Replaced pixel computation inner loop by a call to pixvalue. * Moved code to maniter. * * Revision 1.4 85/09/03 17:36:58 mikee * Increased displayed precision of parameters. * * Revision 1.3 85/08/27 00:33:50 mikee * Converted to packed-pixel file format. * * Revision 1.2 85/08/26 17:49:27 mikee * Corrected an error in the inner loop of the pixel comp * rtn that caused pixel's iteration counts to run from * 0-niter rather than 0-(niter-1). * * Revision 1.1 85/08/26 15:10:46 mikee * Cleaned up code, shortened pixels from int to short, etc. * */ /* * Mandelzoom (from Scientific American, August 1985). * Recommended places for exploration (according to the article): * real imaginary side * -2.00 -1.25 2.50 Entire Mandelbrot set * .26 0.00 .01 * -.76 0.01 .02 * -1.26 0.01 .02 * * This program computes the Mandelbrot set, writing the pixels * to xxx.pix and the parameters (origin, size, and a pixel density * histogram to xxx.his). * * Option command line (for spawning): * mandel origin_real origin_imag size npixel niter filename * or mandel xxx.cmd read commands from a file. * or mandel interactive * * Values are: * orig_real (double) lower-left hand corner of the picture (real part) * orig_imag (double) lower-left hand corner of the picture (imag part) * size (double) size of a side (defines the view into the set) * npixel (int) number of pixels on each side (max == 512) * default = 100 * niter (int) number of iterations per point. * default = 100 * file (string) name of output file (no type) * default = mandel * * In "mandel file" format, each line generates a separate picture. * * Each picture causes two files to be written: * file.his (readable text format) contains picture definition parameters * and a histogram of pixel values: * orig_real orig_imag side npixel niter \n * bottom top sum (first non-zero histogram, last non-zero, * sum of histogram values). * hist[bottom] (number of pixels with count == bottom) * ... (etc.) * hist[top] (number of pixels with specified count) * file.pix (binary format) contains Npixel rows, each containing Npixel * integers, defining the count at each pixel location. * * Note: this program is very cpu intensive. There are a maximum of * 4 * Niter * (Npixel**2) floating-point multiplies * 10 * Niter * (Npixel**2) other floating-point (add, compare, store) * per picture. * * Decus C bug note: * all printf's that format floats must have only one floating-point * parameter, and it must be the last parameter in the argument list. * Also, Decus C doesn't support (double) x++. */ #include "mandefs.h" #include #define DEF_FILENAME "mandel" /* Default output filename */ #define DEF_NITER 100 /* Default number of iterations */ #define DEF_NPIXEL 100 /* Default number of pixels */ #define MAX_ARGS 8 /* Command line arguments */ char line[BUFSIZ]; /* General text work area */ char filename[81]; /* Output file name work area */ char *myargv[MAX_ARGS]; /* To build command arguments */ int myargc; /* Index into myargv[] */ main(argc, argv) int argc; char *argv[]; { char stdoutbuf[BUFSIZ]; setbuf(stdout, stdoutbuf); /* do explicit output buffering */ Niter = DEF_NITER; Npixel = DEF_NPIXEL; RealOrigin = -2.0; ImagOrigin = -1.25; SideLength = 2.5; if (argc <= 1) { while (interactive()) { doit(); } } else if (argc == 2 && !isdigit(argv[1][0])) { if (freopen(argv[1], "r", stdin) == NULL) { perror(argv[1]); exit(EOF); } while (comfile()) { getarguments(myargc, myargv); doit(); } } else { getarguments(argc, argv); doit(); } exit(0); } doit() { if ((hisopen(filename, 'w') == TRUE) && (pixopen(filename, 'w') == TRUE)) { process(); hiswrite(); } hisclose(); pixclose(); } static x,y; /* Row/col counters */ static double interval; /* Time between progress notifications */ process() /* * Compute the Mandelbrot set. */ { double offset[MAX_NPIXEL]; /* Pixel offsets (from origin) */ double c_real[MAX_NPIXEL]; /* Real axis position */ double float_pixels; /* To compute pixel position */ int progress(); if (isatty(fileno(stdout))) { /* start progress logger */ signal(SIGALRM, progress); interval = 1.0; alarm(dbltoint(interval)); } /* * Precompute the position of each pixel on the real axis. * This loop should not be "unrolled" to a succession of * additions as that would lose accuracy. Given what * follows, the cost isn't excessive. */ float_pixels = Npixel; for (x = 0; x < Npixel ; x++) { register double gap; offset[x] = gap = (SideLength * ((double) x)) / float_pixels; c_real[x] = RealOrigin + gap; } for (y = 0; y < Npixel; y++) { register double c_imag; c_imag = ImagOrigin + offset[y]; for (x = 0; x < Npixel; x++) { register value = pixvalue(c_real[x], c_imag); pixwrite(value); } pixflush(); } alarm(0); /* turn off progress logger */ } progress() { double pct; pct = (double)(((y * Npixel) + x) * 100) / (double)(Npixel * Npixel); scr_move(7, 1); printf("Current position = %04d,%04d - %.2f%% completed.", y, x, pct); scr_eol(); fflush(stdout); if ((interval *= 1.1) > 120.0) interval = 120.0; signal(SIGALRM, progress); alarm(dbltoint(interval)); } getarguments(argcount, argstring) int argcount; char *argstring[]; /* * Process argv[] from command line or pseudo argv[] from a file. */ { register int i; if (argcount < 5) { printf("Missing arguments, need at least\n"); printf("real-origin, imaginary-origin, side-length\n"); } else { RealOrigin = atof(argstring[1]); ImagOrigin = atof(argstring[2]); SideLength = atof(argstring[3]); strcpy(filename, DEF_FILENAME); Niter = DEF_NITER; Npixel = DEF_NPIXEL; switch (argcount) { default: printf("Extra arguments ignored:\n"); for (i = 7; i < argcount; i++) printf(" arg[%d] = \"%s\"\n", i, argstring[i]); case 7: strcpy(filename, argstring[6]); case 6: if ((Niter = atoi(argstring[5])) > MAX_NITER) { printf("%d iterations max.\n", MAX_NITER); Niter = MAX_NITER; } case 5: Npixel = atoi(argstring[4]); } if (Npixel > MAX_NPIXEL) Npixel = MAX_NPIXEL; printf("corner = [%.15g,", RealOrigin); printf("%.15g], ", ImagOrigin); printf("side = %.15g, ", SideLength); printf("%d pixels, %d iterations\n", Npixel, Niter); fflush(stdout); } } interactive() /* * Read commands from the terminal -- assumed to be a VT100 or similar. */ { if (isatty(fileno(stdin))) scr_clear(); if (!getcomplex(1, "Lower-left Corner (real, imaginary)", &RealOrigin, &ImagOrigin) || !getdouble(2, "Side Length", &SideLength) || !getint(3,"Number of pixels on a side", &Npixel, DEF_NPIXEL, MAX_NPIXEL) || !getint(4, "Iterations", &Niter, DEF_NITER, MAX_NITER) || !getstring(5, "Output filename", filename, DEF_FILENAME)) return (FALSE); return (TRUE); } comfile() /* * Read commands from an indirect command file. */ { register char *lp; if (gets(line) == NULL) return (FALSE); myargv[0] = ""; for (myargc = 1, lp = line; *lp != EOS && myargc < MAX_ARGS;) { while (isspace(*lp)) lp++; myargv[myargc++] = lp; while(*lp && !isspace(*lp)) lp++; if (*lp != EOS) *lp++ = EOS; } return (TRUE); } SHAR_EOF if test -f 'mandisp.c' then echo shar: over-writing existing file "'mandisp.c'" fi cat << \SHAR_EOF > 'mandisp.c' #ifndef lint static char *RCSid = "$Header: mandisp.c,v 1.6 85/09/18 16:32:23 mikee Exp $"; #endif /* $Log: mandisp.c,v $ * Revision 1.6 85/09/18 16:32:23 mikee * Changed global variable names, added "fill" (-fi) mode (for drawing * low resolution images using rectangles rather than lines), added * handler to reset terminal after interrupt and removed pixel address * calculation code from "process" to speed things up. * * Revision 1.5 85/09/09 00:42:32 mikee * Moved hist. and pixel file functions to manfiles. * * Revision 1.4 85/09/03 17:41:04 mikee * Increased displayed precision of parameters, displayed special * tick marks to show areas that will be off the screen during * a "fill-screen" enlargement and changed spectrum allocation * algorithm. * * Revision 1.3 85/08/27 21:19:04 s3g * Added "fill-screen" mode and made color selection a little * more intelligent. * * Revision 1.2 85/08/27 00:34:38 mikee * Converted to packed-pixel file format. * * Revision 1.1 85/08/26 15:14:11 mikee * Cleaned up code, shortened pixels from int to short, * made display interface more generic, etc. * */ /* * Display Mandelbrot set pixels. * * Usage: mandisp [-nb] [-fs] [-fi] [pixel-file-prefix] * -nb Don't print a numbered grid around the display. * (Default = FALSE - print the border) * -fs Expand display to fill screen (implies -nb). * (Default = FALSE - print the border) * -fi Fill in gaps between lines. * (Default = FALSE - leave gaps blank). * prefix Pixel (suffix = .pix) and histogram (.his) file prefix. * (Default = mandel). */ #include "mandefs.h" #include #define DEF_FILENAME "mandel" /* * Display system statistics (set by display functions). */ extern int Max_Xpixel; extern int Max_Ypixel; extern int Gray_Scale; extern int Tick; extern int Cxsize; extern int Cysize; /* * These values are computed locally based on the above. */ int dpixel, xpixel, ypixel; /* Number of display pixels per side */ int xorigin, yorigin; /* Address of lower-left corner */ int xaddrs[MAX_NPIXEL]; /* Screen address corresponding to */ int yaddrs[MAX_NPIXEL]; /* each pixel in the pixel file. */ int density[MAX_NITER]; /* Density (color) of each iter. level */ int Border = TRUE; /* Should we display a pretty border? */ int Expand = FALSE; /* Should we expand the display? */ int Fill = FALSE; /* Fill in blank lines? */ char line[BUFSIZ]; char filename[81]; main(argc, argv) int argc; char *argv[]; { char stdoutbuf[BUFSIZ]; setbuf(stdout, stdoutbuf); /* do explicit output buffering */ if (argc <= 1) { while (interactive()) { doit(); } } else { register i; for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-nb") == 0) { Border = FALSE; continue; } if (strcmp(argv[i], "-fs") == 0) { Border = FALSE; Expand = TRUE; continue; } if (strcmp(argv[i], "-fi") == 0) { Fill = TRUE; continue; } strcpy(filename, argv[i]); doit(); } } dsp_finis(); scr_clear(); } doit() { int dointr(); if ((pixopen(filename, 'r') != TRUE) || (hisopen(filename, 'r') != TRUE) || (hisread() != TRUE)) { hisclose(); pixclose(); if (isatty(fileno(stdin))) { printf("Press return to continue.\n"); gets(line); } return; } scr_clear(); scr_move(2, 1); printf("origin %.15g, %.15g\n", RealOrigin, ImagOrigin); printf("side %.15g\n", SideLength); printf("npixel %d\n", Npixel); printf("niter %d\n", Niter); fflush(stdout); if (signal(SIGINT, SIG_IGN) != SIG_IGN) signal(SIGINT, dointr); if (signal(SIGHUP, SIG_IGN) != SIG_IGN) signal(SIGHUP, dointr); if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) signal(SIGQUIT, dointr); dsp_init(); set_gray_scale(); if (Border) border(); else if (Expand) fill_screen(); else no_border(); process(); hisclose(); pixclose(); } /* * Clean up terminal modes after an interrupt. */ dointr() { char tempbuf[BUFSIZ]; setbuf(stdout, tempbuf); /* throw away current output buffer */ dsp_finis(); scr_clear(); exit(EOF); } process() { register x, y, oldx, oldy, old_dens, new_dens; int width; width = (dpixel + (Npixel - 1)) / Npixel; if (Fill == TRUE && width > 1) { oldy = -1; for (y = 0; y < Npixel; y++) { if (pixread(y, 0) != TRUE) return; if (yaddrs[y] < 0 || yaddrs[y] == oldy) { for (x = PixCount ; x < Npixel ; x += PixCount) if (pixread(y, x) != TRUE) return; continue; } dsp_move(xorigin, (oldy = yaddrs[y])); oldx = xorigin; old_dens = density[PixValue]; for (x = PixCount ; x < Npixel ; x += PixCount) { if (pixread(y, x) != TRUE) return; new_dens = density[PixValue]; if (new_dens != old_dens) { register len = xaddrs[x] - oldx; if (len > 0) { dsp_rect(old_dens, len, width); oldx = xaddrs[x]; } old_dens = new_dens; } } if ((x = xorigin + xpixel) > oldx) dsp_rect(old_dens, x - oldx, width); dsp_endline(); } } else { oldy = -1; for (y = 0; y < Npixel; y++) { if (pixread(y, 0) != TRUE) return; if (yaddrs[y] < 0 || yaddrs[y] == oldy) { for (x = PixCount ; x < Npixel ; x += PixCount) if (pixread(y, x) != TRUE) return; continue; } dsp_move(xorigin, (oldy = yaddrs[y])); oldx = xorigin; old_dens = density[PixValue]; for (x = PixCount ; x < Npixel ; x += PixCount) { if (pixread(y, x) != TRUE) return; new_dens = density[PixValue]; if (new_dens != old_dens) { register len = xaddrs[x] - oldx; if (len > 0) { dsp_draw(old_dens, len); oldx = xaddrs[x]; } old_dens = new_dens; } } if ((x = xorigin + xpixel) > oldx) dsp_draw(old_dens, x - oldx); dsp_endline(); } } stall(); } set_gray_scale() /* * Take the density histogram and turn it into a gray scale. * (This should probably be interactive.) */ { int colors = Gray_Scale; int hihist = HistMax; int lodens = 0; register locount = 0, midcount, hicount = HistTotal; register sections; sections = getsects(hihist, lodens, 1); if (sections < 2) return; if (colors >= sections) { double factor, curcolor; factor = (double) colors / (double) sections; for (curcolor = 0.0 ; hihist >= HistMin ; hihist--) { if (Histogram[hihist] > 0) { density[hihist] = dbltoint(curcolor); curcolor += factor; } } return; } if (Histogram[HistMax] >= (HistTotal / 500)) { density[hihist--] = lodens++; hicount -= Histogram[HistMax]; colors--; } while ((midcount = ((locount + hicount) / 2)) > locount) { register sections = getsects(hihist, lodens, midcount); if (sections < colors) hicount = midcount; else if (sections > colors) locount = midcount; else { while (getsects(hihist, lodens, --midcount) == colors) ; midcount++; break; } } getsects(hihist, lodens, midcount); } getsects(hihist, lodens, count) register hihist, lodens, count; { register dens = lodens, used; for (used = 0 ; hihist >= HistMin ; hihist--) { density[hihist] = dens; used += Histogram[hihist]; if (used >= count) { used = 0; dens++; } } if (used > 0) dens++; return (dens - lodens); } fill_screen() /* * Expand display to fill screen. */ { xorigin = 0; yorigin = (Cysize * 3) / 2; xpixel = (Max_Xpixel - 1); ypixel = (Max_Ypixel - 1) - yorigin; dpixel = max(xpixel, ypixel); pixaddrs(xaddrs, xorigin, Max_Xpixel); pixaddrs(yaddrs, yorigin, Max_Ypixel); } no_border() /* * No border is to be drawn. Determine optimum location for display. */ { xpixel = (Max_Xpixel - 1); ypixel = (Max_Ypixel - 1) - ((Cysize * 3) / 2); if (xpixel >= ypixel) { xorigin = (xpixel - ypixel) / 2; yorigin = (Max_Ypixel - 1) - ypixel; dpixel = xpixel = ypixel; } else { xorigin = 0; yorigin = ((Max_Ypixel - 1) - xpixel) / 2; dpixel = ypixel = xpixel; } pixaddrs(xaddrs, xorigin, xorigin + xpixel); pixaddrs(yaddrs, yorigin, yorigin + ypixel); } border() /* * Draw a pretty border */ { register x, y; int left, right, top, bottom; int tickx[4], ticky[2]; int do_value; double offset, gap; xpixel = (Max_Xpixel - 1); ypixel = (Max_Ypixel - 1) - ((Cysize * 3) / 2); if (xpixel >= ypixel) { top = Max_Ypixel - 1; bottom = Cysize * 3; left = (xpixel - (top - bottom)) / 2; right = left + (top - bottom); offset = (1.0 - ((double)ypixel / (double)xpixel)) / 2.0; offset *= (double)ypixel; tickx[0] = left - (Tick * 2); tickx[1] = left; tickx[2] = right + (Tick * 2); tickx[3] = right; ticky[0] = top - dbltoint(offset); ticky[1] = bottom + dbltoint(offset); dpixel = xpixel = ypixel = (top - bottom) - (2 * (Tick + 1)); } else { right = Max_Xpixel - 1; left = Cxsize * 8; bottom = (ypixel - (right - left)) / 2; top = bottom + (right - left); offset = (1.0 - ((double)xpixel / (double)ypixel)) / 2.0; offset *= (double)xpixel; tickx[0] = bottom - (Tick * 2); tickx[1] = bottom; tickx[2] = top + (Tick * 2); tickx[3] = top; ticky[0] = right - dbltoint(offset); ticky[1] = left + dbltoint(offset); dpixel = xpixel = ypixel = (right - left) - (2 * (Tick + 1)); } xorigin = left + Tick + 1; yorigin = bottom + Tick + 1; pixaddrs(xaddrs, xorigin, xorigin + xpixel); pixaddrs(yaddrs, yorigin, yorigin + ypixel); dsp_line(left, top, right, top); dsp_line(right, top, right, bottom); dsp_line(right, bottom, left, bottom); dsp_line(left, bottom, left, top); gap = SideLength / ((double) xpixel); do_value = TRUE; offset = 0.0; for (y = 0 ; y <= 10 ; y++) { x = dbltoint(offset) + xorigin; dsp_line(x, bottom, x, bottom + Tick); dsp_line(x, top, x, top - Tick); if (do_value) { sprintf(line, "%9.6f", RealOrigin + (offset * gap)); dsp_text(x - (Cxsize * 5), bottom - ((Cysize * 3) / 2), line); } do_value = !do_value; offset += ((double) xpixel / 10.0); } do_value = TRUE; offset = 0.0; for (x = 0 ; x <= 10 ; x++) { y = dbltoint(offset) + yorigin; dsp_line(left, y, left + Tick, y); dsp_line(right, y, right - Tick, y); if (do_value) { sprintf(line, "%9.6f", ImagOrigin + (offset * gap)); dsp_text(left - (Cxsize * 10), y - (Cysize / 3), line); } do_value = !do_value; offset += ((double) xpixel / 10.0); } for (y = 0 ; y < 2 ; y++) for (x = 0 ; x < 4 ; x += 2) dsp_line(tickx[x], ticky[y], tickx[x+1], ticky[y]); } pixaddrs(array, minadr, maxadr) register int array[], minadr, maxadr; /* * Given the min/max addresses and the number display * pixels on the screen (in "dpixel") calculate the screen * address for each pixel in the pixel-file array. * * Side-effect: if the distance between min and max is less than * "dpixel", the addresses will be "scaled" towards the middle. * (Ie, high and low pixels will be lopped off.) */ { register pixel; double factor; /* Screen pixels per file pixel */ double curadr; factor = (double) dpixel / (double) Npixel; curadr = (double) ((minadr - dpixel) + maxadr) / 2.0; for (pixel = 0 ; pixel < Npixel ; pixel++) { register addr = dbltoint(curadr); if (addr < minadr || addr >= maxadr) array[pixel] = -1; else array[pixel] = addr; curadr += factor; } } interactive() { if (isatty(fileno(stdin))) scr_clear(); if (!getstring(1, "Input filename", filename, DEF_FILENAME)) return FALSE; return TRUE; } stall() { dsp_text(0, 0, "Press return to continue"); dsp_done(); gets(line); dsp_finis(); } SHAR_EOF if test -f 'man4100.c' then echo shar: over-writing existing file "'man4100.c'" fi cat << \SHAR_EOF > 'man4100.c' /* $Header: man4100.c,v 1.2 85/09/18 23:27:42 mikee Exp $ ** ** Tektronix 4100 graphics terminal commands, constants and macros. ** ** This file is designed to be included into a source file which invokes ** the defined 4100-series commands. Unless "SLOW" is defined, most of the ** commands will be compiled as macros for speed. ** ** Mike Edmonds - 9/85 ** ** $Log: man4100.c,v $ ** Revision 1.2 85/09/18 23:27:42 mikee ** Added code to pxraster to handle 8 bit pixels. ** ** Revision 1.1 85/09/16 15:48:41 mikee ** Initial revision ** */ #define ON 1 /* Mode switches */ #define OFF 0 #define ANSI 1 #define TEK 0 /* * Convert from pixel number to logical address and back. */ #ifndef SLOW #define adrconv(adr,in,out) ( (((adr) * (out)) + ((out) / 2)) / (in) ) #define xpixtoaddr(pix) adrconv((pix), MAX_XPIXEL, MAX_XADDR) #define ypixtoaddr(pix) adrconv((pix), MAX_YPIXEL, MAX_YADDR) #define xaddrtopix(adr) adrconv((adr), MAX_XADDR, MAX_XPIXEL) #define yaddrtopix(adr) adrconv((adr), MAX_YADDR, MAX_YPIXEL) #else SLOW xpixtoaddr(pix) int pix; { return (((pix * MAX_XADDR) + (MAX_XADDR / 2)) / MAX_XPIXEL); } ypixtoaddr(pix) int pix; { return (((pix * MAX_YADDR) + (MAX_YADDR / 2)) / MAX_YPIXEL); } xaddrtopix(adr) int adr; { return (((adr * MAX_XPIXEL) + (MAX_XPIXEL / 2)) / MAX_XADDR); } yaddrtopix(adr) int adr; { return (((adr * MAX_YPIXEL) + (MAX_YPIXEL / 2)) / MAX_YADDR); } #endif /* * Switch terminal into various modes. */ #ifndef SLOW #define code(sw) { fputs("\033%!", stdout); encode(sw); } #define vector_mode() putchar('\035') #define alpha_mode() putchar('\037') #else SLOW code() int sw; { fputs("\033%!0", stdout); encode(sw); } vector_mode() { putchar('\035'); } alpha_mode() { putchar('\037'); } #endif SLOW /* * Turn dialog area on and off and clear graphics region. */ #ifndef SLOW #define davisibility(sw) { fputs("\033LV", stdout); encode(sw); } #define page() fputs("\033\014", stdout) #else SLOW davisibility(sw) int sw; { fputs("\033LV1", stdout); encode(sw); } page() { fputs("\033\014", stdout); } #endif SLOW /* * Cancel whatever's going on. */ #ifndef SLOW #define cancel() fputs("\033KC", stdout) #else SLOW cancel() { fputs("\033KC", stdout); } #endif SLOW /* * Set color maps. */ #ifndef SLOW #define cmode(spec, over, gray) { fputs("\033TM", stdout); \ encode(spec); encode(over); encode(gray); } #define cmap(idx, hue, light, satur) \ { fputs("\033TG", stdout); \ encode(1); encode(4); encode(idx); \ encode(hue); encode(light); encode(satur); } #else SLOW cmode(spec, overlay, gray) /* set color definition mode */ int spec, overlay, gray; { fputs("\033TM", stdout); encode(spec); encode(overlay); encode(gray); } cmap(index, hue, light, satur) /* set surface color map */ int index, hue, light, satur; { fputs("\033TG", stdout); encode(1); encode(4); encode(index); encode(hue); encode(light); encode(satur); } #endif SLOW /* * Change line style and color. */ #ifndef SLOW #define linestyle(style) { fputs("\033MV", stdout); \ encode(style); } #define lineindex(index) { fputs("\033ML", stdout); \ encode(index); } #else SLOW linestyle(style) int style; { fputs("\033MV", stdout); encode(style); } lineindex(index) int index; { fputs("\033ML", stdout); encode(index); } #endif SLOW /* * Build panels. */ #ifndef SLOW #define fillpattern(ptrn) { fputs("\033MP", stdout); \ encode(ptrn); } #define beginpanel(x,y,border) { fputs("\033LP", stdout); \ encode_xy(x, y); encode(border); } #define endpanel() { fputs("\033LE", stdout); } #else SLOW fillpattern(ptrn) /* define a fill pattern */ int ptrn; { fputs("\033MP", stdout); encode(ptrn); } beginpanel(x, y, border) /* begin a panel definition */ int x, y, border; { fputs("\033LP", stdout); encode_xy(x, y); encode(border); } endpanel() /* end a panel definition */ { fputs("\033LE", stdout); } #endif SLOW /* * Display graphtext. */ #ifndef SLOW #define gtindex(index) { fputs("\033MT", stdout); \ encode(index); } #define gtprecision(prec) { fputs("\033MQ", stdout); \ encode(prec); } #define gtsize(wd, hi, sp) { fputs("\033MC", stdout); \ encode(wd); encode(hi); encode(sp); } #define gamode(mode) { fputs("\033MG", stdout); \ encode(mode); } #define gtext(str) { fputs("\033LT", stdout); \ encode(strlen(str)); fputs(str, stdout); } #else SLOW gtindex(index) /* set text color */ int index; { fputs("\033MT", stdout); encode(index); } gtprecision(prec) /* define precision */ int prec; { fputs("\033MQ", stdout); encode(prec); } gtsize(wide, high, space) /* define text size */ int wide, high, space; { fputs("\033MC", stdout); encode(wide); encode(high); encode(space); } gamode(mode) /* set writing mode */ int mode; { fputs("\033MG", stdout); encode(mode); } gtext(str) /* display a string */ char *str; { fputs("\033LT", stdout); encode(strlen(str)); fputs(str, stdout); } #endif SLOW /* * Set surface definition. */ sdefinition(surfaces, bits) int surfaces, bits[]; { register count; fputs("\033RD", stdout); encode(surfaces); for (count = 0; count < surfaces ; count++) { encode(bits[count]); } fflush(stdout); /* terminal takes time to handle this */ sleep(2); } /* * Move and draw commands. */ #ifndef SLOW #define move(x,y) { fputs("\033LF", stdout); encode_xy(x, y); } #define draw(x,y) { fputs("\033LG", stdout); encode_xy(x, y); } #else SLOW move(x,y) int x, y; { fputs("\033LF", stdout); encode_xy(x, y); } draw(x,y) int x, y; { fputs("\033LG", stdout); encode_xy(x, y); } #endif SLOW /* * Pixel operations. */ #ifndef SLOW #define pxbegin(surf, alu, bits) \ { fputs("\033RU", stdout); \ encode(surf); encode(alu); encode(bits); } #define pxposition(x, y) { fputs("\033RH", stdout); \ encode_xy(x,y); } #define pxrectangle(ux,uy, lx,ly, index) \ { fputs("\033RR", stdout); \ encode_xy(ux,uy); encode_xy(lx,ly); \ encode(index); } #define pxviewport(ux,uy, lx,ly) \ { fputs("\033RS", stdout); \ encode_xy(ux,uy); encode_xy(lx,ly); } #else SLOW pxbegin(surface, alumode, bits) /* begin pixel operations */ int surface, alumode, bits; { fputs("\033RU", stdout); encode(surface); encode(alumode); encode(bits); } pxposition(x, y) /* set pixel beam position */ int x, y; { fputs("\033RH", stdout); encode_xy(x,y); } pxrectangle(ux,uy, lx,ly, index) /* rectangle fill */ int ux,uy, lx,ly, index; { fputs("\033RR", stdout); encode_xy(ux,uy); encode_xy(lx,ly); encode(index); } pxviewport(ux,uy, lx,ly) /* set pixel viewport */ int ux,uy, lx,ly; { fputs("\033RS", stdout); encode_xy(ux,uy); encode_xy(lx,ly); } #endif SLOW /* * Raster write. */ pxraster(pixels, indexes) int pixels, indexes[]; { register pixel = 0; if (pixels <= 0) return; fputs("\033RP", stdout); encode(pixels); #if (BITS == 1) #define pxrasterlength(pixels) (((pixels) + 5) / 6) encode(pxrasterlength(pixels)); while (pixel < pixels) { register unsigned word = 0, bit; for (bit = 0 ; bit < 6 ; bit++) { word <<= 1; if (pixel < pixels) word |= indexes[pixel++] & 0x1; } putchar(word + 0x20); } #endif (BITS == 1) #if (BITS == 2) #define pxrasterlength(pixels) (((pixels) + 2) / 3) encode(pxrasterlength(pixels)); while (pixel < pixels) { register unsigned word = 0, pair; for (pair = 0 ; pair < 3 ; pair++) { word <<= 2; if (pixel < pixels) word |= indexes[pixel++] & 0x3; } putchar(word + 0x20); } #endif (BITS == 2) #if (BITS == 3) #define pxrasterlength(pixels) (((pixels) + 1) / 2) encode(pxrasterlength(pixels)); while (pixel < pixels) { register unsigned word = indexes[pixel++] & 0x7; word <<= 3; if (pixel < pixels) word |= indexes[pixel++] & 0x7; putchar(word + 0x20); } #endif (BITS == 3) #if (BITS == 4) #define pxrasterlength(pixels) ((((pixels) * 4) + 5) / 6) encode(pxrasterlength(pixels)); while (pixel < pixels) { register unsigned word = indexes[pixel++] & 0xf; word <<= 2; if (pixel < pixels) { register unsigned temp = indexes[pixel++]; word |= (temp >> 2) & 0x3; putchar(word + 0x20); word = (temp & 0x3) << 4; if (pixel < pixels) word |= indexes[pixel++] & 0xf; } putchar(word + 0x20); } #endif (BITS == 4) #if (BITS == 6) #define pxrasterlength(pixels) (pixels) encode(pxrasterlength(pixels)); while (pixel < pixels) { putchar((indexes[pixel++] & 0x3f) + 0x20); } #endif (BITS == 6) #if (BITS == 8) #define pxrasterlength(pixels) ((((pixels) * 8) + 5) / 6) encode(pxrasterlength(pixels)); while (pixel < pixels) { register unsigned word = indexes[pixel++] & 0xff; putchar((word >> 2) + 0x20); word = (word << 4) & 0x30; if (pixel < pixels) { register unsigned temp = indexes[pixel++] & 0xff; word |= temp >> 4; putchar(word + 0x20); word = (temp << 2) & 0x3c; if (pixel < pixels) { temp = indexes[pixel++] & 0xff; word |= temp >> 6; putchar(word + 0x20); word = temp & 0x3f; } } putchar(word + 0x20); } #endif (BITS == 8) } /* * Runlength write. */ pxrunlength(runs, lengths, indexes) int runs, lengths[], indexes[]; { register run; if (runs > 0) { fputs("\033RL", stdout); encode(runs); for (run = 0 ; run < runs ; run++) encode((lengths[run] << BITS) + indexes[run]); } } /* * Convert xy pair to terminal encoded syntax. */ encode_xy(x,y) register x,y; { static lasthix = 0xfff, lasthiy = 0xfff, lastloy = 0xfff, lastext = 0xfff; int hix, lox, hiy, loy, ext; if (x < 0) x = 0; else if (x >= MAX_XADDR) x = MAX_XADDR - 1; if (y < 0) y = 0; else if (y >= MAX_YADDR) y = MAX_YADDR - 1; hix = x & 0xf80; lox = x & 0x07c; hiy = y & 0xf80; loy = y & 0x07c; ext = ((y & 0x03) << 2) | (x & 0x03); if (hiy != lasthiy) { lasthiy = hiy; putchar( (hiy >> 7) | 0x20 ); } if (ext != lastext) { lastext = ext; putchar( ext | 0x60 ); lastloy = loy; putchar( (loy >> 2) | 0x60 ); if (hix != lasthix) { lasthix = hix; putchar( (hix >> 7) | 0x20 ); } } else if (hix != lasthix) { lastloy = loy; putchar( (loy >> 2) | 0x60 ); lasthix = hix; putchar( (hix >> 7) | 0x20 ); } else if (loy != lastloy) { lastloy = loy; putchar( (loy >> 2) | 0x60 ); } putchar( (lox >> 2) | 0x40 ); } /* * Convert integer parameter to terminal syntax. */ encode(i) register i; { char buffer[50]; register char *bp = &buffer[49]; *bp-- = '\0'; if (i < 0) { i = -i; *bp-- = (i & 0xf) | 0x20; } else { *bp-- = (i & 0xf) | 0x30; } i >>= 4; while (i > 0) { *bp-- = (i & 0x3f) | 0x40; i >>= 6; } while (*++bp) putchar(*bp); } SHAR_EOF if test -f 'man4105.c' then echo shar: over-writing existing file "'man4105.c'" fi cat << \SHAR_EOF > 'man4105.c' #ifndef lint static char *RCSid = "$Header: man4105.c,v 1.3 85/09/18 14:23:37 mikee Exp $"; #endif /* $Log: man4105.c,v $ * Revision 1.3 85/09/18 14:23:37 mikee * Changed global variable names, corrected MAX_YADDR and added * dsp_rect(). * * Revision 1.2 85/09/03 17:23:32 mikee * Re-arranged spectrum order. * * Revision 1.1 85/08/26 15:10:43 mikee * Initial revision * */ /* * Display Mandelbrot set pixels. * * This version has been modified to support a Tektronix 4105 * graphics display terminal. It uses the 4105's "move" and * "draw" commands. Consequently, it can handle most other * 41-series terminals with only minor mods. */ #include "mandefs.h" #define MAX_XPIXEL 480 /* Pixels in the display */ #define MAX_YPIXEL 360 #define MAX_XADDR 4096 /* Addresses on the display */ #define MAX_YADDR 3133 #define TICK 4 /* Length of boarder tick-marks */ #define CXSIZE 6 /* Character width */ #define CYSIZE 11 /* Character height */ #define LINE_DENS 1 /* Density of display's border (if any) */ #define BITS 3 /* Number bits needed to encode color */ static int Spectrum[] = /* 4105 color indexes in spectrum order */ { 0, 6, 2, 7, 3, 5, 4, 1, 0 }; #define GRAY_SCALE ( sizeof(Spectrum) / sizeof(int) ) /* * Globalize (most of) these values for the main display code. */ int Max_Xpixel = MAX_XPIXEL; int Max_Ypixel = MAX_YPIXEL; int Gray_Scale = GRAY_SCALE; int Tick = TICK; int Cxsize = CXSIZE; int Cysize = CYSIZE; /* * Display routines: * dsp_init() Initialize for bit-map writing, clear screen. * dsp_done() Done writing to the bit-map (don't clear) * dsp_finis() All done (about to exit to o.s., clear screen) * dsp_move(x,y) Move bitmap cursor to to this row-column * dsp_rect(d,len,wide) Draw a rectangle at current location * dsp_draw(d,len) Draw a horizontal line of the selected density * dsp_endline() End a horizontal line of pixels * dsp_text(x,y,t) Write text string from this position * dsp_line(xf,yf,xt,yt) Draw line from [xf,yf] to [xt,yt] */ #include "man4100.c" static Last_X, Last_Y; /* last known beam coordinates */ dsp_init() /* * Start writing to the bitmap display. */ { code(TEK); /* switch to tek mode */ davisibility(OFF); /* blank out dialog area */ page(); /* clear the graphics region */ colormap(); /* initialize color map */ linestyle(0); /* solid lines */ } dsp_done() /* * Stop writing to the bitmap (don't clear it). */ { alpha_mode(); /* take out of vector mode */ fflush(stdout); } dsp_finis() /* * Exiting, clear display. */ { alpha_mode(); /* take out of vector mode */ davisibility(ON); /* bring back dialog area */ code(ANSI); /* put back in ansi mode */ fflush(stdout); } dsp_move(x, y) int x, y; /* * Move bitmap cursor to this position. * (Since we're using "move" and "draw" commands rather than pixel * operations, we have to convert the given address from pixel mode * back to its logical address equivalent.) */ { move(xpixtoaddr(Last_X = x), ypixtoaddr(Last_Y = y)); } dsp_rect(density, length, width) int density; int length; int width; /* * Draw a rectangle of this density. * On entrance, cursor is at the lower-left corner. * Leave the cursor at the lower-right. */ { int new_top = Last_Y + (width - 1); int new_bottom = Last_Y; int new_left = Last_X; int new_right = Last_X + length; Last_X = new_right; new_top = ypixtoaddr(new_top); new_bottom = ypixtoaddr(new_bottom); new_left = xpixtoaddr(new_left); new_right = xpixtoaddr(new_right); fillpattern(-(Spectrum[density % GRAY_SCALE])); beginpanel(new_left, new_bottom, 0); vector_mode(); encode_xy(new_left, new_top); encode_xy(new_right, new_top); encode_xy(new_right, new_bottom); alpha_mode(); endpanel(); } dsp_draw(density, length) int density; int length; /* * Draw a line of this density. * On entrance, cursor is at the left edge of the line. * Leave the cursor at the end of the line. */ { lineindex(Spectrum[density % GRAY_SCALE]); draw(xpixtoaddr(Last_X += length), ypixtoaddr(Last_Y)); } dsp_endline() /* * End a horizontal line. */ { /* dummy function */ } dsp_text(x, y, text) int x, y; char *text; /* * Display a string at the given location. */ { gtindex(LINE_DENS); /* set text color */ gamode(1); /* overlay chars on each other */ gtsize(0, 50, 0); /* set character size */ dsp_move(x, y); /* position beam */ gtext(text); /* do it */ } dsp_line(xfrom, yfrom, xto, yto) int xfrom, yfrom; int xto, yto; /* * Draw a line */ { lineindex(LINE_DENS); move(xpixtoaddr(xfrom), ypixtoaddr(yfrom)); draw(xpixtoaddr(xto), ypixtoaddr(yto)); Last_X = xto; Last_Y = yto; } static colormap() /* * Initialize the terminal's color map. */ { cmap(00, 0, 0, 0); /* black (clear) */ cmap(01, 0, 100, 0); /* white */ cmap(02, 120, 75, 100); /* red */ cmap(03, 240, 75, 100); /* green */ cmap(04, 0, 75, 100); /* blue */ cmap(05, 300, 44, 100); /* cyan */ cmap(06, 60, 44, 100); /* magenta */ cmap(07, 180, 44, 100); /* yellow */ } SHAR_EOF if test -f 'man4107.c' then echo shar: over-writing existing file "'man4107.c'" fi cat << \SHAR_EOF > 'man4107.c' #ifndef lint static char *RCSid = "$Header: man4107.c,v 1.3 85/09/18 14:23:49 mikee Exp $"; #endif /* $Log: man4107.c,v $ * Revision 1.3 85/09/18 14:23:49 mikee * Changed global variable names, corrected MAX_YADDR def, added * dsp_rect() and converted to array-style runlength and raster * writes. * * Revision 1.2 85/09/03 17:24:21 mikee * Re-arranged spectrum order. * * Revision 1.1 85/08/26 15:10:44 mikee * Initial revision * */ /* * Display Mandelbrot set pixels. * * This version has been modified to support a Tektronix 4107 * graphics display terminal. It uses the 4107 pixel operations * (which are MUCH faster then the corresponding "move" and "draw" * commands). Consequently, it will handle most other 41-series * terminals with only minor mods. */ #include "mandefs.h" #define MAX_XPIXEL 640 /* Pixels in the display */ #define MAX_YPIXEL 480 #define MAX_XADDR 4096 /* Addresses on the display */ #define MAX_YADDR 3133 #define TICK 4 /* Length of boarder tick-marks */ #define CXSIZE 8 /* Character width */ #define CYSIZE 14 /* Character height */ #define LINE_DENS 1 /* Density of display's border (if any) */ #define BITS 4 /* Number bits needed to encode color */ static int Spectrum[] = /* 4107 color indexes in spectrum order */ { 0, 9, 6, 10, 2, 11, 7, 12, 3, 13, 5, 14, 4, 15, 1, 9, 0 }; #define GRAY_SCALE ( sizeof(Spectrum) / sizeof(int) ) /* * Globalize (most of) these values for the main display code. */ int Max_Xpixel = MAX_XPIXEL; int Max_Ypixel = MAX_YPIXEL; int Gray_Scale = GRAY_SCALE; int Tick = TICK; int Cxsize = CXSIZE; int Cysize = CYSIZE; /* * Display routines: * dsp_init() Initialize for bit-map writing, clear screen. * dsp_done() Done writing to the bit-map (don't clear) * dsp_finis() All done (about to exit to o.s., clear screen) * dsp_move(x,y) Move bitmap cursor to to this row-column * dsp_rect(d,len,wide) Draw a rectangle at current location * dsp_draw(d,len) Draw a horizontal line of the selected density * dsp_endline() End a horizontal line of pixels * dsp_text(x,y,t) Write text string from this position * dsp_line(xf,yf,xt,yt) Draw line from [xf,yf] to [xt,yt] */ #include "man4100.c" static Last_X, Last_Y; /* Last known beam coordinates */ static Runs; /* Pixel runs (in RunLengths) */ static Pixels; /* Individual pixels (in Densities) */ static RunLengths[MAX_XPIXEL]; /* Lengths of the pixel runs */ static Densities[MAX_XPIXEL]; /* Run or pixel densities (indexes) */ dsp_init() /* * Start writing to the bitmap display. */ { code(TEK); /* switch to tek mode */ davisibility(OFF); /* blank out dialog area */ page(); /* clear the graphics region */ colormap(); /* initialize color map */ linestyle(0); /* solid lines */ pxbegin(1, 11, BITS); /* ready terminal for pixel ops */ pxviewport(0, 0, (MAX_XPIXEL - 1), (MAX_YPIXEL - 1)); Runs = Pixels = 0; /* initialize static memory */ } dsp_done() /* * Stop writing to the bitmap (don't clear it). */ { alpha_mode(); /* take out of vector mode */ fflush(stdout); } dsp_finis() /* * Exiting, clear display. */ { alpha_mode(); /* take out of vector mode */ davisibility(ON); /* bring back dialog area */ code(ANSI); /* put back in ansi mode */ fflush(stdout); } dsp_move(x, y) int x, y; /* * Move bitmap cursor to this position. */ { pxposition((Last_X = x), (Last_Y = y)); } dsp_rect(density, length, width) int density; int length; int width; /* * Draw a rectangle of this density. * On entrance, cursor is at the lower-left corner. * Leave the cursor at the lower-right. */ { length += Last_X; width += Last_Y - 1; pxrectangle(Last_X, width, length, Last_Y, Spectrum[density % GRAY_SCALE]); Last_X = length; } dsp_draw(density, length) int density; int length; /* * Draw a line of this density. * On entrance, cursor is at the left edge of the line. * Leave the cursor at the end of the line. */ { int rastlen; if ((rastlen = pxrasterlength(length)) > 2) { if (Pixels > 0) { if (rastlen < 8) /* hysteresis */ goto chgtopixels; pxraster(Pixels, Densities); Pixels = 0; } RunLengths[Runs] = length; Densities[Runs] = Spectrum[density % GRAY_SCALE]; if (++Runs >= MAX_XPIXEL) { pxrunlength(Runs, RunLengths, Densities); Runs = 0; } } else if (length > 0) { if (Runs > 0) { pxrunlength(Runs, RunLengths, Densities); Runs = 0; } chgtopixels: density = Spectrum[density % GRAY_SCALE]; do { Densities[Pixels] = density; if (++Pixels >= MAX_XPIXEL) { pxraster(Pixels, Densities); Pixels = 0; } } while (--length > 0); } Last_X += length; } dsp_endline() /* * End a horizontal line. Flush remaining runs or pixels. */ { if (Runs > 0) { pxrunlength(Runs, RunLengths, Densities); Runs = 0; } else if (Pixels > 0) { pxraster(Pixels, Densities); Pixels = 0; } } dsp_text(x, y, text) int x, y; char *text; /* * Display a string at the given location. */ { gtindex(LINE_DENS); /* set text color */ gamode(1); /* overlay chars on each other */ gtsize(0, 50, 0); /* set character size */ /* position beam */ move(xpixtoaddr(x), ypixtoaddr(y)); gtext(text); /* do it */ } dsp_line(xfrom, yfrom, xto, yto) int xfrom, yfrom; int xto, yto; /* * Draw a line */ { lineindex(LINE_DENS); move(xpixtoaddr(xfrom), ypixtoaddr(yfrom)); draw(xpixtoaddr(xto), ypixtoaddr(yto)); } static colormap() /* * Initialize the terminal's color map. */ { cmode(3, 0, 0); cmap(00, 0, 0, 0); /* black (clear) */ cmap(01, 0, 100, 0); /* white */ cmap(02, 120, 75, 100); /* red */ cmap(03, 240, 75, 100); /* green */ cmap(04, 0, 75, 100); /* blue */ cmap(05, 300, 44, 100); /* cyan */ cmap(06, 60, 44, 100); /* magenta */ cmap(07, 180, 44, 100); /* yellow */ cmap(08, 0, 50, 0); /* dark-gray */ cmap(09, 0, 75, 0); /* light-gray */ cmap(10, 82, 62, 92); /* red-magenta */ cmap(11, 158, 62, 100); /* orange */ cmap(12, 202, 62, 92); /* grean-yellow */ cmap(13, 278, 62, 100); /* green-cyan */ cmap(14, 322, 62, 92); /* blue-cyan */ cmap(15, 38, 62, 100); /* blue-magenta */ } SHAR_EOF if test -f 'man4115.c' then echo shar: over-writing existing file "'man4115.c'" fi cat << \SHAR_EOF > 'man4115.c' #ifndef lint static char *RCSid = "$Header: man4115.c,v 1.3 85/09/18 23:28:25 mikee Exp $"; #endif /* $Log: man4115.c,v $ * Revision 1.3 85/09/18 23:28:25 mikee * Altered spectrum generation algorithm * * Revision 1.2 85/09/16 16:40:14 mikee * Changed global variable names, corrected MAX_YADDR def, added * dsp_rect() and converted to array-style runlength and raster * writes. * * Revision 1.1 85/09/09 00:35:49 mikee * Initial revision * */ /* * Display Mandelbrot set pixels. * * This version has been modified to support a Tektronix 4115 * graphics display terminal. It uses the 4115 pixel operations * (which are MUCH faster then the corresponding "move" and "draw" * commands). Consequently, it will handle most other 41-series * terminals with only minor mods. */ #include "mandefs.h" #define MAX_XPIXEL 1280 /* Pixels in the display */ #define MAX_YPIXEL 978 #define MAX_XADDR 4096 /* Addresses on the display */ #define MAX_YADDR 3133 #define GRAY_SCALE 253 /* Density ranges */ #define TICK 8 /* Length of boarder tick-marks */ #define CXSIZE 10 /* Character width */ #define CYSIZE 20 /* Character height */ #define BITS 8 /* number bits needed to encode color */ /* * Globalize (most of) these values for the main display code. */ int Max_Xpixel = MAX_XPIXEL; int Max_Ypixel = MAX_YPIXEL; int Gray_Scale = GRAY_SCALE; int Tick = TICK; int Cxsize = CXSIZE; int Cysize = CYSIZE; /* * Display routines: * dsp_init() Initialize for bit-map writing, clear screen. * dsp_done() Done writing to the bit-map (don't clear) * dsp_finis() All done (about to exit to o.s., clear screen) * dsp_move(x,y) Move bitmap cursor to to this row-column * dsp_rect(d,len,wide) Draw a rectangle at current location * dsp_draw(d,len) Draw a horizontal line of the selected density * dsp_endline() End a horizontal line of pixels * dsp_text(x,y,t) Write text string from this position * dsp_line(xf,yf,xt,yt) Draw line from [xf,yf] to [xt,yt] */ #include "man4100.c" static Last_X, Last_Y; /* Last known beam coordinates */ static Runs; /* Pixel runs (in RunLengths) */ static Pixels; /* Individual pixels (in Densities) */ static RunLengths[MAX_XPIXEL]; /* Lengths of the pixel runs */ static Densities[MAX_XPIXEL]; /* Run or pixel densities (indexes) */ dsp_init() /* * Start writing to the bitmap display. */ { int surfaces[1]; code(TEK); /* switch to tek mode */ surfaces[0] = BITS; /* define surface */ sdefinition(1, surfaces); davisibility(OFF); /* blank out dialog area */ page(); /* clear the graphics region */ colormap(); /* define color map */ linestyle(0); /* solid lines */ pxbegin(1, 11, BITS); /* ready terminal for pixel ops */ pxviewport(0, 0, (MAX_XPIXEL - 1), (MAX_YPIXEL - 1)); Runs = Pixels = 0; /* initialize static memory */ } dsp_done() /* * Stop writing to the bitmap (don't clear it). */ { alpha_mode(); /* take out of vector mode */ fflush(stdout); } dsp_finis() /* * Exiting, clear display. */ { alpha_mode(); /* take out of vector mode */ davisibility(ON); /* bring back dialog area */ code(ANSI); /* put back in ansi mode */ fflush(stdout); } dsp_move(x, y) int x, y; /* * Move bitmap cursor to this position. */ { pxposition((Last_X = x), (Last_Y = y)); } dsp_rect(density, length, width) int density; int length; int width; /* * Draw a rectangle of this density. * On entrance, cursor is at the lower-left corner. * Leave the cursor at the lower-right. */ { length += Last_X; width += Last_Y - 1; pxrectangle(Last_X, width, length, Last_Y, density % GRAY_SCALE); Last_X = length; } dsp_draw(density, length) int density; int length; /* * Draw a line of this density. * On entrance, cursor is at the left edge of the line. * Leave the cursor at the end of the line. */ { int rastlen; if ((rastlen = pxrasterlength(length)) > 2) { if (Pixels > 0) { if (rastlen < 8) /* hysteresis */ goto chgtopixels; pxraster(Pixels, Densities); Pixels = 0; } RunLengths[Runs] = length; Densities[Runs] = density % GRAY_SCALE; if (++Runs >= MAX_XPIXEL) { pxrunlength(Runs, RunLengths, Densities); Runs = 0; } } else if (length > 0) { if (Runs > 0) { pxrunlength(Runs, RunLengths, Densities); Runs = 0; } chgtopixels: density %= GRAY_SCALE; do { Densities[Pixels] = density; if (++Pixels >= MAX_XPIXEL) { pxraster(Pixels, Densities); Pixels = 0; } } while (--length > 0); } Last_X += length; } dsp_endline() /* * End a horizontal line. Flush remaining runs or pixels. */ { if (Runs > 0) { pxrunlength(Runs, RunLengths, Densities); Runs = 0; } else if (Pixels > 0) { pxraster(Pixels, Densities); Pixels = 0; } } dsp_text(x, y, text) int x, y; char *text; /* * Display a string at the given location. */ { gtindex(GRAY_SCALE); /* set text color */ gamode(1); /* overlay chars on each other */ /* set character size */ gtsize(CXSIZE * 2, CYSIZE * 2, CXSIZE); /* position beam */ move(xpixtoaddr(x), ypixtoaddr(y)); gtext(text); /* do it */ } dsp_line(xfrom, yfrom, xto, yto) int xfrom, yfrom; int xto, yto; /* * Draw a line */ { lineindex(GRAY_SCALE); move(xpixtoaddr(xfrom), ypixtoaddr(yfrom)); draw(xpixtoaddr(xto), ypixtoaddr(yto)); } /* * Generate a color spectrum. */ #define PI (double)3.1415926535897932384626433 #define torad(deg) ((deg) * (PI / 180.0)) colormap() { double angle; register color; cmode(4, 0, 0); cmap(0, 0, 0, 0); cmap(GRAY_SCALE, 255, 255, 255); angle = torad(105.0); for (color = 1 ; color < GRAY_SCALE ; color++) { double red, green, blue, cutline; if (angle >= torad(360.0)) angle -= torad(360.0); cutline = (sin((angle * 6.0) - torad(90.0)) + 1.0) / 3.0; blue = fabs(sin(angle)) - cutline; green = fabs(sin(angle + torad(60.0))) - cutline; red = fabs(sin(angle + torad(120.0))) - cutline; if (blue < 0.0) blue = 0.0; if (green < 0.0) green = 0.0; if (red < 0.0) red = 0.0; blue *= 255.0 / (1.0 - cutline); green *= 255.0 / (1.0 - cutline); red *= 255.0 / (1.0 - cutline); cmap(color, dbltoint(red), dbltoint(green), dbltoint(blue)); angle += torad(180.0) / (double)(GRAY_SCALE - 1); } } SHAR_EOF if test -f 'mancompress.c' then echo shar: over-writing existing file "'mancompress.c'" fi cat << \SHAR_EOF > 'mancompress.c' #ifndef lint static char *RCSid = "$Header: mancompress.c,v 1.2 85/09/16 18:21:23 mikee Exp $"; #endif /* $Log: mancompress.c,v $ * Revision 1.2 85/09/16 18:21:23 mikee * Changed global variable names and eliminated PIXREC ref's. * * Revision 1.1 85/09/09 00:36:33 mikee * Initial revision * */ /* * This program can be used to compress an existing pixel file * using the "latest and greatest" version of the "manfiles" * compression techniques. * * Mike Edmonds - 9/6 * * Usage: mancompress [-v] [input-filename-prefix] [output-filename-prefix] * -v verify output against input * (default = off) * prefix pixel and histogram file prefix * (default = "mandel" and "mandel.new") */ #include "mandefs.h" static char *Progname; /* Program name */ static int Verify = FALSE; /* Verify flag */ static char *InFile = NULL; /* File name prefixes */ static char *OutFile = NULL; static short PixArray[MAX_NPIXEL][MAX_NPIXEL]; #define DEFINPUT "mandel" #define DEFOUTPUT "mandel.new" main(argc, argv) int argc; char *argv[]; { char stdoutbuf[BUFSIZ]; setbuf(stdout, stdoutbuf); /* do explicit output buffering */ Progname = *argv; getargs(argc, argv); if (compress()) { if (Verify && verify() != TRUE) exit(EOF); exit(0); } exit(EOF); } getargs(argc, argv) int argc; char *argv[]; { while (--argc) { argv++; if (strcmp(*argv, "-v") == 0) Verify = TRUE; else if (InFile == NULL) InFile = *argv; else if (OutFile == NULL) OutFile = *argv; else { char err[BUFSIZ]; sprintf(err, "Option `%s' invalid", *argv); perror(err); sprintf(err, "Usage: %s [-v] [input-prefix] [output-prefix]", Progname); perror(err); exit(EOF); } } if (InFile == NULL) InFile = DEFINPUT; if (OutFile == NULL) OutFile = DEFOUTPUT; } compress() /* * Read the input file into memory and write it out again. * (Reading the whole pixel array into memory is necessary because * the "manfiles" functions aren't able to handle two files at once * and I don't feel like fixing them.) */ { register x, y; fprintf(stderr, "Input phase starting.\n"); if ((hisopen(InFile, 'r') != TRUE) || (hisread() != TRUE) || (hisclose() != TRUE) || (pixopen(InFile, 'r') != TRUE)) return FALSE; for (y = 0 ; y < Npixel ; y++) { for (x = 0 ; x < Npixel ; ) { if (pixread(y, x) != TRUE) return FALSE; while (PixCount-- > 0) PixArray[y][x++] = PixValue; } } if (pixclose() != TRUE) return FALSE; fprintf(stderr, "Input phase completed.\n"); fprintf(stderr, "Output phase starting.\n"); if ((hisopen(OutFile, 'w') != TRUE) || (pixopen(OutFile, 'w') != TRUE)) return FALSE; for (y = 0 ; y < Npixel ; y++) { for (x = 0 ; x < Npixel ; x++) pixwrite(PixArray[y][x]); pixflush(); } if ((pixclose() != TRUE) || (hiswrite() != TRUE) || (hisclose() != TRUE)) return FALSE; fprintf(stderr, "Output phase completed.\n"); return TRUE; } verify() /* * Read the output file back in and compare it with the original. */ { register x, y, errcnt; fprintf(stderr, "Verify phase starting.\n"); if (pixopen(OutFile, 'r') != TRUE) return FALSE; errcnt = 0; for (y = 0 ; y < Npixel ; y++) { for (x = 0 ; x < Npixel ; ) { if (pixread(y, x) != TRUE) return FALSE; while (PixCount-- > 0) { if (PixArray[y][x] != PixValue) { fprintf(stderr, "\tpixel[%d,%d] differs", y, x); fprintf(stderr, " - wrote %d", PixArray[y][x]); fprintf(stderr, ", read %d\n", PixValue); if (++errcnt > 100) break; } x++; } } if (errcnt > 100) { fprintf(stderr, "Too many errors - giving up\n"); break; } } if (pixclose() != TRUE) return FALSE; fprintf(stderr, "Verify phase completed."); if (errcnt == 0) { fprintf(stderr, " No errors found.\n"); return TRUE; } else { fprintf(stderr, " %d errors found.\n", errcnt); return FALSE; } } SHAR_EOF if test -f 'manscreen.c' then echo shar: over-writing existing file "'manscreen.c'" fi cat << \SHAR_EOF > 'manscreen.c' #ifndef lint static char *RCSid = "$Header: manscreen.c,v 1.2 85/09/16 15:49:20 mikee Exp $"; #endif /* $Log: manscreen.c,v $ * Revision 1.2 85/09/16 15:49:20 mikee * Removed "fcreate" bizarreness. * * Revision 1.1 85/08/26 15:15:10 mikee * Cleaned up code. * */ /* * (Textual) screen handling for Mandelbrot programs. * Also prompt/input routines and some other junk. */ #include "mandefs.h" extern char line[]; /* General scratch (input line) */ /* * Prompt and read (integer/real/complex/string) */ getint(row, prompt, result, def_value, max_value) int row; char *prompt; int *result; int def_value; int max_value; { again: *result = def_value; if (isatty(fileno(stdin))) { scr_move(row, 1); scr_eol(); printf("%s (0:%d) <%d>: ", prompt, max_value, def_value); fflush(stdout); } if (gets(line) == NULL) return (FALSE); if (line[0] != EOS) *result = atoi(line); if (*result < 0 || *result > max_value) { printf("\nvalue %d out of range 0 .. %d, try again", *result, max_value); scr_eol(); goto again; } return (TRUE); } int getdouble(row, prompt, result) int row; char *prompt; double *result; { again: if (isatty(fileno(stdin))) { scr_move(row, 1); scr_eol(); printf("%s: ", prompt); fflush(stdout); } if (gets(line) == NULL) return (FALSE); if (line[0] == EOS) { printf("No default permitted, try again\n"); goto again; } *result = atof(line); return (TRUE); } getcomplex(row, prompt, real, imag) int row; char *prompt; double *real, *imag; { extern char *index(); register char *lp; again: if (isatty(fileno(stdin))) { scr_move(row, 1); scr_eol(); printf("%s: ", prompt); fflush(stdout); } if (gets(line) == NULL) return (FALSE); else if (line[0] == EOS) { printf("No default permitted, try again\n"); goto again; } else if ((lp = index(line, ',')) == NULL) { printf("Need two values, separated by a comma\n"); goto again; } *lp = EOS; *real = atof(line); *imag = atof(lp + 1); return (TRUE); } getstring(row, prompt, result, def_value) int row; char *prompt; char *result; char *def_value; { strcpy(result, def_value); if (isatty(fileno(stdin))) { scr_move(row, 1); scr_eol(); printf("%s <%s>: ", prompt, result); fflush(stdout); } if (gets(line) == NULL) return (FALSE); if (line[0] != EOS) strcpy(result, line); return (TRUE); } /* * Display routines (text -- for commands) These assume ANSI controls: * scr_clear() Clear screen, Home cursor * scr_home() Home cursor * scr_move(r,c) Move to row r, column c (upper-left == 1,1) * scr_eol() Clear to end of line */ scr_clear() { scr_home(); printf("\033[2J"); /* ANSI Erase display */ } scr_home() { scr_move(1, 1); } scr_move(row, col) { printf("\033[%d;%dH", row, col);/* ANSI Cursor Position */ } scr_eol() { printf("\033[0K"); /* ANSI Erase Line */ } SHAR_EOF if test -f 'maniter.c' then echo shar: over-writing existing file "'maniter.c'" fi cat << \SHAR_EOF > 'maniter.c' #ifndef lint static char *RCSid = "$Header: maniter.c,v 1.2 85/09/16 15:50:20 mikee Exp $"; #endif /* $Log: maniter.c,v $ * Revision 1.2 85/09/16 15:50:20 mikee * Changed global variable names. * * Revision 1.1 85/09/09 00:37:35 mikee * Initial revision * */ /* * Calculate a mandelbrot pixel value: * * 1. Set z to 0 + 0i and * set c to the pixel location (real, imag) * * 2. Perform step 3 until either * 1. count reaches the selected number of iterations or * 2. the "size" of z exceeds 2.0, where size is defined * as sqrt(z_real**2 + z_imag**2) * (we don't bother with the square root.) * * 3. z = z**2 + c; * count = count + 1; * size = size of z as defined above. * * 4. return the count. * * This function is in a special source file of its own so that massive * optimizations can be done. Since it is called so often, ANY speed-ups * here result in significant improvements in mancomp. */ #include "mandefs.h" pixvalue(c_real, c_imag) register double c_real; register double c_imag; { register count = 0; register double z_real = c_real; register double z_imag = c_imag; for (;;) { register double z2_real; register double z2_imag; z2_real = z_real * z_real; z2_imag = z_imag * z_imag; if ((z2_real + z2_imag) > 4.0) return count; if (++count >= Niter) return --count; z_imag = (z_real * z_imag * 2.0) + c_imag; z_real = z2_real - z2_imag + c_real; } } SHAR_EOF if test -f 'manfiles.c' then echo shar: over-writing existing file "'manfiles.c'" fi cat << \SHAR_EOF > 'manfiles.c' #ifndef lint static char *RCSid = "$Header: manfiles.c,v 1.2 85/09/18 16:17:16 mikee Exp $"; #endif /* $Log: manfiles.c,v $ * Revision 1.2 85/09/18 16:17:16 mikee * Changed global variable names, recoded double-precision scanf's, * eliminated PIXREC ref's and converted short read/writes from * non-portable fread/fwrite to portable getc/putc. * * Revision 1.1 85/09/09 00:37:03 mikee * Initial revision * */ /* * Functions to read and write mandelbrot pixel and histogram files. * * hisopen(prefix, mode) opens histogram file * hisread() reads data from above file * hiswrite() calculates (where necessary) and writes data * hisclose() closes file * * pixopen(prefix, mode) opens and initializes pixel file * pixread(recd, row, col) reads next pixel record from file * pixwrite(value) writes the given pixel record * pixflush() called at end of a row of pixels * pixclose() closes file */ #include "mandefs.h" int Niter; /* Maximum iterations */ int Npixel; /* Number pixels on each side */ double RealOrigin; /* Corner of the picture */ double ImagOrigin; double SideLength; /* Length of each side */ int Histogram[MAX_NPIXEL]; /* Pixel density histogram */ int HistTotal; /* Sum of histogram values */ int HistMin, HistMax; /* First/last count in histogram*/ static char HistName[81]; /* Histogram file name */ static FILE *HistFile; /* Histogram file pointer */ hisopen(prefix, mode) char *prefix, mode; /* * Open histogram file. */ { sprintf(HistName, "%s.his", prefix); if (mode == 'r') HistFile = fopen(HistName, "r"); else HistFile = fopen(HistName, "w"); if (HistFile == NULL) { char err[BUFSIZ]; sprintf(err, "Can't open %s", HistName); perror(err); return FALSE; } bzero(Histogram, sizeof(Histogram)); return TRUE; } hisread() /* * Read the data from the histogram file into memory. */ { char line[BUFSIZ], sreal[100], simag[100], sside[100]; register i, fields; if (fgets(line, sizeof(line), HistFile) == NULL) { perror("Histogram file -- first line missing"); return FALSE; } fields = sscanf(line, "%s %s %s %d %d", sreal, simag, sside, &Npixel, &Niter); if (fields != 5) { char err[BUFSIZ]; sprintf(err, "First hist line didn't scan\n\"%s\"\n", line); perror(err); return FALSE; } RealOrigin = atof(sreal); ImagOrigin = atof(simag); SideLength = atof(sside); if (fgets(line, sizeof(line), HistFile) == NULL) { perror("Histogram file -- second line missing"); return FALSE; } fields = sscanf(line, "%d %d %d", &HistMin, &HistMax, &HistTotal); if (fields != 3) { char err[BUFSIZ]; sprintf(err, "Second hist line didn't scan\n\"%s\"\n", line); perror(err); return FALSE; } for (i = HistMin; i <= HistMax; i++) { if (fgets(line, sizeof(line), HistFile) == NULL) { perror("Histogram file -- data line(s) missing"); return FALSE; } fields = sscanf(line, "%d", &Histogram[i]); if (fields != 1) { char err[BUFSIZ]; sprintf(err, "Histogram[%d] didn't scan\n\"%s\"\n", i, line); perror(err); return FALSE; } } return TRUE; } hiswrite() /* * Calculate and write histogram file. */ { register i; fprintf(HistFile, "%.15g %.15g %.15g %d %d\n", RealOrigin, ImagOrigin, SideLength, Npixel, Niter); for (HistMin = 0; HistMin < Niter; HistMin++) if (Histogram[HistMin] != 0) break; for (HistMax = Niter - 1; HistMax > HistMin; HistMax--) if (Histogram[HistMax] != 0) break; for (HistTotal = 0, i = HistMin; i <= HistMax; i++) HistTotal += Histogram[i]; fprintf(HistFile, "%d %d %d\n", HistMin, HistMax, HistTotal); for (i = HistMin; i <= HistMax; i++) fprintf(HistFile, "%d\n", Histogram[i]); return TRUE; } hisclose() /* * Close the histogram file and mark it closed. */ { if (HistFile) { fclose(HistFile); HistFile = NULL; return TRUE; } return FALSE; } /* * The following functions attempt to write and read pixel files in the * most space efficient manner possible. Their intent is to use a little * intelligence about normal pixel value distribution within a pixel file * to compress out duplicated data. */ static char PixlName[81]; /* Pixel file name */ static FILE *PixlFile; /* Pixel file pointer */ int PixValue; /* Pixel value */ int PixCount; /* Pixel count (run length) */ static PixMode; /* Read/write compression mode */ static LowValue; /* Last low pixel value */ static PixRun[MAX_NPIXEL]; /* Run of individual pixel values */ static RunLength; /* Length of current run (if any) */ /* Pixel compression modes */ #define CM_CHAR 0x8000 /* Pixels encoded in chars */ #define CM_ADD 0x4000 /* Pixels encoded as offsets from low */ #define CM_LOW 0x2000 /* New low value follows */ #define CM_RUN 0x1000 /* Run of individual pixels follow */ #define CM_SPARE2 0x0800 /* Spare */ #define CM_SPARE3 0x0400 /* Spare */ #define CM_MODES 0xfc00 /* All mode bits */ #define MAXCHAR 0xff /* Maximum value encodable in a char */ #define MAXSHORT 0xffff /* Maximum value encodable in a short */ #define MAXCOUNT 0x03ff /* Maximum pixel count (short - modes) */ /* * Primitive I/O routines. */ static putshort(value) register value; { putc(value & MAXCHAR, PixlFile); putc(value >> 8, PixlFile); } static getshort() { register value = getc(PixlFile); return (value | (getc(PixlFile) << 8)); } static putpixel(value) register value; { if (ison(CM_CHAR, PixMode)) { if (ison(CM_ADD, PixMode)) putc(value - LowValue, PixlFile); else putc(value, PixlFile); } else putshort(value); if (ison(CM_LOW, PixMode)) { turnoff(CM_LOW, PixMode); LowValue = value; } } static getpixel() { register value; if (ison(CM_CHAR, PixMode)) { if (ison(CM_ADD, PixMode)) value = getc(PixlFile) + LowValue; else value = getc(PixlFile); } else value = getshort(); if (ison(CM_LOW, PixMode)) { turnoff(CM_LOW, PixMode); LowValue = value; } return value; } pixopen(prefix, mode) char *prefix, mode; /* * Open pixel file and initialize static data. */ { sprintf(PixlName, "%s.pix", prefix); if (mode == 'r') PixlFile = fopen(PixlName, "r"); else PixlFile = fopen(PixlName, "w"); if (PixlFile == NULL) { char line[BUFSIZ]; sprintf(line, "Can't open %s", PixlName); perror(line); return FALSE; } PixCount = 0; PixValue = -1; PixMode = LowValue = 0; return TRUE; } pixread(row, col) int row, col; /* * Read the next group of identical pixels. */ { static runused = 0; /* pixels used out of current run */ if (ison(CM_RUN, PixMode)) { readrun: PixValue = PixRun[runused]; for (PixCount = 1 ;; PixCount++) { if (++runused >= RunLength) { turnoff(CM_RUN, PixMode); break; } else if (PixValue != PixRun[runused]) break; } return TRUE; } PixMode = getshort(); PixCount = PixMode & MAXCOUNT; if (ison(CM_RUN, PixMode)) { RunLength = runused = 0; while (PixCount-- > 0) PixRun[RunLength++] = getpixel(); goto readrun; } PixValue = getpixel(); if (feof(PixlFile)) { char err[BUFSIZ]; sprintf(err, "early eof; file %s, row %d - missing %d pixels", PixlName, row, Npixel - col); perror(err); sleep(2); return FALSE; } return TRUE; } _pixwrite(newvalue) register newvalue; /* * Write a group of identical pixels. */ { if (PixCount > 4) { Histogram[PixValue] += PixCount; if (ison(CM_RUN, PixMode)) { register cnt = 0; putshort(PixMode | RunLength); while (RunLength-- > 0) putpixel(PixRun[cnt++]); turnoff(CM_RUN, PixMode); } PixMode = pixmode(PixValue); do { register cnt = PixCount & MAXCOUNT; putshort(PixMode | cnt); putpixel(PixValue); PixCount -= cnt; } while (PixCount > 0) ; } else if (PixCount > 0) { register newmode = pixmode(PixValue); Histogram[PixValue] += PixCount; if (ison(CM_RUN, PixMode)) { if (newmode == PixMode) { if ((RunLength + PixCount) >= MAXCOUNT) { register cnt = 0; putshort(PixMode | RunLength); while (RunLength-- > 0) putpixel(PixRun[cnt++]); } do { PixRun[RunLength++] = PixValue; } while (--PixCount > 0); goto byebye; } else { register cnt = 0; putshort(PixMode | RunLength); while (RunLength-- > 0) putpixel(PixRun[cnt++]); turnoff(CM_RUN, newmode); } } if (ison(CM_LOW, newmode)) { PixMode = newmode; do { register cnt = PixCount & MAXCOUNT; putshort(PixMode | cnt); putpixel(PixValue); PixCount -= cnt; } while (PixCount > 0) ; } else { PixMode = newmode | CM_RUN; RunLength = 0; do { PixRun[RunLength++] = PixValue; } while (--PixCount > 0); } } byebye: PixCount = 1; PixValue = newvalue; return TRUE; } pixflush() /* * Write stored pixels. */ { _pixwrite(-1); PixCount = 0; if (ison(CM_RUN, PixMode)) { register cnt = 0; putshort(PixMode | RunLength); while (RunLength-- > 0) putpixel(PixRun[cnt++]); turnoff(CM_RUN, PixMode); } if (ferror(PixlFile)) { perror("pixel file write error"); return FALSE; } return TRUE; } pixclose() /* * Close the pixel file and mark it closed. */ { if (PixlFile) { pixflush(); fclose(PixlFile); PixlFile = NULL; return TRUE; } return FALSE; } static pixmode(value) register value; /* * Using the upcoming pixel value and the current compression mode, * determine the new optimal compression mode. */ { register oldmode = PixMode; if (value <= MAXCHAR) { switch (oldmode & (CM_CHAR | CM_ADD)) { case CM_CHAR: return oldmode; case CM_CHAR | CM_ADD: if (value >= LowValue) return oldmode; break; default: if (value >= LowValue) return (oldmode | CM_CHAR); break; } return (CM_CHAR | CM_LOW); } else { register diff; if (((diff = (value - LowValue)) < 0) || (diff > MAXCHAR)) return CM_LOW; if ((oldmode & (CM_CHAR | CM_ADD)) == (CM_CHAR | CM_ADD)) return oldmode; else return (oldmode | CM_ADD); } } SHAR_EOF if test -f 'manregis.c' then echo shar: over-writing existing file "'manregis.c'" fi cat << \SHAR_EOF > 'manregis.c' #ifndef lint static char *RCSid = "$Header: manregis.c,v 1.0 85/08/23 11:22:23 mikee Exp $"; #endif /* * Display Mandelbrot set pixels. * * This version uses the Regis display protocol (for Dec VT125, * VT240, and PRO-350). It should be "fairly" easy to adapt * it for other displays. */ #include #include #ifdef vms #include errno #define IO_ERROR errno #endif #define FALSE 0 #define TRUE 1 #define EOS '\0' /* * The Regis screen is fixed at 767 horizontal by 479 vertical pixels. * Although there is are relative coordinate system commands, we don't bother. * XORIGIN and YORIGIN define the lower-left corner of the Mandelbrot display. */ #define MAX_NPIXEL 400 #define SMAXX 768 #define SMAXY 480 #define XORIGIN 300 #define YORIGIN 425 #define GRAY_SCALE 13 /* Density ranges from 0 to 12 */ #define TICK 8 /* Length of boarder tick-marks */ #define CXSIZE 8 /* Character width */ #define CYSIZE 10 /* Character height */ /* * Globalize these values for the main display code. */ int max_npixel = MAX_NPIXEL; int smaxx = SMAXX; int smaxy = SMAXY; int xorigin = XORIGIN; int yorigin = YORIGIN; int gray_scale = GRAY_SCALE; /* Make known to mandisp.c */ int tick = TICK; int cxsize = CXSIZE; int cysize = CYSIZE; /* * Display routines for the bit-map display. * dsp_init() Initialize for bit-map writing, clear screen. * dsp_done() Done writing to the bit-map (don't clear) * dsp_finis() All done (about to exit to o.s., clear screen) * dsp_move(r,c) Move bitmap cursor to to this row-column * dsp_endline() Finish off a scanline * dsp_draw(d,len) Draw a horizontal line of the selected density * dsp_text(r,c,t) Write text string from this position * dsp_line(x,yf,xt,yt) Draw line from [xf,yf] to [xt,yt] */ dsp_init() /* * Start writing to the bitmap display. */ { printf("\33P1pS[0,0]S(E)S(C0)"); /* Regis initialize */ printf("S(M0(L0)1(L25)2(L50)3(L75))"); /* Regis Luminance */ } dsp_done() /* * Stop writing to the bitmap (don't clear it). */ { printf("\033\\"); fflush(stdout); } dsp_finis() /* * Exiting, clear display. */ { printf("\033P1pS(E)\033\\"); fflush(stdout); } dsp_move(row, col) int row, col; /* * Move bitmap cursor to this position. */ { printf("P[%d,%d]", row, col); } dsp_endline() /* * Executed at the end of a scan line. */ { printf("W(I3)W(P1)"); /* Reset density to known state */ fflush(stdout); } char *dens_command[GRAY_SCALE] = { /* Regis display controls */ "W(I0)", /* 0 == black */ "W(I1)W(P6)", /* 1 == dim, sparse dots */ "W(I1)W(P4)", /* 2 == dim, half-dense dots */ "W(I1)W(P5)", /* 3 == dim, dense dots */ "W(I1)W(P1)", /* 4 == dim, full line */ "W(I2)W(P6)", /* 5 == mid, sparse dots */ "W(I2)W(P4)", /* 6 == mid, half-dense dots */ "W(I2)W(P5)", /* 7 == mid, dense dots */ "W(I2)W(P1)", /* 8 == mid, full line */ "W(I3)W(P6)", /* 9 == full, sparse dots */ "W(I3)W(P4)", /* 10 == full, half-dense dots */ "W(I3)W(P5)", /* 11 == full, dense dots */ "W(I3)W(P1)", /* 12 == full, full line */ }; dsp_draw(density, length) int density; int length; /* * Draw a line of this density. * On entrance, cursor is at the left edge of the line. * Leave the cursor at the end of the line. */ { if (density < 0) density = 0; else if (density >= GRAY_SCALE) density = GRAY_SCALE - 1; printf("%sV[+%d]", dens_command[density], length); } dsp_text(row, col, text) int row, col; char *text; /* Must not contain a single quote "'" */ { dsp_move(row, col); printf("T'%s'", text); } dsp_line(xfrom, yfrom, xto, yto) int xfrom, yfrom; int xto, yto; /* * Draw a line */ { dsp_move(xfrom, yfrom); printf("V[%d,%d]", xto, yto); } SHAR_EOF # End of shell archive exit 0 -- Mike Edmonds S3G Unix Support Manager UUCPnet: {ucbvax,ihnp4,allegra,uw-beaver,...}!tektronix!mikee CSnet: mikee@tek ARPAnet: mikee.tek@csnet-relay Snail Mail: Tektronix, Inc., S3G Unix Support Del.Sta. 19-333 PO Box 500, Beaverton, OR 97077 MaBell: (503) 627-5340 Brought to you by Super Global Mega Corp .com