25 Years of Programming
An open source source for C, C++, OWL, BASIC, MDB, XLS, DOT, and more...
Home   Projects   Up   Sitemap   Search   Blog   Forum+Chat   About Us   Privacy   Terms of Use   Feedback   FAQ   Images   Services   Ads   Donate   Humor

MBrot.c - Mandelbrot set display

Use Search Site at bottom of page to find the other Mandelbrot programs on this website.

/*	mbrot.c       1-3-06
	Copyright (C)1993, 2006 Steven Whitney.
	DeSmet C 3.03 version for H100 computer.
	Calculates and displays regions of the Mandelbrot set.
	Uses .PIC format: width,height (width * height chars),
	which appears to be compatible with Winbrot.cpp's format
	even though it's not identical.

	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	Version 2 as published by the Free Software Foundation.
	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.
	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

	The program requires several of the functions from my function libraries.
	The special bind command allows using exec(). pcio.o provides the IBM screen fns.
	bind with:  bind exec mbrot mylib.s (or your library module) -ombrot
	For IBM:	bind exec mbrot mylib.s (or your library module) pcio -ombrot

*/
#include   "stdio.h"
#include   "math.h"  	/* no longer required unless you use any double math fns */

/*--------------------------------------------------------------------------*/

#define		H100	1		/* 1 = Heathkit H100 (NORMAL USE), 0 = IBM compatible */
							/* Graphics display is not possible for IBM */
							/* unless you supply some missing graphics routines */
							/* and do some other customization. It can do the calculations, though. */
							/* This #define was only used to allow testing the program */
							/* *without* its graphics on an IBM compatible, */
							/* to determine if everything else works ok. */

#define		WIDTH	640		/* H100 display */
#define		HEIGHT	225     /* H100 draws each scan line twice(?), so pixels are 2x their real height, */
							/* giving an "effective" height of 450. */
#define		ASPECT	(0.75)	/* but the aspect ratio of Zenith ZVM-135 monitor = 7.5"/10" */
							/* Anyway, .75 is the value I had to use to make it look right. */
							/* You may need to adjust it if the Mbrot regions look squished. */

#define     MAXITERATIONS   10		/* MUST be <= 256 so result (0-255) fits in a char */
									/* 256 is best, but takes HOURS to draw on a 4MHz CPU */
									/* 10 shows no detail, but at least it's fast, */
									/* so that's why it's the distribution default. */
int colors[MAXITERATIONS];			/* color map */

/* ----------------------------------------------------------------------- */
/*	LOCATE(LINE,COLUMN)	1-3-06  */
/*	Emulates the Basic LOCATE command	*/
/*	returns 0 and does nothing if coordinates out of range */
/*	returns 1 if ok */
/* ----------------------------------------------------------------------- */
int locate(line, column)
int line, column;
{
if((line < 1) || (line > 25) || (column < 1) || (column > 80))
	return(0);
#if (H100)
	if(line == 25)			/* automatically enable line 25 if requested */
		puts("\033x1");
	puts("\033Y");
	putchar(line + 31);
	putchar(column + 31);
#else
	scr_rowcol(line - 1, column - 1); /* IBM origin seems to be 0,0 */
#endif
return(1);
}
/*--------------------------------------------------------------------------*/
/* Clear screen */
void cls()
{
#if (H100)
	locate(1,1);
	puts("\033E");
#else
	scr_clr();
#endif
}
/*--------------------------------------------------------------------------*/
/* color map file structure: color<cr>color<cr>... */
/* # lines in file must be at least MAXITERATIONS */
/* *EACH* possible iteration count has an associated color */
/* colors[MAXITERATIONS-1] should be 0 (black) */
/* Each iteration value maps to a color. The file provided to this function */
/* should be a text file of 255 lines, with one number on each line. */
/* Each number is the number of the color to use when plotting the */
/* iteration count corresponding to that line number in the file. */
/* Remember that the H100 only has 8 colors available, numbered 0-7.  */
/* EXAMPLE: */
/* 1	<-- ESCAPE TIME OF 0 MAPS TO COLOR 1 */
/* 4	<-- ESCAPE TIME OF 1 MAPS TO COLOR 4 */
/* 5	<-- ESCAPE TIME OF 2 MAPS TO COLOR 5 */
/* ETC. */
/* See the end of this page for an example colors file.  */
void loadcolors()
{
int i;
char filename[80];
FILE *infile;

puts(".COL (color) file to load: ");
gets(filename);
if(!(infile = fopen(filename,"r")))
	abort("Input file not found.");
for(i = 0 ; i < MAXITERATIONS ; i++)
	if(fscanf(infile,"%d\n",&(colors[i])) != 1)
		abort(".COL file corrupt. Repair and rerun.");
fclose(infile);
}
/*--------------------------------------------------------------------------*/
void calcmbrot()
{
int i, row, column;
char ch;
char buf[1024];
double lowx, highx, lowy, highy;
double dx, dy;
double zreal, zimag, oldzreal;
double creal, cimag;
char filename[80];
FILE *outfile;

loadcolors();

puts("\nNote that the output file will be 144,000 bytes, plus the .ZED is 54000.\n\n");
puts("Name of .PIC file to create (omit .PIC): ");
gets(filename);
puts("\n");

puts("Enter X (REAL) Low      : ");
scanf("%lf",&lowx);
puts("Enter X (REAL) High     : ");
scanf("%lf",&highx);

puts("\nFor proper aspect ratio, the Y range (high - low) should be: \n");
printf("%lf\n\n",ASPECT * (highx - lowx));

puts("Enter Y (IMAGINARY) Low : ");
scanf("%lf",&lowy);
puts("Enter Y (IMAGINARY) High: ");
scanf("%lf",&highy);
puts("\n");

strupr(filename);
strcpy(buf,filename);
strcat(buf,".INF");
if(!(outfile = fopen(buf,"w")))
	abort("File creation error.");

sprintf(buf,"X Axis REAL      =  %.13lf  %.13lf\n", lowx, highx);
puts(buf);
fputs(buf, outfile);

sprintf(buf,"Y Axis IMAGINARY =  %.13lf  %.13lf\n\n", lowy, highy);
puts(buf);
fputs(buf, outfile);

fclose(outfile);

locate(25,1);
puts("ESC = Pause (run 2nd command.com),  ^C = abort.");
locate(24,1);					/* leave cursor here for when pgm ends */
puts("Working...");

strcat(filename,".PIC");
if(!(outfile = fopen(filename,"w")))
	abort("File creation error.");

/* must use a trailing space; a \n writes CR+LF, NOT ok! */
/* strangely, these files can be read by Winbrot.cpp, which expects a \n there, */
/* so maybe any single whitespace char will do. */
fprintf(outfile,"%d,%d ",WIDTH,HEIGHT);

dx = (highx - lowx) / (double)(WIDTH - 1);
dy = (highy - lowy) / (double)(HEIGHT - 1);
cimag = highy;
for(row = 0 ; row < HEIGHT ; row++, cimag -= dy)
{
	creal = lowx;
	for(column = 0 ; column < WIDTH ; column++, creal += dx)
	{
		/* Calculate Z = Z*Z + C until the iteration count reaches MAXITERATIONS */
		/* or until we can be certain it is heading to infinity. */
		/* Remember the Min result = 1, Max result = MAXITERATIONS */
		/* 12/31/05 This should be compiled to assembler and optimized. */
		zreal = zimag = 0.;
		for(i = 1 ; i < MAXITERATIONS ; i++)
		{
			oldzreal = zreal;
			zreal = zreal * zreal - zimag * zimag + creal;
			zimag = 2.0 * oldzreal * zimag + cimag;
			if((zreal * zreal + zimag * zimag) > 4.)  /* norm(), magnitude */
				break;
		}
		/* the real i has a minimum value of 1 and a maximum of 256, but char(256) == (char)0 */
		/* i-- maps the range down to 0-255 and allows using all 256 colors. */
		i--;
#if (H100)
		pset(column,row,colors[i]);
#endif
		if(fputc((char)i, outfile) == ERR)
		{
#if (H100)
			zedsave();
#endif
			abort(".PIC file write error.");
		}
		if(csts())
		{
			ch = ci();
			switch(ch)
			{
				case 3:				/* ^C saves partial & aborts */
					fclose(outfile);
#if (H100)
					zedsave();
					puts("\033z");
#endif
					exit(0);

				/* It takes hours to create one image. */
				/* This option allows you to temporarily suspend calculation, */
				/* so you can do something else on your computer. */
				case 27:						/* ESC key runs command.com  */
#if (H100)
					zedsave();                  /* save screen so far */
					puts("\033z");              /* reset terminal */
#endif
					exec("command.com","");		/* shell to command.com */
#if (H100)
					puts("\033z\033x1\033x5");	/* on return, restore terminal as we want */
					_outb(0x78,0xd8);
					zedload("screen.zed");    	/* reload saved screen to resume */
#endif
					break;

				default:
					break;
			}					/* end switch */
		}						/* end if(csts()) */
	}							/* end for(columns) */
}								/* end for(rows) */
fclose(outfile);
#if (H100)
zedsave();
#endif
}
/*--------------------------------------------------------------------------*/
/* if the PIC's dimensions exceed 640x225, its upper left quadrant is displayed */
void LoadPIC()
{
int i, row, column, color, width, height, filewidth, fileheight;
char filename[80];
char buf[4096];
FILE *infile;

puts(".PIC file to read (omit .PIC): ");
gets(filename);
strcat(filename,".PIC");
if(!(infile = fopen(filename,"r")))
	abort("Input file not found.");

loadcolors();

if(fscanf(infile,"%d,%d ",&filewidth,&fileheight) != 2)
	abort(".PIC file corrupt.");
if(filewidth > 4096)
	abort("Specified PIC is too wide to display. Revise program source.");
width = filewidth;
height = fileheight;
if(width > WIDTH)
	width = WIDTH;
if(height > HEIGHT)
	height = HEIGHT;

for(row = 0 ; row < height ; row++)	/* if file has extra rows, it just won't read them */
{
	if(fread(buf, sizeof(char), filewidth, infile) != filewidth)
		abort(".PIC file corrupt.");
	for(column = 0 ; column < width ; column++)	/* pixels beyond right edge just aren't displayed */
#if (H100)
		pset(column, row, colors[buf[column]]);
#endif
	if(csts() == 3)                             /* allow ^C abort after each line */
		break;
}
fclose(infile);
#if (H100)
zedsave();
#endif
}
/*--------------------------------------------------------------------------*/
main()
{
int i;
char choice;
FILE *infile;

if(!(infile = fopen("command.com","r")))
	abort("A copy of COMMAND.COM must be in the current default directory, to allow using EXEC.");
fclose(infile);

#if (H100)
{
	puts("\033z\033x1\033x5");	/* reset, enable 25th, cursor off */
	_outb(0x78,0xd8);			/* enable all H100 color planes */
}
#endif

cls();
do
{
	locate(1,1);
	puts("0 - Exit\n");
	puts("1 - Calculate a Mandelbrot region with coordinates you specify\n");
	puts("2 - Display an existing .PIC file\n\n");
	puts("Enter choice: ");
	choice = getchar();    		/* no CR required */
	puts("\n\n");
}
while((choice < '0') || (choice > '2'));
switch(choice)
{
	case '0':
#if (H100)
		puts("\033z");
#endif
		exit(0);

	case '1':
		calcmbrot();
		break;

	case '2':
		LoadPIC();
		break;
}
#if (H100)
puts("\033z");	 		/* master H100 terminal reset */
#endif
exit(0);
}						/* end main */

/*--------------------------------------------------------------------------*/
/*
Here is a sample colors file:
1
2
3
4
5
6
7
0
1
2
3
4
5
6
7
0
1
2
3
4
5
6
7
0
1
2
3
4
5
6
7
0
1
2
3
4
5
6
7
0
1
2
3
4
5
6
7
0
1
2
3
4
5
6
7
0
1
2
3
4
5
6
7
0
1
2
3
4
5
6
7
0
1
2
3
4
5
6
7
0
1
2
3
4
5
6
7
0
1
2
3
4
5
6
7
0
1
2
3
4
5
6
7
0
1
2
3
4
5
6
7
0
1
2
3
4
5
6
7
0
1
2
3
4
5
6
7
0
1
2
3
4
5
6
7
0
1
2
3
4
5
6
7
0
1
2
3
4
5
6
7
0
1
2
3
4
5
6
7
0
1
2
3
4
5
6
7
0
1
2
3
4
5
6
7
0
1
2
3
4
5
6
7
0
1
2
3
4
5
6
7
0
1
2
3
4
5
6
7
0
1
2
3
4
5
6
7
0
1
2
3
4
5
6
7
0
1
2
3
4
5
6
7
0
1
2
3
4
5
6
7
0
1
2
3
4
5
6
7
0
1
2
3
4
5
6
7
0
1
2
3
4
5
6
7
0
END OF COLORS FILE EXAMPLE.
*/

 

 

Valid HTML 4.01 Transitional Valid CSS
View content labeling at ICRA.
Copyright ©2007 Steven Whitney. Last modified 09/25/2007.