User:Evercat/Mandelbrot.c

From Wikipedia, the free encyclopedia
// 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;
}