// Mandelbrot.c
// Written by User:Evercat
//
// This draws the Mandelbrot set and spits out a .bmp file.
// Should be quite portable (endian issues have been taken
// care of, for example)
//
// Released under the GNU Free Documentation License
// or the GNU Public License, whichever you prefer:
// 9 February, 2004.
#include <stdio.h>
#define OUTFILE "mandelbrot.bmp"
#define WIDTH 1024
#define HEIGHT 768
#define CENTRE_X -0.75
#define CENTRE_Y 0
#define ZOOM 300
#define ITERATIONS 256 // Higher is more detailed, but slower...
// Plotting functions and parameters...
#define bailoutr(n) n * 10
#define bailoutg(n) n * 20
#define bailoutb(n) 0
// Colours for the set itself...
#define IN_SET_R 0
#define IN_SET_G 0
#define IN_SET_B 0
// Declare imagemap structure...
struct imagemap {
int width;
int height;
unsigned char * pixels; // this will point to a malloc of unsigned chars.
};
// Prototypes...
void init_imagemap(struct imagemap * bitmapstruct, int width, int height);
void setrgb(struct imagemap * bitmapstruct, int x, int y, int red, int green, int blue);
void drawbmp(struct imagemap * bitmapstruct, char * filename);
/////////////////////////////////// MAIN PROGRAM ///////////////////////////////////
int main (void)
{
double x; double r; double nextr;
double y; double s; double nexts;
int n; int xtoplot; int ytoplot;
double startx; double endx;
double starty; double endy;
double dx; double dy;
double dx_over_width;
struct imagemap bitmap;
init_imagemap(&bitmap, WIDTH, HEIGHT);
startx = CENTRE_X - ((double) WIDTH / (ZOOM * 2));
endx = CENTRE_X + ((double) WIDTH / (ZOOM * 2));
starty = CENTRE_Y - ((double) HEIGHT / (ZOOM * 2));
endy = CENTRE_Y + ((double) HEIGHT / (ZOOM * 2));
printf("\n Plotting from (%f, %f) to (%f, %f)\n", startx, starty, endx, endy);
dx = endx - startx;
dy = endy - starty;
dx_over_width = dx / WIDTH;
for ((x = startx) && (xtoplot = 0); xtoplot < WIDTH; (x += dx_over_width) && xtoplot++)
{
for ((y = starty) && (ytoplot = 0); ytoplot < HEIGHT; (y += dx_over_width) && ytoplot++)
{
r = x; s = y; // r = 0; s = 0; also works (just adds an iteration)
for (n = 0; n <= ITERATIONS; n++)
{
nextr = ((r * r) - (s * s)) + x;
nexts = (2 * r * s) + y;
r = nextr;
s = nexts;
if (n == ITERATIONS)
{
setrgb(&bitmap, xtoplot, ytoplot, IN_SET_R, IN_SET_G, IN_SET_B);
} else if ((r * r) + (s * s) > 4) {
setrgb(&bitmap, xtoplot, ytoplot, bailoutr(n), bailoutg(n), bailoutb(n));
break;
}
}
}
}
drawbmp(&bitmap, OUTFILE);
printf("\n Saved to %s. Done.\n", OUTFILE);
return 0;
}
//////////////////////////////// GRAPHICS ROUTINES /////////////////////////////////
// Function for initialising a bitmap (which already exists)...
void init_imagemap(struct imagemap * bitmapstruct, int width, int height)
{
bitmapstruct->width = width;
bitmapstruct->height = height;
bitmapstruct->pixels = (unsigned char *) malloc(bitmapstruct->width * bitmapstruct->height * 3);
if (bitmapstruct->pixels == NULL)
{
printf("Memory allocation failed. Quitting.\n");
exit(1);
}
return;
}
// Set a pixel...
void setrgb(struct imagemap * bitmapstruct, int x, int y, int red, int green, int blue)
{
if (x < 0 || x >= bitmapstruct->width || y < 0 || y >= bitmapstruct->height)
return;
if (red > 255) red = 255; if (red < 0) red = 0;
if (green > 255) green = 255; if (green < 0) green = 0;
if (blue > 255) blue = 255; if (blue < 0) blue = 0;
bitmapstruct->pixels[(x * 3) + 0 + (y * bitmapstruct->width * 3)] = red;
bitmapstruct->pixels[(x * 3) + 1 + (y * bitmapstruct->width * 3)] = green;
bitmapstruct->pixels[(x * 3) + 2 + (y * bitmapstruct->width * 3)] = blue;
return;
}
// Draw a .bmp file...
void drawbmp (struct imagemap * bitmapstruct, char * filename) {
unsigned int headers[13];
FILE * outfile;
int extrabytes;
int paddedsize;
int x; int y; int n;
extrabytes = 4 - ((bitmapstruct->width * 3) % 4); // How many bytes of padding to add to
// eachhorizontal line - the size of
// which must be a multiple of 4 bytes.
if (extrabytes == 4)
extrabytes = 0;
paddedsize = ((bitmapstruct->width * 3) + extrabytes) * bitmapstruct->height;
// Headers...
headers[0] = paddedsize + 54; // bfSize (whole file size)
headers[1] = 0; // bfReserved (both)
headers[2] = 54; // bfOffbits
headers[3] = 40; // biSize
headers[4] = bitmapstruct->width; // biWidth
headers[5] = bitmapstruct->height; // biHeight
// 6 will be written directly...
headers[7] = 0; // biCompression
headers[8] = paddedsize; // biSizeImage
headers[9] = 0; // biXPelsPerMeter
headers[10] = 0; // biYPelsPerMeter
headers[11] = 0; // biClrUsed
headers[12] = 0; // biClrImportant
outfile = fopen (filename, "wb");
// Headers begin...
// When printing ints and shorts, we write out 1 character at a time to avoid endian issues.
fprintf (outfile, "BM");
for (n = 0; n <= 5; n++)
{
fprintf(outfile, "%c", headers[n] & 0x000000FF);
fprintf(outfile, "%c", (headers[n] & 0x0000FF00) >> 8);
fprintf(outfile, "%c", (headers[n] & 0x00FF0000) >> 16);
fprintf(outfile, "%c", (headers[n] & (unsigned int) 0xFF000000) >> 24);
}
// These next 4 characters are for the biPlanes and biBitCount fields.
fprintf(outfile, "%c", 1);
fprintf(outfile, "%c", 0);
fprintf(outfile, "%c", 24);
fprintf(outfile, "%c", 0);
for (n = 7; n <= 12; n++)
{
fprintf(outfile, "%c", headers[n] & 0x000000FF);
fprintf(outfile, "%c", (headers[n] & 0x0000FF00) >> 8);
fprintf(outfile, "%c", (headers[n] & 0x00FF0000) >> 16);
fprintf(outfile, "%c", (headers[n] & (unsigned int) 0xFF000000) >> 24);
}
// Headers done, now write the data...
for (y = bitmapstruct->height - 1; y >= 0; y--) // BMPs are written bottom to top.
{
for (x = 0; x <= bitmapstruct->width - 1; x++)
{
// Also, it's written in (b,g,r) format...
fprintf(outfile, "%c", bitmapstruct->pixels[(x * 3) + 2 + (y * bitmapstruct->width * 3)]);
fprintf(outfile, "%c", bitmapstruct->pixels[(x * 3) + 1 + (y * bitmapstruct->width * 3)]);
fprintf(outfile, "%c", bitmapstruct->pixels[(x * 3) + 0 + (y * bitmapstruct->width * 3)]);
}
if (extrabytes) // See above - BMP lines must be of lengths divisible by 4.
{
for (n = 1; n <= extrabytes; n++)
{
fprintf(outfile, "%c", 0);
}
}
}
fclose (outfile);
return;
}