User:Evercat/Mandelbrot.c
Appearance
// 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; }